@bsv/sdk 1.6.18 → 1.6.20
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/README.md +11 -11
- package/dist/cjs/package.json +5 -9
- package/dist/cjs/src/auth/transports/SimplifiedFetchTransport.js +39 -39
- package/dist/cjs/src/auth/transports/SimplifiedFetchTransport.js.map +1 -1
- package/dist/cjs/src/primitives/ECDSA.js +69 -167
- package/dist/cjs/src/primitives/ECDSA.js.map +1 -1
- package/dist/cjs/src/primitives/Hash.js +660 -436
- package/dist/cjs/src/primitives/Hash.js.map +1 -1
- package/dist/cjs/src/primitives/Point.js +285 -293
- package/dist/cjs/src/primitives/Point.js.map +1 -1
- package/dist/cjs/src/script/ScriptEvaluationError.js +27 -0
- package/dist/cjs/src/script/ScriptEvaluationError.js.map +1 -0
- package/dist/cjs/src/script/Spend.js +13 -7
- package/dist/cjs/src/script/Spend.js.map +1 -1
- package/dist/cjs/src/script/index.js +3 -1
- package/dist/cjs/src/script/index.js.map +1 -1
- package/dist/cjs/src/transaction/Beef.js +4 -4
- package/dist/cjs/src/transaction/Transaction.js +3 -3
- package/dist/cjs/src/transaction/Transaction.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/auth/transports/SimplifiedFetchTransport.js +39 -39
- package/dist/esm/src/auth/transports/SimplifiedFetchTransport.js.map +1 -1
- package/dist/esm/src/primitives/ECDSA.js +69 -167
- package/dist/esm/src/primitives/ECDSA.js.map +1 -1
- package/dist/esm/src/primitives/Hash.js +672 -444
- package/dist/esm/src/primitives/Hash.js.map +1 -1
- package/dist/esm/src/primitives/Point.js +268 -293
- package/dist/esm/src/primitives/Point.js.map +1 -1
- package/dist/esm/src/script/ScriptEvaluationError.js +33 -0
- package/dist/esm/src/script/ScriptEvaluationError.js.map +1 -0
- package/dist/esm/src/script/Spend.js +14 -8
- package/dist/esm/src/script/Spend.js.map +1 -1
- package/dist/esm/src/script/index.js +1 -0
- package/dist/esm/src/script/index.js.map +1 -1
- package/dist/esm/src/transaction/Beef.js +4 -4
- package/dist/esm/src/transaction/Transaction.js +3 -3
- package/dist/esm/src/transaction/Transaction.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/src/auth/transports/SimplifiedFetchTransport.d.ts +1 -1
- package/dist/types/src/auth/transports/SimplifiedFetchTransport.d.ts.map +1 -1
- package/dist/types/src/primitives/ECDSA.d.ts.map +1 -1
- package/dist/types/src/primitives/Hash.d.ts +12 -19
- package/dist/types/src/primitives/Hash.d.ts.map +1 -1
- package/dist/types/src/primitives/Point.d.ts +37 -5
- package/dist/types/src/primitives/Point.d.ts.map +1 -1
- package/dist/types/src/script/ScriptEvaluationError.d.ts +24 -0
- package/dist/types/src/script/ScriptEvaluationError.d.ts.map +1 -0
- package/dist/types/src/script/Spend.d.ts.map +1 -1
- package/dist/types/src/script/index.d.ts +1 -0
- package/dist/types/src/script/index.d.ts.map +1 -1
- package/dist/types/src/transaction/Transaction.d.ts.map +1 -1
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/dist/umd/bundle.js +20 -1
- package/dist/umd/bundle.js.map +1 -0
- package/package.json +5 -9
- package/src/auth/transports/SimplifiedFetchTransport.ts +64 -67
- package/src/primitives/ECDSA.ts +80 -222
- package/src/primitives/Hash.ts +752 -589
- package/src/primitives/Point.ts +277 -336
- package/src/script/ScriptEvaluationError.ts +44 -0
- package/src/script/Spend.ts +14 -12
- package/src/script/index.ts +1 -0
- package/src/transaction/Beef.ts +4 -4
- package/src/transaction/Transaction.ts +11 -3
package/src/primitives/Point.ts
CHANGED
|
@@ -2,7 +2,206 @@ import BasePoint from './BasePoint.js'
|
|
|
2
2
|
import JPoint from './JacobianPoint.js'
|
|
3
3
|
import BigNumber from './BigNumber.js'
|
|
4
4
|
import { toArray, toHex } from './utils.js'
|
|
5
|
-
|
|
5
|
+
|
|
6
|
+
// -----------------------------------------------------------------------------
|
|
7
|
+
// BigInt helpers & constants (secp256k1) – hoisted so we don't recreate them on
|
|
8
|
+
// every Point.mul() call.
|
|
9
|
+
// -----------------------------------------------------------------------------
|
|
10
|
+
export const BI_ZERO = 0n
|
|
11
|
+
export const BI_ONE = 1n
|
|
12
|
+
export const BI_TWO = 2n
|
|
13
|
+
export const BI_THREE = 3n
|
|
14
|
+
export const BI_FOUR = 4n
|
|
15
|
+
export const BI_EIGHT = 8n
|
|
16
|
+
|
|
17
|
+
export const P_BIGINT = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2Fn
|
|
18
|
+
export const N_BIGINT = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141n
|
|
19
|
+
export const MASK_256 = (1n << 256n) - 1n // 0xffff…ffff (256 sones)
|
|
20
|
+
|
|
21
|
+
export function red (x: bigint): bigint {
|
|
22
|
+
// first fold
|
|
23
|
+
let hi = x >> 256n
|
|
24
|
+
x = (x & MASK_256) + (hi << 32n) + hi * 977n
|
|
25
|
+
|
|
26
|
+
// second fold (hi ≤ 2³² + 977 here, so one more pass is enough)
|
|
27
|
+
hi = x >> 256n
|
|
28
|
+
x = (x & MASK_256) + (hi << 32n) + hi * 977n
|
|
29
|
+
|
|
30
|
+
// final conditional subtraction
|
|
31
|
+
if (x >= P_BIGINT) x -= P_BIGINT
|
|
32
|
+
return x
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const biMod = (a: bigint): bigint => red((a % P_BIGINT + P_BIGINT) % P_BIGINT)
|
|
36
|
+
export const biModSub = (a: bigint, b: bigint): bigint => (a >= b ? a - b : P_BIGINT - (b - a))
|
|
37
|
+
export const biModMul = (a: bigint, b: bigint): bigint => red(a * b)
|
|
38
|
+
export const biModAdd = (a: bigint, b: bigint): bigint => red(a + b)
|
|
39
|
+
export const biModInv = (a: bigint): bigint => { // binary‑ext GCD
|
|
40
|
+
let lm = BI_ONE; let hm = BI_ZERO; let low = biMod(a); let high = P_BIGINT
|
|
41
|
+
while (low > BI_ONE) { const r = high / low; [lm, hm] = [hm - lm * r, lm]; [low, high] = [high - low * r, low] }
|
|
42
|
+
return biMod(lm)
|
|
43
|
+
}
|
|
44
|
+
export const biModSqr = (a: bigint): bigint => biModMul(a, a)
|
|
45
|
+
|
|
46
|
+
export const biModPow = (base: bigint, exp: bigint): bigint => {
|
|
47
|
+
let result = BI_ONE
|
|
48
|
+
base = biMod(base)
|
|
49
|
+
let e = exp
|
|
50
|
+
while (e > BI_ZERO) {
|
|
51
|
+
if ((e & BI_ONE) === BI_ONE) result = biModMul(result, base)
|
|
52
|
+
base = biModMul(base, base)
|
|
53
|
+
e >>= BI_ONE
|
|
54
|
+
}
|
|
55
|
+
return result
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export const P_PLUS1_DIV4 = (P_BIGINT + 1n) >> 2n
|
|
59
|
+
|
|
60
|
+
export const biModSqrt = (a: bigint): bigint | null => {
|
|
61
|
+
const r = biModPow(a, P_PLUS1_DIV4)
|
|
62
|
+
return biModMul(r, r) === biMod(a) ? r : null
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const toBigInt = (x: BigNumber | number | number[] | string): bigint => {
|
|
66
|
+
if (BigNumber.isBN(x)) return BigInt('0x' + (x as BigNumber).toString(16))
|
|
67
|
+
if (typeof x === 'string') return BigInt('0x' + x)
|
|
68
|
+
if (Array.isArray(x)) return BigInt('0x' + toHex(x))
|
|
69
|
+
return BigInt(x as number)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Generator point coordinates as bigint constants
|
|
73
|
+
export const GX_BIGINT = BigInt('0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798')
|
|
74
|
+
export const GY_BIGINT = BigInt('0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8')
|
|
75
|
+
|
|
76
|
+
// Cache for precomputed windowed tables keyed by 'window:x:y'
|
|
77
|
+
const WNAF_TABLE_CACHE: Map<string, JacobianPointBI[]> = new Map()
|
|
78
|
+
|
|
79
|
+
export interface JacobianPointBI { X: bigint, Y: bigint, Z: bigint }
|
|
80
|
+
|
|
81
|
+
export const jpDouble = (P: JacobianPointBI): JacobianPointBI => {
|
|
82
|
+
const { X: X1, Y: Y1, Z: Z1 } = P
|
|
83
|
+
if (Y1 === BI_ZERO) return { X: BI_ZERO, Y: BI_ONE, Z: BI_ZERO }
|
|
84
|
+
|
|
85
|
+
const Y1sq = biModMul(Y1, Y1)
|
|
86
|
+
const S = biModMul(BI_FOUR, biModMul(X1, Y1sq))
|
|
87
|
+
const M = biModMul(BI_THREE, biModMul(X1, X1))
|
|
88
|
+
const X3 = biModSub(biModMul(M, M), biModMul(BI_TWO, S))
|
|
89
|
+
const Y3 = biModSub(
|
|
90
|
+
biModMul(M, biModSub(S, X3)),
|
|
91
|
+
biModMul(BI_EIGHT, biModMul(Y1sq, Y1sq))
|
|
92
|
+
)
|
|
93
|
+
const Z3 = biModMul(BI_TWO, biModMul(Y1, Z1))
|
|
94
|
+
return { X: X3, Y: Y3, Z: Z3 }
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export const jpAdd = (P: JacobianPointBI, Q: JacobianPointBI): JacobianPointBI => {
|
|
98
|
+
if (P.Z === BI_ZERO) return Q
|
|
99
|
+
if (Q.Z === BI_ZERO) return P
|
|
100
|
+
|
|
101
|
+
const Z1Z1 = biModMul(P.Z, P.Z)
|
|
102
|
+
const Z2Z2 = biModMul(Q.Z, Q.Z)
|
|
103
|
+
const U1 = biModMul(P.X, Z2Z2)
|
|
104
|
+
const U2 = biModMul(Q.X, Z1Z1)
|
|
105
|
+
const S1 = biModMul(P.Y, biModMul(Z2Z2, Q.Z))
|
|
106
|
+
const S2 = biModMul(Q.Y, biModMul(Z1Z1, P.Z))
|
|
107
|
+
|
|
108
|
+
const H = biModSub(U2, U1)
|
|
109
|
+
const r = biModSub(S2, S1)
|
|
110
|
+
if (H === BI_ZERO) {
|
|
111
|
+
if (r === BI_ZERO) return jpDouble(P)
|
|
112
|
+
return { X: BI_ZERO, Y: BI_ONE, Z: BI_ZERO } // Infinity
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const HH = biModMul(H, H)
|
|
116
|
+
const HHH = biModMul(H, HH)
|
|
117
|
+
const V = biModMul(U1, HH)
|
|
118
|
+
|
|
119
|
+
const X3 = biModSub(biModSub(biModMul(r, r), HHH), biModMul(BI_TWO, V))
|
|
120
|
+
const Y3 = biModSub(biModMul(r, biModSub(V, X3)), biModMul(S1, HHH))
|
|
121
|
+
const Z3 = biModMul(H, biModMul(P.Z, Q.Z))
|
|
122
|
+
return { X: X3, Y: Y3, Z: Z3 }
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export const jpNeg = (P: JacobianPointBI): JacobianPointBI => {
|
|
126
|
+
if (P.Z === BI_ZERO) return P
|
|
127
|
+
return { X: P.X, Y: P_BIGINT - P.Y, Z: P.Z }
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Fast windowed-NAF scalar multiplication (default window = 5) in Jacobian
|
|
131
|
+
// coordinates. Returns Q = k * P0 as a JacobianPoint.
|
|
132
|
+
export const scalarMultiplyWNAF = (
|
|
133
|
+
k: bigint,
|
|
134
|
+
P0: { x: bigint, y: bigint },
|
|
135
|
+
window: number = 5
|
|
136
|
+
): JacobianPointBI => {
|
|
137
|
+
const key = `${window}:${P0.x.toString(16)}:${P0.y.toString(16)}`
|
|
138
|
+
let tbl = WNAF_TABLE_CACHE.get(key)
|
|
139
|
+
let P: JacobianPointBI
|
|
140
|
+
if (tbl === undefined) {
|
|
141
|
+
// Convert affine to Jacobian and pre-compute odd multiples
|
|
142
|
+
const tblSize = 1 << (window - 1) // e.g. w=5 → 16 entries
|
|
143
|
+
tbl = new Array(tblSize)
|
|
144
|
+
P = { X: P0.x, Y: P0.y, Z: BI_ONE }
|
|
145
|
+
tbl[0] = P
|
|
146
|
+
const twoP = jpDouble(P)
|
|
147
|
+
for (let i = 1; i < tblSize; i++) {
|
|
148
|
+
tbl[i] = jpAdd(tbl[i - 1], twoP)
|
|
149
|
+
}
|
|
150
|
+
WNAF_TABLE_CACHE.set(key, tbl)
|
|
151
|
+
} else {
|
|
152
|
+
P = tbl[0]
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Build wNAF representation of k
|
|
156
|
+
const wnaf: number[] = []
|
|
157
|
+
const wBig = 1n << BigInt(window)
|
|
158
|
+
const wHalf = wBig >> 1n
|
|
159
|
+
let kTmp = k
|
|
160
|
+
while (kTmp > 0n) {
|
|
161
|
+
if ((kTmp & BI_ONE) === BI_ZERO) {
|
|
162
|
+
wnaf.push(0)
|
|
163
|
+
kTmp >>= BI_ONE
|
|
164
|
+
} else {
|
|
165
|
+
let z = kTmp & (wBig - 1n) // kTmp mod 2^w
|
|
166
|
+
if (z > wHalf) z -= wBig // make it odd & within (-2^{w-1}, 2^{w-1})
|
|
167
|
+
wnaf.push(Number(z))
|
|
168
|
+
kTmp -= z
|
|
169
|
+
kTmp >>= BI_ONE
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Accumulate from MSB to LSB
|
|
174
|
+
let Q: JacobianPointBI = { X: BI_ZERO, Y: BI_ONE, Z: BI_ZERO } // infinity
|
|
175
|
+
for (let i = wnaf.length - 1; i >= 0; i--) {
|
|
176
|
+
Q = jpDouble(Q)
|
|
177
|
+
const di = wnaf[i]
|
|
178
|
+
if (di !== 0) {
|
|
179
|
+
const idx = Math.abs(di) >> 1 // (|di|-1)/2 because di is odd
|
|
180
|
+
const addend = di > 0 ? tbl[idx] : jpNeg(tbl[idx])
|
|
181
|
+
Q = jpAdd(Q, addend)
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return Q
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export const modN = (a: bigint): bigint => {
|
|
188
|
+
let r = a % N_BIGINT
|
|
189
|
+
if (r < 0n) r += N_BIGINT
|
|
190
|
+
return r
|
|
191
|
+
}
|
|
192
|
+
export const modMulN = (a: bigint, b: bigint): bigint => modN(a * b)
|
|
193
|
+
|
|
194
|
+
/** modular inverse modulo n with plain extended‑gcd (not constant‑time) */
|
|
195
|
+
export const modInvN = (a: bigint): bigint => {
|
|
196
|
+
let lm = 1n; let hm = 0n
|
|
197
|
+
let low = modN(a); let high = N_BIGINT
|
|
198
|
+
while (low > 1n) {
|
|
199
|
+
const q = high / low
|
|
200
|
+
;[lm, hm] = [hm - lm * q, lm]
|
|
201
|
+
;[low, high] = [high - low * q, low]
|
|
202
|
+
}
|
|
203
|
+
return modN(lm)
|
|
204
|
+
}
|
|
6
205
|
|
|
7
206
|
/**
|
|
8
207
|
* `Point` class is a representation of an elliptic curve point with affine coordinates.
|
|
@@ -17,10 +216,6 @@ import ReductionContext from './ReductionContext.js'
|
|
|
17
216
|
* @property inf - Flag to record if the point is at infinity in the Elliptic Curve.
|
|
18
217
|
*/
|
|
19
218
|
export default class Point extends BasePoint {
|
|
20
|
-
private static readonly red: any = new ReductionContext('k256')
|
|
21
|
-
private static readonly a: BigNumber = new BigNumber(0).toRed(Point.red)
|
|
22
|
-
private static readonly b: BigNumber = new BigNumber(7).toRed(Point.red)
|
|
23
|
-
private static readonly zero: BigNumber = new BigNumber(0).toRed(Point.red)
|
|
24
219
|
x: BigNumber | null
|
|
25
220
|
y: BigNumber | null
|
|
26
221
|
inf: boolean
|
|
@@ -95,13 +290,6 @@ export default class Point extends BasePoint {
|
|
|
95
290
|
return Point.fromDER(bytes)
|
|
96
291
|
}
|
|
97
292
|
|
|
98
|
-
static redSqrtOptimized (y2: BigNumber): BigNumber {
|
|
99
|
-
const red = Point.red
|
|
100
|
-
const p = red.m // The modulus
|
|
101
|
-
const exponent = p.addn(1).iushrn(2) // (p + 1) / 4
|
|
102
|
-
return y2.redPow(exponent)
|
|
103
|
-
}
|
|
104
|
-
|
|
105
293
|
/**
|
|
106
294
|
* Generates a point from an x coordinate and a boolean indicating whether the corresponding
|
|
107
295
|
* y coordinate is odd.
|
|
@@ -118,66 +306,17 @@ export default class Point extends BasePoint {
|
|
|
118
306
|
* const point = Point.fromX(xCoordinate, true);
|
|
119
307
|
*/
|
|
120
308
|
static fromX (x: BigNumber | number | number[] | string, odd: boolean): Point {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
result = mod(result * base, modulus)
|
|
130
|
-
}
|
|
131
|
-
exponent >>= BigInt(1)
|
|
132
|
-
base = mod(base * base, modulus)
|
|
133
|
-
}
|
|
134
|
-
return result
|
|
135
|
-
}
|
|
136
|
-
function sqrtMod (a: bigint, p: bigint): bigint | null {
|
|
137
|
-
const exponent = (p + BigInt(1)) >> BigInt(2)
|
|
138
|
-
const sqrtCandidate = modPow(a, exponent, p)
|
|
139
|
-
if (mod(sqrtCandidate * sqrtCandidate, p) === mod(a, p)) {
|
|
140
|
-
return sqrtCandidate
|
|
141
|
-
} else {
|
|
142
|
-
return null
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Curve parameters for secp256k1
|
|
147
|
-
const p = BigInt(
|
|
148
|
-
'0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F'
|
|
149
|
-
)
|
|
150
|
-
const b = BigInt(7)
|
|
151
|
-
|
|
152
|
-
let xBigInt: bigint
|
|
153
|
-
if (x instanceof BigNumber) {
|
|
154
|
-
xBigInt = BigInt('0x' + x.toString(16))
|
|
155
|
-
} else if (typeof x === 'string') {
|
|
156
|
-
xBigInt = BigInt('0x' + x)
|
|
157
|
-
} else if (Array.isArray(x)) {
|
|
158
|
-
xBigInt = BigInt('0x' + toHex(x).padStart(64, '0'))
|
|
159
|
-
} else if (typeof x === 'number') {
|
|
160
|
-
xBigInt = BigInt(x)
|
|
161
|
-
} else {
|
|
162
|
-
throw new Error('Invalid x-coordinate type')
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
xBigInt = mod(xBigInt, p)
|
|
166
|
-
|
|
167
|
-
const y2 = mod(modPow(xBigInt, BigInt(3), p) + b, p)
|
|
168
|
-
|
|
169
|
-
let y = sqrtMod(y2, p)
|
|
170
|
-
if (y === null) {
|
|
171
|
-
throw new Error('Invalid point')
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const isYOdd = y % BigInt(2) === BigInt(1)
|
|
175
|
-
if ((odd && !isYOdd) || (!odd && isYOdd)) {
|
|
176
|
-
y = p - y
|
|
309
|
+
let xBigInt = toBigInt(x)
|
|
310
|
+
xBigInt = biMod(xBigInt)
|
|
311
|
+
const y2 = biModAdd(biModMul(biModSqr(xBigInt), xBigInt), 7n)
|
|
312
|
+
const y = biModSqrt(y2)
|
|
313
|
+
if (y === null) throw new Error('Invalid point')
|
|
314
|
+
let yBig = y
|
|
315
|
+
if ((yBig & BI_ONE) !== (odd ? BI_ONE : BI_ZERO)) {
|
|
316
|
+
yBig = biModSub(P_BIGINT, yBig)
|
|
177
317
|
}
|
|
178
|
-
|
|
179
318
|
const xBN = new BigNumber(xBigInt.toString(16), 16)
|
|
180
|
-
const yBN = new BigNumber(
|
|
319
|
+
const yBN = new BigNumber(yBig.toString(16), 16)
|
|
181
320
|
return new Point(xBN, yBN)
|
|
182
321
|
}
|
|
183
322
|
|
|
@@ -448,25 +587,31 @@ export default class Point extends BasePoint {
|
|
|
448
587
|
|
|
449
588
|
// P + (-P) = O
|
|
450
589
|
if (this.neg().eq(p)) {
|
|
451
|
-
return new Point(
|
|
590
|
+
return new Point(null, null)
|
|
452
591
|
}
|
|
453
592
|
|
|
454
593
|
// P + Q = O
|
|
455
594
|
if (this.x?.cmp(p.x ?? new BigNumber(0)) === 0) {
|
|
456
|
-
return new Point(
|
|
595
|
+
return new Point(null, null)
|
|
457
596
|
}
|
|
458
597
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
598
|
+
const P1 = {
|
|
599
|
+
X: BigInt('0x' + (this.x as BigNumber).fromRed().toString(16)),
|
|
600
|
+
Y: BigInt('0x' + (this.y as BigNumber).fromRed().toString(16)),
|
|
601
|
+
Z: BI_ONE
|
|
462
602
|
}
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
603
|
+
const Q1 = {
|
|
604
|
+
X: BigInt('0x' + (p.x as BigNumber).fromRed().toString(16)),
|
|
605
|
+
Y: BigInt('0x' + (p.y as BigNumber).fromRed().toString(16)),
|
|
606
|
+
Z: BI_ONE
|
|
607
|
+
}
|
|
608
|
+
const R = jpAdd(P1, Q1)
|
|
609
|
+
if (R.Z === BI_ZERO) return new Point(null, null)
|
|
610
|
+
const zInv = biModInv(R.Z)
|
|
611
|
+
const zInv2 = biModMul(zInv, zInv)
|
|
612
|
+
const xRes = biModMul(R.X, zInv2)
|
|
613
|
+
const yRes = biModMul(R.Y, biModMul(zInv2, zInv))
|
|
614
|
+
return new Point(xRes.toString(16), yRes.toString(16))
|
|
470
615
|
}
|
|
471
616
|
|
|
472
617
|
/**
|
|
@@ -479,25 +624,21 @@ export default class Point extends BasePoint {
|
|
|
479
624
|
* const result = P.dbl();
|
|
480
625
|
* */
|
|
481
626
|
dbl (): Point {
|
|
482
|
-
if (this.inf)
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
// 2P = O
|
|
487
|
-
const ys1 = (this.y ?? new BigNumber(0)).redAdd(this.y ?? new BigNumber(0))
|
|
488
|
-
if (ys1.cmpn(0) === 0) {
|
|
489
|
-
return new Point(new BigNumber(0), new BigNumber(0))
|
|
627
|
+
if (this.inf) return this
|
|
628
|
+
if (this.x === null || this.y === null) {
|
|
629
|
+
throw new Error('Point coordinates cannot be null')
|
|
490
630
|
}
|
|
491
631
|
|
|
492
|
-
const
|
|
493
|
-
const
|
|
494
|
-
|
|
495
|
-
const c = x2.redAdd(x2).redIAdd(x2).redIAdd(a).redMul(dyinv)
|
|
632
|
+
const X = BigInt('0x' + this.x.fromRed().toString(16))
|
|
633
|
+
const Y = BigInt('0x' + this.y.fromRed().toString(16))
|
|
634
|
+
if (Y === BI_ZERO) return new Point(null, null)
|
|
496
635
|
|
|
497
|
-
const
|
|
498
|
-
const
|
|
499
|
-
|
|
500
|
-
|
|
636
|
+
const R = jpDouble({ X, Y, Z: BI_ONE })
|
|
637
|
+
const zInv = biModInv(R.Z)
|
|
638
|
+
const zInv2 = biModMul(zInv, zInv)
|
|
639
|
+
const xRes = biModMul(R.X, zInv2)
|
|
640
|
+
const yRes = biModMul(R.Y, biModMul(zInv2, zInv))
|
|
641
|
+
return new Point(xRes.toString(16), yRes.toString(16))
|
|
501
642
|
}
|
|
502
643
|
|
|
503
644
|
/**
|
|
@@ -538,102 +679,48 @@ export default class Point extends BasePoint {
|
|
|
538
679
|
k = new BigNumber(k as number, 16)
|
|
539
680
|
}
|
|
540
681
|
k = k as BigNumber
|
|
541
|
-
if (
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
const zero = 0n
|
|
547
|
-
const one = 1n
|
|
548
|
-
const p = BigInt(
|
|
549
|
-
'0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F'
|
|
550
|
-
)
|
|
551
|
-
const n = BigInt(
|
|
552
|
-
'0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141'
|
|
553
|
-
)
|
|
554
|
-
|
|
555
|
-
let kBig = BigInt('0x' + k.toString(16))
|
|
556
|
-
const isNeg = kBig < zero
|
|
557
|
-
if (isNeg) kBig = -kBig
|
|
558
|
-
kBig = ((kBig % n) + n) % n
|
|
559
|
-
if (kBig === zero) {
|
|
560
|
-
return new Point(null, null)
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
if (this.x === null || this.y === null) {
|
|
564
|
-
throw new Error('Point coordinates cannot be null')
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
let Px: bigint
|
|
568
|
-
let Py: bigint
|
|
569
|
-
if (this === this.curve.g) {
|
|
570
|
-
Px = GX_BIGINT
|
|
571
|
-
Py = GY_BIGINT
|
|
572
|
-
} else {
|
|
573
|
-
Px = BigInt('0x' + this.x.fromRed().toString(16))
|
|
574
|
-
Py = BigInt('0x' + this.y.fromRed().toString(16))
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
const mod = (a: bigint, m: bigint): bigint => ((a % m) + m) % m
|
|
578
|
-
const modMul = (a: bigint, b: bigint, m: bigint): bigint => mod(a * b, m)
|
|
579
|
-
const modInv = (a: bigint, m: bigint): bigint => {
|
|
580
|
-
let lm = one
|
|
581
|
-
let hm = zero
|
|
582
|
-
let low = mod(a, m)
|
|
583
|
-
let high = m
|
|
584
|
-
while (low > one) {
|
|
585
|
-
const r = high / low
|
|
586
|
-
const nm = hm - lm * r
|
|
587
|
-
const neww = high - low * r
|
|
588
|
-
hm = lm
|
|
589
|
-
lm = nm
|
|
590
|
-
high = low
|
|
591
|
-
low = neww
|
|
592
|
-
}
|
|
593
|
-
return mod(lm, m)
|
|
594
|
-
}
|
|
682
|
+
if (this.inf) {
|
|
683
|
+
return this
|
|
684
|
+
}
|
|
595
685
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
686
|
+
let kBig = BigInt('0x' + k.toString(16))
|
|
687
|
+
const isNeg = kBig < BI_ZERO
|
|
688
|
+
if (isNeg) kBig = -kBig
|
|
689
|
+
kBig = biMod(kBig)
|
|
690
|
+
if (kBig === BI_ZERO) {
|
|
691
|
+
return new Point(null, null)
|
|
692
|
+
}
|
|
601
693
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
): JacobianPoint => {
|
|
606
|
-
// Delegate to the hoisted windowed-NAF implementation above. We
|
|
607
|
-
// keep the wrapper so that the rest of the mul() code remains
|
|
608
|
-
// untouched while providing a massive speed-up (≈4-6×).
|
|
609
|
-
return scalarMultiplyWNAF(kVal, P0) as unknown as JacobianPoint
|
|
610
|
-
}
|
|
694
|
+
if (this.x === null || this.y === null) {
|
|
695
|
+
throw new Error('Point coordinates cannot be null')
|
|
696
|
+
}
|
|
611
697
|
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
const zInv2 = modMul(zInv, zInv, p)
|
|
618
|
-
const xRes = modMul(R.X, zInv2, p)
|
|
619
|
-
const yRes = modMul(R.Y, modMul(zInv2, zInv, p), p)
|
|
620
|
-
|
|
621
|
-
const xBN = new BigNumber(xRes.toString(16), 16)
|
|
622
|
-
const yBN = new BigNumber(yRes.toString(16), 16)
|
|
623
|
-
const result = new Point(xBN, yBN)
|
|
624
|
-
if (isNeg) {
|
|
625
|
-
return result.neg()
|
|
626
|
-
}
|
|
627
|
-
return result
|
|
698
|
+
let Px: bigint
|
|
699
|
+
let Py: bigint
|
|
700
|
+
if (this === this.curve.g) {
|
|
701
|
+
Px = GX_BIGINT
|
|
702
|
+
Py = GY_BIGINT
|
|
628
703
|
} else {
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
704
|
+
Px = BigInt('0x' + this.x.fromRed().toString(16))
|
|
705
|
+
Py = BigInt('0x' + this.y.fromRed().toString(16))
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
const R = scalarMultiplyWNAF(kBig, { x: Px, y: Py })
|
|
709
|
+
if (R.Z === BI_ZERO) {
|
|
710
|
+
return new Point(null, null)
|
|
711
|
+
}
|
|
712
|
+
const zInv = biModInv(R.Z)
|
|
713
|
+
const zInv2 = biModMul(zInv, zInv)
|
|
714
|
+
const xRes = biModMul(R.X, zInv2)
|
|
715
|
+
const yRes = biModMul(R.Y, biModMul(zInv2, zInv))
|
|
716
|
+
|
|
717
|
+
const xBN = new BigNumber(xRes.toString(16), 16)
|
|
718
|
+
const yBN = new BigNumber(yRes.toString(16), 16)
|
|
719
|
+
const result = new Point(xBN, yBN)
|
|
720
|
+
if (isNeg) {
|
|
721
|
+
return result.neg()
|
|
636
722
|
}
|
|
723
|
+
return result
|
|
637
724
|
}
|
|
638
725
|
|
|
639
726
|
/**
|
|
@@ -1013,7 +1100,7 @@ export default class Point extends BasePoint {
|
|
|
1013
1100
|
for (i = 0; i < points.length; i++) {
|
|
1014
1101
|
const split = this.curve._endoSplit(coeffs[i])
|
|
1015
1102
|
let p = points[i]
|
|
1016
|
-
let beta: Point = p._getBeta() ?? new Point(
|
|
1103
|
+
let beta: Point = p._getBeta() ?? new Point(null, null)
|
|
1017
1104
|
|
|
1018
1105
|
if (split.k1.negative !== 0) {
|
|
1019
1106
|
split.k1.ineg()
|
|
@@ -1107,149 +1194,3 @@ export default class Point extends BasePoint {
|
|
|
1107
1194
|
}
|
|
1108
1195
|
}
|
|
1109
1196
|
}
|
|
1110
|
-
|
|
1111
|
-
// -----------------------------------------------------------------------------
|
|
1112
|
-
// BigInt helpers & constants (secp256k1) – hoisted so we don't recreate them on
|
|
1113
|
-
// every Point.mul() call.
|
|
1114
|
-
// -----------------------------------------------------------------------------
|
|
1115
|
-
const BI_ZERO = 0n
|
|
1116
|
-
const BI_ONE = 1n
|
|
1117
|
-
const BI_TWO = 2n
|
|
1118
|
-
const BI_THREE = 3n
|
|
1119
|
-
const BI_FOUR = 4n
|
|
1120
|
-
const BI_EIGHT = 8n
|
|
1121
|
-
|
|
1122
|
-
const P_BIGINT = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2Fn
|
|
1123
|
-
const MASK_256 = (1n << 256n) - 1n // 0xffff…ffff (256 sones)
|
|
1124
|
-
|
|
1125
|
-
function red (x: bigint): bigint {
|
|
1126
|
-
// first fold
|
|
1127
|
-
let hi = x >> 256n
|
|
1128
|
-
x = (x & MASK_256) + (hi << 32n) + hi * 977n
|
|
1129
|
-
|
|
1130
|
-
// second fold (hi ≤ 2³² + 977 here, so one more pass is enough)
|
|
1131
|
-
hi = x >> 256n
|
|
1132
|
-
x = (x & MASK_256) + (hi << 32n) + hi * 977n
|
|
1133
|
-
|
|
1134
|
-
// final conditional subtraction
|
|
1135
|
-
if (x >= P_BIGINT) x -= P_BIGINT
|
|
1136
|
-
return x
|
|
1137
|
-
}
|
|
1138
|
-
|
|
1139
|
-
const biModSub = (a: bigint, b: bigint): bigint => (a >= b ? a - b : P_BIGINT - (b - a))
|
|
1140
|
-
const biModMul = (a: bigint, b: bigint): bigint => red(a * b)
|
|
1141
|
-
|
|
1142
|
-
// Generator point coordinates as bigint constants
|
|
1143
|
-
const GX_BIGINT = BigInt('0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798')
|
|
1144
|
-
const GY_BIGINT = BigInt('0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8')
|
|
1145
|
-
|
|
1146
|
-
// Cache for precomputed windowed tables keyed by 'window:x:y'
|
|
1147
|
-
const WNAF_TABLE_CACHE: Map<string, JacobianPointBI[]> = new Map()
|
|
1148
|
-
|
|
1149
|
-
interface JacobianPointBI { X: bigint, Y: bigint, Z: bigint }
|
|
1150
|
-
|
|
1151
|
-
const jpDouble = (P: JacobianPointBI): JacobianPointBI => {
|
|
1152
|
-
const { X: X1, Y: Y1, Z: Z1 } = P
|
|
1153
|
-
if (Y1 === BI_ZERO) return { X: BI_ZERO, Y: BI_ONE, Z: BI_ZERO }
|
|
1154
|
-
|
|
1155
|
-
const Y1sq = biModMul(Y1, Y1)
|
|
1156
|
-
const S = biModMul(BI_FOUR, biModMul(X1, Y1sq))
|
|
1157
|
-
const M = biModMul(BI_THREE, biModMul(X1, X1))
|
|
1158
|
-
const X3 = biModSub(biModMul(M, M), biModMul(BI_TWO, S))
|
|
1159
|
-
const Y3 = biModSub(
|
|
1160
|
-
biModMul(M, biModSub(S, X3)),
|
|
1161
|
-
biModMul(BI_EIGHT, biModMul(Y1sq, Y1sq))
|
|
1162
|
-
)
|
|
1163
|
-
const Z3 = biModMul(BI_TWO, biModMul(Y1, Z1))
|
|
1164
|
-
return { X: X3, Y: Y3, Z: Z3 }
|
|
1165
|
-
}
|
|
1166
|
-
|
|
1167
|
-
const jpAdd = (P: JacobianPointBI, Q: JacobianPointBI): JacobianPointBI => {
|
|
1168
|
-
if (P.Z === BI_ZERO) return Q
|
|
1169
|
-
if (Q.Z === BI_ZERO) return P
|
|
1170
|
-
|
|
1171
|
-
const Z1Z1 = biModMul(P.Z, P.Z)
|
|
1172
|
-
const Z2Z2 = biModMul(Q.Z, Q.Z)
|
|
1173
|
-
const U1 = biModMul(P.X, Z2Z2)
|
|
1174
|
-
const U2 = biModMul(Q.X, Z1Z1)
|
|
1175
|
-
const S1 = biModMul(P.Y, biModMul(Z2Z2, Q.Z))
|
|
1176
|
-
const S2 = biModMul(Q.Y, biModMul(Z1Z1, P.Z))
|
|
1177
|
-
|
|
1178
|
-
const H = biModSub(U2, U1)
|
|
1179
|
-
const r = biModSub(S2, S1)
|
|
1180
|
-
if (H === BI_ZERO) {
|
|
1181
|
-
if (r === BI_ZERO) return jpDouble(P)
|
|
1182
|
-
return { X: BI_ZERO, Y: BI_ONE, Z: BI_ZERO } // Infinity
|
|
1183
|
-
}
|
|
1184
|
-
|
|
1185
|
-
const HH = biModMul(H, H)
|
|
1186
|
-
const HHH = biModMul(H, HH)
|
|
1187
|
-
const V = biModMul(U1, HH)
|
|
1188
|
-
|
|
1189
|
-
const X3 = biModSub(biModSub(biModMul(r, r), HHH), biModMul(BI_TWO, V))
|
|
1190
|
-
const Y3 = biModSub(biModMul(r, biModSub(V, X3)), biModMul(S1, HHH))
|
|
1191
|
-
const Z3 = biModMul(H, biModMul(P.Z, Q.Z))
|
|
1192
|
-
return { X: X3, Y: Y3, Z: Z3 }
|
|
1193
|
-
}
|
|
1194
|
-
|
|
1195
|
-
const jpNeg = (P: JacobianPointBI): JacobianPointBI => {
|
|
1196
|
-
if (P.Z === BI_ZERO) return P
|
|
1197
|
-
return { X: P.X, Y: P_BIGINT - P.Y, Z: P.Z }
|
|
1198
|
-
}
|
|
1199
|
-
|
|
1200
|
-
// Fast windowed-NAF scalar multiplication (default window = 5) in Jacobian
|
|
1201
|
-
// coordinates. Returns Q = k * P0 as a JacobianPoint.
|
|
1202
|
-
const scalarMultiplyWNAF = (
|
|
1203
|
-
k: bigint,
|
|
1204
|
-
P0: { x: bigint, y: bigint },
|
|
1205
|
-
window: number = 5
|
|
1206
|
-
): JacobianPointBI => {
|
|
1207
|
-
const key = `${window}:${P0.x.toString(16)}:${P0.y.toString(16)}`
|
|
1208
|
-
let tbl = WNAF_TABLE_CACHE.get(key)
|
|
1209
|
-
let P: JacobianPointBI
|
|
1210
|
-
if (tbl === undefined) {
|
|
1211
|
-
// Convert affine to Jacobian and pre-compute odd multiples
|
|
1212
|
-
const tblSize = 1 << (window - 1) // e.g. w=5 → 16 entries
|
|
1213
|
-
tbl = new Array(tblSize)
|
|
1214
|
-
P = { X: P0.x, Y: P0.y, Z: BI_ONE }
|
|
1215
|
-
tbl[0] = P
|
|
1216
|
-
const twoP = jpDouble(P)
|
|
1217
|
-
for (let i = 1; i < tblSize; i++) {
|
|
1218
|
-
tbl[i] = jpAdd(tbl[i - 1], twoP)
|
|
1219
|
-
}
|
|
1220
|
-
WNAF_TABLE_CACHE.set(key, tbl)
|
|
1221
|
-
} else {
|
|
1222
|
-
P = tbl[0]
|
|
1223
|
-
}
|
|
1224
|
-
|
|
1225
|
-
// Build wNAF representation of k
|
|
1226
|
-
const wnaf: number[] = []
|
|
1227
|
-
const wBig = 1n << BigInt(window)
|
|
1228
|
-
const wHalf = wBig >> 1n
|
|
1229
|
-
let kTmp = k
|
|
1230
|
-
while (kTmp > 0n) {
|
|
1231
|
-
if ((kTmp & BI_ONE) === BI_ZERO) {
|
|
1232
|
-
wnaf.push(0)
|
|
1233
|
-
kTmp >>= BI_ONE
|
|
1234
|
-
} else {
|
|
1235
|
-
let z = kTmp & (wBig - 1n) // kTmp mod 2^w
|
|
1236
|
-
if (z > wHalf) z -= wBig // make it odd & within (-2^{w-1}, 2^{w-1})
|
|
1237
|
-
wnaf.push(Number(z))
|
|
1238
|
-
kTmp -= z
|
|
1239
|
-
kTmp >>= BI_ONE
|
|
1240
|
-
}
|
|
1241
|
-
}
|
|
1242
|
-
|
|
1243
|
-
// Accumulate from MSB to LSB
|
|
1244
|
-
let Q: JacobianPointBI = { X: BI_ZERO, Y: BI_ONE, Z: BI_ZERO } // infinity
|
|
1245
|
-
for (let i = wnaf.length - 1; i >= 0; i--) {
|
|
1246
|
-
Q = jpDouble(Q)
|
|
1247
|
-
const di = wnaf[i]
|
|
1248
|
-
if (di !== 0) {
|
|
1249
|
-
const idx = Math.abs(di) >> 1 // (|di|-1)/2 because di is odd
|
|
1250
|
-
const addend = di > 0 ? tbl[idx] : jpNeg(tbl[idx])
|
|
1251
|
-
Q = jpAdd(Q, addend)
|
|
1252
|
-
}
|
|
1253
|
-
}
|
|
1254
|
-
return Q
|
|
1255
|
-
}
|