@smartledger/bsv 8.2.0 → 8.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,261 @@
1
+ 'use strict'
2
+
3
+ var Script = require('../script/script')
4
+ var Opcode = require('../opcode')
5
+ var Hash = require('../crypto/hash')
6
+ var $ = require('../util/preconditions')
7
+
8
+ /**
9
+ * BRC-220 on-chain record: an `OP_FALSE OP_RETURN` safe data output.
10
+ *
11
+ * full (mode 0): "NOTARYHASH" | u8(1) | u8(0) | algorithm | hashAlgorithm |
12
+ * payloadHash | proofHash | publicKey | signature
13
+ * hybrid (mode 1): as full, but the last two pushes are SHA-256 of each
14
+ * batch (kind 2): "NOTARYHASH" | u8(1) | u8(2) | merkleRoot(32) | u32be(leafCount)
15
+ *
16
+ * NOTE the framing differs from the canonical proof bytes on purpose. Those use
17
+ * `lp(x) = u32be(len(x)) || x` because they are one flat byte string; here each field is
18
+ * its own SCRIPT PUSH, and the push opcode already carries the length. Applying `lp()`
19
+ * again would double-encode every field. Both achieve unambiguous boundaries; only one is
20
+ * correct in each place.
21
+ */
22
+
23
+ var NotaryScript = {}
24
+
25
+ /** Push index 0. Ten ASCII bytes; the spec states no length, the literal is the spec. */
26
+ NotaryScript.PREFIX = 'NOTARYHASH'
27
+
28
+ /** Push index 1. */
29
+ NotaryScript.VERSION = 1
30
+
31
+ /** Push index 2 — the byte that discriminates the layout. */
32
+ NotaryScript.MODE = {
33
+ FULL: 0,
34
+ HYBRID: 1,
35
+ BATCH: 2
36
+ }
37
+
38
+ function u8 (n) { return Buffer.from([n]) }
39
+
40
+ function u32be (n) {
41
+ var b = Buffer.alloc(4)
42
+ b.writeUInt32BE(n, 0)
43
+ return b
44
+ }
45
+
46
+ function requireBytes (value, name, length) {
47
+ if (!Buffer.isBuffer(value)) {
48
+ throw new Error(name + ' must be a Buffer of raw bytes, not ' + (typeof value) +
49
+ '. Decode hex with Buffer.from(hex, \'hex\') first.')
50
+ }
51
+ if (length != null && value.length !== length) {
52
+ throw new Error(name + ' must be exactly ' + length + ' bytes, got ' + value.length)
53
+ }
54
+ return value
55
+ }
56
+
57
+ /**
58
+ * Read a push that carries a single unsigned byte.
59
+ *
60
+ * A 1-byte data push is what this library emits and what the spec's `u8(...)` describes.
61
+ * `OP_0` and `OP_1`–`OP_16` are ALSO accepted, because a builder that minimally encodes
62
+ * its pushes — which is the default in several Bitcoin libraries — represents the same
63
+ * values that way, and rejecting those would reject records that are otherwise perfectly
64
+ * conformant. Being strict here would buy nothing: the mode byte is a routing hint, and
65
+ * every field that matters is checked on its own terms further down.
66
+ *
67
+ * @private
68
+ */
69
+ function readU8 (chunk, name) {
70
+ if (chunk.buf && chunk.buf.length === 1) return chunk.buf[0]
71
+ if (chunk.opcodenum === Opcode.OP_0) return 0
72
+ if (chunk.opcodenum >= Opcode.OP_1 && chunk.opcodenum <= Opcode.OP_16) {
73
+ return chunk.opcodenum - Opcode.OP_1 + 1
74
+ }
75
+ throw new Error(name + ' must be a single byte at this push')
76
+ }
77
+
78
+ function readBuf (chunk, name) {
79
+ if (!chunk || !chunk.buf) throw new Error(name + ' push is missing or carries no data')
80
+ return chunk.buf
81
+ }
82
+
83
+ /**
84
+ * Build the on-chain record.
85
+ *
86
+ * `publicKey` and `signature` are always supplied in FULL form, whatever the mode. In
87
+ * hybrid mode this function hashes them itself rather than accepting pre-hashed values —
88
+ * a caller who passed an already-hashed blob would produce a record that looks right and
89
+ * cannot be reconciled with the certificate, and nothing downstream would notice.
90
+ *
91
+ * @param {Object} record
92
+ * @param {Number} record.mode - NotaryScript.MODE.*
93
+ * @param {String} record.algorithm - full/hybrid
94
+ * @param {String} record.hashAlgorithm - full/hybrid
95
+ * @param {Buffer} record.payloadHash - full/hybrid, 32 bytes
96
+ * @param {Buffer} record.proofHash - full/hybrid, 32 bytes
97
+ * @param {Buffer} record.publicKey - full/hybrid, raw bytes
98
+ * @param {Buffer} record.signature - full/hybrid, raw bytes
99
+ * @param {Buffer} record.merkleRoot - batch, 32 bytes
100
+ * @param {Number} record.leafCount - batch
101
+ * @returns {Script}
102
+ */
103
+ NotaryScript.build = function (record) {
104
+ $.checkArgument(record && typeof record === 'object', 'record is required')
105
+
106
+ var mode = record.mode
107
+ $.checkArgument(mode === NotaryScript.MODE.FULL ||
108
+ mode === NotaryScript.MODE.HYBRID ||
109
+ mode === NotaryScript.MODE.BATCH,
110
+ 'mode must be 0 (full), 1 (hybrid) or 2 (batch)')
111
+
112
+ var script = new Script()
113
+ .add(Opcode.OP_FALSE)
114
+ .add(Opcode.OP_RETURN)
115
+ .add(Buffer.from(NotaryScript.PREFIX, 'ascii'))
116
+ .add(u8(NotaryScript.VERSION))
117
+ .add(u8(mode))
118
+
119
+ if (mode === NotaryScript.MODE.BATCH) {
120
+ $.checkArgument(typeof record.leafCount === 'number' && Number.isInteger(record.leafCount) &&
121
+ record.leafCount >= 0, 'leafCount must be a non-negative integer')
122
+ script.add(requireBytes(record.merkleRoot, 'merkleRoot', 32))
123
+ script.add(u32be(record.leafCount))
124
+ return script
125
+ }
126
+
127
+ $.checkArgument(typeof record.algorithm === 'string' && record.algorithm.length > 0,
128
+ 'algorithm must be a non-empty string')
129
+ $.checkArgument(typeof record.hashAlgorithm === 'string' && record.hashAlgorithm.length > 0,
130
+ 'hashAlgorithm must be a non-empty string')
131
+
132
+ script.add(Buffer.from(record.algorithm, 'utf8'))
133
+ script.add(Buffer.from(record.hashAlgorithm, 'utf8'))
134
+ script.add(requireBytes(record.payloadHash, 'payloadHash', 32))
135
+ script.add(requireBytes(record.proofHash, 'proofHash', 32))
136
+
137
+ var publicKey = requireBytes(record.publicKey, 'publicKey')
138
+ var signature = requireBytes(record.signature, 'signature')
139
+
140
+ if (mode === NotaryScript.MODE.HYBRID) {
141
+ script.add(Hash.sha256(publicKey))
142
+ script.add(Hash.sha256(signature))
143
+ } else {
144
+ script.add(publicKey)
145
+ script.add(signature)
146
+ }
147
+
148
+ return script
149
+ }
150
+
151
+ /**
152
+ * Parse an on-chain record.
153
+ *
154
+ * Returns a plain object, or throws with a message naming what was wrong. It never
155
+ * returns a partially-populated result: a caller that cannot distinguish "parsed" from
156
+ * "parsed some of it" is the shape that produces confident wrong answers.
157
+ *
158
+ * In hybrid mode the returned `publicKeyHash` / `signatureHash` are the on-chain digests;
159
+ * the full blobs live only in the certificate, and reconciling the two is the caller's
160
+ * job.
161
+ *
162
+ * @param {Script|String} script
163
+ * @returns {Object}
164
+ */
165
+ NotaryScript.parse = function (script) {
166
+ if (typeof script === 'string') script = Script.fromHex(script)
167
+ $.checkArgument(script instanceof Script, 'script must be a Script or hex string')
168
+
169
+ var chunks = script.chunks
170
+
171
+ if (chunks.length < 5) {
172
+ throw new Error('not a NotaryHash record: too few pushes')
173
+ }
174
+ if (chunks[0].opcodenum !== Opcode.OP_FALSE && chunks[0].opcodenum !== Opcode.OP_0) {
175
+ throw new Error('not a NotaryHash record: does not start with OP_FALSE')
176
+ }
177
+ if (chunks[1].opcodenum !== Opcode.OP_RETURN) {
178
+ throw new Error('not a NotaryHash record: no OP_RETURN')
179
+ }
180
+
181
+ var prefix = readBuf(chunks[2], 'prefix')
182
+ if (prefix.toString('ascii') !== NotaryScript.PREFIX) {
183
+ throw new Error('not a NotaryHash record: prefix is ' + JSON.stringify(prefix.toString('ascii')))
184
+ }
185
+
186
+ var version = readU8(chunks[3], 'version')
187
+ if (version !== NotaryScript.VERSION) {
188
+ throw new Error('unsupported NotaryHash version: ' + version)
189
+ }
190
+
191
+ var mode = readU8(chunks[4], 'mode')
192
+
193
+ if (mode === NotaryScript.MODE.BATCH) {
194
+ if (chunks.length !== 7) {
195
+ throw new Error('batch record must have exactly 7 pushes, got ' + chunks.length)
196
+ }
197
+ var leafCountBuf = readBuf(chunks[6], 'leafCount')
198
+ if (leafCountBuf.length !== 4) {
199
+ throw new Error('leafCount must be 4 bytes (u32be), got ' + leafCountBuf.length)
200
+ }
201
+ return {
202
+ mode: mode,
203
+ version: version,
204
+ merkleRoot: requireBytes(readBuf(chunks[5], 'merkleRoot'), 'merkleRoot', 32),
205
+ leafCount: leafCountBuf.readUInt32BE(0)
206
+ }
207
+ }
208
+
209
+ if (mode !== NotaryScript.MODE.FULL && mode !== NotaryScript.MODE.HYBRID) {
210
+ throw new Error('unknown NotaryHash mode: ' + mode)
211
+ }
212
+
213
+ if (chunks.length !== 11) {
214
+ throw new Error('full/hybrid record must have exactly 11 pushes, got ' + chunks.length)
215
+ }
216
+
217
+ var parsed = {
218
+ mode: mode,
219
+ version: version,
220
+ algorithm: readBuf(chunks[5], 'algorithm').toString('utf8'),
221
+ hashAlgorithm: readBuf(chunks[6], 'hashAlgorithm').toString('utf8'),
222
+ payloadHash: requireBytes(readBuf(chunks[7], 'payloadHash'), 'payloadHash', 32),
223
+ proofHash: requireBytes(readBuf(chunks[8], 'proofHash'), 'proofHash', 32)
224
+ }
225
+
226
+ if (mode === NotaryScript.MODE.HYBRID) {
227
+ parsed.publicKeyHash = requireBytes(readBuf(chunks[9], 'publicKeyHash'), 'publicKeyHash', 32)
228
+ parsed.signatureHash = requireBytes(readBuf(chunks[10], 'signatureHash'), 'signatureHash', 32)
229
+ } else {
230
+ parsed.publicKey = readBuf(chunks[9], 'publicKey')
231
+ parsed.signature = readBuf(chunks[10], 'signature')
232
+ }
233
+
234
+ return parsed
235
+ }
236
+
237
+ /**
238
+ * Does this script look like a NotaryHash record?
239
+ *
240
+ * Strictly a cheap filter for scanning outputs — a true result means `parse()` is worth
241
+ * attempting, NOT that the record is well-formed. Anything that acts on the contents must
242
+ * call `parse()` and handle its errors.
243
+ *
244
+ * @param {Script|String} script
245
+ * @returns {Boolean}
246
+ */
247
+ NotaryScript.isNotaryHash = function (script) {
248
+ try {
249
+ if (typeof script === 'string') script = Script.fromHex(script)
250
+ var c = script.chunks
251
+ return c.length >= 5 &&
252
+ (c[0].opcodenum === Opcode.OP_FALSE || c[0].opcodenum === Opcode.OP_0) &&
253
+ c[1].opcodenum === Opcode.OP_RETURN &&
254
+ !!c[2].buf &&
255
+ c[2].buf.toString('ascii') === NotaryScript.PREFIX
256
+ } catch (e) {
257
+ return false
258
+ }
259
+ }
260
+
261
+ module.exports = NotaryScript
@@ -0,0 +1,172 @@
1
+ 'use strict'
2
+
3
+ var BN = require('../crypto/bn')
4
+ var ECDSA = require('../crypto/ecdsa')
5
+ var Signature = require('../crypto/signature')
6
+ var PublicKey = require('../publickey')
7
+ var Point = require('../crypto/point')
8
+ var $ = require('../util/preconditions')
9
+
10
+ /**
11
+ * Signature suites, keyed on the `algorithm` string BRC-220 already carries.
12
+ *
13
+ * `ECDSA-secp256k1` is registered here and needs nothing new. ML-DSA and SLH-DSA are NOT
14
+ * built in, and that is deliberate rather than unfinished:
15
+ *
16
+ * @noble/post-quantum is the one Noble package with no independent audit -- its README
17
+ * says so -- and it is 0.x, 669 KB, and does not claim constant-time execution. This
18
+ * library's other primitives carry a published Cure53 audit, which is what lets
19
+ * docs/AUDIT_SCOPE.md tell a vendor not to price the primitive layer. Making an
20
+ * unaudited implementation a hard dependency of a transaction-signing library would
21
+ * forfeit that for a capability the spec does not require: ECDSA-secp256k1 is a
22
+ * first-class algorithm alongside the post-quantum ones, so an ECDSA-only
23
+ * implementation is conformant.
24
+ *
25
+ * So post-quantum suites are supplied by the caller -- most obviously from
26
+ * @smartledger/keys, which already wraps @noble/post-quantum -- and callers who do not
27
+ * need them pay nothing in bundle size or audit surface. See docs/BRC220_PLAN.md §2.
28
+ */
29
+
30
+ var Suites = {}
31
+
32
+ var registry = {}
33
+
34
+ /**
35
+ * Register a signature suite.
36
+ *
37
+ * `verify` MUST return a strict boolean. A suite returning a truthy object would make
38
+ * every signature check pass, which is the single defect class this codebase has had to
39
+ * fix most often -- so the registry enforces it at call time rather than trusting the
40
+ * suite.
41
+ *
42
+ * @param {String} algorithm - e.g. 'ML-DSA-65'
43
+ * @param {Object} suite
44
+ * @param {Function} suite.verify - (payloadHash: Buffer, signature: Buffer, publicKey: Buffer) => boolean
45
+ */
46
+ Suites.register = function (algorithm, suite) {
47
+ $.checkArgument(typeof algorithm === 'string' && algorithm.length > 0,
48
+ 'algorithm must be a non-empty string')
49
+ $.checkArgument(suite && typeof suite.verify === 'function',
50
+ 'suite must provide a verify(payloadHash, signature, publicKey) function')
51
+ registry[algorithm] = suite
52
+ return Suites
53
+ }
54
+
55
+ /** @returns {Object|undefined} */
56
+ Suites.get = function (algorithm) {
57
+ return registry[algorithm]
58
+ }
59
+
60
+ /** @returns {Array<String>} registered algorithm identifiers */
61
+ Suites.list = function () {
62
+ return Object.keys(registry).sort()
63
+ }
64
+
65
+ /** Test seam. */
66
+ Suites.unregister = function (algorithm) {
67
+ delete registry[algorithm]
68
+ return Suites
69
+ }
70
+
71
+ /**
72
+ * Verify a signature under the named suite.
73
+ *
74
+ * An UNREGISTERED algorithm returns false. It does not fall through to a default, and it
75
+ * does not throw: a certificate naming an algorithm this process cannot check has not
76
+ * been verified, and `false` is the honest answer. Falling through to ECDSA for an
77
+ * `ML-DSA-65` certificate would be catastrophic and is exactly what a default invites.
78
+ *
79
+ * The suite's own return value is coerced with `=== true`, so a suite that returns a
80
+ * truthy object cannot smuggle a pass through.
81
+ *
82
+ * @param {String} algorithm
83
+ * @param {Buffer} payloadHash - the 32 bytes that were signed
84
+ * @param {Buffer} signature
85
+ * @param {Buffer} publicKey
86
+ * @returns {Boolean}
87
+ */
88
+ Suites.verify = function (algorithm, payloadHash, signature, publicKey) {
89
+ var suite = registry[algorithm]
90
+ if (!suite) return false
91
+ if (!Buffer.isBuffer(payloadHash) || !Buffer.isBuffer(signature) || !Buffer.isBuffer(publicKey)) {
92
+ return false
93
+ }
94
+ try {
95
+ return suite.verify(payloadHash, signature, publicKey) === true
96
+ } catch (e) {
97
+ return false
98
+ }
99
+ }
100
+
101
+ /**
102
+ * ECDSA over secp256k1.
103
+ *
104
+ * The signer signs the 32-byte `payloadHash` DIRECTLY (spec §Algorithms: "post-quantum
105
+ * schemes apply their own internal hashing"). There is no second hash, and no Bitcoin
106
+ * sighash — this is a detached signature over a digest.
107
+ *
108
+ * Signatures are 64 raw bytes, `r || s`, each a 32-byte big-endian integer. DER is
109
+ * accepted as a length-discriminated fallback for Bitcoin-native signers, because the
110
+ * certificate's `encoding` field may say so; see docs/BRC220_ENCODING_AMENDMENT.md for
111
+ * why raw is what new implementations should emit.
112
+ *
113
+ * Low-S is REQUIRED. A high-S signature is rejected rather than normalised: normalising
114
+ * changes the signature bytes, and those bytes are inside `proofHash`, so accepting both
115
+ * forms would mean two valid certificates exist for one signing act.
116
+ */
117
+ Suites.register('ECDSA-secp256k1', {
118
+ verify: function (payloadHash, signature, publicKey) {
119
+ if (payloadHash.length !== 32) return false
120
+
121
+ var sig
122
+ if (signature.length === 64) {
123
+ sig = new Signature(
124
+ BN.fromBuffer(signature.slice(0, 32)),
125
+ BN.fromBuffer(signature.slice(32, 64))
126
+ )
127
+ } else {
128
+ // DER, for the legacy `encoding: "der"` case.
129
+ try {
130
+ sig = Signature.fromDER(signature)
131
+ } catch (e) {
132
+ return false
133
+ }
134
+ }
135
+
136
+ // Low-S, enforced rather than normalised.
137
+ var halfOrder = Point.getN().div(new BN(2))
138
+ if (sig.s.gt(halfOrder)) return false
139
+
140
+ var pubkey
141
+ try {
142
+ pubkey = PublicKey.fromBuffer(publicKey)
143
+ } catch (e) {
144
+ return false
145
+ }
146
+
147
+ var ecdsa = new ECDSA()
148
+ ecdsa.hashbuf = payloadHash
149
+ // NO endian override. `payloadHash` is the scalar, big-endian, exactly as the
150
+ // 32 bytes are given — which is what every other ECDSA implementation does and
151
+ // what BRC-220 means by "signs the payloadHash".
152
+ //
153
+ // 8.3.0 set `endian = 'little'` here, which made ECDSA reverse the digest before
154
+ // reducing it to the scalar. That is Bitcoin's message-signing convention, not
155
+ // this protocol's, and it is why lib/crypto/ecdsa.js offers the option at all.
156
+ //
157
+ // The effect was on the VERIFY side: a signature produced the way BRC-220
158
+ // specifies was rejected, and the only signatures accepted were ones made with
159
+ // bsv's own little-endian convention. Every test in this repo signed that way
160
+ // too, so the module and its tests were self-consistent and wrong together —
161
+ // the exact failure shape test/notaryhash/encoding.js warns about in its header.
162
+ //
163
+ // test/notaryhash/interop.js now pins this against @noble/curves, which shares
164
+ // no verification code with lib/crypto/ecdsa.js. A second implementation is the
165
+ // only thing that can catch a defect where the code and its tests agree.
166
+ ecdsa.pubkey = pubkey
167
+ ecdsa.sig = sig
168
+ return ecdsa.verify() === true
169
+ }
170
+ })
171
+
172
+ module.exports = Suites
@@ -0,0 +1,75 @@
1
+ 'use strict'
2
+
3
+ /**
4
+ * RFC 8785 — JSON Canonicalization Scheme.
5
+ *
6
+ * Extracted from lib/gdaf/attestation-signer.js, where it was added in 8.2.0. Two
7
+ * unrelated things now need it — GDAF credential signatures and BRC-220 certificates —
8
+ * and a notarization module reaching into the credentials module for it would be the
9
+ * wrong direction. JCS is a general serialization concern, not a GDAF concept.
10
+ *
11
+ * The behaviour is unchanged; `AttestationSigner._canonicalizeJCS` delegates here.
12
+ *
13
+ * The point of JCS is that two independent implementations produce identical bytes, so
14
+ * everything below is fixed by the RFC rather than by local preference:
15
+ *
16
+ * - Object keys sort by UTF-16 code unit, which is what Array.prototype.sort already
17
+ * does for strings. The sort is applied DURING serialization rather than by
18
+ * rebuilding an object, because V8 orders integer-like own properties numerically
19
+ * ahead of string keys and would silently undo it — `{"2":…,"10":…}` where the RFC
20
+ * requires `{"10":…,"2":…}`. That was a real defect in this codebase before 8.2.0.
21
+ * - JSON.stringify supplies the leaf types deliberately: for finite numbers it produces
22
+ * ECMAScript Number::toString, which the RFC mandates, and since ES2019 it emits
23
+ * well-formed output for lone surrogates. Both are easy to get subtly wrong by hand.
24
+ * - Non-finite numbers throw rather than serializing as `null`, which is what
25
+ * JSON.stringify does and which would silently canonicalize a different document than
26
+ * the one supplied.
27
+ */
28
+
29
+ var JCS = {}
30
+
31
+ /**
32
+ * Serialize a value as RFC 8785 canonical JSON.
33
+ *
34
+ * @param {*} value
35
+ * @returns {String}
36
+ */
37
+ JCS.stringify = function (value) {
38
+ if (value === null) return 'null'
39
+
40
+ var type = typeof value
41
+
42
+ if (type === 'boolean') return value ? 'true' : 'false'
43
+
44
+ if (type === 'number') {
45
+ if (!isFinite(value)) {
46
+ throw new Error('Cannot canonicalize non-finite number: ' + value)
47
+ }
48
+ return JSON.stringify(value)
49
+ }
50
+
51
+ if (type === 'string') return JSON.stringify(value)
52
+
53
+ if (Array.isArray(value)) {
54
+ // Arrays are order-significant. `undefined` has no JSON form and becomes null in an
55
+ // array, matching JSON.stringify.
56
+ return '[' + value.map(function (item) {
57
+ return item === undefined ? 'null' : JCS.stringify(item)
58
+ }).join(',') + ']'
59
+ }
60
+
61
+ if (type === 'object') {
62
+ // Absent and explicitly-undefined are indistinguishable in JSON, so both are dropped.
63
+ var keys = Object.keys(value).filter(function (key) {
64
+ return value[key] !== undefined && typeof value[key] !== 'function'
65
+ }).sort()
66
+
67
+ return '{' + keys.map(function (key) {
68
+ return JSON.stringify(key) + ':' + JCS.stringify(value[key])
69
+ }).join(',') + '}'
70
+ }
71
+
72
+ throw new Error('Cannot canonicalize value of type: ' + type)
73
+ }
74
+
75
+ module.exports = JCS
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smartledger/bsv",
3
- "version": "8.2.0",
3
+ "version": "8.3.1",
4
4
  "description": "🚀 Complete Bitcoin SV development framework with legally-recognizable DID:web + W3C VC-JWT toolkit, Legal Token Protocol (LTP), Global Digital Attestation Framework (GDAF), StatusList2021 revocation, and 16 flexible loading options. Standards-based credentials with ES256/ES256K support, on-chain BSV anchoring, and comprehensive Bitcoin SV API. Perfect for legal tokens, verifiable credentials, DeFi, smart contracts, and secure Bitcoin applications.",
