clone

every nostr nip as a chapter of an illustrated, early-2000s printed game manual

main
nip.guide / source-nips / 13.md
13.md 3.7K rendered
1NIP-132======34Proof of Work5-------------67`draft` `optional` `relay`89This NIP defines a way to generate and interpret Proof of Work for nostr notes. Proof of Work (PoW) is a way to add a proof of computational work to a note. This is a bearer proof that all relays and clients can universally validate with a small amount of code. This proof can be used as a means of spam deterrence.1011`difficulty` is defined to be the number of leading zero bits in the `NIP-01` id. For example, an id of `000000000e9d97a1ab09fc381030b346cdd7a142ad57e6df0b46dc9bef6c7e2d` has a difficulty of `36` with `36` leading 0 bits.1213`002f...` is `0000 0000 0010 1111...` in binary, which has 10 leading zeroes. Do not forget to count leading zeroes for hex digits <= `7`.1415Mining16------1718To generate PoW for a `NIP-01` note, a `nonce` tag is used:1920```json21{"content": "It's just me mining my own business", "tags": [["nonce", "1", "21"]]}22```2324When mining, the second entry to the nonce tag is updated, and then the id is recalculated (see [NIP-01](./01.md)). If the id has the desired number of leading zero bits, the note has been mined. It is recommended to update the `created_at` as well during this process.2526The third entry to the nonce tag `SHOULD` contain the target difficulty. This allows clients to protect against situations where bulk spammers targeting a lower difficulty get lucky and match a higher difficulty. For example, if you require 40 bits to reply to your thread and see a committed target of 30, you can safely reject it even if the note has 40 bits difficulty. Without a committed target difficulty you could not reject it. Committing to a target difficulty is something all honest miners should be ok with, and clients `MAY` reject a note matching a target difficulty if it is missing a difficulty commitment.2728Example mined note29------------------3031```json32{33 "id": "000006d8c378af1779d2feebc7603a125d99eca0ccf1085959b307f64e5dd358",34 "pubkey": "a48380f4cfcc1ad5378294fcac36439770f9c878dd880ffa94bb74ea54a6f243",35 "created_at": 1651794653,36 "kind": 1,37 "tags": [38 ["nonce", "776797", "20"]39 ],40 "content": "It's just me mining my own business",41 "sig": "284622fc0a3f4f1303455d5175f7ba962a3300d136085b9566801bc2e0699de0c7e31e44c81fb40ad9049173742e904713c3594a1da0fc5d2382a25c11aba977"42}43```4445Validating46----------4748Here is some reference C code for calculating the difficulty (aka number of leading zero bits) in a nostr event id:4950```c51int zero_bits(unsigned char b)52{53 int n = 0;5455 if (b == 0)56 return 8;5758 while (b >>= 1)59 n++;6061 return 7-n;62}6364/* find the number of leading zero bits in a hash */65int count_leading_zero_bits(unsigned char *hash)66{67 int bits, total, i;68 for (i = 0, total = 0; i < 32; i++) {69 bits = zero_bits(hash[i]);70 total += bits;71 if (bits != 8)72 break;73 }74 return total;75}76```7778Here is some JavaScript code for doing the same thing:7980```javascript81// hex should be a hexadecimal string (with no 0x prefix)82function countLeadingZeroes(hex) {83 let count = 0;8485 for (let i = 0; i < hex.length; i++) {86 const nibble = parseInt(hex[i], 16);87 if (nibble === 0) {88 count += 4;89 } else {90 count += Math.clz32(nibble) - 28;91 break;92 }93 }9495 return count;96}97```9899Delegated Proof of Work100-----------------------101102Since the `NIP-01` note id does not commit to any signature, PoW can be outsourced to PoW providers, perhaps for a fee. This provides a way for clients to get their messages out to PoW-restricted relays without having to do any work themselves, which is useful for energy-constrained devices like mobile phones.