@bsv/sdk 1.1.23 → 1.1.25

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.
Files changed (86) hide show
  1. package/dist/cjs/package.json +1 -1
  2. package/dist/cjs/src/primitives/Curve.js +7 -7
  3. package/dist/cjs/src/primitives/Curve.js.map +1 -1
  4. package/dist/cjs/src/primitives/ECDSA.js +394 -71
  5. package/dist/cjs/src/primitives/ECDSA.js.map +1 -1
  6. package/dist/cjs/src/primitives/Point.js +103 -23
  7. package/dist/cjs/src/primitives/Point.js.map +1 -1
  8. package/dist/cjs/src/primitives/TransactionSignature.js +4 -3
  9. package/dist/cjs/src/primitives/TransactionSignature.js.map +1 -1
  10. package/dist/cjs/src/primitives/utils.js +14 -15
  11. package/dist/cjs/src/primitives/utils.js.map +1 -1
  12. package/dist/cjs/src/script/Spend.js +4 -4
  13. package/dist/cjs/src/script/Spend.js.map +1 -1
  14. package/dist/cjs/src/totp/totp.js +1 -1
  15. package/dist/cjs/src/totp/totp.js.map +1 -1
  16. package/dist/cjs/src/transaction/Beef.js +492 -0
  17. package/dist/cjs/src/transaction/Beef.js.map +1 -0
  18. package/dist/cjs/src/transaction/BeefParty.js +97 -0
  19. package/dist/cjs/src/transaction/BeefParty.js.map +1 -0
  20. package/dist/cjs/src/transaction/BeefTx.js +123 -0
  21. package/dist/cjs/src/transaction/BeefTx.js.map +1 -0
  22. package/dist/cjs/src/transaction/Transaction.js +81 -66
  23. package/dist/cjs/src/transaction/Transaction.js.map +1 -1
  24. package/dist/cjs/src/transaction/index.js +7 -1
  25. package/dist/cjs/src/transaction/index.js.map +1 -1
  26. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  27. package/dist/esm/src/primitives/Curve.js +7 -7
  28. package/dist/esm/src/primitives/Curve.js.map +1 -1
  29. package/dist/esm/src/primitives/ECDSA.js +394 -71
  30. package/dist/esm/src/primitives/ECDSA.js.map +1 -1
  31. package/dist/esm/src/primitives/Point.js +103 -23
  32. package/dist/esm/src/primitives/Point.js.map +1 -1
  33. package/dist/esm/src/primitives/TransactionSignature.js +4 -3
  34. package/dist/esm/src/primitives/TransactionSignature.js.map +1 -1
  35. package/dist/esm/src/primitives/utils.js +14 -15
  36. package/dist/esm/src/primitives/utils.js.map +1 -1
  37. package/dist/esm/src/script/Spend.js +4 -4
  38. package/dist/esm/src/script/Spend.js.map +1 -1
  39. package/dist/esm/src/totp/totp.js +1 -1
  40. package/dist/esm/src/totp/totp.js.map +1 -1
  41. package/dist/esm/src/transaction/Beef.js +485 -0
  42. package/dist/esm/src/transaction/Beef.js.map +1 -0
  43. package/dist/esm/src/transaction/BeefParty.js +93 -0
  44. package/dist/esm/src/transaction/BeefParty.js.map +1 -0
  45. package/dist/esm/src/transaction/BeefTx.js +121 -0
  46. package/dist/esm/src/transaction/BeefTx.js.map +1 -0
  47. package/dist/esm/src/transaction/Transaction.js +81 -66
  48. package/dist/esm/src/transaction/Transaction.js.map +1 -1
  49. package/dist/esm/src/transaction/index.js +3 -0
  50. package/dist/esm/src/transaction/index.js.map +1 -1
  51. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  52. package/dist/types/src/primitives/ECDSA.d.ts.map +1 -1
  53. package/dist/types/src/primitives/Point.d.ts +5 -0
  54. package/dist/types/src/primitives/Point.d.ts.map +1 -1
  55. package/dist/types/src/primitives/TransactionSignature.d.ts.map +1 -1
  56. package/dist/types/src/primitives/utils.d.ts.map +1 -1
  57. package/dist/types/src/transaction/Beef.d.ts +143 -0
  58. package/dist/types/src/transaction/Beef.d.ts.map +1 -0
  59. package/dist/types/src/transaction/BeefParty.d.ts +62 -0
  60. package/dist/types/src/transaction/BeefParty.d.ts.map +1 -0
  61. package/dist/types/src/transaction/BeefTx.d.ts +35 -0
  62. package/dist/types/src/transaction/BeefTx.d.ts.map +1 -0
  63. package/dist/types/src/transaction/Transaction.d.ts.map +1 -1
  64. package/dist/types/src/transaction/TransactionInput.d.ts +1 -1
  65. package/dist/types/src/transaction/TransactionInput.d.ts.map +1 -1
  66. package/dist/types/src/transaction/index.d.ts +3 -0
  67. package/dist/types/src/transaction/index.d.ts.map +1 -1
  68. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  69. package/docs/primitives.md +373 -55
  70. package/docs/transaction.md +467 -1
  71. package/package.json +1 -1
  72. package/src/primitives/Curve.ts +7 -7
  73. package/src/primitives/ECDSA.ts +485 -75
  74. package/src/primitives/Point.ts +110 -25
  75. package/src/primitives/TransactionSignature.ts +4 -3
  76. package/src/primitives/utils.ts +15 -11
  77. package/src/script/Spend.ts +4 -4
  78. package/src/totp/totp.ts +1 -1
  79. package/src/transaction/Beef.ts +533 -0
  80. package/src/transaction/BeefParty.ts +100 -0
  81. package/src/transaction/BeefTx.ts +121 -0
  82. package/src/transaction/Transaction.ts +95 -69
  83. package/src/transaction/TransactionInput.ts +1 -1
  84. package/src/transaction/__tests/Beef.test.ts +290 -0
  85. package/src/transaction/__tests/Transaction.benchmarks.test.ts +222 -0
  86. package/src/transaction/index.ts +3 -0
