@noble/curves 2.0.1 → 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 +82 -22
  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 +322 -10
  15. package/abstract/fft.d.ts.map +1 -1
  16. package/abstract/fft.js +154 -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 +125 -14
  59. package/ed25519.d.ts.map +1 -1
  60. package/ed25519.js +202 -40
  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 +11 -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 +350 -67
  82. package/src/abstract/curve.ts +327 -44
  83. package/src/abstract/edwards.ts +367 -143
  84. package/src/abstract/fft.ts +369 -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 +227 -55
  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,9 +257,10 @@ 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
 
@@ -199,7 +277,8 @@ export function _map_to_curve_elligator2_curve25519(u: bigint): {
199
277
 
200
278
  let tv1 = Fp.sqr(u); // 1. tv1 = u^2
201
279
  tv1 = Fp.mul(tv1, _2n); // 2. tv1 = 2 * tv1
202
- 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);
203
282
  let x1n = Fp.neg(ELL2_J); // 4. x1n = -J # x1 = x1n / xd = -J / (1 + 2 * u^2)
204
283
  let tv2 = Fp.sqr(xd); // 5. tv2 = xd^2
205
284
  let gxd = Fp.mul(tv2, xd); // 6. gxd = tv2 * xd # gxd = xd^3
@@ -218,7 +297,8 @@ export function _map_to_curve_elligator2_curve25519(u: bigint): {
218
297
  tv2 = Fp.sqr(y11); // 19. tv2 = y11^2
219
298
  tv2 = Fp.mul(tv2, gxd); // 20. tv2 = tv2 * gxd
220
299
  let e1 = Fp.eql(tv2, gx1); // 21. e1 = tv2 == gx1
221
- 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);
222
302
  let x2n = Fp.mul(x1n, tv1); // 23. x2n = x1n * tv1 # x2 = x2n / xd = 2 * u^2 * x1n / xd
223
303
  let y21 = Fp.mul(y11, u); // 24. y21 = y11 * u
224
304
  y21 = Fp.mul(y21, ELL2_C2); // 25. y21 = y21 * c2
@@ -227,7 +307,8 @@ export function _map_to_curve_elligator2_curve25519(u: bigint): {
227
307
  tv2 = Fp.sqr(y21); // 28. tv2 = y21^2
228
308
  tv2 = Fp.mul(tv2, gxd); // 29. tv2 = tv2 * gxd
229
309
  let e2 = Fp.eql(tv2, gx2); // 30. e2 = tv2 == gx2
230
- 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);
231
312
  tv2 = Fp.sqr(y1); // 32. tv2 = y1^2
232
313
  tv2 = Fp.mul(tv2, gxd); // 33. tv2 = tv2 * gxd
233
314
  let e3 = Fp.eql(tv2, gx1); // 34. e3 = tv2 == gx1
@@ -238,15 +319,18 @@ export function _map_to_curve_elligator2_curve25519(u: bigint): {
238
319
  return { xMn: xn, xMd: xd, yMn: y, yMd: _1n }; // 39. return (xn, xd, y, 1)
239
320
  }
240
321
 
241
- 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))))();
242
324
  function map_to_curve_elligator2_edwards25519(u: bigint) {
243
- 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);
244
327
  // map_to_curve_elligator2_curve25519(u)
245
328
  let xn = Fp.mul(xMn, yMd); // 2. xn = xMn * yMd
246
329
  xn = Fp.mul(xn, ELL2_C1_EDWARDS); // 3. xn = xn * c1
247
330
  let xd = Fp.mul(xMd, yMn); // 4. xd = xMd * yMn # xn / xd = c1 * xM / yM
248
331
  let yn = Fp.sub(xMn, xMd); // 5. yn = xMn - xMd
249
- 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);
250
334
  let tv1 = Fp.mul(xd, yd); // 7. tv1 = xd * yd
251
335
  let e = Fp.eql(tv1, Fp.ZERO); // 8. e = tv1 == 0
252
336
  xn = Fp.cmov(xn, Fp.ZERO, e); // 9. xn = CMOV(xn, 0, e)
@@ -254,10 +338,22 @@ function map_to_curve_elligator2_edwards25519(u: bigint) {
254
338
  yn = Fp.cmov(yn, Fp.ONE, e); // 11. yn = CMOV(yn, 1, e)
255
339
  yd = Fp.cmov(yd, Fp.ONE, e); // 12. yd = CMOV(yd, 1, e)
256
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.
257
343
  return { x: Fp.mul(xn, xd_inv), y: Fp.mul(yn, yd_inv) }; // 13. return (xn, xd, yn, yd)
258
344
  }
