@noble/curves 1.7.0 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/README.md +40 -21
  2. package/_shortw_utils.d.ts +9 -55
  3. package/_shortw_utils.d.ts.map +1 -1
  4. package/_shortw_utils.js +6 -2
  5. package/_shortw_utils.js.map +1 -1
  6. package/abstract/bls.d.ts +8 -6
  7. package/abstract/bls.d.ts.map +1 -1
  8. package/abstract/bls.js +17 -1
  9. package/abstract/bls.js.map +1 -1
  10. package/abstract/curve.d.ts +27 -32
  11. package/abstract/curve.d.ts.map +1 -1
  12. package/abstract/curve.js +19 -12
  13. package/abstract/curve.js.map +1 -1
  14. package/abstract/edwards.d.ts +14 -25
  15. package/abstract/edwards.d.ts.map +1 -1
  16. package/abstract/edwards.js +5 -1
  17. package/abstract/edwards.js.map +1 -1
  18. package/abstract/hash-to-curve.d.ts +29 -9
  19. package/abstract/hash-to-curve.d.ts.map +1 -1
  20. package/abstract/hash-to-curve.js +15 -10
  21. package/abstract/hash-to-curve.js.map +1 -1
  22. package/abstract/modular.d.ts +30 -5
  23. package/abstract/modular.d.ts.map +1 -1
  24. package/abstract/modular.js +36 -16
  25. package/abstract/modular.js.map +1 -1
  26. package/abstract/montgomery.d.ts.map +1 -1
  27. package/abstract/montgomery.js +6 -1
  28. package/abstract/montgomery.js.map +1 -1
  29. package/abstract/poseidon.d.ts +10 -1
  30. package/abstract/poseidon.d.ts.map +1 -1
  31. package/abstract/poseidon.js +9 -1
  32. package/abstract/poseidon.js.map +1 -1
  33. package/abstract/tower.d.ts +12 -1
  34. package/abstract/tower.d.ts.map +1 -1
  35. package/abstract/tower.js +14 -11
  36. package/abstract/tower.js.map +1 -1
  37. package/abstract/utils.d.ts +10 -5
  38. package/abstract/utils.d.ts.map +1 -1
  39. package/abstract/utils.js +5 -1
  40. package/abstract/utils.js.map +1 -1
  41. package/abstract/weierstrass.d.ts +51 -85
  42. package/abstract/weierstrass.d.ts.map +1 -1
  43. package/abstract/weierstrass.js +42 -15
  44. package/abstract/weierstrass.js.map +1 -1
  45. package/bls12-381.d.ts +12 -1
  46. package/bls12-381.d.ts.map +1 -1
  47. package/bls12-381.js +72 -60
  48. package/bls12-381.js.map +1 -1
  49. package/bn254.d.ts +4 -3
  50. package/bn254.d.ts.map +1 -1
  51. package/bn254.js +23 -20
  52. package/bn254.js.map +1 -1
  53. package/ed25519.d.ts +27 -7
  54. package/ed25519.d.ts.map +1 -1
  55. package/ed25519.js +30 -6
  56. package/ed25519.js.map +1 -1
  57. package/ed448.d.ts +25 -10
  58. package/ed448.d.ts.map +1 -1
  59. package/ed448.js +30 -8
  60. package/ed448.js.map +1 -1
  61. package/esm/_shortw_utils.d.ts +9 -55
  62. package/esm/_shortw_utils.d.ts.map +1 -1
  63. package/esm/_shortw_utils.js +6 -2
  64. package/esm/_shortw_utils.js.map +1 -1
  65. package/esm/abstract/bls.d.ts +8 -6
  66. package/esm/abstract/bls.d.ts.map +1 -1
  67. package/esm/abstract/bls.js +17 -1
  68. package/esm/abstract/bls.js.map +1 -1
  69. package/esm/abstract/curve.d.ts +27 -32
  70. package/esm/abstract/curve.d.ts.map +1 -1
  71. package/esm/abstract/curve.js +21 -14
  72. package/esm/abstract/curve.js.map +1 -1
  73. package/esm/abstract/edwards.d.ts +14 -25
  74. package/esm/abstract/edwards.d.ts.map +1 -1
  75. package/esm/abstract/edwards.js +8 -4
  76. package/esm/abstract/edwards.js.map +1 -1
  77. package/esm/abstract/hash-to-curve.d.ts +29 -9
  78. package/esm/abstract/hash-to-curve.d.ts.map +1 -1
  79. package/esm/abstract/hash-to-curve.js +15 -10
  80. package/esm/abstract/hash-to-curve.js.map +1 -1
  81. package/esm/abstract/modular.d.ts +30 -5
  82. package/esm/abstract/modular.d.ts.map +1 -1
  83. package/esm/abstract/modular.js +36 -16
  84. package/esm/abstract/modular.js.map +1 -1
  85. package/esm/abstract/montgomery.d.ts.map +1 -1
  86. package/esm/abstract/montgomery.js +6 -1
  87. package/esm/abstract/montgomery.js.map +1 -1
  88. package/esm/abstract/poseidon.d.ts +10 -1
  89. package/esm/abstract/poseidon.d.ts.map +1 -1
  90. package/esm/abstract/poseidon.js +9 -1
  91. package/esm/abstract/poseidon.js.map +1 -1
  92. package/esm/abstract/tower.d.ts +12 -1
  93. package/esm/abstract/tower.d.ts.map +1 -1
  94. package/esm/abstract/tower.js +14 -11
  95. package/esm/abstract/tower.js.map +1 -1
  96. package/esm/abstract/utils.d.ts +10 -5
  97. package/esm/abstract/utils.d.ts.map +1 -1
  98. package/esm/abstract/utils.js +4 -0
  99. package/esm/abstract/utils.js.map +1 -1
  100. package/esm/abstract/weierstrass.d.ts +51 -85
  101. package/esm/abstract/weierstrass.d.ts.map +1 -1
  102. package/esm/abstract/weierstrass.js +42 -16
  103. package/esm/abstract/weierstrass.js.map +1 -1
  104. package/esm/bls12-381.d.ts +12 -1
  105. package/esm/bls12-381.d.ts.map +1 -1
  106. package/esm/bls12-381.js +73 -61
  107. package/esm/bls12-381.js.map +1 -1
  108. package/esm/bn254.d.ts +4 -3
  109. package/esm/bn254.d.ts.map +1 -1
  110. package/esm/bn254.js +23 -20
  111. package/esm/bn254.js.map +1 -1
  112. package/esm/ed25519.d.ts +27 -7
  113. package/esm/ed25519.d.ts.map +1 -1
  114. package/esm/ed25519.js +31 -7
  115. package/esm/ed25519.js.map +1 -1
  116. package/esm/ed448.d.ts +25 -10
  117. package/esm/ed448.d.ts.map +1 -1
  118. package/esm/ed448.js +31 -9
  119. package/esm/ed448.js.map +1 -1
  120. package/esm/index.js +16 -0
  121. package/esm/index.js.map +1 -1
  122. package/esm/jubjub.d.ts +4 -8
  123. package/esm/jubjub.d.ts.map +1 -1
  124. package/esm/jubjub.js +6 -5
  125. package/esm/jubjub.js.map +1 -1
  126. package/esm/p256.d.ts +10 -104
  127. package/esm/p256.d.ts.map +1 -1
  128. package/esm/p256.js +9 -2
  129. package/esm/p256.js.map +1 -1
  130. package/esm/p384.d.ts +10 -104
  131. package/esm/p384.d.ts.map +1 -1
  132. package/esm/p384.js +9 -2
  133. package/esm/p384.js.map +1 -1
  134. package/esm/p521.d.ts +11 -104
  135. package/esm/p521.d.ts.map +1 -1
  136. package/esm/p521.js +11 -3
  137. package/esm/p521.js.map +1 -1
  138. package/esm/pasta.d.ts +5 -2
  139. package/esm/pasta.d.ts.map +1 -1
  140. package/esm/pasta.js +6 -2
  141. package/esm/pasta.js.map +1 -1
  142. package/esm/secp256k1.d.ts +30 -58
  143. package/esm/secp256k1.d.ts.map +1 -1
  144. package/esm/secp256k1.js +34 -8
  145. package/esm/secp256k1.js.map +1 -1
  146. package/index.js +16 -0
  147. package/index.js.map +1 -1
  148. package/jubjub.d.ts +4 -8
  149. package/jubjub.d.ts.map +1 -1
  150. package/jubjub.js +6 -5
  151. package/jubjub.js.map +1 -1
  152. package/p256.d.ts +10 -104
  153. package/p256.d.ts.map +1 -1
  154. package/p256.js +9 -2
  155. package/p256.js.map +1 -1
  156. package/p384.d.ts +10 -104
  157. package/p384.d.ts.map +1 -1
  158. package/p384.js +9 -2
  159. package/p384.js.map +1 -1
  160. package/p521.d.ts +11 -104
  161. package/p521.d.ts.map +1 -1
  162. package/p521.js +11 -3
  163. package/p521.js.map +1 -1
  164. package/package.json +16 -13
  165. package/pasta.d.ts +5 -2
  166. package/pasta.d.ts.map +1 -1
  167. package/pasta.js +6 -2
  168. package/pasta.js.map +1 -1
  169. package/secp256k1.d.ts +30 -58
  170. package/secp256k1.d.ts.map +1 -1
  171. package/secp256k1.js +33 -7
  172. package/secp256k1.js.map +1 -1
  173. package/src/_shortw_utils.ts +19 -9
  174. package/src/abstract/bls.ts +20 -18
  175. package/src/abstract/curve.ts +52 -19
  176. package/src/abstract/edwards.ts +18 -12
  177. package/src/abstract/hash-to-curve.ts +42 -17
  178. package/src/abstract/modular.ts +55 -27
  179. package/src/abstract/montgomery.ts +7 -1
  180. package/src/abstract/poseidon.ts +29 -7
  181. package/src/abstract/tower.ts +59 -14
  182. package/src/abstract/utils.ts +26 -19
  183. package/src/abstract/weierstrass.ts +91 -50
  184. package/src/bls12-381.ts +80 -66
  185. package/src/bn254.ts +30 -24
  186. package/src/ed25519.ts +52 -23
  187. package/src/ed448.ts +50 -23
  188. package/src/index.ts +16 -0
  189. package/src/jubjub.ts +10 -10
  190. package/src/p256.ts +15 -9
  191. package/src/p384.ts +15 -9
  192. package/src/p521.ts +17 -10
  193. package/src/pasta.ts +15 -7
  194. package/src/secp256k1.ts +57 -15
