@bsv/sdk 2.0.11 → 2.0.13

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 (106) hide show
  1. package/dist/cjs/package.json +1 -1
  2. package/dist/cjs/src/auth/clients/__tests__/AuthFetch.additional.test.js +827 -0
  3. package/dist/cjs/src/auth/clients/__tests__/AuthFetch.additional.test.js.map +1 -0
  4. package/dist/cjs/src/auth/transports/__tests__/SimplifiedFetchTransport.additional.test.js +654 -0
  5. package/dist/cjs/src/auth/transports/__tests__/SimplifiedFetchTransport.additional.test.js.map +1 -0
  6. package/dist/cjs/src/overlay-tools/HostReputationTracker.js +21 -13
  7. package/dist/cjs/src/overlay-tools/HostReputationTracker.js.map +1 -1
  8. package/dist/cjs/src/primitives/PrivateKey.js +3 -3
  9. package/dist/cjs/src/primitives/PrivateKey.js.map +1 -1
  10. package/dist/cjs/src/script/Spend.js +17 -9
  11. package/dist/cjs/src/script/Spend.js.map +1 -1
  12. package/dist/cjs/src/storage/StorageDownloader.js +6 -6
  13. package/dist/cjs/src/storage/StorageDownloader.js.map +1 -1
  14. package/dist/cjs/src/storage/StorageUtils.js +1 -1
  15. package/dist/cjs/src/storage/StorageUtils.js.map +1 -1
  16. package/dist/cjs/src/transaction/MerklePath.js +168 -27
  17. package/dist/cjs/src/transaction/MerklePath.js.map +1 -1
  18. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  19. package/dist/esm/src/auth/clients/__tests__/AuthFetch.additional.test.js +825 -0
  20. package/dist/esm/src/auth/clients/__tests__/AuthFetch.additional.test.js.map +1 -0
  21. package/dist/esm/src/auth/transports/__tests__/SimplifiedFetchTransport.additional.test.js +619 -0
  22. package/dist/esm/src/auth/transports/__tests__/SimplifiedFetchTransport.additional.test.js.map +1 -0
  23. package/dist/esm/src/overlay-tools/HostReputationTracker.js +21 -13
  24. package/dist/esm/src/overlay-tools/HostReputationTracker.js.map +1 -1
  25. package/dist/esm/src/primitives/PrivateKey.js +3 -3
  26. package/dist/esm/src/primitives/PrivateKey.js.map +1 -1
  27. package/dist/esm/src/script/Spend.js +17 -9
  28. package/dist/esm/src/script/Spend.js.map +1 -1
  29. package/dist/esm/src/storage/StorageDownloader.js +6 -6
  30. package/dist/esm/src/storage/StorageDownloader.js.map +1 -1
  31. package/dist/esm/src/storage/StorageUtils.js +1 -1
  32. package/dist/esm/src/storage/StorageUtils.js.map +1 -1
  33. package/dist/esm/src/transaction/MerklePath.js +168 -27
  34. package/dist/esm/src/transaction/MerklePath.js.map +1 -1
  35. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  36. package/dist/types/src/auth/clients/__tests__/AuthFetch.additional.test.d.ts +21 -0
  37. package/dist/types/src/auth/clients/__tests__/AuthFetch.additional.test.d.ts.map +1 -0
  38. package/dist/types/src/auth/transports/__tests__/SimplifiedFetchTransport.additional.test.d.ts +2 -0
  39. package/dist/types/src/auth/transports/__tests__/SimplifiedFetchTransport.additional.test.d.ts.map +1 -0
  40. package/dist/types/src/overlay-tools/HostReputationTracker.d.ts.map +1 -1
  41. package/dist/types/src/script/Spend.d.ts.map +1 -1
  42. package/dist/types/src/transaction/MerklePath.d.ts +27 -0
  43. package/dist/types/src/transaction/MerklePath.d.ts.map +1 -1
  44. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  45. package/dist/umd/bundle.js +3 -3
  46. package/dist/umd/bundle.js.map +1 -1
  47. package/docs/reference/storage.md +1 -1
  48. package/docs/reference/transaction.md +40 -0
  49. package/package.json +1 -1
  50. package/src/auth/clients/__tests__/AuthFetch.additional.test.ts +1131 -0
  51. package/src/auth/transports/__tests__/SimplifiedFetchTransport.additional.test.ts +770 -0
  52. package/src/auth/utils/__tests/validateCertificates.test.ts +12 -9
  53. package/src/compat/__tests/Mnemonic.additional.test.ts +64 -0
  54. package/src/identity/__tests/IdentityClient.additional.test.ts +767 -0
  55. package/src/kvstore/__tests/LocalKVStore.additional.test.ts +611 -0
  56. package/src/kvstore/__tests/LocalKVStore.test.ts +4 -6
  57. package/src/kvstore/__tests/kvStoreInterpreter.test.ts +327 -0
  58. package/src/overlay-tools/HostReputationTracker.ts +17 -14
  59. package/src/overlay-tools/__tests/HostReputationTracker.additional.test.ts +561 -0
  60. package/src/overlay-tools/__tests/LookupResolver.additional.test.ts +612 -0
  61. package/src/overlay-tools/__tests/withDoubleSpendRetry.test.ts +278 -0
  62. package/src/primitives/PrivateKey.ts +3 -3
  63. package/src/primitives/__tests/BigNumber.additional.test.ts +79 -0
  64. package/src/primitives/__tests/Curve.additional.test.ts +208 -0
  65. package/src/primitives/__tests/ECDSA.additional.test.ts +122 -0
  66. package/src/primitives/__tests/Hash.additional.test.ts +59 -0
  67. package/src/primitives/__tests/JacobianPoint.test.ts +308 -0
  68. package/src/primitives/__tests/Point.additional.test.ts +503 -0
  69. package/src/primitives/__tests/PublicKey.additional.test.ts +383 -0
  70. package/src/primitives/__tests/Random.additional.test.ts +262 -0
  71. package/src/primitives/__tests/Signature.test.ts +333 -0
  72. package/src/primitives/__tests/TransactionSignature.additional.test.ts +241 -0
  73. package/src/registry/__tests/RegistryClient.additional.test.ts +750 -0
  74. package/src/remittance/__tests/BasicBRC29.additional.test.ts +657 -0
  75. package/src/remittance/__tests/RemittanceManager.additional.test.ts +1272 -0
  76. package/src/script/Spend.ts +19 -11
  77. package/src/script/__tests/LockingUnlockingScript.test.ts +79 -0
  78. package/src/script/__tests/Script.additional.test.ts +100 -0
  79. package/src/script/__tests/ScriptEvaluationError.test.ts +98 -0
  80. package/src/script/__tests/Spend.additional.test.ts +837 -0
  81. package/src/script/templates/__tests/RPuzzle.test.ts +134 -0
  82. package/src/storage/StorageDownloader.ts +6 -6
  83. package/src/storage/StorageUtils.ts +1 -1
  84. package/src/transaction/MerklePath.ts +196 -36
  85. package/src/transaction/__tests/BeefParty.additional.test.ts +22 -0
  86. package/src/transaction/__tests/Broadcaster.test.ts +159 -0
  87. package/src/transaction/__tests/MerklePath.bench.test.ts +105 -0
  88. package/src/transaction/__tests/MerklePath.test.ts +232 -21
  89. package/src/transaction/__tests/Transaction.additional.test.ts +225 -0
  90. package/src/transaction/broadcasters/__tests/ARC.additional.test.ts +585 -0
  91. package/src/transaction/broadcasters/__tests/Teranode.test.ts +349 -0
  92. package/src/transaction/chaintrackers/__tests/BlockHeadersService.test.ts +253 -0
  93. package/src/transaction/chaintrackers/__tests/DefaultChainTracker.test.ts +44 -0
  94. package/src/transaction/chaintrackers/__tests/WhatsOnChain.additional.test.ts +193 -0
  95. package/src/transaction/fee-models/__tests/SatoshisPerKilobyte.test.ts +262 -0
  96. package/src/transaction/http/__tests/BinaryFetchClient.test.ts +212 -0
  97. package/src/transaction/http/__tests/DefaultHttpClient.additional.test.ts +192 -0
  98. package/src/transaction/http/__tests/DefaultHttpClient.test.ts +71 -0
  99. package/src/wallet/__tests/ProtoWallet.additional.test.ts +134 -0
  100. package/src/wallet/__tests/WERR.test.ts +212 -0
  101. package/src/wallet/__tests/WalletClient.additional.test.ts +699 -0
  102. package/src/wallet/__tests/WalletClient.substrate.test.ts +759 -0
  103. package/src/wallet/__tests/WalletError.test.ts +290 -0
  104. package/src/wallet/__tests/validationHelpers.test.ts +1218 -0
  105. package/src/wallet/substrates/__tests/HTTPWalletJSON.test.ts +496 -0
  106. package/src/wallet/substrates/__tests/HTTPWalletWire.test.ts +273 -0
