@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,97 +0,0 @@
1
- 'use strict'
2
-
3
- var chai = require('chai')
4
- var expect = chai.expect
5
- /* global structuredClone */
6
- // structuredClone, not the former clone-deep dependency: the fixture below is plain
7
- // JSON (strings and numbers), where the two are equivalent. The interpreter's stack
8
- // clone is NOT — it holds Buffers, which structuredClone would return as Uint8Array.
9
- // The global comment is for standard@12's eslint, which predates the API.
10
- var cloneDeep = structuredClone
11
-
12
- var bsv = require('../..')
13
- var UnspentOutput = bsv.Transaction.UnspentOutput
14
-
15
- describe('UnspentOutput', function () {
16
- var sampleData1 = {
17
- 'address': 'mszYqVnqKoQx4jcTdJXxwKAissE3Jbrrc1',
18
- 'txId': 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458',
19
- 'outputIndex': 0,
20
- 'script': 'OP_DUP OP_HASH160 20 0x88d9931ea73d60eaf7e5671efc0552b912911f2a OP_EQUALVERIFY OP_CHECKSIG',
21
- 'satoshis': 1020000
22
- }
23
- var sampleData2 = {
24
- 'txid': 'e42447187db5a29d6db161661e4bc66d61c3e499690fe5ea47f87b79ca573986',
25
- 'vout': 1,
26
- 'address': 'mgBCJAsvzgT2qNNeXsoECg2uPKrUsZ76up',
27
- 'scriptPubKey': '76a914073b7eae2823efa349e3b9155b8a735526463a0f88ac',
28
- 'amount': 0.01080000
29
- }
30
-
31
- it('roundtrip from raw data', function () {
32
- expect(UnspentOutput(sampleData2).toObject()).to.deep.equal(sampleData2)
33
- })
34
-
35
- it('can be created without "new" operand', function () {
36
- expect(UnspentOutput(sampleData1) instanceof UnspentOutput).to.equal(true)
37
- })
38
-
39
- it('fails if no tx id is provided', function () {
40
- expect(function () {
41
- return new UnspentOutput({})
42
- }).to.throw()
43
- })
44
-
45
- it('fails if vout is not a number', function () {
46
- var sample = cloneDeep(sampleData2)
47
- sample.vout = '1'
48
- expect(function () {
49
- return new UnspentOutput(sample)
50
- }).to.throw()
51
- })
52
-
53
- it('displays nicely on the console', function () {
54
- var expected = '<UnspentOutput: a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458:0' +
55
- ', satoshis: 1020000, address: mszYqVnqKoQx4jcTdJXxwKAissE3Jbrrc1>'
56
- expect(new UnspentOutput(sampleData1).inspect()).to.equal(expected)
57
- })
58
-
59
- describe('checking the constructor parameters', function () {
60
- var notDefined = {
61
- 'txId': 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458',
62
- 'outputIndex': 0,
63
- 'script': 'OP_DUP OP_HASH160 20 0x88d9931ea73d60eaf7e5671efc0552b912911f2a OP_EQUALVERIFY OP_CHECKSIG'
64
- }
65
- var zero = {
66
- 'txId': 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458',
67
- 'outputIndex': 0,
68
- 'script': 'OP_DUP OP_HASH160 20 0x88d9931ea73d60eaf7e5671efc0552b912911f2a OP_EQUALVERIFY OP_CHECKSIG',
69
- 'amount': 0
70
- }
71
- it('fails when no amount is defined', function () {
72
- expect(function () {
73
- return new UnspentOutput(notDefined)
74
- }).to.throw('Must provide an amount for the output')
75
- })
76
- it('does not fail when amount is zero', function () {
77
- expect(function () {
78
- return new UnspentOutput(zero)
79
- }).to.not.throw()
80
- })
81
- })
82
-
83
- it('toString returns txid:vout', function () {
84
- var expected = 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458:0'
85
- expect(new UnspentOutput(sampleData1).toString()).to.equal(expected)
86
- })
87
-
88
- it('to/from JSON roundtrip', function () {
89
- var utxo = new UnspentOutput(sampleData2)
90
- var obj = UnspentOutput.fromObject(utxo.toJSON()).toObject()
91
- expect(obj).to.deep.equal(sampleData2)
92
- var str = JSON.stringify(UnspentOutput.fromObject(obj))
93
- expect(JSON.parse(str)).to.deep.equal(sampleData2)
94
- var str2 = JSON.stringify(new UnspentOutput(JSON.parse(str)))
95
- expect(JSON.parse(str2)).to.deep.equal(sampleData2)
96
- })
97
- })
@@ -1,124 +0,0 @@
1
- 'use strict'
2
-
3
- /* global describe, it, before */
4
-
5
- // TYPE-DRIFT GATE — mechanically proves the hand-maintained `bsv.d.ts` does not lie
6
- // about the runtime. `bsv.d.ts` is a curated public-API surface (better than anything
7
- // auto-generated from the spotty JSDoc), but nothing stopped it drifting — its own
8
- // header said "3.4.x" on a 6.x package. This test parses the .d.ts with the real
9
- // TypeScript AST and asserts:
10
- // (1) every declared value symbol (class / function / const, at any nesting) EXISTS
11
- // at runtime — no phantom APIs that the types promise but the code doesn't have;
12
- // (2) for the audited namespaces (Ordinals, Ordinals.BSV20, SPV) every runtime
13
- // function is DECLARED — so new APIs there can't ship untyped.
14
- // Interfaces and type aliases are compile-time only and are ignored.
15
-
16
- require('chai').should()
17
- var path = require('path')
18
- var fs = require('fs')
19
- var ts = require('typescript')
20
- var bsv = require('../..')
21
-
22
- var DTS_PATH = path.join(__dirname, '../../bsv.d.ts')
23
- var MODULE_NAME = '@smartledger/bsv'
24
-
25
- // Walk the `declare module '@smartledger/bsv'` block and collect the dotted path of
26
- // every value declaration (class / function / const), recursing into namespaces.
27
- function collectDeclaredPaths (source) {
28
- var sf = ts.createSourceFile('bsv.d.ts', source, ts.ScriptTarget.Latest, true)
29
- var paths = []
30
- var moduleBody = null
31
-
32
- sf.forEachChild(function (node) {
33
- if (ts.isModuleDeclaration(node) && node.name && ts.isStringLiteral(node.name) &&
34
- node.name.text === MODULE_NAME && node.body && ts.isModuleBlock(node.body)) {
35
- moduleBody = node.body
36
- }
37
- })
38
- if (!moduleBody) throw new Error('could not find `declare module "' + MODULE_NAME + '"` in bsv.d.ts')
39
-
40
- function walk (statements, prefix) {
41
- statements.forEach(function (node) {
42
- if (ts.isModuleDeclaration(node) && node.name && node.body && ts.isModuleBlock(node.body)) {
43
- // A namespace: recurse (the namespace itself is checked via its members' paths).
44
- walk(node.body.statements, prefix.concat(node.name.text))
45
- } else if (ts.isClassDeclaration(node) && node.name) {
46
- paths.push(prefix.concat(node.name.text))
47
- } else if (ts.isFunctionDeclaration(node) && node.name) {
48
- var p = prefix.concat(node.name.text)
49
- p.returnType = node.type ? node.type.getText() : null
50
- paths.push(p)
51
- } else if (ts.isVariableStatement(node)) {
52
- node.declarationList.declarations.forEach(function (d) {
53
- if (ts.isIdentifier(d.name)) paths.push(prefix.concat(d.name.text))
54
- })
55
- }
56
- // InterfaceDeclaration / TypeAliasDeclaration: compile-time only — ignored.
57
- })
58
- }
59
- walk(moduleBody.statements, [])
60
- return paths
61
- }
62
-
63
- // Resolve a dotted path on the runtime object; returns undefined if any segment is missing.
64
- function resolve (root, segments) {
65
- return segments.reduce(function (o, k) { return (o == null) ? undefined : o[k] }, root)
66
- }
67
-
68
- describe('types: bsv.d.ts does not drift from runtime', function () {
69
- var declaredPaths
70
-
71
- before(function () {
72
- declaredPaths = collectDeclaredPaths(fs.readFileSync(DTS_PATH, 'utf8'))
73
- })
74
-
75
- it('parses a non-trivial number of declared symbols', function () {
76
- // Sanity: if the parse silently produced nothing, the whole gate would be a no-op.
77
- declaredPaths.length.should.be.above(50)
78
- })
79
-
80
- it('every declared class / function / const exists at runtime (no phantom API)', function () {
81
- var missing = declaredPaths
82
- .filter(function (segs) { return resolve(bsv, segs) === undefined })
83
- .map(function (segs) { return segs.join('.') })
84
- missing.should.deep.equal([], 'bsv.d.ts declares these but runtime does not expose them:\n ' + missing.join('\n '))
85
- })
86
-
87
- // Reverse direction where it matters most: the modules added in 6.x must stay fully typed.
88
- var AUDITED = [
89
- { label: 'Ordinals', obj: bsv.Ordinals, decl: 'Ordinals' },
90
- { label: 'Ordinals.BSV20', obj: bsv.Ordinals && bsv.Ordinals.BSV20, decl: 'Ordinals.BSV20' },
91
- { label: 'SPV', obj: bsv.SPV, decl: 'SPV' }
92
- ]
93
-
94
- // An `async` runtime function declared with a non-Promise return type is the most
95
- // dangerous kind of drift, because the type checker actively hides the bug rather than
96
- // merely failing to catch it: `StatusList.getCredentialStatusEntry` was declared
97
- // `: CredentialStatus` while being async, so `if (fn(...) === 'revoked')` compiled clean
98
- // and was ALWAYS false — every revoked credential passed as valid.
99
- it('no async runtime function is declared with a synchronous return type', function () {
100
- var lies = []
101
- declaredPaths.forEach(function (segs) {
102
- if (!segs.returnType) return
103
- var fn = resolve(bsv, segs)
104
- if (typeof fn !== 'function') return
105
- var isAsync = fn.constructor && fn.constructor.name === 'AsyncFunction'
106
- var declaresPromise = /\bPromise\s*</.test(segs.returnType)
107
- if (isAsync && !declaresPromise) {
108
- lies.push(segs.join('.') + ' is async but is declared `: ' + segs.returnType + '`')
109
- }
110
- })
111
- lies.should.deep.equal([], 'these declarations hide a Promise:\n ' + lies.join('\n '))
112
- })
113
-
114
- AUDITED.forEach(function (ns) {
115
- it('every runtime function on ' + ns.label + ' is declared in bsv.d.ts', function () {
116
- ns.obj.should.be.an('object')
117
- var declaredSet = {}
118
- declaredPaths.forEach(function (segs) { declaredSet[segs.join('.')] = true })
119
- var runtimeFns = Object.keys(ns.obj).filter(function (k) { return typeof ns.obj[k] === 'function' })
120
- var untyped = runtimeFns.filter(function (k) { return !declaredSet[ns.decl + '.' + k] })
121
- untyped.should.deep.equal([], ns.label + ' exposes these functions but bsv.d.ts does not declare them:\n ' + untyped.join('\n '))
122
- })
123
- })
124
- })
@@ -1,102 +0,0 @@
1
- 'use strict'
2
-
3
- /* global describe, it */
4
-
5
- // Runtime half of a field review that found declarations disagreeing with the code.
6
- // The declarations themselves are gated by dts_drift.js and by the tsc check in CI; the
7
- // cases below are the ones where the RUNTIME also had to change, because a declaration
8
- // that merely matched the old behaviour would have been documenting a bug.
9
-
10
- var should = require('chai').should()
11
- var bsv = require('../..')
12
- var SC = bsv.SmartContract
13
-
14
- describe('public surface tells the truth about itself', function () {
15
- describe('SmartContract.ownershipToken forwards its authorizer', function () {
16
- it('is not a two-argument alias that drops the third', function () {
17
- // The top-level alias took (fee, ownerPubKeyHash) and called through with only
18
- // those two, so a co-signed token built via this path came out single-key — the
19
- // authorizer was accepted and silently discarded.
20
- var auth = SC.Authorizers.multisig(2, 3)
21
- var withAuth = SC.ownershipToken(1, Buffer.alloc(20), auth).toHex()
22
- var without = SC.ownershipToken(1, Buffer.alloc(20)).toHex()
23
- withAuth.should.not.equal(without)
24
- })
25
-
26
- it('agrees with SmartContract.Token.ownershipToken', function () {
27
- var auth = SC.Authorizers.multisig(2, 3)
28
- SC.ownershipToken(1, Buffer.alloc(20), auth).toHex()
29
- .should.equal(SC.Token.ownershipToken(1, Buffer.alloc(20), auth).toHex())
30
- })
31
- })
32
-
33
- describe('Authorizers.multisig takes a key COUNT', function () {
34
- it('rejects an array of keys instead of silently building a broken authorizer', function () {
35
- // `m > nKeys` compared a number to an array, which coerces to NaN, so the guard
36
- // passed and the array was interpolated into the authorizer's name.
37
- var keys = [1, 2, 3].map(function () {
38
- return bsv.PrivateKey.fromRandom().toPublicKey().toBuffer()
39
- })
40
- ;(function () { SC.Authorizers.multisig(2, keys) }).should.throw(/NUMBER of keys/)
41
- // The message names the fix.
42
- ;(function () { SC.Authorizers.multisig(2, keys) }).should.throw(/pass 3 instead/)
43
- })
44
-
45
- it('still accepts the documented count form', function () {
46
- SC.Authorizers.multisig(2, 3).n.should.equal(3)
47
- SC.Authorizers.multisig(2, 3).m.should.equal(2)
48
- })
49
-
50
- it('rejects non-integer m', function () {
51
- (function () { SC.Authorizers.multisig('2', 3) }).should.throw(/m must be an integer/)
52
- })
53
- })
54
-
55
- describe('StatusList refuses to record a suspension as a revocation', function () {
56
- it('throws on status: suspended rather than setting the revocation bit', function () {
57
- // Both statuses set the SAME bit and read back as 'revoked', so a suspension was
58
- // silently recorded — and later reported — as a permanent revocation.
59
- return bsv.StatusList.updateStatusList({
60
- listVcJwt: 'x', index: 1, status: 'suspended', privateJwk: {}
61
- }).then(
62
- function () { throw new Error('should not have accepted suspended') },
63
- function (err) { err.message.should.match(/'suspended' is not supported/) }
64
- )
65
- })
66
- })
67
-
68
- describe('securityFeatures describes what is actually shipped', function () {
69
- it('no longer claims elliptic patches, since elliptic is not a dependency', function () {
70
- var pkg = require('../../package.json')
71
- var deps = Object.keys(pkg.dependencies || {})
72
- deps.indexOf('elliptic').should.equal(-1)
73
- bsv.securityFeatures.indexOf('elliptic-patches').should.equal(-1)
74
- bsv.securityFeatures.should.be.an('array')
75
- bsv.securityFeatures.length.should.be.above(0)
76
- })
77
- })
78
-
79
- describe('documented sub-path entry points resolve', function () {
80
- // Every one of these was MODULE_NOT_FOUND: the package `exports` map had no aliases
81
- // for the *-entry.js files, so a documented deep import could not be loaded at all.
82
- var SUBPATHS = ['didweb', 'vcjwt', 'gdaf', 'ltp', 'statuslist', 'shamir',
83
- 'anchor', 'covenant', 'security', 'smartcontract', 'script-helper']
84
-
85
- SUBPATHS.forEach(function (name) {
86
- it('@smartledger/bsv/' + name, function () {
87
- var mod = require('@smartledger/bsv/' + name)
88
- // Some entry points export a class (a function), others a namespace object.
89
- var t = typeof mod
90
- t.should.be.oneOf(['object', 'function'])
91
- should.exist(mod)
92
- })
93
- })
94
-
95
- it('still resolves the package root and lib deep imports', function () {
96
- require('@smartledger/bsv').should.be.an('object')
97
- require('@smartledger/bsv/version').should.be.a('string')
98
- // Directory deep-imports need the explicit file — a documented 7.0 exports break.
99
- require('@smartledger/bsv/lib/ordinals/index.js').should.be.an('object')
100
- })
101
- })
102
- })
package/test/util/id.js DELETED
@@ -1,72 +0,0 @@
1
- 'use strict'
2
-
3
- /* global describe, it */
4
-
5
- require('chai').should()
6
- var expect = require('chai').expect
7
-
8
- var Id = require('../../lib/util/id')
9
-
10
- var UUID_V4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/
11
-
12
- describe('util/id', function () {
13
- describe('#uuid4', function () {
14
- it('produces a well-formed RFC 4122 v4 uuid', function () {
15
- Id.uuid4().should.match(UUID_V4)
16
- })
17
-
18
- it('sets the version and variant bits on every draw', function () {
19
- for (var i = 0; i < 200; i++) {
20
- Id.uuid4().should.match(UUID_V4)
21
- }
22
- })
23
-
24
- it('does not repeat', function () {
25
- var seen = {}
26
- for (var i = 0; i < 2000; i++) {
27
- var id = Id.uuid4()
28
- expect(seen[id], 'duplicate uuid: ' + id).to.equal(undefined)
29
- seen[id] = true
30
- }
31
- })
32
- })
33
-
34
- describe('#randomHex', function () {
35
- it('returns the requested number of hex characters', function () {
36
- Id.randomHex(16).should.match(/^[0-9a-f]{16}$/)
37
- Id.randomHex(12).should.match(/^[0-9a-f]{12}$/)
38
- Id.randomHex(1).should.match(/^[0-9a-f]$/)
39
- })
40
-
41
- it('does not repeat', function () {
42
- var seen = {}
43
- for (var i = 0; i < 2000; i++) {
44
- var id = Id.randomHex(16)
45
- expect(seen[id], 'duplicate id: ' + id).to.equal(undefined)
46
- seen[id] = true
47
- }
48
- })
49
- })
50
-
51
- describe('entropy source', function () {
52
- // Identifiers must come from the CSPRNG. Freezing the engine PRNG must not
53
- // affect them; if it does, they are predictable from observed output.
54
- var withFrozenMathRandom = function (fn) {
55
- var original = Math.random
56
- Math.random = function () { return 0.5 }
57
- try { return fn() } finally { Math.random = original }
58
- }
59
-
60
- it('uuid4 is unaffected by the engine PRNG', function () {
61
- withFrozenMathRandom(function () {
62
- Id.uuid4().should.not.equal(Id.uuid4())
63
- })
64
- })
65
-
66
- it('randomHex is unaffected by the engine PRNG', function () {
67
- withFrozenMathRandom(function () {
68
- Id.randomHex(16).should.not.equal(Id.randomHex(16))
69
- })
70
- })
71
- })
72
- })
package/test/util/js.js DELETED
@@ -1,76 +0,0 @@
1
- 'use strict'
2
-
3
- require('chai').should()
4
-
5
- var bsv = require('../..')
6
- var JSUtil = bsv.util.js
7
-
8
- describe('js utils', function () {
9
- describe('isValidJSON', function () {
10
- var hexa = '8080808080808080808080808080808080808080808080808080808080808080'
11
- var json = '{"key": ["value", "value2"]}'
12
- var json2 = '["value", "value2", {"key": "value"}]'
13
-
14
- it('does not mistake an integer as valid json object', function () {
15
- var valid = JSUtil.isValidJSON(hexa)
16
- valid.should.equal(false)
17
- })
18
-
19
- it('correctly validates a json object', function () {
20
- var valid = JSUtil.isValidJSON(json)
21
- valid.should.equal(true)
22
- })
23
-
24
- it('correctly validates an array json object', function () {
25
- var valid = JSUtil.isValidJSON(json2)
26
- valid.should.equal(true)
27
- })
28
- })
29
-
30
- describe('isNaturalNumber', function () {
31
- it('false for float', function () {
32
- var a = JSUtil.isNaturalNumber(0.1)
33
- a.should.equal(false)
34
- })
35
-
36
- it('false for string float', function () {
37
- var a = JSUtil.isNaturalNumber('0.1')
38
- a.should.equal(false)
39
- })
40
-
41
- it('false for string integer', function () {
42
- var a = JSUtil.isNaturalNumber('1')
43
- a.should.equal(false)
44
- })
45
-
46
- it('false for negative integer', function () {
47
- var a = JSUtil.isNaturalNumber(-1)
48
- a.should.equal(false)
49
- })
50
-
51
- it('false for negative integer string', function () {
52
- var a = JSUtil.isNaturalNumber('-1')
53
- a.should.equal(false)
54
- })
55
-
56
- it('false for infinity', function () {
57
- var a = JSUtil.isNaturalNumber(Infinity)
58
- a.should.equal(false)
59
- })
60
-
61
- it('false for NaN', function () {
62
- var a = JSUtil.isNaturalNumber(NaN)
63
- a.should.equal(false)
64
- })
65
-
66
- it('true for zero', function () {
67
- var a = JSUtil.isNaturalNumber(0)
68
- a.should.equal(true)
69
- })
70
-
71
- it('true for positive integer', function () {
72
- var a = JSUtil.isNaturalNumber(1000)
73
- a.should.equal(true)
74
- })
75
- })
76
- })
@@ -1,79 +0,0 @@
1
- 'use strict'
2
-
3
- var should = require('chai').should()
4
-
5
- var bsv = require('../..')
6
- var errors = bsv.errors
7
- var $ = bsv.util.preconditions
8
- var PrivateKey = bsv.PrivateKey
9
-
10
- describe('preconditions', function () {
11
- it('can be used to assert state', function () {
12
- (function () {
13
- $.checkState(false, 'testing')
14
- }).should.throw(errors.InvalidState)
15
- })
16
- it('throws no false negative', function () {
17
- (function () {
18
- $.checkState(true, 'testing')
19
- }).should.not.throw()
20
- })
21
-
22
- it('can be used to check an argument', function () {
23
- (function () {
24
- $.checkArgument(false, 'testing')
25
- }).should.throw(errors.InvalidArgument);
26
-
27
- (function () {
28
- $.checkArgument(true, 'testing')
29
- }).should.not.throw(errors.InvalidArgument)
30
- })
31
-
32
- it('can be used to check an argument type', function () {
33
- var error
34
- try {
35
- $.checkArgumentType(1, 'string', 'argumentName')
36
- } catch (e) {
37
- error = e
38
- e.message.should.equal('Invalid Argument for argumentName, expected string but got number')
39
- }
40
- should.exist(error)
41
- })
42
- it('has no false negatives when used to check an argument type', function () {
43
- (function () {
44
- $.checkArgumentType('a String', 'string', 'argumentName')
45
- }).should.not.throw()
46
- })
47
-
48
- it('can be used to check an argument type for a class', function () {
49
- var error
50
- try {
51
- $.checkArgumentType(1, PrivateKey)
52
- } catch (e) {
53
- error = e
54
- var fail = !(~e.message.indexOf('Invalid Argument for (unknown name)'))
55
- fail.should.equal(false)
56
- }
57
- should.exist(error)
58
- })
59
- it('has no false negatives when checking a type for a class', function () {
60
- (function () {
61
- $.checkArgumentType(new PrivateKey(), PrivateKey)
62
- }).should.not.throw()
63
- })
64
-
65
- it('formats correctly a message on InvalidArgument()', function () {
66
- var error = new errors.InvalidArgument()
67
- error.message.should.equal('Invalid Argument')
68
- })
69
-
70
- it('formats correctly a message on checkArgument', function () {
71
- var error
72
- try {
73
- $.checkArgument(null, 'parameter must be provided')
74
- } catch (e) {
75
- error = e
76
- }
77
- error.message.should.equal('Invalid Argument: parameter must be provided')
78
- })
79
- })
@@ -1,126 +0,0 @@
1
- 'use strict'
2
-
3
- /* global describe, it */
4
-
5
- // Proves the VC-JWT module is interoperable with the standards-compliant
6
- // `jose` library in BOTH directions, for ES256 (P-256) and ES256K (secp256k1),
7
- // and that algorithm pinning / curve binding reject substitution attacks.
8
-
9
- var assert = require('assert')
10
- var crypto = require('crypto')
11
- var jose = require('jose')
12
- var vcjwt = require('../../lib/vcjwt')
13
-
14
- function genKeys (alg, namedCurve) {
15
- var pair = crypto.generateKeyPairSync('ec', { namedCurve: namedCurve })
16
- var privateJwk = pair.privateKey.export({ format: 'jwk' })
17
- var publicJwk = pair.publicKey.export({ format: 'jwk' })
18
- privateJwk.kid = publicJwk.kid = 'test-key-1'
19
- privateJwk.alg = publicJwk.alg = alg
20
- return { privateJwk: privateJwk, publicJwk: publicJwk }
21
- }
22
-
23
- function resolverFor (publicJwk) {
24
- return function () {
25
- return Promise.resolve({ jwks: { keys: [publicJwk] } })
26
- }
27
- }
28
-
29
- var CASES = [
30
- { alg: 'ES256', curve: 'prime256v1' },
31
- { alg: 'ES256K', curve: 'secp256k1' }
32
- ]
33
-
34
- describe('vcjwt JOSE interop', function () {
35
- CASES.forEach(function (c) {
36
- it('issues a token that ' + c.alg + ' jose can verify (P1363 encoding)', async function () {
37
- var keys = genKeys(c.alg, c.curve)
38
- var issued = await vcjwt.issueVcJwt({
39
- issuerDid: 'did:web:example.com',
40
- subjectId: 'did:web:subject.example',
41
- credentialSubject: { name: 'Alice' },
42
- privateJwk: keys.privateJwk,
43
- alg: c.alg
44
- })
45
- var joseKey = await jose.importJWK(keys.publicJwk, c.alg)
46
- var result = await jose.jwtVerify(issued.jwt, joseKey) // throws if non-compliant
47
- assert.strictEqual(result.payload.iss, 'did:web:example.com')
48
- })
49
-
50
- it('verifies a ' + c.alg + ' token issued by jose', async function () {
51
- var keys = genKeys(c.alg, c.curve)
52
- var josePriv = await jose.importJWK(keys.privateJwk, c.alg)
53
- var joseJwt = await new jose.SignJWT({ vc: { type: ['VerifiableCredential'] } })
54
- .setProtectedHeader({ alg: c.alg, typ: 'JWT', kid: keys.publicJwk.kid })
55
- .setIssuer('did:web:example.com')
56
- .setSubject('did:web:subject.example')
57
- .setIssuedAt()
58
- .setExpirationTime('1y')
59
- .sign(josePriv)
60
- var res = await vcjwt.verifyVcJwt(joseJwt, { didResolver: resolverFor(keys.publicJwk) })
61
- assert.strictEqual(res.valid, true, res.error)
62
- })
63
- })
64
-
65
- it('rejects a token whose alg is not in the allowlist', async function () {
66
- var keys = genKeys('ES256', 'prime256v1')
67
- var issued = await vcjwt.issueVcJwt({
68
- issuerDid: 'did:web:example.com', subjectId: 's', credentialSubject: {}, privateJwk: keys.privateJwk, alg: 'ES256'
69
- })
70
- var res = await vcjwt.verifyVcJwt(issued.jwt, {
71
- allowedAlgs: ['ES256K'],
72
- didResolver: resolverFor(keys.publicJwk)
73
- })
74
- assert.strictEqual(res.valid, false)
75
- assert.ok(/Algorithm not allowed/.test(res.error), res.error)
76
- })
77
-
78
- it('rejects when the resolved key curve does not match the algorithm', async function () {
79
- // ES256 token, but the JWKS serves a secp256k1 key under the same kid.
80
- var p256 = genKeys('ES256', 'prime256v1')
81
- var k1 = genKeys('ES256K', 'secp256k1')
82
- var issued = await vcjwt.issueVcJwt({
83
- issuerDid: 'did:web:example.com', subjectId: 's', credentialSubject: {}, privateJwk: p256.privateJwk, alg: 'ES256'
84
- })
85
- var res = await vcjwt.verifyVcJwt(issued.jwt, { didResolver: resolverFor(k1.publicJwk) })
86
- assert.strictEqual(res.valid, false)
87
- assert.ok(/curve does not match/.test(res.error), res.error)
88
- })
89
-
90
- it('refuses to sign when the key curve does not match the algorithm', async function () {
91
- var k1 = genKeys('ES256K', 'secp256k1')
92
- var threw = false
93
- try {
94
- await vcjwt.issueVcJwt({
95
- issuerDid: 'did:web:example.com', subjectId: 's', credentialSubject: {}, privateJwk: k1.privateJwk, alg: 'ES256'
96
- })
97
- } catch (e) {
98
- threw = /does not match alg/.test(e.message)
99
- }
100
- assert.ok(threw, 'expected curve/alg mismatch to throw')
101
- })
102
-
103
- it('accepts a legacy DER-encoded token only when allowLegacyDER is set', async function () {
104
- // Simulate a <=4.6.0 token: same signing input, but DER-encoded signature.
105
- var keys = genKeys('ES256', 'prime256v1')
106
- var header = { alg: 'ES256', typ: 'JWT', kid: keys.publicJwk.kid }
107
- var payload = { iss: 'did:web:example.com', sub: 's', iat: 1700000000, exp: 4102444800, vc: {} }
108
- var headerB64 = vcjwt.base64UrlEncode(Buffer.from(JSON.stringify(header)))
109
- var payloadB64 = vcjwt.base64UrlEncode(Buffer.from(JSON.stringify(payload)))
110
- var signingInput = headerB64 + '.' + payloadB64
111
- var derSig = crypto.sign('sha256', Buffer.from(signingInput), {
112
- key: crypto.createPrivateKey({ key: keys.privateJwk, format: 'jwk' }),
113
- dsaEncoding: 'der'
114
- })
115
- var legacyJwt = signingInput + '.' + vcjwt.base64UrlEncode(derSig)
116
-
117
- var rejected = await vcjwt.verifyVcJwt(legacyJwt, { didResolver: resolverFor(keys.publicJwk) })
118
- assert.strictEqual(rejected.valid, false, 'legacy DER token must fail by default')
119
-
120
- var accepted = await vcjwt.verifyVcJwt(legacyJwt, {
121
- allowLegacyDER: true,
122
- didResolver: resolverFor(keys.publicJwk)
123
- })
124
- assert.strictEqual(accepted.valid, true, accepted.error)
125
- })
126
- })