@noble/curves 1.1.0 → 1.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 (67) hide show
  1. package/README.md +267 -164
  2. package/abstract/bls.d.ts.map +1 -1
  3. package/abstract/bls.js +2 -2
  4. package/abstract/bls.js.map +1 -1
  5. package/abstract/hash-to-curve.d.ts +1 -1
  6. package/abstract/hash-to-curve.d.ts.map +1 -1
  7. package/abstract/hash-to-curve.js +14 -8
  8. package/abstract/hash-to-curve.js.map +1 -1
  9. package/abstract/modular.d.ts +51 -11
  10. package/abstract/modular.d.ts.map +1 -1
  11. package/abstract/modular.js +79 -21
  12. package/abstract/modular.js.map +1 -1
  13. package/abstract/poseidon.d.ts.map +1 -1
  14. package/abstract/poseidon.js +39 -41
  15. package/abstract/poseidon.js.map +1 -1
  16. package/abstract/utils.d.ts +1 -0
  17. package/abstract/utils.d.ts.map +1 -1
  18. package/abstract/utils.js +2 -1
  19. package/abstract/utils.js.map +1 -1
  20. package/abstract/weierstrass.d.ts +2 -1
  21. package/abstract/weierstrass.d.ts.map +1 -1
  22. package/abstract/weierstrass.js +13 -11
  23. package/abstract/weierstrass.js.map +1 -1
  24. package/bls12-381.d.ts.map +1 -1
  25. package/bls12-381.js +7 -8
  26. package/bls12-381.js.map +1 -1
  27. package/ed25519.d.ts +1 -0
  28. package/ed25519.d.ts.map +1 -1
  29. package/ed25519.js +9 -6
  30. package/ed25519.js.map +1 -1
  31. package/ed448.d.ts +51 -2
  32. package/ed448.d.ts.map +1 -1
  33. package/ed448.js +206 -28
  34. package/ed448.js.map +1 -1
  35. package/esm/abstract/bls.js +3 -3
  36. package/esm/abstract/bls.js.map +1 -1
  37. package/esm/abstract/hash-to-curve.js +14 -8
  38. package/esm/abstract/hash-to-curve.js.map +1 -1
  39. package/esm/abstract/modular.js +75 -20
  40. package/esm/abstract/modular.js.map +1 -1
  41. package/esm/abstract/poseidon.js +39 -41
  42. package/esm/abstract/poseidon.js.map +1 -1
  43. package/esm/abstract/utils.js +2 -1
  44. package/esm/abstract/utils.js.map +1 -1
  45. package/esm/abstract/weierstrass.js +13 -11
  46. package/esm/abstract/weierstrass.js.map +1 -1
  47. package/esm/bls12-381.js +7 -8
  48. package/esm/bls12-381.js.map +1 -1
  49. package/esm/ed25519.js +9 -6
  50. package/esm/ed25519.js.map +1 -1
  51. package/esm/ed448.js +208 -31
  52. package/esm/ed448.js.map +1 -1
  53. package/esm/jubjub.js +1 -1
  54. package/esm/jubjub.js.map +1 -1
  55. package/esm/package.json +1 -4
  56. package/jubjub.js.map +1 -1
  57. package/package.json +4 -3
  58. package/src/abstract/bls.ts +3 -3
  59. package/src/abstract/hash-to-curve.ts +14 -8
  60. package/src/abstract/modular.ts +81 -22
  61. package/src/abstract/poseidon.ts +39 -40
  62. package/src/abstract/utils.ts +4 -1
  63. package/src/abstract/weierstrass.ts +13 -11
  64. package/src/bls12-381.ts +7 -8
  65. package/src/ed25519.ts +9 -6
  66. package/src/ed448.ts +251 -33
  67. package/src/jubjub.ts +1 -1
@@ -75,9 +75,14 @@ export function invert(number: bigint, modulo: bigint): bigint {
75
75
  return mod(x, modulo);
76
76
  }
77
77
 
