@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/src/abstract/modular.ts
CHANGED
|
@@ -6,13 +6,18 @@
|
|
|
6
6
|
*/
|
|
7
7
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
8
8
|
import {
|
|
9
|
+
abool,
|
|
9
10
|
abytes,
|
|
10
11
|
anumber,
|
|
12
|
+
asafenumber,
|
|
13
|
+
bitLen,
|
|
11
14
|
bytesToNumberBE,
|
|
12
15
|
bytesToNumberLE,
|
|
13
16
|
numberToBytesBE,
|
|
14
17
|
numberToBytesLE,
|
|
15
18
|
validateObject,
|
|
19
|
+
type TArg,
|
|
20
|
+
type TRet,
|
|
16
21
|
} from '../utils.ts';
|
|
17
22
|
|
|
18
23
|
// Numbers aren't used in x25519 / x448 builds
|
|
@@ -24,23 +29,62 @@ const _3n = /* @__PURE__ */ BigInt(3), _4n = /* @__PURE__ */ BigInt(4), _5n = /*
|
|
|
24
29
|
const _7n = /* @__PURE__ */ BigInt(7), _8n = /* @__PURE__ */ BigInt(8), _9n = /* @__PURE__ */ BigInt(9);
|
|
25
30
|
const _16n = /* @__PURE__ */ BigInt(16);
|
|
26
31
|
|
|
27
|
-
|
|
32
|
+
/**
|
|
33
|
+
* @param a - Dividend value.
|
|
34
|
+
* @param b - Positive modulus.
|
|
35
|
+
* @returns Reduced value in `[0, b)` only when `b` is positive.
|
|
36
|
+
* @throws If the modulus is not positive. {@link Error}
|
|
37
|
+
* @example
|
|
38
|
+
* Normalize a bigint into one field residue.
|
|
39
|
+
*
|
|
40
|
+
* ```ts
|
|
41
|
+
* mod(-1n, 5n);
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
28
44
|
export function mod(a: bigint, b: bigint): bigint {
|
|
45
|
+
if (b <= _0n) throw new Error('mod: expected positive modulus, got ' + b);
|
|
29
46
|
const result = a % b;
|
|
30
47
|
return result >= _0n ? result : b + result;
|
|
31
48
|
}
|
|
32
49
|
/**
|
|
33
|
-
* Efficiently raise num to power
|
|
50
|
+
* Efficiently raise num to a power with modular reduction.
|
|
34
51
|
* Unsafe in some contexts: uses ladder, so can expose bigint bits.
|
|
52
|
+
* Low-level helper: callers that need canonical residues must pass a valid `num` for the chosen
|
|
53
|
+
* modulus instead of relying on the `power===0/1` fast paths to normalize it.
|
|
54
|
+
* @param num - Base value.
|
|
55
|
+
* @param power - Exponent value.
|
|
56
|
+
* @param modulo - Reduction modulus.
|
|
57
|
+
* @returns Modular exponentiation result.
|
|
58
|
+
* @throws If the modulus or exponent is invalid. {@link Error}
|
|
35
59
|
* @example
|
|
60
|
+
* Raise one bigint to a modular power.
|
|
61
|
+
*
|
|
62
|
+
* ```ts
|
|
36
63
|
* pow(2n, 6n, 11n) // 64n % 11n == 9n
|
|
64
|
+
* ```
|
|
37
65
|
*/
|
|
38
66
|
export function pow(num: bigint, power: bigint, modulo: bigint): bigint {
|
|
39
67
|
return FpPow(Field(modulo), num, power);
|
|
40
68
|
}
|
|
41
69
|
|
|
42
|
-
/**
|
|
70
|
+
/**
|
|
71
|
+
* Does `x^(2^power)` mod p. `pow2(30, 4)` == `30^(2^4)`.
|
|
72
|
+
* Low-level helper: callers that need canonical residues must pass a valid `x` for the chosen
|
|
73
|
+
* modulus; the `power===0` fast path intentionally returns the input unchanged.
|
|
74
|
+
* @param x - Base value.
|
|
75
|
+
* @param power - Number of squarings.
|
|
76
|
+
* @param modulo - Reduction modulus.
|
|
77
|
+
* @returns Repeated-squaring result.
|
|
78
|
+
* @throws If the exponent is negative. {@link Error}
|
|
79
|
+
* @example
|
|
80
|
+
* Apply repeated squaring inside one field.
|
|
81
|
+
*
|
|
82
|
+
* ```ts
|
|
83
|
+
* pow2(3n, 2n, 11n);
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
43
86
|
export function pow2(x: bigint, power: bigint, modulo: bigint): bigint {
|
|
87
|
+
if (power < _0n) throw new Error('pow2: expected non-negative exponent, got ' + power);
|
|
44
88
|
let res = x;
|
|
45
89
|
while (power-- > _0n) {
|
|
46
90
|
res *= res;
|
|
@@ -51,7 +95,17 @@ export function pow2(x: bigint, power: bigint, modulo: bigint): bigint {
|
|
|
51
95
|
|
|
52
96
|
/**
|
|
53
97
|
* Inverses number over modulo.
|
|
54
|
-
* Implemented using
|
|
98
|
+
* Implemented using the {@link https://brilliant.org/wiki/extended-euclidean-algorithm/ | extended Euclidean algorithm}.
|
|
99
|
+
* @param number - Value to invert.
|
|
100
|
+
* @param modulo - Positive modulus.
|
|
101
|
+
* @returns Multiplicative inverse.
|
|
102
|
+
* @throws If the modulus is invalid or the inverse does not exist. {@link Error}
|
|
103
|
+
* @example
|
|
104
|
+
* Compute one modular inverse with the extended Euclidean algorithm.
|
|
105
|
+
*
|
|
106
|
+
* ```ts
|
|
107
|
+
* invert(3n, 11n);
|
|
108
|
+
* ```
|
|
55
109
|
*/
|
|
56
110
|
export function invert(number: bigint, modulo: bigint): bigint {
|
|
57
111
|
if (number === _0n) throw new Error('invert: expected non-zero number');
|
|
@@ -62,9 +116,8 @@ export function invert(number: bigint, modulo: bigint): bigint {
|
|
|
62
116
|
// prettier-ignore
|
|
63
117
|
let x = _0n, y = _1n, u = _1n, v = _0n;
|
|
64
118
|
while (a !== _0n) {
|
|
65
|
-
// JIT applies optimization if those two lines follow each other
|
|
66
119
|
const q = b / a;
|
|
67
|
-
const r = b
|
|
120
|
+
const r = b - a * q;
|
|
68
121
|
const m = x - u * q;
|
|
69
122
|
const n = y - v * q;
|
|
70
123
|
// prettier-ignore
|
|
@@ -75,65 +128,82 @@ export function invert(number: bigint, modulo: bigint): bigint {
|
|
|
75
128
|
return mod(x, modulo);
|
|
76
129
|
}
|
|
77
130
|
|
|
78
|
-
function assertIsSquare<T>(Fp: IField<T
|
|
79
|
-
|
|
131
|
+
function assertIsSquare<T>(Fp: TArg<IField<T>>, root: T, n: T): void {
|
|
132
|
+
const F = Fp as IField<T>;
|
|
133
|
+
if (!F.eql(F.sqr(root), n)) throw new Error('Cannot find square root');
|
|
80
134
|
}
|
|
81
135
|
|
|
82
136
|
// Not all roots are possible! Example which will throw:
|
|
83
137
|
// const NUM =
|
|
84
138
|
// n = 72057594037927816n;
|
|
85
139
|
// Fp = Field(BigInt('0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab'));
|
|
86
|
-
function sqrt3mod4<T>(Fp: IField<T
|
|
87
|
-
const
|
|
88
|
-
const
|
|
89
|
-
|
|
140
|
+
function sqrt3mod4<T>(Fp: TArg<IField<T>>, n: T) {
|
|
141
|
+
const F = Fp as IField<T>;
|
|
142
|
+
const p1div4 = (F.ORDER + _1n) / _4n;
|
|
143
|
+
const root = F.pow(n, p1div4);
|
|
144
|
+
assertIsSquare(F, root, n);
|
|
90
145
|
return root;
|
|
91
146
|
}
|
|
92
147
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const
|
|
97
|
-
const
|
|
98
|
-
const
|
|
99
|
-
const
|
|
100
|
-
|
|
148
|
+
// Equivalent `q = 5 (mod 8)` square-root formula (Atkin-style), not the RFC Appendix I.2 CMOV
|
|
149
|
+
// pseudocode verbatim.
|
|
150
|
+
function sqrt5mod8<T>(Fp: TArg<IField<T>>, n: T) {
|
|
151
|
+
const F = Fp as IField<T>;
|
|
152
|
+
const p5div8 = (F.ORDER - _5n) / _8n;
|
|
153
|
+
const n2 = F.mul(n, _2n);
|
|
154
|
+
const v = F.pow(n2, p5div8);
|
|
155
|
+
const nv = F.mul(n, v);
|
|
156
|
+
const i = F.mul(F.mul(nv, _2n), v);
|
|
157
|
+
const root = F.mul(nv, F.sub(i, F.ONE));
|
|
158
|
+
assertIsSquare(F, root, n);
|
|
101
159
|
return root;
|
|
102
160
|
}
|
|
103
161
|
|
|
104
162
|
// Based on RFC9380, Kong algorithm
|
|
105
163
|
// prettier-ignore
|
|
106
|
-
function sqrt9mod16(P: bigint):
|
|
164
|
+
function sqrt9mod16(P: bigint): TRet<<T>(Fp: IField<T>, n: T) => T> {
|
|
107
165
|
const Fp_ = Field(P);
|
|
108
166
|
const tn = tonelliShanks(P);
|
|
109
167
|
const c1 = tn(Fp_, Fp_.neg(Fp_.ONE));// 1. c1 = sqrt(-1) in F, i.e., (c1^2) == -1 in F
|
|
110
168
|
const c2 = tn(Fp_, c1); // 2. c2 = sqrt(c1) in F, i.e., (c2^2) == c1 in F
|
|
111
169
|
const c3 = tn(Fp_, Fp_.neg(c1)); // 3. c3 = sqrt(-c1) in F, i.e., (c3^2) == -c1 in F
|
|
112
170
|
const c4 = (P + _7n) / _16n; // 4. c4 = (q + 7) / 16 # Integer arithmetic
|
|
113
|
-
return <T>(Fp: IField<T
|
|
114
|
-
|
|
115
|
-
let
|
|
116
|
-
|
|
117
|
-
const
|
|
118
|
-
const
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const
|
|
124
|
-
|
|
171
|
+
return (<T>(Fp: TArg<IField<T>>, n: T): T => {
|
|
172
|
+
const F = Fp as IField<T>;
|
|
173
|
+
let tv1 = F.pow(n, c4); // 1. tv1 = x^c4
|
|
174
|
+
let tv2 = F.mul(tv1, c1); // 2. tv2 = c1 * tv1
|
|
175
|
+
const tv3 = F.mul(tv1, c2); // 3. tv3 = c2 * tv1
|
|
176
|
+
const tv4 = F.mul(tv1, c3); // 4. tv4 = c3 * tv1
|
|
177
|
+
const e1 = F.eql(F.sqr(tv2), n); // 5. e1 = (tv2^2) == x
|
|
178
|
+
const e2 = F.eql(F.sqr(tv3), n); // 6. e2 = (tv3^2) == x
|
|
179
|
+
tv1 = F.cmov(tv1, tv2, e1); // 7. tv1 = CMOV(tv1, tv2, e1) # Select tv2 if (tv2^2) == x
|
|
180
|
+
tv2 = F.cmov(tv4, tv3, e2); // 8. tv2 = CMOV(tv4, tv3, e2) # Select tv3 if (tv3^2) == x
|
|
181
|
+
const e3 = F.eql(F.sqr(tv2), n); // 9. e3 = (tv2^2) == x
|
|
182
|
+
const root = F.cmov(tv1, tv2, e3); // 10. z = CMOV(tv1, tv2, e3) # Select sqrt from tv1 & tv2
|
|
183
|
+
assertIsSquare(F, root, n);
|
|
125
184
|
return root;
|
|
126
|
-
}
|
|
185
|
+
}) as TRet<<T>(Fp: IField<T>, n: T) => T>;
|
|
127
186
|
}
|
|
128
187
|
|
|
129
188
|
/**
|
|
130
189
|
* Tonelli-Shanks square root search algorithm.
|
|
131
|
-
*
|
|
190
|
+
* This implementation is variable-time: it searches data-dependently for the first non-residue `Z`
|
|
191
|
+
* and for the smallest `i` in the main loop, unlike RFC 9380 Appendix I.4's constant-time shape.
|
|
192
|
+
* 1. {@link https://eprint.iacr.org/2012/685.pdf | eprint 2012/685}, page 12
|
|
132
193
|
* 2. Square Roots from 1; 24, 51, 10 to Dan Shanks
|
|
133
|
-
* @param P field order
|
|
194
|
+
* @param P - field order
|
|
134
195
|
* @returns function that takes field Fp (created from P) and number n
|
|
196
|
+
* @throws If the field is too small, non-prime, or the square root does not exist. {@link Error}
|
|
197
|
+
* @example
|
|
198
|
+
* Construct a square-root helper for primes that need Tonelli-Shanks.
|
|
199
|
+
*
|
|
200
|
+
* ```ts
|
|
201
|
+
* import { Field, tonelliShanks } from '@noble/curves/abstract/modular.js';
|
|
202
|
+
* const Fp = Field(17n);
|
|
203
|
+
* const sqrt = tonelliShanks(17n)(Fp, 4n);
|
|
204
|
+
* ```
|
|
135
205
|
*/
|
|
136
|
-
export function tonelliShanks(P: bigint):
|
|
206
|
+
export function tonelliShanks(P: bigint): TRet<<T>(Fp: IField<T>, n: T) => T> {
|
|
137
207
|
// Initialization (precomputation).
|
|
138
208
|
// Caching initialization could boost perf by 7%.
|
|
139
209
|
if (P < _3n) throw new Error('sqrt is not defined for small field');
|
|
@@ -154,49 +224,50 @@ export function tonelliShanks(P: bigint): <T>(Fp: IField<T>, n: T) => T {
|
|
|
154
224
|
if (Z++ > 1000) throw new Error('Cannot find square root: probably non-prime P');
|
|
155
225
|
}
|
|
156
226
|
// Fast-path; usually done before Z, but we do "primality test".
|
|
157
|
-
if (S === 1) return sqrt3mod4
|
|
227
|
+
if (S === 1) return sqrt3mod4 as TRet<<T>(Fp: IField<T>, n: T) => T>;
|
|
158
228
|
|
|
159
229
|
// Slow-path
|
|
160
230
|
// TODO: test on Fp2 and others
|
|
161
231
|
let cc = _Fp.pow(Z, Q); // c = z^Q
|
|
162
232
|
const Q1div2 = (Q + _1n) / _2n;
|
|
163
|
-
return function tonelliSlow<T>(Fp: IField<T
|
|
164
|
-
|
|
233
|
+
return function tonelliSlow<T>(Fp: TArg<IField<T>>, n: T): T {
|
|
234
|
+
const F = Fp as IField<T>;
|
|
235
|
+
if (F.is0(n)) return n;
|
|
165
236
|
// Check if n is a quadratic residue using Legendre symbol
|
|
166
|
-
if (FpLegendre(
|
|
237
|
+
if (FpLegendre(F, n) !== 1) throw new Error('Cannot find square root');
|
|
167
238
|
|
|
168
239
|
// Initialize variables for the main loop
|
|
169
240
|
let M = S;
|
|
170
|
-
let c =
|
|
171
|
-
let t =
|
|
172
|
-
let R =
|
|
241
|
+
let c = F.mul(F.ONE, cc); // c = z^Q, move cc from field _Fp into field Fp
|
|
242
|
+
let t = F.pow(n, Q); // t = n^Q, first guess at the fudge factor
|
|
243
|
+
let R = F.pow(n, Q1div2); // R = n^((Q+1)/2), first guess at the square root
|
|
173
244
|
|
|
174
245
|
// Main loop
|
|
175
246
|
// while t != 1
|
|
176
|
-
while (!
|
|
177
|
-
if (
|
|
247
|
+
while (!F.eql(t, F.ONE)) {
|
|
248
|
+
if (F.is0(t)) return F.ZERO; // if t=0 return R=0
|
|
178
249
|
let i = 1;
|
|
179
250
|
|
|
180
251
|
// Find the smallest i >= 1 such that t^(2^i) ≡ 1 (mod P)
|
|
181
|
-
let t_tmp =
|
|
182
|
-
while (!
|
|
252
|
+
let t_tmp = F.sqr(t); // t^(2^1)
|
|
253
|
+
while (!F.eql(t_tmp, F.ONE)) {
|
|
183
254
|
i++;
|
|
184
|
-
t_tmp =
|
|
255
|
+
t_tmp = F.sqr(t_tmp); // t^(2^2)...
|
|
185
256
|
if (i === M) throw new Error('Cannot find square root');
|
|
186
257
|
}
|
|
187
258
|
|
|
188
259
|
// Calculate the exponent for b: 2^(M - i - 1)
|
|
189
260
|
const exponent = _1n << BigInt(M - i - 1); // bigint is important
|
|
190
|
-
const b =
|
|
261
|
+
const b = F.pow(c, exponent); // b = 2^(M - i - 1)
|
|
191
262
|
|
|
192
263
|
// Update variables
|
|
193
264
|
M = i;
|
|
194
|
-
c =
|
|
195
|
-
t =
|
|
196
|
-
R =
|
|
265
|
+
c = F.sqr(b); // c = b^2
|
|
266
|
+
t = F.mul(t, c); // t = (t * b^2)
|
|
267
|
+
R = F.mul(R, b); // R = R*b
|
|
197
268
|
}
|
|
198
269
|
return R;
|
|
199
|
-
}
|
|
270
|
+
} as TRet<<T>(Fp: IField<T>, n: T) => T>;
|
|
200
271
|
}
|
|
201
272
|
|
|
202
273
|
/**
|
|
@@ -208,72 +279,255 @@ export function tonelliShanks(P: bigint): <T>(Fp: IField<T>, n: T) => T {
|
|
|
208
279
|
* 4. Tonelli-Shanks algorithm
|
|
209
280
|
*
|
|
210
281
|
* Different algorithms can give different roots, it is up to user to decide which one they want.
|
|
211
|
-
* For example there is FpSqrtOdd/FpSqrtEven to
|
|
282
|
+
* For example there is FpSqrtOdd/FpSqrtEven to choose a root by oddness
|
|
283
|
+
* (used for hash-to-curve).
|
|
284
|
+
* @param P - Field order.
|
|
285
|
+
* @returns Square-root helper. The generic fallback inherits Tonelli-Shanks' variable-time
|
|
286
|
+
* behavior and this selector assumes prime-field-style integer moduli.
|
|
287
|
+
* @throws If the field is unsupported or the square root does not exist. {@link Error}
|
|
288
|
+
* @example
|
|
289
|
+
* Choose the square-root helper appropriate for one field modulus.
|
|
290
|
+
*
|
|
291
|
+
* ```ts
|
|
292
|
+
* import { Field, FpSqrt } from '@noble/curves/abstract/modular.js';
|
|
293
|
+
* const Fp = Field(17n);
|
|
294
|
+
* const sqrt = FpSqrt(17n)(Fp, 4n);
|
|
295
|
+
* ```
|
|
212
296
|
*/
|
|
213
|
-
export function FpSqrt(P: bigint):
|
|
297
|
+
export function FpSqrt(P: bigint): TRet<<T>(Fp: IField<T>, n: T) => T> {
|
|
214
298
|
// P ≡ 3 (mod 4) => √n = n^((P+1)/4)
|
|
215
|
-
if (P % _4n === _3n) return sqrt3mod4
|
|
299
|
+
if (P % _4n === _3n) return sqrt3mod4 as TRet<<T>(Fp: IField<T>, n: T) => T>;
|
|
216
300
|
// P ≡ 5 (mod 8) => Atkin algorithm, page 10 of https://eprint.iacr.org/2012/685.pdf
|
|
217
|
-
if (P % _8n === _5n) return sqrt5mod8
|
|
301
|
+
if (P % _8n === _5n) return sqrt5mod8 as TRet<<T>(Fp: IField<T>, n: T) => T>;
|
|
218
302
|
// P ≡ 9 (mod 16) => Kong algorithm, page 11 of https://eprint.iacr.org/2012/685.pdf (algorithm 4)
|
|
219
303
|
if (P % _16n === _9n) return sqrt9mod16(P);
|
|
220
304
|
// Tonelli-Shanks algorithm
|
|
221
305
|
return tonelliShanks(P);
|
|
222
306
|
}
|
|
223
307
|
|
|
224
|
-
|
|
308
|
+
/**
|
|
309
|
+
* @param num - Value to inspect.
|
|
310
|
+
* @param modulo - Field modulus.
|
|
311
|
+
* @returns `true` when the least-significant little-endian bit is set.
|
|
312
|
+
* @throws If the modulus is invalid for `mod(...)`. {@link Error}
|
|
313
|
+
* @example
|
|
314
|
+
* Inspect the low bit used by little-endian sign conventions.
|
|
315
|
+
*
|
|
316
|
+
* ```ts
|
|
317
|
+
* isNegativeLE(3n, 11n);
|
|
318
|
+
* ```
|
|
319
|
+
*/
|
|
225
320
|
export const isNegativeLE = (num: bigint, modulo: bigint): boolean =>
|
|
226
321
|
(mod(num, modulo) & _1n) === _1n;
|
|
227
322
|
|
|
228
|
-
/**
|
|
323
|
+
/** Generic field interface used by prime and extension fields alike.
|
|
324
|
+
* Generic helpers treat field operations as pure functions: implementations MUST treat provided
|
|
325
|
+
* values/byte buffers as read-only and return detached results instead of mutating arguments.
|
|
326
|
+
*/
|
|
229
327
|
export interface IField<T> {
|
|
328
|
+
/** Field order `q`, which may be prime or a prime power. */
|
|
230
329
|
ORDER: bigint;
|
|
330
|
+
/** Canonical encoded byte length. */
|
|
231
331
|
BYTES: number;
|
|
332
|
+
/** Canonical encoded bit length. */
|
|
232
333
|
BITS: number;
|
|
334
|
+
/** Whether encoded field elements use little-endian bytes. */
|
|
233
335
|
isLE: boolean;
|
|
336
|
+
/** Additive identity. */
|
|
234
337
|
ZERO: T;
|
|
338
|
+
/** Multiplicative identity. */
|
|
235
339
|
ONE: T;
|
|
236
340
|
// 1-arg
|
|
341
|
+
/**
|
|
342
|
+
* Normalize one value into the field.
|
|
343
|
+
* @param num - Input value.
|
|
344
|
+
* @returns Normalized field value.
|
|
345
|
+
*/
|
|
237
346
|
create: (num: T) => T;
|
|
347
|
+
/**
|
|
348
|
+
* Check whether one value already belongs to the field.
|
|
349
|
+
* @param num - Input value.
|
|
350
|
+
* Implementations may throw `TypeError` on malformed input types instead of returning `false`.
|
|
351
|
+
* @returns Whether the value already belongs to the field.
|
|
352
|
+
*/
|
|
238
353
|
isValid: (num: T) => boolean;
|
|
354
|
+
/**
|
|
355
|
+
* Check whether one value is zero.
|
|
356
|
+
* @param num - Input value.
|
|
357
|
+
* @returns Whether the value is zero.
|
|
358
|
+
*/
|
|
239
359
|
is0: (num: T) => boolean;
|
|
360
|
+
/**
|
|
361
|
+
* Check whether one value is non-zero and belongs to the field.
|
|
362
|
+
* @param num - Input value.
|
|
363
|
+
* Implementations may throw `TypeError` on malformed input types instead of returning `false`.
|
|
364
|
+
* @returns Whether the value is non-zero and valid.
|
|
365
|
+
*/
|
|
240
366
|
isValidNot0: (num: T) => boolean;
|
|
367
|
+
/**
|
|
368
|
+
* Negate one value.
|
|
369
|
+
* @param num - Input value.
|
|
370
|
+
* @returns Negated value.
|
|
371
|
+
*/
|
|
241
372
|
neg(num: T): T;
|
|
373
|
+
/**
|
|
374
|
+
* Invert one value multiplicatively.
|
|
375
|
+
* @param num - Input value.
|
|
376
|
+
* @returns Multiplicative inverse.
|
|
377
|
+
*/
|
|
242
378
|
inv(num: T): T;
|
|
379
|
+
/**
|
|
380
|
+
* Compute one square root when it exists.
|
|
381
|
+
* @param num - Input value.
|
|
382
|
+
* @returns Square root.
|
|
383
|
+
*/
|
|
243
384
|
sqrt(num: T): T;
|
|
385
|
+
/**
|
|
386
|
+
* Square one value.
|
|
387
|
+
* @param num - Input value.
|
|
388
|
+
* @returns Squared value.
|
|
389
|
+
*/
|
|
244
390
|
sqr(num: T): T;
|
|
245
391
|
// 2-args
|
|
392
|
+
/**
|
|
393
|
+
* Compare two field values.
|
|
394
|
+
* @param lhs - Left value.
|
|
395
|
+
* @param rhs - Right value.
|
|
396
|
+
* @returns Whether both values are equal.
|
|
397
|
+
*/
|
|
246
398
|
eql(lhs: T, rhs: T): boolean;
|
|
399
|
+
/**
|
|
400
|
+
* Add two normalized field values.
|
|
401
|
+
* @param lhs - Left value.
|
|
402
|
+
* @param rhs - Right value.
|
|
403
|
+
* @returns Sum value.
|
|
404
|
+
*/
|
|
247
405
|
add(lhs: T, rhs: T): T;
|
|
406
|
+
/**
|
|
407
|
+
* Subtract two normalized field values.
|
|
408
|
+
* @param lhs - Left value.
|
|
409
|
+
* @param rhs - Right value.
|
|
410
|
+
* @returns Difference value.
|
|
411
|
+
*/
|
|
248
412
|
sub(lhs: T, rhs: T): T;
|
|
413
|
+
/**
|
|
414
|
+
* Multiply two field values.
|
|
415
|
+
* @param lhs - Left value.
|
|
416
|
+
* @param rhs - Right value or scalar.
|
|
417
|
+
* @returns Product value.
|
|
418
|
+
*/
|
|
249
419
|
mul(lhs: T, rhs: T | bigint): T;
|
|
420
|
+
/**
|
|
421
|
+
* Raise one field value to a power.
|
|
422
|
+
* @param lhs - Base value.
|
|
423
|
+
* @param power - Exponent.
|
|
424
|
+
* @returns Power value.
|
|
425
|
+
*/
|
|
250
426
|
pow(lhs: T, power: bigint): T;
|
|
427
|
+
/**
|
|
428
|
+
* Divide one field value by another.
|
|
429
|
+
* @param lhs - Dividend.
|
|
430
|
+
* @param rhs - Divisor or scalar.
|
|
431
|
+
* @returns Quotient value.
|
|
432
|
+
*/
|
|
251
433
|
div(lhs: T, rhs: T | bigint): T;
|
|
252
434
|
// N for NonNormalized (for now)
|
|
435
|
+
/**
|
|
436
|
+
* Add two values without re-normalizing the result.
|
|
437
|
+
* @param lhs - Left value.
|
|
438
|
+
* @param rhs - Right value.
|
|
439
|
+
* @returns Non-normalized sum.
|
|
440
|
+
*/
|
|
253
441
|
addN(lhs: T, rhs: T): T;
|
|
442
|
+
/**
|
|
443
|
+
* Subtract two values without re-normalizing the result.
|
|
444
|
+
* @param lhs - Left value.
|
|
445
|
+
* @param rhs - Right value.
|
|
446
|
+
* @returns Non-normalized difference.
|
|
447
|
+
*/
|
|
254
448
|
subN(lhs: T, rhs: T): T;
|
|
449
|
+
/**
|
|
450
|
+
* Multiply two values without re-normalizing the result.
|
|
451
|
+
* @param lhs - Left value.
|
|
452
|
+
* @param rhs - Right value or scalar.
|
|
453
|
+
* @returns Non-normalized product.
|
|
454
|
+
*/
|
|
255
455
|
mulN(lhs: T, rhs: T | bigint): T;
|
|
456
|
+
/**
|
|
457
|
+
* Square one value without re-normalizing the result.
|
|
458
|
+
* @param num - Input value.
|
|
459
|
+
* @returns Non-normalized square.
|
|
460
|
+
*/
|
|
256
461
|
sqrN(num: T): T;
|
|
257
462
|
|
|
258
463
|
// Optional
|
|
259
464
|
// Should be same as sgn0 function in
|
|
260
465
|
// [RFC9380](https://www.rfc-editor.org/rfc/rfc9380#section-4.1).
|
|
261
|
-
// NOTE: sgn0 is
|
|
262
|
-
|
|
466
|
+
// NOTE: sgn0 is "negative in LE", which is the same as odd.
|
|
467
|
+
// Negative in LE is a somewhat strange definition anyway.
|
|
468
|
+
/**
|
|
469
|
+
* Return the RFC 9380 `sgn0`-style oddness bit when supported.
|
|
470
|
+
* This uses oddness instead of evenness so extension fields like Fp2 can expose the same hook.
|
|
471
|
+
* Returns whether the value is odd under the field encoding.
|
|
472
|
+
*/
|
|
473
|
+
isOdd?(num: T): boolean;
|
|
263
474
|
// legendre?(num: T): T;
|
|
475
|
+
/**
|
|
476
|
+
* Invert many field elements in one batch.
|
|
477
|
+
* @param lst - Values to invert.
|
|
478
|
+
* @returns Batch of inverses.
|
|
479
|
+
*/
|
|
264
480
|
invertBatch: (lst: T[]) => T[];
|
|
481
|
+
/**
|
|
482
|
+
* Encode one field value into fixed-width bytes.
|
|
483
|
+
* Callers that need canonical encodings MUST supply a valid field element.
|
|
484
|
+
* Low-level protocols may also use this to serialize raw / non-canonical residues.
|
|
485
|
+
* @param num - Input value.
|
|
486
|
+
* @returns Fixed-width byte encoding.
|
|
487
|
+
*/
|
|
265
488
|
toBytes(num: T): Uint8Array;
|
|
489
|
+
/**
|
|
490
|
+
* Decode one field value from fixed-width bytes.
|
|
491
|
+
* @param bytes - Fixed-width byte encoding.
|
|
492
|
+
* @param skipValidation - Whether to skip range validation.
|
|
493
|
+
* Implementations MUST treat `bytes` as read-only.
|
|
494
|
+
* @returns Decoded field value.
|
|
495
|
+
*/
|
|
266
496
|
fromBytes(bytes: Uint8Array, skipValidation?: boolean): T;
|
|
267
497
|
// If c is False, CMOV returns a, otherwise it returns b.
|
|
498
|
+
/**
|
|
499
|
+
* Constant-time conditional move.
|
|
500
|
+
* @param a - Value used when the condition is false.
|
|
501
|
+
* @param b - Value used when the condition is true.
|
|
502
|
+
* @param c - Selection bit.
|
|
503
|
+
* @returns Selected value.
|
|
504
|
+
*/
|
|
268
505
|
cmov(a: T, b: T, c: boolean): T;
|
|
269
506
|
}
|
|
270
507
|
// prettier-ignore
|
|
508
|
+
// Arithmetic-only subset checked by validateField(). This is intentionally not the full runtime
|
|
509
|
+
// IField contract: helpers like `isValidNot0`, `invertBatch`, `toBytes`, `fromBytes`, `cmov`, and
|
|
510
|
+
// field-specific extras like `isOdd` are left to the callers that actually need them.
|
|
271
511
|
const FIELD_FIELDS = [
|
|
272
512
|
'create', 'isValid', 'is0', 'neg', 'inv', 'sqrt', 'sqr',
|
|
273
513
|
'eql', 'add', 'sub', 'mul', 'pow', 'div',
|
|
274
514
|
'addN', 'subN', 'mulN', 'sqrN'
|
|
275
515
|
] as const;
|
|
276
|
-
|
|
516
|
+
/**
|
|
517
|
+
* @param field - Field implementation.
|
|
518
|
+
* @returns Validated field. This only checks the arithmetic subset needed by generic helpers; it
|
|
519
|
+
* does not guarantee full runtime-method coverage for serialization, batching, `cmov`, or
|
|
520
|
+
* field-specific extras beyond positive `BYTES` / `BITS`.
|
|
521
|
+
* @throws If the field shape or numeric metadata are invalid. {@link Error}
|
|
522
|
+
* @example
|
|
523
|
+
* Check that a field implementation exposes the operations curve code expects.
|
|
524
|
+
*
|
|
525
|
+
* ```ts
|
|
526
|
+
* import { Field, validateField } from '@noble/curves/abstract/modular.js';
|
|
527
|
+
* const Fp = validateField(Field(17n));
|
|
528
|
+
* ```
|
|
529
|
+
*/
|
|
530
|
+
export function validateField<T>(field: TArg<IField<T>>): TRet<IField<T>> {
|
|
277
531
|
const initial = {
|
|
278
532
|
ORDER: 'bigint',
|
|
279
533
|
BYTES: 'number',
|
|
@@ -284,10 +538,15 @@ export function validateField<T>(field: IField<T>): IField<T> {
|
|
|
284
538
|
return map;
|
|
285
539
|
}, initial);
|
|
286
540
|
validateObject(field, opts);
|
|
287
|
-
//
|
|
288
|
-
//
|
|
289
|
-
|
|
290
|
-
|
|
541
|
+
// Runtime field implementations must expose real integer byte/bit sizes; fractional / NaN /
|
|
542
|
+
// infinite metadata leaks through validateObject(type='number') but breaks encoders and caches.
|
|
543
|
+
asafenumber(field.BYTES, 'BYTES');
|
|
544
|
+
asafenumber(field.BITS, 'BITS');
|
|
545
|
+
// Runtime field implementations must expose positive byte/bit sizes; zero leaks through the
|
|
546
|
+
// numeric shape checks above but still breaks encoding helpers and cached-length assumptions.
|
|
547
|
+
if (field.BYTES < 1 || field.BITS < 1) throw new Error('invalid field: expected BYTES/BITS > 0');
|
|
548
|
+
if (field.ORDER <= _1n) throw new Error('invalid field: expected ORDER > 1, got ' + field.ORDER);
|
|
549
|
+
return field as TRet<IField<T>>;
|
|
291
550
|
}
|
|
292
551
|
|
|
293
552
|
// Generic field functions
|
|
@@ -295,16 +554,30 @@ export function validateField<T>(field: IField<T>): IField<T> {
|
|
|
295
554
|
/**
|
|
296
555
|
* Same as `pow` but for Fp: non-constant-time.
|
|
297
556
|
* Unsafe in some contexts: uses ladder, so can expose bigint bits.
|
|
557
|
+
* @param Fp - Field implementation.
|
|
558
|
+
* @param num - Base value.
|
|
559
|
+
* @param power - Exponent value.
|
|
560
|
+
* @returns Powered field element.
|
|
561
|
+
* @throws If the exponent is negative. {@link Error}
|
|
562
|
+
* @example
|
|
563
|
+
* Raise one field element to a public exponent.
|
|
564
|
+
*
|
|
565
|
+
* ```ts
|
|
566
|
+
* import { Field, FpPow } from '@noble/curves/abstract/modular.js';
|
|
567
|
+
* const Fp = Field(17n);
|
|
568
|
+
* const x = FpPow(Fp, 3n, 5n);
|
|
569
|
+
* ```
|
|
298
570
|
*/
|
|
299
|
-
export function FpPow<T>(Fp: IField<T
|
|
571
|
+
export function FpPow<T>(Fp: TArg<IField<T>>, num: T, power: bigint): T {
|
|
572
|
+
const F = Fp as IField<T>;
|
|
300
573
|
if (power < _0n) throw new Error('invalid exponent, negatives unsupported');
|
|
301
|
-
if (power === _0n) return
|
|
574
|
+
if (power === _0n) return F.ONE;
|
|
302
575
|
if (power === _1n) return num;
|
|
303
|
-
let p =
|
|
576
|
+
let p = F.ONE;
|
|
304
577
|
let d = num;
|
|
305
578
|
while (power > _0n) {
|
|
306
|
-
if (power & _1n) p =
|
|
307
|
-
d =
|
|
579
|
+
if (power & _1n) p = F.mul(p, d);
|
|
580
|
+
d = F.sqr(d);
|
|
308
581
|
power >>= _1n;
|
|
309
582
|
}
|
|
310
583
|
return p;
|
|
@@ -312,31 +585,58 @@ export function FpPow<T>(Fp: IField<T>, num: T, power: bigint): T {
|
|
|
312
585
|
|
|
313
586
|
/**
|
|
314
587
|
* Efficiently invert an array of Field elements.
|
|
315
|
-
* Exception-free.
|
|
316
|
-
* @param
|
|
588
|
+
* Exception-free. Zero-valued field elements stay `undefined` unless `passZero` is enabled.
|
|
589
|
+
* @param Fp - Field implementation.
|
|
590
|
+
* @param nums - Values to invert.
|
|
591
|
+
* @param passZero - map 0 to 0 (instead of undefined)
|
|
592
|
+
* @returns Inverted values.
|
|
593
|
+
* @example
|
|
594
|
+
* Invert several field elements with one shared inversion.
|
|
595
|
+
*
|
|
596
|
+
* ```ts
|
|
597
|
+
* import { Field, FpInvertBatch } from '@noble/curves/abstract/modular.js';
|
|
598
|
+
* const Fp = Field(17n);
|
|
599
|
+
* const inv = FpInvertBatch(Fp, [1n, 2n, 4n]);
|
|
600
|
+
* ```
|
|
317
601
|
*/
|
|
318
|
-
export function FpInvertBatch<T>(Fp: IField<T
|
|
319
|
-
const
|
|
602
|
+
export function FpInvertBatch<T>(Fp: TArg<IField<T>>, nums: T[], passZero = false): T[] {
|
|
603
|
+
const F = Fp as IField<T>;
|
|
604
|
+
const inverted = new Array(nums.length).fill(passZero ? F.ZERO : undefined) as T[];
|
|
320
605
|
// Walk from first to last, multiply them by each other MOD p
|
|
321
606
|
const multipliedAcc = nums.reduce((acc, num, i) => {
|
|
322
|
-
if (
|
|
607
|
+
if (F.is0(num)) return acc;
|
|
323
608
|
inverted[i] = acc;
|
|
324
|
-
return
|
|
325
|
-
},
|
|
609
|
+
return F.mul(acc, num);
|
|
610
|
+
}, F.ONE);
|
|
326
611
|
// Invert last element
|
|
327
|
-
const invertedAcc =
|
|
612
|
+
const invertedAcc = F.inv(multipliedAcc);
|
|
328
613
|
// Walk from last to first, multiply them by inverted each other MOD p
|
|
329
614
|
nums.reduceRight((acc, num, i) => {
|
|
330
|
-
if (
|
|
331
|
-
inverted[i] =
|
|
332
|
-
return
|
|
615
|
+
if (F.is0(num)) return acc;
|
|
616
|
+
inverted[i] = F.mul(acc, inverted[i]);
|
|
617
|
+
return F.mul(acc, num);
|
|
333
618
|
}, invertedAcc);
|
|
334
619
|
return inverted;
|
|
335
620
|
}
|
|
336
621
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
622
|
+
/**
|
|
623
|
+
* @param Fp - Field implementation.
|
|
624
|
+
* @param lhs - Dividend value.
|
|
625
|
+
* @param rhs - Divisor value.
|
|
626
|
+
* @returns Division result.
|
|
627
|
+
* @throws If the divisor is non-invertible. {@link Error}
|
|
628
|
+
* @example
|
|
629
|
+
* Divide one field element by another.
|
|
630
|
+
*
|
|
631
|
+
* ```ts
|
|
632
|
+
* import { Field, FpDiv } from '@noble/curves/abstract/modular.js';
|
|
633
|
+
* const Fp = Field(17n);
|
|
634
|
+
* const x = FpDiv(Fp, 6n, 3n);
|
|
635
|
+
* ```
|
|
636
|
+
*/
|
|
637
|
+
export function FpDiv<T>(Fp: TArg<IField<T>>, lhs: T, rhs: T | bigint): T {
|
|
638
|
+
const F = Fp as IField<T>;
|
|
639
|
+
return F.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, F.ORDER) : F.inv(rhs));
|
|
340
640
|
}
|
|
341
641
|
|
|
342
642
|
/**
|
|
@@ -347,31 +647,85 @@ export function FpDiv<T>(Fp: IField<T>, lhs: T, rhs: T | bigint): T {
|
|
|
347
647
|
* * (a | p) ≡ 1 if a is a square (mod p), quadratic residue
|
|
348
648
|
* * (a | p) ≡ -1 if a is not a square (mod p), quadratic non residue
|
|
349
649
|
* * (a | p) ≡ 0 if a ≡ 0 (mod p)
|
|
650
|
+
* @param Fp - Field implementation.
|
|
651
|
+
* @param n - Value to inspect.
|
|
652
|
+
* @returns Legendre symbol.
|
|
653
|
+
* @throws If the field returns an invalid Legendre symbol value. {@link Error}
|
|
654
|
+
* @example
|
|
655
|
+
* Compute the Legendre symbol of one field element.
|
|
656
|
+
*
|
|
657
|
+
* ```ts
|
|
658
|
+
* import { Field, FpLegendre } from '@noble/curves/abstract/modular.js';
|
|
659
|
+
* const Fp = Field(17n);
|
|
660
|
+
* const symbol = FpLegendre(Fp, 4n);
|
|
661
|
+
* ```
|
|
350
662
|
*/
|
|
351
|
-
export function FpLegendre<T>(Fp: IField<T
|
|
663
|
+
export function FpLegendre<T>(Fp: TArg<IField<T>>, n: T): -1 | 0 | 1 {
|
|
664
|
+
const F = Fp as IField<T>;
|
|
352
665
|
// We can use 3rd argument as optional cache of this value
|
|
353
666
|
// but seems unneeded for now. The operation is very fast.
|
|
354
|
-
const p1mod2 = (
|
|
355
|
-
const powered =
|
|
356
|
-
const yes =
|
|
357
|
-
const zero =
|
|
358
|
-
const no =
|
|
667
|
+
const p1mod2 = (F.ORDER - _1n) / _2n;
|
|
668
|
+
const powered = F.pow(n, p1mod2);
|
|
669
|
+
const yes = F.eql(powered, F.ONE);
|
|
670
|
+
const zero = F.eql(powered, F.ZERO);
|
|
671
|
+
const no = F.eql(powered, F.neg(F.ONE));
|
|
359
672
|
if (!yes && !zero && !no) throw new Error('invalid Legendre symbol result');
|
|
360
673
|
return yes ? 1 : zero ? 0 : -1;
|
|
361
674
|
}
|
|
362
675
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
676
|
+
/**
|
|
677
|
+
* @param Fp - Field implementation.
|
|
678
|
+
* @param n - Value to inspect.
|
|
679
|
+
* @returns `true` when `Fp.sqrt(n)` exists. This includes `0`, even though strict "quadratic
|
|
680
|
+
* residue" terminology often reserves that name for the non-zero square class.
|
|
681
|
+
* @throws If the field returns an invalid Legendre symbol value. {@link Error}
|
|
682
|
+
* @example
|
|
683
|
+
* Check whether one field element has a square root in the field.
|
|
684
|
+
*
|
|
685
|
+
* ```ts
|
|
686
|
+
* import { Field, FpIsSquare } from '@noble/curves/abstract/modular.js';
|
|
687
|
+
* const Fp = Field(17n);
|
|
688
|
+
* const isSquare = FpIsSquare(Fp, 4n);
|
|
689
|
+
* ```
|
|
690
|
+
*/
|
|
691
|
+
export function FpIsSquare<T>(Fp: TArg<IField<T>>, n: T): boolean {
|
|
692
|
+
const l = FpLegendre(Fp as IField<T>, n);
|
|
693
|
+
// Zero is a square too: 0 = 0^2, and Fp.sqrt(0) already returns 0.
|
|
694
|
+
return l !== -1;
|
|
367
695
|
}
|
|
368
696
|
|
|
369
|
-
|
|
370
|
-
|
|
697
|
+
/** Byte and bit lengths derived from one scalar order. */
|
|
698
|
+
export type NLength = {
|
|
699
|
+
/** Canonical byte length. */
|
|
700
|
+
nByteLength: number;
|
|
701
|
+
/** Canonical bit length. */
|
|
702
|
+
nBitLength: number;
|
|
703
|
+
};
|
|
704
|
+
/**
|
|
705
|
+
* @param n - Curve order. Callers are expected to pass a positive order.
|
|
706
|
+
* @param nBitLength - Optional cached bit length. Callers are expected to pass a positive cached
|
|
707
|
+
* value when overriding the derived bit length.
|
|
708
|
+
* @returns Byte and bit lengths.
|
|
709
|
+
* @throws If the order or cached bit length is invalid. {@link Error}
|
|
710
|
+
* @example
|
|
711
|
+
* Measure the encoding sizes needed for one modulus.
|
|
712
|
+
*
|
|
713
|
+
* ```ts
|
|
714
|
+
* nLength(255n);
|
|
715
|
+
* ```
|
|
716
|
+
*/
|
|
371
717
|
export function nLength(n: bigint, nBitLength?: number): NLength {
|
|
372
718
|
// Bit size, byte size of CURVE.n
|
|
373
719
|
if (nBitLength !== undefined) anumber(nBitLength);
|
|
374
|
-
|
|
720
|
+
if (n <= _0n) throw new Error('invalid n length: expected positive n, got ' + n);
|
|
721
|
+
if (nBitLength !== undefined && nBitLength < 1)
|
|
722
|
+
throw new Error('invalid n length: expected positive bit length, got ' + nBitLength);
|
|
723
|
+
const bits = bitLen(n);
|
|
724
|
+
// Cached bit lengths smaller than ORDER would truncate serialized scalars/elements and poison
|
|
725
|
+
// any math that relies on the derived field metadata.
|
|
726
|
+
if (nBitLength !== undefined && nBitLength < bits)
|
|
727
|
+
throw new Error(`invalid n length: expected bit length (${bits}) >= n.length (${nBitLength})`);
|
|
728
|
+
const _nBitLength = nBitLength !== undefined ? nBitLength : bits;
|
|
375
729
|
const nByteLength = Math.ceil(_nBitLength / 8);
|
|
376
730
|
return { nBitLength: _nBitLength, nByteLength };
|
|
377
731
|
}
|
|
@@ -382,9 +736,12 @@ type FieldOpts = Partial<{
|
|
|
382
736
|
isLE: boolean;
|
|
383
737
|
BITS: number;
|
|
384
738
|
sqrt: SqrtFn;
|
|
385
|
-
allowedLengths?: readonly number[]; // for P521 (adds padding for smaller sizes)
|
|
739
|
+
allowedLengths?: readonly number[]; // for P521 (adds padding for smaller sizes); must stay > 0
|
|
386
740
|
modFromBytes: boolean; // bls12-381 requires mod(n) instead of rejecting keys >= n
|
|
387
741
|
}>;
|
|
742
|
+
// Keep the lazy sqrt cache off-instance so Field(...) can return a frozen object. Otherwise the
|
|
743
|
+
// cached helper write would keep the field surface externally mutable.
|
|
744
|
+
const FIELD_SQRT = new WeakMap<object, ReturnType<typeof FpSqrt>>();
|
|
388
745
|
class _Field implements IField<bigint> {
|
|
389
746
|
readonly ORDER: bigint;
|
|
390
747
|
readonly BITS: number;
|
|
@@ -392,18 +749,23 @@ class _Field implements IField<bigint> {
|
|
|
392
749
|
readonly isLE: boolean;
|
|
393
750
|
readonly ZERO = _0n;
|
|
394
751
|
readonly ONE = _1n;
|
|
395
|
-
readonly _lengths?: number[];
|
|
396
|
-
private _sqrt: ReturnType<typeof FpSqrt> | undefined; // cached sqrt
|
|
752
|
+
readonly _lengths?: readonly number[];
|
|
397
753
|
private readonly _mod?: boolean;
|
|
398
754
|
constructor(ORDER: bigint, opts: FieldOpts = {}) {
|
|
399
|
-
|
|
755
|
+
// ORDER <= 1 is degenerate: ONE would not be a valid field element and helpers like pow/inv
|
|
756
|
+
// would stop modeling field arithmetic.
|
|
757
|
+
if (ORDER <= _1n) throw new Error('invalid field: expected ORDER > 1, got ' + ORDER);
|
|
400
758
|
let _nbitLength: number | undefined = undefined;
|
|
401
759
|
this.isLE = false;
|
|
402
760
|
if (opts != null && typeof opts === 'object') {
|
|
761
|
+
// Cached bit lengths are trusted here and should already be positive / consistent with ORDER.
|
|
403
762
|
if (typeof opts.BITS === 'number') _nbitLength = opts.BITS;
|
|
404
|
-
if (typeof opts.sqrt === 'function')
|
|
763
|
+
if (typeof opts.sqrt === 'function')
|
|
764
|
+
// `_Field.prototype` is frozen below, so custom sqrt hooks must become own properties
|
|
765
|
+
// explicitly instead of relying on writable prototype shadowing via assignment.
|
|
766
|
+
Object.defineProperty(this, 'sqrt', { value: opts.sqrt, enumerable: true });
|
|
405
767
|
if (typeof opts.isLE === 'boolean') this.isLE = opts.isLE;
|
|
406
|
-
if (opts.allowedLengths) this._lengths = opts.allowedLengths
|
|
768
|
+
if (opts.allowedLengths) this._lengths = Object.freeze(opts.allowedLengths.slice());
|
|
407
769
|
if (typeof opts.modFromBytes === 'boolean') this._mod = opts.modFromBytes;
|
|
408
770
|
}
|
|
409
771
|
const { nBitLength, nByteLength } = nLength(ORDER, _nbitLength);
|
|
@@ -411,8 +773,7 @@ class _Field implements IField<bigint> {
|
|
|
411
773
|
this.ORDER = ORDER;
|
|
412
774
|
this.BITS = nBitLength;
|
|
413
775
|
this.BYTES = nByteLength;
|
|
414
|
-
this
|
|
415
|
-
Object.preventExtensions(this);
|
|
776
|
+
Object.freeze(this);
|
|
416
777
|
}
|
|
417
778
|
|
|
418
779
|
create(num: bigint) {
|
|
@@ -420,7 +781,7 @@ class _Field implements IField<bigint> {
|
|
|
420
781
|
}
|
|
421
782
|
isValid(num: bigint) {
|
|
422
783
|
if (typeof num !== 'bigint')
|
|
423
|
-
throw new
|
|
784
|
+
throw new TypeError('invalid field element: expected bigint, got ' + typeof num);
|
|
424
785
|
return _0n <= num && num < this.ORDER; // 0 is valid element, but it's not invertible
|
|
425
786
|
}
|
|
426
787
|
is0(num: bigint) {
|
|
@@ -477,18 +838,25 @@ class _Field implements IField<bigint> {
|
|
|
477
838
|
return invert(num, this.ORDER);
|
|
478
839
|
}
|
|
479
840
|
sqrt(num: bigint): bigint {
|
|
480
|
-
// Caching
|
|
481
|
-
|
|
482
|
-
|
|
841
|
+
// Caching sqrt helpers speeds up sqrt9mod16 by 5x and Tonelli-Shanks by about 10% without keeping
|
|
842
|
+
// the field instance itself mutable.
|
|
843
|
+
let sqrt = FIELD_SQRT.get(this);
|
|
844
|
+
if (!sqrt) FIELD_SQRT.set(this, (sqrt = FpSqrt(this.ORDER)));
|
|
845
|
+
return sqrt(this, num);
|
|
483
846
|
}
|
|
484
847
|
toBytes(num: bigint) {
|
|
848
|
+
// Serialize fixed-width limbs without re-validating the field range. Callers that need a
|
|
849
|
+
// canonical encoding must pass a valid element; some protocols intentionally serialize raw
|
|
850
|
+
// residues here and reduce or validate them elsewhere.
|
|
485
851
|
return this.isLE ? numberToBytesLE(num, this.BYTES) : numberToBytesBE(num, this.BYTES);
|
|
486
852
|
}
|
|
487
853
|
fromBytes(bytes: Uint8Array, skipValidation = false) {
|
|
488
854
|
abytes(bytes);
|
|
489
855
|
const { _lengths: allowedLengths, BYTES, isLE, ORDER, _mod: modFromBytes } = this;
|
|
490
856
|
if (allowedLengths) {
|
|
491
|
-
|
|
857
|
+
// `allowedLengths` must list real positive byte lengths; otherwise empty input would get
|
|
858
|
+
// padded into zero and silently decode as a field element.
|
|
859
|
+
if (bytes.length < 1 || !allowedLengths.includes(bytes.length) || bytes.length > BYTES) {
|
|
492
860
|
throw new Error(
|
|
493
861
|
'Field.fromBytes: expected ' + allowedLengths + ' bytes, got ' + bytes.length
|
|
494
862
|
);
|
|
@@ -505,8 +873,8 @@ class _Field implements IField<bigint> {
|
|
|
505
873
|
if (!skipValidation)
|
|
506
874
|
if (!this.isValid(scalar))
|
|
507
875
|
throw new Error('invalid field element: outside of range 0..ORDER');
|
|
508
|
-
//
|
|
509
|
-
//
|
|
876
|
+
// Range validation is optional here because some protocols intentionally decode raw residues
|
|
877
|
+
// and reduce or validate them elsewhere.
|
|
510
878
|
return scalar;
|
|
511
879
|
}
|
|
512
880
|
// TODO: we don't need it here, move out to separate fn
|
|
@@ -516,30 +884,43 @@ class _Field implements IField<bigint> {
|
|
|
516
884
|
// We can't move this out because Fp6, Fp12 implement it
|
|
517
885
|
// and it's unclear what to return in there.
|
|
518
886
|
cmov(a: bigint, b: bigint, condition: boolean) {
|
|
887
|
+
// Field elements have `isValid(...)`; the CMOV branch bit is a direct runtime input, so reject
|
|
888
|
+
// non-boolean selectors here instead of letting JS truthiness silently change arithmetic.
|
|
889
|
+
abool(condition, 'condition');
|
|
519
890
|
return condition ? b : a;
|
|
520
891
|
}
|
|
521
892
|
}
|
|
893
|
+
// Freeze the shared method surface too; otherwise callers can still poison every Field instance by
|
|
894
|
+
// monkey-patching `_Field.prototype` even if each instance is frozen.
|
|
895
|
+
Object.freeze(_Field.prototype);
|
|
522
896
|
|
|
523
897
|
/**
|
|
524
898
|
* Creates a finite field. Major performance optimizations:
|
|
525
899
|
* * 1. Denormalized operations like mulN instead of mul.
|
|
526
900
|
* * 2. Identical object shape: never add or remove keys.
|
|
527
|
-
* * 3. `
|
|
901
|
+
* * 3. Frozen stable object shape; the lazy sqrt cache lives in a module-level `WeakMap`.
|
|
528
902
|
* Fragile: always run a benchmark on a change.
|
|
529
|
-
* Security note: operations don't check
|
|
530
|
-
*
|
|
903
|
+
* Security note: operations and low-level serializers like `toBytes` don't check `isValid` for
|
|
904
|
+
* all elements for performance and protocol-flexibility reasons; callers are responsible for
|
|
905
|
+
* supplying valid elements when they need canonical field behavior.
|
|
531
906
|
* This is low-level code, please make sure you know what you're doing.
|
|
532
907
|
*
|
|
533
908
|
* Note about field properties:
|
|
534
909
|
* * CHARACTERISTIC p = prime number, number of elements in main subgroup.
|
|
535
910
|
* * ORDER q = similar to cofactor in curves, may be composite `q = p^m`.
|
|
536
911
|
*
|
|
537
|
-
* @param ORDER field order, probably prime, or could be composite
|
|
538
|
-
* @param
|
|
539
|
-
* @
|
|
540
|
-
*
|
|
912
|
+
* @param ORDER - field order, probably prime, or could be composite
|
|
913
|
+
* @param opts - Field options such as bit length or endianness. See {@link FieldOpts}.
|
|
914
|
+
* @returns Frozen field instance with a stable object shape. This wrapper forwards `opts` straight
|
|
915
|
+
* into `_Field`, so it inherits `_Field`'s assumptions about cached sizes and `allowedLengths`.
|
|
916
|
+
* @example
|
|
917
|
+
* Construct one prime field with optional overrides.
|
|
918
|
+
*
|
|
919
|
+
* ```ts
|
|
920
|
+
* Field(11n);
|
|
921
|
+
* ```
|
|
541
922
|
*/
|
|
542
|
-
export function Field(ORDER: bigint, opts: FieldOpts = {}): Readonly<FpField
|
|
923
|
+
export function Field(ORDER: bigint, opts: FieldOpts = {}): TRet<Readonly<FpField>> {
|
|
543
924
|
return new _Field(ORDER, opts);
|
|
544
925
|
}
|
|
545
926
|
|
|
@@ -557,27 +938,69 @@ export function Field(ORDER: bigint, opts: FieldOpts = {}): Readonly<FpField> {
|
|
|
557
938
|
// return reduced;
|
|
558
939
|
// },
|
|
559
940
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
941
|
+
/**
|
|
942
|
+
* @param Fp - Field implementation.
|
|
943
|
+
* @param elm - Value to square-root.
|
|
944
|
+
* @returns Odd square root when two roots exist. The special case `elm = 0` still returns `0`,
|
|
945
|
+
* which is the only square root but is not odd.
|
|
946
|
+
* @throws If the field lacks oddness checks or the square root does not exist. {@link Error}
|
|
947
|
+
* @example
|
|
948
|
+
* Select the odd square root when two roots exist.
|
|
949
|
+
*
|
|
950
|
+
* ```ts
|
|
951
|
+
* import { Field, FpSqrtOdd } from '@noble/curves/abstract/modular.js';
|
|
952
|
+
* const Fp = Field(17n);
|
|
953
|
+
* const root = FpSqrtOdd(Fp, 4n);
|
|
954
|
+
* ```
|
|
955
|
+
*/
|
|
956
|
+
export function FpSqrtOdd<T>(Fp: TArg<IField<T>>, elm: T): T {
|
|
957
|
+
const F = Fp as IField<T>;
|
|
958
|
+
if (!F.isOdd) throw new Error("Field doesn't have isOdd");
|
|
959
|
+
const root = F.sqrt(elm);
|
|
960
|
+
return F.isOdd(root) ? root : F.neg(root);
|
|
564
961
|
}
|
|
565
962
|
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
963
|
+
/**
|
|
964
|
+
* @param Fp - Field implementation.
|
|
965
|
+
* @param elm - Value to square-root.
|
|
966
|
+
* @returns Even square root.
|
|
967
|
+
* @throws If the field lacks oddness checks or the square root does not exist. {@link Error}
|
|
968
|
+
* @example
|
|
969
|
+
* Select the even square root when two roots exist.
|
|
970
|
+
*
|
|
971
|
+
* ```ts
|
|
972
|
+
* import { Field, FpSqrtEven } from '@noble/curves/abstract/modular.js';
|
|
973
|
+
* const Fp = Field(17n);
|
|
974
|
+
* const root = FpSqrtEven(Fp, 4n);
|
|
975
|
+
* ```
|
|
976
|
+
*/
|
|
977
|
+
export function FpSqrtEven<T>(Fp: TArg<IField<T>>, elm: T): T {
|
|
978
|
+
const F = Fp as IField<T>;
|
|
979
|
+
if (!F.isOdd) throw new Error("Field doesn't have isOdd");
|
|
980
|
+
const root = F.sqrt(elm);
|
|
981
|
+
return F.isOdd(root) ? F.neg(root) : root;
|
|
570
982
|
}
|
|
571
983
|
|
|
572
984
|
/**
|
|
573
985
|
* Returns total number of bytes consumed by the field element.
|
|
574
986
|
* For example, 32 bytes for usual 256-bit weierstrass curve.
|
|
575
|
-
* @param fieldOrder number of field elements, usually CURVE.n
|
|
987
|
+
* @param fieldOrder - number of field elements, usually CURVE.n. Callers are expected to pass an
|
|
988
|
+
* order greater than 1.
|
|
576
989
|
* @returns byte length of field
|
|
990
|
+
* @throws If the field order is not a bigint. {@link Error}
|
|
991
|
+
* @example
|
|
992
|
+
* Read the fixed-width byte length of one field.
|
|
993
|
+
*
|
|
994
|
+
* ```ts
|
|
995
|
+
* getFieldBytesLength(255n);
|
|
996
|
+
* ```
|
|
577
997
|
*/
|
|
578
998
|
export function getFieldBytesLength(fieldOrder: bigint): number {
|
|
579
999
|
if (typeof fieldOrder !== 'bigint') throw new Error('field order must be bigint');
|
|
580
|
-
|
|
1000
|
+
// Valid field elements are in 0..ORDER-1, so ORDER <= 1 would make the encoded range degenerate.
|
|
1001
|
+
if (fieldOrder <= _1n) throw new Error('field order must be greater than 1');
|
|
1002
|
+
// Valid field elements are < ORDER, so the maximal encoded element is ORDER - 1.
|
|
1003
|
+
const bitLength = bitLen(fieldOrder - _1n);
|
|
581
1004
|
return Math.ceil(bitLength / 8);
|
|
582
1005
|
}
|
|
583
1006
|
|
|
@@ -585,8 +1008,17 @@ export function getFieldBytesLength(fieldOrder: bigint): number {
|
|
|
585
1008
|
* Returns minimal amount of bytes that can be safely reduced
|
|
586
1009
|
* by field order.
|
|
587
1010
|
* Should be 2^-128 for 128-bit curve such as P256.
|
|
588
|
-
*
|
|
1011
|
+
* This is the reduction / modulo-bias lower bound; higher-level helpers may still impose a larger
|
|
1012
|
+
* absolute floor for policy reasons.
|
|
1013
|
+
* @param fieldOrder - number of field elements greater than 1, usually CURVE.n.
|
|
589
1014
|
* @returns byte length of target hash
|
|
1015
|
+
* @throws If the field order is invalid. {@link Error}
|
|
1016
|
+
* @example
|
|
1017
|
+
* Compute the minimum hash length needed for field reduction.
|
|
1018
|
+
*
|
|
1019
|
+
* ```ts
|
|
1020
|
+
* getMinHashLength(255n);
|
|
1021
|
+
* ```
|
|
590
1022
|
*/
|
|
591
1023
|
export function getMinHashLength(fieldOrder: bigint): number {
|
|
592
1024
|
const length = getFieldBytesLength(fieldOrder);
|
|
@@ -597,22 +1029,37 @@ export function getMinHashLength(fieldOrder: bigint): number {
|
|
|
597
1029
|
* "Constant-time" private key generation utility.
|
|
598
1030
|
* Can take (n + n/2) or more bytes of uniform input e.g. from CSPRNG or KDF
|
|
599
1031
|
* and convert them into private scalar, with the modulo bias being negligible.
|
|
600
|
-
* Needs at least 48 bytes of input for 32-byte private key.
|
|
601
|
-
*
|
|
602
|
-
*
|
|
603
|
-
*
|
|
604
|
-
* @
|
|
605
|
-
* @
|
|
606
|
-
*
|
|
1032
|
+
* Needs at least 48 bytes of input for 32-byte private key. The implementation also keeps a hard
|
|
1033
|
+
* 16-byte minimum even when `getMinHashLength(...)` is smaller, so toy-small inputs do not look
|
|
1034
|
+
* accidentally acceptable for real scalar derivation.
|
|
1035
|
+
* 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},
|
|
1036
|
+
* {@link https://csrc.nist.gov/publications/detail/fips/186/5/final | FIPS 186-5 appendix A.2}, and
|
|
1037
|
+
* {@link https://www.rfc-editor.org/rfc/rfc9380#section-5 | RFC 9380 section 5}. Unlike RFC 9380
|
|
1038
|
+
* `hash_to_field`, this helper intentionally maps into the non-zero private-scalar range `1..n-1`.
|
|
1039
|
+
* @param key - Uniform input bytes.
|
|
1040
|
+
* @param fieldOrder - Size of subgroup.
|
|
1041
|
+
* @param isLE - interpret hash bytes as LE num
|
|
607
1042
|
* @returns valid private scalar
|
|
1043
|
+
* @throws If the hash length or field order is invalid for scalar reduction. {@link Error}
|
|
1044
|
+
* @example
|
|
1045
|
+
* Map hash output into a private scalar range.
|
|
1046
|
+
*
|
|
1047
|
+
* ```ts
|
|
1048
|
+
* mapHashToField(new Uint8Array(48).fill(1), 255n);
|
|
1049
|
+
* ```
|
|
608
1050
|
*/
|
|
609
|
-
export function mapHashToField(
|
|
1051
|
+
export function mapHashToField(
|
|
1052
|
+
key: TArg<Uint8Array>,
|
|
1053
|
+
fieldOrder: bigint,
|
|
1054
|
+
isLE = false
|
|
1055
|
+
): TRet<Uint8Array> {
|
|
610
1056
|
abytes(key);
|
|
611
1057
|
const len = key.length;
|
|
612
1058
|
const fieldLen = getFieldBytesLength(fieldOrder);
|
|
613
|
-
const minLen = getMinHashLength(fieldOrder);
|
|
614
|
-
// No small
|
|
615
|
-
|
|
1059
|
+
const minLen = Math.max(getMinHashLength(fieldOrder), 16);
|
|
1060
|
+
// No toy-small inputs: the helper is for real scalar derivation, not tiny test curves. No huge
|
|
1061
|
+
// inputs: easier to reason about JS timing / allocation behavior.
|
|
1062
|
+
if (len < minLen || len > 1024)
|
|
616
1063
|
throw new Error('expected ' + minLen + '-1024 bytes of input, got ' + len);
|
|
617
1064
|
const num = isLE ? bytesToNumberLE(key) : bytesToNumberBE(key);
|
|
618
1065
|
// `mod(x, 11)` can sometimes produce 0. `mod(x, 10) + 1` is the same, but no 0
|