12<html lang="en">3<head>4<meta charset="utf-8">5<meta name="viewport" content="width=device-width, initial-scale=1">6<title>NIP-13 - Proof of Work — Nostr Instruction Manual</title>7<meta name="description" content="NIP-13: Proof of Work. Leading-zero-bit difficulty in the event id, the nonce tag, mining and validation rules, delegated PoW, and the pow OK prefix.">8<link rel="preload" href="../assets/fonts/michroma-400-latin.woff2" as="font" type="font/woff2" crossorigin>9<link rel="preload" href="../assets/fonts/exo2-var-latin.woff2" as="font" type="font/woff2" crossorigin>10<link rel="preload" href="../assets/fonts/sairacondensed-600-latin.woff2" as="font" type="font/woff2" crossorigin>11<link rel="preload" href="../assets/fonts/sairacondensed-700-latin.woff2" as="font" type="font/woff2" crossorigin>12<link rel="preload" href="../assets/fonts/sairacondensed-500-latin.woff2" as="font" type="font/woff2" crossorigin>13<link rel="preload" href="../assets/fonts/sharetechmono-400-latin.woff2" as="font" type="font/woff2" crossorigin>14<link rel="preload" href="../assets/fonts/exo2-400i-latin.woff2" as="font" type="font/woff2" crossorigin>15<link rel="icon" href="../assets/favicon.svg" type="image/svg+xml">16<link rel="stylesheet" href="../assets/manual.css">17</head>18<body>1920<svg width="0" height="0" style="position:absolute">21 <defs>22 <marker id="arr" markerWidth="9" markerHeight="9" refX="7" refY="4.5" orient="auto">23 <path d="M1,1 L8,4.5 L1,8 Z" fill="#f26a00"/>24 </marker>25 <marker id="arrb" markerWidth="9" markerHeight="9" refX="7" refY="4.5" orient="auto">26 <path d="M1,1 L8,4.5 L1,8 Z" fill="#2e5f9e"/>27 </marker>28 </defs>29</svg>3031<div class="page">32 <span class="staple s1"></span><span class="staple s2"></span>3334 <header class="band">35 <a class="logo" href="../index.html">NOSTR<b>▸</b>PROTOCOL MANUAL</a>36 <span class="booklet-note">Chapter 13 - Relay Ops</span>37 </header>38 <nav class="tabs">39 <a href="../index.html">Contents</a>40 <a href="#overview" class="on">Overview</a>41 <a href="#spec">Spec</a>42 <a href="#examples">Examples</a>43 <a href="#history">History</a>44 </nav>4546 <div class="chapter">47 <div class="nipno" data-n="13">13</div>48 <div class="titles">49 <div class="kicker">Nostr Implementation Possibility - Hex № 13</div>50 <h1>Proof of Work</h1>51 <p class="sub">A bearer proof of computational work, baked directly into an event's id. Relays and clients use it to deter spam with a few lines of code and no extra infrastructure.</p>52 </div>53 </div>5455 <main class="spread">56 <div class="main">5758 <h2 class="bar" id="overview"><span class="num">1</span> Overview</h2>59 <p>Anyone can publish an event to a relay for free. That is a feature of <a href="01.html">NIP-01</a>, and also a weakness: a relay has no cheap way to tell a real user from a flood of spam. Proof of Work (PoW) gives relays and clients a way to raise the cost of publishing, one event at a time.</p>60 <p>PoW makes the author spend real computation before an event is valid. The proof lives inside the event's own <code>id</code>, so it is a <strong>bearer proof</strong>: whoever holds the event can check the proof, with no lookup, no server call, and no extra signature. This NIP defines <strong>difficulty</strong> as the number of leading zero bits in the event <code>id</code>. More required bits means more expected computation.</p>61 <p>PoW is optional. Nothing in <a href="01.html">NIP-01</a> requires it. A relay may demand a minimum difficulty before it accepts events, using the <code>min_pow_difficulty</code> field from its <a href="11.html">NIP-11</a> information document. A client may demand a minimum difficulty on replies to one of its own threads, to slow down flooding.</p>6263 <div class="box hint">64 <span class="tag">Hint!</span>65 <p>PoW does not identify a spammer or block a pubkey. It only makes each event cost something. A relay that wants strong spam control usually combines PoW with other tools, such as <a href="42.html">NIP-42</a> authentication or a payment requirement.</p>66 </div>6768 <h2 class="bar" id="spec"><span class="num">2</span> Difficulty</h2>69 <p><strong>Difficulty</strong> is the number of leading zero bits in the <code>id</code> field defined by <a href="01.html">NIP-01</a>. The <code>id</code> is a 32-byte sha256 hash, written as 64 lowercase hex characters. Count the zero bits from the left, and stop at the first <code>1</code> bit.</p>70 <p>For example, the id <code>000000000e9d97a1ab09fc381030b346cdd7a142ad57e6df0b46dc9bef6c7e2d</code> has a difficulty of <code>36</code>. It has 36 leading zero bits.</p>71 <div class="box warn">72 <span class="tag">Warning!</span>73 <p>Do not just count leading zero hex characters. A hex digit of <code>7</code> or less still starts with one or more zero bits. <code>002f...</code> is <code>0000 0000 0010 1111...</code> in binary. That is 10 leading zero bits, not 8. Always convert to binary before you count.</p>74 </div>7576 <h2 class="bar" id="mining"><span class="num">3</span> Mining</h2>77 <p>To mine PoW for a <a href="01.html">NIP-01</a> event, add a <code>nonce</code> tag to it:</p>78 <div class="crt">79 <div class="titlebar">Example - unmined event with a nonce tag</div>80<pre>{<span class="k">"content"</span>: <span class="s">"It's just me mining my own business"</span>, <span class="k">"tags"</span>: [[<span class="s">"nonce"</span>, <span class="s">"1"</span>, <span class="s">"21"</span>]]}</pre>81 </div>82 <p>The <code>nonce</code> tag has this shape:</p>83 <div class="tscroll"><table class="ref">84 <caption>The nonce tag</caption>85 <tr><th>Element</th><th>Value</th><th>Rule</th></tr>86 <tr><td class="btn">0</td><td><code>"nonce"</code></td><td>Fixed tag name.</td></tr>87 <tr><td class="btn">1</td><td>nonce value</td><td>An arbitrary string. The miner changes this on every attempt.</td></tr>88 <tr><td class="btn">2</td><td>target difficulty</td><td>The difficulty the miner is aiming for. <code>SHOULD</code> be present. See the committed-target rule below.</td></tr>89 </table></div>90 <p>To mine, repeat this loop: change the nonce value, serialize the event and compute the <code>id</code> again (following <a href="01.html">NIP-01</a>), then count the leading zero bits. If the count meets or beats the desired difficulty, the event is mined. If not, change the nonce again. It is recommended to also update <code>created_at</code> during mining, since the timestamp is part of the serialized data and changing it gives the miner a fresh search space.</p>9192 <figure class="diagram">93 <div class="frame">94 <svg viewBox="0 0 660 200" role="img" aria-label="Mining loop: adjust the nonce, serialize the event, hash it with sha256, count leading zero bits, compare to the target, and repeat until the target is met">95 <rect class="d-actor" x="10" y="30" width="110" height="54" rx="8"/>96 <text class="d-actor-label" x="65" y="53" text-anchor="middle">Adjust</text>97 <text class="d-note" x="65" y="70" text-anchor="middle">nonce / created_at</text>98 <rect class="d-actor" x="150" y="30" width="100" height="54" rx="8"/>99 <text class="d-actor-label" x="200" y="57" text-anchor="middle">Serialize</text>100 <rect class="d-actor" x="280" y="30" width="90" height="54" rx="8"/>101 <text class="d-actor-label" x="325" y="57" text-anchor="middle">sha256</text>102 <rect class="d-actor" x="400" y="30" width="130" height="54" rx="8"/>103 <text class="d-actor-label" x="465" y="53" text-anchor="middle">Count zero bits</text>104 <text class="d-note" x="465" y="70" text-anchor="middle">of the id</text>105 <rect class="d-actor" x="560" y="30" width="90" height="54" rx="8"/>106 <text class="d-actor-label" x="605" y="53" text-anchor="middle">Compare</text>107 <text class="d-note" x="605" y="70" text-anchor="middle">to target</text>108 <path class="d-msg d-flow" d="M122,57 L148,57"/>109 <path class="d-msg d-flow" d="M252,57 L278,57"/>110 <path class="d-msg d-flow" d="M372,57 L398,57"/>111 <path class="d-msg d-flow" d="M532,57 L558,57"/>112 <path class="d-msg d-flow" d="M580,84 C560,140 540,155 500,155 L66,155 C26,155 26,120 44,86" marker-end="url(#arr)"/>113 <text class="d-label" x="300" y="175" text-anchor="middle">bits < target — increment nonce and try again</text>114 <text class="d-note" x="605" y="100" text-anchor="middle">bits >= target</text>115 <text class="d-note" x="605" y="114" text-anchor="middle">mined — publish</text>116 </svg>117 </div>118 <figcaption>Fig. 13-1 — <b>The mining loop.</b> Every failed attempt only costs a hash. Every extra required bit doubles the expected number of attempts.</figcaption>119 </figure>120121 <h2 class="bar" id="validating"><span class="num">4</span> Validating</h2>122 <p>A relay or client validates PoW after it already validated the event's signature under <a href="01.html">NIP-01</a>. Validation has three steps:</p>123 <ol>124 <li>Count the leading zero bits of the event <code>id</code>, using the binary method from §2.</li>125 <li>Compare that count to the difficulty this relay or client requires.</li>126 <li>Check the <code>nonce</code> tag's third element, the committed target. Reject the event if the committed target is lower than the difficulty required, even if the actual bit count happens to be high enough.</li>127 </ol>128 <p>Step 3 stops a specific attack. Say a relay requires 40 bits of difficulty on replies to one thread. A bulk spammer mining for a lower, easier target of 30 bits will occasionally get lucky and produce an id with 40 or more zero bits by chance. If the note commits to a target of 30, the relay can safely reject it, because the author never promised 40 bits of work. Without a committed target, the relay could not tell a lucky low-effort note from an honestly high-effort one. Honest miners should have no objection to committing to their real target. A relay or client <code>MAY</code> reject any note that matches its target difficulty but carries no difficulty commitment at all.</p>129130 <div class="box tech">131 <span class="tag">Tech Note</span>132 <p>The <code>OK</code> and <code>CLOSED</code> messages defined in <a href="01.html">NIP-01</a> carry a <code>pow</code> prefix for this exact purpose. A relay reports the difficulty it saw and the difficulty it needed, for example <code>"pow: difficulty 25>=24"</code> on acceptance or <code>"pow: difficulty 26 is less than 30"</code> on rejection.</p>133 </div>134135 <p>Reference C code for counting leading zero bits in a raw hash:</p>136 <div class="crt">137 <div class="titlebar">Reference code (C) - count_leading_zero_bits</div>138<pre><span class="c">int zero_bits(unsigned char b)139{140 int n = 0;141142 if (b == 0)143 return 8;144145 while (b >>= 1)146 n++;147148 return 7-n;149}150151/* find the number of leading zero bits in a hash */152int count_leading_zero_bits(unsigned char *hash)153{154 int bits, total, i;155 for (i = 0, total = 0; i < 32; i++) {156 bits = zero_bits(hash[i]);157 total += bits;158 if (bits != 8)159 break;160 }161 return total;162}</span></pre>163 </div>164 <p>The same logic in JavaScript, working on the hex string form of the <code>id</code>:</p>165 <div class="crt">166 <div class="titlebar">Reference code (JavaScript) - countLeadingZeroes</div>167<pre><span class="c">// hex should be a hexadecimal string (with no 0x prefix)168function countLeadingZeroes(hex) {169 let count = 0;170171 for (let i = 0; i < hex.length; i++) {172 const nibble = parseInt(hex[i], 16);173 if (nibble === 0) {174 count += 4;175 } else {176 count += Math.clz32(nibble) - 28;177 break;178 }179 }180181 return count;182}</span></pre>183 </div>184185 <h2 class="bar" id="delegated"><span class="num">5</span> Delegated Proof of Work</h2>186 <p>The <a href="01.html">NIP-01</a> event <code>id</code> does not commit to the <code>sig</code> field. The id only hashes <code>pubkey</code>, <code>created_at</code>, <code>kind</code>, <code>tags</code>, and <code>content</code>. This means PoW can be mined without ever holding the author's private key.</p>187 <p>A client can hand its unsigned fields to a separate PoW provider, perhaps for a fee. The provider mines the <code>nonce</code> tag until the target difficulty is met, then returns the mined fields. The original client signs the result and publishes it. This lets an energy-constrained device, such as a mobile phone, reach a PoW-restricted relay without spending its own battery on hashing.</p>188189 <h2 class="bar" id="examples"><span class="num">6</span> Worked Example</h2>190 <p>This is a complete mined event. The nonce value <code>776797</code> was the winning attempt; the nonce commits to a target difficulty of <code>20</code>.</p>191 <div class="crt">192 <div class="titlebar">Example mined note</div>193<pre>{194 <span class="k">"id"</span>: <span class="s">"000006d8c378af1779d2feebc7603a125d99eca0ccf1085959b307f64e5dd358"</span>,195 <span class="k">"pubkey"</span>: <span class="s">"a48380f4cfcc1ad5378294fcac36439770f9c878dd880ffa94bb74ea54a6f243"</span>,196 <span class="k">"created_at"</span>: 1651794653,197 <span class="k">"kind"</span>: 1,198 <span class="k">"tags"</span>: [199 [<span class="s">"nonce"</span>, <span class="s">"776797"</span>, <span class="s">"20"</span>]200 ],201 <span class="k">"content"</span>: <span class="s">"It's just me mining my own business"</span>,202 <span class="k">"sig"</span>: <span class="s">"284622fc0a3f4f1303455d5175f7ba962a3300d136085b9566801bc2e0699de0c7e31e44c81fb40ad9049173742e904713c3594a1da0fc5d2382a25c11aba977"</span>203}</pre>204 </div>205 <p>Count the leading zero bits of the <code>id</code> to check the proof:</p>206 <div class="crt">207 <div class="titlebar">Counting the difficulty of the id above</div>208<pre><span class="c">id = 000006d8c378af1779d2feebc7603a125d99eca0ccf1085959b307f64e5dd358209hex = 0 0 0 0 0 6 d 8 ...210 └───┬───┘ │211 5 zero hex digits = 20 zero bits212 6 = 0110 binary → 1 more leading zero bit, then a 1 bit — stop213214total difficulty = 20 + 1 = 21 bits</span></pre>215 </div>216 <p>21 bits meets the committed target of 20. A relay requiring 20 bits or fewer accepts this event. A relay requiring more than 21 bits rejects it, even though the note is honestly mined, because 21 is still short of the higher bar.</p>217 <p>The <code>OK</code> message reports the outcome using the <code>pow</code> prefix defined in <a href="01.html">NIP-01</a>:</p>218 <div class="crt">219 <div class="titlebar">OK message - pow status prefix</div>220<pre><span class="recv">← ["OK", "000006d8c378af1779d2feebc7603a125d99eca0ccf1085959b307f64e5dd358", true, "pow: difficulty 25>=24"]</span>221<span class="recv">← ["OK", "000006d8c378af1779d2feebc7603a125d99eca0ccf1085959b307f64e5dd358", false, "pow: difficulty 26 is less than 30"]</span></pre>222 </div>223224 <h2 class="bar" id="history"><span class="num">7</span> Version History</h2>225 <p>NIP-13 has changed little since William Casarin first proposed it. Notable changes, newest first:</p>226 <ul class="patchnotes">227 <li><span class="ver">2025</span><span class="when">2025-12</span>mattn added the <code>relay</code> applicability tag, making explicit that relays are expected to enforce this NIP.</li>228 <li class="minor"><span class="ver">2024</span><span class="when">2024-09</span>Jon Staab reverted a change to the example code.</li>229 <li><span class="ver">2024</span><span class="when">2024-08</span>fiatjaf removed a section describing how to query relays by PoW prefix, narrowing this NIP to mining and validation only.</li>230 <li><span class="ver">2024</span><span class="when">2024-05</span>Václav Navrátil fixed the worked example so its <code>id</code> and <code>sig</code> actually verify against the stated fields.</li>231 <li class="minor"><span class="ver">2023</span><span class="when">2023-08 - 2023-11</span>Repo-wide passes: swept in alongside the <a href="01.html">NIP-01</a> merge of NIP-12/16/20/33, removed the per-file author byline, and reformatted JSON examples.</li>232 <li><span class="ver">2023</span><span class="when">2023-04</span>arkin0x corrected the worked mining example and its initial-nonce explanation.</li>233 <li class="minor"><span class="ver">2022</span><span class="when">2022-12 - 2023-04</span>sgmoore and vivganes fixed grammar and typos.</li>234 <li><span class="ver">Origin</span><span class="when">2022-05-05</span>William Casarin (jb55) published NIP-13, "Proof of Work."</li>235 </ul>236237 <div class="credits">238 <h3 class="cardhead">Original Proposal - Credits</h3>239 <table>240 <tr><td>Author</td><td>William Casarin</td></tr>241 <tr><td>First commit</td><td>2022-05-05 — “Proof of Work”</td></tr>242 <tr><td>Status</td><td>draft - optional — relays and clients may enforce it</td></tr>243 <tr><td>Source</td><td><a href="https://github.com/nostr-protocol/nips/blob/master/13.md">13.md on GitHub</a> - <a href="https://github.com/nostr-protocol/nips/commits/master/13.md">full change history</a></td></tr>244 </table>245 </div>246247 <h2 class="bar"><span class="num">8</span> See Also</h2>248 <ul>249 <li><a href="01.html">NIP-01</a> — the event <code>id</code> and serialization rule this NIP hashes for leading zero bits, and the <code>pow</code> status prefix in <code>OK</code>/<code>CLOSED</code> messages.</li>250 <li><a href="11.html">NIP-11</a> — the relay information document; its <code>min_pow_difficulty</code> field tells clients the minimum difficulty a relay requires.</li>251 <li><a href="42.html">NIP-42</a> — client authentication, often combined with PoW for stronger spam control.</li>252 </ul>253 </div>254255 <aside>256 <div class="cartridge">257 <div class="inner">258 <h3 class="cardhead">Spec Card</h3>259 <div class="lights"><span class="led on"></span><span class="led on"></span><span class="led on"></span></div>260 <dl>261 <dt>Status</dt><dd><span class="chip draft">draft</span><span class="chip optional">optional</span></dd>262 <dt>Defines</dt><dd>difficulty (leading zero bits of id) - nonce tag - pow OK/CLOSED prefix (usage)</dd>263 <dt>Kind(s)</dt><dd>none — applies to any event kind via the nonce tag</dd>264 <dt>Requires</dt><dd><a href="01.html">NIP-01</a> event id and serialization</dd>265 <dt>Pairs with</dt><dd><a href="11.html">NIP-11</a> min_pow_difficulty</dd>266 <dt>Transport</dt><dd>none — local computation, checked when a relay receives EVENT</dd>267 <dt>Crypto</dt><dd>sha256 (reuses the NIP-01 id hash)</dd>268 <dt>First commit</dt><dd>2022-05-05</dd>269 <dt>Last updated</dt><dd>2025-12-24</dd>270 </dl>271 </div>272 </div>273 </aside>274 </main>275276 <nav class="navbtns">277 <a href="12.html">◀ NIP-12: Generic Tag Queries</a>278 <a href="14.html">NIP-14: Subject Tag in Text Events ▶</a>279 </nav>280281 <footer class="pagefoot">282 <a href="../index.html">Nostr Protocol Manual</a>283 <span class="pageno">NIP 13 / F4</span>284 </footer>285</div>286287<script src="../assets/webmcp.js" defer></script>288</body>289</html>