@@ -17,6 +17,10 @@ import ReductionContext from './ReductionContext.js'
17
17
  * @property inf - Flag to record if the point is at infinity in the Elliptic Curve.
18
18
  */
19
19
  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)
20
24
  x: BigNumber | null
21
25
  y: BigNumber | null
22
26
  inf: boolean
@@ -59,7 +63,7 @@ export default class Point extends BasePoint {
59
63
 
60
64
  return res
61
65
  } else if ((bytes[0] === 0x02 || bytes[0] === 0x03) &&
62
- bytes.length - 1 === len) {
66
+ bytes.length - 1 === len) {
63
67
  return Point.fromX(bytes.slice(1, 1 + len), bytes[0] === 0x03)
64
68
  }
65
69
  throw new Error('Unknown point format')
@@ -87,6 +91,13 @@ export default class Point extends BasePoint {
87
91
  return Point.fromDER(bytes)
88
92
  }
89
93
 
94
+ static redSqrtOptimized (y2: BigNumber): BigNumber {
95
+ const red = Point.red
96
+ const p = red.m // The modulus
97
+ const exponent = p.addn(1).iushrn(2) // (p + 1) / 4
98
+ return y2.redPow(exponent)
99
+ }
100
+
90
101
  /**
91
102
  * Generates a point from an x coordinate and a boolean indicating whether the corresponding
92
103
  * y coordinate is odd.
@@ -102,34 +113,108 @@ export default class Point extends BasePoint {
102
113
  * const xCoordinate = new BigNumber('10');
103
114
  * const point = Point.fromX(xCoordinate, true);
104
115
  */
