@noble/curves 2.0.1 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +214 -122
- package/abstract/bls.d.ts +299 -16
- package/abstract/bls.d.ts.map +1 -1
- package/abstract/bls.js +82 -22
- package/abstract/bls.js.map +1 -1
- package/abstract/curve.d.ts +274 -27
- package/abstract/curve.d.ts.map +1 -1
- package/abstract/curve.js +177 -23
- package/abstract/curve.js.map +1 -1
- package/abstract/edwards.d.ts +166 -30
- package/abstract/edwards.d.ts.map +1 -1
- package/abstract/edwards.js +221 -86
- package/abstract/edwards.js.map +1 -1
- package/abstract/fft.d.ts +322 -10
- package/abstract/fft.d.ts.map +1 -1
- package/abstract/fft.js +154 -12
- package/abstract/fft.js.map +1 -1
- package/abstract/frost.d.ts +293 -0
- package/abstract/frost.d.ts.map +1 -0
- package/abstract/frost.js +704 -0
- package/abstract/frost.js.map +1 -0
- package/abstract/hash-to-curve.d.ts +173 -24
- package/abstract/hash-to-curve.d.ts.map +1 -1
- package/abstract/hash-to-curve.js +170 -31
- package/abstract/hash-to-curve.js.map +1 -1
- package/abstract/modular.d.ts +429 -37
- package/abstract/modular.d.ts.map +1 -1
- package/abstract/modular.js +414 -119
- package/abstract/modular.js.map +1 -1
- package/abstract/montgomery.d.ts +83 -12
- package/abstract/montgomery.d.ts.map +1 -1
- package/abstract/montgomery.js +32 -7
- package/abstract/montgomery.js.map +1 -1
- package/abstract/oprf.d.ts +164 -91
- package/abstract/oprf.d.ts.map +1 -1
- package/abstract/oprf.js +88 -29
- package/abstract/oprf.js.map +1 -1
- package/abstract/poseidon.d.ts +138 -7
- package/abstract/poseidon.d.ts.map +1 -1
- package/abstract/poseidon.js +178 -15
- package/abstract/poseidon.js.map +1 -1
- package/abstract/tower.d.ts +122 -3
- package/abstract/tower.d.ts.map +1 -1
- package/abstract/tower.js +323 -139
- package/abstract/tower.js.map +1 -1
- package/abstract/weierstrass.d.ts +339 -76
- package/abstract/weierstrass.d.ts.map +1 -1
- package/abstract/weierstrass.js +395 -205
- package/abstract/weierstrass.js.map +1 -1
- package/bls12-381.d.ts +16 -2
- package/bls12-381.d.ts.map +1 -1
- package/bls12-381.js +199 -209
- package/bls12-381.js.map +1 -1
- package/bn254.d.ts +11 -2
- package/bn254.d.ts.map +1 -1
- package/bn254.js +93 -38
- package/bn254.js.map +1 -1
- package/ed25519.d.ts +125 -14
- package/ed25519.d.ts.map +1 -1
- package/ed25519.js +202 -40
- package/ed25519.js.map +1 -1
- package/ed448.d.ts +108 -14
- package/ed448.d.ts.map +1 -1
- package/ed448.js +194 -42
- package/ed448.js.map +1 -1
- package/index.js +7 -1
- package/index.js.map +1 -1
- package/misc.d.ts +106 -7
- package/misc.d.ts.map +1 -1
- package/misc.js +141 -32
- package/misc.js.map +1 -1
- package/nist.d.ts +112 -11
- package/nist.d.ts.map +1 -1
- package/nist.js +139 -17
- package/nist.js.map +1 -1
- package/package.json +11 -6
- package/secp256k1.d.ts +92 -15
- package/secp256k1.d.ts.map +1 -1
- package/secp256k1.js +211 -28
- package/secp256k1.js.map +1 -1
- package/src/abstract/bls.ts +350 -67
- package/src/abstract/curve.ts +327 -44
- package/src/abstract/edwards.ts +367 -143
- package/src/abstract/fft.ts +369 -36
- package/src/abstract/frost.ts +1092 -0
- package/src/abstract/hash-to-curve.ts +255 -56
- package/src/abstract/modular.ts +591 -144
- package/src/abstract/montgomery.ts +114 -30
- package/src/abstract/oprf.ts +383 -194
- package/src/abstract/poseidon.ts +235 -35
- package/src/abstract/tower.ts +428 -159
- package/src/abstract/weierstrass.ts +710 -312
- package/src/bls12-381.ts +239 -236
- package/src/bn254.ts +107 -46
- package/src/ed25519.ts +227 -55
- package/src/ed448.ts +227 -57
- package/src/index.ts +7 -1
- package/src/misc.ts +154 -35
- package/src/nist.ts +143 -20
- package/src/secp256k1.ts +284 -41
- package/src/utils.ts +583 -81
- package/src/webcrypto.ts +302 -73
- package/utils.d.ts +457 -24
- package/utils.d.ts.map +1 -1
- package/utils.js +410 -53
- package/utils.js.map +1 -1
- package/webcrypto.d.ts +167 -25
- package/webcrypto.d.ts.map +1 -1
- package/webcrypto.js +165 -58
- package/webcrypto.js.map +1 -1
package/abstract/modular.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* @module
|
|
6
6
|
*/
|
|
7
7
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
8
|
-
import { abytes, anumber, bytesToNumberBE, bytesToNumberLE, numberToBytesBE, numberToBytesLE, validateObject, } from "../utils.js";
|
|
8
|
+
import { abool, abytes, anumber, asafenumber, bitLen, bytesToNumberBE, bytesToNumberLE, numberToBytesBE, numberToBytesLE, validateObject, } from "../utils.js";
|
|
9
9
|
// Numbers aren't used in x25519 / x448 builds
|
|
10
10
|
// prettier-ignore
|
|
11
11
|
const _0n = /* @__PURE__ */ BigInt(0), _1n = /* @__PURE__ */ BigInt(1), _2n = /* @__PURE__ */ BigInt(2);
|
|
@@ -14,22 +14,63 @@ const _3n = /* @__PURE__ */ BigInt(3), _4n = /* @__PURE__ */ BigInt(4), _5n = /*
|
|
|
14
14
|
// prettier-ignore
|
|
15
15
|
const _7n = /* @__PURE__ */ BigInt(7), _8n = /* @__PURE__ */ BigInt(8), _9n = /* @__PURE__ */ BigInt(9);
|
|
16
16
|
const _16n = /* @__PURE__ */ BigInt(16);
|
|
17
|
-
|
|
17
|
+
/**
|
|
18
|
+
* @param a - Dividend value.
|
|
19
|
+
* @param b - Positive modulus.
|
|
20
|
+
* @returns Reduced value in `[0, b)` only when `b` is positive.
|
|
21
|
+
* @throws If the modulus is not positive. {@link Error}
|
|
22
|
+
* @example
|
|
23
|
+
* Normalize a bigint into one field residue.
|
|
24
|
+
*
|
|
25
|
+
* ```ts
|
|
26
|
+
* mod(-1n, 5n);
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
18
29
|
export function mod(a, b) {
|
|
30
|
+
if (b <= _0n)
|
|
31
|
+
throw new Error('mod: expected positive modulus, got ' + b);
|
|
19
32
|
const result = a % b;
|
|
20
33
|
return result >= _0n ? result : b + result;
|
|
21
34
|
}
|
|
22
35
|
/**
|
|
23
|
-
* Efficiently raise num to power
|
|
36
|
+
* Efficiently raise num to a power with modular reduction.
|
|
24
37
|
* Unsafe in some contexts: uses ladder, so can expose bigint bits.
|
|
38
|
+
* Low-level helper: callers that need canonical residues must pass a valid `num` for the chosen
|
|
39
|
+
* modulus instead of relying on the `power===0/1` fast paths to normalize it.
|
|
40
|
+
* @param num - Base value.
|
|
41
|
+
* @param power - Exponent value.
|
|
42
|
+
* @param modulo - Reduction modulus.
|
|
43
|
+
* @returns Modular exponentiation result.
|
|
44
|
+
* @throws If the modulus or exponent is invalid. {@link Error}
|
|
25
45
|
* @example
|
|
46
|
+
* Raise one bigint to a modular power.
|
|
47
|
+
*
|
|
48
|
+
* ```ts
|
|
26
49
|
* pow(2n, 6n, 11n) // 64n % 11n == 9n
|
|
50
|
+
* ```
|
|
27
51
|
*/
|
|
28
52
|
export function pow(num, power, modulo) {
|
|
29
53
|
return FpPow(Field(modulo), num, power);
|
|
30
54
|
}
|
|
31
|
-
/**
|
|
55
|
+
/**
|
|
56
|
+
* Does `x^(2^power)` mod p. `pow2(30, 4)` == `30^(2^4)`.
|
|
57
|
+
* Low-level helper: callers that need canonical residues must pass a valid `x` for the chosen
|
|
58
|
+
* modulus; the `power===0` fast path intentionally returns the input unchanged.
|
|
59
|
+
* @param x - Base value.
|
|
60
|
+
* @param power - Number of squarings.
|
|
61
|
+
* @param modulo - Reduction modulus.
|
|
62
|
+
* @returns Repeated-squaring result.
|
|
63
|
+
* @throws If the exponent is negative. {@link Error}
|
|
64
|
+
* @example
|
|
65
|
+
* Apply repeated squaring inside one field.
|
|
66
|
+
*
|
|
67
|
+
* ```ts
|
|
68
|
+
* pow2(3n, 2n, 11n);
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
32
71
|
export function pow2(x, power, modulo) {
|
|
72
|
+
if (power < _0n)
|
|
73
|
+
throw new Error('pow2: expected non-negative exponent, got ' + power);
|
|
33
74
|
let res = x;
|
|
34
75
|
while (power-- > _0n) {
|
|
35
76
|
res *= res;
|
|
@@ -39,7 +80,17 @@ export function pow2(x, power, modulo) {
|
|
|
39
80
|
}
|
|
40
81
|
/**
|
|
41
82
|
* Inverses number over modulo.
|
|
42
|
-
* Implemented using
|
|
83
|
+
* Implemented using the {@link https://brilliant.org/wiki/extended-euclidean-algorithm/ | extended Euclidean algorithm}.
|
|
84
|
+
* @param number - Value to invert.
|
|
85
|
+
* @param modulo - Positive modulus.
|
|
86
|
+
* @returns Multiplicative inverse.
|
|
87
|
+
* @throws If the modulus is invalid or the inverse does not exist. {@link Error}
|
|
88
|
+
* @example
|
|
89
|
+
* Compute one modular inverse with the extended Euclidean algorithm.
|
|
90
|
+
*
|
|
91
|
+
* ```ts
|
|
92
|
+
* invert(3n, 11n);
|
|
93
|
+
* ```
|
|
43
94
|
*/
|
|
44
95
|
export function invert(number, modulo) {
|
|
45
96
|
if (number === _0n)
|
|
@@ -52,9 +103,8 @@ export function invert(number, modulo) {
|
|
|
52
103
|
// prettier-ignore
|
|
53
104
|
let x = _0n, y = _1n, u = _1n, v = _0n;
|
|
54
105
|
while (a !== _0n) {
|
|
55
|
-
// JIT applies optimization if those two lines follow each other
|
|
56
106
|
const q = b / a;
|
|
57
|
-
const r = b
|
|
107
|
+
const r = b - a * q;
|
|
58
108
|
const m = x - u * q;
|
|
59
109
|
const n = y - v * q;
|
|
60
110
|
// prettier-ignore
|
|
@@ -66,7 +116,8 @@ export function invert(number, modulo) {
|
|
|
66
116
|
return mod(x, modulo);
|
|
67
117
|
}
|
|
68
118
|
function assertIsSquare(Fp, root, n) {
|
|
69
|
-
|
|
119
|
+
const F = Fp;
|
|
120
|
+
if (!F.eql(F.sqr(root), n))
|
|
70
121
|
throw new Error('Cannot find square root');
|
|
71
122
|
}
|
|
72
123
|
// Not all roots are possible! Example which will throw:
|
|
@@ -74,19 +125,23 @@ function assertIsSquare(Fp, root, n) {
|
|
|
74
125
|
// n = 72057594037927816n;
|
|
75
126
|
// Fp = Field(BigInt('0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab'));
|
|
76
127
|
function sqrt3mod4(Fp, n) {
|
|
77
|
-
const
|
|
78
|
-
const
|
|
79
|
-
|
|
128
|
+
const F = Fp;
|
|
129
|
+
const p1div4 = (F.ORDER + _1n) / _4n;
|
|
130
|
+
const root = F.pow(n, p1div4);
|
|
131
|
+
assertIsSquare(F, root, n);
|
|
80
132
|
return root;
|
|
81
133
|
}
|
|
134
|
+
// Equivalent `q = 5 (mod 8)` square-root formula (Atkin-style), not the RFC Appendix I.2 CMOV
|
|
135
|
+
// pseudocode verbatim.
|
|
82
136
|
function sqrt5mod8(Fp, n) {
|
|
83
|
-
const
|
|
84
|
-
const
|
|
85
|
-
const
|
|
86
|
-
const
|
|
87
|
-
const
|
|
88
|
-
const
|
|
89
|
-
|
|
137
|
+
const F = Fp;
|
|
138
|
+
const p5div8 = (F.ORDER - _5n) / _8n;
|
|
139
|
+
const n2 = F.mul(n, _2n);
|
|
140
|
+
const v = F.pow(n2, p5div8);
|
|
141
|
+
const nv = F.mul(n, v);
|
|
142
|
+
const i = F.mul(F.mul(nv, _2n), v);
|
|
143
|
+
const root = F.mul(nv, F.sub(i, F.ONE));
|
|
144
|
+
assertIsSquare(F, root, n);
|
|
90
145
|
return root;
|
|
91
146
|
}
|
|
92
147
|
// Based on RFC9380, Kong algorithm
|
|
@@ -98,27 +153,39 @@ function sqrt9mod16(P) {
|
|
|
98
153
|
const c2 = tn(Fp_, c1); // 2. c2 = sqrt(c1) in F, i.e., (c2^2) == c1 in F
|
|
99
154
|
const c3 = tn(Fp_, Fp_.neg(c1)); // 3. c3 = sqrt(-c1) in F, i.e., (c3^2) == -c1 in F
|
|
100
155
|
const c4 = (P + _7n) / _16n; // 4. c4 = (q + 7) / 16 # Integer arithmetic
|
|
101
|
-
return (Fp, n) => {
|
|
102
|
-
|
|
103
|
-
let
|
|
104
|
-
|
|
105
|
-
const
|
|
106
|
-
const
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const
|
|
112
|
-
|
|
156
|
+
return ((Fp, n) => {
|
|
157
|
+
const F = Fp;
|
|
158
|
+
let tv1 = F.pow(n, c4); // 1. tv1 = x^c4
|
|
159
|
+
let tv2 = F.mul(tv1, c1); // 2. tv2 = c1 * tv1
|
|
160
|
+
const tv3 = F.mul(tv1, c2); // 3. tv3 = c2 * tv1
|
|
161
|
+
const tv4 = F.mul(tv1, c3); // 4. tv4 = c3 * tv1
|
|
162
|
+
const e1 = F.eql(F.sqr(tv2), n); // 5. e1 = (tv2^2) == x
|
|
163
|
+
const e2 = F.eql(F.sqr(tv3), n); // 6. e2 = (tv3^2) == x
|
|
164
|
+
tv1 = F.cmov(tv1, tv2, e1); // 7. tv1 = CMOV(tv1, tv2, e1) # Select tv2 if (tv2^2) == x
|
|
165
|
+
tv2 = F.cmov(tv4, tv3, e2); // 8. tv2 = CMOV(tv4, tv3, e2) # Select tv3 if (tv3^2) == x
|
|
166
|
+
const e3 = F.eql(F.sqr(tv2), n); // 9. e3 = (tv2^2) == x
|
|
167
|
+
const root = F.cmov(tv1, tv2, e3); // 10. z = CMOV(tv1, tv2, e3) # Select sqrt from tv1 & tv2
|
|
168
|
+
assertIsSquare(F, root, n);
|
|
113
169
|
return root;
|
|
114
|
-
};
|
|
170
|
+
});
|
|
115
171
|
}
|
|
116
172
|
/**
|
|
117
173
|
* Tonelli-Shanks square root search algorithm.
|
|
118
|
-
*
|
|
174
|
+
* This implementation is variable-time: it searches data-dependently for the first non-residue `Z`
|
|
175
|
+
* and for the smallest `i` in the main loop, unlike RFC 9380 Appendix I.4's constant-time shape.
|
|
176
|
+
* 1. {@link https://eprint.iacr.org/2012/685.pdf | eprint 2012/685}, page 12
|
|
119
177
|
* 2. Square Roots from 1; 24, 51, 10 to Dan Shanks
|
|
120
|
-
* @param P field order
|
|
178
|
+
* @param P - field order
|
|
121
179
|
* @returns function that takes field Fp (created from P) and number n
|
|
180
|
+
* @throws If the field is too small, non-prime, or the square root does not exist. {@link Error}
|
|
181
|
+
* @example
|
|
182
|
+
* Construct a square-root helper for primes that need Tonelli-Shanks.
|
|
183
|
+
*
|
|
184
|
+
* ```ts
|
|
185
|
+
* import { Field, tonelliShanks } from '@noble/curves/abstract/modular.js';
|
|
186
|
+
* const Fp = Field(17n);
|
|
187
|
+
* const sqrt = tonelliShanks(17n)(Fp, 4n);
|
|
188
|
+
* ```
|
|
122
189
|
*/
|
|
123
190
|
export function tonelliShanks(P) {
|
|
124
191
|
// Initialization (precomputation).
|
|
@@ -149,38 +216,39 @@ export function tonelliShanks(P) {
|
|
|
149
216
|
let cc = _Fp.pow(Z, Q); // c = z^Q
|
|
150
217
|
const Q1div2 = (Q + _1n) / _2n;
|
|
151
218
|
return function tonelliSlow(Fp, n) {
|
|
152
|
-
|
|
219
|
+
const F = Fp;
|
|
220
|
+
if (F.is0(n))
|
|
153
221
|
return n;
|
|
154
222
|
// Check if n is a quadratic residue using Legendre symbol
|
|
155
|
-
if (FpLegendre(
|
|
223
|
+
if (FpLegendre(F, n) !== 1)
|
|
156
224
|
throw new Error('Cannot find square root');
|
|
157
225
|
// Initialize variables for the main loop
|
|
158
226
|
let M = S;
|
|
159
|
-
let c =
|
|
160
|
-
let t =
|
|
161
|
-
let R =
|
|
227
|
+
let c = F.mul(F.ONE, cc); // c = z^Q, move cc from field _Fp into field Fp
|
|
228
|
+
let t = F.pow(n, Q); // t = n^Q, first guess at the fudge factor
|
|
229
|
+
let R = F.pow(n, Q1div2); // R = n^((Q+1)/2), first guess at the square root
|
|
162
230
|
// Main loop
|
|
163
231
|
// while t != 1
|
|
164
|
-
while (!
|
|
165
|
-
if (
|
|
166
|
-
return
|
|
232
|
+
while (!F.eql(t, F.ONE)) {
|
|
233
|
+
if (F.is0(t))
|
|
234
|
+
return F.ZERO; // if t=0 return R=0
|
|
167
235
|
let i = 1;
|
|
168
236
|
// Find the smallest i >= 1 such that t^(2^i) ≡ 1 (mod P)
|
|
169
|
-
let t_tmp =
|
|
170
|
-
while (!
|
|
237
|
+
let t_tmp = F.sqr(t); // t^(2^1)
|
|
238
|
+
while (!F.eql(t_tmp, F.ONE)) {
|
|
171
239
|
i++;
|
|
172
|
-
t_tmp =
|
|
240
|
+
t_tmp = F.sqr(t_tmp); // t^(2^2)...
|
|
173
241
|
if (i === M)
|
|
174
242
|
throw new Error('Cannot find square root');
|
|
175
243
|
}
|
|
176
244
|
// Calculate the exponent for b: 2^(M - i - 1)
|
|
177
245
|
const exponent = _1n << BigInt(M - i - 1); // bigint is important
|
|
178
|
-
const b =
|
|
246
|
+
const b = F.pow(c, exponent); // b = 2^(M - i - 1)
|
|
179
247
|
// Update variables
|
|
180
248
|
M = i;
|
|
181
|
-
c =
|
|
182
|
-
t =
|
|
183
|
-
R =
|
|
249
|
+
c = F.sqr(b); // c = b^2
|
|
250
|
+
t = F.mul(t, c); // t = (t * b^2)
|
|
251
|
+
R = F.mul(R, b); // R = R*b
|
|
184
252
|
}
|
|
185
253
|
return R;
|
|
186
254
|
};
|
|
@@ -194,7 +262,20 @@ export function tonelliShanks(P) {
|
|
|
194
262
|
* 4. Tonelli-Shanks algorithm
|
|
195
263
|
*
|
|
196
264
|
* Different algorithms can give different roots, it is up to user to decide which one they want.
|
|
197
|
-
* For example there is FpSqrtOdd/FpSqrtEven to
|
|
265
|
+
* For example there is FpSqrtOdd/FpSqrtEven to choose a root by oddness
|
|
266
|
+
* (used for hash-to-curve).
|
|
267
|
+
* @param P - Field order.
|
|
268
|
+
* @returns Square-root helper. The generic fallback inherits Tonelli-Shanks' variable-time
|
|
269
|
+
* behavior and this selector assumes prime-field-style integer moduli.
|
|
270
|
+
* @throws If the field is unsupported or the square root does not exist. {@link Error}
|
|
271
|
+
* @example
|
|
272
|
+
* Choose the square-root helper appropriate for one field modulus.
|
|
273
|
+
*
|
|
274
|
+
* ```ts
|
|
275
|
+
* import { Field, FpSqrt } from '@noble/curves/abstract/modular.js';
|
|
276
|
+
* const Fp = Field(17n);
|
|
277
|
+
* const sqrt = FpSqrt(17n)(Fp, 4n);
|
|
278
|
+
* ```
|
|
198
279
|
*/
|
|
199
280
|
export function FpSqrt(P) {
|
|
200
281
|
// P ≡ 3 (mod 4) => √n = n^((P+1)/4)
|
|
@@ -209,14 +290,42 @@ export function FpSqrt(P) {
|
|
|
209
290
|
// Tonelli-Shanks algorithm
|
|
210
291
|
return tonelliShanks(P);
|
|
211
292
|
}
|
|
212
|
-
|
|
293
|
+
/**
|
|
294
|
+
* @param num - Value to inspect.
|
|
295
|
+
* @param modulo - Field modulus.
|
|
296
|
+
* @returns `true` when the least-significant little-endian bit is set.
|
|
297
|
+
* @throws If the modulus is invalid for `mod(...)`. {@link Error}
|
|
298
|
+
* @example
|
|
299
|
+
* Inspect the low bit used by little-endian sign conventions.
|
|
300
|
+
*
|
|
301
|
+
* ```ts
|
|
302
|
+
* isNegativeLE(3n, 11n);
|
|
303
|
+
* ```
|
|
304
|
+
*/
|
|
213
305
|
export const isNegativeLE = (num, modulo) => (mod(num, modulo) & _1n) === _1n;
|
|
214
306
|
// prettier-ignore
|
|
307
|
+
// Arithmetic-only subset checked by validateField(). This is intentionally not the full runtime
|
|
308
|
+
// IField contract: helpers like `isValidNot0`, `invertBatch`, `toBytes`, `fromBytes`, `cmov`, and
|
|
309
|
+
// field-specific extras like `isOdd` are left to the callers that actually need them.
|
|
215
310
|
const FIELD_FIELDS = [
|
|
216
311
|
'create', 'isValid', 'is0', 'neg', 'inv', 'sqrt', 'sqr',
|
|
217
312
|
'eql', 'add', 'sub', 'mul', 'pow', 'div',
|
|
218
313
|
'addN', 'subN', 'mulN', 'sqrN'
|
|
219
314
|
];
|
|
315
|
+
/**
|
|
316
|
+
* @param field - Field implementation.
|
|
317
|
+
* @returns Validated field. This only checks the arithmetic subset needed by generic helpers; it
|
|
318
|
+
* does not guarantee full runtime-method coverage for serialization, batching, `cmov`, or
|
|
319
|
+
* field-specific extras beyond positive `BYTES` / `BITS`.
|
|
320
|
+
* @throws If the field shape or numeric metadata are invalid. {@link Error}
|
|
321
|
+
* @example
|
|
322
|
+
* Check that a field implementation exposes the operations curve code expects.
|
|
323
|
+
*
|
|
324
|
+
* ```ts
|
|
325
|
+
* import { Field, validateField } from '@noble/curves/abstract/modular.js';
|
|
326
|
+
* const Fp = validateField(Field(17n));
|
|
327
|
+
* ```
|
|
328
|
+
*/
|
|
220
329
|
export function validateField(field) {
|
|
221
330
|
const initial = {
|
|
222
331
|
ORDER: 'bigint',
|
|
@@ -228,61 +337,109 @@ export function validateField(field) {
|
|
|
228
337
|
return map;
|
|
229
338
|
}, initial);
|
|
230
339
|
validateObject(field, opts);
|
|
231
|
-
//
|
|
232
|
-
//
|
|
233
|
-
|
|
340
|
+
// Runtime field implementations must expose real integer byte/bit sizes; fractional / NaN /
|
|
341
|
+
// infinite metadata leaks through validateObject(type='number') but breaks encoders and caches.
|
|
342
|
+
asafenumber(field.BYTES, 'BYTES');
|
|
343
|
+
asafenumber(field.BITS, 'BITS');
|
|
344
|
+
// Runtime field implementations must expose positive byte/bit sizes; zero leaks through the
|
|
345
|
+
// numeric shape checks above but still breaks encoding helpers and cached-length assumptions.
|
|
346
|
+
if (field.BYTES < 1 || field.BITS < 1)
|
|
347
|
+
throw new Error('invalid field: expected BYTES/BITS > 0');
|
|
348
|
+
if (field.ORDER <= _1n)
|
|
349
|
+
throw new Error('invalid field: expected ORDER > 1, got ' + field.ORDER);
|
|
234
350
|
return field;
|
|
235
351
|
}
|
|
236
352
|
// Generic field functions
|
|
237
353
|
/**
|
|
238
354
|
* Same as `pow` but for Fp: non-constant-time.
|
|
239
355
|
* Unsafe in some contexts: uses ladder, so can expose bigint bits.
|
|
356
|
+
* @param Fp - Field implementation.
|
|
357
|
+
* @param num - Base value.
|
|
358
|
+
* @param power - Exponent value.
|
|
359
|
+
* @returns Powered field element.
|
|
360
|
+
* @throws If the exponent is negative. {@link Error}
|
|
361
|
+
* @example
|
|
362
|
+
* Raise one field element to a public exponent.
|
|
363
|
+
*
|
|
364
|
+
* ```ts
|
|
365
|
+
* import { Field, FpPow } from '@noble/curves/abstract/modular.js';
|
|
366
|
+
* const Fp = Field(17n);
|
|
367
|
+
* const x = FpPow(Fp, 3n, 5n);
|
|
368
|
+
* ```
|
|
240
369
|
*/
|
|
241
370
|
export function FpPow(Fp, num, power) {
|
|
371
|
+
const F = Fp;
|
|
242
372
|
if (power < _0n)
|
|
243
373
|
throw new Error('invalid exponent, negatives unsupported');
|
|
244
374
|
if (power === _0n)
|
|
245
|
-
return
|
|
375
|
+
return F.ONE;
|
|
246
376
|
if (power === _1n)
|
|
247
377
|
return num;
|
|
248
|
-
let p =
|
|
378
|
+
let p = F.ONE;
|
|
249
379
|
let d = num;
|
|
250
380
|
while (power > _0n) {
|
|
251
381
|
if (power & _1n)
|
|
252
|
-
p =
|
|
253
|
-
d =
|
|
382
|
+
p = F.mul(p, d);
|
|
383
|
+
d = F.sqr(d);
|
|
254
384
|
power >>= _1n;
|
|
255
385
|
}
|
|
256
386
|
return p;
|
|
257
387
|
}
|
|
258
388
|
/**
|
|
259
389
|
* Efficiently invert an array of Field elements.
|
|
260
|
-
* Exception-free.
|
|
261
|
-
* @param
|
|
390
|
+
* Exception-free. Zero-valued field elements stay `undefined` unless `passZero` is enabled.
|
|
391
|
+
* @param Fp - Field implementation.
|
|
392
|
+
* @param nums - Values to invert.
|
|
393
|
+
* @param passZero - map 0 to 0 (instead of undefined)
|
|
394
|
+
* @returns Inverted values.
|
|
395
|
+
* @example
|
|
396
|
+
* Invert several field elements with one shared inversion.
|
|
397
|
+
*
|
|
398
|
+
* ```ts
|
|
399
|
+
* import { Field, FpInvertBatch } from '@noble/curves/abstract/modular.js';
|
|
400
|
+
* const Fp = Field(17n);
|
|
401
|
+
* const inv = FpInvertBatch(Fp, [1n, 2n, 4n]);
|
|
402
|
+
* ```
|
|
262
403
|
*/
|
|
263
404
|
export function FpInvertBatch(Fp, nums, passZero = false) {
|
|
264
|
-
const
|
|
405
|
+
const F = Fp;
|
|
406
|
+
const inverted = new Array(nums.length).fill(passZero ? F.ZERO : undefined);
|
|
265
407
|
// Walk from first to last, multiply them by each other MOD p
|
|
266
408
|
const multipliedAcc = nums.reduce((acc, num, i) => {
|
|
267
|
-
if (
|
|
409
|
+
if (F.is0(num))
|
|
268
410
|
return acc;
|
|
269
411
|
inverted[i] = acc;
|
|
270
|
-
return
|
|
271
|
-
},
|
|
412
|
+
return F.mul(acc, num);
|
|
413
|
+
}, F.ONE);
|
|
272
414
|
// Invert last element
|
|
273
|
-
const invertedAcc =
|
|
415
|
+
const invertedAcc = F.inv(multipliedAcc);
|
|
274
416
|
// Walk from last to first, multiply them by inverted each other MOD p
|
|
275
417
|
nums.reduceRight((acc, num, i) => {
|
|
276
|
-
if (
|
|
418
|
+
if (F.is0(num))
|
|
277
419
|
return acc;
|
|
278
|
-
inverted[i] =
|
|
279
|
-
return
|
|
420
|
+
inverted[i] = F.mul(acc, inverted[i]);
|
|
421
|
+
return F.mul(acc, num);
|
|
280
422
|
}, invertedAcc);
|
|
281
423
|
return inverted;
|
|
282
424
|
}
|
|
283
|
-
|
|
425
|
+
/**
|
|
426
|
+
* @param Fp - Field implementation.
|
|
427
|
+
* @param lhs - Dividend value.
|
|
428
|
+
* @param rhs - Divisor value.
|
|
429
|
+
* @returns Division result.
|
|
430
|
+
* @throws If the divisor is non-invertible. {@link Error}
|
|
431
|
+
* @example
|
|
432
|
+
* Divide one field element by another.
|
|
433
|
+
*
|
|
434
|
+
* ```ts
|
|
435
|
+
* import { Field, FpDiv } from '@noble/curves/abstract/modular.js';
|
|
436
|
+
* const Fp = Field(17n);
|
|
437
|
+
* const x = FpDiv(Fp, 6n, 3n);
|
|
438
|
+
* ```
|
|
439
|
+
*/
|
|
284
440
|
export function FpDiv(Fp, lhs, rhs) {
|
|
285
|
-
|
|
441
|
+
const F = Fp;
|
|
442
|
+
return F.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, F.ORDER) : F.inv(rhs));
|
|
286
443
|
}
|
|
287
444
|
/**
|
|
288
445
|
* Legendre symbol.
|
|
@@ -292,33 +449,85 @@ export function FpDiv(Fp, lhs, rhs) {
|
|
|
292
449
|
* * (a | p) ≡ 1 if a is a square (mod p), quadratic residue
|
|
293
450
|
* * (a | p) ≡ -1 if a is not a square (mod p), quadratic non residue
|
|
294
451
|
* * (a | p) ≡ 0 if a ≡ 0 (mod p)
|
|
452
|
+
* @param Fp - Field implementation.
|
|
453
|
+
* @param n - Value to inspect.
|
|
454
|
+
* @returns Legendre symbol.
|
|
455
|
+
* @throws If the field returns an invalid Legendre symbol value. {@link Error}
|
|
456
|
+
* @example
|
|
457
|
+
* Compute the Legendre symbol of one field element.
|
|
458
|
+
*
|
|
459
|
+
* ```ts
|
|
460
|
+
* import { Field, FpLegendre } from '@noble/curves/abstract/modular.js';
|
|
461
|
+
* const Fp = Field(17n);
|
|
462
|
+
* const symbol = FpLegendre(Fp, 4n);
|
|
463
|
+
* ```
|
|
295
464
|
*/
|
|
296
465
|
export function FpLegendre(Fp, n) {
|
|
466
|
+
const F = Fp;
|
|
297
467
|
// We can use 3rd argument as optional cache of this value
|
|
298
468
|
// but seems unneeded for now. The operation is very fast.
|
|
299
|
-
const p1mod2 = (
|
|
300
|
-
const powered =
|
|
301
|
-
const yes =
|
|
302
|
-
const zero =
|
|
303
|
-
const no =
|
|
469
|
+
const p1mod2 = (F.ORDER - _1n) / _2n;
|
|
470
|
+
const powered = F.pow(n, p1mod2);
|
|
471
|
+
const yes = F.eql(powered, F.ONE);
|
|
472
|
+
const zero = F.eql(powered, F.ZERO);
|
|
473
|
+
const no = F.eql(powered, F.neg(F.ONE));
|
|
304
474
|
if (!yes && !zero && !no)
|
|
305
475
|
throw new Error('invalid Legendre symbol result');
|
|
306
476
|
return yes ? 1 : zero ? 0 : -1;
|
|
307
477
|
}
|
|
308
|
-
|
|
478
|
+
/**
|
|
479
|
+
* @param Fp - Field implementation.
|
|
480
|
+
* @param n - Value to inspect.
|
|
481
|
+
* @returns `true` when `Fp.sqrt(n)` exists. This includes `0`, even though strict "quadratic
|
|
482
|
+
* residue" terminology often reserves that name for the non-zero square class.
|
|
483
|
+
* @throws If the field returns an invalid Legendre symbol value. {@link Error}
|
|
484
|
+
* @example
|
|
485
|
+
* Check whether one field element has a square root in the field.
|
|
486
|
+
*
|
|
487
|
+
* ```ts
|
|
488
|
+
* import { Field, FpIsSquare } from '@noble/curves/abstract/modular.js';
|
|
489
|
+
* const Fp = Field(17n);
|
|
490
|
+
* const isSquare = FpIsSquare(Fp, 4n);
|
|
491
|
+
* ```
|
|
492
|
+
*/
|
|
309
493
|
export function FpIsSquare(Fp, n) {
|
|
310
494
|
const l = FpLegendre(Fp, n);
|
|
311
|
-
|
|
495
|
+
// Zero is a square too: 0 = 0^2, and Fp.sqrt(0) already returns 0.
|
|
496
|
+
return l !== -1;
|
|
312
497
|
}
|
|
313
|
-
|
|
498
|
+
/**
|
|
499
|
+
* @param n - Curve order. Callers are expected to pass a positive order.
|
|
500
|
+
* @param nBitLength - Optional cached bit length. Callers are expected to pass a positive cached
|
|
501
|
+
* value when overriding the derived bit length.
|
|
502
|
+
* @returns Byte and bit lengths.
|
|
503
|
+
* @throws If the order or cached bit length is invalid. {@link Error}
|
|
504
|
+
* @example
|
|
505
|
+
* Measure the encoding sizes needed for one modulus.
|
|
506
|
+
*
|
|
507
|
+
* ```ts
|
|
508
|
+
* nLength(255n);
|
|
509
|
+
* ```
|
|
510
|
+
*/
|
|
314
511
|
export function nLength(n, nBitLength) {
|
|
315
512
|
// Bit size, byte size of CURVE.n
|
|
316
513
|
if (nBitLength !== undefined)
|
|
317
514
|
anumber(nBitLength);
|
|
318
|
-
|
|
515
|
+
if (n <= _0n)
|
|
516
|
+
throw new Error('invalid n length: expected positive n, got ' + n);
|
|
517
|
+
if (nBitLength !== undefined && nBitLength < 1)
|
|
518
|
+
throw new Error('invalid n length: expected positive bit length, got ' + nBitLength);
|
|
519
|
+
const bits = bitLen(n);
|
|
520
|
+
// Cached bit lengths smaller than ORDER would truncate serialized scalars/elements and poison
|
|
521
|
+
// any math that relies on the derived field metadata.
|
|
522
|
+
if (nBitLength !== undefined && nBitLength < bits)
|
|
523
|
+
throw new Error(`invalid n length: expected bit length (${bits}) >= n.length (${nBitLength})`);
|
|
524
|
+
const _nBitLength = nBitLength !== undefined ? nBitLength : bits;
|
|
319
525
|
const nByteLength = Math.ceil(_nBitLength / 8);
|
|
320
526
|
return { nBitLength: _nBitLength, nByteLength };
|
|
321
527
|
}
|
|
528
|
+
// Keep the lazy sqrt cache off-instance so Field(...) can return a frozen object. Otherwise the
|
|
529
|
+
// cached helper write would keep the field surface externally mutable.
|
|
530
|
+
const FIELD_SQRT = new WeakMap();
|
|
322
531
|
class _Field {
|
|
323
532
|
ORDER;
|
|
324
533
|
BITS;
|
|
@@ -327,22 +536,26 @@ class _Field {
|
|
|
327
536
|
ZERO = _0n;
|
|
328
537
|
ONE = _1n;
|
|
329
538
|
_lengths;
|
|
330
|
-
_sqrt; // cached sqrt
|
|
331
539
|
_mod;
|
|
332
540
|
constructor(ORDER, opts = {}) {
|
|
333
|
-
|
|
334
|
-
|
|
541
|
+
// ORDER <= 1 is degenerate: ONE would not be a valid field element and helpers like pow/inv
|
|
542
|
+
// would stop modeling field arithmetic.
|
|
543
|
+
if (ORDER <= _1n)
|
|
544
|
+
throw new Error('invalid field: expected ORDER > 1, got ' + ORDER);
|
|
335
545
|
let _nbitLength = undefined;
|
|
336
546
|
this.isLE = false;
|
|
337
547
|
if (opts != null && typeof opts === 'object') {
|
|
548
|
+
// Cached bit lengths are trusted here and should already be positive / consistent with ORDER.
|
|
338
549
|
if (typeof opts.BITS === 'number')
|
|
339
550
|
_nbitLength = opts.BITS;
|
|
340
551
|
if (typeof opts.sqrt === 'function')
|
|
341
|
-
|
|
552
|
+
// `_Field.prototype` is frozen below, so custom sqrt hooks must become own properties
|
|
553
|
+
// explicitly instead of relying on writable prototype shadowing via assignment.
|
|
554
|
+
Object.defineProperty(this, 'sqrt', { value: opts.sqrt, enumerable: true });
|
|
342
555
|
if (typeof opts.isLE === 'boolean')
|
|
343
556
|
this.isLE = opts.isLE;
|
|
344
557
|
if (opts.allowedLengths)
|
|
345
|
-
this._lengths = opts.allowedLengths
|
|
558
|
+
this._lengths = Object.freeze(opts.allowedLengths.slice());
|
|
346
559
|
if (typeof opts.modFromBytes === 'boolean')
|
|
347
560
|
this._mod = opts.modFromBytes;
|
|
348
561
|
}
|
|
@@ -352,15 +565,14 @@ class _Field {
|
|
|
352
565
|
this.ORDER = ORDER;
|
|
353
566
|
this.BITS = nBitLength;
|
|
354
567
|
this.BYTES = nByteLength;
|
|
355
|
-
this
|
|
356
|
-
Object.preventExtensions(this);
|
|
568
|
+
Object.freeze(this);
|
|
357
569
|
}
|
|
358
570
|
create(num) {
|
|
359
571
|
return mod(num, this.ORDER);
|
|
360
572
|
}
|
|
361
573
|
isValid(num) {
|
|
362
574
|
if (typeof num !== 'bigint')
|
|
363
|
-
throw new
|
|
575
|
+
throw new TypeError('invalid field element: expected bigint, got ' + typeof num);
|
|
364
576
|
return _0n <= num && num < this.ORDER; // 0 is valid element, but it's not invertible
|
|
365
577
|
}
|
|
366
578
|
is0(num) {
|
|
@@ -414,19 +626,26 @@ class _Field {
|
|
|
414
626
|
return invert(num, this.ORDER);
|
|
415
627
|
}
|
|
416
628
|
sqrt(num) {
|
|
417
|
-
// Caching
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
629
|
+
// Caching sqrt helpers speeds up sqrt9mod16 by 5x and Tonelli-Shanks by about 10% without keeping
|
|
630
|
+
// the field instance itself mutable.
|
|
631
|
+
let sqrt = FIELD_SQRT.get(this);
|
|
632
|
+
if (!sqrt)
|
|
633
|
+
FIELD_SQRT.set(this, (sqrt = FpSqrt(this.ORDER)));
|
|
634
|
+
return sqrt(this, num);
|
|
421
635
|
}
|
|
422
636
|
toBytes(num) {
|
|
637
|
+
// Serialize fixed-width limbs without re-validating the field range. Callers that need a
|
|
638
|
+
// canonical encoding must pass a valid element; some protocols intentionally serialize raw
|
|
639
|
+
// residues here and reduce or validate them elsewhere.
|
|
423
640
|
return this.isLE ? numberToBytesLE(num, this.BYTES) : numberToBytesBE(num, this.BYTES);
|
|
424
641
|
}
|
|
425
642
|
fromBytes(bytes, skipValidation = false) {
|
|
426
643
|
abytes(bytes);
|
|
427
644
|
const { _lengths: allowedLengths, BYTES, isLE, ORDER, _mod: modFromBytes } = this;
|
|
428
645
|
if (allowedLengths) {
|
|
429
|
-
|
|
646
|
+
// `allowedLengths` must list real positive byte lengths; otherwise empty input would get
|
|
647
|
+
// padded into zero and silently decode as a field element.
|
|
648
|
+
if (bytes.length < 1 || !allowedLengths.includes(bytes.length) || bytes.length > BYTES) {
|
|
430
649
|
throw new Error('Field.fromBytes: expected ' + allowedLengths + ' bytes, got ' + bytes.length);
|
|
431
650
|
}
|
|
432
651
|
const padded = new Uint8Array(BYTES);
|
|
@@ -442,8 +661,8 @@ class _Field {
|
|
|
442
661
|
if (!skipValidation)
|
|
443
662
|
if (!this.isValid(scalar))
|
|
444
663
|
throw new Error('invalid field element: outside of range 0..ORDER');
|
|
445
|
-
//
|
|
446
|
-
//
|
|
664
|
+
// Range validation is optional here because some protocols intentionally decode raw residues
|
|
665
|
+
// and reduce or validate them elsewhere.
|
|
447
666
|
return scalar;
|
|
448
667
|
}
|
|
449
668
|
// TODO: we don't need it here, move out to separate fn
|
|
@@ -453,27 +672,40 @@ class _Field {
|
|
|
453
672
|
// We can't move this out because Fp6, Fp12 implement it
|
|
454
673
|
// and it's unclear what to return in there.
|
|
455
674
|
cmov(a, b, condition) {
|
|
675
|
+
// Field elements have `isValid(...)`; the CMOV branch bit is a direct runtime input, so reject
|
|
676
|
+
// non-boolean selectors here instead of letting JS truthiness silently change arithmetic.
|
|
677
|
+
abool(condition, 'condition');
|
|
456
678
|
return condition ? b : a;
|
|
457
679
|
}
|
|
458
680
|
}
|
|
681
|
+
// Freeze the shared method surface too; otherwise callers can still poison every Field instance by
|
|
682
|
+
// monkey-patching `_Field.prototype` even if each instance is frozen.
|
|
683
|
+
Object.freeze(_Field.prototype);
|
|
459
684
|
/**
|
|
460
685
|
* Creates a finite field. Major performance optimizations:
|
|
461
686
|
* * 1. Denormalized operations like mulN instead of mul.
|
|
462
687
|
* * 2. Identical object shape: never add or remove keys.
|
|
463
|
-
* * 3. `
|
|
688
|
+
* * 3. Frozen stable object shape; the lazy sqrt cache lives in a module-level `WeakMap`.
|
|
464
689
|
* Fragile: always run a benchmark on a change.
|
|
465
|
-
* Security note: operations don't check
|
|
466
|
-
*
|
|
690
|
+
* Security note: operations and low-level serializers like `toBytes` don't check `isValid` for
|
|
691
|
+
* all elements for performance and protocol-flexibility reasons; callers are responsible for
|
|
692
|
+
* supplying valid elements when they need canonical field behavior.
|
|
467
693
|
* This is low-level code, please make sure you know what you're doing.
|
|
468
694
|
*
|
|
469
695
|
* Note about field properties:
|
|
470
696
|
* * CHARACTERISTIC p = prime number, number of elements in main subgroup.
|
|
471
697
|
* * ORDER q = similar to cofactor in curves, may be composite `q = p^m`.
|
|
472
698
|
*
|
|
473
|
-
* @param ORDER field order, probably prime, or could be composite
|
|
474
|
-
* @param
|
|
475
|
-
* @
|
|
476
|
-
*
|
|
699
|
+
* @param ORDER - field order, probably prime, or could be composite
|
|
700
|
+
* @param opts - Field options such as bit length or endianness. See {@link FieldOpts}.
|
|
701
|
+
* @returns Frozen field instance with a stable object shape. This wrapper forwards `opts` straight
|
|
702
|
+
* into `_Field`, so it inherits `_Field`'s assumptions about cached sizes and `allowedLengths`.
|
|
703
|
+
* @example
|
|
704
|
+
* Construct one prime field with optional overrides.
|
|
705
|
+
*
|
|
706
|
+
* ```ts
|
|
707
|
+
* Field(11n);
|
|
708
|
+
* ```
|
|
477
709
|
*/
|
|
478
710
|
export function Field(ORDER, opts = {}) {
|
|
479
711
|
return new _Field(ORDER, opts);
|
|
@@ -491,36 +723,88 @@ export function Field(ORDER, opts = {}) {
|
|
|
491
723
|
// const reduced = unsafeAllowZero ? mod(num, ORDER) : mod(num, ORDER - _1n) + _1n;
|
|
492
724
|
// return reduced;
|
|
493
725
|
// },
|
|
726
|
+
/**
|
|
727
|
+
* @param Fp - Field implementation.
|
|
728
|
+
* @param elm - Value to square-root.
|
|
729
|
+
* @returns Odd square root when two roots exist. The special case `elm = 0` still returns `0`,
|
|
730
|
+
* which is the only square root but is not odd.
|
|
731
|
+
* @throws If the field lacks oddness checks or the square root does not exist. {@link Error}
|
|
732
|
+
* @example
|
|
733
|
+
* Select the odd square root when two roots exist.
|
|
734
|
+
*
|
|
735
|
+
* ```ts
|
|
736
|
+
* import { Field, FpSqrtOdd } from '@noble/curves/abstract/modular.js';
|
|
737
|
+
* const Fp = Field(17n);
|
|
738
|
+
* const root = FpSqrtOdd(Fp, 4n);
|
|
739
|
+
* ```
|
|
740
|
+
*/
|
|
494
741
|
export function FpSqrtOdd(Fp, elm) {
|
|
495
|
-
|
|
742
|
+
const F = Fp;
|
|
743
|
+
if (!F.isOdd)
|
|
496
744
|
throw new Error("Field doesn't have isOdd");
|
|
497
|
-
const root =
|
|
498
|
-
return
|
|
745
|
+
const root = F.sqrt(elm);
|
|
746
|
+
return F.isOdd(root) ? root : F.neg(root);
|
|
499
747
|
}
|
|
748
|
+
/**
|
|
749
|
+
* @param Fp - Field implementation.
|
|
750
|
+
* @param elm - Value to square-root.
|
|
751
|
+
* @returns Even square root.
|
|
752
|
+
* @throws If the field lacks oddness checks or the square root does not exist. {@link Error}
|
|
753
|
+
* @example
|
|
754
|
+
* Select the even square root when two roots exist.
|
|
755
|
+
*
|
|
756
|
+
* ```ts
|
|
757
|
+
* import { Field, FpSqrtEven } from '@noble/curves/abstract/modular.js';
|
|
758
|
+
* const Fp = Field(17n);
|
|
759
|
+
* const root = FpSqrtEven(Fp, 4n);
|
|
760
|
+
* ```
|
|
761
|
+
*/
|
|
500
762
|
export function FpSqrtEven(Fp, elm) {
|
|
501
|
-
|
|
763
|
+
const F = Fp;
|
|
764
|
+
if (!F.isOdd)
|
|
502
765
|
throw new Error("Field doesn't have isOdd");
|
|
503
|
-
const root =
|
|
504
|
-
return
|
|
766
|
+
const root = F.sqrt(elm);
|
|
767
|
+
return F.isOdd(root) ? F.neg(root) : root;
|
|
505
768
|
}
|
|
506
769
|
/**
|
|
507
770
|
* Returns total number of bytes consumed by the field element.
|
|
508
771
|
* For example, 32 bytes for usual 256-bit weierstrass curve.
|
|
509
|
-
* @param fieldOrder number of field elements, usually CURVE.n
|
|
772
|
+
* @param fieldOrder - number of field elements, usually CURVE.n. Callers are expected to pass an
|
|
773
|
+
* order greater than 1.
|
|
510
774
|
* @returns byte length of field
|
|
775
|
+
* @throws If the field order is not a bigint. {@link Error}
|
|
776
|
+
* @example
|
|
777
|
+
* Read the fixed-width byte length of one field.
|
|
778
|
+
*
|
|
779
|
+
* ```ts
|
|
780
|
+
* getFieldBytesLength(255n);
|
|
781
|
+
* ```
|
|
511
782
|
*/
|
|
512
783
|
export function getFieldBytesLength(fieldOrder) {
|
|
513
784
|
if (typeof fieldOrder !== 'bigint')
|
|
514
785
|
throw new Error('field order must be bigint');
|
|
515
|
-
|
|
786
|
+
// Valid field elements are in 0..ORDER-1, so ORDER <= 1 would make the encoded range degenerate.
|
|
787
|
+
if (fieldOrder <= _1n)
|
|
788
|
+
throw new Error('field order must be greater than 1');
|
|
789
|
+
// Valid field elements are < ORDER, so the maximal encoded element is ORDER - 1.
|
|
790
|
+
const bitLength = bitLen(fieldOrder - _1n);
|
|
516
791
|
return Math.ceil(bitLength / 8);
|
|
517
792
|
}
|
|
518
793
|
/**
|
|
519
794
|
* Returns minimal amount of bytes that can be safely reduced
|
|
520
795
|
* by field order.
|
|
521
796
|
* Should be 2^-128 for 128-bit curve such as P256.
|
|
522
|
-
*
|
|
797
|
+
* This is the reduction / modulo-bias lower bound; higher-level helpers may still impose a larger
|
|
798
|
+
* absolute floor for policy reasons.
|
|
799
|
+
* @param fieldOrder - number of field elements greater than 1, usually CURVE.n.
|
|
523
800
|
* @returns byte length of target hash
|
|
801
|
+
* @throws If the field order is invalid. {@link Error}
|
|
802
|
+
* @example
|
|
803
|
+
* Compute the minimum hash length needed for field reduction.
|
|
804
|
+
*
|
|
805
|
+
* ```ts
|
|
806
|
+
* getMinHashLength(255n);
|
|
807
|
+
* ```
|
|
524
808
|
*/
|
|
525
809
|
export function getMinHashLength(fieldOrder) {
|
|
526
810
|
const length = getFieldBytesLength(fieldOrder);
|
|
@@ -530,22 +814,33 @@ export function getMinHashLength(fieldOrder) {
|
|
|
530
814
|
* "Constant-time" private key generation utility.
|
|
531
815
|
* Can take (n + n/2) or more bytes of uniform input e.g. from CSPRNG or KDF
|
|
532
816
|
* and convert them into private scalar, with the modulo bias being negligible.
|
|
533
|
-
* Needs at least 48 bytes of input for 32-byte private key.
|
|
534
|
-
*
|
|
535
|
-
*
|
|
536
|
-
*
|
|
537
|
-
* @
|
|
538
|
-
* @
|
|
539
|
-
*
|
|
817
|
+
* Needs at least 48 bytes of input for 32-byte private key. The implementation also keeps a hard
|
|
818
|
+
* 16-byte minimum even when `getMinHashLength(...)` is smaller, so toy-small inputs do not look
|
|
819
|
+
* accidentally acceptable for real scalar derivation.
|
|
820
|
+
* See {@link https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/ | Kudelski's modulo-bias guide},
|
|
821
|
+
* {@link https://csrc.nist.gov/publications/detail/fips/186/5/final | FIPS 186-5 appendix A.2}, and
|
|
822
|
+
* {@link https://www.rfc-editor.org/rfc/rfc9380#section-5 | RFC 9380 section 5}. Unlike RFC 9380
|
|
823
|
+
* `hash_to_field`, this helper intentionally maps into the non-zero private-scalar range `1..n-1`.
|
|
824
|
+
* @param key - Uniform input bytes.
|
|
825
|
+
* @param fieldOrder - Size of subgroup.
|
|
826
|
+
* @param isLE - interpret hash bytes as LE num
|
|
540
827
|
* @returns valid private scalar
|
|
828
|
+
* @throws If the hash length or field order is invalid for scalar reduction. {@link Error}
|
|
829
|
+
* @example
|
|
830
|
+
* Map hash output into a private scalar range.
|
|
831
|
+
*
|
|
832
|
+
* ```ts
|
|
833
|
+
* mapHashToField(new Uint8Array(48).fill(1), 255n);
|
|
834
|
+
* ```
|
|
541
835
|
*/
|
|
542
836
|
export function mapHashToField(key, fieldOrder, isLE = false) {
|
|
543
837
|
abytes(key);
|
|
544
838
|
const len = key.length;
|
|
545
839
|
const fieldLen = getFieldBytesLength(fieldOrder);
|
|
546
|
-
const minLen = getMinHashLength(fieldOrder);
|
|
547
|
-
// No small
|
|
548
|
-
|
|
840
|
+
const minLen = Math.max(getMinHashLength(fieldOrder), 16);
|
|
841
|
+
// No toy-small inputs: the helper is for real scalar derivation, not tiny test curves. No huge
|
|
842
|
+
// inputs: easier to reason about JS timing / allocation behavior.
|
|
843
|
+
if (len < minLen || len > 1024)
|
|
549
844
|
throw new Error('expected ' + minLen + '-1024 bytes of input, got ' + len);
|
|
550
845
|
const num = isLE ? bytesToNumberLE(key) : bytesToNumberBE(key);
|
|
551
846
|
// `mod(x, 11)` can sometimes produce 0. `mod(x, 10) + 1` is the same, but no 0
|