From a05506468dc1fb3ffe98161f5c8e130f1d2ec811 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 11 Apr 2023 15:49:08 -0500 Subject: [PATCH] Add NIP-13 (proof-of-work) module --- index.ts | 1 + nip13.test.js | 8 ++++++++ nip13.ts | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 nip13.test.js create mode 100644 nip13.ts diff --git a/index.ts b/index.ts index 0295f02..8f45843 100644 --- a/index.ts +++ b/index.ts @@ -9,6 +9,7 @@ export * as nip04 from './nip04' export * as nip05 from './nip05' export * as nip06 from './nip06' export * as nip10 from './nip10' +export * as nip13 from './nip13' export * as nip19 from './nip19' export * as nip26 from './nip26' export * as nip39 from './nip39' diff --git a/nip13.test.js b/nip13.test.js new file mode 100644 index 0000000..9f23fab --- /dev/null +++ b/nip13.test.js @@ -0,0 +1,8 @@ +/* eslint-env jest */ +const {nip13} = require('./lib/nostr.cjs') + +test('identifies proof-of-work difficulty', async () => { + const id = '000006d8c378af1779d2feebc7603a125d99eca0ccf1085959b307f64e5dd358' + const difficulty = nip13.getPow(id) + expect(difficulty).toEqual(21) +}) diff --git a/nip13.ts b/nip13.ts new file mode 100644 index 0000000..f96c58b --- /dev/null +++ b/nip13.ts @@ -0,0 +1,42 @@ +import * as secp256k1 from '@noble/secp256k1' + +/** Get POW difficulty from a Nostr hex ID. */ +export function getPow(id: string): number { + return getLeadingZeroBits(secp256k1.utils.hexToBytes(id)) +} + +/** + * Get number of leading 0 bits. Adapted from nostream. + * https://github.com/Cameri/nostream/blob/fb6948fd83ca87ce552f39f9b5eb780ea07e272e/src/utils/proof-of-work.ts + */ +function getLeadingZeroBits(hash: Uint8Array): number { + let total: number, i: number, bits: number + + for (i = 0, total = 0; i < hash.length; i++) { + bits = msb(hash[i]) + total += bits + if (bits !== 8) { + break + } + } + return total +} + +/** + * Adapted from nostream. + * https://github.com/Cameri/nostream/blob/fb6948fd83ca87ce552f39f9b5eb780ea07e272e/src/utils/proof-of-work.ts + */ +function msb(b: number) { + let n = 0 + + if (b === 0) { + return 8 + } + + // eslint-disable-next-line no-cond-assign + while (b >>= 1) { + n++ + } + + return 7 - n +}