105
-
106
116
  static fromX (x: BigNumber | number | number[] | string, odd: boolean): Point {
107
- const red = new ReductionContext('k256')
108
- const a = new BigNumber(0).toRed(red)
109
- const b = new BigNumber(7).toRed(red)
110
- const zero = new BigNumber(0).toRed(red)
111
- if (!BigNumber.isBN(x)) {
112
- x = new BigNumber(x as number, 16)
113
- }
114
- x = x as BigNumber
115
- if (x.red == null) {
116
- x = x.toRed(red)
117
- }
117
+ if (typeof BigInt === 'function') {
118
+ function mod (a: bigint, n: bigint): bigint {
119
+ return ((a % n) + n) % n
120
+ }
121
+ function modPow (base: bigint, exponent: bigint, modulus: bigint): bigint {
122
+ let result = BigInt(1)
123
+ base = mod(base, modulus)
124
+ while (exponent > BigInt(0)) {
125
+ if ((exponent & BigInt(1)) === BigInt(1)) {
126
+ result = mod(result * base, modulus)
127
+ }
128
+ exponent >>= BigInt(1)
129
+ base = mod(base * base, modulus)
130
+ }
131
+ return result
132
+ }
133
+ function sqrtMod (a: bigint, p: bigint): bigint | null {
134
+ const exponent = (p + BigInt(1)) >> BigInt(2) // Precomputed exponent
135
+ const sqrtCandidate = modPow(a, exponent, p)
136
+ if (mod(sqrtCandidate * sqrtCandidate, p) === mod(a, p)) {
137
+ return sqrtCandidate
138
+ } else {
139
+ // No square root exists
140
+ return null
141
+ }
142
+ }
118
143
 
119
- const y2 = x.redSqr().redMul(x).redIAdd(x.redMul(a)).redIAdd(b)
120
- let y = y2.redSqrt()
121
- if (y.redSqr().redSub(y2).cmp(zero) !== 0) {
122
- throw new Error('invalid point')
123
- }
144
+ // Curve parameters for secp256k1
145
+ const p = BigInt(
146
+ '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F'
147
+ )
148
+ const a = BigInt(0)
149
+ const b = BigInt(7)
150
+
151
+ // Convert x to BigInt
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(
159
+ '0x' +
160
+ Buffer.from(x).toString('hex').padStart(64, '0')
161
+ )
162
+ } else if (typeof x === 'number') {
163
+ xBigInt = BigInt(x)
164
+ } else {
165
+ throw new Error('Invalid x-coordinate type')
166
+ }
124
167
 
125
- // XXX Is there any way to tell if the number is odd without converting it
126
- // to non-red form?
127
- const isOdd = y.fromRed().isOdd()
128
- if ((odd && !isOdd) || (!odd && isOdd)) {
129
- y = y.redNeg()
130
- }
168
+ // Ensure x is within field range
169
+ xBigInt = mod(xBigInt, p)
131
170
 
132
- return new Point(x, y)
171
+ // Compute y^2 = x^3 + a x + b mod p
172
+ const y2 = mod(modPow(xBigInt, BigInt(3), p) + b, p)
173
+
174
+ // Compute modular square root y = sqrt(y2) mod p
175
+ let y = sqrtMod(y2, p)
176
+
177
+ if (y === null) {
178
+ throw new Error('Invalid point')
179
+ }
180
+
181
+ // Adjust y to match the oddness
182
+ const isYOdd = (y % BigInt(2)) === BigInt(1)
183
+ if ((odd && !isYOdd) || (!odd && isYOdd)) {
184
+ y = p - y
185
+ }
186
+
187
+ // Convert x and y to BigNumber
188
+ const xBN = new BigNumber(xBigInt.toString(16), 16)
189
+ const yBN = new BigNumber(y.toString(16), 16)
190
+ return new Point(xBN, yBN)
191
+ } else {
192
+ const red = new ReductionContext('k256')
193
+ const a = new BigNumber(0).toRed(red)
194
+ const b = new BigNumber(7).toRed(red)
195
+ const zero = new BigNumber(0).toRed(red)
196
+ if (!BigNumber.isBN(x)) {
197
+ x = new BigNumber(x as number, 16)
198
+ }
199
+ x = x as BigNumber
200
+ if (x.red == null) {
201
+ x = x.toRed(red)
202
+ }
203
+
204
+ const y2 = x.redSqr().redMul(x).redIAdd(x.redMul(a)).redIAdd(b)
205
+ let y = y2.redSqrt()
206
+ if (y.redSqr().redSub(y2).cmp(zero) !== 0) {
207
+ throw new Error('invalid point')
208
+ }
209
+
210
+ // XXX Is there any way to tell if the number is odd without converting it
211
+ // to non-red form?
212
+ const isOdd = y.fromRed().isOdd()
213
+ if ((odd && !isOdd) || (!odd && isOdd)) {
214
+ y = y.redNeg()
215
+ }
216
+ return new Point(x, y)
217
+ }
133
218
  }
134
219
 
