@smartledger/bsv 9.2.0 → 9.4.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 CHANGED
@@ -7,6 +7,139 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [9.4.0] - 2026-09-01
11
+
12
+ ### Fixed — `policy().lockUntil()` did not bind, and `OP_BIN2NUM` used the wrong era's width
13
+
14
+ Two defects, found together because the second is what stops you fixing the first.
15
+
16
+ #### `lockUntil` checked one third of a time lock
17
+
18
+ The compiled script asserted `nLockTime >= floor` and nothing else. A time lock
19
+ is three rules in the node's `CheckLockTime`, and the other two each have a spend
20
+ that walks straight through:
21
+
22
+ - **Sequence.** `IsFinalTx()` ignores `nLockTime` outright when every input is
23
+ `0xffffffff`. A spender who set a final sequence satisfied the script with the
24
+ very locktime it demanded and produced a transaction minable in the next block.
25
+ The honest `unlock()` helper set `0xfffffffe`, so the covenant looked correct
26
+ from inside — and the test that covered the early-locktime case set
27
+ `0xfffffffe` too, which is why nothing caught it.
28
+ - **Units.** Consensus reads `nLockTime` below 500,000,000 as a block height and
29
+ at or above it as a unix timestamp. A bare `>=` compares the two as plain
30
+ numbers, so `1500000000 >= 900000` cleared a floor of block 900,000 with a
31
+ timestamp from July 2017 — a transaction that is final today.
32
+
33
+ Both are now enforced in script: this input must be non-final, and a height floor
34
+ requires the locktime to be a height. `describe()` reports both, and
35
+ `lockUntil(0)` throws, since consensus reads 0 as "no lock" whatever the
36
+ sequences are.
37
+
38
+ This is the same defect that removed `Locks.timeLockCLTV` and `Locks.htlc` in
39
+ 9.0.0 — a time lock that enforces nothing — reappearing in the DSL that replaced
40
+ them. There, the cause was Genesis reverting `OP_CHECKLOCKTIMEVERIFY` to a NOP.
41
+ Here, it was reimplementing `CHECKLOCKTIMEVERIFY` by hand and reproducing only
42
+ its comparison.
43
+
44
+ #### `OP_BIN2NUM` capped every era at the pre-Genesis 4 bytes
45
+
46
+ It range-checked its result with `_isMinimallyEncoded(buf)`, whose `nMaxNumSize`
47
+ argument **defaults to 4**. The node passes `maxScriptNumLength`, which is 4
48
+ before Genesis, 750,000 after it and 32,000,000 after Chronicle.
49
+
50
+ Any unsigned field whose top byte has the sign bit set needs a fifth byte to read
51
+ as positive, so this rejected:
52
+
53
+ - **Every perpetual covenant and ownership token holding 21.47 BSV or more**
54
+ (2³¹ satoshis). Both read the preimage's 8-byte value field through
55
+ `OP_BIN2NUM`, so the coins were locked in and unspendable.
56
+ - **Every `nLockTime` from 19 Jan 2038**, whose high bit is set.
57
+
58
+ The node's own corpus did not catch it: all 25 of its `OP_BIN2NUM` vectors run
59
+ under `P2SH,STRICTENC` alone — pre-Genesis, where 4 is the right answer either
60
+ way. 1,483/1,483 passed before the fix and after it. The opcode was covered; the
61
+ *era* was not, and era selection is where both of this library's consensus
62
+ defects have been.
63
+
64
+ `lockUntil` also needed this: `nLockTime` is unsigned and `OP_BIN2NUM` reads
65
+ signed, so from 2038 the extracted value came back as negative zero and no spend
66
+ could clear the floor. The fix is to sign-pad to five bytes first, and that push
67
+ is only legal once `OP_BIN2NUM` honours the era.
68
+
69
+ #### Upgrading
70
+
71
+ `lockUntil` compiles different bytes, so a UTXO locked by 9.3.0 or earlier cannot
72
+ be spent with a script compiled by this version — keep the compiled object, or
73
+ recompile with the old version. Those locks bind nothing, so treat their coins as
74
+ spendable by anyone and move them.
75
+
76
+ ## [9.3.0] - 2026-08-28
77
+
78
+ ### Added
79
+
80
+ - **Type declarations for every subpath export.** Eleven of the thirteen
81
+ subpaths — `anchor`, `covenant`, `didweb`, `gdaf`, `ltp`, `script-helper`,
82
+ `security`, `shamir`, `smartcontract`, `statuslist`, `vcjwt` — shipped with no
83
+ `types` condition and no declaration file, so
84
+ `import covenant from '@smartledger/bsv/covenant'` was a TS7016 error under
85
+ `node16`/`nodenext` resolution and every symbol behind it was `any`. Each now
86
+ has a declaration; the eight that map onto existing declarations re-export
87
+ them, and `security` (`SmartMiner`) and `script-helper` (`CustomScriptHelper`)
88
+ are newly described, having had no types anywhere.
89
+ - `scripts/check-types.js` and `npm run check:types`, wired into
90
+ `prepublishOnly`. It compiles a fixture of correct usage, then asserts that a
91
+ fixture of *misuse* still fails — a declaration that quietly degrades to `any`
92
+ makes those errors vanish, which is the regression this catches. Resolution
93
+ goes through the real `exports` map rather than tsconfig `paths`.
94
+ - **`buildInscription` can write envelope fields.** `fields` takes tag numbers to
95
+ values and emits them between the content type and the body, in ascending tag
96
+ order so identical input always produces identical bytes. Tag 5 is `metadata`,
97
+ the spec's own home for an object's own record; it previously could not be
98
+ written at all, so the only way to produce one was to assemble envelope bytes by
99
+ hand — permanent, already paid for, and unreported by anything local.
100
+
101
+ Three tags are refused at build time because each is silent afterwards. Tag 0
102
+ opens the body, so a field there does not fail — it becomes part of the file.
103
+ Tag 1 is the content type, and a second one declares it twice. An unrecognized
104
+ EVEN tag costs the inscription its location everywhere: the spec requires such
105
+ an inscription to be treated as unbound. Odd tags are ignored by an indexer that
106
+ does not know them, which is why the spec says it is okay to be odd.
107
+
108
+ `allowUnknownEvenFields` overrides the last of those. It exists because the
109
+ named tag set grows with the protocol, and a library that could never be
110
+ overridden would eventually be wrong AND unbypassable — sending people back to
111
+ hand-assembled bytes, which is worse than what the check prevents.
112
+
113
+ Tags 1..16 are emitted as opcodes and anything larger as a minimal data push,
114
+ since OP_16 is the largest numeric opcode. Script numbers carry sign in the high
115
+ bit of the last byte, so a tag ending >= 0x80 is zero-padded rather than read
116
+ back negative. Verified by round-tripping through `@smartledger/ordinals`, a
117
+ separate implementation: a builder agreeing with its own parser proves only that
118
+ they agree.
119
+
120
+ ### Fixed
121
+
122
+ - **`@types/node` is now a declared dependency.** `bsv.d.ts` carries
123
+ `/// <reference types="node" />` and names `Buffer` 150 times, but nothing
124
+ pulled the types in. A TypeScript consumer without `@types/node` installed got
125
+ `Buffer` widened to `any`, silently disabling type checking on every `Buffer`
126
+ parameter in the public API — `Anchor.sha256Hex(12345)` type-checked cleanly.
127
+ - **`SECURITY.md` described a release line three majors old.** Corrected against
128
+ the code rather than edited in place; every claim below was verified:
129
+ - Supported versions said `6.x` on a 9.x package, and told readers to upgrade
130
+ to "the latest 6.x".
131
+ - The "known residual footgun" section warned that
132
+ `ECDSA.prototype.verify()` returns the truthy *instance* and is "slated for
133
+ removal in the next major". That was fixed in **7.0.0** — it returns a strict
134
+ boolean, `bsv.d.ts` types it `verify(): boolean`, and a contract test locks it
135
+ closed. The policy was warning about a landmine that no longer exists while
136
+ contradicting the package's own declarations.
137
+ - Pinned dependencies were listed as `bn.js@4.12.3` and `bs58@4.0.1`; the
138
+ actual pin is `bn.js@=4.12.5` and `bs58` is no longer a dependency at all.
139
+ - It apologised at length for "currently 17, all dev-only" `npm audit`
140
+ findings. `npm audit` now reports none, dev included.
141
+ - `bsv.d.ts` header advertised "Type definitions for @smartledger/bsv 6.x".
142
+
10
143
  ## [9.2.0] - 2026-08-25
