@noble/curves 1.8.2 → 1.9.1

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 (199) hide show
  1. package/README.md +49 -24
  2. package/abstract/bls.js +1 -1
  3. package/abstract/bls.js.map +1 -1
  4. package/abstract/curve.d.ts +1 -1
  5. package/abstract/curve.d.ts.map +1 -1
  6. package/abstract/curve.js +13 -4
  7. package/abstract/curve.js.map +1 -1
  8. package/abstract/edwards.d.ts.map +1 -1
  9. package/abstract/edwards.js +17 -3
  10. package/abstract/edwards.js.map +1 -1
  11. package/abstract/fft.d.ts +120 -0
  12. package/abstract/fft.d.ts.map +1 -0
  13. package/abstract/fft.js +439 -0
  14. package/abstract/fft.js.map +1 -0
  15. package/abstract/hash-to-curve.d.ts +10 -5
  16. package/abstract/hash-to-curve.d.ts.map +1 -1
  17. package/abstract/hash-to-curve.js +31 -23
  18. package/abstract/hash-to-curve.js.map +1 -1
  19. package/abstract/modular.d.ts +13 -12
  20. package/abstract/modular.d.ts.map +1 -1
  21. package/abstract/modular.js +158 -158
  22. package/abstract/modular.js.map +1 -1
  23. package/abstract/montgomery.d.ts +4 -9
  24. package/abstract/montgomery.d.ts.map +1 -1
  25. package/abstract/montgomery.js +70 -90
  26. package/abstract/montgomery.js.map +1 -1
  27. package/abstract/poseidon.d.ts +39 -2
  28. package/abstract/poseidon.d.ts.map +1 -1
  29. package/abstract/poseidon.js +183 -4
  30. package/abstract/poseidon.js.map +1 -1
  31. package/abstract/tower.d.ts.map +1 -1
  32. package/abstract/tower.js +4 -5
  33. package/abstract/tower.js.map +1 -1
  34. package/abstract/utils.d.ts +1 -0
  35. package/abstract/utils.d.ts.map +1 -1
  36. package/abstract/utils.js +2 -0
  37. package/abstract/utils.js.map +1 -1
  38. package/abstract/weierstrass.d.ts +31 -9
  39. package/abstract/weierstrass.d.ts.map +1 -1
  40. package/abstract/weierstrass.js +67 -48
  41. package/abstract/weierstrass.js.map +1 -1
  42. package/bls12-381.d.ts.map +1 -1
  43. package/bls12-381.js +9 -23
  44. package/bls12-381.js.map +1 -1
  45. package/bn254.d.ts +1 -0
  46. package/bn254.d.ts.map +1 -1
  47. package/bn254.js +10 -0
  48. package/bn254.js.map +1 -1
  49. package/ed25519.d.ts +19 -5
  50. package/ed25519.d.ts.map +1 -1
  51. package/ed25519.js +29 -18
  52. package/ed25519.js.map +1 -1
  53. package/ed448.d.ts +21 -5
  54. package/ed448.d.ts.map +1 -1
  55. package/ed448.js +46 -34
  56. package/ed448.js.map +1 -1
  57. package/esm/abstract/bls.js +1 -1
  58. package/esm/abstract/bls.js.map +1 -1
  59. package/esm/abstract/curve.d.ts +1 -1
  60. package/esm/abstract/curve.d.ts.map +1 -1
  61. package/esm/abstract/curve.js +13 -4
  62. package/esm/abstract/curve.js.map +1 -1
  63. package/esm/abstract/edwards.d.ts.map +1 -1
  64. package/esm/abstract/edwards.js +19 -5
  65. package/esm/abstract/edwards.js.map +1 -1
  66. package/esm/abstract/fft.d.ts +120 -0
  67. package/esm/abstract/fft.d.ts.map +1 -0
  68. package/esm/abstract/fft.js +426 -0
  69. package/esm/abstract/fft.js.map +1 -0
  70. package/esm/abstract/hash-to-curve.d.ts +10 -5
  71. package/esm/abstract/hash-to-curve.d.ts.map +1 -1
  72. package/esm/abstract/hash-to-curve.js +32 -24
  73. package/esm/abstract/hash-to-curve.js.map +1 -1
  74. package/esm/abstract/modular.d.ts +13 -12
  75. package/esm/abstract/modular.d.ts.map +1 -1
  76. package/esm/abstract/modular.js +158 -158
  77. package/esm/abstract/modular.js.map +1 -1
  78. package/esm/abstract/montgomery.d.ts +4 -9
  79. package/esm/abstract/montgomery.d.ts.map +1 -1
  80. package/esm/abstract/montgomery.js +71 -91
  81. package/esm/abstract/montgomery.js.map +1 -1
  82. package/esm/abstract/poseidon.d.ts +39 -2
  83. package/esm/abstract/poseidon.d.ts.map +1 -1
  84. package/esm/abstract/poseidon.js +180 -5
  85. package/esm/abstract/poseidon.js.map +1 -1
  86. package/esm/abstract/tower.d.ts.map +1 -1
  87. package/esm/abstract/tower.js +4 -5
  88. package/esm/abstract/tower.js.map +1 -1
  89. package/esm/abstract/utils.d.ts +1 -0
  90. package/esm/abstract/utils.d.ts.map +1 -1
  91. package/esm/abstract/utils.js +2 -0
  92. package/esm/abstract/utils.js.map +1 -1
  93. package/esm/abstract/weierstrass.d.ts +31 -9
  94. package/esm/abstract/weierstrass.d.ts.map +1 -1
  95. package/esm/abstract/weierstrass.js +69 -50
  96. package/esm/abstract/weierstrass.js.map +1 -1
  97. package/esm/bls12-381.d.ts.map +1 -1
  98. package/esm/bls12-381.js +9 -23
  99. package/esm/bls12-381.js.map +1 -1
  100. package/esm/bn254.d.ts +1 -0
  101. package/esm/bn254.d.ts.map +1 -1
  102. package/esm/bn254.js +10 -0
  103. package/esm/bn254.js.map +1 -1
  104. package/esm/ed25519.d.ts +19 -5
  105. package/esm/ed25519.d.ts.map +1 -1
  106. package/esm/ed25519.js +29 -18
  107. package/esm/ed25519.js.map +1 -1
  108. package/esm/ed448.d.ts +21 -5
  109. package/esm/ed448.d.ts.map +1 -1
  110. package/esm/ed448.js +47 -35
  111. package/esm/ed448.js.map +1 -1
  112. package/esm/jubjub.d.ts +11 -1
  113. package/esm/jubjub.d.ts.map +1 -1
  114. package/esm/jubjub.js +11 -1
  115. package/esm/jubjub.js.map +1 -1
  116. package/esm/misc.d.ts +8 -2
  117. package/esm/misc.d.ts.map +1 -1
  118. package/esm/misc.js +10 -4
  119. package/esm/misc.js.map +1 -1
  120. package/esm/nist.d.ts +30 -0
  121. package/esm/nist.d.ts.map +1 -0
  122. package/esm/nist.js +121 -0
  123. package/esm/nist.js.map +1 -0
  124. package/esm/p256.d.ts +7 -9
  125. package/esm/p256.d.ts.map +1 -1
  126. package/esm/p256.js +6 -44
  127. package/esm/p256.js.map +1 -1
  128. package/esm/p384.d.ts +9 -10
  129. package/esm/p384.d.ts.map +1 -1
  130. package/esm/p384.js +7 -46
  131. package/esm/p384.js.map +1 -1
  132. package/esm/p521.d.ts +7 -8
  133. package/esm/p521.d.ts.map +1 -1
  134. package/esm/p521.js +6 -46
  135. package/esm/p521.js.map +1 -1
  136. package/esm/pasta.d.ts +9 -1
  137. package/esm/pasta.d.ts.map +1 -1
  138. package/esm/pasta.js +9 -1
  139. package/esm/pasta.js.map +1 -1
  140. package/esm/secp256k1.d.ts +3 -3
  141. package/esm/secp256k1.d.ts.map +1 -1
  142. package/esm/secp256k1.js +8 -9
  143. package/esm/secp256k1.js.map +1 -1
  144. package/jubjub.d.ts +11 -1
  145. package/jubjub.d.ts.map +1 -1
  146. package/jubjub.js +12 -5
  147. package/jubjub.js.map +1 -1
  148. package/misc.d.ts +8 -2
  149. package/misc.d.ts.map +1 -1
  150. package/misc.js +11 -5
  151. package/misc.js.map +1 -1
  152. package/nist.d.ts +30 -0
  153. package/nist.d.ts.map +1 -0
  154. package/nist.js +124 -0
  155. package/nist.js.map +1 -0
  156. package/p256.d.ts +7 -9
  157. package/p256.d.ts.map +1 -1
  158. package/p256.js +5 -49
  159. package/p256.js.map +1 -1
  160. package/p384.d.ts +9 -10
  161. package/p384.d.ts.map +1 -1
  162. package/p384.js +6 -51
  163. package/p384.js.map +1 -1
  164. package/p521.d.ts +7 -8
  165. package/p521.d.ts.map +1 -1
  166. package/p521.js +5 -51
  167. package/p521.js.map +1 -1
  168. package/package.json +117 -8
  169. package/pasta.d.ts +9 -1
  170. package/pasta.d.ts.map +1 -1
  171. package/pasta.js +9 -3
  172. package/pasta.js.map +1 -1
  173. package/secp256k1.d.ts +3 -3
  174. package/secp256k1.d.ts.map +1 -1
  175. package/secp256k1.js +9 -10
  176. package/secp256k1.js.map +1 -1
  177. package/src/abstract/bls.ts +1 -1
  178. package/src/abstract/curve.ts +11 -6
  179. package/src/abstract/edwards.ts +26 -12
  180. package/src/abstract/fft.ts +508 -0
  181. package/src/abstract/hash-to-curve.ts +44 -36
  182. package/src/abstract/modular.ts +154 -153
  183. package/src/abstract/montgomery.ts +78 -109
  184. package/src/abstract/poseidon.ts +208 -13
  185. package/src/abstract/tower.ts +4 -5
  186. package/src/abstract/utils.ts +2 -0
  187. package/src/abstract/weierstrass.ts +109 -61
  188. package/src/bls12-381.ts +11 -27
  189. package/src/bn254.ts +10 -0
  190. package/src/ed25519.ts +32 -19
  191. package/src/ed448.ts +91 -75
  192. package/src/jubjub.ts +12 -5
  193. package/src/misc.ts +10 -4
  194. package/src/nist.ts +155 -0
  195. package/src/p256.ts +6 -50
  196. package/src/p384.ts +8 -56
  197. package/src/p521.ts +6 -65
  198. package/src/pasta.ts +9 -1
  199. package/src/secp256k1.ts +12 -11
