@noble/curves 1.8.2 → 1.9.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 (199) hide show
  1. package/README.md +49 -24
  2. package/abstract/bls.js +1 -1
  3. package/abstract/bls.js.map +1 -1
  4. package/abstract/curve.d.ts +1 -1
  5. package/abstract/curve.d.ts.map +1 -1
  6. package/abstract/curve.js +13 -4
  7. package/abstract/curve.js.map +1 -1
  8. package/abstract/edwards.d.ts.map +1 -1
  9. package/abstract/edwards.js +17 -3
  10. package/abstract/edwards.js.map +1 -1
  11. package/abstract/fft.d.ts +120 -0
  12. package/abstract/fft.d.ts.map +1 -0
  13. package/abstract/fft.js +439 -0
  14. package/abstract/fft.js.map +1 -0
  15. package/abstract/hash-to-curve.d.ts +10 -5
  16. package/abstract/hash-to-curve.d.ts.map +1 -1
  17. package/abstract/hash-to-curve.js +31 -23
  18. package/abstract/hash-to-curve.js.map +1 -1
  19. package/abstract/modular.d.ts +13 -12
  20. package/abstract/modular.d.ts.map +1 -1
  21. package/abstract/modular.js +158 -158
  22. package/abstract/modular.js.map +1 -1
  23. package/abstract/montgomery.d.ts +4 -9
  24. package/abstract/montgomery.d.ts.map +1 -1
  25. package/abstract/montgomery.js +70 -90
  26. package/abstract/montgomery.js.map +1 -1
  27. package/abstract/poseidon.d.ts +39 -2
  28. package/abstract/poseidon.d.ts.map +1 -1
  29. package/abstract/poseidon.js +183 -4
  30. package/abstract/poseidon.js.map +1 -1
  31. package/abstract/tower.d.ts.map +1 -1
  32. package/abstract/tower.js +4 -5
  33. package/abstract/tower.js.map +1 -1
  34. package/abstract/utils.d.ts +1 -0
  35. package/abstract/utils.d.ts.map +1 -1
  36. package/abstract/utils.js +2 -0
  37. package/abstract/utils.js.map +1 -1
  38. package/abstract/weierstrass.d.ts +31 -9
  39. package/abstract/weierstrass.d.ts.map +1 -1
  40. package/abstract/weierstrass.js +67 -48
  41. package/abstract/weierstrass.js.map +1 -1
  42. package/bls12-381.d.ts.map +1 -1
  43. package/bls12-381.js +9 -23
  44. package/bls12-381.js.map +1 -1
  45. package/bn254.d.ts +1 -0
  46. package/bn254.d.ts.map +1 -1
  47. package/bn254.js +10 -0
  48. package/bn254.js.map +1 -1
  49. package/ed25519.d.ts +19 -5
  50. package/ed25519.d.ts.map +1 -1
  51. package/ed25519.js +29 -18
  52. package/ed25519.js.map +1 -1
  53. package/ed448.d.ts +21 -5
  54. package/ed448.d.ts.map +1 -1
  55. package/ed448.js +46 -34
  56. package/ed448.js.map +1 -1
  57. package/esm/abstract/bls.js +1 -1
  58. package/esm/abstract/bls.js.map +1 -1
  59. package/esm/abstract/curve.d.ts +1 -1
  60. package/esm/abstract/curve.d.ts.map +1 -1
  61. package/esm/abstract/curve.js +13 -4
  62. package/esm/abstract/curve.js.map +1 -1
  63. package/esm/abstract/edwards.d.ts.map +1 -1
  64. package/esm/abstract/edwards.js +19 -5
  65. package/esm/abstract/edwards.js.map +1 -1
  66. package/esm/abstract/fft.d.ts +120 -0
  67. package/esm/abstract/fft.d.ts.map +1 -0
  68. package/esm/abstract/fft.js +426 -0
  69. package/esm/abstract/fft.js.map +1 -0
  70. package/esm/abstract/hash-to-curve.d.ts +10 -5
  71. package/esm/abstract/hash-to-curve.d.ts.map +1 -1
  72. package/esm/abstract/hash-to-curve.js +32 -24
  73. package/esm/abstract/hash-to-curve.js.map +1 -1
  74. package/esm/abstract/modular.d.ts +13 -12
  75. package/esm/abstract/modular.d.ts.map +1 -1
  76. package/esm/abstract/modular.js +158 -158
  77. package/esm/abstract/modular.js.map +1 -1
  78. package/esm/abstract/montgomery.d.ts +4 -9
  79. package/esm/abstract/montgomery.d.ts.map +1 -1
  80. package/esm/abstract/montgomery.js +71 -91
  81. package/esm/abstract/montgomery.js.map +1 -1
  82. package/esm/abstract/poseidon.d.ts +39 -2
  83. package/esm/abstract/poseidon.d.ts.map +1 -1
  84. package/esm/abstract/poseidon.js +180 -5
  85. package/esm/abstract/poseidon.js.map +1 -1
  86. package/esm/abstract/tower.d.ts.map +1 -1
  87. package/esm/abstract/tower.js +4 -5
  88. package/esm/abstract/tower.js.map +1 -1
  89. package/esm/abstract/utils.d.ts +1 -0
  90. package/esm/abstract/utils.d.ts.map +1 -1
  91. package/esm/abstract/utils.js +2 -0
  92. package/esm/abstract/utils.js.map +1 -1
  93. package/esm/abstract/weierstrass.d.ts +31 -9
  94. package/esm/abstract/weierstrass.d.ts.map +1 -1
  95. package/esm/abstract/weierstrass.js +69 -50
  96. package/esm/abstract/weierstrass.js.map +1 -1
  97. package/esm/bls12-381.d.ts.map +1 -1
  98. package/esm/bls12-381.js +9 -23
  99. package/esm/bls12-381.js.map +1 -1
  100. package/esm/bn254.d.ts +1 -0
  101. package/esm/bn254.d.ts.map +1 -1
  102. package/esm/bn254.js +10 -0
  103. package/esm/bn254.js.map +1 -1
  104. package/esm/ed25519.d.ts +19 -5
  105. package/esm/ed25519.d.ts.map +1 -1
  106. package/esm/ed25519.js +29 -18
  107. package/esm/ed25519.js.map +1 -1
  108. package/esm/ed448.d.ts +21 -5
  109. package/esm/ed448.d.ts.map +1 -1
  110. package/esm/ed448.js +47 -35
  111. package/esm/ed448.js.map +1 -1
  112. package/esm/jubjub.d.ts +11 -1
  113. package/esm/jubjub.d.ts.map +1 -1
  114. package/esm/jubjub.js +11 -1
  115. package/esm/jubjub.js.map +1 -1
  116. package/esm/misc.d.ts +8 -2
  117. package/esm/misc.d.ts.map +1 -1
  118. package/esm/misc.js +10 -4
  119. package/esm/misc.js.map +1 -1
  120. package/esm/nist.d.ts +30 -0
  121. package/esm/nist.d.ts.map +1 -0
  122. package/esm/nist.js +121 -0
  123. package/esm/nist.js.map +1 -0
  124. package/esm/p256.d.ts +7 -9
  125. package/esm/p256.d.ts.map +1 -1
  126. package/esm/p256.js +6 -44
  127. package/esm/p256.js.map +1 -1
  128. package/esm/p384.d.ts +9 -10
  129. package/esm/p384.d.ts.map +1 -1
  130. package/esm/p384.js +7 -46
  131. package/esm/p384.js.map +1 -1
  132. package/esm/p521.d.ts +7 -8
  133. package/esm/p521.d.ts.map +1 -1
  134. package/esm/p521.js +6 -46
  135. package/esm/p521.js.map +1 -1
  136. package/esm/pasta.d.ts +9 -1
  137. package/esm/pasta.d.ts.map +1 -1
  138. package/esm/pasta.js +9 -1
  139. package/esm/pasta.js.map +1 -1
  140. package/esm/secp256k1.d.ts +3 -3
  141. package/esm/secp256k1.d.ts.map +1 -1
  142. package/esm/secp256k1.js +8 -9
  143. package/esm/secp256k1.js.map +1 -1
  144. package/jubjub.d.ts +11 -1
  145. package/jubjub.d.ts.map +1 -1
  146. package/jubjub.js +12 -5
  147. package/jubjub.js.map +1 -1
  148. package/misc.d.ts +8 -2
  149. package/misc.d.ts.map +1 -1
  150. package/misc.js +11 -5
  151. package/misc.js.map +1 -1
  152. package/nist.d.ts +30 -0
  153. package/nist.d.ts.map +1 -0
  154. package/nist.js +124 -0
  155. package/nist.js.map +1 -0
  156. package/p256.d.ts +7 -9
  157. package/p256.d.ts.map +1 -1
  158. package/p256.js +5 -49
  159. package/p256.js.map +1 -1
  160. package/p384.d.ts +9 -10
  161. package/p384.d.ts.map +1 -1
  162. package/p384.js +6 -51
  163. package/p384.js.map +1 -1
  164. package/p521.d.ts +7 -8
  165. package/p521.d.ts.map +1 -1
  166. package/p521.js +5 -51
  167. package/p521.js.map +1 -1
  168. package/package.json +117 -8
  169. package/pasta.d.ts +9 -1
  170. package/pasta.d.ts.map +1 -1
  171. package/pasta.js +9 -3
  172. package/pasta.js.map +1 -1
  173. package/secp256k1.d.ts +3 -3
  174. package/secp256k1.d.ts.map +1 -1
  175. package/secp256k1.js +9 -10
  176. package/secp256k1.js.map +1 -1
  177. package/src/abstract/bls.ts +1 -1
  178. package/src/abstract/curve.ts +11 -6
  179. package/src/abstract/edwards.ts +26 -12
  180. package/src/abstract/fft.ts +508 -0
  181. package/src/abstract/hash-to-curve.ts +44 -36
  182. package/src/abstract/modular.ts +154 -153
  183. package/src/abstract/montgomery.ts +78 -109
  184. package/src/abstract/poseidon.ts +208 -13
  185. package/src/abstract/tower.ts +4 -5
  186. package/src/abstract/utils.ts +2 -0
  187. package/src/abstract/weierstrass.ts +109 -61
  188. package/src/bls12-381.ts +11 -27
  189. package/src/bn254.ts +10 -0
  190. package/src/ed25519.ts +32 -19
  191. package/src/ed448.ts +91 -75
  192. package/src/jubjub.ts +12 -5
  193. package/src/misc.ts +10 -4
  194. package/src/nist.ts +155 -0
  195. package/src/p256.ts +6 -50
  196. package/src/p384.ts +8 -56
  197. package/src/p521.ts +6 -65
  198. package/src/pasta.ts +9 -1
  199. package/src/secp256k1.ts +12 -11
