@noble/curves 1.9.0 → 1.9.2

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 (207) hide show
  1. package/README.md +78 -34
  2. package/_shortw_utils.d.ts +7 -5
  3. package/_shortw_utils.d.ts.map +1 -1
  4. package/_shortw_utils.js +2 -8
  5. package/_shortw_utils.js.map +1 -1
  6. package/abstract/bls.d.ts +60 -24
  7. package/abstract/bls.d.ts.map +1 -1
  8. package/abstract/bls.js +158 -109
  9. package/abstract/bls.js.map +1 -1
  10. package/abstract/curve.d.ts +44 -9
  11. package/abstract/curve.d.ts.map +1 -1
  12. package/abstract/curve.js +99 -11
  13. package/abstract/curve.js.map +1 -1
  14. package/abstract/edwards.d.ts +112 -25
  15. package/abstract/edwards.d.ts.map +1 -1
  16. package/abstract/edwards.js +141 -92
  17. package/abstract/edwards.js.map +1 -1
  18. package/abstract/fft.d.ts +122 -0
  19. package/abstract/fft.d.ts.map +1 -0
  20. package/abstract/fft.js +438 -0
  21. package/abstract/fft.js.map +1 -0
  22. package/abstract/hash-to-curve.d.ts +25 -11
  23. package/abstract/hash-to-curve.d.ts.map +1 -1
  24. package/abstract/hash-to-curve.js +17 -14
  25. package/abstract/hash-to-curve.js.map +1 -1
  26. package/abstract/modular.d.ts +28 -17
  27. package/abstract/modular.d.ts.map +1 -1
  28. package/abstract/modular.js +156 -139
  29. package/abstract/modular.js.map +1 -1
  30. package/abstract/montgomery.d.ts +3 -8
  31. package/abstract/montgomery.d.ts.map +1 -1
  32. package/abstract/montgomery.js +73 -93
  33. package/abstract/montgomery.js.map +1 -1
  34. package/abstract/poseidon.d.ts +5 -13
  35. package/abstract/poseidon.d.ts.map +1 -1
  36. package/abstract/poseidon.js +12 -7
  37. package/abstract/poseidon.js.map +1 -1
  38. package/abstract/tower.d.ts +20 -46
  39. package/abstract/tower.d.ts.map +1 -1
  40. package/abstract/tower.js +10 -4
  41. package/abstract/tower.js.map +1 -1
  42. package/abstract/utils.d.ts +1 -115
  43. package/abstract/utils.d.ts.map +1 -1
  44. package/abstract/utils.js +17 -371
  45. package/abstract/utils.js.map +1 -1
  46. package/abstract/weierstrass.d.ts +152 -73
  47. package/abstract/weierstrass.d.ts.map +1 -1
  48. package/abstract/weierstrass.js +487 -404
  49. package/abstract/weierstrass.js.map +1 -1
  50. package/bls12-381.d.ts +2 -0
  51. package/bls12-381.d.ts.map +1 -1
  52. package/bls12-381.js +504 -480
  53. package/bls12-381.js.map +1 -1
  54. package/bn254.d.ts +2 -0
  55. package/bn254.d.ts.map +1 -1
  56. package/bn254.js +44 -32
  57. package/bn254.js.map +1 -1
  58. package/ed25519.d.ts +25 -9
  59. package/ed25519.d.ts.map +1 -1
  60. package/ed25519.js +89 -65
  61. package/ed25519.js.map +1 -1
  62. package/ed448.d.ts +29 -10
  63. package/ed448.d.ts.map +1 -1
  64. package/ed448.js +116 -81
  65. package/ed448.js.map +1 -1
  66. package/esm/_shortw_utils.d.ts +7 -5
  67. package/esm/_shortw_utils.d.ts.map +1 -1
  68. package/esm/_shortw_utils.js +2 -8
  69. package/esm/_shortw_utils.js.map +1 -1
  70. package/esm/abstract/bls.d.ts +60 -24
  71. package/esm/abstract/bls.d.ts.map +1 -1
  72. package/esm/abstract/bls.js +158 -109
  73. package/esm/abstract/bls.js.map +1 -1
  74. package/esm/abstract/curve.d.ts +44 -9
  75. package/esm/abstract/curve.d.ts.map +1 -1
  76. package/esm/abstract/curve.js +96 -12
  77. package/esm/abstract/curve.js.map +1 -1
  78. package/esm/abstract/edwards.d.ts +112 -25
  79. package/esm/abstract/edwards.d.ts.map +1 -1
  80. package/esm/abstract/edwards.js +141 -94
  81. package/esm/abstract/edwards.js.map +1 -1
  82. package/esm/abstract/fft.d.ts +122 -0
  83. package/esm/abstract/fft.d.ts.map +1 -0
  84. package/esm/abstract/fft.js +425 -0
  85. package/esm/abstract/fft.js.map +1 -0
  86. package/esm/abstract/hash-to-curve.d.ts +25 -11
  87. package/esm/abstract/hash-to-curve.d.ts.map +1 -1
  88. package/esm/abstract/hash-to-curve.js +17 -14
  89. package/esm/abstract/hash-to-curve.js.map +1 -1
  90. package/esm/abstract/modular.d.ts +28 -17
  91. package/esm/abstract/modular.d.ts.map +1 -1
  92. package/esm/abstract/modular.js +155 -138
  93. package/esm/abstract/modular.js.map +1 -1
  94. package/esm/abstract/montgomery.d.ts +3 -8
  95. package/esm/abstract/montgomery.d.ts.map +1 -1
  96. package/esm/abstract/montgomery.js +74 -94
  97. package/esm/abstract/montgomery.js.map +1 -1
  98. package/esm/abstract/poseidon.d.ts +5 -13
  99. package/esm/abstract/poseidon.d.ts.map +1 -1
  100. package/esm/abstract/poseidon.js +12 -7
  101. package/esm/abstract/poseidon.js.map +1 -1
  102. package/esm/abstract/tower.d.ts +20 -46
  103. package/esm/abstract/tower.d.ts.map +1 -1
  104. package/esm/abstract/tower.js +10 -4
  105. package/esm/abstract/tower.js.map +1 -1
  106. package/esm/abstract/utils.d.ts +1 -115
  107. package/esm/abstract/utils.d.ts.map +1 -1
  108. package/esm/abstract/utils.js +3 -344
  109. package/esm/abstract/utils.js.map +1 -1
  110. package/esm/abstract/weierstrass.d.ts +152 -73
  111. package/esm/abstract/weierstrass.d.ts.map +1 -1
  112. package/esm/abstract/weierstrass.js +485 -406
  113. package/esm/abstract/weierstrass.js.map +1 -1
  114. package/esm/bls12-381.d.ts +2 -0
  115. package/esm/bls12-381.d.ts.map +1 -1
  116. package/esm/bls12-381.js +503 -479
  117. package/esm/bls12-381.js.map +1 -1
  118. package/esm/bn254.d.ts +2 -0
  119. package/esm/bn254.d.ts.map +1 -1
  120. package/esm/bn254.js +41 -29
  121. package/esm/bn254.js.map +1 -1
  122. package/esm/ed25519.d.ts +25 -9
  123. package/esm/ed25519.d.ts.map +1 -1
  124. package/esm/ed25519.js +84 -60
  125. package/esm/ed25519.js.map +1 -1
  126. package/esm/ed448.d.ts +29 -10
  127. package/esm/ed448.d.ts.map +1 -1
  128. package/esm/ed448.js +113 -78
  129. package/esm/ed448.js.map +1 -1
  130. package/esm/jubjub.d.ts +4 -0
  131. package/esm/jubjub.d.ts.map +1 -1
  132. package/esm/jubjub.js +4 -0
  133. package/esm/jubjub.js.map +1 -1
  134. package/esm/misc.d.ts.map +1 -1
  135. package/esm/misc.js +31 -26
  136. package/esm/misc.js.map +1 -1
  137. package/esm/nist.d.ts +8 -16
  138. package/esm/nist.d.ts.map +1 -1
  139. package/esm/nist.js +87 -97
  140. package/esm/nist.js.map +1 -1
  141. package/esm/p256.d.ts +3 -3
  142. package/esm/p384.d.ts +3 -3
  143. package/esm/p521.d.ts +3 -3
  144. package/esm/pasta.d.ts +4 -0
  145. package/esm/pasta.d.ts.map +1 -1
  146. package/esm/pasta.js +4 -0
  147. package/esm/pasta.js.map +1 -1
  148. package/esm/secp256k1.d.ts +6 -6
  149. package/esm/secp256k1.d.ts.map +1 -1
  150. package/esm/secp256k1.js +44 -41
  151. package/esm/secp256k1.js.map +1 -1
  152. package/esm/utils.d.ts +96 -0
  153. package/esm/utils.d.ts.map +1 -0
  154. package/esm/utils.js +279 -0
  155. package/esm/utils.js.map +1 -0
  156. package/jubjub.d.ts +4 -0
  157. package/jubjub.d.ts.map +1 -1
  158. package/jubjub.js +4 -0
  159. package/jubjub.js.map +1 -1
  160. package/misc.d.ts.map +1 -1
  161. package/misc.js +35 -30
  162. package/misc.js.map +1 -1
  163. package/nist.d.ts +8 -16
  164. package/nist.d.ts.map +1 -1
  165. package/nist.js +87 -97
  166. package/nist.js.map +1 -1
  167. package/p256.d.ts +3 -3
  168. package/p384.d.ts +3 -3
  169. package/p521.d.ts +3 -3
  170. package/package.json +26 -8
  171. package/pasta.d.ts +4 -0
  172. package/pasta.d.ts.map +1 -1
  173. package/pasta.js +4 -0
  174. package/pasta.js.map +1 -1
  175. package/secp256k1.d.ts +6 -6
  176. package/secp256k1.d.ts.map +1 -1
  177. package/secp256k1.js +47 -44
  178. package/secp256k1.js.map +1 -1
  179. package/src/_shortw_utils.ts +5 -15
  180. package/src/abstract/bls.ts +260 -145
  181. package/src/abstract/curve.ts +125 -18
  182. package/src/abstract/edwards.ts +282 -127
  183. package/src/abstract/fft.ts +519 -0
  184. package/src/abstract/hash-to-curve.ts +51 -27
  185. package/src/abstract/modular.ts +156 -143
  186. package/src/abstract/montgomery.ts +81 -111
  187. package/src/abstract/poseidon.ts +22 -18
  188. package/src/abstract/tower.ts +37 -68
  189. package/src/abstract/utils.ts +3 -378
  190. package/src/abstract/weierstrass.ts +752 -461
  191. package/src/bls12-381.ts +542 -507
  192. package/src/bn254.ts +47 -35
  193. package/src/ed25519.ts +104 -76
  194. package/src/ed448.ts +156 -105
  195. package/src/jubjub.ts +4 -0
  196. package/src/misc.ts +39 -34
  197. package/src/nist.ts +138 -126
  198. package/src/p256.ts +3 -3
  199. package/src/p384.ts +3 -3
  200. package/src/p521.ts +3 -3
  201. package/src/pasta.ts +5 -1
  202. package/src/secp256k1.ts +59 -47
  203. package/src/utils.ts +328 -0
  204. package/utils.d.ts +96 -0
  205. package/utils.d.ts.map +1 -0
  206. package/utils.js +313 -0
  207. package/utils.js.map +1 -0