@@ -7,9 +7,9 @@
7
7
  *
8
8
  * * a: formula param
9
9
  * * b: formula param
10
- * * Fp: finite Field over which we'll do calculations. Can be complex (Fp2, Fp12)
11
- * * n: Curve prime subgroup order, total count of valid points in the field
12
- * * Gx: Base point (x, y) aka generator point x coordinate
10
+ * * Fp: finite field of prime characteristic P; may be complex (Fp2). Arithmetics is done in field
11
+ * * n: order of prime subgroup a.k.a total amount of valid curve points
12
+ * * Gx: Base point (x, y) aka generator point. Gx = x coordinate
13
13
  * * Gy: ...y coordinate
14
14
  * * h: cofactor, usually 1. h*n = curve group order (n is only subgroup order)
15
15
  * * lowS: whether to enable (default) or disable "low-s" non-malleable signatures
@@ -40,25 +40,51 @@
40
40
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
41
41
  // prettier-ignore
42
42
  import {
43
- type AffinePoint, type BasicCurve, type Group, type GroupConstructor,
44
43
  pippenger, validateBasic, wNAF,
44
+ type AffinePoint, type BasicCurve, type Group, type GroupConstructor
45
45
  } from './curve.ts';
46
46
  // prettier-ignore
47
47
  import {
48
- Field, type IField, getMinHashLength, invert, mapHashToField, mod, validateField,
48
+ Field,
49
+ FpInvertBatch,
50
+ getMinHashLength, invert, mapHashToField, mod, validateField,
51
+ type IField
49
52
  } from './modular.ts';
50
53
  // prettier-ignore
51
54
  import {
52
- type CHash, type Hex, type PrivKey,
53
55
  aInRange, abool,
54
56
  bitMask,
55
57
  bytesToHex, bytesToNumberBE, concatBytes, createHmacDrbg, ensureBytes, hexToBytes,
56
- inRange, isBytes, memoized, numberToBytesBE, numberToHexUnpadded, validateObject
58
+ inRange, isBytes, memoized, numberToBytesBE, numberToHexUnpadded, validateObject,
59
+ type CHash, type Hex, type PrivKey
57
60
  } from './utils.ts';
