@bsv/sdk 1.9.22 → 1.9.23

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsv/sdk",
3
- "version": "1.9.22",
3
+ "version": "1.9.23",
4
4
  "type": "module",
5
5
  "description": "BSV Blockchain Software Development Kit",
6
6
  "main": "dist/cjs/mod.js",
@@ -73,6 +73,14 @@ export default class JacobianPoint extends BasePoint {
73
73
  }
74
74
 
75
75
  this.zOne = this.z === this.curve.one
76
+
77
+ // --- Canonicalize point at infinity ---
78
+ if (this.isInfinity()) {
79
+ this.x = this.curve.one
80
+ this.y = this.curve.one
81
+ this.z = new BigNumber(0).toRed(this.curve.red)
82
+ this.zOne = false
83
+ }
76
84
  }
77
85
 
78
86
  /**
@@ -361,9 +369,18 @@ export default class JacobianPoint extends BasePoint {
361
369
  return true
362
370
  }
363
371
 
372
+ p = p as JacobianPoint
373
+
374
+ // --- Infinity handling ---
375
+ if (this.isInfinity() && p.isInfinity()) {
376
+ return true
377
+ }
378
+ if (this.isInfinity() !== p.isInfinity()) {
379
+ return false
380
+ }
381
+
364
382
  // x1 * z2^2 == x2 * z1^2
365
383
  const z2 = this.z.redSqr()
366
- p = p as JacobianPoint
367
384
  const pz2 = p.z.redSqr()
368
385
  if (this.x.redMul(pz2).redISub(p.x.redMul(z2)).cmpn(0) !== 0) {
369
386
  return false
@@ -445,6 +445,10 @@ export default class Point extends BasePoint {
445
445
  * const encodedPointHex = aPoint.encode(true, 'hex');
446
446
  */
447
447
  encode (compact: boolean = true, enc?: 'hex'): number[] | string {
448
+ if (this.inf) {
449
+ if (enc === 'hex') return '00'
450
+ return [0x00]
451
+ }
448
452
  const len = this.curve.p.byteLength()
449
453
  const x = this.getX().toArray('be', len)
450
454
  let res: number[]
@@ -212,3 +212,66 @@ describe('Point codec', () => {
212
212
  makeShortTest(shortPointOddY)
213
213
  )
214
214
  })
215
+
216
+ describe('JacobianPoint – Infinity handling and equality (TOB-18)', () => {
217
+ function J(x: any, y: any, z: any) {
218
+ return new JPoint(x, y, z)
219
+ }
220
+
221
+ it('Multiple infinity representations are canonicalized and equal', () => {
222
+ const inf1 = J(null, null, null)
223
+ const inf2 = J('0', '0', '0')
224
+ const inf3 = J(new BigNumber(0), new BigNumber(0), new BigNumber(0))
225
+
226
+ expect(inf1.isInfinity()).toBe(true)
227
+ expect(inf2.isInfinity()).toBe(true)
228
+ expect(inf3.isInfinity()).toBe(true)
229
+
230
+ expect(inf1.eq(inf2)).toBe(true)
231
+ expect(inf2.eq(inf3)).toBe(true)
232
+ expect(inf1.eq(inf3)).toBe(true)
233
+ })
234
+
235
+ it('Infinity must not equal a finite point', () => {
236
+ const inf = J(null, null, null)
237
+
238
+ const good = J(
239
+ new BigNumber('e7789226', 16),
240
+ new BigNumber('4b76b191', 16),
241
+ new BigNumber('cbf8d990', 16)
242
+ )
243
+
244
+ expect(inf.eq(good)).toBe(false)
245
+ expect(good.eq(inf)).toBe(false)
246
+ })
247
+
248
+ it('Infinity equals infinity (canonicalized)', () => {
249
+ const inf1 = J(null, null, null)
250
+ const inf2 = J('0', '0', '0')
251
+
252
+ expect(inf1.eq(inf2)).toBe(true)
253
+ expect(inf2.eq(inf1)).toBe(true)
254
+ })
255
+
256
+ it('Infinity is detected when z is zero in RED form', () => {
257
+ const redZero = new BigNumber(0).toRed(new Curve().red)
258
+ const p = J('1', '2', redZero)
259
+
260
+ expect(p.isInfinity()).toBe(true)
261
+
262
+ const clean = J(null, null, null)
263
+ expect(p.eq(clean)).toBe(true)
264
+ expect(clean.eq(p)).toBe(true)
265
+ })
266
+
267
+ it('eq() must handle mixed canonical and non-canonical infinity cases', () => {
268
+ const canonical = J(null, null, null)
269
+ const messy = J('1', '1', new BigNumber(0))
270
+
271
+ expect(messy.isInfinity()).toBe(true)
272
+ expect(canonical.eq(messy)).toBe(true)
273
+ expect(messy.eq(canonical)).toBe(true)
274
+ })
275
+ })
276
+
277
+
@@ -11,6 +11,7 @@ import {
11
11
  toBase58Check,
12
12
  verifyNotNull
13
13
  } from '../../primitives/utils'
14
+ import Point from '../../primitives/Point'
14
15
 
15
16
  describe('utils', () => {
16
17
  it('should convert to array', () => {
@@ -359,3 +360,19 @@ describe('toUTF8 strict UTF-8 decoding (TOB-21)', () => {
359
360
 
360
361
  })
361
362
 
363
+ describe('Point.encode infinity handling', () => {
364
+ it('encodes infinity as 00 (array)', () => {
365
+ const p = new Point(null, null)
366
+ expect(p.encode()).toEqual([0x00])
367
+ })
368
+
369
+ it('encodes infinity as 00 (hex)', () => {
370
+ const p = new Point(null, null)
371
+ expect(p.encode(true, 'hex')).toBe('00')
372
+ })
373
+
374
+ it('does not throw for infinity', () => {
375
+ const p = new Point(null, null)
376
+ expect(() => p.encode()).not.toThrow()
377
+ })
378
+ })