@smartledger/bsv 9.9.0 โ†’ 9.10.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.
@@ -159,17 +159,17 @@ const recovered = bsv.reconstructSecret([shares[0], shares[2], shares[4]]);
159
159
  ### **New Modular Options**
160
160
  ```html
161
161
  <!-- Core compatibility (same size as bsv@1.5.6) -->
162
- <script src="https://unpkg.com/@smartledger/bsv@9.9.0/bsv.min.js"></script>
162
+ <script src="https://unpkg.com/@smartledger/bsv@9.10.1/bsv.min.js"></script>
163
163
 
164
164
  <!-- Add smart contracts when ready -->
165
- <script src="https://unpkg.com/@smartledger/bsv@9.9.0/bsv-smartcontract.min.js"></script>
165
+ <script src="https://unpkg.com/@smartledger/bsv@9.10.1/bsv-smartcontract.min.js"></script>
166
166
 
167
167
  <!-- Add advanced features as needed -->
168
- <script src="https://unpkg.com/@smartledger/bsv@9.9.0/bsv-ltp.min.js"></script>
169
- <script src="https://unpkg.com/@smartledger/bsv@9.9.0/bsv-gdaf.min.js"></script>
168
+ <script src="https://unpkg.com/@smartledger/bsv@9.10.1/bsv-ltp.min.js"></script>
169
+ <script src="https://unpkg.com/@smartledger/bsv@9.10.1/bsv-gdaf.min.js"></script>
170
170
 
171
171
  <!-- Everything in one file -->
172
- <script src="https://unpkg.com/@smartledger/bsv@9.9.0/bsv.bundle.js"></script>
172
+ <script src="https://unpkg.com/@smartledger/bsv@9.10.1/bsv.bundle.js"></script>
173
173
  ```
174
174
 
175
175
  ## ๐Ÿ” **Testing Your Migration**
@@ -101,11 +101,11 @@ var LEGACY_VERSION = 1
101
101
  var LEGACY_MODE = { 0: 'full', 1: 'hybrid', 2: 'full' }
102
102
 
103
103
  var HEX_RE = /^[0-9a-fA-F]*$/
104
- // The reference decodes base64 with Buffer.from(value, 'base64'), which also takes the
105
- // URL-safe alphabet and missing padding. Those are accepted here too, so nothing the
106
- // reference reads is refused. What is NOT accepted is any other character: Buffer.from
107
- // skips those silently, turning a corrupted field into different bytes instead of an
108
- // error.
104
+ // Both RFC 4648 alphabets (ยง4 standard, ยง5 URL-safe) and missing padding are accepted, as
105
+ // the reference accepts them. What is NOT accepted is anything that is not base64: a
106
+ // character outside the alphabet, padding out of place, or a length no byte string
107
+ // encodes. Buffer.from skips the first and truncates the last, turning a corrupted field
108
+ // into different bytes instead of an error.
109
109
  var BASE64_RE = /^[A-Za-z0-9+/_-]*={0,2}$/
110
110
 
111
111
  /**
@@ -131,6 +131,10 @@ Certificate.decodeBytes = function (value, encoding, name) {
131
131
  }
132
132
  if (encoding === Certificate.ENCODING.BASE64) {
133
133
  if (!BASE64_RE.test(value)) throw new Error(name + ' must be base64')
134
+ var body = value.replace(/=+$/, '')
135
+ if ((body.length !== value.length && value.length % 4 !== 0) || body.length % 4 === 1) {
136
+ throw new Error(name + ' is not a valid base64 length')
137
+ }
134
138
  return Buffer.from(value, 'base64')
135
139
  }
136
140
  throw new Error('encoding must be "hex" or "base64", not ' + JSON.stringify(encoding))
@@ -165,6 +165,8 @@ NotaryHash.recordMatchesCertificate = function (record, certificate) {
165
165
  * @param {Object} certificate - must carry an `spv` envelope
166
166
  * @param {Object} opts
167
167
  * @param {String|Buffer|BlockHeader} opts.header - independently obtained
168
+ * @param {Number} [opts.height] - the height the header was obtained at. A header's 80
169
+ * bytes do not carry it, so it is checked against spv.blockHeight only when supplied.
168
170
  * @param {Boolean} [opts.requirePow=true] - pass false only for test fixtures
169
171
  * @returns {Object} { valid, errors }
170
172
  */
@@ -221,6 +223,13 @@ NotaryHash.verifyAnchorSPV = function (certificate, opts) {
221
223
  errors.push('the supplied header is not the block the SPV envelope names')
222
224
  }
223
225
 
226
+ // And "at spv.blockHeight". A header does not say what height it is at โ€” that comes
227
+ // from wherever the caller obtained it โ€” so a caller that knows passes it. It cannot be
228
+ // required without breaking every caller that holds only the 80 bytes.
229
+ if (opts.height !== undefined && opts.height !== spv.blockHeight) {
230
+ errors.push('the supplied header is not at the height the SPV envelope names')
231
+ }
232
+
224
233
  return { valid: errors.length === 0, errors: errors }