58
61
 
59
62
  export type { AffinePoint };
60
63
  type HmacFnSync = (key: Uint8Array, ...messages: Uint8Array[]) => Uint8Array;
61
- type EndomorphismOpts = {
64
+ /**
65
+ * When Weierstrass curve has `a=0`, it becomes Koblitz curve.
66
+ * Koblitz curves allow using **efficiently-computable GLV endomorphism ψ**.
67
+ * Endomorphism uses 2x less RAM, speeds up precomputation by 2x and ECDH / key recovery by 20%.
68
+ * For precomputed wNAF it trades off 1/2 init time & 1/3 ram for 20% perf hit.
69
+ *
70
+ * Endomorphism consists of beta, lambda and splitScalar:
71
+ *
72
+ * 1. GLV endomorphism ψ transforms a point: `P = (x, y) ↦ ψ(P) = (β·x mod p, y)`
73
+ * 2. GLV scalar decomposition transforms a scalar: `k ≡ k₁ + k₂·λ (mod n)`
74
+ * 3. Then these are combined: `k·P = k₁·P + k₂·ψ(P)`
75
+ * 4. Two 128-bit point-by-scalar multiplications + one point addition is faster than
76
+ * one 256-bit multiplication.
77
+ *
78
+ * where
79
+ * * beta: β ∈ Fₚ with β³ = 1, β ≠ 1
80
+ * * lambda: λ ∈ Fₙ with λ³ = 1, λ ≠ 1
81
+ * * splitScalar decomposes k ↦ k₁, k₂, by using reduced basis vectors.
82
+ * Gauss lattice reduction calculates them from initial basis vectors `(n, 0), (-λ, 0)`
83
+ *
84
+ * Check out `test/misc/endomorphism.js` and
85
+ * [gist](https://gist.github.com/paulmillr/eb670806793e84df628a7c434a873066).
86
+ */
87
+ export type EndomorphismOpts = {
62
88
  beta: bigint;
63
89
  splitScalar: (k: bigint) => { k1neg: boolean; k1: bigint; k2neg: boolean; k2: bigint };
64
90
  };
@@ -70,7 +96,7 @@ export type BasicWCurve<T> = BasicCurve<T> & {
70
96
  // Optional params
71
97
  allowedPrivateKeyLengths?: readonly number[]; // for P521
72
98
  wrapPrivateKey?: boolean; // bls12-381 requires mod(n) instead of rejecting keys >= n
73
- endo?: EndomorphismOpts; // Endomorphism options for Koblitz curves
99
+ endo?: EndomorphismOpts;
74
100
  // When a cofactor != 1, there can be an effective methods to:
75
101
  // 1. Determine whether a point is torsion-free
76
102
  isTorsionFree?: (c: ProjConstructor<T>, point: ProjPointType<T>) => boolean;
@@ -94,17 +120,16 @@ export interface ProjPointType<T> extends Group<ProjPointType<T>> {
94
120
  readonly pz: T;
95
121
  get x(): T;
96
122
  get y(): T;
97
- multiply(scalar: bigint): ProjPointType<T>;
98
123
  toAffine(iz?: T): AffinePoint<T>;
99
- isTorsionFree(): boolean;
100
- clearCofactor(): ProjPointType<T>;
101
- assertValidity(): void;
102
- hasEvenY(): boolean;
103
- toRawBytes(isCompressed?: boolean): Uint8Array;
104
124
  toHex(isCompressed?: boolean): string;
125
+ toRawBytes(isCompressed?: boolean): Uint8Array;
105
126
 
127
+ assertValidity(): void;
128
+ hasEvenY(): boolean;
106
129
  multiplyUnsafe(scalar: bigint): ProjPointType<T>;
107
130
  multiplyAndAddUnsafe(Q: ProjPointType<T>, a: bigint, b: bigint): ProjPointType<T> | undefined;
131
+ isTorsionFree(): boolean;
132
+ clearCofactor(): ProjPointType<T>;
108
133
  _setWindowSize(windowSize: number): void;
109
134
  }
110
135
  // Static methods for 3d XYZ points
@@ -136,26 +161,26 @@ function validatePointOpts<T>(curve: CurvePointsType<T>): CurvePointsTypeWithLen
136
161
  b: 'field',
137
162
  },
138
163
  {
164
+ allowInfinityPoint: 'boolean',
139
165
  allowedPrivateKeyLengths: 'array',
140
- wrapPrivateKey: 'boolean',
141
- isTorsionFree: 'function',
142
166
  clearCofactor: 'function',
143
- allowInfinityPoint: 'boolean',
144
167
  fromBytes: 'function',
168
+ isTorsionFree: 'function',
145
169
  toBytes: 'function',
170
+ wrapPrivateKey: 'boolean',
146
171
  }
147
172
  );
148
173
  const { endo, Fp, a } = opts;
149
174
  if (endo) {
150
175
  if (!Fp.eql(a, Fp.ZERO)) {
151
- throw new Error('invalid endomorphism, can only be defined for Koblitz curves that have a=0');
176
+ throw new Error('invalid endo: CURVE.a must be 0');
152
177
  }
153
178
  if (
154
179
  typeof endo !== 'object' ||
155
180
  typeof endo.beta !== 'bigint' ||
156
181
  typeof endo.splitScalar !== 'function'
157
182
  ) {
158
- throw new Error('invalid endomorphism, expected beta: bigint and splitScalar: function');
183
+ throw new Error('invalid endo: expected "beta": bigint and "splitScalar": function');
159
184
  }
160
185
  }
161
186
  return Object.freeze({ ...opts } as const);
@@ -287,6 +312,10 @@ export const DER: IDER = {
287
312
  },
288
313
  };
289
314
 
315
+ function numToSizedHex(num: bigint, size: number): string {
316
+ return bytesToHex(numberToBytesBE(num, size));
317
+ }
318
+
290
319
  // Be friendly to bad ECMAScript parsers by not using bigint literals
291
320
  // prettier-ignore
292
321
  const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3), _4n = BigInt(4);
