1 Overview
Anyone can publish an event to a relay for free. That is a feature of NIP-01, 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.
PoW makes the author spend real computation before an event is valid. The proof lives inside the event's own id, so it is a bearer proof: whoever holds the event can check the proof, with no lookup, no server call, and no extra signature. This NIP defines difficulty as the number of leading zero bits in the event id. More required bits means more expected computation.
PoW is optional. Nothing in NIP-01 requires it. A relay may demand a minimum difficulty before it accepts events, using the min_pow_difficulty field from its NIP-11 information document. A client may demand a minimum difficulty on replies to one of its own threads, to slow down flooding.
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 NIP-42 authentication or a payment requirement.
2 Difficulty
Difficulty is the number of leading zero bits in the id field defined by NIP-01. The id is a 32-byte sha256 hash, written as 64 lowercase hex characters. Count the zero bits from the left, and stop at the first 1 bit.
For example, the id 000000000e9d97a1ab09fc381030b346cdd7a142ad57e6df0b46dc9bef6c7e2d has a difficulty of 36. It has 36 leading zero bits.
Do not just count leading zero hex characters. A hex digit of 7 or less still starts with one or more zero bits. 002f... is 0000 0000 0010 1111... in binary. That is 10 leading zero bits, not 8. Always convert to binary before you count.
3 Mining
To mine PoW for a NIP-01 event, add a nonce tag to it:
{"content": "It's just me mining my own business", "tags": [["nonce", "1", "21"]]}
The nonce tag has this shape:
| Element | Value | Rule |
|---|---|---|
| 0 | "nonce" | Fixed tag name. |
| 1 | nonce value | An arbitrary string. The miner changes this on every attempt. |
| 2 | target difficulty | The difficulty the miner is aiming for. SHOULD be present. See the committed-target rule below. |
To mine, repeat this loop: change the nonce value, serialize the event and compute the id again (following NIP-01), 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 created_at during mining, since the timestamp is part of the serialized data and changing it gives the miner a fresh search space.
4 Validating
A relay or client validates PoW after it already validated the event's signature under NIP-01. Validation has three steps:
- Count the leading zero bits of the event
id, using the binary method from §2. - Compare that count to the difficulty this relay or client requires.
- Check the
noncetag'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.
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 MAY reject any note that matches its target difficulty but carries no difficulty commitment at all.
The OK and CLOSED messages defined in NIP-01 carry a pow prefix for this exact purpose. A relay reports the difficulty it saw and the difficulty it needed, for example "pow: difficulty 25>=24" on acceptance or "pow: difficulty 26 is less than 30" on rejection.
Reference C code for counting leading zero bits in a raw hash:
int zero_bits(unsigned char b)
{
int n = 0;
if (b == 0)
return 8;
while (b >>= 1)
n++;
return 7-n;
}
/* find the number of leading zero bits in a hash */
int count_leading_zero_bits(unsigned char *hash)
{
int bits, total, i;
for (i = 0, total = 0; i < 32; i++) {
bits = zero_bits(hash[i]);
total += bits;
if (bits != 8)
break;
}
return total;
}
The same logic in JavaScript, working on the hex string form of the id:
// hex should be a hexadecimal string (with no 0x prefix)
function countLeadingZeroes(hex) {
let count = 0;
for (let i = 0; i < hex.length; i++) {
const nibble = parseInt(hex[i], 16);
if (nibble === 0) {
count += 4;
} else {
count += Math.clz32(nibble) - 28;
break;
}
}
return count;
}
5 Delegated Proof of Work
The NIP-01 event id does not commit to the sig field. The id only hashes pubkey, created_at, kind, tags, and content. This means PoW can be mined without ever holding the author's private key.
A client can hand its unsigned fields to a separate PoW provider, perhaps for a fee. The provider mines the nonce 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.
6 Worked Example
This is a complete mined event. The nonce value 776797 was the winning attempt; the nonce commits to a target difficulty of 20.
{
"id": "000006d8c378af1779d2feebc7603a125d99eca0ccf1085959b307f64e5dd358",
"pubkey": "a48380f4cfcc1ad5378294fcac36439770f9c878dd880ffa94bb74ea54a6f243",
"created_at": 1651794653,
"kind": 1,
"tags": [
["nonce", "776797", "20"]
],
"content": "It's just me mining my own business",
"sig": "284622fc0a3f4f1303455d5175f7ba962a3300d136085b9566801bc2e0699de0c7e31e44c81fb40ad9049173742e904713c3594a1da0fc5d2382a25c11aba977"
}
Count the leading zero bits of the id to check the proof:
id = 000006d8c378af1779d2feebc7603a125d99eca0ccf1085959b307f64e5dd358
hex = 0 0 0 0 0 6 d 8 ...
└───┬───┘ │
5 zero hex digits = 20 zero bits
6 = 0110 binary → 1 more leading zero bit, then a 1 bit — stop
total difficulty = 20 + 1 = 21 bits
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.
The OK message reports the outcome using the pow prefix defined in NIP-01:
← ["OK", "000006d8c378af1779d2feebc7603a125d99eca0ccf1085959b307f64e5dd358", true, "pow: difficulty 25>=24"] ← ["OK", "000006d8c378af1779d2feebc7603a125d99eca0ccf1085959b307f64e5dd358", false, "pow: difficulty 26 is less than 30"]
7 Version History
NIP-13 has changed little since William Casarin first proposed it. Notable changes, newest first:
- 20252025-12mattn added the
relayapplicability tag, making explicit that relays are expected to enforce this NIP. - 20242024-09Jon Staab reverted a change to the example code.
- 20242024-08fiatjaf removed a section describing how to query relays by PoW prefix, narrowing this NIP to mining and validation only.
- 20242024-05Václav Navrátil fixed the worked example so its
idandsigactually verify against the stated fields. - 20232023-08 - 2023-11Repo-wide passes: swept in alongside the NIP-01 merge of NIP-12/16/20/33, removed the per-file author byline, and reformatted JSON examples.
- 20232023-04arkin0x corrected the worked mining example and its initial-nonce explanation.
- 20222022-12 - 2023-04sgmoore and vivganes fixed grammar and typos.
- Origin2022-05-05William Casarin (jb55) published NIP-13, "Proof of Work."
Original Proposal - Credits
| Author | William Casarin |
| First commit | 2022-05-05 — “Proof of Work” |
| Status | draft - optional — relays and clients may enforce it |
| Source | 13.md on GitHub - full change history |
8 See Also
- NIP-01 — the event
idand serialization rule this NIP hashes for leading zero bits, and thepowstatus prefix inOK/CLOSEDmessages. - NIP-11 — the relay information document; its
min_pow_difficultyfield tells clients the minimum difficulty a relay requires. - NIP-42 — client authentication, often combined with PoW for stronger spam control.