225
234
  } catch (e) {
226
235
  return { valid: false, errors: ['anchor verification error: ' + e.message] }
@@ -303,6 +312,7 @@ function merkleFolds (c, failure) {
303
312
  * @param {Object} certificate
304
313
  * @param {Object} [opts]
305
314
  * @param {String|Buffer} [opts.header] - an independently obtained block header
315
+ * @param {Number} [opts.height] - the height it was obtained at; see verifyAnchorSPV
306
316
  * @param {Boolean} [opts.skipAnchor] - check 1 and 2 only; the result is NOT a valid
307
317
  * certificate, and `valid` will be false. For offline triage.
308
318
  * @returns {Object} { valid, signature, proofIntegrity, anchor, batchInclusion, shape,
@@ -107,8 +107,8 @@ Suites.verify = function (algorithm, payloadHash, signature, publicKey) {
107
107
  * What it accepts is what the reference implementation accepts, because a verifier that
108
108
  * refuses certificates the reference issued is not a BRC-220 verifier:
109
109
  *
110
- * - a signature of 64 bytes, `r || s`, each a 32-byte big-endian integer, OR DER,
111
- * told apart by the bytes themselves (DER opens with 0x30 and is not 64 bytes). The
110
+ * - a signature of 64 bytes, `r || s`, each a 32-byte big-endian integer, OR DER. A
111
+ * 64-byte signature is always read as r || s; anything else must parse as DER. The
112
112
  * certificate's `encoding` field says how the bytes are WRITTEN โ€” hex or base64 โ€” and
113
113
  * nothing about which of these they are;
114
114
  * - a 33-byte compressed or 65-byte uncompressed public key;
@@ -1091,6 +1091,9 @@ Interpreter._minimallyEncode = function (buf) {
1091
1091
  }
1092
1092
 
1093
1093
  // We are not minimally encoded, we need to figure out how much to trim.
1094
+ // Work on a copy: the argument can be a stack element that is also the
1095
+ // script's push data or a shared constant.
1096
+ buf = Buffer.from(buf)
1094
1097
  for (var i = buf.length - 1; i > 0; i--) {
1095
1098
  // We found a non zero byte, time to encode.
1096
1099
  if (buf[i - 1] !== 0) {
@@ -2067,29 +2070,33 @@ Interpreter.prototype.step = function () {
2067
2070
  return false
2068
2071
  }
2069
2072
 
2070
- // To avoid allocating, we modify vch1 in place.
2073
+ // Into a new buffer, never in place: an operand can be the script's
2074
+ // own push data, an OP_SPLIT view of it, or the shared Interpreter.true
2075
+ // (and both operands can be that same buffer). Writing into it
2076
+ // rewrote the script and corrupted TRUE for every later evaluation.
2077
+ spliced = Buffer.alloc(buf1.length)
2071
2078
  switch (opcodenum) {
2072
2079
  case Opcode.OP_AND:
2073
2080
  for (let i = 0; i < buf1.length; i++) {
2074
- buf1[i] &= buf2[i]
2081
+ spliced[i] = buf1[i] & buf2[i]
2075
2082
  }
2076
2083
  break
2077
2084
  case Opcode.OP_OR:
2078
2085
  for (let i = 0; i < buf1.length; i++) {
2079
- buf1[i] |= buf2[i]
2086
+ spliced[i] = buf1[i] | buf2[i]
2080
2087
  }
2081
2088
  break
2082
2089
  case Opcode.OP_XOR:
2083
2090
  for (let i = 0; i < buf1.length; i++) {
2084
- buf1[i] ^= buf2[i]
2091
+ spliced[i] = buf1[i] ^ buf2[i]
2085
2092
  }
2086
2093
  break
2087
2094
  default:
2088
2095
  break
2089
2096
  }
2090
2097
 
2091
- // And pop vch2.
2092
2098
  this.stack.pop()
2099
+ this.stack[this.stack.length - 1] = spliced
2093
2100
  break
2094
2101
 
2095
2102
  case Opcode.OP_INVERT:
@@ -2101,10 +2108,13 @@ Interpreter.prototype.step = function () {
2101
2108
  // stack error it had already decided on.
2102
2109
  return false
2103
2110
  }
2111
+ // A new buffer, for the same reason as OP_AND above.
2104
2112
  buf = stacktop(-1)
2113
+ buf1 = Buffer.alloc(buf.length)
2105
2114
  for (let i = 0; i < buf.length; i++) {
2106
- buf[i] = ~buf[i]
2115
+ buf1[i] = ~buf[i] & 0xff
2107
2116
  }
2117
+ this.stack[this.stack.length - 1] = buf1
2108
2118
  break
2109
2119
 
2110
2120
  case Opcode.OP_LSHIFT:
@@ -2770,6 +2780,9 @@ Interpreter.prototype.step = function () {
2770
2780
 
2771
2781
  var signbit = 0x00
2772
2782
  if (rawnum.length > 0) {
2783
+ // A copy before clearing the sign bit: rawnum can still be the
2784
+ // operand itself when it was already minimally encoded.
2785
+ rawnum = Buffer.from(rawnum)
2773
2786
  signbit = rawnum[rawnum.length - 1] & 0x80
2774
2787
  rawnum[rawnum.length - 1] &= 0x7f
2775
2788
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smartledger/bsv",
3
- "version": "9.9.0",
3
+ "version": "9.10.1",
4
4
  "description": "Bitcoin SV library with an interpreter-verified script engine: OP_PUSH_TX covenants, BIP-143 preimage tooling, and consensus flags that match what miners actually enforce. Also ships DID:web / W3C VC-JWT credentials and the Legal Token Protocol.",
5
5
  "author": "SmartLedger Technology <hello@smartledger.technology> (https://smartledger.technology)",
6
6
  "homepage": "https://github.com/codenlighten/smartledger-bsv#readme",
package/version.js CHANGED
@@ -1,3 +1,3 @@
1
1
  'use strict'
2
2
  // GENERATED by scripts/sync-version.js on `npm version` โ€” do not edit.
3
- module.exports = '9.9.0'
3
+ module.exports = '9.10.1'