78
- // Tonelli-Shanks algorithm
79
- // Paper 1: https://eprint.iacr.org/2012/685.pdf (page 12)
80
- // Paper 2: Square Roots from 1; 24, 51, 10 to Dan Shanks
78
+ /**
79
+ * Tonelli-Shanks square root search algorithm.
80
+ * 1. https://eprint.iacr.org/2012/685.pdf (page 12)
81
+ * 2. Square Roots from 1; 24, 51, 10 to Dan Shanks
82
+ * Will start an infinite loop if field order P is not prime.
83
+ * @param P field order
84
+ * @returns function that takes field Fp (created from P) and number n
85
+ */
81
86
  export function tonelliShanks(P: bigint) {
82
87
  // Legendre constant: used to calculate Legendre symbol (a | p),
83
88
  // which denotes the value of a^((p-1)/2) (mod p).
@@ -198,7 +203,7 @@ export function FpSqrt(P: bigint) {
198
203
  // Little-endian check for first LE bit (last BE bit);
199
204
  export const isNegativeLE = (num: bigint, modulo: bigint) => (mod(num, modulo) & _1n) === _1n;
200
205
 
201
- // Field is not always over prime, Fp2 for example has ORDER(q)=p^m
206
+ // Field is not always over prime: for example, Fp2 has ORDER(q)=p^m
202
207
  export interface IField<T> {
203
208
  ORDER: bigint;
204
209
  BYTES: number;
@@ -228,7 +233,8 @@ export interface IField<T> {
228
233
  sqrN(num: T): T;
229
234
 
230
235
  // Optional
231
- // Should be same as sgn0 function in https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/
236
+ // Should be same as sgn0 function in
237
+ // [RFC9380](https://www.rfc-editor.org/rfc/rfc9380#section-4.1).
232
238
  // NOTE: sgn0 is 'negative in LE', which is same as odd. And negative in LE is kinda strange definition anyway.
233
239
  isOdd?(num: T): boolean; // Odd instead of even since we have it for Fp2
234
240
  // legendre?(num: T): T;
@@ -260,6 +266,11 @@ export function validateField<T>(field: IField<T>) {
260
266
  }
261
267
 
262
268
  // Generic field functions
269
+
270
+ /**
271
+ * Same as `pow` but for Fp: non-constant-time.
272
+ * Unsafe in some contexts: uses ladder, so can expose bigint bits.
273
+ */
263
274
  export function FpPow<T>(f: IField<T>, num: T, power: bigint): T {
264
275
  // Should have same speed as pow for bigints
265
276
  // TODO: benchmark!
@@ -276,7 +287,10 @@ export function FpPow<T>(f: IField<T>, num: T, power: bigint): T {
276
287
  return p;
277
288
  }
278
289
 
279
- // 0 is non-invertible: non-batched version will throw on 0
290
+ /**
291
+ * Efficiently invert an array of Field elements.
292
+ * `inv(0)` will return `undefined` here: make sure to throw an error.
293
+ */
280
294
  export function FpInvertBatch<T>(f: IField<T>, nums: T[]): T[] {
281
295
  const tmp = new Array(nums.length);
282
296
  // Walk from first to last, multiply them by each other MOD p
@@ -319,12 +333,12 @@ export function nLength(n: bigint, nBitLength?: number) {
319
333
 
320
334
  type FpField = IField<bigint> & Required<Pick<IField<bigint>, 'isOdd'>>;
321
335
  /**
322
- * Initializes a galois field over prime. Non-primes are not supported for now.
323
- * Do not init in loop: slow. Very fragile: always run a benchmark on change.
324
- * Major performance gains:
325
- * a) non-normalized operations like mulN instead of mul
326
- * b) `Object.freeze`
327
- * c) Same object shape: never add or remove keys
336
+ * Initializes a finite field over prime. **Non-primes are not supported.**
337
+ * Do not init in loop: slow. Very fragile: always run a benchmark on a change.
338
+ * Major performance optimizations:
339
+ * * a) denormalized operations like mulN instead of mul
340
+ * * b) same object shape: never add or remove keys
341
+ * * c) Object.freeze
328
342
  * @param ORDER prime positive bigint
329
343
  * @param bitLen how many bits the field consumes
330
344
  * @param isLE (def: false) if encoding / decoding should be in little-endian
@@ -336,7 +350,7 @@ export function Field(
336
350
  isLE = false,
337
351
  redef: Partial<IField<bigint>> = {}
338
352
  ): Readonly<FpField> {
339
- if (ORDER <= _0n) throw new Error(`Expected Fp ORDER > 0, got ${ORDER}`);
353
+ if (ORDER <= _0n) throw new Error(`Expected Field ORDER > 0, got ${ORDER}`);
340
354
  const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, bitLen);
341
355
  if (BYTES > 2048) throw new Error('Field lengths over 2048 bytes are not supported');
342
356
  const sqrtP = FpSqrt(ORDER);
@@ -400,15 +414,10 @@ export function FpSqrtEven<T>(Fp: IField<T>, elm: T) {
400
414
  }
401
415
 
402
416
  /**
403
- * FIPS 186 B.4.1-compliant "constant-time" private key generation utility.
404
- * Can take (n+8) or more bytes of uniform input e.g. from CSPRNG or KDF
405
- * and convert them into private scalar, with the modulo bias being negligible.
406
- * Needs at least 40 bytes of input for 32-byte private key.
407
- * https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
408
- * @param hash hash output from SHA3 or a similar function
409
- * @param groupOrder size of subgroup - (e.g. curveFn.CURVE.n)
410
- * @param isLE interpret hash bytes as LE num
411
- * @returns valid private scalar
417
+ * "Constant-time" private key generation utility.
418
+ * Same as mapKeyToField, but accepts less bytes (40 instead of 48 for 32-byte field).
419
+ * Which makes it slightly more biased, less secure.
420
+ * @deprecated use mapKeyToField instead
412
421
  */
413
422
  export function hashToPrivateScalar(
414
423
  hash: string | Uint8Array,
@@ -423,3 +432,53 @@ export function hashToPrivateScalar(
423
432
  const num = isLE ? bytesToNumberLE(hash) : bytesToNumberBE(hash);
424
433
  return mod(num, groupOrder - _1n) + _1n;
425
434
  }
435
+
436
+ /**
437
+ * Returns total number of bytes consumed by the field element.
438
+ * For example, 32 bytes for usual 256-bit weierstrass curve.
439
+ * @param fieldOrder number of field elements, usually CURVE.n
440
+ * @returns byte length of field
441
+ */
442
+ export function getFieldBytesLength(fieldOrder: bigint): number {
443
+ if (typeof fieldOrder !== 'bigint') throw new Error('field order must be bigint');
444
+ const bitLength = fieldOrder.toString(2).length;
445
+ return Math.ceil(bitLength / 8);
446
+ }
447
+
448
+ /**
449
+ * Returns minimal amount of bytes that can be safely reduced
450
+ * by field order.
451
+ * Should be 2^-128 for 128-bit curve such as P256.
452
+ * @param fieldOrder number of field elements, usually CURVE.n
453
+ * @returns byte length of target hash
454
+ */
455
+ export function getMinHashLength(fieldOrder: bigint): number {
456
+ const length = getFieldBytesLength(fieldOrder);
457
+ return length + Math.ceil(length / 2);
458
+ }
459
+
460
+ /**
461
+ * "Constant-time" private key generation utility.
462
+ * Can take (n + n/2) or more bytes of uniform input e.g. from CSPRNG or KDF
463
+ * and convert them into private scalar, with the modulo bias being negligible.
464
+ * Needs at least 48 bytes of input for 32-byte private key.
465
+ * https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
466
+ * FIPS 186-5, A.2 https://csrc.nist.gov/publications/detail/fips/186/5/final
467
+ * RFC 9380, https://www.rfc-editor.org/rfc/rfc9380#section-5
468
+ * @param hash hash output from SHA3 or a similar function
469
+ * @param groupOrder size of subgroup - (e.g. secp256k1.CURVE.n)
470
+ * @param isLE interpret hash bytes as LE num
471
+ * @returns valid private scalar
472
+ */
473
+ export function mapHashToField(key: Uint8Array, fieldOrder: bigint, isLE = false): Uint8Array {
474
+ const len = key.length;
475
+ const fieldLen = getFieldBytesLength(fieldOrder);
476
+ const minLen = getMinHashLength(fieldOrder);
477
+ // No small numbers: need to understand bias story. No huge numbers: easier to detect JS timings.
478
+ if (len < 16 || len < minLen || len > 1024)
479
+ throw new Error(`expected ${minLen}-1024 bytes of input, got ${len}`);
480
+ const num = isLE ? bytesToNumberBE(key) : bytesToNumberLE(key);
481
+ // `mod(x, 11)` can sometimes produce 0. `mod(x, 10) + 1` is the same, but no 0
482
+ const reduced = mod(num, fieldOrder - _1n) + _1n;
483
+ return isLE ? numberToBytesLE(reduced, fieldLen) : numberToBytesBE(reduced, fieldLen);
484
+ }
@@ -15,34 +15,36 @@ export type PoseidonOpts = {
15
15
  };
16
16
 
17
17
  export function validateOpts(opts: PoseidonOpts) {
18
- const { Fp } = opts;
18
+ const { Fp, mds, reversePartialPowIdx: rev, roundConstants: rc } = opts;
19
+ const { roundsFull, roundsPartial, sboxPower, t } = opts;
20
+
19
21
  validateField(Fp);
20
22
  for (const i of ['t', 'roundsFull', 'roundsPartial'] as const) {
21
23
  if (typeof opts[i] !== 'number' || !Number.isSafeInteger(opts[i]))
22
24
  throw new Error(`Poseidon: invalid param ${i}=${opts[i]} (${typeof opts[i]})`);
23
25
  }
24
- if (opts.reversePartialPowIdx !== undefined && typeof opts.reversePartialPowIdx !== 'boolean')
25
- throw new Error(`Poseidon: invalid param reversePartialPowIdx=${opts.reversePartialPowIdx}`);
26
- // Default is 5, but by some reasons stark uses 3
27
- let sboxPower = opts.sboxPower;
28
- if (sboxPower === undefined) sboxPower = 5;
29
- if (typeof sboxPower !== 'number' || !Number.isSafeInteger(sboxPower))
30
- throw new Error(`Poseidon wrong sboxPower=${sboxPower}`);
31
26
 
32
- const _sboxPower = BigInt(sboxPower);
33
- let sboxFn = (n: bigint) => FpPow(Fp, n, _sboxPower);
34
- // Unwrapped sbox power for common cases (195->142μs)
35
- if (sboxPower === 3) sboxFn = (n: bigint) => Fp.mul(Fp.sqrN(n), n);
36
- else if (sboxPower === 5) sboxFn = (n: bigint) => Fp.mul(Fp.sqrN(Fp.sqrN(n)), n);
27
+ // MDS is TxT matrix
28
+ if (!Array.isArray(mds) || mds.length !== t) throw new Error('Poseidon: wrong MDS matrix');
29
+ const _mds = mds.map((mdsRow) => {
30
+ if (!Array.isArray(mdsRow) || mdsRow.length !== t)
31
+ throw new Error(`Poseidon MDS matrix row: ${mdsRow}`);
32
+ return mdsRow.map((i) => {
33
+ if (typeof i !== 'bigint') throw new Error(`Poseidon MDS matrix value=${i}`);
34
+ return Fp.create(i);
35
+ });
36
+ });
37
+
38
+ if (rev !== undefined && typeof rev !== 'boolean')
39
+ throw new Error(`Poseidon: invalid param reversePartialPowIdx=${rev}`);
37
40
 
38
- if (opts.roundsFull % 2 !== 0)
39
- throw new Error(`Poseidon roundsFull is not even: ${opts.roundsFull}`);
40
- const rounds = opts.roundsFull + opts.roundsPartial;
41
+ if (roundsFull % 2 !== 0) throw new Error(`Poseidon roundsFull is not even: ${roundsFull}`);
42
+ const rounds = roundsFull + roundsPartial;
41
43
 
42
- if (!Array.isArray(opts.roundConstants) || opts.roundConstants.length !== rounds)
44
+ if (!Array.isArray(rc) || rc.length !== rounds)
43
45
  throw new Error('Poseidon: wrong round constants');
44
- const roundConstants = opts.roundConstants.map((rc) => {
45
- if (!Array.isArray(rc) || rc.length !== opts.t)
46
+ const roundConstants = rc.map((rc) => {
47
+ if (!Array.isArray(rc) || rc.length !== t)
46
48
  throw new Error(`Poseidon wrong round constants: ${rc}`);
47
49
  return rc.map((i) => {
48
50
  if (typeof i !== 'bigint' || !Fp.isValid(i))
@@ -50,18 +52,16 @@ export function validateOpts(opts: PoseidonOpts) {
50
52
  return Fp.create(i);
51
53
  });
52
54
  });
53
- // MDS is TxT matrix
54
- if (!Array.isArray(opts.mds) || opts.mds.length !== opts.t)
55
- throw new Error('Poseidon: wrong MDS matrix');
56
- const mds = opts.mds.map((mdsRow) => {
57
- if (!Array.isArray(mdsRow) || mdsRow.length !== opts.t)
58
- throw new Error(`Poseidon MDS matrix row: ${mdsRow}`);
59
- return mdsRow.map((i) => {
60
- if (typeof i !== 'bigint') throw new Error(`Poseidon MDS matrix value=${i}`);
61
- return Fp.create(i);
62
- });
63
- });
64
- return Object.freeze({ ...opts, rounds, sboxFn, roundConstants, mds });
55
+
56
+ if (!sboxPower || ![3, 5, 7].includes(sboxPower))
57
+ throw new Error(`Poseidon wrong sboxPower=${sboxPower}`);
58
+ const _sboxPower = BigInt(sboxPower);
59
+ let sboxFn = (n: bigint) => FpPow(Fp, n, _sboxPower);
60
+ // Unwrapped sbox power for common cases (195->142μs)
61
+ if (sboxPower === 3) sboxFn = (n: bigint) => Fp.mul(Fp.sqrN(n), n);
62
+ else if (sboxPower === 5) sboxFn = (n: bigint) => Fp.mul(Fp.sqrN(Fp.sqrN(n)), n);
63
+
64
+ return Object.freeze({ ...opts, rounds, sboxFn, roundConstants, mds: _mds });
65
65
  }
66
66
 
67
67
  export function splitConstants(rc: bigint[], t: number) {
@@ -80,18 +80,17 @@ export function splitConstants(rc: bigint[], t: number) {
80
80
  }
81
81
 
82
82
  export function poseidon(opts: PoseidonOpts) {
83
- const { t, Fp, rounds, sboxFn, reversePartialPowIdx } = validateOpts(opts);
84
- const halfRoundsFull = Math.floor(opts.roundsFull / 2);
85
- const partialIdx = reversePartialPowIdx ? t - 1 : 0;
83
+ const _opts = validateOpts(opts);
84
+ const { Fp, mds, roundConstants, rounds, roundsPartial, sboxFn, t } = _opts;
85
+ const halfRoundsFull = _opts.roundsFull / 2;
86
+ const partialIdx = _opts.reversePartialPowIdx ? t - 1 : 0;
86
87
  const poseidonRound = (values: bigint[], isFull: boolean, idx: number) => {
87
- values = values.map((i, j) => Fp.add(i, opts.roundConstants[idx][j]));
88
+ values = values.map((i, j) => Fp.add(i, roundConstants[idx][j]));
88
89
 
89
90
  if (isFull) values = values.map((i) => sboxFn(i));
90
91
  else values[partialIdx] = sboxFn(values[partialIdx]);
91
92
  // Matrix multiplication
92
- values = opts.mds.map((i) =>
93
- i.reduce((acc, i, j) => Fp.add(acc, Fp.mulN(i, values[j])), Fp.ZERO)
94
- );
93
+ values = mds.map((i) => i.reduce((acc, i, j) => Fp.add(acc, Fp.mulN(i, values[j])), Fp.ZERO));
95
94
  return values;
96
95
  };
97
96
  const poseidonHash = function poseidonHash(values: bigint[]) {
@@ -105,7 +104,7 @@ export function poseidon(opts: PoseidonOpts) {
105
104
  // Apply r_f/2 full rounds.
106
105
  for (let i = 0; i < halfRoundsFull; i++) values = poseidonRound(values, true, round++);
107
106
  // Apply r_p partial rounds.
108
- for (let i = 0; i < opts.roundsPartial; i++) values = poseidonRound(values, false, round++);
107
+ for (let i = 0; i < roundsPartial; i++) values = poseidonRound(values, false, round++);
109
108
  // Apply r_f/2 full rounds.
110
109
  for (let i = 0; i < halfRoundsFull; i++) values = poseidonRound(values, true, round++);
111
110
 
@@ -114,6 +113,6 @@ export function poseidon(opts: PoseidonOpts) {
114
113
  return values;
115
114
  };
116
115
  // For verification in tests
117
- poseidonHash.roundConstants = opts.roundConstants;
116
+ poseidonHash.roundConstants = roundConstants;
118
117
  return poseidonHash;
119
118
  }
@@ -17,7 +17,9 @@ export type CHash = {
17
17
  };
18
18
  export type FHash = (message: Uint8Array | string) => Uint8Array;
19
19
 
20
- const hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, '0'));
20
+ const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) =>
21
+ i.toString(16).padStart(2, '0')
22
+ );
21
23
  /**
22
24
  * @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'
23
25
  */
@@ -246,6 +248,7 @@ const validatorFns = {
246
248
  function: (val: any) => typeof val === 'function',
247
249
  boolean: (val: any) => typeof val === 'boolean',
248
250
  string: (val: any) => typeof val === 'string',
251
+ stringOrUint8Array: (val: any) => typeof val === 'string' || val instanceof Uint8Array,
249
252
  isSafeInteger: (val: any) => Number.isSafeInteger(val),
250
253
  array: (val: any) => Array.isArray(val),
251
254
  field: (val: any, object: any) => (object as any).Fp.isValid(val),
@@ -193,7 +193,7 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
193
193
 
194
194
  const toBytes =
195
195
  CURVE.toBytes ||
196
- ((c: ProjConstructor<T>, point: ProjPointType<T>, isCompressed: boolean) => {
196
+ ((_c: ProjConstructor<T>, point: ProjPointType<T>, _isCompressed: boolean) => {
197
197
  const a = point.toAffine();
198
198
  return ut.concatBytes(Uint8Array.from([0x04]), Fp.toBytes(a.x), Fp.toBytes(a.y));
199
199
  });
@@ -333,9 +333,11 @@ export function weierstrassPoints<T>(opts: CurvePointsType<T>) {
333
333
 
334
334
  // A point on curve is valid if it conforms to equation.
335
335
  assertValidity(): void {
336
- // Zero is valid point too!
337
336
  if (this.is0()) {
338
- if (CURVE.allowInfinityPoint) return;
337
+ // (0, 1, 0) aka ZERO is invalid in most contexts.
338
+ // In BLS, ZERO can be serialized, so we allow it.
339
+ // (0, 0, 0) is wrong representation of ZERO and is always invalid.
340
+ if (CURVE.allowInfinityPoint && !Fp.is0(this.py)) return;
339
341
  throw new Error('bad point: ZERO');
340
342
  }
341
343
  // Some 3rd-party test vectors require different wording between here & `fromCompressedHex`
@@ -707,7 +709,7 @@ export function weierstrass(curveDef: CurveType): CurveFn {
707
709
  isWithinCurveOrder,
708
710
  } = weierstrassPoints({
709
711
  ...CURVE,
710
- toBytes(c, point, isCompressed: boolean): Uint8Array {
712
+ toBytes(_c, point, isCompressed: boolean): Uint8Array {
711
713
  const a = point.toAffine();
712
714
  const x = Fp.toBytes(a.x);
713
715
  const cat = ut.concatBytes;
@@ -845,13 +847,12 @@ export function weierstrass(curveDef: CurveType): CurveFn {
845
847
  normPrivateKeyToScalar: normPrivateKeyToScalar,
846
848
 
847
849
  /**
848
- * Produces cryptographically secure private key from random of size (nBitLength+64)
849
- * as per FIPS 186 B.4.1 with modulo bias being neglible.
850
+ * Produces cryptographically secure private key from random of size
851
+ * (groupLen + ceil(groupLen / 2)) with modulo bias being negligible.
850
852
  */
851
853
  randomPrivateKey: (): Uint8Array => {
852
- const rand = CURVE.randomBytes(Fp.BYTES + 8);
853
- const num = mod.hashToPrivateScalar(rand, CURVE_ORDER);
854
- return ut.numberToBytesBE(num, CURVE.nByteLength);
854
+ const length = mod.getMinHashLength(CURVE.n);
855
+ return mod.mapHashToField(CURVE.randomBytes(length), CURVE.n);
855
856
  },
856
857
 
857
858
  /**
@@ -964,7 +965,7 @@ export function weierstrass(curveDef: CurveType): CurveFn {
964
965
  if (ent != null) {
965
966
  // K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) || k')
966
967
  const e = ent === true ? randomBytes(Fp.BYTES) : ent; // generate random bytes OR pass as-is
967
- seedArgs.push(ensureBytes('extraEntropy', e, Fp.BYTES)); // check for being of size BYTES
968
+ seedArgs.push(ensureBytes('extraEntropy', e)); // check for being bytes
968
969
  }
969
970
  const seed = ut.concatBytes(...seedArgs); // Step D of RFC6979 3.2
970
971
  const m = h1int; // NOTE: no need to call bits2int second time here, it is inside truncateHash!
@@ -1170,7 +1171,8 @@ export function SWUFpSqrtRatio<T>(Fp: mod.IField<T>, Z: T) {
1170
1171
  return sqrtRatio;
1171
1172
  }
1172
1173
  /**
1173
- * From draft-irtf-cfrg-hash-to-curve-16
1174
+ * Simplified Shallue-van de Woestijne-Ulas Method
1175
+ * https://www.rfc-editor.org/rfc/rfc9380#section-6.6.2
1174
1176
  */
1175
1177
  export function mapToCurveSimpleSWU<T>(
1176
1178
  Fp: mod.IField<T>,
package/src/bls12-381.ts CHANGED
@@ -8,8 +8,8 @@
8
8
  // The library uses G1 for public keys and G2 for signatures. Support for G1 signatures is planned.
9
9
  // Compatible with Algorand, Chia, Dfinity, Ethereum, FIL, Zcash. Matches specs
10
10
  // [pairing-curves-11](https://tools.ietf.org/html/draft-irtf-cfrg-pairing-friendly-curves-11),
11
- // [bls-sigs-04](https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-04),
12
- // [hash-to-curve-12](https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-12).
11
+ // [bls-sigs-04](https:/cfrg-hash-to/tools.ietf.org/html/draft-irtf-cfrg-bls-signature-04),
12
+ // [hash-to-curve-12](https://tools.ietf.org/html/draft-irtf--curve-12).
13
13
  //
14
14
  // ### Summary
15
15
  // 1. BLS Relies on Bilinear Pairing (expensive)
@@ -177,7 +177,7 @@ const Fp2: mod.IField<Fp2> & Fp2Utils = {
177
177
  if (im1 > im2 || (im1 === im2 && re1 > re2)) return x1;
178
178
  return x2;
179
179
  },
180
- // Same as sgn0_fp2 in draft-irtf-cfrg-hash-to-curve-16
180
+ // Same as sgn0_m_eq_2 in RFC 9380
181
181
  isOdd: (x: Fp2) => {
182
182
  const { re: x0, im: x1 } = Fp2.reim(x);
183
183
  const sign_0 = x0 % _2n;
@@ -780,8 +780,7 @@ const FP12_FROBENIUS_COEFFICIENTS = [
780
780
 
781
781
  // HashToCurve
782
782
 
783
- // 3-isogeny map from E' to E
784
- // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#appendix-E.3
783
+ // 3-isogeny map from E' to E https://www.rfc-editor.org/rfc/rfc9380#appendix-E.3
785
784
  const isogenyMapG2 = isogenyMap(
786
785
  Fp2,
787
786
  [
@@ -985,7 +984,7 @@ function G2psi2(c: ProjConstructor<Fp2>, P: ProjPointType<Fp2>) {
985
984
  //
986
985
  // Parameter definitions are in section 5.3 of the spec unless otherwise noted.
987
986
  // Parameter values come from section 8.8.2 of the spec.
988
- // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-8.8.2
987
+ // https://www.rfc-editor.org/rfc/rfc9380#section-8.8.2
989
988
  //
990
989
  // Base field F is GF(p^m)
991
990
  // p = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab
@@ -1040,7 +1039,7 @@ function signatureG2ToRawBytes(point: ProjPointType<Fp2>) {
1040
1039
  }
1041
1040
 
1042
1041
  // To verify curve parameters, see pairing-friendly-curves spec:
1043
- // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-09
1042
+ // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-11
1044
1043
  // Basic math is done over finite fields over p.
1045
1044
  // More complicated math is done over polynominal extension fields.
1046
1045
  // To simplify calculations in Fp12, we construct extension tower:
@@ -1108,7 +1107,7 @@ export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
1108
1107
  },
1109
1108
  // Clear cofactor of G1
1110
1109
  // https://eprint.iacr.org/2019/403
1111
- clearCofactor: (c, point) => {
1110
+ clearCofactor: (_c, point) => {
1112
1111
  // return this.multiplyUnsafe(CURVE.h);
1113
1112
  return point.multiplyUnsafe(bls12_381.params.x).add(point); // x*P + P
1114
1113
  },
package/src/ed25519.ts CHANGED
@@ -123,7 +123,7 @@ const ed25519Defaults = {
123
123
  uvRatio,
124
124
  } as const;
125
125
 
126
- export const ed25519 = twistedEdwards(ed25519Defaults);
126
+ export const ed25519 = /* @__PURE__ */ twistedEdwards(ed25519Defaults);
127
127
 
128
128
  function ed25519_domain(data: Uint8Array, ctx: Uint8Array, phflag: boolean) {
129
129
  if (ctx.length > 255) throw new Error('Context is too big');
@@ -135,8 +135,11 @@ function ed25519_domain(data: Uint8Array, ctx: Uint8Array, phflag: boolean) {
135
135
  );
136
136
  }
137
137
 
138
- export const ed25519ctx = twistedEdwards({ ...ed25519Defaults, domain: ed25519_domain });
139
- export const ed25519ph = twistedEdwards({
138
+ export const ed25519ctx = /* @__PURE__ */ twistedEdwards({
139
+ ...ed25519Defaults,
140
+ domain: ed25519_domain,
141
+ });
142
+ export const ed25519ph = /* @__PURE__ */ twistedEdwards({
140
143
  ...ed25519Defaults,
141
144
  domain: ed25519_domain,
142
145
  prehash: sha512,
@@ -475,12 +478,12 @@ export const RistrettoPoint = /* @__PURE__ */ (() => {
475
478
  return RistPoint;
476
479
  })();
477
480
 
478
- // https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/14/
479
- // Appendix B. Hashing to ristretto255
480
- export const hash_to_ristretto255 = (msg: Uint8Array, options: htfBasicOpts) => {
481
+ // Hashing to ristretto255. https://www.rfc-editor.org/rfc/rfc9380#appendix-B
482
+ export const hashToRistretto255 = (msg: Uint8Array, options: htfBasicOpts) => {
481
483
  const d = options.DST;
482
484
  const DST = typeof d === 'string' ? utf8ToBytes(d) : d;
483
485
  const uniform_bytes = expand_message_xmd(msg, DST, 64, sha512);
484
486
  const P = RistPoint.hashToCurve(uniform_bytes);
485
487
  return P;
486
488
  };
489
+ export const hash_to_ristretto255 = hashToRistretto255; // legacy