@@ -1,27 +1,26 @@
1
1
  /**
2
- * Utils for modular division and finite fields.
3
- * A finite field over 11 is integer number operations `mod 11`.
2
+ * Utils for modular division and fields.
3
+ * Field over 11 is a finite (Galois) field is integer number operations `mod 11`.
4
4
  * There is no division: it is replaced by modular multiplicative inverse.
5
5
  * @module
6
6
  */
7
7
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
8
- import { anumber } from '@noble/hashes/utils';
9
8
  import {
9
+ _validateObject,
10
+ anumber,
10
11
  bitMask,
11
12
  bytesToNumberBE,
12
13
  bytesToNumberLE,
13
14
  ensureBytes,
14
15
  numberToBytesBE,
15
16
  numberToBytesLE,
16
- validateObject,
17
- } from './utils.ts';
17
+ } from '../utils.ts';
18
18
 
19
19
  // prettier-ignore
20
20
  const _0n = BigInt(0), _1n = BigInt(1), _2n = /* @__PURE__ */ BigInt(2), _3n = /* @__PURE__ */ BigInt(3);
21
21
  // prettier-ignore
22
- const _4n = /* @__PURE__ */ BigInt(4), _5n = /* @__PURE__ */ BigInt(5), _8n = /* @__PURE__ */ BigInt(8);
23
- // prettier-ignore
24
- const _9n =/* @__PURE__ */ BigInt(9), _16n = /* @__PURE__ */ BigInt(16);
22
+ const _4n = /* @__PURE__ */ BigInt(4), _5n = /* @__PURE__ */ BigInt(5);
23
+ const _8n = /* @__PURE__ */ BigInt(8);
25
24
 