5
5
  "author": "SmartLedger Technology <hello@smartledger.technology> (https://smartledger.technology)",
6
6
  "homepage": "https://github.com/codenlighten/smartledger-bsv#readme",
@@ -39,6 +39,7 @@
39
39
  "./lib/ltp": "./lib/ltp/index.js",
40
40
  "./lib/message": "./lib/message/index.js",
41
41
  "./lib/mnemonic": "./lib/mnemonic/index.js",
42
+ "./lib/notaryhash": "./lib/notaryhash/index.js",
42
43
  "./lib/ordinals": "./lib/ordinals/index.js",
43
44
  "./lib/script": "./lib/script/index.js",
44
45
  "./lib/smart_contract": "./lib/smart_contract/index.js",
@@ -64,6 +65,7 @@
64
65
  "vectors:sv-tx": "node tools/sv-tx-report.js",
65
66
  "vectors:sv-sighash": "node tools/sv-sighash-report.js",
66
67
  "conformance:generate": "node conformance/generate.js",
68
+ "check:readme": "node scripts/check-readme-accuracy.js",
67
69
  "lint:ratchet": "node scripts/lint-ratchet.js",
68
70
  "lint:ratchet:update": "node scripts/lint-ratchet.js --update",
69
71
  "test": "mocha",