135
220
  /**
@@ -40,7 +40,7 @@ export default class TransactionSignature extends Signature {
40
40
  const writer = new Writer()
41
41
  for (const input of inputs) {
42
42
  if (typeof input.sourceTXID === 'undefined') {
43
- writer.writeReverse(input.sourceTransaction.id())
43
+ writer.write(input.sourceTransaction.hash() as number[])
44
44
  } else {
45
45
  writer.writeReverse(toArray(input.sourceTXID, 'hex'))
46
46
  }
@@ -122,8 +122,9 @@ export default class TransactionSignature extends Signature {
122
122
  writer.writeUInt32LE(params.sourceOutputIndex)
123
123
 
124
124
  // scriptCode of the input (serialized as scripts inside CTxOuts)
125
- writer.writeVarIntNum(params.subscript.toBinary().length)
126
- writer.write(params.subscript.toBinary())
125
+ const subscriptBin = params.subscript.toBinary()
126
+ writer.writeVarIntNum(subscriptBin.length)
127
+ writer.write(subscriptBin)
127
128
 
128
129
  // value of the output spent by this input (8-byte little endian)
129
130
  writer.writeUInt64LE(params.sourceSatoshis)
@@ -320,9 +320,13 @@ export class Writer {
320
320
  }
321
321
 
322
322
  toArray (): number[] {
323
- let ret = []
324
- for (const x of this.bufs) {
325
- if (x.length < 65536) { ret.push(...x) } else { ret = ret.concat(x) }
323
+ const totalLength = this.getLength()
324
+ const ret = new Array(totalLength)
325
+ let offset = 0
326
+ for (const buf of this.bufs) {
327
+ for (let i = 0; i < buf.length; i++) {
328
+ ret[offset++] = buf[i]
329
+ }
326
330
  }
327
331
  return ret
328
332
  }
@@ -515,18 +519,18 @@ export class Reader {
515
519
  }
516
520
 
517
521
  public read (len = this.bin.length): number[] {
518
- const bin = this.bin.slice(this.pos, this.pos + len)
519
- this.pos = this.pos + len
520
- return bin
522
+ const start = this.pos
523
+ const end = this.pos + len
524
+ this.pos = end
525
+ return this.bin.slice(start, end)
521
526
  }
522
527
 
523
528
  public readReverse (len = this.bin.length): number[] {
524
- const bin = this.bin.slice(this.pos, this.pos + len)
525
- this.pos = this.pos + len
526
- const buf2 = new Array(bin.length)
527
- for (let i = 0; i < buf2.length; i++) {
528
- buf2[i] = bin[bin.length - 1 - i]
529
+ const buf2 = new Array(len)
530
+ for (let i = 0; i < len; i++) {
531
+ buf2[i] = this.bin[this.pos + len - 1 - i]
529
532
  }
533
+ this.pos += len
530
534
  return buf2
531
535
  }
532
536
 
@@ -207,9 +207,9 @@ export default class Spend {
207
207
  }
208
208
 
209
209
  const padDataToSize = (buf: number[], len: number): number[] => {
210
- let b = buf
210
+ const b = buf
211
211
  while (b.length < len) {
212
- b = [0x00, ...b]
212
+ b.unshift(0)
213
213
  }
214
214
  return b
215
215
  }
@@ -785,7 +785,7 @@ export default class Spend {
785
785
  shifted = bn1.ushrn(n)
786
786
  }
787
787
  const bufShifted = padDataToSize(
788
- [...shifted.toArray().slice(buf1.length * -1)],
788
+ shifted.toArray().slice(buf1.length * -1),
789
789
  buf1.length
790
790
  )
791
791
  this.stack.push(bufShifted)
@@ -1016,7 +1016,7 @@ export default class Spend {
1016
1016
 
1017
1017
  try {
1018
1018
  sig = TransactionSignature.fromChecksigFormat(bufSig)
1019
- pubkey = PublicKey.fromString(toHex(bufPubkey))
1019
+ pubkey = PublicKey.fromDER(bufPubkey)
1020
1020
  fSuccess = verifySignature(sig, pubkey, subscript)
1021
1021
  } catch (e) {
1022
1022
  // invalid sig or pubkey
package/src/totp/totp.ts CHANGED
@@ -106,7 +106,7 @@ function generateHOTP (
106
106
  options: Required<TOTPOptions>
107
107
  ): string {
108
108
  const timePad = new BigNumber(counter).toArray('be', 8)
109
- console.log({ timePad })
109
+ //console.log({ timePad })
110
110
  const hmac = calcHMAC(secret, timePad, options.algorithm)
111
111
  const signature = hmac.digest()
112
112