@smartledger/bsv 9.0.0 → 9.1.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.
- package/CHANGELOG.md +164 -0
- package/README.md +152 -1041
- package/STABILITY.md +134 -0
- package/bsv-gdaf.min.js +53 -48
- package/bsv-ltp.min.js +23 -18
- package/bsv-smartcontract.min.js +18 -18
- package/bsv.bundle.js +53 -48
- package/bsv.min.js +53 -48
- package/docs/MODULE_REFERENCE_COMPLETE.md +27 -27
- package/docs/advanced/UTXO_MANAGER_GUIDE.md +1 -1
- package/docs/getting-started/INSTALLATION.md +23 -23
- package/docs/getting-started/QUICK_START.md +7 -7
- package/docs/migration/FROM_BSV_1_5_6.md +5 -5
- package/docs/proposals/10.0.0-package-split.md +131 -0
- package/index.js +5 -0
- package/lib/block/merkleblock.js +53 -9
- package/lib/hdprivatekey.js +15 -0
- package/lib/script/interpreter.js +109 -1
- package/lib/smart_contract/builder.js +14 -0
- package/lib/util/deprecate.js +159 -0
- package/package.json +19 -82
- package/version.js +1 -1
- package/.mocharc.json +0 -5
- package/test/address.js +0 -629
- package/test/block/block.js +0 -239
- package/test/block/blockheader.js +0 -270
- package/test/block/merkleblock.js +0 -207
- package/test/build/bundle_crypto_shim.js +0 -104
- package/test/build/bundle_externals.js +0 -125
- package/test/build/bundle_smoke.js +0 -55
- package/test/build/esbuild_main.js +0 -65
- package/test/build/esm_wrapper.js +0 -97
- package/test/build/exports_resolution.js +0 -84
- package/test/build/version_sync.js +0 -14
- package/test/cli/smoke.js +0 -261
- package/test/consensus/base58-vectors.js +0 -120
- package/test/consensus/sv-script-vectors.js +0 -81
- package/test/consensus/sv-sighash-vectors.js +0 -51
- package/test/consensus/sv-tx-vectors.js +0 -48
- package/test/credentials-test.js +0 -332
- package/test/crypto/backend_selection.js +0 -126
- package/test/crypto/bn.js +0 -168
- package/test/crypto/ecdsa.js +0 -426
- package/test/crypto/elliptic-fixed.js +0 -61
- package/test/crypto/hash.browser.js +0 -121
- package/test/crypto/hash.js +0 -122
- package/test/crypto/point.js +0 -193
- package/test/crypto/random.js +0 -105
- package/test/crypto/security.js +0 -176
- package/test/crypto/shamir.js +0 -177
- package/test/crypto/shamir_rngcap.js +0 -29
- package/test/crypto/signature.js +0 -399
- package/test/data/bip69.json +0 -215
- package/test/data/bitcoin-sv/README.md +0 -170
- package/test/data/bitcoin-sv/base58_encode_decode.json +0 -14
- package/test/data/bitcoin-sv/base58_keys_invalid.json +0 -152
- package/test/data/bitcoin-sv/base58_keys_valid.json +0 -452
- package/test/data/bitcoin-sv/script_tests.json +0 -2591
- package/test/data/bitcoin-sv/sighash.json +0 -1003
- package/test/data/bitcoin-sv/tx_invalid.json +0 -285
- package/test/data/bitcoin-sv/tx_valid.json +0 -367
- package/test/data/bitcoind/base58_keys_invalid.json +0 -152
- package/test/data/bitcoind/base58_keys_valid.json +0 -452
- package/test/data/bitcoind/blocks.json +0 -27
- package/test/data/bitcoind/script_tests.json +0 -2244
- package/test/data/bitcoind/sig_canonical.json +0 -7
- package/test/data/bitcoind/sig_noncanonical.json +0 -22
- package/test/data/bitcoind/tx_invalid.json +0 -177
- package/test/data/bitcoind/tx_valid.json +0 -224
- package/test/data/blk86756-testnet.dat +0 -0
- package/test/data/blk86756-testnet.js +0 -12
- package/test/data/blk86756-testnet.json +0 -684
- package/test/data/brc220-batch-vector.json +0 -129
- package/test/data/ecdsa.json +0 -230
- package/test/data/merkleblocks.js +0 -486
- package/test/data/messages.json +0 -22
- package/test/data/sighash.json +0 -1004
- package/test/data/tx_creation.json +0 -85
- package/test/didweb/relationships.js +0 -144
- package/test/ecies/bitcore-ecies.js +0 -178
- package/test/ecies/electrum-ecies.js +0 -206
- package/test/encoding/base58.js +0 -131
- package/test/encoding/base58check.js +0 -145
- package/test/encoding/bufferreader.js +0 -328
- package/test/encoding/bufferwriter.js +0 -160
- package/test/encoding/varint.js +0 -104
- package/test/gdaf/anchor_no_key_leak.js +0 -146
- package/test/gdaf/anchor_spv.js +0 -163
- package/test/gdaf/canonicalization.js +0 -106
- package/test/gdaf/canonicalize.js +0 -140
- package/test/gdaf/zk_prover.js +0 -204
- package/test/hdkeys.js +0 -365
- package/test/hdprivatekey.js +0 -339
- package/test/hdpublickey.js +0 -293
- package/test/index.js +0 -16
- package/test/ltp/ids.js +0 -74
- package/test/ltp/right.js +0 -198
- package/test/ltp/verify_failclosed.js +0 -134
- package/test/message/message.js +0 -190
- package/test/mnemonic/data/fixtures.json +0 -300
- package/test/mnemonic/mnemonic.js +0 -277
- package/test/mnemonic/mocha.opts +0 -1
- package/test/mnemonic/pbkdf2.test.js +0 -43
- package/test/networks.js +0 -207
- package/test/notaryhash/batch_leaf.js +0 -140
- package/test/notaryhash/batch_vector.js +0 -282
- package/test/notaryhash/certificate.js +0 -249
- package/test/notaryhash/encoding.js +0 -186
- package/test/notaryhash/interop.js +0 -112
- package/test/notaryhash/merkle.js +0 -181
- package/test/notaryhash/script.js +0 -270
- package/test/notaryhash/verify.js +0 -342
- package/test/opcode.js +0 -186
- package/test/ordinals/bsv20.js +0 -337
- package/test/ordinals/inscription.js +0 -329
- package/test/ordinals/ordlock.js +0 -567
- package/test/privatekey.js +0 -540
- package/test/publickey.js +0 -411
- package/test/regressions.js +0 -215
- package/test/script/chronicle.js +0 -543
- package/test/script/defaults.js +0 -160
- package/test/script/genesis_limits.js +0 -203
- package/test/script/interpreter.js +0 -776
- package/test/script/script.js +0 -1259
- package/test/script/string_ops.js +0 -88
- package/test/security/fail_closed_contracts.js +0 -104
- package/test/security/threat_model_coverage.js +0 -31
- package/test/smart_contract/covenants.js +0 -207
- package/test/smart_contract/dsl_debugger.js +0 -92
- package/test/smart_contract/extract_field.js +0 -61
- package/test/smart_contract/nonenforcing_guard.js +0 -44
- package/test/smart_contract/ordinal_transfer.js +0 -71
- package/test/smart_contract/preimage.js +0 -98
- package/test/smart_contract/sighash_marketplace.js +0 -98
- package/test/smart_contract/token_generalized.js +0 -175
- package/test/spv/headerchain.js +0 -86
- package/test/spv/merkleproof.js +0 -133
- package/test/statuslist/failclosed.js +0 -78
- package/test/transaction/deserialize.js +0 -33
- package/test/transaction/input/input.js +0 -92
- package/test/transaction/input/multisig.js +0 -174
- package/test/transaction/input/multisigscripthash.js +0 -111
- package/test/transaction/input/publickey.js +0 -68
- package/test/transaction/input/publickeyhash.js +0 -59
- package/test/transaction/output.js +0 -185
- package/test/transaction/sighash.js +0 -91
- package/test/transaction/signature.js +0 -127
- package/test/transaction/transaction.js +0 -1299
- package/test/transaction/unspentoutput.js +0 -97
- package/test/types/dts_drift.js +0 -124
- package/test/types/surface_honesty.js +0 -102
- package/test/util/id.js +0 -72
- package/test/util/js.js +0 -76
- package/test/util/preconditions.js +0 -79
- package/test/vcjwt/interop.js +0 -126
|
@@ -1,342 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
/* global describe, it, before */
|
|
4
|
-
|
|
5
|
-
// BRC-220 verification: the three checks the spec requires, wired together.
|
|
6
|
-
//
|
|
7
|
-
// The plan's stance is that each check must have a test that defeats it IN ISOLATION —
|
|
8
|
-
// a suite where only the conjunction is tested cannot tell you that check 3 was never
|
|
9
|
-
// wired up, because checks 1 and 2 carry the verdict. Each of the three below is broken
|
|
10
|
-
// on its own with the others left intact.
|
|
11
|
-
|
|
12
|
-
require('chai').should()
|
|
13
|
-
var bsv = require('../..')
|
|
14
|
-
var NH = require('../../lib/notaryhash')
|
|
15
|
-
var Encoding = require('../../lib/notaryhash/encoding')
|
|
16
|
-
var Hash = require('../../lib/crypto/hash')
|
|
17
|
-
var BN = require('../../lib/crypto/bn')
|
|
18
|
-
|
|
19
|
-
// The Bitcoin genesis coinbase — one of the reference vectors the spec names, and the
|
|
20
|
-
// only check here that is external to this implementation.
|
|
21
|
-
var GENESIS_COINBASE_RAWTX =
|
|
22
|
-
'01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff' +
|
|
23
|
-
'4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72' +
|
|
24
|
-
'206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff' +
|
|
25
|
-
'0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f' +
|
|
26
|
-
'61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000'
|
|
27
|
-
var GENESIS_COINBASE_TXID = '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b'
|
|
28
|
-
|
|
29
|
-
function rawSig (sig) {
|
|
30
|
-
return Buffer.concat([
|
|
31
|
-
sig.r.toArrayLike(Buffer, 'be', 32),
|
|
32
|
-
sig.s.toArrayLike(Buffer, 'be', 32)
|
|
33
|
-
])
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
describe('BRC-220 verification', function () {
|
|
37
|
-
var key, publicKey, payloadHash, signature, certificate, header, rawTx
|
|
38
|
-
|
|
39
|
-
before(function () {
|
|
40
|
-
key = bsv.PrivateKey.fromRandom()
|
|
41
|
-
publicKey = key.toPublicKey().toBuffer()
|
|
42
|
-
payloadHash = Hash.sha256(Buffer.from('the document nobody sees'))
|
|
43
|
-
|
|
44
|
-
// The signer signs the 32-byte payloadHash DIRECTLY — spec §Algorithms. No endian
|
|
45
|
-
// option: the digest IS the scalar, big-endian. Until 8.3.1 this line passed
|
|
46
|
-
// `endian: 'little'` while the comment above it said "directly", and the suite
|
|
47
|
-
// reversed to match, so the two agreed with each other and with nothing else.
|
|
48
|
-
var ecdsa = bsv.crypto.ECDSA().set({ hashbuf: payloadHash, privkey: key })
|
|
49
|
-
ecdsa.sign()
|
|
50
|
-
signature = rawSig(ecdsa.sig)
|
|
51
|
-
|
|
52
|
-
var createdAt = '2026-08-16T00:00:00.000Z'
|
|
53
|
-
var proofHash = Encoding.proofHash({
|
|
54
|
-
algorithm: 'ECDSA-secp256k1',
|
|
55
|
-
hashAlgorithm: 'SHA-256',
|
|
56
|
-
payloadHash: payloadHash,
|
|
57
|
-
publicKey: publicKey,
|
|
58
|
-
signature: signature,
|
|
59
|
-
createdAtUnix: Encoding.toUnixSeconds(createdAt)
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
// A real transaction carrying the record, so the anchor check has something to read.
|
|
63
|
-
var tx = new bsv.Transaction()
|
|
64
|
-
tx.addOutput(new bsv.Transaction.Output({
|
|
65
|
-
script: NH.Script.build({
|
|
66
|
-
mode: NH.MODE.FULL,
|
|
67
|
-
algorithm: 'ECDSA-secp256k1',
|
|
68
|
-
hashAlgorithm: 'SHA-256',
|
|
69
|
-
payloadHash: payloadHash,
|
|
70
|
-
proofHash: proofHash,
|
|
71
|
-
publicKey: publicKey,
|
|
72
|
-
signature: signature
|
|
73
|
-
}),
|
|
74
|
-
satoshis: 0
|
|
75
|
-
}))
|
|
76
|
-
rawTx = tx.toString()
|
|
77
|
-
var txid = NH.txidFromRawTx(rawTx)
|
|
78
|
-
|
|
79
|
-
// A single-transaction block: the Merkle root is the txid itself, so an empty path
|
|
80
|
-
// folds to it. Proof of work is not required for these fixtures.
|
|
81
|
-
header = new bsv.BlockHeader({
|
|
82
|
-
version: 1,
|
|
83
|
-
prevHash: Buffer.alloc(32),
|
|
84
|
-
merkleRoot: Buffer.from(txid, 'hex').reverse(),
|
|
85
|
-
time: 1786838400,
|
|
86
|
-
bits: 0x1d00ffff,
|
|
87
|
-
nonce: 0
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
certificate = NH.Certificate.attachSPV(
|
|
91
|
-
NH.Certificate.build({
|
|
92
|
-
mode: NH.MODE.FULL,
|
|
93
|
-
algorithm: 'ECDSA-secp256k1',
|
|
94
|
-
hashAlgorithm: 'SHA-256',
|
|
95
|
-
payloadHash: payloadHash,
|
|
96
|
-
publicKey: publicKey,
|
|
97
|
-
signature: signature,
|
|
98
|
-
createdAt: createdAt,
|
|
99
|
-
anchor: { txid: txid, blockHeight: 800000 }
|
|
100
|
-
}),
|
|
101
|
-
{ rawTx: rawTx, blockHash: header.id, blockHeight: 800000, merkleProof: { index: 0, nodes: [] } }
|
|
102
|
-
)
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
var OPTS = function () { return { header: header, requirePow: false } }
|
|
106
|
-
|
|
107
|
-
describe('the happy path', function () {
|
|
108
|
-
it('passes all three checks', function () {
|
|
109
|
-
var report = NH.verify(certificate, OPTS())
|
|
110
|
-
report.signature.should.equal(true)
|
|
111
|
-
report.proofIntegrity.should.equal(true)
|
|
112
|
-
report.anchor.should.equal(true, JSON.stringify(report.errors))
|
|
113
|
-
report.valid.should.equal(true)
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
it('isValid returns a strict boolean', function () {
|
|
117
|
-
NH.isValid(certificate, OPTS()).should.equal(true)
|
|
118
|
-
NH.isValid(certificate, OPTS()).should.be.a('boolean')
|
|
119
|
-
})
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
// Each check defeated on its own, with the other two left working.
|
|
123
|
-
describe('check 1 — signature, defeated in isolation', function () {
|
|
124
|
-
it('fails when the signature is forged, while proof integrity still passes', function () {
|
|
125
|
-
var forged = Object.assign({}, certificate, { signature: 'aa'.repeat(64) })
|
|
126
|
-
var report = NH.verify(forged, OPTS())
|
|
127
|
-
report.signature.should.equal(false)
|
|
128
|
-
report.valid.should.equal(false)
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
it('fails when the certificate names a key that did not sign', function () {
|
|
132
|
-
var other = bsv.PrivateKey.fromRandom().toPublicKey().toBuffer()
|
|
133
|
-
var swapped = Object.assign({}, certificate, { publicKey: other.toString('hex') })
|
|
134
|
-
NH.verify(swapped, OPTS()).signature.should.equal(false)
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
// An unregistered algorithm must FAIL, never fall through to a default. Falling
|
|
138
|
-
// through to ECDSA for an ML-DSA certificate would be catastrophic.
|
|
139
|
-
it('fails for an algorithm no suite is registered for', function () {
|
|
140
|
-
var pq = Object.assign({}, certificate, { algorithm: 'ML-DSA-65' })
|
|
141
|
-
NH.verifySignature(pq).should.equal(false)
|
|
142
|
-
NH.Suites.verify('ML-DSA-65', Buffer.alloc(32), Buffer.alloc(64), Buffer.alloc(33))
|
|
143
|
-
.should.equal(false)
|
|
144
|
-
})
|
|
145
|
-
})
|
|
146
|
-
|
|
147
|
-
describe('check 2 — proof integrity, defeated in isolation', function () {
|
|
148
|
-
// The signature still verifies here: payloadHash, signature and publicKey are
|
|
149
|
-
// untouched. Only proofHash is a lie, and only check 2 can see it.
|
|
150
|
-
it('fails when proofHash is replaced, while the signature still verifies', function () {
|
|
151
|
-
var lying = Object.assign({}, certificate, { proofHash: '00'.repeat(32) })
|
|
152
|
-
var report = NH.verify(lying, OPTS())
|
|
153
|
-
report.signature.should.equal(true)
|
|
154
|
-
report.proofIntegrity.should.equal(false)
|
|
155
|
-
report.valid.should.equal(false)
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
it('fails when createdAt is moved after issuance', function () {
|
|
159
|
-
var moved = Object.assign({}, certificate, { createdAt: '2026-08-17T00:00:00.000Z' })
|
|
160
|
-
NH.verify(moved, OPTS()).proofIntegrity.should.equal(false)
|
|
161
|
-
})
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
describe('check 3 — anchor, defeated in isolation', function () {
|
|
165
|
-
// Signature and proof integrity both still pass; only the anchor is wrong.
|
|
166
|
-
it('fails when rawTx does not hash to anchor.txid', function () {
|
|
167
|
-
var wrongTxid = Object.assign({}, certificate, {
|
|
168
|
-
anchor: { txid: 'ff'.repeat(32), blockHeight: 800000 }
|
|
169
|
-
})
|
|
170
|
-
var report = NH.verify(wrongTxid, OPTS())
|
|
171
|
-
report.signature.should.equal(true)
|
|
172
|
-
report.proofIntegrity.should.equal(true)
|
|
173
|
-
report.anchor.should.equal(false)
|
|
174
|
-
report.errors.should.include('rawTx does not hash to anchor.txid')
|
|
175
|
-
})
|
|
176
|
-
|
|
177
|
-
it('fails when the merkle proof does not fold to the header root', function () {
|
|
178
|
-
var otherHeader = new bsv.BlockHeader({
|
|
179
|
-
version: 1,
|
|
180
|
-
prevHash: Buffer.alloc(32),
|
|
181
|
-
merkleRoot: Buffer.alloc(32, 0x77),
|
|
182
|
-
time: 1786838400,
|
|
183
|
-
bits: 0x1d00ffff,
|
|
184
|
-
nonce: 0
|
|
185
|
-
})
|
|
186
|
-
NH.verifyAnchorSPV(certificate, { header: otherHeader, requirePow: false })
|
|
187
|
-
.valid.should.equal(false)
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
it('fails when the transaction carries no NotaryHash record', function () {
|
|
191
|
-
var empty = new bsv.Transaction()
|
|
192
|
-
empty.addOutput(new bsv.Transaction.Output({
|
|
193
|
-
script: bsv.Script.buildDataOut('nothing to see'), satoshis: 0
|
|
194
|
-
}))
|
|
195
|
-
var swapped = Object.assign({}, certificate, {
|
|
196
|
-
spv: Object.assign({}, certificate.spv, { rawTx: empty.toString() })
|
|
197
|
-
})
|
|
198
|
-
NH.verifyAnchorSPV(swapped, OPTS()).errors.join(' ').should.match(/no NotaryHash record|does not hash/)
|
|
199
|
-
})
|
|
200
|
-
|
|
201
|
-
// THE anchor check. The certificate is internally perfect and the transaction is
|
|
202
|
-
// real; it simply is not the transaction this certificate describes.
|
|
203
|
-
it('fails when the on-chain record describes a different payload', function () {
|
|
204
|
-
var otherPayload = Hash.sha256(Buffer.from('a different document'))
|
|
205
|
-
var tx = new bsv.Transaction()
|
|
206
|
-
tx.addOutput(new bsv.Transaction.Output({
|
|
207
|
-
script: NH.Script.build({
|
|
208
|
-
mode: NH.MODE.FULL,
|
|
209
|
-
algorithm: 'ECDSA-secp256k1',
|
|
210
|
-
hashAlgorithm: 'SHA-256',
|
|
211
|
-
payloadHash: otherPayload,
|
|
212
|
-
proofHash: Buffer.alloc(32, 0x01),
|
|
213
|
-
publicKey: Buffer.from(certificate.publicKey, 'hex'),
|
|
214
|
-
signature: Buffer.from(certificate.signature, 'hex')
|
|
215
|
-
}),
|
|
216
|
-
satoshis: 0
|
|
217
|
-
}))
|
|
218
|
-
var raw = tx.toString()
|
|
219
|
-
var txid = NH.txidFromRawTx(raw)
|
|
220
|
-
var h = new bsv.BlockHeader({
|
|
221
|
-
version: 1,
|
|
222
|
-
prevHash: Buffer.alloc(32),
|
|
223
|
-
merkleRoot: Buffer.from(txid, 'hex').reverse(),
|
|
224
|
-
time: 1786838400,
|
|
225
|
-
bits: 0x1d00ffff,
|
|
226
|
-
nonce: 0
|
|
227
|
-
})
|
|
228
|
-
var mismatched = Object.assign({}, certificate, {
|
|
229
|
-
anchor: { txid: txid, blockHeight: 800000 },
|
|
230
|
-
spv: Object.assign({}, certificate.spv, { rawTx: raw })
|
|
231
|
-
})
|
|
232
|
-
var report = NH.verifyAnchorSPV(mismatched, { header: h, requirePow: false })
|
|
233
|
-
report.valid.should.equal(false)
|
|
234
|
-
report.errors.should.include('on-chain record does not match the certificate')
|
|
235
|
-
})
|
|
236
|
-
|
|
237
|
-
// Not supplying a header is not a pass. This is the trust the spec exists to remove.
|
|
238
|
-
it('refuses to pass without a block header', function () {
|
|
239
|
-
var report = NH.verifyAnchorSPV(certificate, {})
|
|
240
|
-
report.valid.should.equal(false)
|
|
241
|
-
report.errors.join(' ').should.match(/block header is required/)
|
|
242
|
-
})
|
|
243
|
-
|
|
244
|
-
it('reports a missing SPV envelope rather than ignoring the anchor', function () {
|
|
245
|
-
var noSpv = Object.assign({}, certificate)
|
|
246
|
-
delete noSpv.spv
|
|
247
|
-
NH.verifyAnchorSPV(noSpv, OPTS()).errors.should.include('certificate has no SPV envelope')
|
|
248
|
-
})
|
|
249
|
-
})
|
|
250
|
-
|
|
251
|
-
describe('reporting', function () {
|
|
252
|
-
it('names which check failed rather than saying only "invalid"', function () {
|
|
253
|
-
var forged = Object.assign({}, certificate, { signature: 'aa'.repeat(64) })
|
|
254
|
-
NH.verify(forged, OPTS()).errors.should.include('signature does not verify')
|
|
255
|
-
})
|
|
256
|
-
|
|
257
|
-
it('reports shape problems before attempting the checks', function () {
|
|
258
|
-
var report = NH.verify({ protocol: 'NotaryHash' }, OPTS())
|
|
259
|
-
report.shape.length.should.be.above(0)
|
|
260
|
-
report.signature.should.equal(false)
|
|
261
|
-
report.valid.should.equal(false)
|
|
262
|
-
})
|
|
263
|
-
|
|
264
|
-
// skipAnchor is for offline triage and must never report a valid certificate.
|
|
265
|
-
it('never reports valid when the anchor was skipped', function () {
|
|
266
|
-
var report = NH.verify(certificate, { skipAnchor: true })
|
|
267
|
-
report.signature.should.equal(true)
|
|
268
|
-
report.proofIntegrity.should.equal(true)
|
|
269
|
-
report.valid.should.equal(false)
|
|
270
|
-
report.errors.join(' ').should.match(/NOT verified/)
|
|
271
|
-
})
|
|
272
|
-
})
|
|
273
|
-
|
|
274
|
-
describe('txidFromRawTx', function () {
|
|
275
|
-
// External check: the spec names this reference vector, and it is the one assertion
|
|
276
|
-
// here that does not depend on our own construction being right.
|
|
277
|
-
it('matches the Bitcoin genesis coinbase transaction', function () {
|
|
278
|
-
NH.txidFromRawTx(GENESIS_COINBASE_RAWTX).should.equal(GENESIS_COINBASE_TXID)
|
|
279
|
-
})
|
|
280
|
-
|
|
281
|
-
it('accepts a Buffer as well as hex', function () {
|
|
282
|
-
NH.txidFromRawTx(Buffer.from(GENESIS_COINBASE_RAWTX, 'hex')).should.equal(GENESIS_COINBASE_TXID)
|
|
283
|
-
})
|
|
284
|
-
})
|
|
285
|
-
|
|
286
|
-
describe('suite registry', function () {
|
|
287
|
-
it('registers a caller-supplied suite and uses it', function () {
|
|
288
|
-
var called = false
|
|
289
|
-
NH.registerSuite('TEST-SUITE', {
|
|
290
|
-
verify: function () { called = true; return true }
|
|
291
|
-
})
|
|
292
|
-
NH.Suites.verify('TEST-SUITE', Buffer.alloc(32), Buffer.alloc(8), Buffer.alloc(8))
|
|
293
|
-
.should.equal(true)
|
|
294
|
-
called.should.equal(true)
|
|
295
|
-
NH.Suites.unregister('TEST-SUITE')
|
|
296
|
-
})
|
|
297
|
-
|
|
298
|
-
// A suite returning a truthy object must not smuggle a pass through — that is the
|
|
299
|
-
// defect class this codebase has fixed most often.
|
|
300
|
-
it('coerces a truthy non-boolean suite result to false', function () {
|
|
301
|
-
NH.registerSuite('TRUTHY-SUITE', { verify: function () { return { ok: true } } })
|
|
302
|
-
NH.Suites.verify('TRUTHY-SUITE', Buffer.alloc(32), Buffer.alloc(8), Buffer.alloc(8))
|
|
303
|
-
.should.equal(false)
|
|
304
|
-
NH.Suites.unregister('TRUTHY-SUITE')
|
|
305
|
-
})
|
|
306
|
-
|
|
307
|
-
it('survives a throwing suite without reporting a pass', function () {
|
|
308
|
-
NH.registerSuite('THROWS', { verify: function () { throw new Error('boom') } })
|
|
309
|
-
NH.Suites.verify('THROWS', Buffer.alloc(32), Buffer.alloc(8), Buffer.alloc(8))
|
|
310
|
-
.should.equal(false)
|
|
311
|
-
NH.Suites.unregister('THROWS')
|
|
312
|
-
})
|
|
313
|
-
|
|
314
|
-
it('ships only ECDSA-secp256k1 by default', function () {
|
|
315
|
-
NH.Suites.list().should.deep.equal(['ECDSA-secp256k1'])
|
|
316
|
-
})
|
|
317
|
-
})
|
|
318
|
-
|
|
319
|
-
describe('ECDSA suite specifics', function () {
|
|
320
|
-
it('requires low-S, rejecting the malleated form', function () {
|
|
321
|
-
var sig = bsv.crypto.Signature.fromDER(
|
|
322
|
-
new bsv.crypto.Signature(
|
|
323
|
-
BN.fromBuffer(Buffer.from(certificate.signature, 'hex').slice(0, 32)),
|
|
324
|
-
BN.fromBuffer(Buffer.from(certificate.signature, 'hex').slice(32))
|
|
325
|
-
).toDER()
|
|
326
|
-
)
|
|
327
|
-
var high = Buffer.concat([
|
|
328
|
-
sig.r.toArrayLike(Buffer, 'be', 32),
|
|
329
|
-
bsv.crypto.Point.getN().sub(sig.s).toArrayLike(Buffer, 'be', 32)
|
|
330
|
-
])
|
|
331
|
-
NH.Suites.verify('ECDSA-secp256k1', payloadHash, high, publicKey).should.equal(false)
|
|
332
|
-
})
|
|
333
|
-
|
|
334
|
-
it('accepts DER for the legacy encoding', function () {
|
|
335
|
-
var raw = Buffer.from(certificate.signature, 'hex')
|
|
336
|
-
var der = new bsv.crypto.Signature(
|
|
337
|
-
BN.fromBuffer(raw.slice(0, 32)), BN.fromBuffer(raw.slice(32))
|
|
338
|
-
).toDER()
|
|
339
|
-
NH.Suites.verify('ECDSA-secp256k1', payloadHash, der, publicKey).should.equal(true)
|
|
340
|
-
})
|
|
341
|
-
})
|
|
342
|
-
})
|
package/test/opcode.js
DELETED
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
var chai = require('chai')
|
|
4
|
-
var should = chai.should()
|
|
5
|
-
var expect = chai.expect
|
|
6
|
-
var bsv = require('..')
|
|
7
|
-
var Opcode = bsv.Opcode
|
|
8
|
-
|
|
9
|
-
describe('Opcode', function () {
|
|
10
|
-
it('should create a new Opcode', function () {
|
|
11
|
-
var opcode = new Opcode(5)
|
|
12
|
-
should.exist(opcode)
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
it('should convert to a string with this handy syntax', function () {
|
|
16
|
-
Opcode(0).toString().should.equal('OP_0')
|
|
17
|
-
Opcode(96).toString().should.equal('OP_16')
|
|
18
|
-
Opcode(97).toString().should.equal('OP_NOP')
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
it('should convert to a number with this handy syntax', function () {
|
|
22
|
-
Opcode('OP_0').toNumber().should.equal(0)
|
|
23
|
-
Opcode('OP_16').toNumber().should.equal(96)
|
|
24
|
-
Opcode('OP_NOP').toNumber().should.equal(97)
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
describe('#fromNumber', function () {
|
|
28
|
-
it('should work for 0', function () {
|
|
29
|
-
Opcode.fromNumber(0).num.should.equal(0)
|
|
30
|
-
})
|
|
31
|
-
it('should fail for non-number', function () {
|
|
32
|
-
Opcode.fromNumber.bind(null, 'a string').should.throw('Invalid Argument')
|
|
33
|
-
})
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
describe('#set', function () {
|
|
37
|
-
it('should work for object', function () {
|
|
38
|
-
Opcode(42).num.should.equal(42)
|
|
39
|
-
})
|
|
40
|
-
it('should fail for empty-object', function () {
|
|
41
|
-
expect(function () {
|
|
42
|
-
Opcode()
|
|
43
|
-
}).to.throw(TypeError)
|
|
44
|
-
})
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
describe('#toNumber', function () {
|
|
48
|
-
it('should work for 0', function () {
|
|
49
|
-
Opcode.fromNumber(0).toNumber().should.equal(0)
|
|
50
|
-
})
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
describe('#buffer', function () {
|
|
54
|
-
it('should correctly input/output a buffer', function () {
|
|
55
|
-
var buf = Buffer.from('a6', 'hex')
|
|
56
|
-
Opcode.fromBuffer(buf).toBuffer().should.deep.equal(buf)
|
|
57
|
-
})
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
describe('#fromString', function () {
|
|
61
|
-
it('should work for OP_0', function () {
|
|
62
|
-
Opcode.fromString('OP_0').num.should.equal(0)
|
|
63
|
-
})
|
|
64
|
-
it('should fail for invalid string', function () {
|
|
65
|
-
Opcode.fromString.bind(null, 'OP_SATOSHI').should.throw('Invalid opcodestr')
|
|
66
|
-
Opcode.fromString.bind(null, 'BANANA').should.throw('Invalid opcodestr')
|
|
67
|
-
})
|
|
68
|
-
it('should fail for non-string', function () {
|
|
69
|
-
Opcode.fromString.bind(null, 123).should.throw('Invalid Argument')
|
|
70
|
-
})
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
describe('#toString', function () {
|
|
74
|
-
it('should work for OP_0', function () {
|
|
75
|
-
Opcode.fromString('OP_0').toString().should.equal('OP_0')
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
it('should not work for non-opcode', function () {
|
|
79
|
-
expect(function () {
|
|
80
|
-
Opcode('OP_NOTACODE').toString()
|
|
81
|
-
}).to.throw('Opcode does not have a string representation')
|
|
82
|
-
})
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
describe('@map', function () {
|
|
86
|
-
it('should have a map containing 118 elements', function () {
|
|
87
|
-
Object.keys(Opcode.map).length.should.equal(118)
|
|
88
|
-
})
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
describe('@reverseMap', function () {
|
|
92
|
-
it('should exist and have op 185', function () {
|
|
93
|
-
should.exist(Opcode.reverseMap)
|
|
94
|
-
Opcode.reverseMap[185].should.equal('OP_NOP10')
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
// Chronicle reassigns 179-183 and names which NOP each byte used to be, so
|
|
98
|
-
// OP_NOP4..OP_NOP8 cease to exist and OP_NOP9/OP_NOP10 keep their own numbers.
|
|
99
|
-
// Pinning the whole range by name catches a future edit sliding them again —
|
|
100
|
-
// which is how 182 came to parse as a no-op and verify a shift that never ran.
|
|
101
|
-
it('assigns the Chronicle range exactly, with no invented NOPs above it', function () {
|
|
102
|
-
var expected = {
|
|
103
|
-
179: 'OP_SUBSTR',
|
|
104
|
-
180: 'OP_LEFT',
|
|
105
|
-
181: 'OP_RIGHT',
|
|
106
|
-
182: 'OP_LSHIFTNUM',
|
|
107
|
-
183: 'OP_RSHIFTNUM',
|
|
108
|
-
184: 'OP_NOP9',
|
|
109
|
-
185: 'OP_NOP10'
|
|
110
|
-
}
|
|
111
|
-
Object.keys(expected).forEach(function (b) {
|
|
112
|
-
Opcode.reverseMap[b].should.equal(expected[b])
|
|
113
|
-
})
|
|
114
|
-
;[186, 187, 188].forEach(function (b) {
|
|
115
|
-
should.not.exist(Opcode.reverseMap[b])
|
|
116
|
-
})
|
|
117
|
-
;['OP_NOP4', 'OP_NOP5', 'OP_NOP6', 'OP_NOP7', 'OP_NOP8'].forEach(function (n) {
|
|
118
|
-
should.not.exist(Opcode.map[n])
|
|
119
|
-
})
|
|
120
|
-
})
|
|
121
|
-
})
|
|
122
|
-
var smallints = [
|
|
123
|
-
Opcode('OP_0'),
|
|
124
|
-
Opcode('OP_1'),
|
|
125
|
-
Opcode('OP_2'),
|
|
126
|
-
Opcode('OP_3'),
|
|
127
|
-
Opcode('OP_4'),
|
|
128
|
-
Opcode('OP_5'),
|
|
129
|
-
Opcode('OP_6'),
|
|
130
|
-
Opcode('OP_7'),
|
|
131
|
-
Opcode('OP_8'),
|
|
132
|
-
Opcode('OP_9'),
|
|
133
|
-
Opcode('OP_10'),
|
|
134
|
-
Opcode('OP_11'),
|
|
135
|
-
Opcode('OP_12'),
|
|
136
|
-
Opcode('OP_13'),
|
|
137
|
-
Opcode('OP_14'),
|
|
138
|
-
Opcode('OP_15'),
|
|
139
|
-
Opcode('OP_16')
|
|
140
|
-
]
|
|
141
|
-
|
|
142
|
-
describe('@smallInt', function () {
|
|
143
|
-
var testSmallInt = function (n, op) {
|
|
144
|
-
Opcode.smallInt(n).toString().should.equal(op.toString())
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
for (var i = 0; i < smallints.length; i++) {
|
|
148
|
-
var op = smallints[i]
|
|
149
|
-
it('should work for small int ' + op, testSmallInt.bind(null, i, op))
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
it('with not number', function () {
|
|
153
|
-
Opcode.smallInt.bind(null, '2').should.throw('Invalid Argument')
|
|
154
|
-
})
|
|
155
|
-
|
|
156
|
-
it('with n equal -1', function () {
|
|
157
|
-
Opcode.smallInt.bind(null, -1).should.throw('Invalid Argument')
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
it('with n equal 17', function () {
|
|
161
|
-
Opcode.smallInt.bind(null, 17).should.throw('Invalid Argument')
|
|
162
|
-
})
|
|
163
|
-
})
|
|
164
|
-
describe('@isSmallIntOp', function () {
|
|
165
|
-
var testIsSmallInt = function (op) {
|
|
166
|
-
Opcode.isSmallIntOp(op).should.equal(true)
|
|
167
|
-
}
|
|
168
|
-
for (var i = 0; i < smallints.length; i++) {
|
|
169
|
-
var op = smallints[i]
|
|
170
|
-
it('should work for small int ' + op, testIsSmallInt.bind(null, op))
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
it('should work for non-small ints', function () {
|
|
174
|
-
Opcode.isSmallIntOp(Opcode('OP_RETURN')).should.equal(false)
|
|
175
|
-
Opcode.isSmallIntOp(Opcode('OP_CHECKSIG')).should.equal(false)
|
|
176
|
-
Opcode.isSmallIntOp(Opcode('OP_IF')).should.equal(false)
|
|
177
|
-
Opcode.isSmallIntOp(Opcode('OP_NOP')).should.equal(false)
|
|
178
|
-
})
|
|
179
|
-
})
|
|
180
|
-
|
|
181
|
-
describe('#inspect', function () {
|
|
182
|
-
it('should output opcode by name, hex, and decimal', function () {
|
|
183
|
-
Opcode.fromString('OP_NOP').inspect().should.equal('<Opcode: OP_NOP, hex: 61, decimal: 97>')
|
|
184
|
-
})
|
|
185
|
-
})
|
|
186
|
-
})
|