@@ -320,15 +349,25 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>): CurvePointsRes<T
320
349
  function weierstrassEquation(x: T): T {
321
350
  const { a, b } = CURVE;
322
351
  const x2 = Fp.sqr(x); // x * x
323
- const x3 = Fp.mul(x2, x); // x2 * x
324
- return Fp.add(Fp.add(x3, Fp.mul(x, a)), b); // x3 + a * x + b
352
+ const x3 = Fp.mul(x2, x); // * x
353
+ return Fp.add(Fp.add(x3, Fp.mul(x, a)), b); // + a * x + b
325
354
  }
355
+
356
+ function isValidXY(x: T, y: T): boolean {
357
+ const left = Fp.sqr(y); // y²
358
+ const right = weierstrassEquation(x); // x³ + ax + b
359
+ return Fp.eql(left, right);
360
+ }
361
+
326
362
  // Validate whether the passed curve params are valid.
327
- // We check if curve equation works for generator point.
328
- // `assertValidity()` won't work: `isTorsionFree()` is not available at this point in bls12-381.
329
- // ProjectivePoint class has not been initialized yet.
330
- if (!Fp.eql(Fp.sqr(CURVE.Gy), weierstrassEquation(CURVE.Gx)))
331
- throw new Error('bad generator point: equation left != right');
363
+ // Test 1: equation = + ax + b should work for generator point.
364
+ if (!isValidXY(CURVE.Gx, CURVE.Gy)) throw new Error('bad curve params: generator point');
365
+
366
+ // Test 2: discriminant Δ part should be non-zero: 4a³ + 27b² != 0.
367
+ // Guarantees curve is genus-1, smooth (non-singular).
368
+ const _4a3 = Fp.mul(Fp.pow(CURVE.a, _3n), _4n);
369
+ const _27b2 = Fp.mul(Fp.sqr(CURVE.b), BigInt(27));
370
+ if (Fp.is0(Fp.add(_4a3, _27b2))) throw new Error('bad curve params: a or b');
332
371
 
333
372
  // Valid group elements reside in range 1..n-1
334
373
  function isWithinCurveOrder(num: bigint): boolean {
@@ -369,7 +408,7 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>): CurvePointsRes<T
369
408
 
370
409
  // Converts Projective point to affine (x, y) coordinates.
371
410
  // Can accept precomputed Z^-1 - for example, from invertBatch.
372
- // (x, y, z) ∋ (x=x/z, y=y/z)
411
+ // (X, Y, Z) ∋ (x=X/Z, y=Y/Z)
373
412
  const toAffineMemo = memoized((p: Point, iz?: T): AffinePoint<T> => {
374
413
  const { px: x, py: y, pz: z } = p;
375
414
  // Fast-path for normalized points
@@ -399,28 +438,28 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>): CurvePointsRes<T
399
438
  const { x, y } = p.toAffine();
400
439
  // Check if x, y are valid field elements
401
440
  if (!Fp.isValid(x) || !Fp.isValid(y)) throw new Error('bad point: x or y not FE');
402
- const left = Fp.sqr(y); // y²
403
- const right = weierstrassEquation(x); // x³ + ax + b
404
- if (!Fp.eql(left, right)) throw new Error('bad point: equation left != right');
441
+ if (!isValidXY(x, y)) throw new Error('bad point: equation left != right');
405
442
  if (!p.isTorsionFree()) throw new Error('bad point: not in prime-order subgroup');
406
443
  return true;
407
444
  });
408
445
 
409
446
  /**
410
- * Projective Point works in 3d / projective (homogeneous) coordinates: (x, y, z) ∋ (x=x/z, y=y/z)
447
+ * Projective Point works in 3d / projective (homogeneous) coordinates: (X, Y, Z) ∋ (x=X/Z, y=Y/Z)
411
448
  * Default Point works in 2d / affine coordinates: (x, y)
412
449
  * We're doing calculations in projective, because its operations don't require costly inversion.
413
450
  */
414
451
  class Point implements ProjPointType<T> {
452
+ // base / generator point
415
453
  static readonly BASE = new Point(CURVE.Gx, CURVE.Gy, Fp.ONE);
416
- static readonly ZERO = new Point(Fp.ZERO, Fp.ONE, Fp.ZERO);
454
+ // zero / infinity / identity point
455
+ static readonly ZERO = new Point(Fp.ZERO, Fp.ONE, Fp.ZERO); // 0, 1, 0
417
456
  readonly px: T;
418
457
  readonly py: T;
419
458
  readonly pz: T;
420
459
 
421
460
  constructor(px: T, py: T, pz: T) {
422
461
  if (px == null || !Fp.isValid(px)) throw new Error('x required');
423
- if (py == null || !Fp.isValid(py)) throw new Error('y required');
462
+ if (py == null || !Fp.isValid(py) || Fp.is0(py)) throw new Error('y required');
424
463
  if (pz == null || !Fp.isValid(pz)) throw new Error('z required');
425
464
  this.px = px;
426
465
  this.py = py;
@@ -454,7 +493,10 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>): CurvePointsRes<T
454
493
  * Optimization: converts a list of projective points to a list of identical points with Z=1.
455
494
  */
456
495
  static normalizeZ(points: Point[]): Point[] {
457
- const toInv = Fp.invertBatch(points.map((p) => p.pz));
496
+ const toInv = FpInvertBatch(
497
+ Fp,
498
+ points.map((p) => p.pz)
499
+ );
458
500
  return points.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine);
459
501
  }
460
502
 
@@ -617,6 +659,7 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>): CurvePointsRes<T
617
659
  is0() {
618
660
  return this.equals(Point.ZERO);
619
661
  }
662
+
620
663
  private wNAF(n: bigint): { p: Point; f: Point } {
621
664
  return wnaf.wNAFCached(this, n, Point.normalizeZ);
622
665
  }
@@ -638,6 +681,7 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>): CurvePointsRes<T
638
681
  return wnaf.wNAFCachedUnsafe(this, sc, Point.normalizeZ);
639
682
 
640
683
  // Case c: endomorphism
684
+ /** See docs for {@link EndomorphismOpts} */
641
685
  let { k1neg, k1, k2neg, k2 } = endo.splitScalar(sc);
642
686
  let k1p = I;
643
687
  let k2p = I;
@@ -668,6 +712,7 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>): CurvePointsRes<T
668
712
  const { endo, n: N } = CURVE;
669
713
  aInRange('scalar', scalar, _1n, N);
670
714
  let point: Point, fake: Point; // Fake point is used to const-time mult