@@ -0,0 +1,503 @@
1
+ import Point from '../../primitives/Point'
2
+ import BigNumber from '../../primitives/BigNumber'
3
+ import Curve from '../../primitives/Curve'
4
+
5
+ const G_COMPRESSED = '0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798'
6
+
7
+ describe('Point – additional coverage', () => {
8
+ const curve = new Curve()
9
+ const G = curve.g as Point
10
+
11
+ // --------------------------------------------------------------------------
12
+ // Constructor and coordinate handling
13
+ // --------------------------------------------------------------------------
14
+ describe('constructor', () => {
15
+ it('constructs an infinity point with null, null', () => {
16
+ const inf = new Point(null, null)
17
+ expect(inf.isInfinity()).toBe(true)
18
+ })
19
+
20
+ it('constructs from number array x/y', () => {
21
+ const G2 = G.mul(new BigNumber(2))
22
+ const x = G2.getX().toArray()
23
+ const y = G2.getY().toArray()
24
+ const p = new Point(x, y)
25
+ expect(p.isInfinity()).toBe(false)
26
+ expect(p.getX().eq(G2.getX())).toBe(true)
27
+ })
28
+
29
+ it('constructs with isRed=false', () => {
30
+ const G2 = G.mul(new BigNumber(2))
31
+ const xBN = G2.getX()
32
+ const yBN = G2.getY()
33
+ const p = new Point(xBN, yBN, false)
34
+ expect(p.isInfinity()).toBe(false)
35
+ })
36
+ })
37
+
38
+ // --------------------------------------------------------------------------
39
+ // fromDER – uncompressed and hybrid formats
40
+ // --------------------------------------------------------------------------
41
+ describe('fromDER', () => {
42
+ it('parses uncompressed point (0x04)', () => {
43
+ const g = Point.fromString(G_COMPRESSED)
44
+ const bytes = g.encode(false) as number[]
45
+ expect(bytes[0]).toBe(0x04)
46
+ const restored = Point.fromDER(bytes)
47
+ expect(restored.eq(g)).toBe(true)
48
+ })
49
+
50
+ it('parses 0x06 hybrid (y-even) format', () => {
51
+ // Find a point where the last byte of the y coordinate is even
52
+ let gn: Point | null = null
53
+ for (let i = 2; i <= 20; i++) {
54
+ const candidate = G.mul(new BigNumber(i))
55
+ const uncompressed = candidate.encode(false) as number[]
56
+ if (uncompressed[uncompressed.length - 1] % 2 === 0) {
57
+ gn = candidate
58
+ break
59
+ }
60
+ }
61
+ if (gn === null) {
62
+ return
63
+ }
64
+ const uncompressed = gn.encode(false) as number[]
65
+ // Replace prefix with 0x06 (even y last byte)
66
+ uncompressed[0] = 0x06
67
+ const restored = Point.fromDER(uncompressed)
68
+ expect(restored.validate()).toBe(true)
69
+ })
70
+
71
+ it('parses 0x07 hybrid (y-odd) format', () => {
72
+ // Find a point where the last byte of the y coordinate (in the uncompressed encoding) is odd
73
+ let gn: Point | null = null
74
+ for (let i = 2; i <= 20; i++) {
75
+ const candidate = G.mul(new BigNumber(i))
76
+ const uncompressed = candidate.encode(false) as number[]
77
+ if (uncompressed[uncompressed.length - 1] % 2 === 1) {
78
+ gn = candidate
79
+ break
80
+ }
81
+ }
82
+ if (gn === null) {
83
+ // Skip if no suitable point found in range
84
+ return
85
+ }
86
+ const uncompressed = gn.encode(false) as number[]
87
+ // Replace prefix with 0x07 (odd y last byte)
88
+ uncompressed[0] = 0x07
89
+ const restored = Point.fromDER(uncompressed)
90
+ expect(restored.validate()).toBe(true)
91
+ })
92
+
93
+ it('throws for 0x06 when last byte is odd', () => {
94
+ // Build a valid-looking 65-byte buffer but set last byte to odd
95
+ // 0x06 requires last byte to be even, so odd → throws
96
+ const g = Point.fromString(G_COMPRESSED)
97
+ const uncompressed = g.encode(false) as number[]
98
+ uncompressed[0] = 0x06
99
+ // Force last byte to be odd
100
+ if (uncompressed[uncompressed.length - 1] % 2 === 0) {
101
+ uncompressed[uncompressed.length - 1] = 0x01
102
+ }
103
+ // Note: this may produce an invalid point too (validation error), either way it throws
104
+ expect(() => Point.fromDER(uncompressed)).toThrow()
105
+ })
106
+
107
+ it('throws for 0x07 when last byte is even', () => {
108
+ // Build a valid-looking 65-byte buffer but set last byte to even
109
+ // 0x07 requires last byte to be odd, so even → throws
110
+ const g = Point.fromString(G_COMPRESSED)
111
+ const uncompressed = g.encode(false) as number[]
112
+ uncompressed[0] = 0x07
113
+ // Force last byte to be even
114
+ if (uncompressed[uncompressed.length - 1] % 2 === 1) {
115
+ uncompressed[uncompressed.length - 1] = 0x02
116
+ }
117
+ expect(() => Point.fromDER(uncompressed)).toThrow()
118
+ })
119
+
120
+ it('throws for unknown format', () => {
121
+ const der = [0x05, ...Array(32).fill(0x01)]
122
+ expect(() => Point.fromDER(der)).toThrow('Unknown point format')
123
+ })
124
+ })
125
+
126
+ // --------------------------------------------------------------------------
127
+ // fromString
128
+ // --------------------------------------------------------------------------
129
+ describe('fromString', () => {
130
+ it('parses a compressed hex point', () => {
131
+ const p = Point.fromString(G_COMPRESSED)
132
+ expect(p.validate()).toBe(true)
133
+ })
134
+ })
135
+
136
+ // --------------------------------------------------------------------------
137
+ // fromX
138
+ // --------------------------------------------------------------------------
139
+ describe('fromX', () => {
140
+ it('fromX accepts BigNumber', () => {
141
+ const g = Point.fromString(G_COMPRESSED)
142
+ const xBN = g.getX()
143
+ const p = Point.fromX(xBN, false)
144
+ expect(p.validate()).toBe(true)
145
+ })
146
+
147
+ it('fromX accepts number', () => {
148
+ // Use a valid x value that has a square root mod p
149
+ const g = G.mul(new BigNumber(7))
150
+ const xNum = parseInt(g.getX().toString(16).slice(-4), 16)
151
+ // fromX with a number, may produce a point
152
+ const p = Point.fromX(g.getX(), true)
153
+ expect(p.validate()).toBe(true)
154
+ })
155
+
156
+ it('fromX accepts hex string', () => {
157
+ const g = G.mul(new BigNumber(7))
158
+ const xHex = g.getX().toString(16)
159
+ const p = Point.fromX(xHex, false)
160
+ expect(p.validate()).toBe(true)
161
+ })
162
+
163
+ it('fromX accepts number array', () => {
164
+ const g = G.mul(new BigNumber(7))
165
+ const xArr = g.getX().toArray()
166
+ const p = Point.fromX(xArr, true)
167
+ expect(p.validate()).toBe(true)
168
+ })
169
+ })
170
+
171
+ // --------------------------------------------------------------------------
172
+ // fromJSON
173
+ // --------------------------------------------------------------------------
174
+ describe('fromJSON', () => {
175
+ it('accepts JSON string', () => {
176
+ const g = Point.fromString(G_COMPRESSED)
177
+ const json = JSON.stringify(g.toJSON())
178
+ const restored = Point.fromJSON(json, true)
179
+ expect(restored.eq(g)).toBe(true)
180
+ })
181
+
182
+ it('fromJSON with naf precomputed data', () => {
183
+ const g = Point.fromString(G_COMPRESSED)
184
+ // Precomputed data has naf but no doubles
185
+ const serialized = [g.getX(), g.getY(), { naf: { wnd: 2, points: [] }, doubles: null }]
186
+ const restored = Point.fromJSON(serialized as any, true)
187
+ expect(restored.validate()).toBe(true)
188
+ })
189
+
190
+ it('fromJSON with doubles precomputed data', () => {
191
+ const g = Point.fromString(G_COMPRESSED)
192
+ const serialized = [g.getX(), g.getY(), { doubles: { step: 4, points: [] }, naf: null }]
193
+ const restored = Point.fromJSON(serialized as any, true)
194
+ expect(restored.validate()).toBe(true)
195
+ })
196
+
197
+ it('fromJSON with no precomputed (third element absent)', () => {
198
+ const g = Point.fromString(G_COMPRESSED)
199
+ const serialized = [g.getX(), g.getY()]
200
+ const restored = Point.fromJSON(serialized as any, true)
201
+ expect(restored.validate()).toBe(true)
202
+ })
203
+ })
204
+
205
+ // --------------------------------------------------------------------------
206
+ // validate
207
+ // --------------------------------------------------------------------------
208
+ describe('validate', () => {
209
+ it('returns false for infinity point', () => {
210
+ const inf = new Point(null, null)
211
+ expect(inf.validate()).toBe(false)
212
+ })
213
+
214
+ it('returns true for a valid curve point', () => {
215
+ const g = Point.fromString(G_COMPRESSED)
216
+ expect(g.validate()).toBe(true)
217
+ })
218
+ })
219
+
220
+ // --------------------------------------------------------------------------
221
+ // encode
222
+ // --------------------------------------------------------------------------
223
+ describe('encode', () => {
224
+ it('encodes infinity as [0x00]', () => {
225
+ const inf = new Point(null, null)
226
+ expect(inf.encode()).toEqual([0x00])
227
+ })
228
+
229
+ it('encodes infinity as "00" when enc=hex', () => {
230
+ const inf = new Point(null, null)
231
+ expect(inf.encode(true, 'hex')).toBe('00')
232
+ })
233
+
234
+ it('encodes compressed point (default compact=true)', () => {
235
+ const g = Point.fromString(G_COMPRESSED)
236
+ const encoded = g.encode()
237
+ expect(Array.isArray(encoded)).toBe(true)
238
+ const prefix = (encoded as number[])[0]
239
+ expect(prefix === 0x02 || prefix === 0x03).toBe(true)
240
+ })
241
+
242
+ it('encodes uncompressed point (compact=false)', () => {
243
+ const g = Point.fromString(G_COMPRESSED)
244
+ const encoded = g.encode(false) as number[]
245
+ expect(encoded[0]).toBe(0x04)
246
+ expect(encoded.length).toBe(65)
247
+ })
248
+
249
+ it('returns hex when enc=hex', () => {
250
+ const g = Point.fromString(G_COMPRESSED)
251
+ const hex = g.encode(true, 'hex')
252
+ expect(typeof hex).toBe('string')
253
+ expect(hex as string).toMatch(/^0[23][0-9a-f]+$/)
254
+ })
255
+ })
256
+
257
+ // --------------------------------------------------------------------------
258
+ // inspect
259
+ // --------------------------------------------------------------------------
260
+ describe('inspect', () => {
261
+ it('returns "<EC Point Infinity>" for infinity', () => {
262
+ const inf = new Point(null, null)
263
+ expect(inf.inspect()).toBe('<EC Point Infinity>')
264
+ })
265
+
266
+ it('returns readable string for valid point', () => {
267
+ const g = Point.fromString(G_COMPRESSED)
268
+ const s = g.inspect()
269
+ expect(s).toContain('<EC Point x:')
270
+ expect(s).toContain('y:')
271
+ })
272
+ })
273
+
274
+ // --------------------------------------------------------------------------
275
+ // add – edge cases
276
+ // --------------------------------------------------------------------------
277
+ describe('add edge cases', () => {
278
+ it('O + P = P (this is infinity)', () => {
279
+ const inf = new Point(null, null)
280
+ const g = Point.fromString(G_COMPRESSED)
281
+ const result = inf.add(g)
282
+ expect(result.eq(g)).toBe(true)
283
+ })
284
+
285
+ it('P + O = P (argument is infinity)', () => {
286
+ const inf = new Point(null, null)
287
+ const g = Point.fromString(G_COMPRESSED)
288
+ const result = g.add(inf)
289
+ expect(result.eq(g)).toBe(true)
290
+ })
291
+
292
+ it('P + P = 2P', () => {
293
+ const g = Point.fromString(G_COMPRESSED)
294
+ const g2 = g.dbl()
295
+ const result = g.add(g)
296
+ expect(result.eq(g2)).toBe(true)
297
+ })
298
+
299
+ it('P + (-P) = infinity', () => {
300
+ const g = Point.fromString(G_COMPRESSED)
301
+ const negG = g.neg()
302
+ const result = g.add(negG)
303
+ expect(result.isInfinity()).toBe(true)
304
+ })
305
+ })
306
+
307
+ // --------------------------------------------------------------------------
308
+ // dbl
309
+ // --------------------------------------------------------------------------
310
+ describe('dbl', () => {
311
+ it('dbl of infinity is infinity', () => {
312
+ const inf = new Point(null, null)
313
+ const result = inf.dbl()
314
+ expect(result.isInfinity()).toBe(true)
315
+ })
316
+
317
+ it('dbl of a valid point', () => {
318
+ const g = Point.fromString(G_COMPRESSED)
319
+ const g2 = g.dbl()
320
+ expect(g2.validate()).toBe(true)
321
+ expect(g2.eq(g)).toBe(false)
322
+ })
323
+ })
324
+
325
+ // --------------------------------------------------------------------------
326
+ // neg
327
+ // --------------------------------------------------------------------------
328
+ describe('neg', () => {
329
+ it('neg of infinity is infinity', () => {
330
+ const inf = new Point(null, null)
331
+ expect(inf.neg().isInfinity()).toBe(true)
332
+ })
333
+
334
+ it('neg of a valid point', () => {
335
+ const g = Point.fromString(G_COMPRESSED)
336
+ const negG = g.neg()
337
+ expect(negG.validate()).toBe(true)
338
+ expect(g.add(negG).isInfinity()).toBe(true)
339
+ })
340
+
341
+ it('neg with _precompute=true propagates precomputed data', () => {
342
+ const g = Point.fromString(G_COMPRESSED)
343
+ // Force precomputation via mul (which caches NAF)
344
+ g.mul(new BigNumber(2))
345
+ const negG = g.neg(true)
346
+ expect(negG.validate()).toBe(true)
347
+ })
348
+ })
349
+
350
+ // --------------------------------------------------------------------------
351
+ // dblp
352
+ // --------------------------------------------------------------------------
353
+ describe('dblp', () => {
354
+ it('dblp with k=0 returns same point', () => {
355
+ const g = Point.fromString(G_COMPRESSED)
356
+ const result = g.dblp(0)
357
+ expect(result.eq(g)).toBe(true)
358
+ })
359
+
360
+ it('dblp with k=3 equals three doublings', () => {
361
+ const g = Point.fromString(G_COMPRESSED)
362
+ const tripled = g.dbl().dbl().dbl()
363
+ const result = g.dblp(3)
364
+ expect(result.eq(tripled)).toBe(true)
365
+ })
366
+ })
367
+
368
+ // --------------------------------------------------------------------------
369
+ // getX / getY
370
+ // --------------------------------------------------------------------------
371
+ describe('getX / getY', () => {
372
+ it('getX and getY return BigNumber', () => {
373
+ const g = Point.fromString(G_COMPRESSED)
374
+ expect(BigNumber.isBN(g.getX())).toBe(true)
375
+ expect(BigNumber.isBN(g.getY())).toBe(true)
376
+ })
377
+ })
378
+
379
+ // --------------------------------------------------------------------------
380
+ // mul – edge cases
381
+ // --------------------------------------------------------------------------
382
+ describe('mul', () => {
383
+ it('mul by 0 returns infinity', () => {
384
+ const g = Point.fromString(G_COMPRESSED)
385
+ const result = g.mul(new BigNumber(0))
386
+ expect(result.isInfinity()).toBe(true)
387
+ })
388
+
389
+ it('mul infinity returns infinity', () => {
390
+ const inf = new Point(null, null)
391
+ const result = inf.mul(new BigNumber(5))
392
+ expect(result.isInfinity()).toBe(true)
393
+ })
394
+
395
+ it('mul by negative scalar', () => {
396
+ const g = Point.fromString(G_COMPRESSED)
397
+ const k = new BigNumber(3)
398
+ const r1 = g.mul(k)
399
+ const r2 = g.mul(k.neg())
400
+ expect(r1.eq(r2.neg())).toBe(true)
401
+ })
402
+
403
+ it('mul by number', () => {
404
+ const g = Point.fromString(G_COMPRESSED)
405
+ const r = g.mul(7)
406
+ expect(r.validate()).toBe(true)
407
+ })
408
+
409
+ it('mul by hex string', () => {
410
+ const g = Point.fromString(G_COMPRESSED)
411
+ const r = g.mul('0a')
412
+ expect(r.validate()).toBe(true)
413
+ })
414
+
415
+ it('mul by number array', () => {
416
+ const g = Point.fromString(G_COMPRESSED)
417
+ const r = g.mul([0x05])
418
+ expect(r.validate()).toBe(true)
419
+ })
420
+ })
421
+
422
+ // --------------------------------------------------------------------------
423
+ // mulAdd / jmulAdd
424
+ // --------------------------------------------------------------------------
425
+ describe('mulAdd / jmulAdd', () => {
426
+ it('mulAdd(1, G, 0) = G', () => {
427
+ const g = Point.fromString(G_COMPRESSED)
428
+ const result = g.mulAdd(new BigNumber(1), g, new BigNumber(0))
429
+ expect(result.eq(g)).toBe(true)
430
+ })
431
+
432
+ it('mulAdd(1, G, 1) = 2G', () => {
433
+ const g = Point.fromString(G_COMPRESSED)
434
+ const g2 = g.mul(new BigNumber(2))
435
+ const result = g.mulAdd(new BigNumber(1), g, new BigNumber(1))
436
+ expect(result.eq(g2)).toBe(true)
437
+ })
438
+
439
+ it('jmulAdd returns a JPoint', () => {
440
+ const g = Point.fromString(G_COMPRESSED)
441
+ const result = g.jmulAdd(new BigNumber(2), g, new BigNumber(1))
442
+ expect(result).toBeDefined()
443
+ const asPoint = result.toP()
444
+ const g3 = g.mul(new BigNumber(3))
445
+ expect(asPoint.eq(g3)).toBe(true)
446
+ })
447
+ })
448
+
449
+ // --------------------------------------------------------------------------
450
+ // eq
451
+ // --------------------------------------------------------------------------
452
+ describe('eq', () => {
453
+ it('same instance is equal', () => {
454
+ const g = Point.fromString(G_COMPRESSED)
455
+ expect(g.eq(g)).toBe(true)
456
+ })
457
+
458
+ it('both infinity are equal', () => {
459
+ const inf1 = new Point(null, null)
460
+ const inf2 = new Point(null, null)
461
+ expect(inf1.eq(inf2)).toBe(true)
462
+ })
463
+
464
+ it('infinity != non-infinity', () => {
465
+ const inf = new Point(null, null)
466
+ const g = Point.fromString(G_COMPRESSED)
467
+ expect(inf.eq(g)).toBe(false)
468
+ })
469
+ })
470
+
471
+ // --------------------------------------------------------------------------
472
+ // toJ
473
+ // --------------------------------------------------------------------------
474
+ describe('toJ', () => {
475
+ it('toJ of infinity gives JPoint at infinity', () => {
476
+ const inf = new Point(null, null)
477
+ const j = inf.toJ()
478
+ expect(j.isInfinity()).toBe(true)
479
+ })
480
+
481
+ it('toJ of valid point gives equivalent JPoint', () => {
482
+ const g = Point.fromString(G_COMPRESSED)
483
+ const j = g.toJ()
484
+ const restored = j.toP()
485
+ expect(restored.eq(g)).toBe(true)
486
+ })
487
+ })
488
+
489
+ // --------------------------------------------------------------------------
490
+ // toJSON with precomputed
491
+ // --------------------------------------------------------------------------
492
+ describe('toJSON with precomputed', () => {
493
+ it('toJSON returns array with precomputed when precomputed is set', () => {
494
+ // Force precomputation by using internal _getNAFPoints
495
+ const g = Point.fromString(G_COMPRESSED)
496
+ // Trigger precomputation via mul (which uses precomputed internally)
497
+ g.mul(new BigNumber(2))
498
+ const json = g.toJSON()
499
+ // Even without precomputed being set externally, should return at least 2 elements
500
+ expect(json.length).toBeGreaterThanOrEqual(2)
501
+ })
502
+ })
503
+ })