@smartledger/bsv 8.3.1 → 9.1.0

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.
Files changed (169) hide show
  1. package/CHANGELOG.md +228 -0
  2. package/README.md +152 -1031
  3. package/STABILITY.md +134 -0
  4. package/bsv-gdaf.min.js +58 -53
  5. package/bsv-ltp.min.js +23 -18
  6. package/bsv-script-helper.min.js +1 -1
  7. package/bsv-smartcontract.min.js +21 -21
  8. package/bsv.bundle.js +58 -53
  9. package/bsv.d.ts +0 -4
  10. package/bsv.min.js +58 -53
  11. package/docs/BRC220_BATCH_LEAF_AMENDMENT.md +82 -7
  12. package/docs/MODULE_REFERENCE_COMPLETE.md +27 -27
  13. package/docs/README.md +2 -1
  14. package/docs/THREAT_MODEL.md +10 -2
  15. package/docs/advanced/UTXO_MANAGER_GUIDE.md +1 -1
  16. package/docs/getting-started/INSTALLATION.md +23 -23
  17. package/docs/getting-started/QUICK_START.md +7 -7
  18. package/docs/migration/FROM_BSV_1_5_6.md +5 -5
  19. package/docs/proposals/10.0.0-package-split.md +131 -0
  20. package/index.js +15 -26
  21. package/lib/block/merkleblock.js +19 -5
  22. package/lib/covenant/helpers.js +34 -35
  23. package/lib/covenant/pushtx.js +2 -2
  24. package/lib/custom-script-helper.js +0 -16
  25. package/lib/hdprivatekey.js +15 -0
  26. package/lib/ordinals/ordlock.js +1 -1
  27. package/lib/script/interpreter.js +109 -1
  28. package/lib/smart_contract/builder.js +14 -0
  29. package/lib/smart_contract/debugger.js +2 -2
  30. package/lib/smart_contract/dsl.js +2 -2
  31. package/lib/smart_contract/index.js +0 -3
  32. package/lib/smart_contract/locks.js +1 -41
  33. package/lib/smart_contract/pels.js +1 -1
  34. package/lib/smart_contract/token.js +1 -1
  35. package/lib/util/deprecate.js +159 -0
  36. package/package.json +19 -82
  37. package/tools/gen-brc220-batch-vector.js +205 -0
  38. package/version.js +1 -1
  39. package/.mocharc.json +0 -5
  40. package/test/address.js +0 -629
  41. package/test/block/block.js +0 -239
  42. package/test/block/blockheader.js +0 -270
  43. package/test/block/merkleblock.js +0 -207
  44. package/test/build/bundle_crypto_shim.js +0 -104
  45. package/test/build/bundle_externals.js +0 -125
  46. package/test/build/bundle_smoke.js +0 -55
  47. package/test/build/esbuild_main.js +0 -65
  48. package/test/build/esm_wrapper.js +0 -73
  49. package/test/build/exports_resolution.js +0 -84
  50. package/test/build/version_sync.js +0 -14
  51. package/test/cli/smoke.js +0 -261
  52. package/test/consensus/base58-vectors.js +0 -120
  53. package/test/consensus/sv-script-vectors.js +0 -81
  54. package/test/consensus/sv-sighash-vectors.js +0 -51
  55. package/test/consensus/sv-tx-vectors.js +0 -48
  56. package/test/credentials-test.js +0 -332
  57. package/test/crypto/backend_selection.js +0 -126
  58. package/test/crypto/bn.js +0 -168
  59. package/test/crypto/ecdsa.js +0 -426
  60. package/test/crypto/elliptic-fixed.js +0 -61
  61. package/test/crypto/hash.browser.js +0 -121
  62. package/test/crypto/hash.js +0 -122
  63. package/test/crypto/point.js +0 -193
  64. package/test/crypto/random.js +0 -105
  65. package/test/crypto/security.js +0 -176
  66. package/test/crypto/shamir.js +0 -177
  67. package/test/crypto/shamir_rngcap.js +0 -29
  68. package/test/crypto/signature.js +0 -399
  69. package/test/data/bip69.json +0 -215
  70. package/test/data/bitcoin-sv/README.md +0 -170
  71. package/test/data/bitcoin-sv/base58_encode_decode.json +0 -14
  72. package/test/data/bitcoin-sv/base58_keys_invalid.json +0 -152
  73. package/test/data/bitcoin-sv/base58_keys_valid.json +0 -452
  74. package/test/data/bitcoin-sv/script_tests.json +0 -2591
  75. package/test/data/bitcoin-sv/sighash.json +0 -1003
  76. package/test/data/bitcoin-sv/tx_invalid.json +0 -285
  77. package/test/data/bitcoin-sv/tx_valid.json +0 -367
  78. package/test/data/bitcoind/base58_keys_invalid.json +0 -152
  79. package/test/data/bitcoind/base58_keys_valid.json +0 -452
  80. package/test/data/bitcoind/blocks.json +0 -27
  81. package/test/data/bitcoind/script_tests.json +0 -2244
  82. package/test/data/bitcoind/sig_canonical.json +0 -7
  83. package/test/data/bitcoind/sig_noncanonical.json +0 -22
  84. package/test/data/bitcoind/tx_invalid.json +0 -177
  85. package/test/data/bitcoind/tx_valid.json +0 -224
  86. package/test/data/blk86756-testnet.dat +0 -0
  87. package/test/data/blk86756-testnet.js +0 -12
  88. package/test/data/blk86756-testnet.json +0 -684
  89. package/test/data/ecdsa.json +0 -230
  90. package/test/data/merkleblocks.js +0 -486
  91. package/test/data/messages.json +0 -22
  92. package/test/data/sighash.json +0 -1004
  93. package/test/data/tx_creation.json +0 -85
  94. package/test/didweb/relationships.js +0 -144
  95. package/test/ecies/bitcore-ecies.js +0 -178
  96. package/test/ecies/electrum-ecies.js +0 -206
  97. package/test/encoding/base58.js +0 -131
  98. package/test/encoding/base58check.js +0 -145
  99. package/test/encoding/bufferreader.js +0 -328
  100. package/test/encoding/bufferwriter.js +0 -160
  101. package/test/encoding/varint.js +0 -104
  102. package/test/gdaf/anchor_no_key_leak.js +0 -146
  103. package/test/gdaf/anchor_spv.js +0 -163
  104. package/test/gdaf/canonicalization.js +0 -106
  105. package/test/gdaf/canonicalize.js +0 -140
  106. package/test/gdaf/zk_prover.js +0 -204
  107. package/test/hdkeys.js +0 -365
  108. package/test/hdprivatekey.js +0 -339
  109. package/test/hdpublickey.js +0 -293
  110. package/test/index.js +0 -16
  111. package/test/ltp/ids.js +0 -74
  112. package/test/ltp/right.js +0 -198
  113. package/test/ltp/verify_failclosed.js +0 -134
  114. package/test/message/message.js +0 -190
  115. package/test/mnemonic/data/fixtures.json +0 -300
  116. package/test/mnemonic/mnemonic.js +0 -277
  117. package/test/mnemonic/mocha.opts +0 -1
  118. package/test/mnemonic/pbkdf2.test.js +0 -43
  119. package/test/networks.js +0 -207
  120. package/test/notaryhash/batch_leaf.js +0 -140
  121. package/test/notaryhash/certificate.js +0 -249
  122. package/test/notaryhash/encoding.js +0 -186
  123. package/test/notaryhash/interop.js +0 -112
  124. package/test/notaryhash/merkle.js +0 -181
  125. package/test/notaryhash/script.js +0 -270
  126. package/test/notaryhash/verify.js +0 -342
  127. package/test/opcode.js +0 -186
  128. package/test/ordinals/bsv20.js +0 -337
  129. package/test/ordinals/inscription.js +0 -319
  130. package/test/ordinals/ordlock.js +0 -613
  131. package/test/privatekey.js +0 -540
  132. package/test/publickey.js +0 -411
  133. package/test/regressions.js +0 -215
  134. package/test/script/chronicle.js +0 -543
  135. package/test/script/defaults.js +0 -160
  136. package/test/script/genesis_limits.js +0 -203
  137. package/test/script/interpreter.js +0 -776
  138. package/test/script/script.js +0 -1259
  139. package/test/script/string_ops.js +0 -88
  140. package/test/security/fail_closed_contracts.js +0 -104
  141. package/test/security/threat_model_coverage.js +0 -31
  142. package/test/smart_contract/covenants.js +0 -245
  143. package/test/smart_contract/dsl_debugger.js +0 -101
  144. package/test/smart_contract/extract_field.js +0 -61
  145. package/test/smart_contract/nonenforcing_guard.js +0 -44
  146. package/test/smart_contract/ordinal_transfer.js +0 -81
  147. package/test/smart_contract/preimage.js +0 -98
  148. package/test/smart_contract/sighash_marketplace.js +0 -108
  149. package/test/smart_contract/token_generalized.js +0 -185
  150. package/test/spv/headerchain.js +0 -86
  151. package/test/spv/merkleproof.js +0 -133
  152. package/test/statuslist/failclosed.js +0 -78
  153. package/test/transaction/deserialize.js +0 -33
  154. package/test/transaction/input/input.js +0 -92
  155. package/test/transaction/input/multisig.js +0 -174
  156. package/test/transaction/input/multisigscripthash.js +0 -111
  157. package/test/transaction/input/publickey.js +0 -68
  158. package/test/transaction/input/publickeyhash.js +0 -59
  159. package/test/transaction/output.js +0 -185
  160. package/test/transaction/sighash.js +0 -91
  161. package/test/transaction/signature.js +0 -127
  162. package/test/transaction/transaction.js +0 -1299
  163. package/test/transaction/unspentoutput.js +0 -97
  164. package/test/types/dts_drift.js +0 -124
  165. package/test/types/surface_honesty.js +0 -102
  166. package/test/util/id.js +0 -72
  167. package/test/util/js.js +0 -76
  168. package/test/util/preconditions.js +0 -79
  169. package/test/vcjwt/interop.js +0 -126
