@bsv/sdk 1.6.18 → 1.6.19
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 +4 -8
- 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 +26 -125
- 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 +226 -213
- package/dist/cjs/src/primitives/Point.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 +26 -125
- 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 +211 -213
- package/dist/esm/src/primitives/Point.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 +34 -0
- package/dist/types/src/primitives/Point.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 +4 -8
- package/src/auth/transports/SimplifiedFetchTransport.ts +64 -67
- package/src/primitives/ECDSA.ts +30 -173
- package/src/primitives/Hash.ts +752 -589
- package/src/primitives/Point.ts +222 -247
- package/src/transaction/Beef.ts +4 -4
- package/src/transaction/Transaction.ts +11 -3
package/src/primitives/Point.ts
CHANGED
|
@@ -4,6 +4,180 @@ import BigNumber from './BigNumber.js'
|
|
|
4
4
|
import { toArray, toHex } from './utils.js'
|
|
5
5
|
import ReductionContext from './ReductionContext.js'
|
|
6
6
|
|
|
7
|
+
// -----------------------------------------------------------------------------
|
|
8
|
+
// BigInt helpers & constants (secp256k1) – hoisted so we don't recreate them on
|
|
9
|
+
// every Point.mul() call.
|
|
10
|
+
// -----------------------------------------------------------------------------
|
|
11
|
+
export const BI_ZERO = 0n
|
|
12
|
+
export const BI_ONE = 1n
|
|
13
|
+
export const BI_TWO = 2n
|
|
14
|
+
export const BI_THREE = 3n
|
|
15
|
+
export const BI_FOUR = 4n
|
|
16
|
+
export const BI_EIGHT = 8n
|
|
17
|
+
|
|
18
|
+
export const P_BIGINT = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2Fn
|
|
19
|
+
export const N_BIGINT = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141n
|
|
20
|
+
export const MASK_256 = (1n << 256n) - 1n // 0xffff…ffff (256 sones)
|
|
21
|
+
|
|
22
|
+
export function red (x: bigint): bigint {
|
|
23
|
+
// first fold
|
|
24
|
+
let hi = x >> 256n
|
|
25
|
+
x = (x & MASK_256) + (hi << 32n) + hi * 977n
|
|
26
|
+
|
|
27
|
+
// second fold (hi ≤ 2³² + 977 here, so one more pass is enough)
|
|
28
|
+
hi = x >> 256n
|
|
29
|
+
x = (x & MASK_256) + (hi << 32n) + hi * 977n
|
|
30
|
+
|
|
31
|
+
// final conditional subtraction
|
|
32
|
+
if (x >= P_BIGINT) x -= P_BIGINT
|
|
33
|
+
return x
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const biMod = (a: bigint): bigint => red((a % P_BIGINT + P_BIGINT) % P_BIGINT)
|
|
37
|
+
export const biModSub = (a: bigint, b: bigint): bigint => (a >= b ? a - b : P_BIGINT - (b - a))
|
|
38
|
+
export const biModMul = (a: bigint, b: bigint): bigint => red(a * b)
|
|
39
|
+
export const biModAdd = (a: bigint, b: bigint): bigint => red(a + b)
|
|
40
|
+
export const biModInv = (a: bigint): bigint => { // binary‑ext GCD
|
|
41
|
+
let lm = BI_ONE; let hm = BI_ZERO; let low = biMod(a); let high = P_BIGINT
|
|
42
|
+
while (low > BI_ONE) { const r = high / low; [lm, hm] = [hm - lm * r, lm]; [low, high] = [high - low * r, low] }
|
|
43
|
+
return biMod(lm)
|
|
44
|
+
}
|
|
45
|
+
export const biModSqr = (a: bigint): bigint => biModMul(a, a)
|
|
46
|
+
|
|
47
|
+
// Generator point coordinates as bigint constants
|
|
48
|
+
export const GX_BIGINT = BigInt('0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798')
|
|
49
|
+
export const GY_BIGINT = BigInt('0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8')
|
|
50
|
+
|
|
51
|
+
// Cache for precomputed windowed tables keyed by 'window:x:y'
|
|
52
|
+
const WNAF_TABLE_CACHE: Map<string, JacobianPointBI[]> = new Map()
|
|
53
|
+
|
|
54
|
+
export interface JacobianPointBI { X: bigint, Y: bigint, Z: bigint }
|
|
55
|
+
|
|
56
|
+
export const jpDouble = (P: JacobianPointBI): JacobianPointBI => {
|
|
57
|
+
const { X: X1, Y: Y1, Z: Z1 } = P
|
|
58
|
+
if (Y1 === BI_ZERO) return { X: BI_ZERO, Y: BI_ONE, Z: BI_ZERO }
|
|
59
|
+
|
|
60
|
+
const Y1sq = biModMul(Y1, Y1)
|
|
61
|
+
const S = biModMul(BI_FOUR, biModMul(X1, Y1sq))
|
|
62
|
+
const M = biModMul(BI_THREE, biModMul(X1, X1))
|
|
63
|
+
const X3 = biModSub(biModMul(M, M), biModMul(BI_TWO, S))
|
|
64
|
+
const Y3 = biModSub(
|
|
65
|
+
biModMul(M, biModSub(S, X3)),
|
|
66
|
+
biModMul(BI_EIGHT, biModMul(Y1sq, Y1sq))
|
|
67
|
+
)
|
|
68
|
+
const Z3 = biModMul(BI_TWO, biModMul(Y1, Z1))
|
|
69
|
+
return { X: X3, Y: Y3, Z: Z3 }
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export const jpAdd = (P: JacobianPointBI, Q: JacobianPointBI): JacobianPointBI => {
|
|
73
|
+
if (P.Z === BI_ZERO) return Q
|
|
74
|
+
if (Q.Z === BI_ZERO) return P
|
|
75
|
+
|
|
76
|
+
const Z1Z1 = biModMul(P.Z, P.Z)
|
|
77
|
+
const Z2Z2 = biModMul(Q.Z, Q.Z)
|
|
78
|
+
const U1 = biModMul(P.X, Z2Z2)
|
|
79
|
+
const U2 = biModMul(Q.X, Z1Z1)
|
|
80
|
+
const S1 = biModMul(P.Y, biModMul(Z2Z2, Q.Z))
|
|
81
|
+
const S2 = biModMul(Q.Y, biModMul(Z1Z1, P.Z))
|
|
82
|
+
|
|
83
|
+
const H = biModSub(U2, U1)
|
|
84
|
+
const r = biModSub(S2, S1)
|
|
85
|
+
if (H === BI_ZERO) {
|
|
86
|
+
if (r === BI_ZERO) return jpDouble(P)
|
|
87
|
+
return { X: BI_ZERO, Y: BI_ONE, Z: BI_ZERO } // Infinity
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const HH = biModMul(H, H)
|
|
91
|
+
const HHH = biModMul(H, HH)
|
|
92
|
+
const V = biModMul(U1, HH)
|
|
93
|
+
|
|
94
|
+
const X3 = biModSub(biModSub(biModMul(r, r), HHH), biModMul(BI_TWO, V))
|
|
95
|
+
const Y3 = biModSub(biModMul(r, biModSub(V, X3)), biModMul(S1, HHH))
|
|
96
|
+
const Z3 = biModMul(H, biModMul(P.Z, Q.Z))
|
|
97
|
+
return { X: X3, Y: Y3, Z: Z3 }
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export const jpNeg = (P: JacobianPointBI): JacobianPointBI => {
|
|
101
|
+
if (P.Z === BI_ZERO) return P
|
|
102
|
+
return { X: P.X, Y: P_BIGINT - P.Y, Z: P.Z }
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Fast windowed-NAF scalar multiplication (default window = 5) in Jacobian
|
|
106
|
+
// coordinates. Returns Q = k * P0 as a JacobianPoint.
|
|
107
|
+
export const scalarMultiplyWNAF = (
|
|
108
|
+
k: bigint,
|
|
109
|
+
P0: { x: bigint, y: bigint },
|
|
110
|
+
window: number = 5
|
|
111
|
+
): JacobianPointBI => {
|
|
112
|
+
const key = `${window}:${P0.x.toString(16)}:${P0.y.toString(16)}`
|
|
113
|
+
let tbl = WNAF_TABLE_CACHE.get(key)
|
|
114
|
+
let P: JacobianPointBI
|
|
115
|
+
if (tbl === undefined) {
|
|
116
|
+
// Convert affine to Jacobian and pre-compute odd multiples
|
|
117
|
+
const tblSize = 1 << (window - 1) // e.g. w=5 → 16 entries
|
|
118
|
+
tbl = new Array(tblSize)
|
|
119
|
+
P = { X: P0.x, Y: P0.y, Z: BI_ONE }
|
|
120
|
+
tbl[0] = P
|
|
121
|
+
const twoP = jpDouble(P)
|
|
122
|
+
for (let i = 1; i < tblSize; i++) {
|
|
123
|
+
tbl[i] = jpAdd(tbl[i - 1], twoP)
|
|
124
|
+
}
|
|
125
|
+
WNAF_TABLE_CACHE.set(key, tbl)
|
|
126
|
+
} else {
|
|
127
|
+
P = tbl[0]
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Build wNAF representation of k
|
|
131
|
+
const wnaf: number[] = []
|
|
132
|
+
const wBig = 1n << BigInt(window)
|
|
133
|
+
const wHalf = wBig >> 1n
|
|
134
|
+
let kTmp = k
|
|
135
|
+
while (kTmp > 0n) {
|
|
136
|
+
if ((kTmp & BI_ONE) === BI_ZERO) {
|
|
137
|
+
wnaf.push(0)
|
|
138
|
+
kTmp >>= BI_ONE
|
|
139
|
+
} else {
|
|
140
|
+
let z = kTmp & (wBig - 1n) // kTmp mod 2^w
|
|
141
|
+
if (z > wHalf) z -= wBig // make it odd & within (-2^{w-1}, 2^{w-1})
|
|
142
|
+
wnaf.push(Number(z))
|
|
143
|
+
kTmp -= z
|
|
144
|
+
kTmp >>= BI_ONE
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Accumulate from MSB to LSB
|
|
149
|
+
let Q: JacobianPointBI = { X: BI_ZERO, Y: BI_ONE, Z: BI_ZERO } // infinity
|
|
150
|
+
for (let i = wnaf.length - 1; i >= 0; i--) {
|
|
151
|
+
Q = jpDouble(Q)
|
|
152
|
+
const di = wnaf[i]
|
|
153
|
+
if (di !== 0) {
|
|
154
|
+
const idx = Math.abs(di) >> 1 // (|di|-1)/2 because di is odd
|
|
155
|
+
const addend = di > 0 ? tbl[idx] : jpNeg(tbl[idx])
|
|
156
|
+
Q = jpAdd(Q, addend)
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return Q
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export const modN = (a: bigint): bigint => {
|
|
163
|
+
let r = a % N_BIGINT
|
|
164
|
+
if (r < 0n) r += N_BIGINT
|
|
165
|
+
return r
|
|
166
|
+
}
|
|
167
|
+
export const modMulN = (a: bigint, b: bigint): bigint => modN(a * b)
|
|
168
|
+
|
|
169
|
+
/** modular inverse modulo n with plain extended‑gcd (not constant‑time) */
|
|
170
|
+
export const modInvN = (a: bigint): bigint => {
|
|
171
|
+
let lm = 1n; let hm = 0n
|
|
172
|
+
let low = modN(a); let high = N_BIGINT
|
|
173
|
+
while (low > 1n) {
|
|
174
|
+
const q = high / low
|
|
175
|
+
;[lm, hm] = [hm - lm * q, lm]
|
|
176
|
+
;[low, high] = [high - low * q, low]
|
|
177
|
+
}
|
|
178
|
+
return modN(lm)
|
|
179
|
+
}
|
|
180
|
+
|
|
7
181
|
/**
|
|
8
182
|
* `Point` class is a representation of an elliptic curve point with affine coordinates.
|
|
9
183
|
* It extends the functionality of BasePoint and carries x, y coordinates of point on the curve.
|
|
@@ -456,17 +630,18 @@ export default class Point extends BasePoint {
|
|
|
456
630
|
return new Point(new BigNumber(0), new BigNumber(0))
|
|
457
631
|
}
|
|
458
632
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
633
|
+
const q = {
|
|
634
|
+
x: BigInt('0x' + (p.x as BigNumber).fromRed().toString(16)),
|
|
635
|
+
y: BigInt('0x' + (p.y as BigNumber).fromRed().toString(16))
|
|
462
636
|
}
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
637
|
+
const t = {
|
|
638
|
+
x: BigInt('0x' + (this.x as BigNumber).fromRed().toString(16)),
|
|
639
|
+
y: BigInt('0x' + (this.y as BigNumber).fromRed().toString(16))
|
|
640
|
+
}
|
|
641
|
+
const λ = biModMul(biModSub(q.y, t.y), biModInv(biModSub(q.x, t.x)))
|
|
642
|
+
const rx = biModSub(biModSub(biModSqr(λ), t.x), q.x)
|
|
643
|
+
const ry = biModSub(biModMul(λ, biModSub(t.x, rx)), t.y)
|
|
644
|
+
return new Point(rx.toString(16), ry.toString(16))
|
|
470
645
|
}
|
|
471
646
|
|
|
472
647
|
/**
|
|
@@ -538,102 +713,48 @@ export default class Point extends BasePoint {
|
|
|
538
713
|
k = new BigNumber(k as number, 16)
|
|
539
714
|
}
|
|
540
715
|
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
|
-
}
|
|
716
|
+
if (this.inf) {
|
|
717
|
+
return this
|
|
718
|
+
}
|
|
595
719
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
720
|
+
let kBig = BigInt('0x' + k.toString(16))
|
|
721
|
+
const isNeg = kBig < BI_ZERO
|
|
722
|
+
if (isNeg) kBig = -kBig
|
|
723
|
+
kBig = biMod(kBig)
|
|
724
|
+
if (kBig === BI_ZERO) {
|
|
725
|
+
return new Point(null, null)
|
|
726
|
+
}
|
|
601
727
|
|
|
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
|
-
}
|
|
728
|
+
if (this.x === null || this.y === null) {
|
|
729
|
+
throw new Error('Point coordinates cannot be null')
|
|
730
|
+
}
|
|
611
731
|
|
|
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
|
|
732
|
+
let Px: bigint
|
|
733
|
+
let Py: bigint
|
|
734
|
+
if (this === this.curve.g) {
|
|
735
|
+
Px = GX_BIGINT
|
|
736
|
+
Py = GY_BIGINT
|
|
628
737
|
} else {
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
} else if (this._hasDoubles(k)) {
|
|
632
|
-
return this._fixedNafMul(k)
|
|
633
|
-
} else {
|
|
634
|
-
return this._endoWnafMulAdd([this], [k]) as Point
|
|
635
|
-
}
|
|
738
|
+
Px = BigInt('0x' + this.x.fromRed().toString(16))
|
|
739
|
+
Py = BigInt('0x' + this.y.fromRed().toString(16))
|
|
636
740
|
}
|
|
741
|
+
|
|
742
|
+
const R = scalarMultiplyWNAF(kBig, { x: Px, y: Py })
|
|
743
|
+
if (R.Z === BI_ZERO) {
|
|
744
|
+
return new Point(null, null)
|
|
745
|
+
}
|
|
746
|
+
const zInv = biModInv(R.Z)
|
|
747
|
+
const zInv2 = biModMul(zInv, zInv)
|
|
748
|
+
const xRes = biModMul(R.X, zInv2)
|
|
749
|
+
const yRes = biModMul(R.Y, biModMul(zInv2, zInv))
|
|
750
|
+
|
|
751
|
+
const xBN = new BigNumber(xRes.toString(16), 16)
|
|
752
|
+
const yBN = new BigNumber(yRes.toString(16), 16)
|
|
753
|
+
const result = new Point(xBN, yBN)
|
|
754
|
+
if (isNeg) {
|
|
755
|
+
return result.neg()
|
|
756
|
+
}
|
|
757
|
+
return result
|
|
637
758
|
}
|
|
638
759
|
|
|
639
760
|
/**
|
|
@@ -1107,149 +1228,3 @@ export default class Point extends BasePoint {
|
|
|
1107
1228
|
}
|
|
1108
1229
|
}
|
|
1109
1230
|
}
|
|
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
|
-
}
|
package/src/transaction/Beef.ts
CHANGED
|
@@ -21,18 +21,18 @@ export enum TX_DATA_FORMAT {
|
|
|
21
21
|
|
|
22
22
|
/*
|
|
23
23
|
* BEEF standard: BRC-62: Background Evaluation Extended Format (BEEF) Transactions
|
|
24
|
-
* https://github.com/
|
|
24
|
+
* https://github.com/bsv-blockchain/BRCs/blob/master/transactions/0062.md
|
|
25
25
|
*
|
|
26
26
|
* BUMP standard: BRC-74: BSV Unified Merkle Path (BUMP) Format
|
|
27
|
-
* https://github.com/
|
|
27
|
+
* https://github.com/bsv-blockchain/BRCs/blob/master/transactions/0074.md
|
|
28
28
|
*
|
|
29
29
|
* BRC-95: Atomic BEEF Transactions
|
|
30
|
-
* https://github.com/
|
|
30
|
+
* https://github.com/bsv-blockchain/BRCs/blob/master/transactions/0095.md
|
|
31
31
|
*
|
|
32
32
|
* The Atomic BEEF format is supported by the binary deserialization static method `fromBinary`.
|
|
33
33
|
*
|
|
34
34
|
* BRC-96: BEEF V2, Txid Only Extension
|
|
35
|
-
* https://github.com/
|
|
35
|
+
* https://github.com/bsv-blockchain/BRCs/blob/master/transactions/0096.md
|
|
36
36
|
*
|
|
37
37
|
* A valid serialized BEEF is the cornerstone of Simplified Payment Validation (SPV)
|
|
38
38
|
* where they are exchanged between two non-trusting parties to establish the
|
|
@@ -119,7 +119,11 @@ export default class Transaction {
|
|
|
119
119
|
static fromAtomicBEEF (beef: number[]): Transaction {
|
|
120
120
|
const { tx, txid, beef: b } = Transaction.fromAnyBeef(beef)
|
|
121
121
|
if (txid !== b.atomicTxid) {
|
|
122
|
-
if (b.atomicTxid
|
|
122
|
+
if (b.atomicTxid != null) {
|
|
123
|
+
throw new Error(`Transaction with TXID ${b.atomicTxid} not found in BEEF data.`)
|
|
124
|
+
} else {
|
|
125
|
+
throw new Error('beef must conform to BRC-95 and must contain the subject txid.')
|
|
126
|
+
}
|
|
123
127
|
}
|
|
124
128
|
return tx
|
|
125
129
|
}
|
|
@@ -129,10 +133,14 @@ export default class Transaction {
|
|
|
129
133
|
if (b.txs.length < 1) {
|
|
130
134
|
throw new Error('beef must include at least one transaction.')
|
|
131
135
|
}
|
|
132
|
-
const target = txid
|
|
136
|
+
const target = txid ?? b.atomicTxid ?? b.txs.slice(-1)[0].txid
|
|
133
137
|
const tx = b.findAtomicTransaction(target)
|
|
134
138
|
if (tx == null) {
|
|
135
|
-
if (txid
|
|
139
|
+
if (txid != null) {
|
|
140
|
+
throw new Error(`Transaction with TXID ${target} not found in BEEF data.`)
|
|
141
|
+
} else {
|
|
142
|
+
throw new Error('beef does not contain transaction for atomic txid.')
|
|
143
|
+
}
|
|
136
144
|
}
|
|
137
145
|
return { tx, beef: b, txid: target }
|
|
138
146
|
}
|