@noble/curves 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -14
- package/lib/_shortw_utils.d.ts +2 -6
- package/lib/abstract/bls.d.ts +17 -8
- package/lib/abstract/bls.js +15 -78
- package/lib/abstract/edwards.d.ts +7 -16
- package/lib/abstract/edwards.js +89 -106
- package/lib/abstract/hash-to-curve.d.ts +10 -1
- package/lib/abstract/hash-to-curve.js +32 -10
- package/lib/abstract/modular.d.ts +8 -17
- package/lib/abstract/modular.js +134 -152
- package/lib/abstract/montgomery.js +1 -1
- package/lib/abstract/utils.d.ts +8 -4
- package/lib/abstract/utils.js +22 -14
- package/lib/abstract/weierstrass.d.ts +8 -8
- package/lib/abstract/weierstrass.js +209 -168
- package/lib/bls12-381.d.ts +2 -1
- package/lib/bls12-381.js +14 -9
- package/lib/ed25519.js +75 -12
- package/lib/ed448.js +86 -2
- package/lib/esm/abstract/bls.js +19 -82
- package/lib/esm/abstract/edwards.js +90 -107
- package/lib/esm/abstract/hash-to-curve.js +30 -9
- package/lib/esm/abstract/modular.js +128 -148
- package/lib/esm/abstract/montgomery.js +2 -4
- package/lib/esm/abstract/utils.js +20 -13
- package/lib/esm/abstract/weierstrass.js +210 -169
- package/lib/esm/bls12-381.js +13 -8
- package/lib/esm/ed25519.js +76 -13
- package/lib/esm/ed448.js +87 -3
- package/lib/esm/jubjub.js +5 -4
- package/lib/esm/p256.js +1 -1
- package/lib/esm/p384.js +1 -1
- package/lib/esm/p521.js +1 -1
- package/lib/esm/secp256k1.js +27 -27
- package/lib/esm/stark.js +5 -2
- package/lib/jubjub.d.ts +1 -0
- package/lib/jubjub.js +5 -4
- package/lib/p192.d.ts +4 -12
- package/lib/p224.d.ts +4 -12
- package/lib/p256.d.ts +4 -12
- package/lib/p256.js +1 -1
- package/lib/p384.d.ts +4 -12
- package/lib/p384.js +1 -1
- package/lib/p521.d.ts +4 -12
- package/lib/p521.js +1 -1
- package/lib/secp256k1.d.ts +2 -6
- package/lib/secp256k1.js +27 -27
- package/lib/stark.d.ts +1 -3
- package/lib/stark.js +5 -2
- package/package.json +2 -2
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
|
+
// TODO: remove circular imports
|
|
2
3
|
import * as utils from './utils.js';
|
|
3
4
|
// Utilities for modular arithmetics and finite fields
|
|
4
5
|
// prettier-ignore
|
|
5
6
|
const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3);
|
|
6
7
|
// prettier-ignore
|
|
7
|
-
const _4n = BigInt(4), _5n = BigInt(5),
|
|
8
|
+
const _4n = BigInt(4), _5n = BigInt(5), _8n = BigInt(8);
|
|
8
9
|
// prettier-ignore
|
|
9
10
|
const _9n = BigInt(9), _16n = BigInt(16);
|
|
10
11
|
// Calculates a modulo b
|
|
@@ -54,6 +55,7 @@ export function invert(number, modulo) {
|
|
|
54
55
|
// prettier-ignore
|
|
55
56
|
let x = _0n, y = _1n, u = _1n, v = _0n;
|
|
56
57
|
while (a !== _0n) {
|
|
58
|
+
// JIT applies optimization if those two lines follow each other
|
|
57
59
|
const q = b / a;
|
|
58
60
|
const r = b % a;
|
|
59
61
|
const m = x - u * q;
|
|
@@ -66,25 +68,68 @@ export function invert(number, modulo) {
|
|
|
66
68
|
throw new Error('invert: does not exist');
|
|
67
69
|
return mod(x, modulo);
|
|
68
70
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
71
|
+
// Tonelli-Shanks algorithm
|
|
72
|
+
// Paper 1: https://eprint.iacr.org/2012/685.pdf (page 12)
|
|
73
|
+
// Paper 2: Square Roots from 1; 24, 51, 10 to Dan Shanks
|
|
74
|
+
export function tonelliShanks(P) {
|
|
75
|
+
// Legendre constant: used to calculate Legendre symbol (a | p),
|
|
76
|
+
// which denotes the value of a^((p-1)/2) (mod p).
|
|
77
|
+
// (a | p) ≡ 1 if a is a square (mod p)
|
|
78
|
+
// (a | p) ≡ -1 if a is not a square (mod p)
|
|
79
|
+
// (a | p) ≡ 0 if a ≡ 0 (mod p)
|
|
80
|
+
const legendreC = (P - _1n) / _2n;
|
|
81
|
+
let Q, S, Z;
|
|
82
|
+
// Step 1: By factoring out powers of 2 from p - 1,
|
|
83
|
+
// find q and s such that p - 1 = q*(2^s) with q odd
|
|
84
|
+
for (Q = P - _1n, S = 0; Q % _2n === _0n; Q /= _2n, S++)
|
|
85
|
+
;
|
|
86
|
+
// Step 2: Select a non-square z such that (z | p) ≡ -1 and set c ≡ zq
|
|
87
|
+
for (Z = _2n; Z < P && pow(Z, legendreC, P) !== P - _1n; Z++)
|
|
88
|
+
;
|
|
89
|
+
// Fast-path
|
|
90
|
+
if (S === 1) {
|
|
91
|
+
const p1div4 = (P + _1n) / _4n;
|
|
92
|
+
return function tonelliFast(Fp, n) {
|
|
93
|
+
const root = Fp.pow(n, p1div4);
|
|
94
|
+
if (!Fp.equals(Fp.square(root), n))
|
|
95
|
+
throw new Error('Cannot find square root');
|
|
96
|
+
return root;
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
// Slow-path
|
|
100
|
+
const Q1div2 = (Q + _1n) / _2n;
|
|
101
|
+
return function tonelliSlow(Fp, n) {
|
|
102
|
+
// Step 0: Check that n is indeed a square: (n | p) should not be ≡ -1
|
|
103
|
+
if (Fp.pow(n, legendreC) === Fp.negate(Fp.ONE))
|
|
104
|
+
throw new Error('Cannot find square root');
|
|
105
|
+
let r = S;
|
|
106
|
+
// TODO: will fail at Fp2/etc
|
|
107
|
+
let g = Fp.pow(Fp.mul(Fp.ONE, Z), Q); // will update both x and b
|
|
108
|
+
let x = Fp.pow(n, Q1div2); // first guess at the square root
|
|
109
|
+
let b = Fp.pow(n, Q); // first guess at the fudge factor
|
|
110
|
+
while (!Fp.equals(b, Fp.ONE)) {
|
|
111
|
+
if (Fp.equals(b, Fp.ZERO))
|
|
112
|
+
return Fp.ZERO; // https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm (4. If t = 0, return r = 0)
|
|
113
|
+
// Find m such b^(2^m)==1
|
|
114
|
+
let m = 1;
|
|
115
|
+
for (let t2 = Fp.square(b); m < r; m++) {
|
|
116
|
+
if (Fp.equals(t2, Fp.ONE))
|
|
117
|
+
break;
|
|
118
|
+
t2 = Fp.square(t2); // t2 *= t2
|
|
119
|
+
}
|
|
120
|
+
// NOTE: r-m-1 can be bigger than 32, need to convert to bigint before shift, otherwise there will be overflow
|
|
121
|
+
const ge = Fp.pow(g, _1n << BigInt(r - m - 1)); // ge = 2^(r-m-1)
|
|
122
|
+
g = Fp.square(ge); // g = ge * ge
|
|
123
|
+
x = Fp.mul(x, ge); // x *= ge
|
|
124
|
+
b = Fp.mul(b, g); // b *= g
|
|
125
|
+
r = m;
|
|
126
|
+
}
|
|
127
|
+
return x;
|
|
128
|
+
};
|
|
77
129
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
*/
|
|
82
|
-
// TODO: rewrite as generic Fp function && remove bls versions
|
|
83
|
-
export function sqrt(number, modulo) {
|
|
84
|
-
// prettier-ignore
|
|
85
|
-
const n = number;
|
|
86
|
-
const P = modulo;
|
|
87
|
-
const p1div4 = (P + _1n) / _4n;
|
|
130
|
+
export function FpSqrt(P) {
|
|
131
|
+
// NOTE: different algorithms can give different roots, it is up to user to decide which one they want.
|
|
132
|
+
// For example there is FpSqrtOdd/FpSqrtEven to choice root based on oddness (used for hash-to-curve).
|
|
88
133
|
// P ≡ 3 (mod 4)
|
|
89
134
|
// √n = n^((P+1)/4)
|
|
90
135
|
if (P % _4n === _3n) {
|
|
@@ -92,50 +137,53 @@ export function sqrt(number, modulo) {
|
|
|
92
137
|
// const ORDER =
|
|
93
138
|
// 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn;
|
|
94
139
|
// const NUM = 72057594037927816n;
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
140
|
+
const p1div4 = (P + _1n) / _4n;
|
|
141
|
+
return function sqrt3mod4(Fp, n) {
|
|
142
|
+
const root = Fp.pow(n, p1div4);
|
|
143
|
+
// Throw if root**2 != n
|
|
144
|
+
if (!Fp.equals(Fp.square(root), n))
|
|
145
|
+
throw new Error('Cannot find square root');
|
|
146
|
+
return root;
|
|
147
|
+
};
|
|
100
148
|
}
|
|
101
|
-
//
|
|
149
|
+
// Atkin algorithm for q ≡ 5 (mod 8), https://eprint.iacr.org/2012/685.pdf (page 10)
|
|
102
150
|
if (P % _8n === _5n) {
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
151
|
+
const c1 = (P - _5n) / _8n;
|
|
152
|
+
return function sqrt5mod8(Fp, n) {
|
|
153
|
+
const n2 = Fp.mul(n, _2n);
|
|
154
|
+
const v = Fp.pow(n2, c1);
|
|
155
|
+
const nv = Fp.mul(n, v);
|
|
156
|
+
const i = Fp.mul(Fp.mul(nv, _2n), v);
|
|
157
|
+
const root = Fp.mul(nv, Fp.sub(i, Fp.ONE));
|
|
158
|
+
if (!Fp.equals(Fp.square(root), n))
|
|
159
|
+
throw new Error('Cannot find square root');
|
|
160
|
+
return root;
|
|
161
|
+
};
|
|
109
162
|
}
|
|
110
|
-
//
|
|
111
|
-
if (
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
;
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
let b = pow(c, BigInt(1 << (s - i - 1)), P);
|
|
133
|
-
r = mod(r * b, P);
|
|
134
|
-
c = mod(b * b, P);
|
|
135
|
-
t = mod(t * c, P);
|
|
136
|
-
s = i;
|
|
163
|
+
// P ≡ 9 (mod 16)
|
|
164
|
+
if (P % _16n === _9n) {
|
|
165
|
+
// NOTE: tonelli is too slow for bls-Fp2 calculations even on start
|
|
166
|
+
// Means we cannot use sqrt for constants at all!
|
|
167
|
+
//
|
|
168
|
+
// const c1 = Fp.sqrt(Fp.negate(Fp.ONE)); // 1. c1 = sqrt(-1) in F, i.e., (c1^2) == -1 in F
|
|
169
|
+
// const c2 = Fp.sqrt(c1); // 2. c2 = sqrt(c1) in F, i.e., (c2^2) == c1 in F
|
|
170
|
+
// const c3 = Fp.sqrt(Fp.negate(c1)); // 3. c3 = sqrt(-c1) in F, i.e., (c3^2) == -c1 in F
|
|
171
|
+
// const c4 = (P + _7n) / _16n; // 4. c4 = (q + 7) / 16 # Integer arithmetic
|
|
172
|
+
// sqrt = (x) => {
|
|
173
|
+
// let tv1 = Fp.pow(x, c4); // 1. tv1 = x^c4
|
|
174
|
+
// let tv2 = Fp.mul(c1, tv1); // 2. tv2 = c1 * tv1
|
|
175
|
+
// const tv3 = Fp.mul(c2, tv1); // 3. tv3 = c2 * tv1
|
|
176
|
+
// let tv4 = Fp.mul(c3, tv1); // 4. tv4 = c3 * tv1
|
|
177
|
+
// const e1 = Fp.equals(Fp.square(tv2), x); // 5. e1 = (tv2^2) == x
|
|
178
|
+
// const e2 = Fp.equals(Fp.square(tv3), x); // 6. e2 = (tv3^2) == x
|
|
179
|
+
// tv1 = Fp.cmov(tv1, tv2, e1); // 7. tv1 = CMOV(tv1, tv2, e1) # Select tv2 if (tv2^2) == x
|
|
180
|
+
// tv2 = Fp.cmov(tv4, tv3, e2); // 8. tv2 = CMOV(tv4, tv3, e2) # Select tv3 if (tv3^2) == x
|
|
181
|
+
// const e3 = Fp.equals(Fp.square(tv2), x); // 9. e3 = (tv2^2) == x
|
|
182
|
+
// return Fp.cmov(tv1, tv2, e3); // 10. z = CMOV(tv1, tv2, e3) # Select the sqrt from tv1 and tv2
|
|
183
|
+
// }
|
|
137
184
|
}
|
|
138
|
-
|
|
185
|
+
// Other cases: Tonelli-Shanks algorithm
|
|
186
|
+
return tonelliShanks(P);
|
|
139
187
|
}
|
|
140
188
|
// Little-endian check for first LE bit (last BE bit);
|
|
141
189
|
export const isNegativeLE = (num, modulo) => (mod(num, modulo) & _1n) === _1n;
|
|
@@ -202,17 +250,21 @@ export function FpInvertBatch(f, nums) {
|
|
|
202
250
|
export function FpDiv(f, lhs, rhs) {
|
|
203
251
|
return f.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, f.ORDER) : f.invert(rhs));
|
|
204
252
|
}
|
|
205
|
-
//
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
253
|
+
// This function returns True whenever the value x is a square in the field F.
|
|
254
|
+
export function FpIsSquare(f) {
|
|
255
|
+
const legendreConst = (f.ORDER - _1n) / _2n; // Integer arithmetic
|
|
256
|
+
return (x) => {
|
|
257
|
+
const p = f.pow(x, legendreConst);
|
|
258
|
+
return f.equals(p, f.ZERO) || f.equals(p, f.ONE);
|
|
259
|
+
};
|
|
260
|
+
}
|
|
209
261
|
export function Fp(ORDER, bitLen, isLE = false, redef = {}) {
|
|
210
262
|
if (ORDER <= _0n)
|
|
211
263
|
throw new Error(`Expected Fp ORDER > 0, got ${ORDER}`);
|
|
212
264
|
const { nBitLength: BITS, nByteLength: BYTES } = utils.nLength(ORDER, bitLen);
|
|
213
265
|
if (BYTES > 2048)
|
|
214
266
|
throw new Error('Field lengths over 2048 bytes are not supported');
|
|
215
|
-
const sqrtP = (
|
|
267
|
+
const sqrtP = FpSqrt(ORDER);
|
|
216
268
|
const f = Object.freeze({
|
|
217
269
|
ORDER,
|
|
218
270
|
BITS,
|
|
@@ -242,7 +294,7 @@ export function Fp(ORDER, bitLen, isLE = false, redef = {}) {
|
|
|
242
294
|
subN: (lhs, rhs) => lhs - rhs,
|
|
243
295
|
mulN: (lhs, rhs) => lhs * rhs,
|
|
244
296
|
invert: (num) => invert(num, ORDER),
|
|
245
|
-
sqrt: redef.sqrt || sqrtP,
|
|
297
|
+
sqrt: redef.sqrt || ((n) => sqrtP(f, n)),
|
|
246
298
|
invertBatch: (lst) => FpInvertBatch(f, lst),
|
|
247
299
|
// TODO: do we really need constant cmov?
|
|
248
300
|
// We don't have const-time bigints anyway, so probably will be not very useful
|
|
@@ -256,87 +308,15 @@ export function Fp(ORDER, bitLen, isLE = false, redef = {}) {
|
|
|
256
308
|
});
|
|
257
309
|
return Object.freeze(f);
|
|
258
310
|
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
const p = Fp.pow(x, squareConst);
|
|
271
|
-
return Fp.equals(p, Fp.ZERO) || Fp.equals(p, Fp.ONE);
|
|
272
|
-
};
|
|
273
|
-
// Constant-time Tonelli-Shanks algorithm
|
|
274
|
-
let l = _0n;
|
|
275
|
-
for (let o = q - _1n; o % _2n === _0n; o /= _2n)
|
|
276
|
-
l += _1n;
|
|
277
|
-
const c1 = l; // 1. c1, the largest integer such that 2^c1 divides q - 1.
|
|
278
|
-
const c2 = (q - _1n) / _2n ** c1; // 2. c2 = (q - 1) / (2^c1) # Integer arithmetic
|
|
279
|
-
const c3 = (c2 - _1n) / _2n; // 3. c3 = (c2 - 1) / 2 # Integer arithmetic
|
|
280
|
-
// 4. c4, a non-square value in F
|
|
281
|
-
// 5. c5 = c4^c2 in F
|
|
282
|
-
let c4 = Fp.ONE;
|
|
283
|
-
while (isSquare(c4))
|
|
284
|
-
c4 = Fp.add(c4, Fp.ONE);
|
|
285
|
-
const c5 = Fp.pow(c4, c2);
|
|
286
|
-
let sqrt = (x) => {
|
|
287
|
-
let z = Fp.pow(x, c3); // 1. z = x^c3
|
|
288
|
-
let t = Fp.square(z); // 2. t = z * z
|
|
289
|
-
t = Fp.mul(t, x); // 3. t = t * x
|
|
290
|
-
z = Fp.mul(z, x); // 4. z = z * x
|
|
291
|
-
let b = t; // 5. b = t
|
|
292
|
-
let c = c5; // 6. c = c5
|
|
293
|
-
// 7. for i in (c1, c1 - 1, ..., 2):
|
|
294
|
-
for (let i = c1; i > 1; i--) {
|
|
295
|
-
// 8. for j in (1, 2, ..., i - 2):
|
|
296
|
-
// 9. b = b * b
|
|
297
|
-
for (let j = _1n; j < i - _1n; i++)
|
|
298
|
-
b = Fp.square(b);
|
|
299
|
-
const e = Fp.equals(b, Fp.ONE); // 10. e = b == 1
|
|
300
|
-
const zt = Fp.mul(z, c); // 11. zt = z * c
|
|
301
|
-
z = Fp.cmov(zt, z, e); // 12. z = CMOV(zt, z, e)
|
|
302
|
-
c = Fp.square(c); // 13. c = c * c
|
|
303
|
-
let tt = Fp.mul(t, c); // 14. tt = t * c
|
|
304
|
-
t = Fp.cmov(tt, t, e); // 15. t = CMOV(tt, t, e)
|
|
305
|
-
b = t; // 16. b = t
|
|
306
|
-
}
|
|
307
|
-
return z; // 17. return z
|
|
308
|
-
};
|
|
309
|
-
if (q % _4n === _3n) {
|
|
310
|
-
const c1 = (q + _1n) / _4n; // 1. c1 = (q + 1) / 4 # Integer arithmetic
|
|
311
|
-
sqrt = (x) => Fp.pow(x, c1);
|
|
312
|
-
}
|
|
313
|
-
else if (q % _8n === _5n) {
|
|
314
|
-
const c1 = Fp.sqrt(Fp.negate(Fp.ONE)); // 1. c1 = sqrt(-1) in F, i.e., (c1^2) == -1 in F
|
|
315
|
-
const c2 = (q + _3n) / _8n; // 2. c2 = (q + 3) / 8 # Integer arithmetic
|
|
316
|
-
sqrt = (x) => {
|
|
317
|
-
let tv1 = Fp.pow(x, c2); // 1. tv1 = x^c2
|
|
318
|
-
let tv2 = Fp.mul(tv1, c1); // 2. tv2 = tv1 * c1
|
|
319
|
-
let e = Fp.equals(Fp.square(tv1), x); // 3. e = (tv1^2) == x
|
|
320
|
-
return Fp.cmov(tv2, tv1, e); // 4. z = CMOV(tv2, tv1, e)
|
|
321
|
-
};
|
|
322
|
-
}
|
|
323
|
-
else if (Fp.ORDER % _16n === _9n) {
|
|
324
|
-
const c1 = Fp.sqrt(Fp.negate(Fp.ONE)); // 1. c1 = sqrt(-1) in F, i.e., (c1^2) == -1 in F
|
|
325
|
-
const c2 = Fp.sqrt(c1); // 2. c2 = sqrt(c1) in F, i.e., (c2^2) == c1 in F
|
|
326
|
-
const c3 = Fp.sqrt(Fp.negate(c1)); // 3. c3 = sqrt(-c1) in F, i.e., (c3^2) == -c1 in F
|
|
327
|
-
const c4 = (Fp.ORDER + _7n) / _16n; // 4. c4 = (q + 7) / 16 # Integer arithmetic
|
|
328
|
-
sqrt = (x) => {
|
|
329
|
-
let tv1 = Fp.pow(x, c4); // 1. tv1 = x^c4
|
|
330
|
-
let tv2 = Fp.mul(c1, tv1); // 2. tv2 = c1 * tv1
|
|
331
|
-
const tv3 = Fp.mul(c2, tv1); // 3. tv3 = c2 * tv1
|
|
332
|
-
let tv4 = Fp.mul(c3, tv1); // 4. tv4 = c3 * tv1
|
|
333
|
-
const e1 = Fp.equals(Fp.square(tv2), x); // 5. e1 = (tv2^2) == x
|
|
334
|
-
const e2 = Fp.equals(Fp.square(tv3), x); // 6. e2 = (tv3^2) == x
|
|
335
|
-
tv1 = Fp.cmov(tv1, tv2, e1); // 7. tv1 = CMOV(tv1, tv2, e1) # Select tv2 if (tv2^2) == x
|
|
336
|
-
tv2 = Fp.cmov(tv4, tv3, e2); // 8. tv2 = CMOV(tv4, tv3, e2) # Select tv3 if (tv3^2) == x
|
|
337
|
-
const e3 = Fp.equals(Fp.square(tv2), x); // 9. e3 = (tv2^2) == x
|
|
338
|
-
return Fp.cmov(tv1, tv2, e3); // 10. z = CMOV(tv1, tv2, e3) # Select the sqrt from tv1 and tv2
|
|
339
|
-
};
|
|
340
|
-
}
|
|
341
|
-
return { sqrt, isSquare };
|
|
311
|
+
export function FpSqrtOdd(Fp, elm) {
|
|
312
|
+
if (!Fp.isOdd)
|
|
313
|
+
throw new Error(`Field doesn't have isOdd`);
|
|
314
|
+
const root = Fp.sqrt(elm);
|
|
315
|
+
return Fp.isOdd(root) ? root : Fp.negate(root);
|
|
316
|
+
}
|
|
317
|
+
export function FpSqrtEven(Fp, elm) {
|
|
318
|
+
if (!Fp.isOdd)
|
|
319
|
+
throw new Error(`Field doesn't have isOdd`);
|
|
320
|
+
const root = Fp.sqrt(elm);
|
|
321
|
+
return Fp.isOdd(root) ? Fp.negate(root) : root;
|
|
342
322
|
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
2
|
import * as mod from './modular.js';
|
|
3
|
-
import { ensureBytes, numberToBytesLE, bytesToNumberLE,
|
|
4
|
-
// nLength,
|
|
5
|
-
} from './utils.js';
|
|
3
|
+
import { ensureBytes, numberToBytesLE, bytesToNumberLE, isPositiveInt } from './utils.js';
|
|
6
4
|
const _0n = BigInt(0);
|
|
7
5
|
const _1n = BigInt(1);
|
|
8
6
|
function validateOpts(curve) {
|
|
@@ -13,7 +11,7 @@ function validateOpts(curve) {
|
|
|
13
11
|
for (const i of ['montgomeryBits', 'nByteLength']) {
|
|
14
12
|
if (curve[i] === undefined)
|
|
15
13
|
continue; // Optional
|
|
16
|
-
if (!
|
|
14
|
+
if (!isPositiveInt(curve[i]))
|
|
17
15
|
throw new Error(`Invalid curve param ${i}=${curve[i]} (${typeof curve[i]})`);
|
|
18
16
|
}
|
|
19
17
|
for (const fn of ['adjustScalarBytes', 'domain', 'powPminus2']) {
|
|
@@ -3,21 +3,27 @@ import * as mod from './modular.js';
|
|
|
3
3
|
const _0n = BigInt(0);
|
|
4
4
|
const _1n = BigInt(1);
|
|
5
5
|
const _2n = BigInt(2);
|
|
6
|
+
// Bans floats and integers above 2^53-1
|
|
7
|
+
export function isPositiveInt(num) {
|
|
8
|
+
return typeof num === 'number' && Number.isSafeInteger(num) && num > 0;
|
|
9
|
+
}
|
|
6
10
|
export function validateOpts(curve) {
|
|
7
11
|
mod.validateField(curve.Fp);
|
|
8
12
|
for (const i of ['n', 'h']) {
|
|
9
|
-
|
|
10
|
-
|
|
13
|
+
const val = curve[i];
|
|
14
|
+
if (typeof val !== 'bigint')
|
|
15
|
+
throw new Error(`Invalid curve param ${i}=${val} (${typeof val})`);
|
|
11
16
|
}
|
|
12
17
|
if (!curve.Fp.isValid(curve.Gx))
|
|
13
18
|
throw new Error('Invalid generator X coordinate Fp element');
|
|
14
19
|
if (!curve.Fp.isValid(curve.Gy))
|
|
15
20
|
throw new Error('Invalid generator Y coordinate Fp element');
|
|
16
21
|
for (const i of ['nBitLength', 'nByteLength']) {
|
|
17
|
-
|
|
22
|
+
const val = curve[i];
|
|
23
|
+
if (val === undefined)
|
|
18
24
|
continue; // Optional
|
|
19
|
-
if (!
|
|
20
|
-
throw new Error(`Invalid curve param ${i}=${
|
|
25
|
+
if (!isPositiveInt(val))
|
|
26
|
+
throw new Error(`Invalid curve param ${i}=${val} (${typeof val})`);
|
|
21
27
|
}
|
|
22
28
|
// Set defaults
|
|
23
29
|
return Object.freeze({ ...nLength(curve.n, curve.nBitLength), ...curve });
|
|
@@ -104,21 +110,22 @@ export function nLength(n, nBitLength) {
|
|
|
104
110
|
return { nBitLength: _nBitLength, nByteLength };
|
|
105
111
|
}
|
|
106
112
|
/**
|
|
113
|
+
* FIPS 186 B.4.1-compliant "constant-time" private key generation utility.
|
|
107
114
|
* Can take (n+8) or more bytes of uniform input e.g. from CSPRNG or KDF
|
|
108
115
|
* and convert them into private scalar, with the modulo bias being neglible.
|
|
109
|
-
*
|
|
116
|
+
* Needs at least 40 bytes of input for 32-byte private key.
|
|
110
117
|
* https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
|
|
111
|
-
* @param hash hash output from
|
|
118
|
+
* @param hash hash output from SHA3 or a similar function
|
|
112
119
|
* @returns valid private scalar
|
|
113
120
|
*/
|
|
114
|
-
export function hashToPrivateScalar(hash,
|
|
121
|
+
export function hashToPrivateScalar(hash, groupOrder, isLE = false) {
|
|
115
122
|
hash = ensureBytes(hash);
|
|
116
|
-
const
|
|
117
|
-
const minLen =
|
|
118
|
-
if (
|
|
119
|
-
throw new Error(
|
|
123
|
+
const hashLen = hash.length;
|
|
124
|
+
const minLen = nLength(groupOrder).nByteLength + 8;
|
|
125
|
+
if (minLen < 24 || hashLen < minLen || hashLen > 1024)
|
|
126
|
+
throw new Error(`hashToPrivateScalar: expected ${minLen}-1024 bytes of input, got ${hashLen}`);
|
|
120
127
|
const num = isLE ? bytesToNumberLE(hash) : bytesToNumberBE(hash);
|
|
121
|
-
return mod.mod(num,
|
|
128
|
+
return mod.mod(num, groupOrder - _1n) + _1n;
|
|
122
129
|
}
|
|
123
130
|
export function equalBytes(b1, b2) {
|
|
124
131
|
// We don't care about timing attacks here
|