715
+ /** See docs for {@link EndomorphismOpts} */
671
716
  if (endo) {
672
717
  const { k1neg, k1, k2neg, k2 } = endo.splitScalar(scalar);
673
718
  let { p: k1p, f: f1p } = this.wNAF(k1);
@@ -732,9 +777,8 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>): CurvePointsRes<T
732
777
  return bytesToHex(this.toRawBytes(isCompressed));
733
778
  }
734
779
  }
735
- const _bits = CURVE.nBitLength;
736
- const wnaf = wNAF(Point, CURVE.endo ? Math.ceil(_bits / 2) : _bits);
737
- // Validate if generator point is on curve
780
+ const { endo, nBitLength } = CURVE;
781
+ const wnaf = wNAF(Point, endo ? Math.ceil(nBitLength / 2) : nBitLength);
738
782
  return {
739
783
  CURVE,
740
784
  ProjectivePoint: Point as ProjConstructor<T>,
@@ -756,7 +800,6 @@ export interface SignatureType {
756
800
  recoverPublicKey(msgHash: Hex): ProjPointType<bigint>;
757
801
  toCompactRawBytes(): Uint8Array;
758
802
  toCompactHex(): string;
759
- // DER-encoded
760
803
  toDERRawBytes(isCompressed?: boolean): Uint8Array;
761
804
  toDERHex(isCompressed?: boolean): string;
762
805
  }
@@ -827,7 +870,7 @@ export type CurveFn = {
827
870
  */
828
871
  export function weierstrass(curveDef: CurveType): CurveFn {
829
872
  const CURVE = validateOpts(curveDef) as ReturnType<typeof validateOpts>;
830
- const { Fp, n: CURVE_ORDER } = CURVE;
873
+ const { Fp, n: CURVE_ORDER, nByteLength, nBitLength } = CURVE;
831
874
  const compressedLen = Fp.BYTES + 1; // e.g. 33 for 32
832
875
  const uncompressedLen = 2 * Fp.BYTES + 1; // e.g. 65 for 32
833
876
 
@@ -890,8 +933,6 @@ export function weierstrass(curveDef: CurveType): CurveFn {
890
933
  }
891
934
  },
892
935
  });
893
- const numToNByteHex = (num: bigint): string =>
894
- bytesToHex(numberToBytesBE(num, CURVE.nByteLength));
895
936
 