259
345
 
260
- /** 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
+ */
261
357
  export const ed25519_hasher: H2CHasher<EdwardsPointCons> = /* @__PURE__ */ (() =>
262
358
  createHasher(
263
359
  ed25519_Point,
@@ -291,18 +387,23 @@ const ONE_MINUS_D_SQ = /* @__PURE__ */ BigInt(
291
387
  const D_MINUS_ONE_SQ = /* @__PURE__ */ BigInt(
292
388
  '40440834346308536858101042469323190826248399146238708352240133220865137265952'
293
389
  );
294
- // 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.
295
392
  const invertSqrt = (number: bigint) => uvRatio(_1n, number);
296
393
 
297
394
  const MAX_255B = /* @__PURE__ */ BigInt(
298
395
  '0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
299
396
  );
300
- 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);
301
401
 
302
402
  /**
303
403
  * Computes Elligator map for Ristretto255.
304
- * Described in [RFC9380](https://www.rfc-editor.org/rfc/rfc9380#appendix-B) and on
305
- * 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`.
306
407
  */
307
408
  function calcElligatorRistrettoMap(r0: bigint): EdwardsPoint {
308
409
  const { d } = ed25519_CURVE;
@@ -355,6 +456,12 @@ class _RistrettoPoint extends PrimeEdwardsPoint<_RistrettoPoint> {
355
456
  super(ep);
356
457
  }
357
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
+ */
358
465
  static fromAffine(ap: AffinePoint<bigint>): _RistrettoPoint {
359
466
  return new _RistrettoPoint(ed25519_Point.fromAffine(ap));
360
467
  }
@@ -367,7 +474,7 @@ class _RistrettoPoint extends PrimeEdwardsPoint<_RistrettoPoint> {
367
474
  return new _RistrettoPoint(ep);
368
475
  }
369
476
 
370
- static fromBytes(bytes: Uint8Array): _RistrettoPoint {
477
+ static fromBytes(bytes: TArg<Uint8Array>): _RistrettoPoint {
371
478
  abytes(bytes, 32);
372
479
  const { a, d } = ed25519_CURVE;
373
480
  const P = ed25519_CURVE_p;
@@ -398,7 +505,7 @@ class _RistrettoPoint extends PrimeEdwardsPoint<_RistrettoPoint> {
398
505
  /**
399
506
  * Converts ristretto-encoded string to ristretto point.
400
507
  * Described in [RFC9496](https://www.rfc-editor.org/rfc/rfc9496#name-decode).
401
- * @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
402
509
  */
403
510
  static fromHex(hex: string): _RistrettoPoint {
404
511
  return _RistrettoPoint.fromBytes(hexToBytes(hex));
@@ -408,7 +515,7 @@ class _RistrettoPoint extends PrimeEdwardsPoint<_RistrettoPoint> {
408
515
  * Encodes ristretto point to Uint8Array.
409
516
  * Described in [RFC9496](https://www.rfc-editor.org/rfc/rfc9496#name-encode).
410
517
  */
411
- toBytes(): Uint8Array {
518
+ toBytes(): TRet<Uint8Array> {
412
519
  let { X, Y, Z, T } = this.ep;
413
520
  const P = ed25519_CURVE_p;
414
521
  const mod = (n: bigint) => Fp.create(n);
@@ -433,7 +540,7 @@ class _RistrettoPoint extends PrimeEdwardsPoint<_RistrettoPoint> {
433
540
  if (isNegativeLE(X * zInv, P)) Y = mod(-Y); // 9
434
541
  let s = mod((Z - Y) * D); // 10 (check footer's note, no sqrt(-a))
435
542
  if (isNegativeLE(s, P)) s = mod(-s);
436
- return Fp.toBytes(s); // 11
543
+ return Fp.toBytes(s) as TRet<Uint8Array>; // 11
437
544
  }
438
545
 
439
546
  /**
@@ -455,13 +562,29 @@ class _RistrettoPoint extends PrimeEdwardsPoint<_RistrettoPoint> {
455
562
  return this.equals(_RistrettoPoint.ZERO);
456
563
  }
457
564
  }
565
+ Object.freeze(_RistrettoPoint.BASE);
566
+ Object.freeze(_RistrettoPoint.ZERO);
567
+ Object.freeze(_RistrettoPoint.prototype);
568
+ Object.freeze(_RistrettoPoint);
458
569
 
570
+ /** Prime-order Ristretto255 group bundle. */
459
571
  export const ristretto255: {
460
572
  Point: typeof _RistrettoPoint;
461
- } = { Point: _RistrettoPoint };
573
+ } = /* @__PURE__ */ Object.freeze({ Point: _RistrettoPoint });
462
574
 
463
- /** Hashing to ristretto255 points / field. RFC 9380 methods. */
464
- 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({
465
588
  Point: _RistrettoPoint,
466
589
  /**
467
590
  * Spec: https://www.rfc-editor.org/rfc/rfc9380.html#name-hashing-to-ristretto255. Caveats:
@@ -472,18 +595,23 @@ export const ristretto255_hasher: H2CHasherBase<typeof _RistrettoPoint> = {
472
595
  * * We cannot re-use 'createHasher', because ristretto255_map is different algorithm/RFC
473
596
  (os2ip -> bytes255ToNumberLE)
474
597
  * * mapToCurve == calcElligatorRistrettoMap, hashToCurve == ristretto255_map
475
- * * 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
476
601
  * * current version is closest to spec.
477
602
  */
478
- hashToCurve(msg: Uint8Array, options?: H2CDSTOpts): _RistrettoPoint {
603
+ hashToCurve(msg: TArg<Uint8Array>, options?: TArg<H2CDSTOpts>): _RistrettoPoint {
479
604
  // == 'hash_to_ristretto255'
480
- 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;
481
607
  const xmd = expand_message_xmd(msg, DST, 64, sha512);
482
- // NOTE: RFC 9380 incorrectly calls this function 'ristretto255_map', in RFC 9496 map was function inside (per point)
483
- // 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.
484
612
  return ristretto255_hasher.deriveToCurve!(xmd);
485
613
  },
486
- hashToScalar(msg: Uint8Array, options: H2CDSTOpts = { DST: _DST_scalar }) {
614
+ hashToScalar(msg: TArg<Uint8Array>, options: TArg<H2CDSTOpts> = { DST: _DST_scalar }) {
487
615
  const xmd = expand_message_xmd(msg, options.DST, 64, sha512);
488
616
  return Fn.create(bytesToNumberLE(xmd));
489
617
  },
@@ -491,10 +619,12 @@ export const ristretto255_hasher: H2CHasherBase<typeof _RistrettoPoint> = {
491
619
  * HashToCurve-like construction based on RFC 9496 (Element Derivation).
492
620
  * Converts 64 uniform random bytes into a curve point.
493
621
  *
494
- * WARNING: This represents an older hash-to-curve construction, preceding the finalization of RFC 9380.
495
- * 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.
496
626
  */
497
- deriveToCurve(bytes: Uint8Array): _RistrettoPoint {
627
+ deriveToCurve(bytes: TArg<Uint8Array>): _RistrettoPoint {
498
628
  // https://www.rfc-editor.org/rfc/rfc9496.html#name-element-derivation
499
629
  abytes(bytes, 64);
500
630
  const r1 = bytes255ToNumberLE(bytes.subarray(0, 32));
@@ -503,25 +633,67 @@ export const ristretto255_hasher: H2CHasherBase<typeof _RistrettoPoint> = {
503
633
  const R2 = calcElligatorRistrettoMap(r2);
504
634
  return new _RistrettoPoint(R1.add(R2));
505
635
  },
506
- };
636
+ });
507
637
 
508
- /** ristretto255 OPRF, defined in RFC 9497. */
509
- export const ristretto255_oprf: OPRF = /* @__PURE__ */ (() =>
510
- 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({
511
653
  name: 'ristretto255-SHA512',
512
654
  Point: _RistrettoPoint,
513
655
  hash: sha512,
514
656
  hashToGroup: ristretto255_hasher.hashToCurve,
515
657
  hashToScalar: ristretto255_hasher.hashToScalar,
516
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
+ }))();
517
681
 
518
682
  /**
519
683
  * Weird / bogus points, useful for debugging.
520
684
  * All 8 ed25519 points of 8-torsion subgroup can be generated from the point
521
685
  * T = `26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05`.
522
- * 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
+ * ```
523
695
  */
524
- export const ED25519_TORSION_SUBGROUP: string[] = [
696
+ export const ED25519_TORSION_SUBGROUP: readonly string[] = /* @__PURE__ */ Object.freeze([
525
697
  '0100000000000000000000000000000000000000000000000000000000000000',
526
698
  'c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a',
527
699
  '0000000000000000000000000000000000000000000000000000000000000080',
@@ -530,4 +702,4 @@ export const ED25519_TORSION_SUBGROUP: string[] = [
530
702
  '26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85',
531
703
  '0000000000000000000000000000000000000000000000000000000000000000',
532
704
  'c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa',
533
- ];
705
+ ]);