@smartledger/bsv 7.10.1 → 7.12.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.
- package/CHANGELOG.md +109 -0
- package/README.md +38 -38
- package/bsv-anchor.min.js +11 -17
- package/bsv-didweb.min.js +11 -17
- package/bsv-gdaf.min.js +69 -75
- package/bsv-ltp.min.js +55 -61
- package/bsv-mnemonic.min.js +11 -17
- package/bsv-shamir.min.js +11 -17
- package/bsv-smartcontract.min.js +1 -1
- package/bsv-statuslist.min.js +53 -59
- package/bsv-vcjwt.min.js +11 -17
- package/bsv.bundle.js +69 -75
- package/bsv.d.ts +15 -0
- package/bsv.min.js +69 -75
- package/build/esbuild/crypto-shim.js +35 -0
- package/build/esbuild.js +7 -3
- package/docs/AUDIT_SCOPE.md +199 -0
- 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/script/interpreter.js +50 -0
- package/package.json +13 -2
- package/test/build/bundle_crypto_shim.js +104 -0
- package/test/build/bundle_externals.js +12 -3
- package/test/script/chronicle.js +40 -3
- package/version.js +1 -1
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/* global describe, it, before */
|
|
4
|
+
|
|
5
|
+
// The browser `crypto` polyfill is our own three-function shim, not crypto-browserify.
|
|
6
|
+
//
|
|
7
|
+
// Two things have to hold, and neither is visible to a test that stays inside lib/.
|
|
8
|
+
//
|
|
9
|
+
// 1. `elliptic` must not re-enter the bundles. It carries an advisory with no patched
|
|
10
|
+
// version, and it is reachable from crypto-browserify via browserify-sign and
|
|
11
|
+
// create-ecdh. build/esbuild.js used to keep it out with a hand-written onResolve
|
|
12
|
+
// stub; removing crypto-browserify removed the need for the stub, and this file
|
|
13
|
+
// replaces it. A stub is silent when it stops matching — an assertion is not.
|
|
14
|
+
//
|
|
15
|
+
// 2. The shim must keep implementing what the bundles actually call. If someone adds a
|
|
16
|
+
// `crypto.pbkdf2` call to a bundled module, resolution still succeeds and the member
|
|
17
|
+
// is simply `undefined`, so the failure surfaces far from its cause.
|
|
18
|
+
//
|
|
19
|
+
// The known-answer test exists because "the bundle builds" and "the bundle hashes
|
|
20
|
+
// correctly" are different claims, and only the second one matters to a caller.
|
|
21
|
+
|
|
22
|
+
require('chai').should()
|
|
23
|
+
var crypto = require('crypto')
|
|
24
|
+
var esbuild = require('../../build/esbuild.js')
|
|
25
|
+
var shim = require('../../build/esbuild/crypto-shim.js')
|
|
26
|
+
|
|
27
|
+
// Reachable from crypto-browserify; `elliptic` is the one with no fix available.
|
|
28
|
+
var BANNED = ['elliptic', 'browserify-sign', 'create-ecdh', 'crypto-browserify']
|
|
29
|
+
|
|
30
|
+
describe('browser crypto shim', function () {
|
|
31
|
+
this.timeout(300000)
|
|
32
|
+
|
|
33
|
+
var pkgsByBundle = {}
|
|
34
|
+
|
|
35
|
+
before(function () {
|
|
36
|
+
return Promise.all(esbuild.BUNDLES.map(function (cfg) {
|
|
37
|
+
return esbuild.buildOne(cfg, { metafile: true, write: false, logLevel: 'silent' })
|
|
38
|
+
.then(function (result) {
|
|
39
|
+
pkgsByBundle[cfg.file] = Object.keys(result.metafile.inputs)
|
|
40
|
+
.map(function (p) {
|
|
41
|
+
var m = /node_modules\/((?:@[^/]+\/)?[^/]+)\//.exec(p)
|
|
42
|
+
return m && m[1]
|
|
43
|
+
})
|
|
44
|
+
.filter(Boolean)
|
|
45
|
+
})
|
|
46
|
+
}))
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('built every bundle', function () {
|
|
50
|
+
esbuild.BUNDLES.length.should.be.above(0)
|
|
51
|
+
Object.keys(pkgsByBundle).length.should.equal(esbuild.BUNDLES.length)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
// Guard against the graph being empty for an unrelated reason, which would make the
|
|
55
|
+
// "no banned packages" assertion below pass without checking anything.
|
|
56
|
+
it('resolved a non-trivial dependency graph', function () {
|
|
57
|
+
Object.keys(pkgsByBundle).forEach(function (file) {
|
|
58
|
+
pkgsByBundle[file].length.should.be.above(0, file + ' has no node_modules inputs')
|
|
59
|
+
})
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('pulls no part of the elliptic chain into any bundle', function () {
|
|
63
|
+
var offenders = []
|
|
64
|
+
Object.keys(pkgsByBundle).forEach(function (file) {
|
|
65
|
+
BANNED.forEach(function (pkg) {
|
|
66
|
+
if (pkgsByBundle[file].indexOf(pkg) !== -1) offenders.push(file + ' → ' + pkg)
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
offenders.should.deep.equal([])
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it('exports exactly the members the bundles call', function () {
|
|
73
|
+
Object.keys(shim).sort().should.deep.equal(['createHash', 'createHmac', 'randomBytes'])
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
// Deliberately absent: secrets.js-grempe prefers getRandomValues over randomBytes when
|
|
77
|
+
// it is present, so exporting it would silently move the Shamir CSPRNG to another code
|
|
78
|
+
// path. crypto-browserify did not expose it either.
|
|
79
|
+
it('does not expose getRandomValues', function () {
|
|
80
|
+
;(shim.getRandomValues === undefined).should.equal(true)
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it('hashes identically to node crypto', function () {
|
|
84
|
+
['', 'abc', 'The quick brown fox jumps over the lazy dog'].forEach(function (input) {
|
|
85
|
+
;['sha1', 'sha256', 'sha512', 'ripemd160'].forEach(function (alg) {
|
|
86
|
+
shim.createHash(alg).update(input).digest('hex')
|
|
87
|
+
.should.equal(crypto.createHash(alg).update(input).digest('hex'), alg + ' of ' + JSON.stringify(input))
|
|
88
|
+
})
|
|
89
|
+
})
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
it('hmacs identically to node crypto', function () {
|
|
93
|
+
shim.createHmac('sha512', Buffer.from('key')).update('message').digest('hex')
|
|
94
|
+
.should.equal(crypto.createHmac('sha512', Buffer.from('key')).update('message').digest('hex'))
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
it('draws distinct random bytes of the requested length', function () {
|
|
98
|
+
var a = shim.randomBytes(32)
|
|
99
|
+
var b = shim.randomBytes(32)
|
|
100
|
+
a.length.should.equal(32)
|
|
101
|
+
b.length.should.equal(32)
|
|
102
|
+
a.toString('hex').should.not.equal(b.toString('hex'))
|
|
103
|
+
})
|
|
104
|
+
})
|
|
@@ -68,9 +68,18 @@ describe('feature bundles externalise the shared primitives', function () {
|
|
|
68
68
|
// from an externalised entry would bundle a second copy silently, with every existing
|
|
69
69
|
// test green.
|
|
70
70
|
it('contains only its own feature code, pinned per bundle', function () {
|
|
71
|
-
// Accepted in any bundle:
|
|
72
|
-
//
|
|
73
|
-
|
|
71
|
+
// Accepted in any bundle: stateless helpers, deliberately duplicated rather than
|
|
72
|
+
// routed through the global.
|
|
73
|
+
//
|
|
74
|
+
// Named FILES, not the directory. `lib/util/` as a prefix exempts anything added
|
|
75
|
+
// under it later, including something stateful — which is the property this test
|
|
76
|
+
// exists to prevent. Listing them means a new util file has to be considered.
|
|
77
|
+
//
|
|
78
|
+
// And listing ONLY what is actually embedded, for the same reason: naming a file
|
|
79
|
+
// that no bundle pulls in pre-approves it, so the consideration never happens.
|
|
80
|
+
// Measured — `lib/util/_.js` is the only one today. If a bundle starts needing
|
|
81
|
+
// another, this line should change in the same commit that causes it.
|
|
82
|
+
var SHARED = ['lib/util/_.js']
|
|
74
83
|
var EXPECTED = {
|
|
75
84
|
'bsv-ecies.min.js': ['lib/ecies/'],
|
|
76
85
|
'bsv-message.min.js': ['lib/message/'],
|
package/test/script/chronicle.js
CHANGED
|
@@ -35,7 +35,10 @@ function run (build, opts) {
|
|
|
35
35
|
return {
|
|
36
36
|
verified: verified,
|
|
37
37
|
errstr: interp.errstr || '',
|
|
38
|
-
stack: (interp.stack || []).map(function (b) { return BN.fromScriptNumBuffer(b).toString() })
|
|
38
|
+
stack: (interp.stack || []).map(function (b) { return BN.fromScriptNumBuffer(b).toString() }),
|
|
39
|
+
// The raw bytes as well: several Chronicle behaviours are about WIDTH, not
|
|
40
|
+
// value, and a script-number reading collapses that distinction.
|
|
41
|
+
raw: (interp.stack || []).map(function (b) { return Buffer.from(b) })
|
|
39
42
|
}
|
|
40
43
|
}
|
|
41
44
|
|
|
@@ -53,8 +56,37 @@ describe('Chronicle script surface', function () {
|
|
|
53
56
|
})
|
|
54
57
|
})
|
|
55
58
|
|
|
56
|
-
|
|
57
|
-
|
|
59
|
+
// This assertion used to read `(Interpreter.DEFAULT_FLAGS & CHRONICLE).should.equal(0)`
|
|
60
|
+
// — and Interpreter.DEFAULT_FLAGS does not exist, so it evaluated `undefined & n`,
|
|
61
|
+
// which is 0 for every n. A tautology, written by me, in the same change that added
|
|
62
|
+
// the flag. What it MEANT to assert is that verify() enables nothing on its own.
|
|
63
|
+
it('is not enabled unless the caller asks: verify() defaults to no flags', function () {
|
|
64
|
+
// Deliberately NOT via run(): that helper defaults to CHRONICLE, so it would
|
|
65
|
+
// measure the helper rather than the library. Omit the argument entirely.
|
|
66
|
+
var script = new Script().add(Opcode.OP_VER)
|
|
67
|
+
var interp = new Interpreter()
|
|
68
|
+
var verified = interp.verify(new Script(), script, new bsv.Transaction(), 0)
|
|
69
|
+
verified.should.equal(false)
|
|
70
|
+
interp.errstr.should.match(/BAD_OPCODE/)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('mainnetFlags() opts in, and can opt out for a pre-activation UTXO', function () {
|
|
74
|
+
// Chronicle gates PER UTXO in the node (`utxo_after_chronicle`), so the library
|
|
75
|
+
// cannot decide this globally — it can only make both answers easy to express.
|
|
76
|
+
(Interpreter.mainnetFlags() & CHRONICLE).should.not.equal(0)
|
|
77
|
+
;(Interpreter.mainnetFlags({ afterChronicle: false }) & CHRONICLE).should.equal(0)
|
|
78
|
+
Interpreter.CHRONICLE_ACTIVATION_HEIGHT.should.equal(943816)
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it('mainnetFlags() actually evaluates a Chronicle script', function () {
|
|
82
|
+
var r = run(function (s) { s.add(Opcode.OP_VER) },
|
|
83
|
+
{ flags: Interpreter.mainnetFlags(), version: 7 })
|
|
84
|
+
r.stack[r.stack.length - 1].should.equal('7')
|
|
85
|
+
|
|
86
|
+
var pre = run(function (s) { s.add(Opcode.OP_VER) },
|
|
87
|
+
{ flags: Interpreter.mainnetFlags({ afterChronicle: false }), version: 7 })
|
|
88
|
+
pre.verified.should.equal(false)
|
|
89
|
+
pre.errstr.should.match(/BAD_OPCODE/)
|
|
58
90
|
})
|
|
59
91
|
})
|
|
60
92
|
|
|
@@ -109,6 +141,11 @@ describe('Chronicle script surface', function () {
|
|
|
109
141
|
;[1, 2, 10].forEach(function (v) {
|
|
110
142
|
var r = run(function (s) { s.add(Opcode.OP_VER) }, { version: v })
|
|
111
143
|
r.stack[r.stack.length - 1].should.equal(String(v))
|
|
144
|
+
// LENGTH too, not just the numeric reading. `01000000` and `01` both read
|
|
145
|
+
// as 1, so the value check alone passes whether OP_VER pushes four
|
|
146
|
+
// little-endian bytes or a minimally-encoded script number — and pushing
|
|
147
|
+
// the script number was the bug fixed in #95.
|
|
148
|
+
r.raw[r.raw.length - 1].length.should.equal(4)
|
|
112
149
|
})
|
|
113
150
|
})
|
|
114
151
|
})
|
package/version.js
CHANGED