11
144
 
12
145
  ### Added — RFC 8785 canonicalization is now public API
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Bitcoin SV library with an interpreter-verified script engine.
4
4
 
5
- [![Version](https://img.shields.io/badge/version-9.2.0-blue.svg)](https://www.npmjs.com/package/@smartledger/bsv)
5
+ [![Version](https://img.shields.io/badge/version-9.4.0-blue.svg)](https://www.npmjs.com/package/@smartledger/bsv)
6
6
  [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
7
7
  [![Stability](https://img.shields.io/badge/9.x%20stable%20until-2027--09--01-brightgreen.svg)](STABILITY.md)
8
8
 
@@ -155,44 +155,44 @@ const bsv = require('@smartledger/bsv') // 128 modules
155
155
  ### **Core Modules**
156
156
  | Module | Size | Use Case | CDN |
157
157
  |--------|------|----------|-----|
158
- | **bsv.min.js** | 1042KB | Core BSV + SmartContract | `unpkg.com/@smartledger/bsv@9.2.0/bsv.min.js` |
159
- | **bsv.bundle.js** | 1042KB | Everything in one file | `unpkg.com/@smartledger/bsv@9.2.0/bsv.bundle.js` |
158
+ | **bsv.min.js** | 1045KB | Core BSV + SmartContract | `unpkg.com/@smartledger/bsv@9.4.0/bsv.min.js` |
159
+ | **bsv.bundle.js** | 1045KB | Everything in one file | `unpkg.com/@smartledger/bsv@9.4.0/bsv.bundle.js` |
160
160
 
161
161
  ### **W3C Verifiable Credentials**
162
162
  | Module | Size | Use Case | CDN |
163
163
  |--------|------|----------|-----|
164
- | **🟢 bsv-didweb.min.js** | 166KB | **DID:web generation** | `unpkg.com/@smartledger/bsv@9.2.0/bsv-didweb.min.js` |
165
- | **🟢 bsv-vcjwt.min.js** | 166KB | **VC-JWT issue/verify** | `unpkg.com/@smartledger/bsv@9.2.0/bsv-vcjwt.min.js` |
166
- | **🟢 bsv-statuslist.min.js** | 256KB | **StatusList2021 revocation** | `unpkg.com/@smartledger/bsv@9.2.0/bsv-statuslist.min.js` |
167
- | **🟢 bsv-anchor.min.js** | 164KB | **BSV anchoring (hash-only)** | `unpkg.com/@smartledger/bsv@9.2.0/bsv-anchor.min.js` |
164
+ | **🟢 bsv-didweb.min.js** | 166KB | **DID:web generation** | `unpkg.com/@smartledger/bsv@9.4.0/bsv-didweb.min.js` |
165
+ | **🟢 bsv-vcjwt.min.js** | 166KB | **VC-JWT issue/verify** | `unpkg.com/@smartledger/bsv@9.4.0/bsv-vcjwt.min.js` |
166
+ | **🟢 bsv-statuslist.min.js** | 256KB | **StatusList2021 revocation** | `unpkg.com/@smartledger/bsv@9.4.0/bsv-statuslist.min.js` |
167
+ | **🟢 bsv-anchor.min.js** | 164KB | **BSV anchoring (hash-only)** | `unpkg.com/@smartledger/bsv@9.4.0/bsv-anchor.min.js` |
168
168
 
169
169
  ### **Smart Contract & Development**
170
170
  | Module | Size | Use Case | CDN |
171
171
  |--------|------|----------|-----|
172
- | **bsv-smartcontract.min.js** | 140KB | Complete covenant framework | `unpkg.com/@smartledger/bsv@9.2.0/bsv-smartcontract.min.js` |
173
- | **bsv-covenant.min.js** | 35KB | Covenant operations | `unpkg.com/@smartledger/bsv@9.2.0/bsv-covenant.min.js` |
174
- | **bsv-script-helper.min.js** | 33KB | Custom script tools | `unpkg.com/@smartledger/bsv@9.2.0/bsv-script-helper.min.js` |
175
- | **bsv-security.min.js** | 32KB | Security enhancements | `unpkg.com/@smartledger/bsv@9.2.0/bsv-security.min.js` |
172
+ | **bsv-smartcontract.min.js** | 141KB | Complete covenant framework | `unpkg.com/@smartledger/bsv@9.4.0/bsv-smartcontract.min.js` |
173
+ | **bsv-covenant.min.js** | 35KB | Covenant operations | `unpkg.com/@smartledger/bsv@9.4.0/bsv-covenant.min.js` |
174
+ | **bsv-script-helper.min.js** | 33KB | Custom script tools | `unpkg.com/@smartledger/bsv@9.4.0/bsv-script-helper.min.js` |
175
+ | **bsv-security.min.js** | 32KB | Security enhancements | `unpkg.com/@smartledger/bsv@9.4.0/bsv-security.min.js` |
176
176
 
177
177
  ### **Legal & Compliance**
178
178
  | Module | Size | Use Case | CDN |
179
179
  |--------|------|----------|-----|
180
- | **bsv-ltp.min.js** | 539KB | Legal Token Protocol | `unpkg.com/@smartledger/bsv@9.2.0/bsv-ltp.min.js` |
181
- | **bsv-gdaf.min.js** | 1042KB | Digital Identity & Attestation | `unpkg.com/@smartledger/bsv@9.2.0/bsv-gdaf.min.js` |
180
+ | **bsv-ltp.min.js** | 539KB | Legal Token Protocol | `unpkg.com/@smartledger/bsv@9.4.0/bsv-ltp.min.js` |
181
+ | **bsv-gdaf.min.js** | 1045KB | Digital Identity & Attestation | `unpkg.com/@smartledger/bsv@9.4.0/bsv-gdaf.min.js` |
182
182
 
183
183
  ### **Advanced Cryptography**
184
184
  | Module | Size | Use Case | CDN |
185
185
  |--------|------|----------|-----|
186
- | **bsv-shamir.min.js** | 177KB | Threshold Cryptography | `unpkg.com/@smartledger/bsv@9.2.0/bsv-shamir.min.js` |
186
+ | **bsv-shamir.min.js** | 177KB | Threshold Cryptography | `unpkg.com/@smartledger/bsv@9.4.0/bsv-shamir.min.js` |
187
187
 
188
188
  ### **Utilities**
189
189
  | Module | Size | Use Case | CDN |
190
190
  |--------|------|----------|-----|
191
- | **bsv-ecies.min.js** | 137KB | Encryption | `unpkg.com/@smartledger/bsv@9.2.0/bsv-ecies.min.js` |
192
- | **bsv-message.min.js** | 34KB | Message signing | `unpkg.com/@smartledger/bsv@9.2.0/bsv-message.min.js` |
193
- | **bsv-mnemonic.min.js** | 320KB | HD wallets | `unpkg.com/@smartledger/bsv@9.2.0/bsv-mnemonic.min.js` |
191
+ | **bsv-ecies.min.js** | 137KB | Encryption | `unpkg.com/@smartledger/bsv@9.4.0/bsv-ecies.min.js` |
192
+ | **bsv-message.min.js** | 34KB | Message signing | `unpkg.com/@smartledger/bsv@9.4.0/bsv-message.min.js` |
193
+ | **bsv-mnemonic.min.js** | 320KB | HD wallets | `unpkg.com/@smartledger/bsv@9.4.0/bsv-mnemonic.min.js` |
194
194
  ```html
195
- <script src="https://unpkg.com/@smartledger/bsv@9.2.0/bsv.min.js"></script>
195
+ <script src="https://unpkg.com/@smartledger/bsv@9.4.0/bsv.min.js"></script>
196
196
  <script>
197
197
  const key = bsv.PrivateKey.fromRandom()
198
198
  </script>
@@ -240,4 +240,4 @@ MIT
240
240
 
241
241
  ---
242
242
 
243
- **SmartLedger-BSV v9.2.0**
243
+ **SmartLedger-BSV v9.4.0**
package/SECURITY.md CHANGED
@@ -7,14 +7,15 @@ Thank you for helping keep `@smartledger/bsv` and its users safe.
7
7
  Security fixes are applied to the latest major release line. Earlier releases
8
8
  are not patched; please upgrade. **Versions < 6.0.0 contain four CRITICAL
9
9
  fail-open signature/verification bugs and a revocation-bypass (fixed in 6.0.0 —
10
- see CHANGELOG `## [6.0.0]`); upgrading to the latest 6.x is strongly recommended.**
10
+ see CHANGELOG `## [6.0.0]`); upgrading to the latest 9.x is strongly recommended.**
11
11
  Requires **Node.js ≥ 20.19** (the audited crypto dependency `@noble/curves@2` is
12
12
  ESM-only).
13
13
 
14
14
  | Version | Supported |
15
15
  | ------- | ------------------ |
16
- | 6.x | :white_check_mark: |
17
- | < 6.0 | :x: (fail-open verification + revocation-bypass; upgrade to 6.x) |
16
+ | 9.x | :white_check_mark: |
17
+ | 6.x – 8.x | :x: (no longer patched; upgrade to 9.x) |
18
+ | < 6.0 | :x: (fail-open verification + revocation-bypass; upgrade to 9.x) |
18
19
 
19
20
  The security model and the adversarial tests that enforce it are documented in
20
21
  [`docs/THREAT_MODEL.md`](./docs/THREAT_MODEL.md).
@@ -55,24 +56,18 @@ to remain anonymous.
55
56
  forgery, replay, or unauthorized revocation.
56
57
  - Bugs in BIP-143 preimage handling, covenant construction, or LTP/GDAF
57
58
  signing paths.
58
- - Supply-chain concerns about pinned runtime dependencies
59
- (`bn.js@4.12.3`, `bs58@4.0.1`, `@noble/*`, etc.). The runtime dependency
60
- tree carries **no known advisories** (`npm audit --omit=dev` is clean);
61
- `elliptic` was dropped from the runtime/bundle path in 5.4.0.
59
+ - Supply-chain concerns about the runtime dependencies: `@noble/ciphers`,
60
+ `@noble/curves`, `@noble/hashes`, `bn.js` (pinned exactly at `=4.12.5`), and
61
+ `secrets.js-grempe`. The runtime dependency tree carries **no known
62
+ advisories** (`npm audit --omit=dev` is clean); `elliptic` was dropped from
63
+ the runtime/bundle path in 5.4.0, and `bs58` is no longer a dependency.
62
64
 
63
65
  ## Out of Scope
64
66
 
65
- - Vulnerabilities in development-only dependencies (`webpack 5`, `esbuild`,
66
- `standard 12`, `mocha`, `nyc`, `crypto-browserify`, etc.). These never reach
67
- installers — the
68
- published tarball ships no `node_modules` and none are listed under
69
- `dependencies`. The remaining `npm audit` findings (currently 17, all
70
- dev-only) are either upstream-blocked — `mocha`/`nyc` are already at their
71
- latest releases but still range-pin affected transitives (`diff`,
72
- `serialize-javascript`, nested `js-yaml`) — or require the deferred
73
- `standard@17` lint migration (`eslint`/`inquirer`/`tmp` chain) and the
74
- `crypto-browserify` browser-build chain. They are accepted dev-only risk and
75
- tracked separately.
67
+ - Vulnerabilities in development-only dependencies (`esbuild`, `standard`,
68
+ `mocha`, `nyc`, etc.). These never reach installers — the published tarball
69
+ ships no `node_modules` and none are listed under `dependencies`. `npm audit`
70
+ currently reports **no findings at all**, dev included.
76
71
  - Issues that require a malicious local environment (compromised Node, browser
77
72
  extension, or filesystem) to exploit.
78
73
  - Denial-of-service from intentionally malformed inputs that do **not** cross
@@ -100,11 +95,13 @@ return value (an ECDSA *instance*, a stub `{verified:true}`) as if it meant
100
95
  feeds each verify path a forged input and asserts rejection as a strict boolean
101
96
  or a throw. The CI suite is a merge gate.
102
97
 
103
- **Known residual footgun (mitigated).** `ECDSA.prototype.verify()` still returns
104
- the *instance* (truthy) with the result on `.verified` — a landmine if read as a
105
- boolean. It is retained for back-compat, typed to make misuse a compile error
106
- (`verify(): this` vs `verifyBool(): boolean` in `bsv.d.ts`), and pinned by a
107
- test; it is slated for **removal in the next major**. Prefer `verifyBool()`.
98
+ **7.0.0 — the trap was closed.** `ECDSA.prototype.verify()` now returns a strict
99
+ `boolean` rather than the ECDSA instance, so `if (ecdsa.verify())` can no longer
100
+ read a truthy object as "valid". The result is still mirrored on `this.verified`;
101
+ only the chained `.verify().verified` idiom is gone. `bsv.d.ts` types it as
102
+ `verify(): boolean`, and a security-contract test locks it closed — a forgery
103
+ must make `verify()` return `false`. `verifyBool()` remains as an explicit alias.
104
+ See [`docs/MIGRATION_7.md`](docs/MIGRATION_7.md).
108
105
 
109
106
  See [`docs/THREAT_MODEL.md`](./docs/THREAT_MODEL.md) for the full property-by-
110
107
  property security model and the tests that enforce each claim, and the
@@ -115,6 +112,9 @@ property security model and the tests that enforce each claim, and the
115
112
  Significant security-relevant changes are documented in
116
113
  [`CHANGELOG.md`](./CHANGELOG.md). Recent entries of note:
117
114
 
115
+ - **7.0.0** — `ECDSA.prototype.verify()` returns a strict `boolean` instead of the
116
+ (always truthy) ECDSA instance, removing the trap that made `if (ecdsa.verify())`
117
+ accept forged signatures. A security-contract test now enforces it.
118
118
  - **6.0.0** — fixed four CRITICAL fail-open verification bugs (the `ECDSA.verify()`
119
119
  returns-the-instance trap at three call sites plus a `//TODO` stub), a StatusList2021
120
120
  revocation bypass (unverified list bitstring), an ownership-forgery in
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Hash anchoring — build and parse the OP_RETURN payload that commits a hash
3
+ * to chain, and check data against an anchored hash.
4
+ *
5
+ * Same surface as `require("@smartledger/bsv").Anchor`.
6
+ */
7
+ import { Anchor } from '@smartledger/bsv';
8
+ export = Anchor;