@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/ed448.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Edwards448 (not Ed448-Goldilocks) curve with following addons:
2
+ * Edwards448 (also called Goldilocks) curve with following addons:
3
3
  * - X448 ECDH
4
4
  * - Decaf cofactor elimination
5
5
  * - Elligator hash-to-group / point indistinguishability
@@ -20,6 +20,7 @@ import {
20
20
  type EdwardsPoint,
21
21
  type EdwardsPointCons,
22
22
  } from './abstract/edwards.ts';
23
+ import { createFROST, type FROST } from './abstract/frost.ts';
23
24
  import {
24
25
  _DST_scalar,
25
26
  createHasher,
@@ -30,8 +31,15 @@ import {
30
31
  } from './abstract/hash-to-curve.ts';
31
32
  import { Field, FpInvertBatch, isNegativeLE, mod, pow2, type IField } from './abstract/modular.ts';
32
33
  import { montgomery, type MontgomeryECDH } from './abstract/montgomery.ts';
33
- import { createORPF, type OPRF } from './abstract/oprf.ts';
34
- import { abytes, asciiToBytes, bytesToNumberLE, equalBytes } from './utils.ts';
34
+ import { createOPRF, type OPRF } from './abstract/oprf.ts';
35
+ import {
36
+ abytes,
37
+ asciiToBytes,
38
+ bytesToNumberLE,
39
+ equalBytes,
40
+ type TArg,
41
+ type TRet,
42
+ } from './utils.ts';
35
43
 
36
44
  // edwards448 curve
37
45
  // a = 1n
@@ -39,7 +47,7 @@ import { abytes, asciiToBytes, bytesToNumberLE, equalBytes } from './utils.ts';
39
47
  // Finite field 2n**448n - 2n**224n - 1n
40
48
  // Subgroup order
41
49
  // 2n**446n - 13818066809895115352007386748515426880336692474882178609894547503885n
42
- const ed448_CURVE_p = BigInt(
50
+ const ed448_CURVE_p = /* @__PURE__ */ BigInt(
43
51
  '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
44
52
  );
45
53
  const ed448_CURVE: EdwardsOpts = /* @__PURE__ */ (() => ({
@@ -60,9 +68,14 @@ const ed448_CURVE: EdwardsOpts = /* @__PURE__ */ (() => ({
60
68
  ),
61
69
  }))();
62
70
 
63
- // E448 NIST curve is identical to edwards448, except for:
64
- // d = 39082/39081
65
- // Gx = 3/2
71
+ // This is not RFC 8032 edwards448 / Goldilocks (`ed448` below, d = -39081).
72
+ // It is NIST SP 800-186 §3.2.3.3 E448, the Curve448-isomorphic Edwards model
73
+ // also described in draft-ietf-lwig-curve-representations-23 Appendix M, with
74
+ // d = 39082/39081 and Gy = 3/2.
75
+ // RFC 7748's literal Edwards point / birational map are wrong here: the literal
76
+ // point is the wrong-sign (Gx, -Gy) order-2*n variant. Keep the corrected
77
+ // prime-order (Gx, Gy) base so Point.BASE stays a subgroup generator, which is
78
+ // what noble's generic Edwards API expects.
66
79
  const E448_CURVE: EdwardsOpts = /* @__PURE__ */ (() =>
67
80
  Object.assign({}, ed448_CURVE, {
68
81
  d: BigInt(
@@ -80,9 +93,9 @@ const shake256_114 = /* @__PURE__ */ wrapConstructor(() => shake256.create({ dkL
80
93
  const shake256_64 = /* @__PURE__ */ wrapConstructor(() => shake256.create({ dkLen: 64 }));
81
94
 
82
95
  // prettier-ignore
83
- const _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3), _4n = /* @__PURE__ */ BigInt(4), _11n = BigInt(11);
96
+ const _1n = /* @__PURE__ */ BigInt(1), _2n = /* @__PURE__ */ BigInt(2), _3n = /* @__PURE__ */ BigInt(3), _4n = /* @__PURE__ */ BigInt(4), _11n = /* @__PURE__ */ BigInt(11);
84
97
  // prettier-ignore
85
- const _22n = BigInt(22), _44n = BigInt(44), _88n = BigInt(88), _223n = BigInt(223);
98
+ const _22n = /* @__PURE__ */ BigInt(22), _44n = /* @__PURE__ */ BigInt(44), _88n = /* @__PURE__ */ BigInt(88), _223n = /* @__PURE__ */ BigInt(223);
86
99
 
87
100
  // powPminus3div4 calculates z = x^k mod p, where k = (p-3)/4.
88
101
  // Used for efficient square root calculation.
@@ -104,18 +117,21 @@ function ed448_pow_Pminus3div4(x: bigint): bigint {
104
117
  return (pow2(b223, _223n, P) * b222) % P;
105
118
  }
106
119
 
107
- function adjustScalarBytes(bytes: Uint8Array): Uint8Array {
120
+ // Mutates and returns the provided buffer in place. The final `bytes[56] = 0`
121
+ // write is the Ed448 path; for 56-byte X448 inputs it is an out-of-bounds no-op.
122
+ function adjustScalarBytes(bytes: TArg<Uint8Array>): TRet<Uint8Array> {
108
123
  // Section 5: Likewise, for X448, set the two least significant bits of the first byte to 0,
109
124
  bytes[0] &= 252; // 0b11111100
110
125
  // and the most significant bit of the last byte to 1.
111
126
  bytes[55] |= 128; // 0b10000000
112
127
  // NOTE: is NOOP for 56 bytes scalars (X25519/X448)
113
128
  bytes[56] = 0; // Byte outside of group (456 buts vs 448 bits)
114
- return bytes;
129
+ return bytes as TRet<Uint8Array>;
115
130
  }
116
131
 
117
- // Constant-time ratio of u to v. Allows to combine inversion and square root u/√v.
118
- // Uses algo from RFC8032 5.1.3.
132
+ // Constant-time Ed448 decode helper for RFC 8032 §5.2.3 steps 2-3. Unlike
133
+ // `SQRT_RATIO_M1`, the returned `value` only has the documented meaning when
134
+ // `isValid` is true.
119
135
  function uvRatio(u: bigint, v: bigint): { isValid: boolean; value: bigint } {
120
136
  const P = ed448_CURVE_p;
121
137
  // https://www.rfc-editor.org/rfc/rfc8032#section-5.2.3
@@ -137,34 +153,50 @@ function uvRatio(u: bigint, v: bigint): { isValid: boolean; value: bigint } {
137
153
  }
138
154
 
139
155
  // Finite field 2n**448n - 2n**224n - 1n
140
- // The value fits in 448 bits, but we use 456-bit (57-byte) elements because of bitflags.
141
- // - ed25519 fits in 255 bits, allowing using last 1 byte for specifying bit flag of point negation.
142
- // - ed448 fits in 448 bits. We can't use last 1 byte: we can only use a bit 224 in the middle.
156
+ // RFC 8032 encodes Ed448 field/scalar elements in 57 bytes even though field
157
+ // values fit in 448 bits and scalars in 446 bits. Noble models that with a
158
+ // 456-bit storage width so the final-octet x-sign bit (bit 455) still fits in
159
+ // the shared little-endian container.
143
160
  const Fp = /* @__PURE__ */ (() => Field(ed448_CURVE_p, { BITS: 456, isLE: true }))();
161
+ // Same 57-byte container shape as `Fp`; canonical scalar encodings still have
162
+ // the top ten bits clear per RFC 8032.
144
163
  const Fn = /* @__PURE__ */ (() => Field(ed448_CURVE.n, { BITS: 456, isLE: true }))();
145
- // decaf448 uses 448-bit (56-byte) keys
164
+ // Generic 56-byte field shape used by decaf448 and raw X448 u-coordinates.
165
+ // Plain `Field` decoding stays canonical here, so callers that want RFC 7748's
166
+ // modulo-p acceptance must reduce externally.
146
167
  const Fp448 = /* @__PURE__ */ (() => Field(ed448_CURVE_p, { BITS: 448, isLE: true }))();
168
+ // Strict 56-byte scalar parser matching RFC 9496's recommended canonical form.
147
169
  const Fn448 = /* @__PURE__ */ (() => Field(ed448_CURVE.n, { BITS: 448, isLE: true }))();
148
170
 
149
171
  // SHAKE256(dom4(phflag,context)||x, 114)
150
- function dom4(data: Uint8Array, ctx: Uint8Array, phflag: boolean) {
172
+ // RFC 8032 `dom4` prefix. Empty contexts are valid; the accepted length range
173
+ // is 0..255 octets inclusive.
174
+ function dom4(data: TArg<Uint8Array>, ctx: TArg<Uint8Array>, phflag: boolean): TRet<Uint8Array> {
151
175
  if (ctx.length > 255) throw new Error('context must be smaller than 255, got: ' + ctx.length);
152
176
  return concatBytes(
153
177
  asciiToBytes('SigEd448'),
154
178
  new Uint8Array([phflag ? 1 : 0, ctx.length]),
155
179
  ctx,
156
180
  data
157
- );
181
+ ) as TRet<Uint8Array>;
158
182
  }
159
183
  const ed448_Point = /* @__PURE__ */ edwards(ed448_CURVE, { Fp, Fn, uvRatio });
160
184
 
161
- function ed4(opts: EdDSAOpts) {
162
- return eddsa(ed448_Point, shake256_114, Object.assign({ adjustScalarBytes, domain: dom4 }, opts));
185
+ // Shared internal factory for both `ed448` and `ed448ph`; callers are only
186
+ // expected to override narrow family options such as prehashing.
187
+ function ed4(opts: TArg<EdDSAOpts>) {
188
+ return eddsa(
189
+ ed448_Point,
190
+ shake256_114,
191
+ Object.assign({ adjustScalarBytes, domain: dom4 }, opts as EdDSAOpts)
192
+ );
163
193
  }
164
194
 
165
195
  /**
166
196
  * ed448 EdDSA curve and methods.
167
197
  * @example
198
+ * Generate one Ed448 keypair, sign a message, and verify it.
199
+ *
168
200
  * ```js
169
201
  * import { ed448 } from '@noble/curves/ed448.js';
170
202
  * const { secretKey, publicKey } = ed448.keygen();
@@ -177,18 +209,47 @@ function ed4(opts: EdDSAOpts) {
177
209
  export const ed448: EdDSA = /* @__PURE__ */ ed4({});
178
210
 
179
211
  // There is no ed448ctx, since ed448 supports ctx by default
180
- /** Prehashed version of ed448. See {@link ed448} */
212
+ /**
213
+ * Prehashed version of ed448. See {@link ed448}
214
+ * @example
215
+ * Use the prehashed Ed448 variant for one message.
216
+ *
217
+ * ```ts
218
+ * const { secretKey, publicKey } = ed448ph.keygen();
219
+ * const msg = new TextEncoder().encode('hello noble');
220
+ * const sig = ed448ph.sign(msg, secretKey);
221
+ * const isValid = ed448ph.verify(sig, msg, publicKey);
222
+ * ```
223
+ */
181
224
  export const ed448ph: EdDSA = /* @__PURE__ */ ed4({ prehash: shake256_64 });
182
225
  /**
183
- * E448 (NIST) != edwards448 used in ed448.
184
- * E448 is birationally equivalent to edwards448.
226
+ * E448 here is NIST SP 800-186 §3.2.3.3 E448, the Edwards representation of
227
+ * Curve448, not RFC 8032 edwards448 / Goldilocks.
228
+ * Goldilocks is the separate 4-isogenous curve exposed as `ed448`.
229
+ * We keep the corrected prime-order base here; RFC 7748's literal Edwards
230
+ * point / map are wrong for this curve model, and the literal point is the
231
+ * wrong-sign order-2*n variant.
232
+ * @param X - Projective X coordinate.
233
+ * @param Y - Projective Y coordinate.
234
+ * @param Z - Projective Z coordinate.
235
+ * @param T - Projective T coordinate.
236
+ * @example
237
+ * Multiply the E448 base point.
238
+ *
239
+ * ```ts
240
+ * const point = E448.BASE.multiply(2n);
241
+ * ```
185
242
  */
186
243
  export const E448: EdwardsPointCons = /* @__PURE__ */ edwards(E448_CURVE);
187
244
 
188
245
  /**
189
246
  * ECDH using curve448 aka x448.
247
+ * The wrapper aborts on all-zero shared secrets by default, and seeded
248
+ * `keygen(seed)` reuses the provided 56-byte seed buffer instead of copying it.
190
249
  *
191
250
  * @example
251
+ * Derive one shared secret between two X448 peers.
252
+ *
192
253
  * ```js
193
254
  * import { x448 } from '@noble/curves/ed448.js';
194
255
  * const alice = x448.keygen();
@@ -196,7 +257,7 @@ export const E448: EdwardsPointCons = /* @__PURE__ */ edwards(E448_CURVE);
196
257
  * const shared = x448.getSharedSecret(alice.secretKey, bob.publicKey);
197
258
  * ```
198
259
  */
199
- export const x448: MontgomeryECDH = /* @__PURE__ */ (() => {
260
+ export const x448: TRet<MontgomeryECDH> = /* @__PURE__ */ (() => {
200
261
  const P = ed448_CURVE_p;
201
262
  return montgomery({
202
263
  P,
@@ -211,9 +272,12 @@ export const x448: MontgomeryECDH = /* @__PURE__ */ (() => {
211
272
  })();
212
273
 
213
274
  // Hash To Curve Elligator2 Map
214
- const ELL2_C1 = /* @__PURE__ */ (() => (ed448_CURVE_p - BigInt(3)) / BigInt(4))(); // 1. c1 = (q - 3) / 4 # Integer arithmetic
275
+ // 1. c1 = (q - 3) / 4 # Integer arithmetic
276
+ const ELL2_C1 = /* @__PURE__ */ (() => (ed448_CURVE_p - BigInt(3)) / BigInt(4))();
215
277
  const ELL2_J = /* @__PURE__ */ BigInt(156326);
216
278
 
279
+ // Returns RFC 9380 Appendix G.2.3 rational Montgomery numerators/denominators
280
+ // `{ xn, xd, yn, yd }`, not an affine point.
217
281
  function map_to_curve_elligator2_curve448(u: bigint) {
218
282
  let tv1 = Fp.sqr(u); // 1. tv1 = u^2
219
283
  let e1 = Fp.eql(tv1, Fp.ONE); // 2. e1 = tv1 == 1
@@ -231,7 +295,8 @@ function map_to_curve_elligator2_curve448(u: bigint) {
231
295
  tv3 = Fp.mul(tv3, tv2); // 14. tv3 = tv3 * tv2 # gx1 * gxd^3
232
296
  let y1 = Fp.pow(tv3, ELL2_C1); // 15. y1 = tv3^c1 # (gx1 * gxd^3)^((p - 3) / 4)
233
297
  y1 = Fp.mul(y1, tv2); // 16. y1 = y1 * tv2 # gx1 * gxd * (gx1 * gxd^3)^((p - 3) / 4)
234
- let x2n = Fp.mul(x1n, Fp.neg(tv1)); // 17. x2n = -tv1 * x1n # x2 = x2n / xd = -1 * u^2 * x1n / xd
298
+ // 17. x2n = -tv1 * x1n # x2 = x2n / xd = -1 * u^2 * x1n / xd
299
+ let x2n = Fp.mul(x1n, Fp.neg(tv1));
235
300
  let y2 = Fp.mul(y1, u); // 18. y2 = y1 * u
236
301
  y2 = Fp.cmov(y2, Fp.ZERO, e1); // 19. y2 = CMOV(y2, 0, e1)
237
302
  tv2 = Fp.sqr(y1); // 20. tv2 = y1^2
@@ -244,8 +309,10 @@ function map_to_curve_elligator2_curve448(u: bigint) {
244
309
  return { xn, xd, yn: y, yd: Fp.ONE }; // 27. return (xn, xd, y, 1)
245
310
  }
246
311
 
312
+ // Returns affine `{ x, y }` after inverting the Appendix G.2.4 denominators.
247
313
  function map_to_curve_elligator2_edwards448(u: bigint) {
248
- let { xn, xd, yn, yd } = map_to_curve_elligator2_curve448(u); // 1. (xn, xd, yn, yd) = map_to_curve_elligator2_curve448(u)
314
+ // 1. (xn, xd, yn, yd) = map_to_curve_elligator2_curve448(u)
315
+ let { xn, xd, yn, yd } = map_to_curve_elligator2_curve448(u);
249
316
  let xn2 = Fp.sqr(xn); // 2. xn2 = xn^2
250
317
  let xd2 = Fp.sqr(xd); // 3. xd2 = xd^2
251
318
  let xd4 = Fp.sqr(xd2); // 4. xd4 = xd2^2
@@ -287,7 +354,18 @@ function map_to_curve_elligator2_edwards448(u: bigint) {
287
354
  return { x: Fp.mul(xEn, inv[0]), y: Fp.mul(yEn, inv[1]) }; // 38. return (xEn, xEd, yEn, yEd)
288
355
  }
289
356
 
290
- /** Hashing / encoding to ed448 points / field. RFC 9380 methods. */
357
+ /**
358
+ * Hashing / encoding to ed448 points / field. RFC 9380 methods.
359
+ * Public `mapToCurve()` consumes one field element bigint for `m = 1`, and RFC
360
+ * Appendix J vectors use the special `QUUX-V01-*` test DST overrides rather
361
+ * than the default suite IDs below.
362
+ * @example
363
+ * Hash one message onto the ed448 curve.
364
+ *
365
+ * ```ts
366
+ * const point = ed448_hasher.hashToCurve(new TextEncoder().encode('hello noble'));
367
+ * ```
368
+ */
291
369
  export const ed448_hasher: H2CHasher<EdwardsPointCons> = /* @__PURE__ */ (() =>
292
370
  createHasher(ed448_Point, (scalars: bigint[]) => map_to_curve_elligator2_edwards448(scalars[0]), {
293
371
  DST: 'edwards448_XOF:SHAKE256_ELL2_RO_',
@@ -298,6 +376,32 @@ export const ed448_hasher: H2CHasher<EdwardsPointCons> = /* @__PURE__ */ (() =>
298
376
  expand: 'xof',
299
377
  hash: shake256,
300
378
  }))();
379
+ /**
380
+ * FROST threshold signatures over ed448. RFC 9591.
381
+ * @example
382
+ * Create one trusted-dealer package for 2-of-3 ed448 signing.
383
+ *
384
+ * ```ts
385
+ * const alice = ed448_FROST.Identifier.derive('alice@example.com');
386
+ * const bob = ed448_FROST.Identifier.derive('bob@example.com');
387
+ * const carol = ed448_FROST.Identifier.derive('carol@example.com');
388
+ * const deal = ed448_FROST.trustedDealer({ min: 2, max: 3 }, [alice, bob, carol]);
389
+ * ```
390
+ */
391
+ export const ed448_FROST: TRet<FROST> = /* @__PURE__ */ (() =>
392
+ createFROST({
393
+ name: 'FROST-ED448-SHAKE256-v1',
394
+ Point: ed448_Point,
395
+ validatePoint: (p) => {
396
+ p.assertValidity();
397
+ if (!p.isTorsionFree()) throw new Error('bad point: not torsion-free');
398
+ },
399
+ // Group: edwards448 [RFC8032], where Ne = 57 and Ns = 57.
400
+ // Fn is 57 bytes, Fp is 57 bytes too
401
+ Fn,
402
+ hash: shake256_114,
403
+ H2: 'SigEd448\0\0',
404
+ }))();
301
405
 
302
406
  // 1-d
303
407
  const ONE_MINUS_D = /* @__PURE__ */ BigInt('39082');
@@ -311,13 +415,22 @@ const SQRT_MINUS_D = /* @__PURE__ */ BigInt(
311
415
  const INVSQRT_MINUS_D = /* @__PURE__ */ BigInt(
312
416
  '315019913931389607337177038330951043522456072897266928557328499619017160722351061360252776265186336876723201881398623946864393857820716'
313
417
  );
314
- // Calculates 1/√(number)
315
- const invertSqrt = (number: bigint) => uvRatio(_1n, number);
418
+ // RFC 9496 `SQRT_RATIO_M1` must return `CT_ABS(s)`, i.e. the nonnegative root.
419
+ // Keep this Decaf-local: RFC 9496 decode/encode/map formulas depend on that
420
+ // canonical representative, while ordinary Ed448 decoding still uses `uvRatio()`
421
+ // plus the public sign bit from RFC 8032.
422
+ const sqrtRatioM1 = (u: bigint, v: bigint) => {
423
+ const P = ed448_CURVE_p;
424
+ const { isValid, value } = uvRatio(u, v);
425
+ return { isValid, value: isNegativeLE(value, P) ? Fp448.create(-value) : value };
426
+ };
427
+ const invertSqrt = (number: bigint) => sqrtRatioM1(_1n, number);
316
428
 
317
429
  /**
318
430
  * Elligator map for hash-to-curve of decaf448.
319
- * Described in [RFC9380](https://www.rfc-editor.org/rfc/rfc9380#appendix-C)
320
- * and [RFC9496](https://www.rfc-editor.org/rfc/rfc9496#name-element-derivation-2).
431
+ * Primary formula source is RFC 9496 §5.3.4. Step 1 intentionally reduces the
432
+ * input modulo `p`, and the return value is the internal Edwards
433
+ * representation, not a public decaf encoding.
321
434
  */
322
435
  function calcElligatorDecafMap(r0: bigint): EdwardsPoint {
323
436
  const { d, p: P } = ed448_CURVE;
@@ -327,7 +440,7 @@ function calcElligatorDecafMap(r0: bigint): EdwardsPoint {
327
440
  const u0 = mod(d * (r - _1n)); // 2
328
441
  const u1 = mod((u0 + _1n) * (u0 - r)); // 3
329
442
 
330
- const { isValid: was_square, value: v } = uvRatio(ONE_MINUS_TWO_D, mod((r + _1n) * u1)); // 4
443
+ const { isValid: was_square, value: v } = sqrtRatioM1(ONE_MINUS_TWO_D, mod((r + _1n) * u1)); // 4
331
444
 
332
445
  let v_prime = v; // 5
333
446
  if (!was_square) v_prime = mod(r0 * v);
@@ -347,6 +460,19 @@ function calcElligatorDecafMap(r0: bigint): EdwardsPoint {
347
460
  return new ed448_Point(mod(W0 * W3), mod(W2 * W1), mod(W1 * W3), mod(W0 * W2));
348
461
  }
349
462
 
463
+ // Keep the Decaf448 base representative literal here: deriving it with
464
+ // `new _DecafPoint(ed448_Point.BASE).multiplyUnsafe(2)` forces eager WNAF precomputes and
465
+ // adds about 100ms to `ed448.js` import time.
466
+ const DECAF_BASE_X = /* @__PURE__ */ BigInt(
467
+ '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa955555555555555555555555555555555555555555555555555555555'
468
+ );
469
+ const DECAF_BASE_Y = /* @__PURE__ */ BigInt(
470
+ '0xae05e9634ad7048db359d6205086c2b0036ed7a035884dd7b7e36d728ad8c4b80d6565833a2a3098bbbcb2bed1cda06bdaeafbcdea9386ed'
471
+ );
472
+ const DECAF_BASE_T = /* @__PURE__ */ BigInt(
473
+ '0x696d84643374bace9d70983a12aa9d461da74d2d5c35e8d97ba72c3aba4450a5d29274229bd22c1d5e3a6474ee4ffb0e7a9e200a28eee402'
474
+ );
475
+
350
476
  /**
351
477
  * Each ed448/EdwardsPoint has 4 different equivalent points. This can be
352
478
  * a source of bugs for protocols like ring signatures. Decaf was created to solve this.
@@ -358,7 +484,7 @@ class _DecafPoint extends PrimeEdwardsPoint<_DecafPoint> {
358
484
  // The following gymnastics is done because typescript strips comments otherwise
359
485
  // prettier-ignore
360
486
  static BASE: _DecafPoint =
361
- /* @__PURE__ */ (() => new _DecafPoint(ed448_Point.BASE).multiplyUnsafe(_2n))();
487
+ /* @__PURE__ */ (() => new _DecafPoint(new ed448_Point(DECAF_BASE_X, DECAF_BASE_Y, _1n, DECAF_BASE_T)))();
362
488
  // prettier-ignore
363
489
  static ZERO: _DecafPoint =
364
490
  /* @__PURE__ */ (() => new _DecafPoint(ed448_Point.ZERO))();
@@ -373,6 +499,12 @@ class _DecafPoint extends PrimeEdwardsPoint<_DecafPoint> {
373
499
  super(ep);
374
500
  }
375
501
 
502
+ /**
503
+ * Create one Decaf448 point from affine Edwards coordinates.
504
+ * This wraps the internal Edwards representative directly and is not a
505
+ * canonical decaf448 decoding path.
506
+ * Use `toBytes()` / `fromBytes()` if canonical decaf448 bytes matter.
507
+ */
376
508
  static fromAffine(ap: AffinePoint<bigint>): _DecafPoint {
377
509
  return new _DecafPoint(ed448_Point.fromAffine(ap));
378
510
  }
@@ -385,7 +517,7 @@ class _DecafPoint extends PrimeEdwardsPoint<_DecafPoint> {
385
517
  return new _DecafPoint(ep);
386
518
  }
387
519
 
388
- static fromBytes(bytes: Uint8Array): _DecafPoint {
520
+ static fromBytes(bytes: TArg<Uint8Array>): _DecafPoint {
389
521
  abytes(bytes, 56);
390
522
  const { d, p: P } = ed448_CURVE;
391
523
  const mod = (n: bigint) => Fp448.create(n);
@@ -417,7 +549,7 @@ class _DecafPoint extends PrimeEdwardsPoint<_DecafPoint> {
417
549
  /**
418
550
  * Converts decaf-encoded string to decaf point.
419
551
  * Described in [RFC9496](https://www.rfc-editor.org/rfc/rfc9496#name-decode-2).
420
- * @param hex Decaf-encoded 56 bytes. Not every 56-byte string is valid decaf encoding
552
+ * @param hex - Decaf-encoded 56 bytes. Not every 56-byte string is valid decaf encoding
421
553
  */
422
554
  static fromHex(hex: string): _DecafPoint {
423
555
  return _DecafPoint.fromBytes(hexToBytes(hex));
@@ -427,7 +559,7 @@ class _DecafPoint extends PrimeEdwardsPoint<_DecafPoint> {
427
559
  * Encodes decaf point to Uint8Array.
428
560
  * Described in [RFC9496](https://www.rfc-editor.org/rfc/rfc9496#name-encode-2).
429
561
  */
430
- toBytes(): Uint8Array {
562
+ toBytes(): TRet<Uint8Array> {
431
563
  const { X, Z, T } = this.ep;
432
564
  const P = ed448_CURVE.p;
433
565
  const mod = (n: bigint) => Fp448.create(n);
@@ -439,7 +571,7 @@ class _DecafPoint extends PrimeEdwardsPoint<_DecafPoint> {
439
571
  const u2 = mod(INVSQRT_MINUS_D * ratio * Z - T); // 4
440
572
  let s = mod(ONE_MINUS_D * invsqrt * X * u2); // 5
441
573
  if (isNegativeLE(s, P)) s = mod(-s);
442
- return Fn448.toBytes(s);
574
+ return Fn448.toBytes(s) as TRet<Uint8Array>;
443
575
  }
444
576
 
445
577
  /**
@@ -458,16 +590,33 @@ class _DecafPoint extends PrimeEdwardsPoint<_DecafPoint> {
458
590
  return this.equals(_DecafPoint.ZERO);
459
591
  }
460
592
  }
593
+ Object.freeze(_DecafPoint.BASE);
594
+ Object.freeze(_DecafPoint.ZERO);
595
+ Object.freeze(_DecafPoint.prototype);
596
+ Object.freeze(_DecafPoint);
461
597
 
598
+ /** Prime-order Decaf448 group bundle. */
462
599
  export const decaf448: {
463
600
  Point: typeof _DecafPoint;
464
- } = { Point: _DecafPoint };
601
+ } = /* @__PURE__ */ Object.freeze({ Point: _DecafPoint });
465
602
 
466
- /** Hashing to decaf448 points / field. RFC 9380 methods. */
467
- export const decaf448_hasher: H2CHasherBase<typeof _DecafPoint> = {
603
+ /**
604
+ * Hashing to decaf448 points / field. RFC 9380 methods.
605
+ * `hashToCurve()` is RFC 9380 `hash_to_decaf448`, `deriveToCurve()` is RFC
606
+ * 9496 element derivation, and `hashToScalar()` is a library helper layered on
607
+ * top of RFC 9496 scalar reduction.
608
+ * @example
609
+ * Hash one message onto decaf448.
610
+ *
611
+ * ```ts
612
+ * const point = decaf448_hasher.hashToCurve(new TextEncoder().encode('hello noble'));
613
+ * ```
614
+ */
615
+ export const decaf448_hasher: H2CHasherBase<typeof _DecafPoint> = Object.freeze({
468
616
  Point: _DecafPoint,
469
- hashToCurve(msg: Uint8Array, options?: H2CDSTOpts): _DecafPoint {
470
- const DST = options?.DST || 'decaf448_XOF:SHAKE256_D448MAP_RO_';
617
+ hashToCurve(msg: TArg<Uint8Array>, options?: TArg<H2CDSTOpts>): _DecafPoint {
618
+ // Preserve explicit empty/invalid DST overrides so expand_message_xof() can reject them.
619
+ const DST = options?.DST === undefined ? 'decaf448_XOF:SHAKE256_D448MAP_RO_' : options.DST;
471
620
  return decaf448_hasher.deriveToCurve!(expand_message_xof(msg, DST, 112, 224, shake256));
472
621
  },
473
622
  /**
@@ -475,7 +624,7 @@ export const decaf448_hasher: H2CHasherBase<typeof _DecafPoint> = {
475
624
  * RFC is invalid. RFC says "use 64-byte xof", while for 2^-112 bias
476
625
  * it must use 84-byte xof (56+56/2), not 64.
477
626
  */
478
- hashToScalar(msg: Uint8Array, options: H2CDSTOpts = { DST: _DST_scalar }): bigint {
627
+ hashToScalar(msg: TArg<Uint8Array>, options: TArg<H2CDSTOpts> = { DST: _DST_scalar }): bigint {
479
628
  // Can't use `Fn448.fromBytes()`. 64-byte input => 56-byte field element
480
629
  const xof = expand_message_xof(msg, options.DST, 64, 256, shake256);
481
630
  return Fn448.create(bytesToNumberLE(xof));
@@ -484,10 +633,12 @@ export const decaf448_hasher: H2CHasherBase<typeof _DecafPoint> = {
484
633
  * HashToCurve-like construction based on RFC 9496 (Element Derivation).
485
634
  * Converts 112 uniform random bytes into a curve point.
486
635
  *
487
- * WARNING: This represents an older hash-to-curve construction, preceding the finalization of RFC 9380.
488
- * It was later reused as a component in the newer `hash_to_ristretto255` function defined in RFC 9380.
636
+ * WARNING: This represents an older hash-to-curve construction from before
637
+ * RFC 9380 was finalized.
638
+ * It was later reused as a component in the newer
639
+ * `hash_to_decaf448` function defined in RFC 9380.
489
640
  */
490
- deriveToCurve(bytes: Uint8Array): _DecafPoint {
641
+ deriveToCurve(bytes: TArg<Uint8Array>): _DecafPoint {
491
642
  abytes(bytes, 112);
492
643
  const skipValidation = true;
493
644
  // Note: Similar to the field element decoding described in
@@ -499,14 +650,26 @@ export const decaf448_hasher: H2CHasherBase<typeof _DecafPoint> = {
499
650
  const R2 = calcElligatorDecafMap(r2);
500
651
  return new _DecafPoint(R1.add(R2));
501
652
  },
502
- };
653
+ });
503
654
 
504
- /** decaf448 OPRF, defined in RFC 9497. */
505
- export const decaf448_oprf: OPRF = /* @__PURE__ */ (() =>
506
- createORPF({
655
+ /**
656
+ * decaf448 OPRF, defined in RFC 9497.
657
+ * @example
658
+ * Run one blind/evaluate/finalize OPRF round over decaf448.
659
+ *
660
+ * ```ts
661
+ * const input = new TextEncoder().encode('hello noble');
662
+ * const keys = decaf448_oprf.oprf.generateKeyPair();
663
+ * const blind = decaf448_oprf.oprf.blind(input);
664
+ * const evaluated = decaf448_oprf.oprf.blindEvaluate(keys.secretKey, blind.blinded);
665
+ * const output = decaf448_oprf.oprf.finalize(input, blind.blind, evaluated);
666
+ * ```
667
+ */
668
+ export const decaf448_oprf: TRet<OPRF> = /* @__PURE__ */ (() =>
669
+ createOPRF({
507
670
  name: 'decaf448-SHAKE256',
508
671
  Point: _DecafPoint,
509
- hash: (msg: Uint8Array) => shake256(msg, { dkLen: 64 }),
672
+ hash: (msg: TArg<Uint8Array>) => shake256(msg, { dkLen: 64 }),
510
673
  hashToGroup: decaf448_hasher.hashToCurve,
511
674
  hashToScalar: decaf448_hasher.hashToScalar,
512
675
  }))();
@@ -514,12 +677,19 @@ export const decaf448_oprf: OPRF = /* @__PURE__ */ (() =>
514
677
  /**
515
678
  * Weird / bogus points, useful for debugging.
516
679
  * Unlike ed25519, there is no ed448 generator point which can produce full T subgroup.
517
- * Instead, there is a Klein four-group, which spans over 2 independent 2-torsion points:
518
- * (0, 1), (0, -1), (-1, 0), (1, 0).
680
+ * Instead, the torsion subgroup here is cyclic of order 4, generated by
681
+ * `(1, 0)`, and the array below lists that subgroup set (Klein four-group).
682
+ * @example
683
+ * Decode one known torsion point for debugging.
684
+ *
685
+ * ```ts
686
+ * import { ED448_TORSION_SUBGROUP, ed448 } from '@noble/curves/ed448.js';
687
+ * const point = ed448.Point.fromHex(ED448_TORSION_SUBGROUP[1]);
688
+ * ```
519
689
  */
520
- export const ED448_TORSION_SUBGROUP: string[] = [
690
+ export const ED448_TORSION_SUBGROUP: readonly string[] = /* @__PURE__ */ Object.freeze([
521
691
  '010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
522
692
  'fefffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffff00',
523
693
  '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
524
694
  '000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080',
525
- ];
695
+ ]);
package/src/index.ts CHANGED
@@ -9,7 +9,13 @@ import { ed448, ed448ph, x448, decaf448 } from '@noble/curves/ed448.js';
9
9
  import { p256, p384, p521 } from '@noble/curves/nist.js';
10
10
  import { bls12_381 } from '@noble/curves/bls12-381.js';
11
11
  import { bn254 } from '@noble/curves/bn254.js';
12
- import { jubjub, babyjubjub, brainpoolP256r1, brainpoolP384r1, brainpoolP512r1 } from '@noble/curves/misc.js';
12
+ import {
13
+ jubjub,
14
+ babyjubjub,
15
+ brainpoolP256r1,
16
+ brainpoolP384r1,
17
+ brainpoolP512r1,
18
+ } from '@noble/curves/misc.js';
13
19
  import * as webcrypto from '@noble/curves/webcrypto.js';
14
20
 
15
21
  // hash-to-curve