@smartledger/bsv 6.0.0 → 6.0.2
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 +46 -0
- package/README.md +38 -38
- package/bsv-covenant.min.js +2 -2
- package/bsv-gdaf.min.js +2 -2
- package/bsv-ltp.min.js +2 -2
- package/bsv-smartcontract.min.js +2 -2
- package/bsv.bundle.js +2 -2
- package/bsv.d.ts +9 -3
- package/bsv.min.js +2 -2
- 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/lib/ordinals/bsv20.js +4 -2
- package/lib/ordinals/ordlock.js +39 -14
- package/package.json +4 -1
- package/test/ordinals/bsv20.js +10 -0
- package/test/ordinals/ordlock.js +70 -0
- package/test/security/fail_closed_contracts.js +100 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/* global describe, it */
|
|
4
|
+
|
|
5
|
+
// FAIL-CLOSED CONTRACTS — a mechanical guard for the operating principle that every
|
|
6
|
+
// security-critical verification "returns a bool or throws, never a chainable object"
|
|
7
|
+
// and that a forged/invalid input is REJECTED (never accepted).
|
|
8
|
+
//
|
|
9
|
+
// This exists because the v6.0.0 security-hardening pass fixed four CRITICAL fail-open
|
|
10
|
+
// forgery bugs, all of the same shape: code read a truthy return value (an ECDSA
|
|
11
|
+
// *instance*, a stub `{verified:true}`) as if it meant "valid". These tests assert the
|
|
12
|
+
// negative — a bad input must not verify — and pin the return-type contract so a
|
|
13
|
+
// regression to fail-open trips a red test instead of shipping.
|
|
14
|
+
|
|
15
|
+
require('chai').should()
|
|
16
|
+
var assert = require('assert')
|
|
17
|
+
var bsv = require('../..')
|
|
18
|
+
|
|
19
|
+
var Hash = bsv.crypto.Hash
|
|
20
|
+
var ECDSA = bsv.crypto.ECDSA
|
|
21
|
+
|
|
22
|
+
function isStrictBool (v) { return v === true || v === false }
|
|
23
|
+
|
|
24
|
+
describe('security: fail-closed verification contracts', function () {
|
|
25
|
+
// A signature over `hash` by `signer`, and a different key it was NOT signed by.
|
|
26
|
+
var signer = bsv.PrivateKey.fromRandom()
|
|
27
|
+
var hash = Hash.sha256(Buffer.from('the message'))
|
|
28
|
+
var goodSig = ECDSA.sign(hash, signer)
|
|
29
|
+
var rightPub = signer.toPublicKey()
|
|
30
|
+
var wrongPub = bsv.PrivateKey.fromRandom().toPublicKey()
|
|
31
|
+
|
|
32
|
+
describe('ECDSA signature verification', function () {
|
|
33
|
+
it('static ECDSA.verify returns a STRICT boolean (never a truthy object)', function () {
|
|
34
|
+
isStrictBool(ECDSA.verify(hash, goodSig, rightPub)).should.equal(true)
|
|
35
|
+
isStrictBool(ECDSA.verify(hash, goodSig, wrongPub)).should.equal(true)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('static ECDSA.verify accepts a valid signature and REJECTS a forged one', function () {
|
|
39
|
+
ECDSA.verify(hash, goodSig, rightPub).should.equal(true)
|
|
40
|
+
ECDSA.verify(hash, goodSig, wrongPub).should.equal(false) // forged: wrong key
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('instance verifyBool() is the safe boolean path and fails closed on a forgery', function () {
|
|
44
|
+
function inst (pub) {
|
|
45
|
+
var e = new ECDSA(); e.hashbuf = hash; e.sig = goodSig; e.pubkey = pub; return e
|
|
46
|
+
}
|
|
47
|
+
isStrictBool(inst(rightPub).verifyBool()).should.equal(true)
|
|
48
|
+
inst(rightPub).verifyBool().should.equal(true)
|
|
49
|
+
inst(wrongPub).verifyBool().should.equal(false)
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
// Locks the documented trap: instance .verify() returns the INSTANCE (truthy), so it
|
|
53
|
+
// must never be read as a boolean. If this ever changes (e.g. a deliberate 7.0 that
|
|
54
|
+
// makes verify() return a bool), this test forces the change to be intentional.
|
|
55
|
+
it('instance .verify() returns the instance with the result on .verified (documented trap)', function () {
|
|
56
|
+
var e = new ECDSA(); e.hashbuf = hash; e.sig = goodSig; e.pubkey = wrongPub
|
|
57
|
+
var r = e.verify()
|
|
58
|
+
;(typeof r).should.equal('object') // NOT a boolean — the trap
|
|
59
|
+
isStrictBool(r.verified).should.equal(true)
|
|
60
|
+
r.verified.should.equal(false) // forged → verified is false, even though `r` is truthy
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
describe('SmartVerify (hardened secp256k1 verify)', function () {
|
|
65
|
+
it('returns a STRICT boolean and rejects a forged signature', function () {
|
|
66
|
+
var ok = bsv.SmartVerify.smartVerify(hash, goodSig.toBuffer(), rightPub)
|
|
67
|
+
var bad = bsv.SmartVerify.smartVerify(hash, goodSig.toBuffer(), wrongPub)
|
|
68
|
+
isStrictBool(ok).should.equal(true)
|
|
69
|
+
isStrictBool(bad).should.equal(true)
|
|
70
|
+
ok.should.equal(true)
|
|
71
|
+
bad.should.equal(false)
|
|
72
|
+
})
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
describe('SPV inclusion / header-chain verification', function () {
|
|
76
|
+
it('verifyHeaderChain fails closed on empty / malformed input (throws, not truthy)', function () {
|
|
77
|
+
assert.throws(function () { bsv.SPV.verifyHeaderChain([], {}) })
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it('verifyMerkleProof rejects a bad proof without ever returning a truthy non-boolean', function () {
|
|
81
|
+
var fakeRoot = Buffer.alloc(32, 1)
|
|
82
|
+
var fakeTxid = Buffer.alloc(32, 2)
|
|
83
|
+
var res
|
|
84
|
+
try {
|
|
85
|
+
res = bsv.SPV.verifyMerkleProof(fakeTxid, { index: 0, nodes: ['00'.repeat(32)] }, fakeRoot)
|
|
86
|
+
} catch (e) { res = false } // throwing is an acceptable fail-closed outcome
|
|
87
|
+
// Whatever the shape, it must not be a truthy value that reads as "included".
|
|
88
|
+
var included = (res === true) || (res && res.valid === true) || (res && res.verified === true)
|
|
89
|
+
included.should.equal(false)
|
|
90
|
+
})
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
describe('SmartContract script verification', function () {
|
|
94
|
+
it('verifyScript reports a boolean ok and fails an unsatisfiable lock', function () {
|
|
95
|
+
var r = bsv.SmartContract.verifyScript(new bsv.Script(), new bsv.Script().add(bsv.Opcode.OP_FALSE))
|
|
96
|
+
isStrictBool(r.ok).should.equal(true)
|
|
97
|
+
r.ok.should.equal(false)
|
|
98
|
+
})
|
|
99
|
+
})
|
|
100
|
+
})
|