@@ -1,160 +0,0 @@
1
- 'use strict'
2
-
3
- var bsv = require('../..')
4
- var should = require('chai').should()
5
- var BufferWriter = bsv.encoding.BufferWriter
6
- var BufferReader = bsv.encoding.BufferReader
7
- var BN = bsv.crypto.BN
8
-
9
- describe('BufferWriter', function () {
10
- it('should create a new buffer writer', function () {
11
- var bw = new BufferWriter()
12
- should.exist(bw)
13
- })
14
-
15
- describe('#set', function () {
16
- it('set bufs', function () {
17
- var buf1 = Buffer.from([0])
18
- var buf2 = Buffer.from([1])
19
- var bw = new BufferWriter().set({ bufs: [buf1, buf2] })
20
- bw.concat().toString('hex').should.equal('0001')
21
- })
22
- })
23
-
24
- describe('#toBuffer', function () {
25
- it('should concat these two bufs', function () {
26
- var buf1 = Buffer.from([0])
27
- var buf2 = Buffer.from([1])
28
- var bw = new BufferWriter({ bufs: [buf1, buf2] })
29
- bw.toBuffer().toString('hex').should.equal('0001')
30
- })
31
- })
32
-
33
- describe('#concat', function () {
34
- it('should concat these two bufs', function () {
35
- var buf1 = Buffer.from([0])
36
- var buf2 = Buffer.from([1])
37
- var bw = new BufferWriter({ bufs: [buf1, buf2] })
38
- bw.concat().toString('hex').should.equal('0001')
39
- })
40
- })
41
-
42
- describe('#write', function () {
43
- it('should write a buffer', function () {
44
- var buf = Buffer.from([0])
45
- var bw = new BufferWriter()
46
- bw.write(buf)
47
- bw.concat().toString('hex').should.equal('00')
48
- })
49
- })
50
-
51
- describe('#writeUInt8', function () {
52
- it('should write 1', function () {
53
- var bw = new BufferWriter()
54
- bw.writeUInt8(1).concat().toString('hex').should.equal('01')
55
- })
56
- })
57
-
58
- describe('#writeUInt16BE', function () {
59
- it('should write 1', function () {
60
- var bw = new BufferWriter()
61
- bw.writeUInt16BE(1).concat().toString('hex').should.equal('0001')
62
- })
63
- })
64
-
65
- describe('#writeUInt16LE', function () {
66
- it('should write 1', function () {
67
- var bw = new BufferWriter()
68
- bw.writeUInt16LE(1).concat().toString('hex').should.equal('0100')
69
- })
70
- })
71
-
72
- describe('#writeUInt32BE', function () {
73
- it('should write 1', function () {
74
- var bw = new BufferWriter()
75
- bw.writeUInt32BE(1).concat().toString('hex').should.equal('00000001')
76
- })
77
- })
78
-
79
- describe('#writeUInt32LE', function () {
80
- it('should write 1', function () {
81
- var bw = new BufferWriter()
82
- bw.writeUInt32LE(1).concat().toString('hex').should.equal('01000000')
83
- })
84
- })
85
-
86
- describe('#writeUInt64BEBN', function () {
87
- it('should write 1', function () {
88
- var bw = new BufferWriter()
89
- bw.writeUInt64BEBN(new BN(1)).concat().toString('hex').should.equal('0000000000000001')
90
- })
91
- })
92
-
93
- describe('#writeUInt64LEBN', function () {
94
- it('should write 1', function () {
95
- var bw = new BufferWriter()
96
- bw.writeUInt64LEBN(new BN(1)).concat().toString('hex').should.equal('0100000000000000')
97
- })
98
- })
99
-
100
- describe('#writeVarint', function () {
101
- it('should write a 1 byte varint', function () {
102
- var bw = new BufferWriter()
103
- bw.writeVarintNum(1)
104
- bw.concat().length.should.equal(1)
105
- })
106
-
107
- it('should write a 3 byte varint', function () {
108
- var bw = new BufferWriter()
109
- bw.writeVarintNum(1000)
110
- bw.concat().length.should.equal(3)
111
- })
112
-
113
- it('should write a 5 byte varint', function () {
114
- var bw = new BufferWriter()
115
- bw.writeVarintNum(Math.pow(2, 16 + 1))
116
- bw.concat().length.should.equal(5)
117
- })
118
-
119
- it('should write a 9 byte varint', function () {
120
- var bw = new BufferWriter()
121
- bw.writeVarintNum(Math.pow(2, 32 + 1))
122
- bw.concat().length.should.equal(9)
123
- })
124
-
125
- it('should read back the same value it wrote for a 9 byte varint', function () {
126
- var bw = new BufferWriter()
127
- var n = Math.pow(2, 53)
128
- n.should.equal(n + 1) // javascript number precision limit
129
- bw.writeVarintNum(n)
130
- var br = new BufferReader({ buf: bw.concat() })
131
- br.readVarintBN().toNumber().should.equal(n)
132
- })
133
- })
134
-
135
- describe('#writeVarintBN', function () {
136
- it('should write a 1 byte varint', function () {
137
- var bw = new BufferWriter()
138
- bw.writeVarintBN(new BN(1))
139
- bw.concat().length.should.equal(1)
140
- })
141
-
142
- it('should write a 3 byte varint', function () {
143
- var bw = new BufferWriter()
144
- bw.writeVarintBN(new BN(1000))
145
- bw.concat().length.should.equal(3)
146
- })
147
-
148
- it('should write a 5 byte varint', function () {
149
- var bw = new BufferWriter()
150
- bw.writeVarintBN(new BN(Math.pow(2, 16 + 1)))
151
- bw.concat().length.should.equal(5)
152
- })
153
-
154
- it('should write a 9 byte varint', function () {
155
- var bw = new BufferWriter()
156
- bw.writeVarintBN(new BN(Math.pow(2, 32 + 1)))
157
- bw.concat().length.should.equal(9)
158
- })
159
- })
160
- })
@@ -1,104 +0,0 @@
1
- 'use strict'
2
-
3
- var should = require('chai').should()
4
- var bsv = require('../..')
5
- var BN = bsv.crypto.BN
6
- var BufferReader = bsv.encoding.BufferReader
7
- var BufferWriter = bsv.encoding.BufferWriter
8
- var Varint = bsv.encoding.Varint
9
-
10
- describe('Varint', function () {
11
- it('should make a new varint', function () {
12
- var buf = Buffer.from('00', 'hex')
13
- var varint = new Varint(buf)
14
- should.exist(varint)
15
- varint.buf.toString('hex').should.equal('00')
16
- varint = Varint(buf)
17
- should.exist(varint)
18
- varint.buf.toString('hex').should.equal('00')
19
-
20
- // various ways to use the constructor
21
- Varint(Varint(0).toBuffer()).toNumber().should.equal(0)
22
- Varint(0).toNumber().should.equal(0)
23
- Varint(new BN(0)).toNumber().should.equal(0)
24
- })
25
-
26
- describe('#set', function () {
27
- it('should set a buffer', function () {
28
- var buf = Buffer.from('00', 'hex')
29
- var varint = Varint().set({ buf: buf })
30
- varint.buf.toString('hex').should.equal('00')
31
- varint.set({})
32
- varint.buf.toString('hex').should.equal('00')
33
- })
34
- })
35
-
36
- describe('#fromString', function () {
37
- it('should set a buffer', function () {
38
- var buf = BufferWriter().writeVarintNum(5).concat()
39
- var varint = Varint().fromString(buf.toString('hex'))
40
- varint.toNumber().should.equal(5)
41
- })
42
- })
43
-
44
- describe('#toString', function () {
45
- it('should return a buffer', function () {
46
- var buf = BufferWriter().writeVarintNum(5).concat()
47
- var varint = Varint().fromString(buf.toString('hex'))
48
- varint.toString().should.equal('05')
49
- })
50
- })
51
-
52
- describe('#fromBuffer', function () {
53
- it('should set a buffer', function () {
54
- var buf = BufferWriter().writeVarintNum(5).concat()
55
- var varint = Varint().fromBuffer(buf)
56
- varint.toNumber().should.equal(5)
57
- })
58
- })
59
-
60
- describe('#fromBufferReader', function () {
61
- it('should set a buffer reader', function () {
62
- var buf = BufferWriter().writeVarintNum(5).concat()
63
- var br = BufferReader(buf)
64
- var varint = Varint().fromBufferReader(br)
65
- varint.toNumber().should.equal(5)
66
- })
67
- })
68
-
69
- describe('#fromBN', function () {
70
- it('should set a number', function () {
71
- var varint = Varint().fromBN(new BN(5))
72
- varint.toNumber().should.equal(5)
73
- })
74
- })
75
-
76
- describe('#fromNumber', function () {
77
- it('should set a number', function () {
78
- var varint = Varint().fromNumber(5)
79
- varint.toNumber().should.equal(5)
80
- })
81
- })
82
-
83
- describe('#toBuffer', function () {
84
- it('should return a buffer', function () {
85
- var buf = BufferWriter().writeVarintNum(5).concat()
86
- var varint = Varint(buf)
87
- varint.toBuffer().toString('hex').should.equal(buf.toString('hex'))
88
- })
89
- })
90
-
91
- describe('#toBN', function () {
92
- it('should return a buffer', function () {
93
- var varint = Varint(5)
94
- varint.toBN().toString().should.equal(new BN(5).toString())
95
- })
96
- })
97
-
98
- describe('#toNumber', function () {
99
- it('should return a buffer', function () {
100
- var varint = Varint(5)
101
- varint.toNumber().should.equal(5)
102
- })
103
- })
104
- })
@@ -1,146 +0,0 @@
1
- 'use strict'
2
-
3
- /* global describe, it */
4
-
5
- // The GDAF anchoring wrappers take (payload, privateKey, options) while the underlying
6
- // SmartLedgerAnchor methods take (payload, metadata, utxos). Every wrapper forwarded
7
- // `privateKey` into a slot that is not a key. For anchorCredential/anchorBatch it landed
8
- // in `metadata`, which is JSON.stringify-ed straight into the OP_RETURN — so the secret
9
- // scalar was broadcast, and the key was recoverable from chain data with an identical WIF.
10
-
11
- require('chai').should()
12
- var bsv = require('../..')
13
-
14
- describe('GDAF anchoring never publishes key material', function () {
15
- var key = bsv.PrivateKey.fromBuffer(Buffer.alloc(32, 7))
16
- var utxos = [{
17
- txId: '11'.repeat(32),
18
- outputIndex: 0,
19
- script: bsv.Script.buildPublicKeyHashOut(key.toAddress()).toHex(),
20
- satoshis: 100000
21
- }]
22
- var HASH = 'ab'.repeat(32)
23
-
24
- function gdaf () { return new bsv.GDAF() }
25
-
26
- // Pull every OP_RETURN payload out of a built transaction, as UTF-8.
27
- function payloadsOf (result) {
28
- var tx = new bsv.Transaction((result.transaction || result.tx || result).toString())
29
- return tx.outputs.map(function (o) {
30
- var asm = o.script.toASM().split(' ')
31
- return Buffer.from(asm[asm.length - 1], 'hex').toString('utf8')
32
- })
33
- }
34
-
35
- function assertNoSecret (result) {
36
- var scalarHex = key.bn.toString('hex')
37
- var raw = (result.transaction || result.tx || result).toString()
38
- raw.indexOf(Buffer.from(scalarHex, 'utf8').toString('hex')).should.equal(-1)
39
- raw.indexOf(Buffer.from('"bn"', 'utf8').toString('hex')).should.equal(-1)
40
- payloadsOf(result).forEach(function (p) {
41
- p.indexOf(scalarHex).should.equal(-1)
42
- p.indexOf('"bn"').should.equal(-1)
43
- })
44
- }
45
-
46
- it('anchorCredential does not put the key in the OP_RETURN', function () {
47
- return gdaf().anchorCredential(HASH, key, utxos).then(assertNoSecret)
48
- })
49
-
50
- it('anchorBatch does not put the key in the OP_RETURN', function () {
51
- return gdaf().anchorBatch([HASH, 'cd'.repeat(32)], key, utxos).then(assertNoSecret)
52
- })
53
-
54
- it('accepts the documented { utxos, metadata } options shape', function () {
55
- return gdaf().anchorCredential(HASH, key, { utxos: utxos, metadata: { issuer: 'did:web:example' } })
56
- .then(function (r) {
57
- assertNoSecret(r)
58
- // The caller's own metadata still reaches the chain.
59
- payloadsOf(r).join('').indexOf('did:web:example').should.not.equal(-1)
60
- })
61
- })
62
-
63
- it('still accepts a bare UTXO array, the only shape that used to work', function () {
64
- return gdaf().anchorCredential(HASH, key, utxos).then(function (r) {
65
- r.should.be.an('object')
66
- })
67
- })
68
-
69
- // Defence in depth: even reaching the payload builder with key material must fail
70
- // loudly rather than broadcast it.
71
- it('refuses to anchor metadata containing a PrivateKey instance', function () {
72
- return gdaf().anchorCredential(HASH, key, { utxos: utxos, metadata: { signer: key } })
73
- .then(function () { throw new Error('should not have anchored') },
74
- function (err) { err.message.should.match(/Refusing to anchor/) })
75
- })
76
-
77
- it('refuses to anchor metadata carrying a key-shaped field', function () {
78
- return gdaf().anchorCredential(HASH, key, { utxos: utxos, metadata: { wif: key.toWIF() } })
79
- .then(function () { throw new Error('should not have anchored') },
80
- function (err) { err.message.should.match(/key material/) })
81
- })
82
-
83
- it('leaves ordinary metadata alone', function () {
84
- return gdaf().anchorCredential(HASH, key, {
85
- utxos: utxos, metadata: { id: 'urn:uuid:1', nested: { note: 'fine' } }
86
- }).then(function (r) { assertNoSecret(r) })
87
- })
88
- // The guard keyed off field NAMES alone, which was wrong in both directions: it
89
- // rejected `{ d: '2026-01-01' }` as key material while publishing a real WIF stored
90
- // under `note`. Detection is now by value as well as name.
91
- describe('detects key material by value, not just by field name', function () {
92
- var Anchor = require('../../lib/gdaf/smartledger-anchor.js')
93
- var other = bsv.PrivateKey.fromBuffer(Buffer.alloc(32, 99))
94
- var HASH_BUF = bsv.crypto.Hash.sha256(Buffer.from('doc'))
95
-
96
- function build (metadata) {
97
- return new Anchor(key, {})._createAnchorPayload('CREDENTIAL', HASH_BUF, metadata)
98
- }
99
- function refuses (label, metadata) {
100
- it('refuses ' + label, function () {
101
- ;(function () { build(metadata) }).should.throw(/Refusing to anchor/)
102
- })
103
- }
104
- function accepts (label, metadata) {
105
- it('accepts ' + label, function () {
106
- var payload = Buffer.from(build(metadata)).toString('utf8')
107
- payload.indexOf(key.toWIF()).should.equal(-1)
108
- })
109
- }
110
-
111
- // Self-identifying secrets: the encoding says "private key" whatever the field is
112
- // called. Naming a WIF `note` does not make it safe to publish.
113
- refuses('a WIF under an innocuous name', { note: other.toWIF() })
114
- refuses('an xprv under an innocuous name', {
115
- ref: bsv.HDPrivateKey.fromSeed(Buffer.alloc(32, 1)).toString()
116
- })
117
- refuses('a BIP39 mnemonic under an innocuous name', {
118
- memo: 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'
119
- })
120
- refuses('a secret nested in an array', { signers: [other.toWIF()] })
121
-
122
- // The anchor's OWN key, in any representation — the exact defect this guard exists
123
- // for. A bare hex scalar is otherwise indistinguishable from a hash, so knowing our
124
- // own key is what makes this catchable.
125
- refuses("the anchor's own key as a raw hex scalar", { backup: key.toString() })
126
- refuses("the anchor's own key as a WIF", { backup: key.toWIF() })
127
-
128
- // Ambiguous names are refused only when the value really is secret.
129
- refuses('d holding a private scalar', { d: other.toString() })
130
- refuses('seed holding a mnemonic', {
131
- seed: 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'
132
- })
133
-
134
- // ...and left alone otherwise. Anchoring a document hash is the module's purpose,
135
- // and a 64-hex hash cannot be told apart from a scalar, so it must not be rejected.
136
- accepts('d as a date', { d: '2026-01-01' })
137
- accepts('seed as a campaign name', { seed: 'spring-campaign' })
138
- accepts('a SHA-256 document hash', { docHash: bsv.crypto.Hash.sha256(Buffer.from('x')).toString('hex') })
139
- accepts('key used as an ordinary label', { key: 'value' })
140
-
141
- // Public material is not secret and an anchor legitimately references it.
142
- accepts('an address', { payTo: key.toAddress().toString() })
143
- accepts('a public key', { pub: key.toPublicKey().toString() })
144
- accepts('an xpub', { xpub: bsv.HDPrivateKey.fromSeed(Buffer.alloc(32, 1)).hdPublicKey.toString() })
145
- })
146
- })
@@ -1,163 +0,0 @@
1
- 'use strict'
2
-
3
- /* global describe, it */
4
-
5
- // Trustless SPV anchor verification end-to-end: build a real anchoring tx with an
6
- // OP_RETURN commitment, place it in a block, prove its inclusion with a Merkle
7
- // branch + header, and verify through SmartLedgerAnchor.verifyAnchor with NO trusted
8
- // provider. Replaces the old {verified:true} stub / trust-the-caller-txData path.
9
-
10
- require('chai').should()
11
- var bsv = require('../..')
12
- var Anchor = require('../../lib/gdaf/smartledger-anchor')
13
- var Hash = bsv.crypto.Hash
14
-
15
- function rev (b) { return Buffer.from(b).reverse() }
16
- function buildTree (leaves) {
17
- var tree = leaves.slice(); var j = 0
18
- for (var size = leaves.length; size > 1; size = Math.floor((size + 1) / 2)) {
19
- for (var i = 0; i < size; i += 2) {
20
- var i2 = Math.min(i + 1, size - 1)
21
- tree.push(Hash.sha256sha256(Buffer.concat([tree[j + i], tree[j + i2]])))
22
- }
23
- j += size
24
- }
25
- return tree
26
- }
27
- function rootOf (l) { var t = buildTree(l); return t[t.length - 1] }
28
- function branchFor (leaves, index) {
29
- var tree = buildTree(leaves); var branch = []; var j = 0; var idx = index
30
- for (var size = leaves.length; size > 1; size = Math.floor((size + 1) / 2)) {
31
- var sib = idx ^ 1; if (sib >= size) sib = idx
32
- branch.push(rev(tree[j + sib]).toString('hex'))
33
- j += size; idx = Math.floor(idx / 2)
34
- }
35
- return branch
36
- }
37
-
38
- function anchorTxFor (hashHex) {
39
- var tx = new bsv.Transaction()
40
- tx.addOutput(new bsv.Transaction.Output({
41
- script: bsv.Script.buildDataOut(Buffer.from(hashHex, 'hex')),
42
- satoshis: 0
43
- }))
44
- return tx
45
- }
46
-
47
- function blockOf (rootInternal) {
48
- return new bsv.BlockHeader({
49
- version: 1, prevHash: Buffer.alloc(32), merkleRoot: rootInternal,
50
- time: 1231006505, bits: 0x1d00ffff, nonce: 0
51
- })
52
- }
53
-
54
- // "Mine" a regtest-difficulty header (PoW passes after trivial nonce grinding).
55
- function minedHeader (prevHashInternal, merkleInternal) {
56
- for (var nonce = 0; nonce < 100000; nonce++) {
57
- var h = new bsv.BlockHeader({
58
- version: 1, prevHash: prevHashInternal, merkleRoot: merkleInternal,
59
- time: 1231006505 + nonce, bits: 0x207fffff, nonce: nonce
60
- })
61
- if (h.validProofOfWork()) return h
62
- }
63
- throw new Error('could not mine header')
64
- }
65
-
66
- describe('SPV anchor verification (trustless)', function () {
67
- var anchorHash = Hash.sha256(Buffer.from('anchor me')).toString('hex')
68
- var atx = anchorTxFor(anchorHash)
69
- var rawTx = atx.uncheckedSerialize()
70
- var txid = atx.hash
71
- // Place the anchor tx at index 2 among 5 leaves.
72
- var leaves = [
73
- bsv.crypto.Random.getRandomBuffer(32),
74
- bsv.crypto.Random.getRandomBuffer(32),
75
- atx._getHash(),
76
- bsv.crypto.Random.getRandomBuffer(32),
77
- bsv.crypto.Random.getRandomBuffer(32)
78
- ]
79
- var header = blockOf(rootOf(leaves))
80
- var spvProof = { index: 2, nodes: branchFor(leaves, 2) }
81
-
82
- it('verifies inclusion + commitment with a valid proof', async function () {
83
- var res = await Anchor.verifyAnchor(txid, anchorHash, {
84
- spvProof: spvProof, header: header, rawTx: rawTx, requirePow: false
85
- })
86
- res.verified.should.equal(true)
87
- res.chainVerified.should.equal(true)
88
- res.committed.should.equal(true)
89
- res.txidBound.should.equal(true)
90
- res.proof.type.should.equal('spv_merkle_inclusion')
91
- })
92
-
93
- it('rejects when the tx does not commit to the expected hash', async function () {
94
- var otherHash = Hash.sha256(Buffer.from('something else')).toString('hex')
95
- var res = await Anchor.verifyAnchor(txid, otherHash, {
96
- spvProof: spvProof, header: header, rawTx: rawTx, requirePow: false
97
- })
98
- res.committed.should.equal(false)
99
- res.verified.should.equal(false)
100
- })
101
-
102
- it('rejects a tampered Merkle branch (inclusion fails)', async function () {
103
- var bad = { index: 2, nodes: branchFor(leaves, 2).slice() }
104
- bad.nodes[0] = rev(bsv.crypto.Random.getRandomBuffer(32)).toString('hex')
105
- var res = await Anchor.verifyAnchor(txid, anchorHash, {
106
- spvProof: bad, header: header, rawTx: rawTx, requirePow: false
107
- })
108
- res.chainVerified.should.equal(false)
109
- res.verified.should.equal(false)
110
- })
111
-
112
- it('rejects rawTx that does not hash to txid', async function () {
113
- var otherRaw = anchorTxFor(Hash.sha256(Buffer.from('decoy')).toString('hex')).uncheckedSerialize()
114
- var res = await Anchor.verifyAnchor(txid, anchorHash, {
115
- spvProof: spvProof, header: header, rawTx: otherRaw, requirePow: false
116
- })
117
- res.txidBound.should.equal(false)
118
- res.verified.should.equal(false)
119
- })
120
-
121
- it('still refuses to fabricate a result with neither an SPV proof nor a provider', async function () {
122
- var threw = false
123
- try { await Anchor.verifyAnchor(txid, anchorHash, {}) } catch (e) { threw = true }
124
- threw.should.equal(true)
125
- })
126
-
127
- describe('with a header chain (confirmations under real PoW)', function () {
128
- this.timeout(10000)
129
- // Block containing the tx must carry the real merkle root; then descendants.
130
- var h0 = minedHeader(Buffer.alloc(32), rootOf(leaves))
131
- var h1 = minedHeader(h0._getHash(), bsv.crypto.Random.getRandomBuffer(32))
132
- var h2 = minedHeader(h1._getHash(), bsv.crypto.Random.getRandomBuffer(32))
133
- var headerChain = [h0, h1, h2]
134
-
135
- it('verifies inclusion + 3 confirmations under real proof-of-work', async function () {
136
- var res = await Anchor.verifyAnchor(txid, anchorHash, {
137
- spvProof: spvProof, headerChain: headerChain, rawTx: rawTx, minConfirmations: 3
138
- })
139
- res.verified.should.equal(true)
140
- res.confirmations.should.equal(3)
141
- res.headerChainValid.should.equal(true)
142
- res.powValid.should.equal(true)
143
- res.tipHash.should.equal(h2.id)
144
- res.proof.type.should.equal('spv_merkle_inclusion_with_confirmations')
145
- })
146
-
147
- it('rejects when confirmations are below the required minimum', async function () {
148
- var res = await Anchor.verifyAnchor(txid, anchorHash, {
149
- spvProof: spvProof, headerChain: headerChain, rawTx: rawTx, minConfirmations: 6
150
- })
151
- res.confirmations.should.equal(3)
152
- res.verified.should.equal(false)
153
- })
154
-
155
- it('rejects a header chain with a broken link', async function () {
156
- var res = await Anchor.verifyAnchor(txid, anchorHash, {
157
- spvProof: spvProof, headerChain: [h0, h2], rawTx: rawTx, minConfirmations: 1
158
- })
159
- res.headerChainValid.should.equal(false)
160
- res.verified.should.equal(false)
161
- })
162
- })
163
- })
@@ -1,106 +0,0 @@
1
- 'use strict'
2
-
3
- /* global describe, it */
4
-
5
- // GDAF signs a hash of canonical JSON, so the canonicalization IS part of the signature
6
- // scheme. It was sorted-key JSON that rebuilt the object, which loses the sort: V8 orders
7
- // integer-like own properties numerically, ahead of string keys, whatever order they were
8
- // inserted in.
9
- //
10
- // Within this library that was deterministic — signing and verification agreed, and no
11
- // forgery followed. Across implementations it was a verification failure, which for
12
- // credentials that exist to be checked by other parties is the thing that matters.
13
-
14
- require('chai').should()
15
- var Signer = require('../../lib/gdaf/attestation-signer')
16
-
17
- describe('GDAF canonicalization', function () {
18
- describe('RFC 8785 conformance', function () {
19
- // The concrete divergence. JCS sorts by UTF-16 code unit, where '10' < '2'.
20
- it('sorts integer-like keys lexicographically, not numerically', function () {
21
- var o = {}
22
- o['10'] = 'ten'
23
- o['2'] = 'two'
24
- Signer._canonicalizeJCS(o).should.equal('{"10":"ten","2":"two"}')
25
- })
26
-
27
- it('is what the legacy form got wrong, which is why both exist', function () {
28
- var o = {}
29
- o['10'] = 'ten'
30
- o['2'] = 'two'
31
- Signer._canonicalizeJSON(o).should.equal('{"2":"two","10":"ten"}')
32
- Signer._canonicalizeJCS(o).should.not.equal(Signer._canonicalizeJSON(o))
33
- })
34
-
35
- it('sorts at every depth and leaves arrays in order', function () {
36
- Signer._canonicalizeJCS({ z: { b: 1, a: 2 }, a: [3, { d: 1, c: 2 }] })
37
- .should.equal('{"a":[3,{"c":2,"d":1}],"z":{"a":2,"b":1}}')
38
- })
39
-
40
- it('is insensitive to key insertion order', function () {
41
- var x = {}; x.b = 1; x.a = 2
42
- var y = {}; y.a = 2; y.b = 1
43
- Signer._canonicalizeJCS(x).should.equal(Signer._canonicalizeJCS(y))
44
- })
45
-
46
- // These are the same IEEE-754 double, so collapsing them is correct rather than a
47
- // weakness — JavaScript has one number type. Pinned so nobody "fixes" it.
48
- it('treats 1847, 1847.0 and 1.847e3 as the one number they are', function () {
49
- Signer._canonicalizeJCS({ a: 1847 }).should.equal('{"a":1847}')
50
- Signer._canonicalizeJCS({ a: 1847.0 }).should.equal('{"a":1847}')
51
- Signer._canonicalizeJCS({ a: 1.847e3 }).should.equal('{"a":1847}')
52
- })
53
-
54
- it('keeps a number distinct from its string form', function () {
55
- Signer._canonicalizeJCS({ a: 1847 }).should.not.equal(Signer._canonicalizeJCS({ a: '1847' }))
56
- })
57
-
58
- // JSON.stringify would emit `null` here, silently signing a different document.
59
- it('refuses non-finite numbers rather than emitting null', function () {
60
- ;(function () { Signer._canonicalizeJCS({ a: NaN }) }).should.throw(/non-finite/)
61
- ;(function () { Signer._canonicalizeJCS({ a: Infinity }) }).should.throw(/non-finite/)
62
- })
63
-
64
- it('emits unicode and non-BMP characters directly', function () {
65
- Signer._canonicalizeJCS({ a: 'é' }).should.equal('{"a":"é"}')
66
- Signer._canonicalizeJCS({ a: '😀' }).should.equal('{"a":"😀"}')
67
- })
68
-
69
- it('drops undefined members, which JSON cannot represent', function () {
70
- Signer._canonicalizeJCS({ a: 1, b: undefined }).should.equal('{"a":1}')
71
- })
72
-
73
- it('nulls undefined array elements, as JSON.stringify does', function () {
74
- Signer._canonicalizeJCS([1, undefined, 2]).should.equal('[1,null,2]')
75
- })
76
- })
77
-
78
- describe('hashing and migration', function () {
79
- var CRED = { id: 'urn:x', credentialSubject: { name: 'Alice', age: 41 } }
80
-
81
- it('hashes with JCS by default', function () {
82
- Signer._hashCredential(CRED).toString('hex')
83
- .should.equal(Signer._hashCredential(CRED, Signer.CANONICALIZATION.JCS).toString('hex'))
84
- })
85
-
86
- // The migration path. A credential whose keys make the two forms differ must hash
87
- // differently, or the legacy fallback in the verifier would be pointless.
88
- it('gives a different hash under the legacy form when the forms diverge', function () {
89
- var withIntKeys = { '10': 'ten', '2': 'two' }
90
- Signer._hashCredential(withIntKeys, Signer.CANONICALIZATION.JCS).toString('hex')
91
- .should.not.equal(
92
- Signer._hashCredential(withIntKeys, Signer.CANONICALIZATION.LEGACY).toString('hex')
93
- )
94
- })
95
-
96
- it('agrees between the forms when no integer-like keys are present', function () {
97
- Signer._hashCredential(CRED, Signer.CANONICALIZATION.JCS).toString('hex')
98
- .should.equal(Signer._hashCredential(CRED, Signer.CANONICALIZATION.LEGACY).toString('hex'))
99
- })
100
-
101
- it('exposes both forms by name', function () {
102
- Signer.CANONICALIZATION.JCS.should.equal('jcs')
103
- Signer.CANONICALIZATION.LEGACY.should.equal('legacy')
104
- })
105
- })
106
- })