@@ -5,6 +5,7 @@
5
5
  * @module
6
6
  */
7
7
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
8
+ import { anumber } from '@noble/hashes/utils';
8
9
  import {
9
10
  bitMask,
10
11
  bytesToNumberBE,
@@ -19,8 +20,6 @@ import {
19
20
  const _0n = BigInt(0), _1n = BigInt(1), _2n = /* @__PURE__ */ BigInt(2), _3n = /* @__PURE__ */ BigInt(3);
20
21
  // prettier-ignore
21
22
  const _4n = /* @__PURE__ */ BigInt(4), _5n = /* @__PURE__ */ BigInt(5), _8n = /* @__PURE__ */ BigInt(8);
22
- // prettier-ignore
23
- const _9n =/* @__PURE__ */ BigInt(9), _16n = /* @__PURE__ */ BigInt(16);
24
23
 
25
24
  // Calculates a modulo b
26
25
  export function mod(a: bigint, b: bigint): bigint {
@@ -30,21 +29,12 @@ export function mod(a: bigint, b: bigint): bigint {
30
29
  /**
31
30
  * Efficiently raise num to power and do modular division.
32
31
  * Unsafe in some contexts: uses ladder, so can expose bigint bits.
33
- * @todo use field version && remove
32
+ * TODO: remove.
34
33
  * @example
35
34
  * pow(2n, 6n, 11n) // 64n % 11n == 9n
36
35
  */
37
36
  export function pow(num: bigint, power: bigint, modulo: bigint): bigint {
38
- if (power < _0n) throw new Error('invalid exponent, negatives unsupported');
39
- if (modulo <= _0n) throw new Error('invalid modulus');
40
- if (modulo === _1n) return _0n;
41
- let res = _1n;
42
- while (power > _0n) {
43
- if (power & _1n) res = (res * num) % modulo;
44
- num = (num * num) % modulo;
45
- power >>= _1n;
46
- }
47
- return res;
37
+ return FpPow(Field(modulo), num, power);
48
38
  }
49
39
 
50
40
  /** Does `x^(2^power)` mod p. `pow2(30, 4)` == `30^(2^4)` */
@@ -83,138 +73,141 @@ export function invert(number: bigint, modulo: bigint): bigint {
83
73
  return mod(x, modulo);
84
74
  }
85
75
 
76
+ // Not all roots are possible! Example which will throw:
77
+ // const NUM =
78
+ // n = 72057594037927816n;
79
+ // Fp = Field(BigInt('0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab'));
80
+ function sqrt3mod4<T>(Fp: IField<T>, n: T) {
81
+ const p1div4 = (Fp.ORDER + _1n) / _4n;
82
+ const root = Fp.pow(n, p1div4);
83
+ // Throw if root^2 != n
84
+ if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');
85
+ return root;
86
+ }
87
+
88
+ function sqrt5mod8<T>(Fp: IField<T>, n: T) {
89
+ const p5div8 = (Fp.ORDER - _5n) / _8n;
90
+ const n2 = Fp.mul(n, _2n);
91
+ const v = Fp.pow(n2, p5div8);
92
+ const nv = Fp.mul(n, v);
93
+ const i = Fp.mul(Fp.mul(nv, _2n), v);
94
+ const root = Fp.mul(nv, Fp.sub(i, Fp.ONE));
95
+ if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');
96
+ return root;
97
+ }
98
+
99
+ // TODO: Commented-out for now. Provide test vectors.
100
+ // Tonelli is too slow for extension fields Fp2.
101
+ // That means we can't use sqrt (c1, c2...) even for initialization constants.
102
+ // if (P % _16n === _9n) return sqrt9mod16;
103
+ // // prettier-ignore
104
+ // function sqrt9mod16<T>(Fp: IField<T>, n: T, p7div16?: bigint) {
105
+ // if (p7div16 === undefined) p7div16 = (Fp.ORDER + BigInt(7)) / _16n;
106
+ // const c1 = Fp.sqrt(Fp.neg(Fp.ONE)); // 1. c1 = sqrt(-1) in F, i.e., (c1^2) == -1 in F
107
+ // const c2 = Fp.sqrt(c1); // 2. c2 = sqrt(c1) in F, i.e., (c2^2) == c1 in F
108
+ // const c3 = Fp.sqrt(Fp.neg(c1)); // 3. c3 = sqrt(-c1) in F, i.e., (c3^2) == -c1 in F
109
+ // const c4 = p7div16; // 4. c4 = (q + 7) / 16 # Integer arithmetic
110
+ // let tv1 = Fp.pow(n, c4); // 1. tv1 = x^c4
111
+ // let tv2 = Fp.mul(c1, tv1); // 2. tv2 = c1 * tv1
112
+ // const tv3 = Fp.mul(c2, tv1); // 3. tv3 = c2 * tv1
113
+ // let tv4 = Fp.mul(c3, tv1); // 4. tv4 = c3 * tv1
114
+ // const e1 = Fp.eql(Fp.sqr(tv2), n); // 5. e1 = (tv2^2) == x
115
+ // const e2 = Fp.eql(Fp.sqr(tv3), n); // 6. e2 = (tv3^2) == x
116
+ // tv1 = Fp.cmov(tv1, tv2, e1); // 7. tv1 = CMOV(tv1, tv2, e1) # Select tv2 if (tv2^2) == x
117
+ // tv2 = Fp.cmov(tv4, tv3, e2); // 8. tv2 = CMOV(tv4, tv3, e2) # Select tv3 if (tv3^2) == x
118
+ // const e3 = Fp.eql(Fp.sqr(tv2), n); // 9. e3 = (tv2^2) == x
119
+ // return Fp.cmov(tv1, tv2, e3); // 10. z = CMOV(tv1, tv2, e3) # Select the sqrt from tv1 and tv2
120
+ // }
121
+
86
122
  /**
87
123
  * Tonelli-Shanks square root search algorithm.
88
124
  * 1. https://eprint.iacr.org/2012/685.pdf (page 12)
89
125
  * 2. Square Roots from 1; 24, 51, 10 to Dan Shanks
90
- * Will start an infinite loop if field order P is not prime.
91
126
  * @param P field order
92
127
  * @returns function that takes field Fp (created from P) and number n
93
128
  */
94
129
  export function tonelliShanks(P: bigint): <T>(Fp: IField<T>, n: T) => T {
95
- // Legendre constant: used to calculate Legendre symbol (a | p),
96
- // which denotes the value of a^((p-1)/2) (mod p).
97
- // (a | p) 1 if a is a square (mod p)
98
- // (a | p) -1 if a is not a square (mod p)
99
- // (a | p) ≡ 0 if a ≡ 0 (mod p)
100
- const legendreC = (P - _1n) / _2n;
101
-
102
- let Q: bigint, S: number, Z: bigint;
103
- // Step 1: By factoring out powers of 2 from p - 1,
104
- // find q and s such that p - 1 = q*(2^s) with q odd
105
- for (Q = P - _1n, S = 0; Q % _2n === _0n; Q /= _2n, S++);
106
-
107
- // Step 2: Select a non-square z such that (z | p) ≡ -1 and set c ≡ zq
108
- for (Z = _2n; Z < P && pow(Z, legendreC, P) !== P - _1n; Z++) {
109
- // Crash instead of infinity loop, we cannot reasonable count until P.
110
- if (Z > 1000) throw new Error('Cannot find square root: likely non-prime P');
130
+ // Initialization (precomputation).
131
+ if (P < BigInt(3)) throw new Error('sqrt is not defined for small field');
132
+ // Factor P - 1 = Q * 2^S, where Q is odd
133
+ let Q = P - _1n;
134
+ let S = 0;
135
+ while (Q % _2n === _0n) {
136
+ Q /= _2n;
137
+ S++;
111
138
  }
112
139
 
113
- // Fast-path
114
- if (S === 1) {
115
- const p1div4 = (P + _1n) / _4n;
116
- return function tonelliFast<T>(Fp: IField<T>, n: T) {
117
- const root = Fp.pow(n, p1div4);
118
- if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');
119
- return root;
120
- };
140
+ // Find the first quadratic non-residue Z >= 2
141
+ let Z = _2n;
142
+ const _Fp = Field(P);
143
+ while (FpLegendre(_Fp, Z) === 1) {
144
+ // Basic primality test for P. After x iterations, chance of
145
+ // not finding quadratic non-residue is 2^x, so 2^1000.
146
+ if (Z++ > 1000) throw new Error('Cannot find square root: probably non-prime P');
121
147
  }
148
+ // Fast-path; usually done before Z, but we do "primality test".
149
+ if (S === 1) return sqrt3mod4;
122
150
 
123
151
  // Slow-path
152
+ // TODO: test on Fp2 and others
153
+ let cc = _Fp.pow(Z, Q); // c = z^Q
124
154
  const Q1div2 = (Q + _1n) / _2n;
125
155
  return function tonelliSlow<T>(Fp: IField<T>, n: T): T {
126
- // Step 0: Check that n is indeed a square: (n | p) should not be ≡ -1
127
- if (Fp.pow(n, legendreC) === Fp.neg(Fp.ONE)) throw new Error('Cannot find square root');
128
- let r = S;
129
- // TODO: will fail at Fp2/etc
130
- let g = Fp.pow(Fp.mul(Fp.ONE, Z), Q); // will update both x and b
131
- let x = Fp.pow(n, Q1div2); // first guess at the square root
132
- let b = Fp.pow(n, Q); // first guess at the fudge factor
133
-
134
- while (!Fp.eql(b, Fp.ONE)) {
135
- if (Fp.eql(b, Fp.ZERO)) return Fp.ZERO; // https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm (4. If t = 0, return r = 0)
136
- // Find m such b^(2^m)==1
137
- let m = 1;
138
- for (let t2 = Fp.sqr(b); m < r; m++) {
139
- if (Fp.eql(t2, Fp.ONE)) break;
140
- t2 = Fp.sqr(t2); // t2 *= t2
156
+ if (Fp.is0(n)) return n;
157
+ // Check if n is a quadratic residue using Legendre symbol
158
+ if (FpLegendre(Fp, n) !== 1) throw new Error('Cannot find square root');
159
+
160
+ // Initialize variables for the main loop
161
+ let M = S;
162
+ let c = Fp.mul(Fp.ONE, cc); // c = z^Q, move cc from field _Fp into field Fp
163
+ let t = Fp.pow(n, Q); // t = n^Q, first guess at the fudge factor
164
+ let R = Fp.pow(n, Q1div2); // R = n^((Q+1)/2), first guess at the square root
165
+
166
+ // Main loop
167
+ // while t != 1
168
+ while (!Fp.eql(t, Fp.ONE)) {
169
+ if (Fp.is0(t)) return Fp.ZERO; // if t=0 return R=0
170
+ let i = 1;
171
+
172
+ // Find the smallest i >= 1 such that t^(2^i) ≡ 1 (mod P)
173
+ let t_tmp = Fp.sqr(t); // t^(2^1)
174
+ while (!Fp.eql(t_tmp, Fp.ONE)) {
175
+ i++;
176
+ t_tmp = Fp.sqr(t_tmp); // t^(2^2)...
177
+ if (i === M) throw new Error('Cannot find square root');
141
178
  }
142
- // NOTE: r-m-1 can be bigger than 32, need to convert to bigint before shift, otherwise there will be overflow
143
- const ge = Fp.pow(g, _1n << BigInt(r - m - 1)); // ge = 2^(r-m-1)
144
- g = Fp.sqr(ge); // g = ge * ge
145
- x = Fp.mul(x, ge); // x *= ge
146
- b = Fp.mul(b, g); // b *= g
147
- r = m;
179
+
180
+ // Calculate the exponent for b: 2^(M - i - 1)
181
+ const exponent = _1n << BigInt(M - i - 1); // bigint is important
182
+ const b = Fp.pow(c, exponent); // b = 2^(M - i - 1)
183
+
184
+ // Update variables
185
+ M = i;
186
+ c = Fp.sqr(b); // c = b^2
187
+ t = Fp.mul(t, c); // t = (t * b^2)
188
+ R = Fp.mul(R, b); // R = R*b
148
189
  }
149
- return x;
190
+ return R;
150
191
  };
151
192
  }
152
193
 
153
194
  /**
154
- * Square root for a finite field. It will try to check if optimizations are applicable and fall back to 4:
195
+ * Square root for a finite field. Will try optimized versions first:
155
196
  *
156
197
  * 1. P ≡ 3 (mod 4)
157
198
  * 2. P ≡ 5 (mod 8)
158
- * 3. P ≡ 9 (mod 16)
159
- * 4. Tonelli-Shanks algorithm
199
+ * 3. Tonelli-Shanks algorithm
160
200
  *
161
201
  * Different algorithms can give different roots, it is up to user to decide which one they want.
162
202
  * For example there is FpSqrtOdd/FpSqrtEven to choice root based on oddness (used for hash-to-curve).
163
203
  */
164
204
  export function FpSqrt(P: bigint): <T>(Fp: IField<T>, n: T) => T {
165
- // P ≡ 3 (mod 4)
166
- // √n = n^((P+1)/4)
167
- if (P % _4n === _3n) {
168
- // Not all roots possible!
169
- // const ORDER =
170
- // 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn;
171
- // const NUM = 72057594037927816n;
172
- const p1div4 = (P + _1n) / _4n;
173
- return function sqrt3mod4<T>(Fp: IField<T>, n: T) {
174
- const root = Fp.pow(n, p1div4);
175
- // Throw if root**2 != n
176
- if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');
177
- return root;
178
- };
179
- }
180
-
181
- // Atkin algorithm for q ≡ 5 (mod 8), https://eprint.iacr.org/2012/685.pdf (page 10)
182
- if (P % _8n === _5n) {
183
- const c1 = (P - _5n) / _8n;
184
- return function sqrt5mod8<T>(Fp: IField<T>, n: T) {
185
- const n2 = Fp.mul(n, _2n);
186
- const v = Fp.pow(n2, c1);
187
- const nv = Fp.mul(n, v);
188
- const i = Fp.mul(Fp.mul(nv, _2n), v);
189
- const root = Fp.mul(nv, Fp.sub(i, Fp.ONE));
190
- if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');
191
- return root;
192
- };
193
- }
194
-
195
- // P ≡ 9 (mod 16)
196
- if (P % _16n === _9n) {
197
- // NOTE: tonelli is too slow for bls-Fp2 calculations even on start
198
- // Means we cannot use sqrt for constants at all!
199
- //
200
- // const c1 = Fp.sqrt(Fp.negate(Fp.ONE)); // 1. c1 = sqrt(-1) in F, i.e., (c1^2) == -1 in F
201
- // const c2 = Fp.sqrt(c1); // 2. c2 = sqrt(c1) in F, i.e., (c2^2) == c1 in F
202
- // const c3 = Fp.sqrt(Fp.negate(c1)); // 3. c3 = sqrt(-c1) in F, i.e., (c3^2) == -c1 in F
203
- // const c4 = (P + _7n) / _16n; // 4. c4 = (q + 7) / 16 # Integer arithmetic
204
- // sqrt = (x) => {
205
- // let tv1 = Fp.pow(x, c4); // 1. tv1 = x^c4
206
- // let tv2 = Fp.mul(c1, tv1); // 2. tv2 = c1 * tv1
207
- // const tv3 = Fp.mul(c2, tv1); // 3. tv3 = c2 * tv1
208
- // let tv4 = Fp.mul(c3, tv1); // 4. tv4 = c3 * tv1
209
- // const e1 = Fp.equals(Fp.square(tv2), x); // 5. e1 = (tv2^2) == x
210
- // const e2 = Fp.equals(Fp.square(tv3), x); // 6. e2 = (tv3^2) == x
211
- // tv1 = Fp.cmov(tv1, tv2, e1); // 7. tv1 = CMOV(tv1, tv2, e1) # Select tv2 if (tv2^2) == x
212
- // tv2 = Fp.cmov(tv4, tv3, e2); // 8. tv2 = CMOV(tv4, tv3, e2) # Select tv3 if (tv3^2) == x
213
- // const e3 = Fp.equals(Fp.square(tv2), x); // 9. e3 = (tv2^2) == x
214
- // return Fp.cmov(tv1, tv2, e3); // 10. z = CMOV(tv1, tv2, e3) # Select the sqrt from tv1 and tv2
215
- // }
216
- }
217
- // Other cases: Tonelli-Shanks algorithm
205
+ // P ≡ 3 (mod 4) => √n = n^((P+1)/4)
206
+ if (P % _4n === _3n) return sqrt3mod4;
207
+ // P 5 (mod 8) => Atkin algorithm, page 10 of https://eprint.iacr.org/2012/685.pdf
208
+ if (P % _8n === _5n) return sqrt5mod8;
209
+ // P 9 (mod 16) not implemented, see above
210
+ // Tonelli-Shanks algorithm
218
211
  return tonelliShanks(P);
219
212
  }
220
213
 
@@ -258,7 +251,6 @@ export interface IField<T> {
258
251
  // NOTE: sgn0 is 'negative in LE', which is same as odd. And negative in LE is kinda strange definition anyway.
259
252
  isOdd?(num: T): boolean; // Odd instead of even since we have it for Fp2
260
253
  // legendre?(num: T): T;
261
- pow(lhs: T, power: bigint): T;
262
254
  invertBatch: (lst: T[]) => T[];
263
255
  toBytes(num: T): Uint8Array;
264
256
  fromBytes(bytes: Uint8Array): T;
@@ -291,17 +283,15 @@ export function validateField<T>(field: IField<T>): IField<T> {
291
283
  * Same as `pow` but for Fp: non-constant-time.
292
284
  * Unsafe in some contexts: uses ladder, so can expose bigint bits.
293
285
  */
294
- export function FpPow<T>(f: IField<T>, num: T, power: bigint): T {
295
- // Should have same speed as pow for bigints
296
- // TODO: benchmark!
286
+ export function FpPow<T>(Fp: IField<T>, num: T, power: bigint): T {
297
287
  if (power < _0n) throw new Error('invalid exponent, negatives unsupported');
298
- if (power === _0n) return f.ONE;
288
+ if (power === _0n) return Fp.ONE;
299
289
  if (power === _1n) return num;
300
- let p = f.ONE;
290
+ let p = Fp.ONE;
301
291
  let d = num;
302
292
  while (power > _0n) {
303
- if (power & _1n) p = f.mul(p, d);
304
- d = f.sqr(d);
293
+ if (power & _1n) p = Fp.mul(p, d);
294
+ d = Fp.sqr(d);
305
295
  power >>= _1n;
306
296
  }
307
297
  return p;
@@ -309,49 +299,58 @@ export function FpPow<T>(f: IField<T>, num: T, power: bigint): T {
309
299
 
310
300
  /**
311
301
  * Efficiently invert an array of Field elements.
312
- * `inv(0)` will return `undefined` here: make sure to throw an error.
302
+ * Exception-free. Will return `undefined` for 0 elements.
303
+ * @param passZero map 0 to 0 (instead of undefined)
313
304
  */
314
- export function FpInvertBatch<T>(f: IField<T>, nums: T[]): T[] {
315
- const tmp = new Array(nums.length);
305
+ export function FpInvertBatch<T>(Fp: IField<T>, nums: T[], passZero = false): T[] {
306
+ const inverted = new Array(nums.length).fill(passZero ? Fp.ZERO : undefined);
316
307
  // Walk from first to last, multiply them by each other MOD p
317
- const lastMultiplied = nums.reduce((acc, num, i) => {
318
- if (f.is0(num)) return acc;
319
- tmp[i] = acc;
320
- return f.mul(acc, num);
321
- }, f.ONE);
308
+ const multipliedAcc = nums.reduce((acc, num, i) => {
309
+ if (Fp.is0(num)) return acc;
310
+ inverted[i] = acc;
311
+ return Fp.mul(acc, num);
312
+ }, Fp.ONE);
322
313
  // Invert last element
323
- const inverted = f.inv(lastMultiplied);
314
+ const invertedAcc = Fp.inv(multipliedAcc);
324
315
  // Walk from last to first, multiply them by inverted each other MOD p
325
316
  nums.reduceRight((acc, num, i) => {
326
- if (f.is0(num)) return acc;
327
- tmp[i] = f.mul(acc, tmp[i]);
328
- return f.mul(acc, num);
329
- }, inverted);
330
- return tmp;
317
+ if (Fp.is0(num)) return acc;
318
+ inverted[i] = Fp.mul(acc, inverted[i]);
319
+ return Fp.mul(acc, num);
320
+ }, invertedAcc);
321
+ return inverted;
331
322
  }
332
323
 
333
- export function FpDiv<T>(f: IField<T>, lhs: T, rhs: T | bigint): T {
334
- return f.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, f.ORDER) : f.inv(rhs));
324
+ // TODO: remove
325
+ export function FpDiv<T>(Fp: IField<T>, lhs: T, rhs: T | bigint): T {
326
+ return Fp.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, Fp.ORDER) : Fp.inv(rhs));
335
327
  }
336
328
 
337
329
  /**
338
330
  * Legendre symbol.
331
+ * Legendre constant is used to calculate Legendre symbol (a | p)
332
+ * which denotes the value of a^((p-1)/2) (mod p).
333
+ *
339
334
  * * (a | p) ≡ 1 if a is a square (mod p), quadratic residue
340
335
  * * (a | p) ≡ -1 if a is not a square (mod p), quadratic non residue
341
336
  * * (a | p) ≡ 0 if a ≡ 0 (mod p)
342
337
  */
343
- export function FpLegendre(order: bigint): <T>(f: IField<T>, x: T) => T {
344
- const legendreConst = (order - _1n) / _2n; // Integer arithmetic
345
- return <T>(f: IField<T>, x: T): T => f.pow(x, legendreConst);
338
+ export function FpLegendre<T>(Fp: IField<T>, n: T): -1 | 0 | 1 {
339
+ // We can use 3rd argument as optional cache of this value
340
+ // but seems unneeded for now. The operation is very fast.
341
+ const p1mod2 = (Fp.ORDER - _1n) / _2n;
342
+ const powered = Fp.pow(n, p1mod2);
343
+ const yes = Fp.eql(powered, Fp.ONE);
344
+ const zero = Fp.eql(powered, Fp.ZERO);
345
+ const no = Fp.eql(powered, Fp.neg(Fp.ONE));
346
+ if (!yes && !zero && !no) throw new Error('invalid Legendre symbol result');
347
+ return yes ? 1 : zero ? 0 : -1;
346
348
  }
347
349
 
348
350
  // This function returns True whenever the value x is a square in the field F.
349
- export function FpIsSquare<T>(f: IField<T>): (x: T) => boolean {
350
- const legendre = FpLegendre(f.ORDER);
351
- return (x: T): boolean => {
352
- const p = legendre(f, x);
353
- return f.eql(p, f.ZERO) || f.eql(p, f.ONE);
354
- };
351
+ export function FpIsSquare<T>(Fp: IField<T>, n: T): boolean {
352
+ const l = FpLegendre(Fp, n);
353
+ return l === 1;
355
354
  }
356
355
 
357
356
  // CURVE.n lengths
@@ -363,6 +362,7 @@ export function nLength(
363
362
  nByteLength: number;
364
363
  } {
365
364
  // Bit size, byte size of CURVE.n
365
+ if (nBitLength !== undefined) anumber(nBitLength);
366
366
  const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length;
367
367
  const nByteLength = Math.ceil(_nBitLength / 8);
368
368
  return { nBitLength: _nBitLength, nByteLength };
@@ -433,16 +433,17 @@ export function Field(
433
433
  if (!sqrtP) sqrtP = FpSqrt(ORDER);
434
434
  return sqrtP(f, n);
435
435
  }),
436
- invertBatch: (lst) => FpInvertBatch(f, lst),
437
- // TODO: do we really need constant cmov?
438
- // We don't have const-time bigints anyway, so probably will be not very useful
439
- cmov: (a, b, c) => (c ? b : a),
440
436
  toBytes: (num) => (isLE ? numberToBytesLE(num, BYTES) : numberToBytesBE(num, BYTES)),
441
437
  fromBytes: (bytes) => {
442
438
  if (bytes.length !== BYTES)
443
439
  throw new Error('Field.fromBytes: expected ' + BYTES + ' bytes, got ' + bytes.length);
444
440
  return isLE ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes);
445
441
  },
442
+ // TODO: we don't need it here, move out to separate fn
443
+ invertBatch: (lst) => FpInvertBatch(f, lst),
444
+ // We can't move this out because Fp6, Fp12 implement it
445
+ // and it's unclear what to return in there.
446
+ cmov: (a, b, c) => (c ? b : a),
446
447
  } as FpField);
447
448
  return Object.freeze(f);
448
449
  }