@smartledger/bsv 5.2.0 → 5.3.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 +49 -0
- package/README.md +42 -42
- package/bsv-covenant.min.js +13 -13
- package/bsv-gdaf.min.js +2 -2
- package/bsv-ltp.min.js +2 -2
- package/bsv-smartcontract.min.js +13 -13
- package/bsv.bundle.js +2 -2
- 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/index.js +0 -2
- package/lib/crypto/elliptic-fixed.js +86 -50
- package/lib/crypto/point.js +164 -103
- package/package.json +1 -2
package/lib/crypto/point.js
CHANGED
|
@@ -1,50 +1,108 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
var BN = require('./bn')
|
|
4
|
+
var { secp256k1 } = require('@noble/curves/secp256k1.js')
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
// secp256k1 point + curve order from the audited @noble/curves implementation.
|
|
7
|
+
// This module preserves the (elliptic-derived) Point API the rest of the
|
|
8
|
+
// codebase depends on — mul/add/mulAdd/getX/getY/.x/.y/eq/isInfinity/validate,
|
|
9
|
+
// the static getG/getN/fromX/fromBuffer helpers — so ECDSA and key handling are
|
|
10
|
+
// unchanged. Only the underlying EC math moved from `elliptic` to `@noble`.
|
|
11
|
+
var NoblePoint = secp256k1.Point
|
|
12
|
+
var N_BIG = NoblePoint.Fn.ORDER
|
|
13
|
+
|
|
14
|
+
function bnToBig (bn) {
|
|
15
|
+
// Coordinates and scalars in this codebase are always non-negative.
|
|
16
|
+
return BigInt('0x' + (bn.toString(16) || '0'))
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function bigToBN (big) {
|
|
20
|
+
var h = big.toString(16)
|
|
21
|
+
if (h.length % 2) h = '0' + h
|
|
22
|
+
return new BN(h, 16)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function toBig (v) {
|
|
26
|
+
if (v == null) throw new Error('Invalid Point')
|
|
27
|
+
if (typeof v === 'bigint') return v
|
|
28
|
+
if (typeof v === 'number') return BigInt(v)
|
|
29
|
+
if (typeof v === 'string') return BigInt(v.indexOf('0x') === 0 ? v : '0x' + v)
|
|
30
|
+
if (typeof v.toString === 'function') return bnToBig(v) // BN
|
|
31
|
+
throw new Error('Invalid Point')
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Wrap a raw @noble point as a Point instance without re-validating (used by
|
|
35
|
+
// internal results of mul/add/getG/fromX which are already valid).
|
|
36
|
+
function wrap (noblePoint) {
|
|
37
|
+
var p = Object.create(Point.prototype)
|
|
38
|
+
p._p = noblePoint
|
|
39
|
+
return p
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Derive the on-curve @noble point at the given X with the requested Y parity.
|
|
43
|
+
// Throws if X is not a valid curve x-coordinate. Low-level (no Point.validate),
|
|
44
|
+
// so it is safe to call from validate() without recursion.
|
|
45
|
+
function nobleFromX (odd, x) {
|
|
46
|
+
// Build the compressed encoding via hex string padding (not BN.toBuffer) so we
|
|
47
|
+
// don't perturb BN.toBuffer call counts the rest of the codebase may rely on.
|
|
48
|
+
var xhex = toBig(x).toString(16).padStart(64, '0')
|
|
49
|
+
return NoblePoint.fromHex((odd ? '03' : '02') + xhex)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Check that (xb, yb) — raw bigint coordinates — lie on the curve, producing
|
|
53
|
+
// the same error messages the previous (elliptic) implementation did. Operates
|
|
54
|
+
// on raw coordinates so it works even for inputs @noble's fromAffine rejects
|
|
55
|
+
// outright (e.g. y = 0).
|
|
56
|
+
function checkOnCurve (xb, yb) {
|
|
57
|
+
var p2
|
|
58
|
+
try {
|
|
59
|
+
p2 = nobleFromX((yb & 1n) === 1n, xb)
|
|
60
|
+
} catch (e) {
|
|
61
|
+
throw new Error('Point does not lie on the curve')
|
|
62
|
+
}
|
|
63
|
+
if (p2.toAffine().y !== yb) {
|
|
64
|
+
throw new Error('Invalid y value for curve.')
|
|
65
|
+
}
|
|
66
|
+
}
|
|
9
67
|
|
|
10
68
|
/**
|
|
11
|
-
* Instantiate a valid secp256k1 Point from the X and Y coordinates.
|
|
12
|
-
* is just an extension of the secp256k1 code from the library "elliptic" by
|
|
13
|
-
* Fedor Indutny. It includes a few extra features that are useful in Bitcoin.
|
|
14
|
-
*
|
|
69
|
+
* Instantiate a valid secp256k1 Point from the X and Y coordinates.
|
|
15
70
|
* @param {BN|String} x - The X coordinate
|
|
16
71
|
* @param {BN|String} y - The Y coordinate
|
|
17
|
-
* @
|
|
18
|
-
* @augments elliptic.curve.point
|
|
19
|
-
* @throws {Error} A validation error if exists
|
|
20
|
-
* @returns {Point} An instance of Point
|
|
72
|
+
* @returns {Point}
|
|
21
73
|
* @constructor
|
|
22
74
|
*/
|
|
23
|
-
|
|
75
|
+
function Point (x, y, isRed) {
|
|
76
|
+
if (!(this instanceof Point)) {
|
|
77
|
+
return new Point(x, y, isRed)
|
|
78
|
+
}
|
|
79
|
+
var xb, yb
|
|
24
80
|
try {
|
|
25
|
-
|
|
81
|
+
xb = toBig(x)
|
|
82
|
+
yb = toBig(y)
|
|
26
83
|
} catch (e) {
|
|
27
84
|
throw new Error('Invalid Point')
|
|
28
85
|
}
|
|
29
|
-
|
|
30
|
-
|
|
86
|
+
// Validate on the raw coordinates first (gives the specific curve/y errors and
|
|
87
|
+
// works for coordinates @noble's fromAffine rejects, e.g. y = 0).
|
|
88
|
+
checkOnCurve(xb, yb)
|
|
89
|
+
try {
|
|
90
|
+
this._p = NoblePoint.fromAffine({ x: xb, y: yb })
|
|
91
|
+
} catch (e) {
|
|
92
|
+
throw new Error('Invalid Point')
|
|
93
|
+
}
|
|
94
|
+
return this
|
|
31
95
|
}
|
|
32
96
|
|
|
33
|
-
Point.prototype = Object.getPrototypeOf(ec.curve.point())
|
|
34
|
-
|
|
35
97
|
/**
|
|
36
|
-
*
|
|
37
|
-
* Instantiate a valid secp256k1 Point from only the X coordinate. This is
|
|
38
|
-
* useful to rederive a full point from the compressed form of a point.
|
|
39
|
-
*
|
|
98
|
+
* Instantiate a valid secp256k1 Point from only the X coordinate.
|
|
40
99
|
* @param {boolean} odd - If the Y coordinate is odd
|
|
41
100
|
* @param {BN|String} x - The X coordinate
|
|
42
|
-
* @
|
|
43
|
-
* @returns {Point} An instance of Point
|
|
101
|
+
* @returns {Point}
|
|
44
102
|
*/
|
|
45
103
|
Point.fromX = function fromX (odd, x) {
|
|
46
104
|
try {
|
|
47
|
-
var point =
|
|
105
|
+
var point = wrap(nobleFromX(odd, x))
|
|
48
106
|
} catch (e) {
|
|
49
107
|
throw new Error('Invalid X')
|
|
50
108
|
}
|
|
@@ -53,89 +111,111 @@ Point.fromX = function fromX (odd, x) {
|
|
|
53
111
|
}
|
|
54
112
|
|
|
55
113
|
/**
|
|
56
|
-
*
|
|
57
|
-
* Will return a secp256k1 ECDSA base point.
|
|
58
|
-
*
|
|
59
|
-
* @link https://en.bitcoin.it/wiki/Secp256k1
|
|
60
|
-
* @returns {Point} An instance of the base point.
|
|
114
|
+
* @returns {Point} the secp256k1 base (generator) point.
|
|
61
115
|
*/
|
|
62
116
|
Point.getG = function getG () {
|
|
63
|
-
return
|
|
117
|
+
return wrap(NoblePoint.BASE)
|
|
64
118
|
}
|
|
65
119
|
|
|
66
120
|
/**
|
|
67
|
-
*
|
|
68
|
-
* Will return the max of range of valid private keys as governed by the
|
|
69
|
-
* secp256k1 ECDSA standard.
|
|
70
|
-
*
|
|
71
|
-
* @link https://en.bitcoin.it/wiki/Private_key#Range_of_valid_ECDSA_private_keys
|
|
72
|
-
* @returns {BN} A BN instance of the number of points on the curve
|
|
121
|
+
* @returns {BN} the curve order n.
|
|
73
122
|
*/
|
|
74
123
|
Point.getN = function getN () {
|
|
75
|
-
return
|
|
124
|
+
return bigToBN(N_BIG)
|
|
76
125
|
}
|
|
77
126
|
|
|
78
|
-
if (!Point.prototype._getX) { Point.prototype._getX = Point.prototype.getX }
|
|
79
|
-
|
|
80
127
|
/**
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
* @returns {BN} A BN instance of the X coordinate
|
|
128
|
+
* @returns {BN} the X coordinate of the Point.
|
|
84
129
|
*/
|
|
85
130
|
Point.prototype.getX = function getX () {
|
|
86
|
-
return
|
|
131
|
+
return bigToBN(this._p.toAffine().x)
|
|
87
132
|
}
|
|
88
133
|
|
|
89
|
-
if (!Point.prototype._getY) { Point.prototype._getY = Point.prototype.getY }
|
|
90
|
-
|
|
91
134
|
/**
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
* @returns {BN} A BN instance of the Y coordinate
|
|
135
|
+
* @returns {BN} the Y coordinate of the Point.
|
|
95
136
|
*/
|
|
96
137
|
Point.prototype.getY = function getY () {
|
|
97
|
-
return
|
|
138
|
+
return bigToBN(this._p.toAffine().y)
|
|
98
139
|
}
|
|
99
140
|
|
|
141
|
+
// `.x` / `.y` are accessed directly in a few places (e.g. ECDSA r = Q.x.umod(N)).
|
|
142
|
+
Object.defineProperty(Point.prototype, 'x', {
|
|
143
|
+
configurable: true,
|
|
144
|
+
enumerable: true,
|
|
145
|
+
get: function () { return this.getX() }
|
|
146
|
+
})
|
|
147
|
+
Object.defineProperty(Point.prototype, 'y', {
|
|
148
|
+
configurable: true,
|
|
149
|
+
enumerable: true,
|
|
150
|
+
get: function () { return this.getY() }
|
|
151
|
+
})
|
|
152
|
+
|
|
100
153
|
/**
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
* @
|
|
104
|
-
*
|
|
105
|
-
*
|
|
154
|
+
* Scalar multiply this point. Every valid secp256k1 point has order n
|
|
155
|
+
* (cofactor 1), so k*P == (k mod n)*P; reducing mod n lets us always use
|
|
156
|
+
* @noble's *constant-time* `multiply` (important for the secret signing nonce)
|
|
157
|
+
* and naturally handles the boundary scalars used by validation / recovery
|
|
158
|
+
* (e.g. n itself reduces to 0 -> the point at infinity).
|
|
159
|
+
* @param {BN} k
|
|
160
|
+
* @returns {Point}
|
|
106
161
|
*/
|
|
107
|
-
Point.prototype.
|
|
108
|
-
|
|
109
|
-
|
|
162
|
+
Point.prototype.mul = function mul (k) {
|
|
163
|
+
var s = ((toBig(k) % N_BIG) + N_BIG) % N_BIG
|
|
164
|
+
if (s === 0n || this._p.is0()) {
|
|
165
|
+
return wrap(NoblePoint.ZERO)
|
|
110
166
|
}
|
|
167
|
+
return wrap(this._p.multiply(s))
|
|
168
|
+
}
|
|
111
169
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
170
|
+
/**
|
|
171
|
+
* @param {Point} p
|
|
172
|
+
* @returns {Point} this + p
|
|
173
|
+
*/
|
|
174
|
+
Point.prototype.add = function add (p) {
|
|
175
|
+
return wrap(this._p.add(p._p))
|
|
176
|
+
}
|
|
118
177
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
178
|
+
/**
|
|
179
|
+
* @returns {Point} k1*this + k2*p2 (used by ECDSA verification).
|
|
180
|
+
*/
|
|
181
|
+
Point.prototype.mulAdd = function mulAdd (k1, p2, k2) {
|
|
182
|
+
return this.mul(k1).add(p2.mul(k2))
|
|
183
|
+
}
|
|
122
184
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
185
|
+
/**
|
|
186
|
+
* @param {Point} p
|
|
187
|
+
* @returns {boolean}
|
|
188
|
+
*/
|
|
189
|
+
Point.prototype.eq = function eq (p) {
|
|
190
|
+
return this._p.equals(p._p)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* @returns {boolean}
|
|
195
|
+
*/
|
|
196
|
+
Point.prototype.isInfinity = function isInfinity () {
|
|
197
|
+
return this._p.is0()
|
|
198
|
+
}
|
|
127
199
|
|
|
200
|
+
/**
|
|
201
|
+
* Will determine if the point is valid.
|
|
202
|
+
* @returns {Point} this
|
|
203
|
+
*/
|
|
204
|
+
Point.prototype.validate = function validate () {
|
|
205
|
+
if (this.isInfinity()) {
|
|
206
|
+
throw new Error('Point cannot be equal to Infinity')
|
|
207
|
+
}
|
|
208
|
+
var a = this._p.toAffine()
|
|
209
|
+
checkOnCurve(a.x, a.y)
|
|
210
|
+
// secp256k1 has cofactor 1, so on-curve implies order n; the old explicit
|
|
211
|
+
// n*P == infinity check is therefore redundant.
|
|
128
212
|
return this
|
|
129
213
|
}
|
|
130
214
|
|
|
131
215
|
/**
|
|
132
|
-
* A "compressed" format point
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
* computation to rederive the full point.
|
|
136
|
-
*
|
|
137
|
-
* @param {Point} point An instance of Point.
|
|
138
|
-
* @returns {Buffer} A compressed point in the form of a buffer.
|
|
216
|
+
* A "compressed" format point: the X coordinate plus a parity byte.
|
|
217
|
+
* @param {Point} point
|
|
218
|
+
* @returns {Buffer}
|
|
139
219
|
*/
|
|
140
220
|
Point.pointToCompressed = function pointToCompressed (point) {
|
|
141
221
|
var xbuf = point.getX().toBuffer({ size: 32 })
|
|
@@ -152,17 +232,15 @@ Point.pointToCompressed = function pointToCompressed (point) {
|
|
|
152
232
|
}
|
|
153
233
|
|
|
154
234
|
/**
|
|
155
|
-
* Converts a compressed buffer into a point.
|
|
156
|
-
*
|
|
157
235
|
* @param {Buffer} buf A compressed point.
|
|
158
|
-
* @returns {Point}
|
|
236
|
+
* @returns {Point}
|
|
159
237
|
*/
|
|
160
238
|
Point.pointFromCompressed = function (buf) {
|
|
161
239
|
if (buf.length !== 33) {
|
|
162
240
|
throw new Error('invalid buffer length')
|
|
163
241
|
}
|
|
164
|
-
|
|
165
|
-
|
|
242
|
+
var prefix = buf[0]
|
|
243
|
+
var odd
|
|
166
244
|
if (prefix === 0x03) {
|
|
167
245
|
odd = true
|
|
168
246
|
} else if (prefix === 0x02) {
|
|
@@ -171,45 +249,28 @@ Point.pointFromCompressed = function (buf) {
|
|
|
171
249
|
throw new Error('invalid value of compressed prefix')
|
|
172
250
|
}
|
|
173
251
|
|
|
174
|
-
|
|
175
|
-
let x = BN.fromBuffer(xbuf)
|
|
252
|
+
var x = BN.fromBuffer(buf.slice(1, 33))
|
|
176
253
|
return Point.fromX(odd, x)
|
|
177
254
|
}
|
|
178
255
|
|
|
179
256
|
/**
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
* @returns {Buffer} A compressed point.
|
|
257
|
+
* @returns {Buffer} this point as a compressed buffer.
|
|
183
258
|
*/
|
|
184
259
|
Point.prototype.toBuffer = function () {
|
|
185
260
|
return Point.pointToCompressed(this)
|
|
186
261
|
}
|
|
187
262
|
|
|
188
263
|
/**
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
* @returns {string} A compressed point as a hex string.
|
|
264
|
+
* @returns {string} this point as a compressed hex string.
|
|
192
265
|
*/
|
|
193
266
|
Point.prototype.toHex = function () {
|
|
194
267
|
return this.toBuffer().toString('hex')
|
|
195
268
|
}
|
|
196
269
|
|
|
197
|
-
/**
|
|
198
|
-
* Converts a compressed buffer into a point.
|
|
199
|
-
*
|
|
200
|
-
* @param {Buffer} buf A compressed point.
|
|
201
|
-
* @returns {Point} A Point.
|
|
202
|
-
*/
|
|
203
270
|
Point.fromBuffer = function (buf) {
|
|
204
271
|
return Point.pointFromCompressed(buf)
|
|
205
272
|
}
|
|
206
273
|
|
|
207
|
-
/**
|
|
208
|
-
* Converts a compressed buffer into a point.
|
|
209
|
-
*
|
|
210
|
-
* @param {Buffer} hex A compressed point as a hex string.
|
|
211
|
-
* @returns {Point} A Point.
|
|
212
|
-
*/
|
|
213
274
|
Point.fromHex = function (hex) {
|
|
214
275
|
return Point.fromBuffer(Buffer.from(hex, 'hex'))
|
|
215
276
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smartledger/bsv",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.3.0",
|
|
4
4
|
"description": "🚀 Complete Bitcoin SV development framework with legally-recognizable DID:web + W3C VC-JWT toolkit, Legal Token Protocol (LTP), Global Digital Attestation Framework (GDAF), StatusList2021 revocation, and 16 flexible loading options. Standards-based credentials with ES256/ES256K support, on-chain BSV anchoring, and comprehensive Bitcoin SV API. Perfect for legal tokens, verifiable credentials, DeFi, smart contracts, and secure Bitcoin applications.",
|
|
5
5
|
"author": "SmartLedger Technology <hello@smartledger.technology> (https://smartledger.technology)",
|
|
6
6
|
"homepage": "https://github.com/codenlighten/smartledger-bsv#readme",
|
|
@@ -198,7 +198,6 @@
|
|
|
198
198
|
"bn.js": "=4.11.9",
|
|
199
199
|
"bs58": "=4.0.1",
|
|
200
200
|
"clone-deep": "^4.0.1",
|
|
201
|
-
"elliptic": "6.6.1",
|
|
202
201
|
"hash.js": "^1.1.7",
|
|
203
202
|
"inherits": "2.0.3",
|
|
204
203
|
"secrets.js-grempe": "^2.0.0",
|