26
25
  // Calculates a modulo b
27
26
  export function mod(a: bigint, b: bigint): bigint {
@@ -31,21 +30,11 @@ export function mod(a: bigint, b: bigint): bigint {
31
30
  /**
32
31
  * Efficiently raise num to power and do modular division.
33
32
  * Unsafe in some contexts: uses ladder, so can expose bigint bits.
34
- * TODO: remove.
35
33
  * @example
36
34
  * pow(2n, 6n, 11n) // 64n % 11n == 9n
37
35
  */
38
36
  export function pow(num: bigint, power: bigint, modulo: bigint): bigint {
39
- if (power < _0n) throw new Error('invalid exponent, negatives unsupported');
40
- if (modulo <= _0n) throw new Error('invalid modulus');
41
- if (modulo === _1n) return _0n;
42
- let res = _1n;
43
- while (power > _0n) {
44
- if (power & _1n) res = (res * num) % modulo;
45
- num = (num * num) % modulo;
46
- power >>= _1n;
47
- }
48
- return res;
37
+ return FpPow(Field(modulo), num, power);
49
38
  }
50
39
 
51
40
  /** Does `x^(2^power)` mod p. `pow2(30, 4)` == `30^(2^4)` */
@@ -84,6 +73,52 @@ export function invert(number: bigint, modulo: bigint): bigint {
84
73
  return mod(x, modulo);
85
74
  }
86
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
+
87
122
  /**
88
123
  * Tonelli-Shanks square root search algorithm.
89
124
  * 1. https://eprint.iacr.org/2012/685.pdf (page 12)
@@ -92,9 +127,10 @@ export function invert(number: bigint, modulo: bigint): bigint {
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
- // Do expensive precomputation step
96
- // Step 1: By factoring out powers of 2 from p - 1,
97
- // find q and s such that p-1 == q*(2^s) with q odd
130
+ // Initialization (precomputation).
131
+ // Caching initialization could boost perf by 7%.
132
+ if (P < BigInt(3)) throw new Error('sqrt is not defined for small field');
133
+ // Factor P - 1 = Q * 2^S, where Q is odd
98
134
  let Q = P - _1n;
99
135
  let S = 0;
100
136
  while (Q % _2n === _0n) {
@@ -102,120 +138,77 @@ export function tonelliShanks(P: bigint): <T>(Fp: IField<T>, n: T) => T {
102
138
  S++;
103
139
  }
104
140
 
105
- // Step 2: Select a non-square z such that (z | p) ≡ -1 and set c ≡ zq
141
+ // Find the first quadratic non-residue Z >= 2
106
142
  let Z = _2n;
107
143
  const _Fp = Field(P);
108
- while (Z < P && FpIsSquare(_Fp, Z)) {
144
+ while (FpLegendre(_Fp, Z) === 1) {
145
+ // Basic primality test for P. After x iterations, chance of
146
+ // not finding quadratic non-residue is 2^x, so 2^1000.
109
147
  if (Z++ > 1000) throw new Error('Cannot find square root: probably non-prime P');
110
148
  }
149
+ // Fast-path; usually done before Z, but we do "primality test".
150
+ if (S === 1) return sqrt3mod4;
111
151
 
112
- // Fast-path
113
- if (S === 1) {
114
- const p1div4 = (P + _1n) / _4n;
115
- return function tonelliFast<T>(Fp: IField<T>, n: T) {
116
- const root = Fp.pow(n, p1div4);
117
- if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');
118
- return root;
119
- };
120
- }
121
152
  // Slow-path
153
+ // TODO: test on Fp2 and others
154
+ let cc = _Fp.pow(Z, Q); // c = z^Q
122
155
  const Q1div2 = (Q + _1n) / _2n;
123
156
  return function tonelliSlow<T>(Fp: IField<T>, n: T): T {
124
- // Step 0: Check that n is indeed a square: (n | p) should not be ≡ -1
125
- if (!FpIsSquare(Fp, n)) throw new Error('Cannot find square root');
126
- let r = S;
127
- // TODO: test on Fp2 and others
128
- let g = Fp.pow(Fp.mul(Fp.ONE, Z), Q); // will update both x and b
129
- let x = Fp.pow(n, Q1div2); // first guess at the square root
130
- let b = Fp.pow(n, Q); // first guess at the fudge factor
131
-
132
- while (!Fp.eql(b, Fp.ONE)) {
133
- // (4. If t = 0, return r = 0)
134
- // https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm
135
- if (Fp.eql(b, Fp.ZERO)) return Fp.ZERO;
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
157
+ if (Fp.is0(n)) return n;
158
+ // Check if n is a quadratic residue using Legendre symbol
159
+ if (FpLegendre(Fp, n) !== 1) throw new Error('Cannot find square root');
160
+
161
+ // Initialize variables for the main loop
162
+ let M = S;
163
+ let c = Fp.mul(Fp.ONE, cc); // c = z^Q, move cc from field _Fp into field Fp
164
+ let t = Fp.pow(n, Q); // t = n^Q, first guess at the fudge factor
165
+ let R = Fp.pow(n, Q1div2); // R = n^((Q+1)/2), first guess at the square root
166
+
167
+ // Main loop
168
+ // while t != 1
169
+ while (!Fp.eql(t, Fp.ONE)) {
170
+ if (Fp.is0(t)) return Fp.ZERO; // if t=0 return R=0
171
+ let i = 1;
172
+
173
+ // Find the smallest i >= 1 such that t^(2^i) 1 (mod P)
174
+ let t_tmp = Fp.sqr(t); // t^(2^1)
175
+ while (!Fp.eql(t_tmp, Fp.ONE)) {
176
+ i++;
177
+ t_tmp = Fp.sqr(t_tmp); // t^(2^2)...
178
+ if (i === M) throw new Error('Cannot find square root');
141
179
  }
142
- // NOTE: r-m-1 can be bigger than 32, need to convert to bigint before shift,
143
- // otherwise there will be overflow.
144
- const ge = Fp.pow(g, _1n << BigInt(r - m - 1)); // ge = 2^(r-m-1)
145
- g = Fp.sqr(ge); // g = ge * ge
146
- x = Fp.mul(x, ge); // x *= ge
147
- b = Fp.mul(b, g); // b *= g
148
- r = m;
180
+
181
+ // Calculate the exponent for b: 2^(M - i - 1)
182
+ const exponent = _1n << BigInt(M - i - 1); // bigint is important
183
+ const b = Fp.pow(c, exponent); // b = 2^(M - i - 1)
184
+
185
+ // Update variables
186
+ M = i;
187
+ c = Fp.sqr(b); // c = b^2
188
+ t = Fp.mul(t, c); // t = (t * b^2)
189
+ R = Fp.mul(R, b); // R = R*b
149
190
  }
150
- return x;
191
+ return R;
151
192
  };
152
193
  }
153
194
 
154
195
  /**
155
- * Square root for a finite field. It will try to check if optimizations are applicable and fall back to 4:
196
+ * Square root for a finite field. Will try optimized versions first:
156
197
  *
157
198
  * 1. P ≡ 3 (mod 4)
158
199
  * 2. P ≡ 5 (mod 8)
159
- * 3. P ≡ 9 (mod 16)
160
- * 4. Tonelli-Shanks algorithm
200
+ * 3. Tonelli-Shanks algorithm
161
201
  *
162
202
  * Different algorithms can give different roots, it is up to user to decide which one they want.
163
203
  * For example there is FpSqrtOdd/FpSqrtEven to choice root based on oddness (used for hash-to-curve).
164
204
  */
165
205
  export function FpSqrt(P: bigint): <T>(Fp: IField<T>, n: T) => T {
166
- // P ≡ 3 (mod 4)
167
- // √n = n^((P+1)/4)
168
- if (P % _4n === _3n) {
169
- // Not all roots possible!
170
- // const ORDER =
171
- // 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn;
172
- // const NUM = 72057594037927816n;
173
- return function sqrt3mod4<T>(Fp: IField<T>, n: T) {
174
- const p1div4 = (P + _1n) / _4n;
175
- const root = Fp.pow(n, p1div4);
176
- // Throw if root**2 != n
177
- if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');
178
- return root;
179
- };
180
- }
181
-
182
- // Atkin algorithm for q ≡ 5 (mod 8), https://eprint.iacr.org/2012/685.pdf (page 10)
183
- if (P % _8n === _5n) {
184
- return function sqrt5mod8<T>(Fp: IField<T>, n: T) {
185
- const n2 = Fp.mul(n, _2n);
186
- const c1 = (P - _5n) / _8n;
187
- const v = Fp.pow(n2, c1);
188
- const nv = Fp.mul(n, v);
189
- const i = Fp.mul(Fp.mul(nv, _2n), v);
190
- const root = Fp.mul(nv, Fp.sub(i, Fp.ONE));
191
- if (!Fp.eql(Fp.sqr(root), n)) throw new Error('Cannot find square root');
192
- return root;
193
- };
194
- }
195
-
196
- // P ≡ 9 (mod 16)
197
- if (P % _16n === _9n) {
198
- // NOTE: tonelli is too slow for bls-Fp2 calculations even on start
199
- // Means we cannot use sqrt for constants at all!
200
- //
201
- // const c1 = Fp.sqrt(Fp.negate(Fp.ONE)); // 1. c1 = sqrt(-1) in F, i.e., (c1^2) == -1 in F
202
- // const c2 = Fp.sqrt(c1); // 2. c2 = sqrt(c1) in F, i.e., (c2^2) == c1 in F
203
- // const c3 = Fp.sqrt(Fp.negate(c1)); // 3. c3 = sqrt(-c1) in F, i.e., (c3^2) == -c1 in F
204
- // const c4 = (P + _7n) / _16n; // 4. c4 = (q + 7) / 16 # Integer arithmetic
205
- // sqrt = (x) => {
206
- // let tv1 = Fp.pow(x, c4); // 1. tv1 = x^c4
207
- // let tv2 = Fp.mul(c1, tv1); // 2. tv2 = c1 * tv1
208
- // const tv3 = Fp.mul(c2, tv1); // 3. tv3 = c2 * tv1
209
- // let tv4 = Fp.mul(c3, tv1); // 4. tv4 = c3 * tv1
210
- // const e1 = Fp.equals(Fp.square(tv2), x); // 5. e1 = (tv2^2) == x
211
- // const e2 = Fp.equals(Fp.square(tv3), x); // 6. e2 = (tv3^2) == x
212
- // tv1 = Fp.cmov(tv1, tv2, e1); // 7. tv1 = CMOV(tv1, tv2, e1) # Select tv2 if (tv2^2) == x
213
- // tv2 = Fp.cmov(tv4, tv3, e2); // 8. tv2 = CMOV(tv4, tv3, e2) # Select tv3 if (tv3^2) == x
214
- // const e3 = Fp.equals(Fp.square(tv2), x); // 9. e3 = (tv2^2) == x
215
- // return Fp.cmov(tv1, tv2, e3); // 10. z = CMOV(tv1, tv2, e3) # Select the sqrt from tv1 and tv2
216
- // }
217
- }
218
- // Other cases: Tonelli-Shanks algorithm
206
+ // P ≡ 3 (mod 4) => √n = n^((P+1)/4)
207
+ if (P % _4n === _3n) return sqrt3mod4;
208
+ // P 5 (mod 8) => Atkin algorithm, page 10 of https://eprint.iacr.org/2012/685.pdf
209
+ if (P % _8n === _5n) return sqrt5mod8;
210
+ // P 9 (mod 16) not implemented, see above
211
+ // Tonelli-Shanks algorithm
219
212
  return tonelliShanks(P);
220
213
  }
221
214
 
@@ -236,6 +229,7 @@ export interface IField<T> {
236
229
  create: (num: T) => T;
237
230
  isValid: (num: T) => boolean;
238
231
  is0: (num: T) => boolean;
232
+ isValidNot0: (num: T) => boolean;
239
233
  neg(num: T): T;
240
234
  inv(num: T): T;
241
235
  sqrt(num: T): T;
@@ -259,7 +253,6 @@ export interface IField<T> {
259
253
  // NOTE: sgn0 is 'negative in LE', which is same as odd. And negative in LE is kinda strange definition anyway.
260
254
  isOdd?(num: T): boolean; // Odd instead of even since we have it for Fp2
261
255
  // legendre?(num: T): T;
262
- pow(lhs: T, power: bigint): T;
263
256
  invertBatch: (lst: T[]) => T[];
264
257
  toBytes(num: T): Uint8Array;
265
258
  fromBytes(bytes: Uint8Array): T;
@@ -276,14 +269,18 @@ export function validateField<T>(field: IField<T>): IField<T> {
276
269
  const initial = {
277
270
  ORDER: 'bigint',
278
271
  MASK: 'bigint',
279
- BYTES: 'isSafeInteger',
280
- BITS: 'isSafeInteger',
272
+ BYTES: 'number',
273
+ BITS: 'number',
281
274
  } as Record<string, string>;
282
275
  const opts = FIELD_FIELDS.reduce((map, val: string) => {
283
276
  map[val] = 'function';
284
277
  return map;
285
278
  }, initial);
286
- return validateObject(field, opts);
279
+ _validateObject(field, opts);
280
+ // const max = 16384;
281
+ // if (field.BYTES < 1 || field.BYTES > max) throw new Error('invalid field');
282
+ // if (field.BITS < 1 || field.BITS > 8 * max) throw new Error('invalid field');
283
+ return field;
287
284
  }
288
285
 
289
286
  // Generic field functions
@@ -296,7 +293,6 @@ export function FpPow<T>(Fp: IField<T>, num: T, power: bigint): T {
296
293
  if (power < _0n) throw new Error('invalid exponent, negatives unsupported');
297
294
  if (power === _0n) return Fp.ONE;
298
295
  if (power === _1n) return num;
299
- // @ts-ignore
300
296
  let p = Fp.ONE;
301
297
  let d = num;
302
298
  while (power > _0n) {
@@ -339,36 +335,33 @@ export function FpDiv<T>(Fp: IField<T>, lhs: T, rhs: T | bigint): T {
339
335
  /**
340
336
  * Legendre symbol.
341
337
  * Legendre constant is used to calculate Legendre symbol (a | p)
342
- * which denotes the value of a^((p-1)/2) (mod p)..
338
+ * which denotes the value of a^((p-1)/2) (mod p).
343
339
  *
344
340
  * * (a | p) ≡ 1 if a is a square (mod p), quadratic residue
345
341
  * * (a | p) ≡ -1 if a is not a square (mod p), quadratic non residue
346
342
  * * (a | p) ≡ 0 if a ≡ 0 (mod p)
347
343
  */
348
- export function FpLegendre<T>(Fp: IField<T>, n: T): number {
349
- const legc = (Fp.ORDER - _1n) / _2n;
350
- const powered = Fp.pow(n, legc);
344
+ export function FpLegendre<T>(Fp: IField<T>, n: T): -1 | 0 | 1 {
345
+ // We can use 3rd argument as optional cache of this value
346
+ // but seems unneeded for now. The operation is very fast.
347
+ const p1mod2 = (Fp.ORDER - _1n) / _2n;
348
+ const powered = Fp.pow(n, p1mod2);
351
349
  const yes = Fp.eql(powered, Fp.ONE);
352
350
  const zero = Fp.eql(powered, Fp.ZERO);
353
351
  const no = Fp.eql(powered, Fp.neg(Fp.ONE));
354
- if (!yes && !zero && !no) throw new Error('Cannot find square root: probably non-prime P');
352
+ if (!yes && !zero && !no) throw new Error('invalid Legendre symbol result');
355
353
  return yes ? 1 : zero ? 0 : -1;
356
354
  }
357
355
 
358
356
  // This function returns True whenever the value x is a square in the field F.
359
357
  export function FpIsSquare<T>(Fp: IField<T>, n: T): boolean {
360
358
  const l = FpLegendre(Fp, n);
361
- return l === 0 || l === 1;
359
+ return l === 1;
362
360
  }
363
361
 
362
+ export type NLength = { nByteLength: number; nBitLength: number };
364
363
  // CURVE.n lengths
365
- export function nLength(
366
- n: bigint,
367
- nBitLength?: number
368
- ): {
369
- nBitLength: number;
370
- nByteLength: number;
371
- } {
364
+ export function nLength(n: bigint, nBitLength?: number): NLength {
372
365
  // Bit size, byte size of CURVE.n
373
366
  if (nBitLength !== undefined) anumber(nBitLength);
374
367
  const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length;
@@ -377,29 +370,47 @@ export function nLength(
377
370
  }
378
371
 
379
372
  type FpField = IField<bigint> & Required<Pick<IField<bigint>, 'isOdd'>>;
373
+ type SqrtFn = (n: bigint) => bigint;
374
+ type FieldOpts = Partial<{ sqrt: SqrtFn; isLE: boolean; BITS: number }>;
380
375
  /**
381
- * Initializes a finite field over prime.
382
- * Major performance optimizations:
383
- * * a) denormalized operations like mulN instead of mul
384
- * * b) same object shape: never add or remove keys
385
- * * c) Object.freeze
376
+ * Creates a finite field. Major performance optimizations:
377
+ * * 1. Denormalized operations like mulN instead of mul.
378
+ * * 2. Identical object shape: never add or remove keys.
379
+ * * 3. `Object.freeze`.
386
380
  * Fragile: always run a benchmark on a change.
387
381
  * Security note: operations don't check 'isValid' for all elements for performance reasons,
388
382
  * it is caller responsibility to check this.
389
383
  * This is low-level code, please make sure you know what you're doing.
390
- * @param ORDER prime positive bigint
384
+ *
385
+ * Note about field properties:
386
+ * * CHARACTERISTIC p = prime number, number of elements in main subgroup.
387
+ * * ORDER q = similar to cofactor in curves, may be composite `q = p^m`.
388
+ *
389
+ * @param ORDER field order, probably prime, or could be composite
391
390
  * @param bitLen how many bits the field consumes
392
- * @param isLE (def: false) if encoding / decoding should be in little-endian
391
+ * @param isLE (default: false) if encoding / decoding should be in little-endian
393
392
  * @param redef optional faster redefinitions of sqrt and other methods
394
393
  */
395
394
  export function Field(
396
395
  ORDER: bigint,
397
- bitLen?: number,
396
+ bitLenOrOpts?: number | FieldOpts,
398
397
  isLE = false,
399
- redef: Partial<IField<bigint>> = {}
398
+ opts: { sqrt?: SqrtFn } = {}
400
399
  ): Readonly<FpField> {
401
400
  if (ORDER <= _0n) throw new Error('invalid field: expected ORDER > 0, got ' + ORDER);
402
- const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, bitLen);
401
+ let _nbitLength: number | undefined = undefined;
402
+ let _sqrt: SqrtFn | undefined = undefined;
403
+ if (typeof bitLenOrOpts === 'object' && bitLenOrOpts != null) {
404
+ if (opts.sqrt || isLE) throw new Error('cannot specify opts in two arguments');
405
+ const _opts = bitLenOrOpts;
406
+ if (_opts.BITS) _nbitLength = _opts.BITS;
407
+ if (_opts.sqrt) _sqrt = _opts.sqrt;
408
+ if (typeof _opts.isLE === 'boolean') isLE = _opts.isLE;
409
+ } else {
410
+ if (typeof bitLenOrOpts === 'number') _nbitLength = bitLenOrOpts;
411
+ if (opts.sqrt) _sqrt = opts.sqrt;
412
+ }
413
+ const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, _nbitLength);
403
414
  if (BYTES > 2048) throw new Error('invalid field: expected ORDER of <= 2048 bytes');
404
415
  let sqrtP: ReturnType<typeof FpSqrt>; // cached sqrtP
405
416
  const f: Readonly<FpField> = Object.freeze({
@@ -417,6 +428,8 @@ export function Field(
417
428
  return _0n <= num && num < ORDER; // 0 is valid element, but it's not invertible
418
429
  },
419
430
  is0: (num) => num === _0n,
431
+ // is valid and invertible
432
+ isValidNot0: (num: bigint) => !f.is0(num) && f.isValid(num),
420
433
  isOdd: (num) => (num & _1n) === _1n,
421
434
  neg: (num) => mod(-num, ORDER),
422
435
  eql: (lhs, rhs) => lhs === rhs,
@@ -436,7 +449,7 @@ export function Field(
436
449
 
437
450
  inv: (num) => invert(num, ORDER),
438
451
  sqrt:
439
- redef.sqrt ||
452
+ _sqrt ||
440
453
  ((n) => {
441
454
  if (!sqrtP) sqrtP = FpSqrt(ORDER);
442
455
  return sqrtP(f, n);