@noble/curves 2.0.0 → 2.2.0

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 (110) hide show
  1. package/README.md +214 -122
  2. package/abstract/bls.d.ts +299 -16
  3. package/abstract/bls.d.ts.map +1 -1
  4. package/abstract/bls.js +89 -24
  5. package/abstract/bls.js.map +1 -1
  6. package/abstract/curve.d.ts +274 -27
  7. package/abstract/curve.d.ts.map +1 -1
  8. package/abstract/curve.js +177 -23
  9. package/abstract/curve.js.map +1 -1
  10. package/abstract/edwards.d.ts +166 -30
  11. package/abstract/edwards.d.ts.map +1 -1
  12. package/abstract/edwards.js +221 -86
  13. package/abstract/edwards.js.map +1 -1
  14. package/abstract/fft.d.ts +327 -10
  15. package/abstract/fft.d.ts.map +1 -1
  16. package/abstract/fft.js +155 -12
  17. package/abstract/fft.js.map +1 -1
  18. package/abstract/frost.d.ts +293 -0
  19. package/abstract/frost.d.ts.map +1 -0
  20. package/abstract/frost.js +704 -0
  21. package/abstract/frost.js.map +1 -0
  22. package/abstract/hash-to-curve.d.ts +173 -24
  23. package/abstract/hash-to-curve.d.ts.map +1 -1
  24. package/abstract/hash-to-curve.js +170 -31
  25. package/abstract/hash-to-curve.js.map +1 -1
  26. package/abstract/modular.d.ts +429 -37
  27. package/abstract/modular.d.ts.map +1 -1
  28. package/abstract/modular.js +414 -119
  29. package/abstract/modular.js.map +1 -1
  30. package/abstract/montgomery.d.ts +83 -12
  31. package/abstract/montgomery.d.ts.map +1 -1
  32. package/abstract/montgomery.js +32 -7
  33. package/abstract/montgomery.js.map +1 -1
  34. package/abstract/oprf.d.ts +164 -91
  35. package/abstract/oprf.d.ts.map +1 -1
  36. package/abstract/oprf.js +88 -29
  37. package/abstract/oprf.js.map +1 -1
  38. package/abstract/poseidon.d.ts +138 -7
  39. package/abstract/poseidon.d.ts.map +1 -1
  40. package/abstract/poseidon.js +178 -15
  41. package/abstract/poseidon.js.map +1 -1
  42. package/abstract/tower.d.ts +122 -3
  43. package/abstract/tower.d.ts.map +1 -1
  44. package/abstract/tower.js +323 -139
  45. package/abstract/tower.js.map +1 -1
  46. package/abstract/weierstrass.d.ts +339 -76
  47. package/abstract/weierstrass.d.ts.map +1 -1
  48. package/abstract/weierstrass.js +395 -205
  49. package/abstract/weierstrass.js.map +1 -1
  50. package/bls12-381.d.ts +16 -2
  51. package/bls12-381.d.ts.map +1 -1
  52. package/bls12-381.js +199 -209
  53. package/bls12-381.js.map +1 -1
  54. package/bn254.d.ts +11 -2
  55. package/bn254.d.ts.map +1 -1
  56. package/bn254.js +93 -38
  57. package/bn254.js.map +1 -1
  58. package/ed25519.d.ts +135 -14
  59. package/ed25519.d.ts.map +1 -1
  60. package/ed25519.js +207 -41
  61. package/ed25519.js.map +1 -1
  62. package/ed448.d.ts +108 -14
  63. package/ed448.d.ts.map +1 -1
  64. package/ed448.js +194 -42
  65. package/ed448.js.map +1 -1
  66. package/index.js +7 -1
  67. package/index.js.map +1 -1
  68. package/misc.d.ts +106 -7
  69. package/misc.d.ts.map +1 -1
  70. package/misc.js +141 -32
  71. package/misc.js.map +1 -1
  72. package/nist.d.ts +112 -11
  73. package/nist.d.ts.map +1 -1
  74. package/nist.js +139 -17
  75. package/nist.js.map +1 -1
  76. package/package.json +34 -6
  77. package/secp256k1.d.ts +92 -15
  78. package/secp256k1.d.ts.map +1 -1
  79. package/secp256k1.js +211 -28
  80. package/secp256k1.js.map +1 -1
  81. package/src/abstract/bls.ts +356 -69
  82. package/src/abstract/curve.ts +327 -44
  83. package/src/abstract/edwards.ts +367 -143
  84. package/src/abstract/fft.ts +371 -36
  85. package/src/abstract/frost.ts +1092 -0
  86. package/src/abstract/hash-to-curve.ts +255 -56
  87. package/src/abstract/modular.ts +591 -144
  88. package/src/abstract/montgomery.ts +114 -30
  89. package/src/abstract/oprf.ts +383 -194
  90. package/src/abstract/poseidon.ts +235 -35
  91. package/src/abstract/tower.ts +428 -159
  92. package/src/abstract/weierstrass.ts +710 -312
  93. package/src/bls12-381.ts +239 -236
  94. package/src/bn254.ts +107 -46
  95. package/src/ed25519.ts +234 -56
  96. package/src/ed448.ts +227 -57
  97. package/src/index.ts +7 -1
  98. package/src/misc.ts +154 -35
  99. package/src/nist.ts +143 -20
  100. package/src/secp256k1.ts +284 -41
  101. package/src/utils.ts +583 -81
  102. package/src/webcrypto.ts +302 -73
  103. package/utils.d.ts +457 -24
  104. package/utils.d.ts.map +1 -1
  105. package/utils.js +410 -53
  106. package/utils.js.map +1 -1
  107. package/webcrypto.d.ts +167 -25
  108. package/webcrypto.d.ts.map +1 -1
  109. package/webcrypto.js +165 -58
  110. package/webcrypto.js.map +1 -1