@@ -1,5 +1,10 @@
1
+ /**
2
+ * Utils for modular division and finite fields.
3
+ * A finite field over 11 is integer number operations `mod 11`.
4
+ * There is no division: it is replaced by modular multiplicative inverse.
5
+ * @module
6
+ */
1
7
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
- // Utilities for modular arithmetics and finite fields
3
8
  import {
4
9
  bitMask,
5
10
  bytesToNumberBE,
@@ -9,6 +14,7 @@ import {
9
14
  numberToBytesLE,
10
15
  validateObject,
11
16
  } from './utils.js';
17
+
12
18
  // prettier-ignore
13
19
  const _0n = BigInt(0), _1n = BigInt(1), _2n = /* @__PURE__ */ BigInt(2), _3n = /* @__PURE__ */ BigInt(3);
14
20
  // prettier-ignore
@@ -24,10 +30,10 @@ export function mod(a: bigint, b: bigint): bigint {
24
30
  /**
25
31
  * Efficiently raise num to power and do modular division.
26
32
  * Unsafe in some contexts: uses ladder, so can expose bigint bits.
33
+ * @todo use field version && remove
27
34
  * @example
28
35
  * pow(2n, 6n, 11n) // 64n % 11n == 9n
29
36
  */
30
- // TODO: use field version && remove
31
37
  export function pow(num: bigint, power: bigint, modulo: bigint): bigint {
32
38
  if (power < _0n) throw new Error('invalid exponent, negatives unsupported');
33
39
  if (modulo <= _0n) throw new Error('invalid modulus');
@@ -41,7 +47,7 @@ export function pow(num: bigint, power: bigint, modulo: bigint): bigint {
41
47
  return res;
42
48
  }
43
49
 
44
- // Does x ^ (2 ^ power) mod p. pow2(30, 4) == 30 ^ (2 ^ 4)
50
+ /** Does `x^(2^power)` mod p. `pow2(30, 4)` == `30^(2^4)` */
45
51
  export function pow2(x: bigint, power: bigint, modulo: bigint): bigint {
46
52
  let res = x;
47
53
  while (power-- > _0n) {
@@ -51,11 +57,13 @@ export function pow2(x: bigint, power: bigint, modulo: bigint): bigint {
51
57
  return res;
52
58
  }
53
59
 
54
- // Inverses number over modulo
60
+ /**
61
+ * Inverses number over modulo.
62
+ * Implemented using [Euclidean GCD](https://brilliant.org/wiki/extended-euclidean-algorithm/).
63
+ */
55
64
  export function invert(number: bigint, modulo: bigint): bigint {
56
65
  if (number === _0n) throw new Error('invert: expected non-zero number');
57
66
  if (modulo <= _0n) throw new Error('invert: expected positive modulus, got ' + modulo);
58
- // Euclidean GCD https://brilliant.org/wiki/extended-euclidean-algorithm/
59
67
  // Fermat's little theorem "CT-like" version inv(n) = n^(m-2) mod m is 30x slower.
60
68
  let a = mod(number, modulo);
61
69
  let b = modulo;
@@ -83,7 +91,7 @@ export function invert(number: bigint, modulo: bigint): bigint {
83
91
  * @param P field order
84
92
  * @returns function that takes field Fp (created from P) and number n
85
93
  */
86
- export function tonelliShanks(P: bigint) {
94
+ export function tonelliShanks(P: bigint): <T>(Fp: IField<T>, n: T) => T {
87
95
  // Legendre constant: used to calculate Legendre symbol (a | p),
88
96
  // which denotes the value of a^((p-1)/2) (mod p).
89
97
  // (a | p) ≡ 1 if a is a square (mod p)
@@ -142,10 +150,18 @@ export function tonelliShanks(P: bigint) {
142
150
  };
143
151
  }
144
152
 
145
- export function FpSqrt(P: bigint) {
146
- // NOTE: different algorithms can give different roots, it is up to user to decide which one they want.
147
- // For example there is FpSqrtOdd/FpSqrtEven to choice root based on oddness (used for hash-to-curve).
148
-
153
+ /**
154
+ * Square root for a finite field. It will try to check if optimizations are applicable and fall back to 4:
155
+ *
156
+ * 1. P ≡ 3 (mod 4)
157
+ * 2. P ≡ 5 (mod 8)
158
+ * 3. P ≡ 9 (mod 16)
159
+ * 4. Tonelli-Shanks algorithm
160
+ *
161
+ * Different algorithms can give different roots, it is up to user to decide which one they want.
162
+ * For example there is FpSqrtOdd/FpSqrtEven to choice root based on oddness (used for hash-to-curve).
163
+ */
164
+ export function FpSqrt(P: bigint): <T>(Fp: IField<T>, n: T) => T {
149
165
  // P ≡ 3 (mod 4)
150
166
  // √n = n^((P+1)/4)
151
167
  if (P % _4n === _3n) {
@@ -203,11 +219,13 @@ export function FpSqrt(P: bigint) {
203
219
  }
204
220
 
205
221
  // Little-endian check for first LE bit (last BE bit);
206
- export const isNegativeLE = (num: bigint, modulo: bigint) => (mod(num, modulo) & _1n) === _1n;
222
+ export const isNegativeLE = (num: bigint, modulo: bigint): boolean =>
223
+ (mod(num, modulo) & _1n) === _1n;
207
224
 
208
- // Field is not always over prime: for example, Fp2 has ORDER(q)=p^m
225
+ /** Field is not always over prime: for example, Fp2 has ORDER(q)=p^m. */
209
226
  export interface IField<T> {
210
227
  ORDER: bigint;
228
+ isLE: boolean;
211
229
  BYTES: number;
212
230
  BITS: number;
213
231
  MASK: bigint;
@@ -253,7 +271,7 @@ const FIELD_FIELDS = [
253
271
  'eql', 'add', 'sub', 'mul', 'pow', 'div',
254
272
  'addN', 'subN', 'mulN', 'sqrN'
255
273
  ] as const;
256
- export function validateField<T>(field: IField<T>) {
274
+ export function validateField<T>(field: IField<T>): IField<T> {
257
275
  const initial = {
258
276
  ORDER: 'bigint',
259
277
  MASK: 'bigint',
@@ -316,16 +334,19 @@ export function FpDiv<T>(f: IField<T>, lhs: T, rhs: T | bigint): T {
316
334
  return f.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, f.ORDER) : f.inv(rhs));
317
335
  }
318
336
 
319
- export function FpLegendre(order: bigint) {
320
- // (a | p) ≡ 1 if a is a square (mod p), quadratic residue
321
- // (a | p) ≡ -1 if a is not a square (mod p), quadratic non residue
322
- // (a | p) ≡ 0 if a 0 (mod p)
337
+ /**
338
+ * Legendre symbol.
339
+ * * (a | p) ≡ 1 if a is a square (mod p), quadratic residue
340
+ * * (a | p) ≡ -1 if a is not a square (mod p), quadratic non residue
341
+ * * (a | p) ≡ 0 if a ≡ 0 (mod p)
342
+ */
343
+ export function FpLegendre(order: bigint): <T>(f: IField<T>, x: T) => T {
323
344
  const legendreConst = (order - _1n) / _2n; // Integer arithmetic
324
345
  return <T>(f: IField<T>, x: T): T => f.pow(x, legendreConst);
325
346
  }
326
347
 
327
348
  // This function returns True whenever the value x is a square in the field F.
328
- export function FpIsSquare<T>(f: IField<T>) {
349
+ export function FpIsSquare<T>(f: IField<T>): (x: T) => boolean {
329
350
  const legendre = FpLegendre(f.ORDER);
330
351
  return (x: T): boolean => {
331
352
  const p = legendre(f, x);
@@ -334,7 +355,13 @@ export function FpIsSquare<T>(f: IField<T>) {
334
355
  }
335
356
 
336
357
  // CURVE.n lengths
337
- export function nLength(n: bigint, nBitLength?: number) {
358
+ export function nLength(
359
+ n: bigint,
360
+ nBitLength?: number
361
+ ): {
362
+ nBitLength: number;
363
+ nByteLength: number;
364
+ } {
338
365
  // Bit size, byte size of CURVE.n
339
366
  const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length;
340
367
  const nByteLength = Math.ceil(_nBitLength / 8);
@@ -343,15 +370,15 @@ export function nLength(n: bigint, nBitLength?: number) {
343
370
 
344
371
  type FpField = IField<bigint> & Required<Pick<IField<bigint>, 'isOdd'>>;
345
372
  /**
346
- * Initializes a finite field over prime. **Non-primes are not supported.**
347
- * Do not init in loop: slow. Very fragile: always run a benchmark on a change.
373
+ * Initializes a finite field over prime.
348
374
  * Major performance optimizations:
349
375
  * * a) denormalized operations like mulN instead of mul
350
376
  * * b) same object shape: never add or remove keys
351
377
  * * c) Object.freeze
352
- * NOTE: operations don't check 'isValid' for all elements for performance reasons,
378
+ * Fragile: always run a benchmark on a change.
379
+ * Security note: operations don't check 'isValid' for all elements for performance reasons,
353
380
  * it is caller responsibility to check this.
354
- * This is low-level code, please make sure you know what you doing.
381
+ * This is low-level code, please make sure you know what you're doing.
355
382
  * @param ORDER prime positive bigint
356
383
  * @param bitLen how many bits the field consumes
357
384
  * @param isLE (def: false) if encoding / decoding should be in little-endian
@@ -369,6 +396,7 @@ export function Field(
369
396
  let sqrtP: ReturnType<typeof FpSqrt>; // cached sqrtP
370
397
  const f: Readonly<FpField> = Object.freeze({
371
398
  ORDER,
399
+ isLE,
372
400
  BITS,
373
401
  BYTES,
374
402
  MASK: bitMask(BITS),
@@ -419,13 +447,13 @@ export function Field(
419
447
  return Object.freeze(f);
420
448
  }
421
449
 
422
- export function FpSqrtOdd<T>(Fp: IField<T>, elm: T) {
450
+ export function FpSqrtOdd<T>(Fp: IField<T>, elm: T): T {
423
451
  if (!Fp.isOdd) throw new Error("Field doesn't have isOdd");
424
452
  const root = Fp.sqrt(elm);
425
453
  return Fp.isOdd(root) ? root : Fp.neg(root);
426
454
  }
427
455
 
428
- export function FpSqrtEven<T>(Fp: IField<T>, elm: T) {
456
+ export function FpSqrtEven<T>(Fp: IField<T>, elm: T): T {
429
457
  if (!Fp.isOdd) throw new Error("Field doesn't have isOdd");
430
458
  const root = Fp.sqrt(elm);
431
459
  return Fp.isOdd(root) ? Fp.neg(root) : root;
@@ -435,7 +463,7 @@ export function FpSqrtEven<T>(Fp: IField<T>, elm: T) {
435
463
  * "Constant-time" private key generation utility.
436
464
  * Same as mapKeyToField, but accepts less bytes (40 instead of 48 for 32-byte field).
437
465
  * Which makes it slightly more biased, less secure.
438
- * @deprecated use mapKeyToField instead
466
+ * @deprecated use `mapKeyToField` instead
439
467
  */
440
468
  export function hashToPrivateScalar(
441
469
  hash: string | Uint8Array,
@@ -497,7 +525,7 @@ export function mapHashToField(key: Uint8Array, fieldOrder: bigint, isLE = false
497
525
  // No small numbers: need to understand bias story. No huge numbers: easier to detect JS timings.
498
526
  if (len < 16 || len < minLen || len > 1024)
499
527
  throw new Error('expected ' + minLen + '-1024 bytes of input, got ' + len);
500
- const num = isLE ? bytesToNumberBE(key) : bytesToNumberLE(key);
528
+ const num = isLE ? bytesToNumberLE(key) : bytesToNumberBE(key);
501
529
  // `mod(x, 11)` can sometimes produce 0. `mod(x, 10) + 1` is the same, but no 0
502
530
  const reduced = mod(num, fieldOrder - _1n) + _1n;
503
531
  return isLE ? numberToBytesLE(reduced, fieldLen) : numberToBytesBE(reduced, fieldLen);
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Montgomery curve methods. It's not really whole montgomery curve,
3
+ * just bunch of very specific methods for X25519 / X448 from
4
+ * [RFC 7748](https://www.rfc-editor.org/rfc/rfc7748)
5
+ * @module
6
+ */
1
7
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
8
  import { mod, pow } from './modular.js';
3
9
  import {
@@ -24,6 +30,7 @@ export type CurveType = {
24
30
  Gu: bigint;
25
31
  randomBytes?: (bytesLength?: number) => Uint8Array;
26
32
  };
33
+
27
34
  export type CurveFn = {
28
35
  scalarMult: (scalar: Hex, u: Hex) => Uint8Array;
29
36
  scalarMultBase: (scalar: Hex) => Uint8Array;
@@ -52,7 +59,6 @@ function validateOpts(curve: CurveType) {
52
59
  return Object.freeze({ ...curve } as const);
53
60
  }
54
61
 
55
- // NOTE: not really montgomery curve, just bunch of very specific methods for X25519/X448 (RFC 7748, https://www.rfc-editor.org/rfc/rfc7748)
56
62
  // Uses only one coordinate instead of two
57
63
  export function montgomery(curveDef: CurveType): CurveFn {
58
64
  const CURVE = validateOpts(curveDef);
@@ -1,8 +1,14 @@
1
+ /**
2
+ * Implements [Poseidon](https://www.poseidon-hash.info) ZK-friendly hash.
3
+ *
4
+ * There are many poseidon variants with different constants.
5
+ * We don't provide them: you should construct them manually.
6
+ * Check out [micro-starknet](https://github.com/paulmillr/micro-starknet) package for a proper example.
7
+ * @module
8
+ */
1
9
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
- // Poseidon Hash: https://eprint.iacr.org/2019/458.pdf, https://www.poseidon-hash.info
3
- import { FpPow, IField, validateField } from './modular.js';
4
- // We don't provide any constants, since different implementations use different constants.
5
- // For reference constants see './test/poseidon.test.js'.
10
+ import { FpPow, type IField, validateField } from './modular.js';
11
+
6
12
  export type PoseidonOpts = {
7
13
  Fp: IField<bigint>;
8
14
  t: number;
@@ -14,7 +20,18 @@ export type PoseidonOpts = {
14
20
  roundConstants: bigint[][];
15
21
  };
16
22
 
17
- export function validateOpts(opts: PoseidonOpts) {
23
+ export function validateOpts(opts: PoseidonOpts): Readonly<{
24
+ rounds: number;
25
+ sboxFn: (n: bigint) => bigint;
26
+ roundConstants: bigint[][];
27
+ mds: bigint[][];
28
+ Fp: IField<bigint>;
29
+ t: number;
30
+ roundsFull: number;
31
+ roundsPartial: number;
32
+ sboxPower?: number;
33
+ reversePartialPowIdx?: boolean; // Hack for stark
34
+ }> {
18
35
  const { Fp, mds, reversePartialPowIdx: rev, roundConstants: rc } = opts;
19
36
  const { roundsFull, roundsPartial, sboxPower, t } = opts;
20
37
 
@@ -61,7 +78,7 @@ export function validateOpts(opts: PoseidonOpts) {
61
78
  return Object.freeze({ ...opts, rounds, sboxFn, roundConstants, mds: _mds });
62
79
  }
63
80
 
64
- export function splitConstants(rc: bigint[], t: number) {
81
+ export function splitConstants(rc: bigint[], t: number): bigint[][] {
65
82
  if (typeof t !== 'number') throw new Error('poseidonSplitConstants: invalid t');
66
83
  if (!Array.isArray(rc) || rc.length % t) throw new Error('poseidonSplitConstants: invalid rc');
67
84
  const res = [];
@@ -76,7 +93,12 @@ export function splitConstants(rc: bigint[], t: number) {
76
93
  return res;
77
94
  }
78
95
 
79
- export function poseidon(opts: PoseidonOpts) {
96
+ /** Poseidon NTT-friendly hash. */
97
+ export function poseidon(opts: PoseidonOpts): {
98
+ (values: bigint[]): bigint[];
99
+ // For verification in tests
100
+ roundConstants: bigint[][];
101
+ } {
80
102
  const _opts = validateOpts(opts);
81
103
  const { Fp, mds, roundConstants, rounds: totalRounds, roundsPartial, sboxFn, t } = _opts;
82
104
  const halfRoundsFull = _opts.roundsFull / 2;
@@ -1,20 +1,19 @@
1
+ /**
2
+ * Towered extension fields.
3
+ * Rather than implementing a massive 12th-degree extension directly, it is more efficient
4
+ * to build it up from smaller extensions: a tower of extensions.
5
+ *
6
+ * For BLS12-381, the Fp12 field is implemented as a quadratic (degree two) extension,
7
+ * on top of a cubic (degree three) extension, on top of a quadratic extension of Fp.
8
+ *
9
+ * For more info: "Pairings for beginners" by Costello, section 7.3.
10
+ * @module
11
+ */
1
12
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
13
  import * as mod from './modular.js';
3
14
  import { bitLen, bitMask, concatBytes, notImplemented } from './utils.js';
4
15
  import type { ProjConstructor, ProjPointType } from './weierstrass.js';
5
16
 
6
- /*
7
- Towered extension fields
8
-
9
- Rather than implementing a massive 12th-degree extension directly, it is more efficient
10
- to build it up from smaller extensions: a tower of extensions.
11
-
12
- For BLS12-381, the Fp12 field is implemented as a quadratic (degree two) extension,
13
- on top of a cubic (degree three) extension, on top of a quadratic extension of Fp.
14
-
15
- For more info: "Pairings for beginners" by Costello, section 7.3.
16
- */
17
-
18
17
  // Be friendly to bad ECMAScript parsers by not using bigint literals
19
18
  // prettier-ignore
20
19
  const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3);
@@ -75,7 +74,20 @@ function calcFrobeniusCoefficients<T>(
75
74
  }
76
75
 
77
76
  // This works same at least for bls12-381, bn254 and bls12-377
78
- export function psiFrobenius(Fp: mod.IField<Fp>, Fp2: Fp2Bls, base: Fp2) {
77
+ export function psiFrobenius(
78
+ Fp: mod.IField<Fp>,
79
+ Fp2: Fp2Bls,
80
+ base: Fp2
81
+ ): {
82
+ psi: (x: Fp2, y: Fp2) => [Fp2, Fp2];
83
+ psi2: (x: Fp2, y: Fp2) => [Fp2, Fp2];
84
+ G2psi: (c: ProjConstructor<Fp2>, P: ProjPointType<Fp2>) => ProjPointType<Fp2>;
85
+ G2psi2: (c: ProjConstructor<Fp2>, P: ProjPointType<Fp2>) => ProjPointType<Fp2>;
86
+ PSI_X: Fp2;
87
+ PSI_Y: Fp2;
88
+ PSI2_X: Fp2;
89
+ PSI2_Y: Fp2;
90
+ } {
79
91
  // Ψ endomorphism
80
92
  const PSI_X = Fp2.pow(base, (Fp.ORDER - _1n) / _3n); // u^((p-1)/3)
81
93
  const PSI_Y = Fp2.pow(base, (Fp.ORDER - _1n) / _2n); // u^((p-1)/2)
@@ -120,7 +132,37 @@ export type Tower12Opts = {
120
132
  Fp12finalExponentiate: (num: Fp12) => Fp12;
121
133
  };
122
134
 
123
- export function tower12(opts: Tower12Opts) {
135
+ export function tower12(opts: Tower12Opts): {
136
+ Fp: Readonly<mod.IField<bigint> & Required<Pick<mod.IField<bigint>, 'isOdd'>>>;
137
+ Fp2: mod.IField<Fp2> & {
138
+ NONRESIDUE: Fp2;
139
+ fromBigTuple: (tuple: BigintTuple | bigint[]) => Fp2;
140
+ reim: (num: Fp2) => { re: bigint; im: bigint };
141
+ mulByNonresidue: (num: Fp2) => Fp2;
142
+ mulByB: (num: Fp2) => Fp2;
143
+ frobeniusMap(num: Fp2, power: number): Fp2;
144
+ };
145
+ Fp6: mod.IField<Fp6> & {
146
+ fromBigSix: (tuple: BigintSix) => Fp6;
147
+ mulByNonresidue: (num: Fp6) => Fp6;
148
+ frobeniusMap(num: Fp6, power: number): Fp6;
149
+ mul1(num: Fp6, b1: Fp2): Fp6;
150
+ mul01(num: Fp6, b0: Fp2, b1: Fp2): Fp6;
151
+ mulByFp2(lhs: Fp6, rhs: Fp2): Fp6;
152
+ };
153
+ Fp4Square: (a: Fp2, b: Fp2) => { first: Fp2; second: Fp2 };
154
+ Fp12: mod.IField<Fp12> & {
155
+ fromBigTwelve: (t: BigintTwelve) => Fp12;
156
+ frobeniusMap(num: Fp12, power: number): Fp12;
157
+ mul014(num: Fp12, o0: Fp2, o1: Fp2, o4: Fp2): Fp12;
158
+ mul034(num: Fp12, o0: Fp2, o3: Fp2, o4: Fp2): Fp12;
159
+ mulByFp2(lhs: Fp12, rhs: Fp2): Fp12;
160
+ conjugate(num: Fp12): Fp12;
161
+ finalExponentiate(num: Fp12): Fp12;
162
+ _cyclotomicSquare(num: Fp12): Fp12;
163
+ _cyclotomicExp(num: Fp12, n: bigint): Fp12;
164
+ };
165
+ } {
124
166
  const { ORDER } = opts;
125
167
  // Fp
126
168
  const Fp = mod.Field(ORDER);
@@ -173,6 +215,7 @@ export function tower12(opts: Tower12Opts) {
173
215
  const Fp2Nonresidue = Fp2fromBigTuple(opts.FP2_NONRESIDUE);
174
216
  const Fp2: mod.IField<Fp2> & Fp2Utils = {
175
217
  ORDER: FP2_ORDER,
218
+ isLE: Fp.isLE,
176
219
  NONRESIDUE: Fp2Nonresidue,
177
220
  BITS: bitLen(FP2_ORDER),
178
221
  BYTES: Math.ceil(bitLen(FP2_ORDER) / 8),
@@ -339,6 +382,7 @@ export function tower12(opts: Tower12Opts) {
339
382
 
340
383
  const Fp6: mod.IField<Fp6> & Fp6Utils = {
341
384
  ORDER: Fp2.ORDER, // TODO: unused, but need to verify
385
+ isLE: Fp2.isLE,
342
386
  BITS: 3 * Fp2.BITS,
343
387
  BYTES: 3 * Fp2.BYTES,
344
388
  MASK: bitMask(3 * Fp2.BITS),
@@ -495,6 +539,7 @@ export function tower12(opts: Tower12Opts) {
495
539
 
496
540
  const Fp12: mod.IField<Fp12> & Fp12Utils = {
497
541
  ORDER: Fp2.ORDER, // TODO: unused, but need to verify
542
+ isLE: Fp6.isLE,
498
543
  BITS: 2 * Fp2.BITS,
499
544
  BYTES: 2 * Fp2.BYTES,
500
545
  MASK: bitMask(2 * Fp2.BITS),
@@ -1,4 +1,9 @@
1
+ /**
2
+ * Hex, bytes and number utilities.
3
+ * @module
4
+ */
1
5
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
6
+
2
7
  // 100 lines of code in the file are duplicated from noble-hashes (utils).
3
8
  // This is OK: `abstract` directory does not use noble-hashes.
4
9
  // User may opt-in into using different hashing library. This way, noble-hashes
@@ -155,7 +160,7 @@ export function concatBytes(...arrays: Uint8Array[]): Uint8Array {
155
160
  }
156
161
 
157
162
  // Compares 2 u8a-s in kinda constant time
158
- export function equalBytes(a: Uint8Array, b: Uint8Array) {
163
+ export function equalBytes(a: Uint8Array, b: Uint8Array): boolean {
159
164
  if (a.length !== b.length) return false;
160
165
  let diff = 0;
161
166
  for (let i = 0; i < a.length; i++) diff |= a[i] ^ b[i];
@@ -177,7 +182,7 @@ export function utf8ToBytes(str: string): Uint8Array {
177
182
  // Is positive bigint
178
183
  const isPosBig = (n: bigint) => typeof n === 'bigint' && _0n <= n;
179
184
 
180
- export function inRange(n: bigint, min: bigint, max: bigint) {
185
+ export function inRange(n: bigint, min: bigint, max: bigint): boolean {
181
186
  return isPosBig(n) && isPosBig(min) && isPosBig(max) && min <= n && n < max;
182
187
  }
183
188
 
@@ -186,7 +191,7 @@ export function inRange(n: bigint, min: bigint, max: bigint) {
186
191
  * @example
187
192
  * aInRange('x', x, 1n, 256n); // would assume x is in (1n..255n)
188
193
  */
189
- export function aInRange(title: string, n: bigint, min: bigint, max: bigint) {
194
+ export function aInRange(title: string, n: bigint, min: bigint, max: bigint): void {
190
195
  // Why min <= n < max and not a (min < n < max) OR b (min <= n <= max)?
191
196
  // consider P=256n, min=0n, max=P
192
197
  // - a for min=0 would require -1: `inRange('x', x, -1n, P)`
@@ -202,7 +207,7 @@ export function aInRange(title: string, n: bigint, min: bigint, max: bigint) {
202
207
  * Calculates amount of bits in a bigint.
203
208
  * Same as `n.toString(2).length`
204
209
  */
205
- export function bitLen(n: bigint) {
210
+ export function bitLen(n: bigint): number {
206
211
  let len;
207
212
  for (len = 0; n > _0n; n >>= _1n, len += 1);
208
213
  return len;
@@ -213,14 +218,14 @@ export function bitLen(n: bigint) {
213
218
  * NOTE: first bit position is 0 (same as arrays)
214
219
  * Same as `!!+Array.from(n.toString(2)).reverse()[pos]`
215
220
  */
216
- export function bitGet(n: bigint, pos: number) {
221
+ export function bitGet(n: bigint, pos: number): bigint {
217
222
  return (n >> BigInt(pos)) & _1n;
218
223
  }
219
224
 
220
225
  /**
221
226
  * Sets single bit at position.
222
227
  */
223
- export function bitSet(n: bigint, pos: number, value: boolean) {
228
+ export function bitSet(n: bigint, pos: number, value: boolean): bigint {
224
229
  return n | ((value ? _1n : _0n) << BigInt(pos));
225
230
  }
226
231
 
@@ -228,7 +233,7 @@ export function bitSet(n: bigint, pos: number, value: boolean) {
228
233
  * Calculate mask for N bits. Not using ** operator with bigints because of old engines.
229
234
  * Same as BigInt(`0b${Array(i).fill('1').join('')}`)
230
235
  */
231
- export const bitMask = (n: number) => (_2n << BigInt(n - 1)) - _1n;
236
+ export const bitMask = (n: number): bigint => (_2n << BigInt(n - 1)) - _1n;
232
237
 
233
238
  // DRBG
234
239
 
@@ -295,15 +300,15 @@ export function createHmacDrbg<T>(
295
300
  // Validating curves and fields
296
301
 
297
302
  const validatorFns = {
298
- bigint: (val: any) => typeof val === 'bigint',
299
- function: (val: any) => typeof val === 'function',
300
- boolean: (val: any) => typeof val === 'boolean',
301
- string: (val: any) => typeof val === 'string',
302
- stringOrUint8Array: (val: any) => typeof val === 'string' || isBytes(val),
303
- isSafeInteger: (val: any) => Number.isSafeInteger(val),
304
- array: (val: any) => Array.isArray(val),
305
- field: (val: any, object: any) => (object as any).Fp.isValid(val),
306
- hash: (val: any) => typeof val === 'function' && Number.isSafeInteger(val.outputLen),
303
+ bigint: (val: any): boolean => typeof val === 'bigint',
304
+ function: (val: any): boolean => typeof val === 'function',
305
+ boolean: (val: any): boolean => typeof val === 'boolean',
306
+ string: (val: any): boolean => typeof val === 'string',
307
+ stringOrUint8Array: (val: any): boolean => typeof val === 'string' || isBytes(val),
308
+ isSafeInteger: (val: any): boolean => Number.isSafeInteger(val),
309
+ array: (val: any): boolean => Array.isArray(val),
310
+ field: (val: any, object: any): any => (object as any).Fp.isValid(val),
311
+ hash: (val: any): boolean => typeof val === 'function' && Number.isSafeInteger(val.outputLen),
307
312
  } as const;
308
313
  type Validator = keyof typeof validatorFns;
309
314
  type ValMap<T extends Record<string, any>> = { [K in keyof T]?: Validator };
@@ -313,7 +318,7 @@ export function validateObject<T extends Record<string, any>>(
313
318
  object: T,
314
319
  validators: ValMap<T>,
315
320
  optValidators: ValMap<T> = {}
316
- ) {
321
+ ): T {
317
322
  const checkField = (fieldName: keyof T, type: Validator, isOptional: boolean) => {
318
323
  const checkVal = validatorFns[type];
319
324
  if (typeof checkVal !== 'function') throw new Error('invalid validator function');
@@ -342,7 +347,7 @@ export function validateObject<T extends Record<string, any>>(
342
347
  /**
343
348
  * throws not implemented error
344
349
  */
345
- export const notImplemented = () => {
350
+ export const notImplemented = (): never => {
346
351
  throw new Error('not implemented');
347
352
  };
348
353
 
@@ -350,7 +355,9 @@ export const notImplemented = () => {
350
355
  * Memoizes (caches) computation result.
351
356
  * Uses WeakMap: the value is going auto-cleaned by GC after last reference is removed.
352
357
  */
353
- export function memoized<T extends object, R, O extends any[]>(fn: (arg: T, ...args: O) => R) {
358
+ export function memoized<T extends object, R, O extends any[]>(
359
+ fn: (arg: T, ...args: O) => R
360
+ ): (arg: T, ...args: O) => R {
354
361
  const map = new WeakMap<T, R>();
355
362
  return (arg: T, ...args: O): R => {
356
363
  const val = map.get(arg);