@@ -96,7 +98,7 @@
96
98
  "test:browser": "echo 'Open tests/standalone-modules-test.html in browser for comprehensive testing'",
97
99
  "test:bundle": "echo 'Open tests/bundle-completeness-test.html in browser to verify bundle completeness'",
98
100
  "preimage:extract": "node examples/preimage/extract_preimage_bidirectional.js",
99
- "prepublishOnly": "npm run build-all",
101
+ "prepublishOnly": "npm run build-all && npm run check:readme",
100
102
  "sync-cdn": "node scripts/sync-cdn-urls.js",
101
103
  "version": "node scripts/sync-cdn-urls.js && node scripts/sync-version.js && node scripts/gen-esm-wrapper.js && git add README.md docs version.js index.mjs",
102
104
  "test:browser:ci": "node tests/browser-smoke-runner.js"
@@ -231,9 +233,9 @@
231
233
  "request": "browser-request"
232
234
  },
233
235
  "dependencies": {
234
- "@noble/ciphers": "2.2.0",
235
- "@noble/curves": "2.2.0",
236
- "@noble/hashes": "2.2.0",
236
+ "@noble/ciphers": "^2.3.0",
237
+ "@noble/curves": "^2.3.0",
238
+ "@noble/hashes": "^2.3.0",
237
239
  "bn.js": "=4.12.5",
238
240
  "secrets.js-grempe": "^2.0.0"
239
241
  },
@@ -277,7 +279,8 @@
277
279
  "beforeEach",
278
280
  "describe",
279
281
  "it",
280
- "globalThis"
282
+ "globalThis",
283
+ "BigInt"
281
284
  ],
282
285
  "ignore": [
283
286
  "dist/**",