896
937
  function isBiggerThanHalfOrder(number: bigint) {
897
938
  const HALF = CURVE_ORDER >> _1n;
@@ -922,7 +963,7 @@ export function weierstrass(curveDef: CurveType): CurveFn {
922
963
 
923
964
  // pair (bytes of r, bytes of s)
924
965
  static fromCompact(hex: Hex) {
925
- const l = CURVE.nByteLength;
966
+ const l = nByteLength;
926
967
  hex = ensureBytes('compactSignature', hex, l * 2);
927
968
  return new Signature(slcNum(hex, 0, l), slcNum(hex, l, 2 * l));
928
969
  }
@@ -951,7 +992,7 @@ export function weierstrass(curveDef: CurveType): CurveFn {
951
992
  const radj = rec === 2 || rec === 3 ? r + CURVE.n : r;
952
993
  if (radj >= Fp.ORDER) throw new Error('recovery id 2 or 3 invalid');
953
994
  const prefix = (rec & 1) === 0 ? '02' : '03';
954
- const R = Point.fromHex(prefix + numToNByteHex(radj));
995
+ const R = Point.fromHex(prefix + numToSizedHex(radj, Fp.BYTES));
955
996
  const ir = invN(radj); // r^-1
956
997
  const u1 = modN(-h * ir); // -hr^-1
957
998
  const u2 = modN(s * ir); // sr^-1
@@ -975,7 +1016,7 @@ export function weierstrass(curveDef: CurveType): CurveFn {
975
1016
  return hexToBytes(this.toDERHex());
976
1017
  }
977
1018
  toDERHex() {
978
- return DER.hexFromSig({ r: this.r, s: this.s });
1019
+ return DER.hexFromSig(this);
979
1020
  }
980
1021
 
981
1022
  // padded bytes of r, then padded bytes of s
@@ -983,7 +1024,8 @@ export function weierstrass(curveDef: CurveType): CurveFn {
983
1024
  return hexToBytes(this.toCompactHex());
984
1025
  }
985
1026
  toCompactHex() {
986
- return numToNByteHex(this.r) + numToNByteHex(this.s);
1027
+ const l = nByteLength;
1028
+ return numToSizedHex(this.r, l) + numToSizedHex(this.s, l);
987
1029
  }
988
1030
  }
989
1031
  type RecoveredSignature = Signature & { recovery: number };
@@ -1036,14 +1078,19 @@ export function weierstrass(curveDef: CurveType): CurveFn {
1036
1078
  /**
1037
1079
  * Quick and dirty check for item being public key. Does not validate hex, or being on-curve.
1038
1080
  */
1039
- function isProbPub(item: PrivKey | PubKey): boolean {
1040
- const arr = isBytes(item);
1041
- const str = typeof item === 'string';
1042
- const len = (arr || str) && (item as Hex).length;
1043
- if (arr) return len === compressedLen || len === uncompressedLen;
1044
- if (str) return len === 2 * compressedLen || len === 2 * uncompressedLen;
1081
+ function isProbPub(item: PrivKey | PubKey): boolean | undefined {
1082
+ if (typeof item === 'bigint') return false;
1045
1083
  if (item instanceof Point) return true;
1046
- return false;
1084
+ const arr = ensureBytes('key', item);
1085
+ const len = arr.length;
1086
+ const fpl = Fp.BYTES;
1087
+ const compLen = fpl + 1; // e.g. 33 for 32
1088
+ const uncompLen = 2 * fpl + 1; // e.g. 65 for 32
1089
+ if (CURVE.allowedPrivateKeyLengths || nByteLength === compLen) {
1090
+ return undefined;
1091
+ } else {
1092
+ return len === compLen || len === uncompLen;
1093
+ }
1047
1094
  }
1048
1095
 
1049
1096
  /**
@@ -1057,8 +1104,8 @@ export function weierstrass(curveDef: CurveType): CurveFn {
1057
1104
  * @returns shared public key
1058
1105
  */
1059
1106
  function getSharedSecret(privateA: PrivKey, publicB: Hex, isCompressed = true): Uint8Array {
1060
- if (isProbPub(privateA)) throw new Error('first arg must be private key');
1061
- if (!isProbPub(publicB)) throw new Error('second arg must be public key');
1107
+ if (isProbPub(privateA) === true) throw new Error('first arg must be private key');
1108
+ if (isProbPub(publicB) === false) throw new Error('second arg must be public key');
1062
1109
  const b = Point.fromHex(publicB); // check for being on-curve
1063
1110
  return b.multiply(normPrivateKeyToScalar(privateA)).toRawBytes(isCompressed);
1064
1111
  }
@@ -1070,12 +1117,12 @@ export function weierstrass(curveDef: CurveType): CurveFn {
1070
1117
  const bits2int =
1071
1118
  CURVE.bits2int ||
1072
1119
  function (bytes: Uint8Array): bigint {
1073
- // Our custom check "just in case"
1120
+ // Our custom check "just in case", for protection against DoS
1074
1121
  if (bytes.length > 8192) throw new Error('input is too large');
1075
1122
  // For curves with nBitLength % 8 !== 0: bits2octets(bits2octets(m)) !== bits2octets(m)
1076
1123
  // for some cases, since bytes.length * 8 is not actual bitLength.
1077
1124
  const num = bytesToNumberBE(bytes); // check for == u8 done here
1078
- const delta = bytes.length * 8 - CURVE.nBitLength; // truncate to nBitLength leftmost bits
1125
+ const delta = bytes.length * 8 - nBitLength; // truncate to nBitLength leftmost bits
1079
1126
  return delta > 0 ? num >> BigInt(delta) : num;
1080
1127
  };
1081
1128
  const bits2int_modN =
@@ -1084,14 +1131,14 @@ export function weierstrass(curveDef: CurveType): CurveFn {
1084
1131
  return modN(bits2int(bytes)); // can't use bytesToNumberBE here
1085
1132
  };
1086
1133
  // NOTE: pads output with zero as per spec
1087
- const ORDER_MASK = bitMask(CURVE.nBitLength);
1134
+ const ORDER_MASK = bitMask(nBitLength);
1088
1135
  /**
1089
1136
  * Converts to bytes. Checks if num in `[0..ORDER_MASK-1]` e.g.: `[0..2^256-1]`.
1090
1137
  */
1091
1138
  function int2octets(num: bigint): Uint8Array {
1092
- aInRange('num < 2^' + CURVE.nBitLength, num, _0n, ORDER_MASK);
1139
+ aInRange('num < 2^' + nBitLength, num, _0n, ORDER_MASK);
1093
1140
  // works with order, can have different size than numToField!
1094
- return numberToBytesBE(num, CURVE.nByteLength);
1141
+ return numberToBytesBE(num, nByteLength);
1095
1142
  }
1096
1143
 
1097
1144
  // Steps A, D of RFC6979 3.2
@@ -1383,7 +1430,8 @@ export function mapToCurveSimpleSWU<T>(
1383
1430
  y = Fp.cmov(y, value, isValid); // 22. y = CMOV(y, y1, is_gx1_square)
1384
1431
  const e1 = Fp.isOdd!(u) === Fp.isOdd!(y); // 23. e1 = sgn0(u) == sgn0(y)
1385
1432
  y = Fp.cmov(Fp.neg(y), y, e1); // 24. y = CMOV(-y, y, e1)
1386
- x = Fp.div(x, tv4); // 25. x = x / tv4
1433
+ const tv4_inv = FpInvertBatch(Fp, [tv4], true)[0];
1434
+ x = Fp.mul(x, tv4_inv); // 25. x = x / tv4
1387
1435
  return { x, y };
1388
1436
  };
1389
1437
  }
package/src/bls12-381.ts CHANGED
@@ -28,12 +28,12 @@
28
28
  * 3. Curve security level is about 120 bits as per [Barbulescu-Duquesne 2017](https://hal.science/hal-01534101/file/main.pdf)
29
29
  * 4. Compatible with specs:
30
30
  * [cfrg-pairing-friendly-curves-11](https://tools.ietf.org/html/draft-irtf-cfrg-pairing-friendly-curves-11),
31
- * [cfrg-bls-signature-05](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-05),
31
+ * [cfrg-bls-signature-05](https://www.rfc-editor.org/rfc/draft-irtf-cfrg-bls-signature-05),
32
32
  * RFC 9380.
33
33
  *
34
34
  * ### Params
35
35
  * To verify curve parameters, see
36
- * [pairing-friendly-curves spec](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-11).
36
+ * [pairing-friendly-curves spec](https://www.rfc-editor.org/rfc/draft-irtf-cfrg-pairing-friendly-curves-11).
37
37
  * Basic math is done over finite fields over p.
38
38
  * More complicated math is done over polynominal extension fields.
39
39
  * To simplify calculations in Fp12, we construct extension tower:
@@ -70,16 +70,16 @@ import {
70
70
  bytesToNumberBE,
71
71
  concatBytes as concatB,
72
72
  ensureBytes,
73
- type Hex,
74
73
  numberToBytesBE,
74
+ type Hex,
75
75
  } from './abstract/utils.ts';
76
76
  // Types
77
77
  import { isogenyMap } from './abstract/hash-to-curve.ts';
78
78
  import type { Fp, Fp12, Fp2, Fp6 } from './abstract/tower.ts';
79
79
  import { psiFrobenius, tower12 } from './abstract/tower.ts';
80
80
  import {
81
- type AffinePoint,
82
81
  mapToCurveSimpleSWU,
82
+ type AffinePoint,
83
83
  type ProjPointType,
84
84
  } from './abstract/weierstrass.ts';
85
85
 
@@ -337,8 +337,7 @@ const G1_SWU = mapToCurveSimpleSWU(Fp, {
337
337
  Z: Fp.create(BigInt(11)),
338
338
  });
339
339
 
340
- // Endomorphisms (for fast cofactor clearing)
341
- // Ψ(P) endomorphism
340
+ // GLV endomorphism Ψ(P), for fast cofactor clearing
342
341
  const { G2psi, G2psi2 } = psiFrobenius(Fp, Fp2, Fp2.div(Fp2.ONE, Fp2.NONRESIDUE)); // 1/(u+1)
343
342
 
344
343
  // Default hash_to_field options are for hash to G2.
@@ -476,28 +475,15 @@ export const bls12_381: CurveFn = bls({
476
475
  // It returns false for shitty points.
477
476
  // https://eprint.iacr.org/2021/1130.pdf
478
477
  isTorsionFree: (c, point): boolean => {
479
- // φ endomorphism
480
- const cubicRootOfUnityModP = BigInt(
478
+ // GLV endomorphism ψ(P)
479
+ const beta = BigInt(
481
480
  '0x5f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'
482
481
  );
483
- const phi = new c(Fp.mul(point.px, cubicRootOfUnityModP), point.py, point.pz);
484
-
485
- // todo: unroll
482
+ const phi = new c(Fp.mul(point.px, beta), point.py, point.pz);
483
+ // TODO: unroll
486
484
  const xP = point.multiplyUnsafe(BLS_X).negate(); // [x]P
487
485
  const u2P = xP.multiplyUnsafe(BLS_X); // [u2]P
488
486
  return u2P.equals(phi);
489
-
490
- // https://eprint.iacr.org/2019/814.pdf
491
- // (z² − 1)/3
492
- // const c1 = BigInt('0x396c8c005555e1560000000055555555');
493
- // const P = this;
494
- // const S = P.sigma();
495
- // const Q = S.double();
496
- // const S2 = S.sigma();
497
- // // [(z² − 1)/3](2σ(P) − P − σ²(P)) − σ²(P) = O
498
- // const left = Q.subtract(P).subtract(S2).multiplyUnsafe(c1);
499
- // const C = left.subtract(S2);
500
- // return C.isZero();
501
487
  },
502
488
  // Clear cofactor of G1
503
489
  // https://eprint.iacr.org/2019/403
@@ -627,14 +613,12 @@ export const bls12_381: CurveFn = bls({
627
613
  // point.isTorsionFree() should return true for valid points
628
614
  // It returns false for shitty points.
629
615
  // https://eprint.iacr.org/2021/1130.pdf
616
+ // Older version: https://eprint.iacr.org/2019/814.pdf
630
617
  isTorsionFree: (c, P): boolean => {
631
618
  return P.multiplyUnsafe(BLS_X).negate().equals(G2psi(c, P)); // ψ(P) == [u](P)
632
- // Older version: https://eprint.iacr.org/2019/814.pdf
633
- // Ψ²(P) => Ψ³(P) => [z]Ψ³(P) where z = -x => [z]Ψ³(P) - Ψ²(P) + P == O
634
- // return P.psi2().psi().mulNegX().subtract(psi2).add(P).isZero();
635
619
  },
636
620
  // Maps the point into the prime-order subgroup G2.
637
- // clear_cofactor_bls12381_g2 from cfrg-hash-to-curve-11
621
+ // clear_cofactor_bls12381_g2 from RFC 9380.
638
622
  // https://eprint.iacr.org/2017/419.pdf
639
623
  // prettier-ignore
640
624
  clearCofactor: (c, P) => {
package/src/bn254.ts CHANGED
@@ -13,6 +13,15 @@ There are huge compatibility issues in the ecosystem:
13
13
  https://github.com/scipr-lab/libff/blob/a44f482e18b8ac04d034c193bd9d7df7817ad73f/libff/algebra/curves/bn128/bn128_init.cpp#L166-L169
14
14
  3. halo2curves bn256 is also incompatible and returns different outputs
15
15
 
16
+ We don't implement Point methods toHex / toRawBytes.
17
+ To work around this limitation, has to initialize points on their own from BigInts.
18
+ Reason it's not implemented is because [there is no standard](https://github.com/privacy-scaling-explorations/halo2curves/issues/109).
19
+ Points of divergence:
20
+
21
+ - Endianness: LE vs BE (byte-swapped)
22
+ - Flags as first hex bits (similar to BLS) vs no-flags
23
+ - Imaginary part last in G2 vs first (c0, c1 vs c1, c0)
24
+
16
25
  The goal of our implementation is to support "Ethereum" variant of the curve,
17
26
  because it at least has specs:
18
27
 
@@ -239,6 +248,7 @@ export const bn254: BLSCurveFn = bls({
239
248
  * bn254 weierstrass curve with ECDSA.
240
249
  * This is very rare and probably not used anywhere.
241
250
  * Instead, you should use G1 / G2, defined above.
251
+ * @deprecated
242
252
  */
243
253
  export const bn254_weierstrass: CurveFn = weierstrass({
244
254
  a: BigInt(0),
package/src/ed25519.ts CHANGED
@@ -13,10 +13,11 @@ import { type CurveFn, type ExtPointType, twistedEdwards } from './abstract/edwa
13
13
  import {
14
14
  createHasher,
15
15
  expand_message_xmd,
16
+ type Hasher,
16
17
  type htfBasicOpts,
17
18
  type HTFMethod,
18
19
  } from './abstract/hash-to-curve.ts';
19
- import { Field, FpSqrtEven, isNegativeLE, mod, pow2 } from './abstract/modular.ts';
20
+ import { Field, FpInvertBatch, FpSqrtEven, isNegativeLE, mod, pow2 } from './abstract/modular.ts';
20
21
  import { montgomery, type CurveFn as XCurveFn } from './abstract/montgomery.ts';
21
22
  import {
22
23
  bytesToHex,
@@ -178,10 +179,7 @@ export const ed25519ph: CurveFn = /* @__PURE__ */ (() =>
178
179
  export const x25519: XCurveFn = /* @__PURE__ */ (() =>
179
180
  montgomery({
180
181
  P: ED25519_P,
181
- a: BigInt(486662),
182
- montgomeryBits: 255, // n is 253 bits
183
- nByteLength: 32,
184
- Gu: BigInt(9),
182
+ type: 'x25519',
185
183
  powPminus2: (x: bigint): bigint => {
186
184
  const P = ED25519_P;
187
185
  // x^(p-2) aka x^(2^255-21)
@@ -289,12 +287,11 @@ function map_to_curve_elligator2_edwards25519(u: bigint) {
289
287
  xd = Fp.cmov(xd, Fp.ONE, e); // 10. xd = CMOV(xd, 1, e)
290
288
  yn = Fp.cmov(yn, Fp.ONE, e); // 11. yn = CMOV(yn, 1, e)
291
289
  yd = Fp.cmov(yd, Fp.ONE, e); // 12. yd = CMOV(yd, 1, e)
292
-
293
- const inv = Fp.invertBatch([xd, yd]); // batch division
294
- return { x: Fp.mul(xn, inv[0]), y: Fp.mul(yn, inv[1]) }; // 13. return (xn, xd, yn, yd)
290
+ const [xd_inv, yd_inv] = FpInvertBatch(Fp, [xd, yd], true); // batch division
291
+ return { x: Fp.mul(xn, xd_inv), y: Fp.mul(yn, yd_inv) }; // 13. return (xn, xd, yn, yd)
295
292
  }
296
293
 
297
- const htf = /* @__PURE__ */ (() =>
294
+ export const ed25519_hasher: Hasher<bigint> = /* @__PURE__ */ (() =>
298
295
  createHasher(
299
296
  ed25519.ExtendedPoint,
300
297
  (scalars: bigint[]) => map_to_curve_elligator2_edwards25519(scalars[0]),
@@ -308,8 +305,9 @@ const htf = /* @__PURE__ */ (() =>
308
305
  hash: sha512,
309
306
  }
310
307
  ))();
311
- export const hashToCurve: HTFMethod<bigint> = /* @__PURE__ */ (() => htf.hashToCurve)();
312
- export const encodeToCurve: HTFMethod<bigint> = /* @__PURE__ */ (() => htf.encodeToCurve)();
308
+ export const hashToCurve: HTFMethod<bigint> = /* @__PURE__ */ (() => ed25519_hasher.hashToCurve)();
309
+ export const encodeToCurve: HTFMethod<bigint> = /* @__PURE__ */ (() =>
310
+ ed25519_hasher.encodeToCurve)();
313
311
 
314
312
  function aristp(other: unknown) {
315
313
  if (!(other instanceof RistPoint)) throw new Error('RistrettoPoint expected');
@@ -344,8 +342,11 @@ const bytes255ToNumberLE = (bytes: Uint8Array) =>
344
342
 
345
343
  type ExtendedPoint = ExtPointType;
346
344
 
347
- // Computes Elligator map for Ristretto
348
- // https://ristretto.group/formulas/elligator.html
345
+ /**
346
+ * Computes Elligator map for Ristretto255.
347
+ * Described in [RFC9380](https://www.rfc-editor.org/rfc/rfc9380#appendix-B) and on
348
+ * the [website](https://ristretto.group/formulas/elligator.html).
349
+ */
349
350
  function calcElligatorRistrettoMap(r0: bigint): ExtendedPoint {
350
351
  const { d } = ed25519.CURVE;
351
352
  const P = ed25519.CURVE.Fp.ORDER;
@@ -373,7 +374,7 @@ function calcElligatorRistrettoMap(r0: bigint): ExtendedPoint {
373
374
  * a source of bugs for protocols like ring signatures. Ristretto was created to solve this.
374
375
  * Ristretto point operates in X:Y:Z:T extended coordinates like ExtendedPoint,
375
376
  * but it should work in its own namespace: do not combine those two.
376
- * https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448
377
+ * See [RFC9496](https://www.rfc-editor.org/rfc/rfc9496).
377
378
  */
378
379
  class RistPoint implements Group<RistPoint> {
379
380
  static BASE: RistPoint;
@@ -393,7 +394,8 @@ class RistPoint implements Group<RistPoint> {
393
394
  * Takes uniform output of 64-byte hash function like sha512 and converts it to `RistrettoPoint`.
394
395
  * The hash-to-group operation applies Elligator twice and adds the results.
395
396
  * **Note:** this is one-way map, there is no conversion from point to hash.
396
- * https://ristretto.group/formulas/elligator.html
397
+ * Described in [RFC9380](https://www.rfc-editor.org/rfc/rfc9380#appendix-B) and on
398
+ * the [website](https://ristretto.group/formulas/elligator.html).
397
399
  * @param hex 64-byte output of a hash function
398
400
  */
399
401
  static hashToCurve(hex: Hex): RistPoint {
@@ -407,7 +409,7 @@ class RistPoint implements Group<RistPoint> {
407
409
 
408
410
  /**
409
411
  * Converts ristretto-encoded string to ristretto point.
410
- * https://ristretto.group/formulas/decoding.html
412
+ * Described in [RFC9496](https://www.rfc-editor.org/rfc/rfc9496#name-decode).
411
413
  * @param hex Ristretto-encoded 32 bytes. Not every 32-byte string is valid ristretto encoding
412
414
  */
413
415
  static fromHex(hex: Hex): RistPoint {
@@ -444,7 +446,7 @@ class RistPoint implements Group<RistPoint> {
444
446
 
445
447
  /**
446
448
  * Encodes ristretto point to Uint8Array.
447
- * https://ristretto.group/formulas/encoding.html
449
+ * Described in [RFC9496](https://www.rfc-editor.org/rfc/rfc9496#name-encode).
448
450
  */
449
451
  toRawBytes(): Uint8Array {
450
452
  let { ex: x, ey: y, ez: z, et: t } = this.ep;
@@ -482,7 +484,10 @@ class RistPoint implements Group<RistPoint> {
482
484
  return this.toHex();
483
485
  }
484
486
 
485
- // Compare one point to another.
487
+ /**
488
+ * Compares two Ristretto points.
489
+ * Described in [RFC9496](https://www.rfc-editor.org/rfc/rfc9496#name-equals).
490
+ */
486
491
  equals(other: RistPoint): boolean {
487
492
  aristp(other);
488
493
  const { ex: X1, ey: Y1 } = this.ep;
@@ -520,13 +525,21 @@ class RistPoint implements Group<RistPoint> {
520
525
  return new RistPoint(this.ep.negate());
521
526
  }
522
527
  }
528
+
529
+ /**
530
+ * Wrapper over Edwards Point for ristretto255 from
531
+ * [RFC9496](https://www.rfc-editor.org/rfc/rfc9496).
532
+ */
523
533
  export const RistrettoPoint: typeof RistPoint = /* @__PURE__ */ (() => {
524
534
  if (!RistPoint.BASE) RistPoint.BASE = new RistPoint(ed25519.ExtendedPoint.BASE);
525
535
  if (!RistPoint.ZERO) RistPoint.ZERO = new RistPoint(ed25519.ExtendedPoint.ZERO);
526
536
  return RistPoint;
527
537
  })();
528
538
 
529
- // Hashing to ristretto255. https://www.rfc-editor.org/rfc/rfc9380#appendix-B
539
+ /**
540
+ * hash-to-curve for ristretto255.
541
+ * Described in [RFC9380](https://www.rfc-editor.org/rfc/rfc9380#appendix-B).
542
+ */
530
543
  export const hashToRistretto255 = (msg: Uint8Array, options: htfBasicOpts): RistPoint => {
531
544
  const d = options.DST;
532
545
  const DST = typeof d === 'string' ? utf8ToBytes(d) : d;