package/src/ed25519.ts CHANGED
@@ -19,6 +19,7 @@ import {
19
19
  type EdwardsPoint,
20
20
  type EdwardsPointCons,
21
21
  } from './abstract/edwards.ts';
22
+ import { createFROST, type FROST } from './abstract/frost.ts';
22
23
  import {
23
24
  _DST_scalar,
24
25
  createHasher,
@@ -36,16 +37,16 @@ import {
36
37
  type IField,
37
38
  } from './abstract/modular.ts';
38
39
  import { montgomery, type MontgomeryECDH } from './abstract/montgomery.ts';
39
- import { createORPF, type OPRF } from './abstract/oprf.ts';
40
- import { asciiToBytes, bytesToNumberLE, equalBytes } from './utils.ts';
40
+ import { createOPRF, type OPRF } from './abstract/oprf.ts';
41
+ import { asciiToBytes, bytesToNumberLE, equalBytes, type TArg, type TRet } from './utils.ts';
41
42
 
42
43
  // prettier-ignore
43
- const _0n = /* @__PURE__ */ BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = /* @__PURE__ */ BigInt(3);
44
+ const _0n = /* @__PURE__ */ BigInt(0), _1n = /* @__PURE__ */ BigInt(1), _2n = /* @__PURE__ */ BigInt(2), _3n = /* @__PURE__ */ BigInt(3);
44
45
  // prettier-ignore
45
- const _5n = BigInt(5), _8n = BigInt(8);
46
+ const _5n = /* @__PURE__ */ BigInt(5), _8n = /* @__PURE__ */ BigInt(8);
46
47
 
47
48
  // P = 2n**255n - 19n
48
- const ed25519_CURVE_p = BigInt(
49
+ const ed25519_CURVE_p = /* @__PURE__ */ BigInt(
49
50
  '0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed'
50
51
  );
51
52
  // N = 2n**252n + 27742317777372353535851937790883648493n
@@ -77,11 +78,12 @@ function ed25519_pow_2_252_3(x: bigint) {
77
78
  const b240 = (pow2(b160, _80n, P) * b80) % P;
78
79
  const b250 = (pow2(b240, _10n, P) * b10) % P;
79
80
  const pow_p_5_8 = (pow2(b250, _2n, P) * x) % P;
80
- // ^ To pow to (p+3)/8, multiply it by x.
81
+ // ^ This is x^((p-5)/8); multiply by x once more to get x^((p+3)/8).
81
82
  return { pow_p_5_8, b2 };
82
83
  }
83
84
 
84
- function adjustScalarBytes(bytes: Uint8Array): Uint8Array {
85
+ // Mutates and returns the provided 32-byte buffer in place.
86
+ function adjustScalarBytes(bytes: TArg<Uint8Array>): TRet<Uint8Array> {
85
87
  // Section 5: For X25519, in order to decode 32 random bytes as an integer scalar,
86
88
  // set the three least significant bits of the first byte
87
89
  bytes[0] &= 248; // 0b1111_1000
@@ -89,7 +91,7 @@ function adjustScalarBytes(bytes: Uint8Array): Uint8Array {
89
91
  bytes[31] &= 127; // 0b0111_1111
90
92
  // set the second most significant bit of the last byte to 1
91
93
  bytes[31] |= 64; // 0b0100_0000
92
- return bytes;
94
+ return bytes as TRet<Uint8Array>;
93
95
  }
94
96
 
95
97
  // √(-1) aka √(a) aka 2^((p-1)/4)
@@ -97,7 +99,8 @@ function adjustScalarBytes(bytes: Uint8Array): Uint8Array {
97
99
  const ED25519_SQRT_M1 = /* @__PURE__ */ BigInt(
98
100
  '19681161376707505956807079304988542015446066515923890162744021073123829784752'
99
101
  );
100
- // sqrt(u/v)
102
+ // sqrt(u/v). Returns `{ isValid, value }`; on non-squares `value` is still a
103
+ // dummy root-shaped field element so callers can stay constant-time.
101
104
  function uvRatio(u: bigint, v: bigint): { isValid: boolean; value: bigint } {
102
105
  const P = ed25519_CURVE_p;
103
106
  const v3 = mod(v * v * v, P); // v³
@@ -118,46 +121,120 @@ function uvRatio(u: bigint, v: bigint): { isValid: boolean; value: bigint } {
118
121
  }
119
122
 
120
123
  const ed25519_Point = /* @__PURE__ */ edwards(ed25519_CURVE, { uvRatio });
124
+ // Public field alias stays stricter than the RFC 8032 Appendix A sample code:
125
+ // `Fp.inv(0)` throws instead of returning `0`.
121
126
  const Fp = /* @__PURE__ */ (() => ed25519_Point.Fp)();
122
127
  const Fn = /* @__PURE__ */ (() => ed25519_Point.Fn)();
123
128
 
124
- function ed25519_domain(data: Uint8Array, ctx: Uint8Array, phflag: boolean) {
129
+ // RFC 8032 `dom2` helper for ctx/ph variants only. Plain Ed25519 keeps the
130
+ // empty-domain path in `ed()` and would be wrong if routed through this helper.
131
+ function ed25519_domain(
132
+ data: TArg<Uint8Array>,
133
+ ctx: TArg<Uint8Array>,
134
+ phflag: boolean
135
+ ): TRet<Uint8Array> {
125
136
  if (ctx.length > 255) throw new Error('Context is too big');
126
137
  return concatBytes(
127
138
  asciiToBytes('SigEd25519 no Ed25519 collisions'),
128
139
  new Uint8Array([phflag ? 1 : 0, ctx.length]),
129
140
  ctx,
130
141
  data
131
- );
142
+ ) as TRet<Uint8Array>;
132
143
  }
133
144
 
134
- function ed(opts: EdDSAOpts) {
135
- return eddsa(ed25519_Point, sha512, Object.assign({ adjustScalarBytes }, opts));
145
+ function ed(opts: TArg<EdDSAOpts>) {
146
+ // Ed25519 keeps ZIP-215 default verification semantics for consensus compatibility.
147
+ return eddsa(
148
+ ed25519_Point,
149
+ sha512,
150
+ Object.assign({ adjustScalarBytes, zip215: true }, opts as EdDSAOpts)
151
+ );
136
152
  }
137
153
 
138
154
  /**
139
155
  * ed25519 curve with EdDSA signatures.
156
+ * Seeded `keygen(seed)` / `utils.randomSecretKey(seed)` reuse the provided
157
+ * 32-byte seed buffer instead of copying it.
140
158
  * @example
159
+ * Generate one Ed25519 keypair, sign a message, and verify it.
160
+ *
141
161
  * ```js
142
162
  * import { ed25519 } from '@noble/curves/ed25519.js';
143
163
  * const { secretKey, publicKey } = ed25519.keygen();
144
164
  * // const publicKey = ed25519.getPublicKey(secretKey);
145
165
  * const msg = new TextEncoder().encode('hello noble');
146
166
  * const sig = ed25519.sign(msg, secretKey);
147
- * const isValid = ed25519.verify(sig, msg, pub); // ZIP215
167
+ * const isValid = ed25519.verify(sig, msg, publicKey); // ZIP215
148
168
  * // RFC8032 / FIPS 186-5
149
- * const isValid2 = ed25519.verify(sig, msg, pub, { zip215: false });
169
+ * const isValid2 = ed25519.verify(sig, msg, publicKey, { zip215: false });
150
170
  * ```
151
171
  */
152
172
  export const ed25519: EdDSA = /* @__PURE__ */ ed({});
153
- /** Context version of ed25519 (ctx for domain separation). See {@link ed25519} */
173
+ /**
174
+ * Context version of ed25519 (ctx for domain separation). See {@link ed25519}
175
+ * Seeded `keygen(seed)` / `utils.randomSecretKey(seed)` reuse the provided
176
+ * 32-byte seed buffer instead of copying it.
177
+ * @example
178
+ * Sign and verify with Ed25519ctx under one explicit context.
179
+ *
180
+ * ```ts
181
+ * const context = new TextEncoder().encode('docs');
182
+ * const { secretKey, publicKey } = ed25519ctx.keygen();
183
+ * const msg = new TextEncoder().encode('hello noble');
184
+ * const sig = ed25519ctx.sign(msg, secretKey, { context });
185
+ * const isValid = ed25519ctx.verify(sig, msg, publicKey, { context });
186
+ * ```
187
+ */
154
188
  export const ed25519ctx: EdDSA = /* @__PURE__ */ ed({ domain: ed25519_domain });
155
- /** Prehashed version of ed25519. See {@link ed25519} */
189
+ /**
190
+ * Prehashed version of ed25519. See {@link ed25519}
191
+ * Seeded `keygen(seed)` / `utils.randomSecretKey(seed)` reuse the provided
192
+ * 32-byte seed buffer instead of copying it.
193
+ * @example
194
+ * Use the prehashed Ed25519 variant for one message.
195
+ *
196
+ * ```ts
197
+ * const { secretKey, publicKey } = ed25519ph.keygen();
198
+ * const msg = new TextEncoder().encode('hello noble');
199
+ * const sig = ed25519ph.sign(msg, secretKey);
200
+ * const isValid = ed25519ph.verify(sig, msg, publicKey);
201
+ * ```
202
+ */
156
203
  export const ed25519ph: EdDSA = /* @__PURE__ */ ed({ domain: ed25519_domain, prehash: sha512 });
204
+ /**
205
+ * FROST threshold signatures over ed25519. RFC 9591.
206
+ * @example
207
+ * Create one trusted-dealer package for 2-of-3 ed25519 signing.
208
+ *
209
+ * ```ts
210
+ * const alice = ed25519_FROST.Identifier.derive('alice@example.com');
211
+ * const bob = ed25519_FROST.Identifier.derive('bob@example.com');
212
+ * const carol = ed25519_FROST.Identifier.derive('carol@example.com');
213
+ * const deal = ed25519_FROST.trustedDealer({ min: 2, max: 3 }, [alice, bob, carol]);
214
+ * ```
215
+ */
216
+ export const ed25519_FROST: TRet<FROST> = /* @__PURE__ */ (() =>
217
+ createFROST({
218
+ name: 'FROST-ED25519-SHA512-v1',
219
+ Point: ed25519_Point,
220
+ validatePoint: (p) => {
221
+ p.assertValidity();
222
+ if (!p.isTorsionFree()) throw new Error('bad point: not torsion-free');
223
+ },
224
+ hash: sha512,
225
+ // RFC 9591 keeps H2 undecorated here for RFC 8032 compatibility. In createFROST(),
226
+ // `H2: ''` becomes an empty DST prefix; the built-in hashToScalar fallback treats
227
+ // that the same as omitted DST, even though custom hooks can still observe the empty bag.
228
+ H2: '',
229
+ }))();
157
230
 
158
231
  /**
159
232
  * ECDH using curve25519 aka x25519.
233
+ * `getSharedSecret()` rejects low-order peer inputs by default, and seeded
234
+ * `keygen(seed)` reuses the provided 32-byte seed buffer instead of copying it.
160
235
  * @example
236
+ * Derive one shared secret between two X25519 peers.
237
+ *
161
238
  * ```js
162
239
  * import { x25519 } from '@noble/curves/ed25519.js';
163
240
  * const alice = x25519.keygen();
@@ -165,7 +242,7 @@ export const ed25519ph: EdDSA = /* @__PURE__ */ ed({ domain: ed25519_domain, pre
165
242
  * const shared = x25519.getSharedSecret(alice.secretKey, bob.publicKey);
166
243
  * ```
167
244
  */
168
- export const x25519: MontgomeryECDH = /* @__PURE__ */ (() => {
245
+ export const x25519: TRet<MontgomeryECDH> = /* @__PURE__ */ (() => {
169
246
  const P = ed25519_CURVE_p;
170
247
  return montgomery({
171
248
  P,
@@ -180,20 +257,28 @@ export const x25519: MontgomeryECDH = /* @__PURE__ */ (() => {
180
257
  })();
181
258
 
182
259
  // Hash To Curve Elligator2 Map (NOTE: different from ristretto255 elligator)
183
- // NOTE: very important part is usage of FpSqrtEven for ELL2_C1_EDWARDS, since
184
- // SageMath returns different root first and everything falls apart
185
- const ELL2_C1 = /* @__PURE__ */ (() => (ed25519_CURVE_p + _3n) / _8n)(); // 1. c1 = (q + 3) / 8 # Integer arithmetic
260
+ // RFC 9380 Appendix G.2.2 / Err4730 requires `sgn0(c1) = 0` for the Edwards
261
+ // map constant below, so use the even root explicitly.
262
+ // 1. c1 = (q + 3) / 8 # Integer arithmetic
263
+ const ELL2_C1 = /* @__PURE__ */ (() => (ed25519_CURVE_p + _3n) / _8n)();
186
264
  const ELL2_C2 = /* @__PURE__ */ (() => Fp.pow(_2n, ELL2_C1))(); // 2. c2 = 2^c1
187
265
  const ELL2_C3 = /* @__PURE__ */ (() => Fp.sqrt(Fp.neg(Fp.ONE)))(); // 3. c3 = sqrt(-1)
188
266
 
267
+ /**
268
+ * RFC 9380 method `map_to_curve_elligator2_curve25519`. Experimental name: may be renamed later.
269
+ * @private
270
+ */
189
271
  // prettier-ignore
190
- function map_to_curve_elligator2_curve25519(u: bigint) {
272
+ export function _map_to_curve_elligator2_curve25519(u: bigint): {
273
+ xMn: bigint, xMd: bigint, yMn: bigint, yMd: bigint
274
+ } {
191
275
  const ELL2_C4 = (ed25519_CURVE_p - _5n) / _8n; // 4. c4 = (q - 5) / 8 # Integer arithmetic
192
276
  const ELL2_J = BigInt(486662);
193
277
 
194
278
  let tv1 = Fp.sqr(u); // 1. tv1 = u^2
195
279
  tv1 = Fp.mul(tv1, _2n); // 2. tv1 = 2 * tv1
196
- let xd = Fp.add(tv1, Fp.ONE); // 3. xd = tv1 + 1 # Nonzero: -1 is square (mod p), tv1 is not
280
+ // 3. xd = tv1 + 1 # Nonzero: -1 is square (mod p), tv1 is not
281
+ let xd = Fp.add(tv1, Fp.ONE);
197
282
  let x1n = Fp.neg(ELL2_J); // 4. x1n = -J # x1 = x1n / xd = -J / (1 + 2 * u^2)
198
283
  let tv2 = Fp.sqr(xd); // 5. tv2 = xd^2
199
284
  let gxd = Fp.mul(tv2, xd); // 6. gxd = tv2 * xd # gxd = xd^3
@@ -212,7 +297,8 @@ function map_to_curve_elligator2_curve25519(u: bigint) {
212
297
  tv2 = Fp.sqr(y11); // 19. tv2 = y11^2
213
298
  tv2 = Fp.mul(tv2, gxd); // 20. tv2 = tv2 * gxd
214
299
  let e1 = Fp.eql(tv2, gx1); // 21. e1 = tv2 == gx1
215
- let y1 = Fp.cmov(y12, y11, e1); // 22. y1 = CMOV(y12, y11, e1) # If g(x1) is square, this is its sqrt
300
+ // 22. y1 = CMOV(y12, y11, e1) # If g(x1) is square, this is its sqrt
301
+ let y1 = Fp.cmov(y12, y11, e1);
216
302
  let x2n = Fp.mul(x1n, tv1); // 23. x2n = x1n * tv1 # x2 = x2n / xd = 2 * u^2 * x1n / xd
217
303
  let y21 = Fp.mul(y11, u); // 24. y21 = y11 * u
218
304
  y21 = Fp.mul(y21, ELL2_C2); // 25. y21 = y21 * c2
@@ -221,7 +307,8 @@ function map_to_curve_elligator2_curve25519(u: bigint) {
221
307
  tv2 = Fp.sqr(y21); // 28. tv2 = y21^2
222
308
  tv2 = Fp.mul(tv2, gxd); // 29. tv2 = tv2 * gxd
223
309
  let e2 = Fp.eql(tv2, gx2); // 30. e2 = tv2 == gx2
224
- let y2 = Fp.cmov(y22, y21, e2); // 31. y2 = CMOV(y22, y21, e2) # If g(x2) is square, this is its sqrt
310
+ // 31. y2 = CMOV(y22, y21, e2) # If g(x2) is square, this is its sqrt
311
+ let y2 = Fp.cmov(y22, y21, e2);
225
312
  tv2 = Fp.sqr(y1); // 32. tv2 = y1^2
226
313
  tv2 = Fp.mul(tv2, gxd); // 33. tv2 = tv2 * gxd
227
314
  let e3 = Fp.eql(tv2, gx1); // 34. e3 = tv2 == gx1
@@ -232,15 +319,18 @@ function map_to_curve_elligator2_curve25519(u: bigint) {
232
319
  return { xMn: xn, xMd: xd, yMn: y, yMd: _1n }; // 39. return (xn, xd, y, 1)
233
320
  }
234
321
 
235
- const ELL2_C1_EDWARDS = /* @__PURE__ */ (() => FpSqrtEven(Fp, Fp.neg(BigInt(486664))))(); // sgn0(c1) MUST equal 0
322
+ // sgn0(c1) MUST equal 0
323
+ const ELL2_C1_EDWARDS = /* @__PURE__ */ (() => FpSqrtEven(Fp, Fp.neg(BigInt(486664))))();
236
324
  function map_to_curve_elligator2_edwards25519(u: bigint) {
237
- const { xMn, xMd, yMn, yMd } = map_to_curve_elligator2_curve25519(u); // 1. (xMn, xMd, yMn, yMd) =
325
+ // 1. (xMn, xMd, yMn, yMd) = map_to_curve_elligator2_curve25519(u)
326
+ const { xMn, xMd, yMn, yMd } = _map_to_curve_elligator2_curve25519(u);
238
327
  // map_to_curve_elligator2_curve25519(u)
239
328
  let xn = Fp.mul(xMn, yMd); // 2. xn = xMn * yMd
240
329
  xn = Fp.mul(xn, ELL2_C1_EDWARDS); // 3. xn = xn * c1
241
330
  let xd = Fp.mul(xMd, yMn); // 4. xd = xMd * yMn # xn / xd = c1 * xM / yM
242
331
  let yn = Fp.sub(xMn, xMd); // 5. yn = xMn - xMd
243
- let yd = Fp.add(xMn, xMd); // 6. yd = xMn + xMd # (n / d - 1) / (n / d + 1) = (n - d) / (n + d)
332
+ // 6. yd = xMn + xMd # (n / d - 1) / (n / d + 1) = (n - d) / (n + d)
333
+ let yd = Fp.add(xMn, xMd);
244
334
  let tv1 = Fp.mul(xd, yd); // 7. tv1 = xd * yd
245
335
  let e = Fp.eql(tv1, Fp.ZERO); // 8. e = tv1 == 0
246
336
  xn = Fp.cmov(xn, Fp.ZERO, e); // 9. xn = CMOV(xn, 0, e)
@@ -248,10 +338,22 @@ function map_to_curve_elligator2_edwards25519(u: bigint) {
248
338
  yn = Fp.cmov(yn, Fp.ONE, e); // 11. yn = CMOV(yn, 1, e)
249
339
  yd = Fp.cmov(yd, Fp.ONE, e); // 12. yd = CMOV(yd, 1, e)
250
340
  const [xd_inv, yd_inv] = FpInvertBatch(Fp, [xd, yd], true); // batch division
341
+ // Noble normalizes the RFC rational representation to affine `{ x, y }`
342
+ // before returning from the internal helper.
251
343
  return { x: Fp.mul(xn, xd_inv), y: Fp.mul(yn, yd_inv) }; // 13. return (xn, xd, yn, yd)
252
344
  }
253
345
 
254
- /** Hashing to ed25519 points / field. RFC 9380 methods. */
346
+ /**
347
+ * Hashing to ed25519 points / field. RFC 9380 methods.
348
+ * Public `mapToCurve()` returns the cofactor-cleared subgroup point; the
349
+ * internal map callback below consumes one field element bigint, not `[bigint]`.
350
+ * @example
351
+ * Hash one message onto the ed25519 curve.
352
+ *
353
+ * ```ts
354
+ * const point = ed25519_hasher.hashToCurve(new TextEncoder().encode('hello noble'));
355
+ * ```
356
+ */
255
357
  export const ed25519_hasher: H2CHasher<EdwardsPointCons> = /* @__PURE__ */ (() =>
256
358
  createHasher(
257
359
  ed25519_Point,
@@ -285,18 +387,23 @@ const ONE_MINUS_D_SQ = /* @__PURE__ */ BigInt(
285
387
  const D_MINUS_ONE_SQ = /* @__PURE__ */ BigInt(
286
388
  '40440834346308536858101042469323190826248399146238708352240133220865137265952'
287
389
  );
288
- // Calculates 1/√(number)
390
+ // `SQRT_RATIO_M1(1, number)` specialization. Returns `{ isValid, value }`,
391
+ // where non-squares get the nonnegative `sqrt(SQRT_M1 / number)` branch.
289
392
  const invertSqrt = (number: bigint) => uvRatio(_1n, number);
290
393
 
291
394
  const MAX_255B = /* @__PURE__ */ BigInt(
292
395
  '0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
293
396
  );
294
- const bytes255ToNumberLE = (bytes: Uint8Array) => Fp.create(bytesToNumberLE(bytes) & MAX_255B);
397
+ // RFC 9496 §4.3.4 MAP parser: masks bit 255 and reduces modulo p for element
398
+ // derivation. The decode path has the opposite contract and rejects that bit.
399
+ const bytes255ToNumberLE = (bytes: TArg<Uint8Array>) =>
400
+ Fp.create(bytesToNumberLE(bytes) & MAX_255B);
295
401
 
296
402
  /**
297
403
  * Computes Elligator map for Ristretto255.
298
- * Described in [RFC9380](https://www.rfc-editor.org/rfc/rfc9380#appendix-B) and on
299
- * the [website](https://ristretto.group/formulas/elligator.html).
404
+ * Primary formula source is RFC 9496 §4.3.4 MAP; RFC 9380 Appendix B builds
405
+ * `hash_to_ristretto255` on top of this helper.
406
+ * Returns an internal Edwards representative, not a public `_RistrettoPoint`.
300
407
  */
301
408
  function calcElligatorRistrettoMap(r0: bigint): EdwardsPoint {
302
409
  const { d } = ed25519_CURVE;
@@ -349,6 +456,12 @@ class _RistrettoPoint extends PrimeEdwardsPoint<_RistrettoPoint> {
349
456
  super(ep);
350
457
  }
351
458
 
459
+ /**
460
+ * Create one Ristretto255 point from affine Edwards coordinates.
461
+ * This wraps the internal Edwards representative directly and is not a
462
+ * canonical ristretto255 decoding path.
463
+ * Use `toBytes()` / `fromBytes()` if canonical ristretto255 bytes matter.
464
+ */
352
465
  static fromAffine(ap: AffinePoint<bigint>): _RistrettoPoint {
353
466
  return new _RistrettoPoint(ed25519_Point.fromAffine(ap));
354
467
  }
@@ -361,7 +474,7 @@ class _RistrettoPoint extends PrimeEdwardsPoint<_RistrettoPoint> {
361
474
  return new _RistrettoPoint(ep);
362
475
  }
363
476
 
364
- static fromBytes(bytes: Uint8Array): _RistrettoPoint {
477
+ static fromBytes(bytes: TArg<Uint8Array>): _RistrettoPoint {
365
478
  abytes(bytes, 32);
366
479
  const { a, d } = ed25519_CURVE;
367
480
  const P = ed25519_CURVE_p;
@@ -392,7 +505,7 @@ class _RistrettoPoint extends PrimeEdwardsPoint<_RistrettoPoint> {
392
505
  /**
393
506
  * Converts ristretto-encoded string to ristretto point.
394
507
  * Described in [RFC9496](https://www.rfc-editor.org/rfc/rfc9496#name-decode).
395
- * @param hex Ristretto-encoded 32 bytes. Not every 32-byte string is valid ristretto encoding
508
+ * @param hex - Ristretto-encoded 32 bytes. Not every 32-byte string is valid ristretto encoding
396
509
  */
397
510
  static fromHex(hex: string): _RistrettoPoint {
398
511
  return _RistrettoPoint.fromBytes(hexToBytes(hex));
@@ -402,7 +515,7 @@ class _RistrettoPoint extends PrimeEdwardsPoint<_RistrettoPoint> {
402
515
  * Encodes ristretto point to Uint8Array.
403
516
  * Described in [RFC9496](https://www.rfc-editor.org/rfc/rfc9496#name-encode).
404
517
  */
405
- toBytes(): Uint8Array {
518
+ toBytes(): TRet<Uint8Array> {
406
519
  let { X, Y, Z, T } = this.ep;
407
520
  const P = ed25519_CURVE_p;
408
521
  const mod = (n: bigint) => Fp.create(n);
@@ -427,7 +540,7 @@ class _RistrettoPoint extends PrimeEdwardsPoint<_RistrettoPoint> {
427
540
  if (isNegativeLE(X * zInv, P)) Y = mod(-Y); // 9
428
541
  let s = mod((Z - Y) * D); // 10 (check footer's note, no sqrt(-a))
429
542
  if (isNegativeLE(s, P)) s = mod(-s);
430
- return Fp.toBytes(s); // 11
543
+ return Fp.toBytes(s) as TRet<Uint8Array>; // 11
431
544
  }
432
545
 
433
546
  /**
@@ -449,13 +562,29 @@ class _RistrettoPoint extends PrimeEdwardsPoint<_RistrettoPoint> {
449
562
  return this.equals(_RistrettoPoint.ZERO);
450
563
  }
451
564
  }
565
+ Object.freeze(_RistrettoPoint.BASE);
566
+ Object.freeze(_RistrettoPoint.ZERO);
567
+ Object.freeze(_RistrettoPoint.prototype);
568
+ Object.freeze(_RistrettoPoint);
452
569
 
570
+ /** Prime-order Ristretto255 group bundle. */
453
571
  export const ristretto255: {
454
572
  Point: typeof _RistrettoPoint;
455
- } = { Point: _RistrettoPoint };
573
+ } = /* @__PURE__ */ Object.freeze({ Point: _RistrettoPoint });
456
574
 
457
- /** Hashing to ristretto255 points / field. RFC 9380 methods. */
458
- export const ristretto255_hasher: H2CHasherBase<typeof _RistrettoPoint> = {
575
+ /**
576
+ * Hashing to ristretto255 points / field. RFC 9380 methods.
577
+ * `hashToCurve()` is RFC 9380 Appendix B, `deriveToCurve()` is the RFC 9496
578
+ * §4.3.4 element-derivation building block, and `hashToScalar()` is a
579
+ * library-specific helper for OPRF-style use.
580
+ * @example
581
+ * Hash one message onto ristretto255.
582
+ *
583
+ * ```ts
584
+ * const point = ristretto255_hasher.hashToCurve(new TextEncoder().encode('hello noble'));
585
+ * ```
586
+ */
587
+ export const ristretto255_hasher: H2CHasherBase<typeof _RistrettoPoint> = Object.freeze({
459
588
  Point: _RistrettoPoint,
460
589
  /**
461
590
  * Spec: https://www.rfc-editor.org/rfc/rfc9380.html#name-hashing-to-ristretto255. Caveats:
@@ -466,18 +595,23 @@ export const ristretto255_hasher: H2CHasherBase<typeof _RistrettoPoint> = {
466
595
  * * We cannot re-use 'createHasher', because ristretto255_map is different algorithm/RFC
467
596
  (os2ip -> bytes255ToNumberLE)
468
597
  * * mapToCurve == calcElligatorRistrettoMap, hashToCurve == ristretto255_map
469
- * * hashToScalar is undefined in RFC9380 for ristretto, we are using version from OPRF here, using bytes255ToNumblerLE will create different result if we use bytes255ToNumberLE as os2ip
598
+ * * hashToScalar is undefined in RFC9380 for ristretto, so we use the OPRF
599
+ version here. Using `bytes255ToNumblerLE` will create a different result
600
+ if we use `bytes255ToNumberLE` as os2ip
470
601
  * * current version is closest to spec.
471
602
  */
472
- hashToCurve(msg: Uint8Array, options?: H2CDSTOpts): _RistrettoPoint {
603
+ hashToCurve(msg: TArg<Uint8Array>, options?: TArg<H2CDSTOpts>): _RistrettoPoint {
473
604
  // == 'hash_to_ristretto255'
474
- const DST = options?.DST || 'ristretto255_XMD:SHA-512_R255MAP_RO_';
605
+ // Preserve explicit empty/invalid DST overrides so expand_message_xmd() can reject them.
606
+ const DST = options?.DST === undefined ? 'ristretto255_XMD:SHA-512_R255MAP_RO_' : options.DST;
475
607
  const xmd = expand_message_xmd(msg, DST, 64, sha512);
476
- // NOTE: RFC 9380 incorrectly calls this function 'ristretto255_map', in RFC 9496 map was function inside (per point)
477
- // That also lead to confustion that ristretto255_map is mapToCurve (it is not! it is old hashToCurve)
608
+ // NOTE: RFC 9380 incorrectly calls this function `ristretto255_map`.
609
+ // In RFC 9496, `map` was the per-point function inside the construction.
610
+ // That also led to confusion that `ristretto255_map` is `mapToCurve`.
611
+ // It is not: it is the older hash-to-curve construction.
478
612
  return ristretto255_hasher.deriveToCurve!(xmd);
479
613
  },
480
- hashToScalar(msg: Uint8Array, options: H2CDSTOpts = { DST: _DST_scalar }) {
614
+ hashToScalar(msg: TArg<Uint8Array>, options: TArg<H2CDSTOpts> = { DST: _DST_scalar }) {
481
615
  const xmd = expand_message_xmd(msg, options.DST, 64, sha512);
482
616
  return Fn.create(bytesToNumberLE(xmd));
483
617
  },
@@ -485,10 +619,12 @@ export const ristretto255_hasher: H2CHasherBase<typeof _RistrettoPoint> = {
485
619
  * HashToCurve-like construction based on RFC 9496 (Element Derivation).
486
620
  * Converts 64 uniform random bytes into a curve point.
487
621
  *
488
- * WARNING: This represents an older hash-to-curve construction, preceding the finalization of RFC 9380.
489
- * It was later reused as a component in the newer `hash_to_ristretto255` function defined in RFC 9380.
622
+ * WARNING: This represents an older hash-to-curve construction from before
623
+ * RFC 9380 was finalized.
624
+ * It was later reused as a component in the newer
625
+ * `hash_to_ristretto255` function defined in RFC 9380.
490
626
  */
491
- deriveToCurve(bytes: Uint8Array): _RistrettoPoint {
627
+ deriveToCurve(bytes: TArg<Uint8Array>): _RistrettoPoint {
492
628
  // https://www.rfc-editor.org/rfc/rfc9496.html#name-element-derivation
493
629
  abytes(bytes, 64);
494
630
  const r1 = bytes255ToNumberLE(bytes.subarray(0, 32));
@@ -497,25 +633,67 @@ export const ristretto255_hasher: H2CHasherBase<typeof _RistrettoPoint> = {
497
633
  const R2 = calcElligatorRistrettoMap(r2);
498
634
  return new _RistrettoPoint(R1.add(R2));
499
635
  },
500
- };
636
+ });
501
637
 
502
- /** ristretto255 OPRF, defined in RFC 9497. */
503
- export const ristretto255_oprf: OPRF = /* @__PURE__ */ (() =>
504
- createORPF({
638
+ /**
639
+ * ristretto255 OPRF/VOPRF/POPRF bundle, defined in RFC 9497.
640
+ * @example
641
+ * Run one blind/evaluate/finalize OPRF round over ristretto255.
642
+ *
643
+ * ```ts
644
+ * const input = new TextEncoder().encode('hello noble');
645
+ * const keys = ristretto255_oprf.oprf.generateKeyPair();
646
+ * const blind = ristretto255_oprf.oprf.blind(input);
647
+ * const evaluated = ristretto255_oprf.oprf.blindEvaluate(keys.secretKey, blind.blinded);
648
+ * const output = ristretto255_oprf.oprf.finalize(input, blind.blind, evaluated);
649
+ * ```
650
+ */
651
+ export const ristretto255_oprf: TRet<OPRF> = /* @__PURE__ */ (() =>
652
+ createOPRF({
505
653
  name: 'ristretto255-SHA512',
506
654
  Point: _RistrettoPoint,
507
655
  hash: sha512,
508
656
  hashToGroup: ristretto255_hasher.hashToCurve,
509
657
  hashToScalar: ristretto255_hasher.hashToScalar,
510
658
  }))();
659
+ /**
660
+ * FROST threshold signatures over ristretto255. RFC 9591.
661
+ * @example
662
+ * Create one trusted-dealer package for 2-of-3 ristretto255 signing.
663
+ *
664
+ * ```ts
665
+ * const alice = ristretto255_FROST.Identifier.derive('alice@example.com');
666
+ * const bob = ristretto255_FROST.Identifier.derive('bob@example.com');
667
+ * const carol = ristretto255_FROST.Identifier.derive('carol@example.com');
668
+ * const deal = ristretto255_FROST.trustedDealer({ min: 2, max: 3 }, [alice, bob, carol]);
669
+ * ```
670
+ */
671
+ export const ristretto255_FROST: TRet<FROST> = /* @__PURE__ */ (() =>
672
+ createFROST({
673
+ name: 'FROST-RISTRETTO255-SHA512-v1',
674
+ Point: _RistrettoPoint,
675
+ validatePoint: (p) => {
676
+ // Prime-order wrappers are torsion-free at the abstract-group level.
677
+ p.assertValidity();
678
+ },
679
+ hash: sha512,
680
+ }))();
511
681
 
512
682
  /**
513
683
  * Weird / bogus points, useful for debugging.
514
684
  * All 8 ed25519 points of 8-torsion subgroup can be generated from the point
515
685
  * T = `26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05`.
516
- * T = { O, T, 2T, 3T, 4T, 5T, 6T, 7T }
686
+ * The subgroup generated by `T` is `{ O, T, 2T, 3T, 4T, 5T, 6T, 7T }`; the
687
+ * array below is that set, not the powers in that exact index order.
688
+ * @example
689
+ * Decode one known torsion point for debugging.
690
+ *
691
+ * ```ts
692
+ * import { ED25519_TORSION_SUBGROUP, ed25519 } from '@noble/curves/ed25519.js';
693
+ * const point = ed25519.Point.fromHex(ED25519_TORSION_SUBGROUP[1]);
694
+ * ```
517
695
  */
518
- export const ED25519_TORSION_SUBGROUP: string[] = [
696
+ export const ED25519_TORSION_SUBGROUP: readonly string[] = /* @__PURE__ */ Object.freeze([
519
697
  '0100000000000000000000000000000000000000000000000000000000000000',
520
698
  'c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a',
521
699
  '0000000000000000000000000000000000000000000000000000000000000080',
@@ -524,4 +702,4 @@ export const ED25519_TORSION_SUBGROUP: string[] = [
524
702
  '26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85',
525
703
  '0000000000000000000000000000000000000000000000000000000000000000',
526
704
  'c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa',
527
- ];
705
+ ]);