@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
package/lib/abstract/modular.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.FpSqrtEven = exports.FpSqrtOdd = exports.Fp = exports.FpIsSquare = exports.FpDiv = exports.FpInvertBatch = exports.FpPow = exports.validateField = exports.isNegativeLE = exports.FpSqrt = exports.tonelliShanks = exports.invert = exports.pow2 = exports.pow = exports.mod = void 0;
|
|
4
4
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
5
|
+
// TODO: remove circular imports
|
|
5
6
|
const utils = require("./utils.js");
|
|
6
7
|
// Utilities for modular arithmetics and finite fields
|
|
7
8
|
// prettier-ignore
|
|
8
9
|
const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3);
|
|
9
10
|
// prettier-ignore
|
|
10
|
-
const _4n = BigInt(4), _5n = BigInt(5),
|
|
11
|
+
const _4n = BigInt(4), _5n = BigInt(5), _8n = BigInt(8);
|
|
11
12
|
// prettier-ignore
|
|
12
13
|
const _9n = BigInt(9), _16n = BigInt(16);
|
|
13
14
|
// Calculates a modulo b
|
|
@@ -60,6 +61,7 @@ function invert(number, modulo) {
|
|
|
60
61
|
// prettier-ignore
|
|
61
62
|
let x = _0n, y = _1n, u = _1n, v = _0n;
|
|
62
63
|
while (a !== _0n) {
|
|
64
|
+
// JIT applies optimization if those two lines follow each other
|
|
63
65
|
const q = b / a;
|
|
64
66
|
const r = b % a;
|
|
65
67
|
const m = x - u * q;
|
|
@@ -73,26 +75,69 @@ function invert(number, modulo) {
|
|
|
73
75
|
return mod(x, modulo);
|
|
74
76
|
}
|
|
75
77
|
exports.invert = invert;
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
78
|
+
// Tonelli-Shanks algorithm
|
|
79
|
+
// Paper 1: https://eprint.iacr.org/2012/685.pdf (page 12)
|
|
80
|
+
// Paper 2: Square Roots from 1; 24, 51, 10 to Dan Shanks
|
|
81
|
+
function tonelliShanks(P) {
|
|
82
|
+
// Legendre constant: used to calculate Legendre symbol (a | p),
|
|
83
|
+
// which denotes the value of a^((p-1)/2) (mod p).
|
|
84
|
+
// (a | p) ≡ 1 if a is a square (mod p)
|
|
85
|
+
// (a | p) ≡ -1 if a is not a square (mod p)
|
|
86
|
+
// (a | p) ≡ 0 if a ≡ 0 (mod p)
|
|
87
|
+
const legendreC = (P - _1n) / _2n;
|
|
88
|
+
let Q, S, Z;
|
|
89
|
+
// Step 1: By factoring out powers of 2 from p - 1,
|
|
90
|
+
// find q and s such that p - 1 = q*(2^s) with q odd
|
|
91
|
+
for (Q = P - _1n, S = 0; Q % _2n === _0n; Q /= _2n, S++)
|
|
92
|
+
;
|
|
93
|
+
// Step 2: Select a non-square z such that (z | p) ≡ -1 and set c ≡ zq
|
|
94
|
+
for (Z = _2n; Z < P && pow(Z, legendreC, P) !== P - _1n; Z++)
|
|
95
|
+
;
|
|
96
|
+
// Fast-path
|
|
97
|
+
if (S === 1) {
|
|
98
|
+
const p1div4 = (P + _1n) / _4n;
|
|
99
|
+
return function tonelliFast(Fp, n) {
|
|
100
|
+
const root = Fp.pow(n, p1div4);
|
|
101
|
+
if (!Fp.equals(Fp.square(root), n))
|
|
102
|
+
throw new Error('Cannot find square root');
|
|
103
|
+
return root;
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
// Slow-path
|
|
107
|
+
const Q1div2 = (Q + _1n) / _2n;
|
|
108
|
+
return function tonelliSlow(Fp, n) {
|
|
109
|
+
// Step 0: Check that n is indeed a square: (n | p) should not be ≡ -1
|
|
110
|
+
if (Fp.pow(n, legendreC) === Fp.negate(Fp.ONE))
|
|
111
|
+
throw new Error('Cannot find square root');
|
|
112
|
+
let r = S;
|
|
113
|
+
// TODO: will fail at Fp2/etc
|
|
114
|
+
let g = Fp.pow(Fp.mul(Fp.ONE, Z), Q); // will update both x and b
|
|
115
|
+
let x = Fp.pow(n, Q1div2); // first guess at the square root
|
|
116
|
+
let b = Fp.pow(n, Q); // first guess at the fudge factor
|
|
117
|
+
while (!Fp.equals(b, Fp.ONE)) {
|
|
118
|
+
if (Fp.equals(b, Fp.ZERO))
|
|
119
|
+
return Fp.ZERO; // https://en.wikipedia.org/wiki/Tonelli%E2%80%93Shanks_algorithm (4. If t = 0, return r = 0)
|
|
120
|
+
// Find m such b^(2^m)==1
|
|
121
|
+
let m = 1;
|
|
122
|
+
for (let t2 = Fp.square(b); m < r; m++) {
|
|
123
|
+
if (Fp.equals(t2, Fp.ONE))
|
|
124
|
+
break;
|
|
125
|
+
t2 = Fp.square(t2); // t2 *= t2
|
|
126
|
+
}
|
|
127
|
+
// NOTE: r-m-1 can be bigger than 32, need to convert to bigint before shift, otherwise there will be overflow
|
|
128
|
+
const ge = Fp.pow(g, _1n << BigInt(r - m - 1)); // ge = 2^(r-m-1)
|
|
129
|
+
g = Fp.square(ge); // g = ge * ge
|
|
130
|
+
x = Fp.mul(x, ge); // x *= ge
|
|
131
|
+
b = Fp.mul(b, g); // b *= g
|
|
132
|
+
r = m;
|
|
133
|
+
}
|
|
134
|
+
return x;
|
|
135
|
+
};
|
|
84
136
|
}
|
|
85
|
-
exports.
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
*/
|
|
90
|
-
// TODO: rewrite as generic Fp function && remove bls versions
|
|
91
|
-
function sqrt(number, modulo) {
|
|
92
|
-
// prettier-ignore
|
|
93
|
-
const n = number;
|
|
94
|
-
const P = modulo;
|
|
95
|
-
const p1div4 = (P + _1n) / _4n;
|
|
137
|
+
exports.tonelliShanks = tonelliShanks;
|
|
138
|
+
function FpSqrt(P) {
|
|
139
|
+
// NOTE: different algorithms can give different roots, it is up to user to decide which one they want.
|
|
140
|
+
// For example there is FpSqrtOdd/FpSqrtEven to choice root based on oddness (used for hash-to-curve).
|
|
96
141
|
// P ≡ 3 (mod 4)
|
|
97
142
|
// √n = n^((P+1)/4)
|
|
98
143
|
if (P % _4n === _3n) {
|
|
@@ -100,52 +145,55 @@ function sqrt(number, modulo) {
|
|
|
100
145
|
// const ORDER =
|
|
101
146
|
// 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn;
|
|
102
147
|
// const NUM = 72057594037927816n;
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
148
|
+
const p1div4 = (P + _1n) / _4n;
|
|
149
|
+
return function sqrt3mod4(Fp, n) {
|
|
150
|
+
const root = Fp.pow(n, p1div4);
|
|
151
|
+
// Throw if root**2 != n
|
|
152
|
+
if (!Fp.equals(Fp.square(root), n))
|
|
153
|
+
throw new Error('Cannot find square root');
|
|
154
|
+
return root;
|
|
155
|
+
};
|
|
108
156
|
}
|
|
109
|
-
//
|
|
157
|
+
// Atkin algorithm for q ≡ 5 (mod 8), https://eprint.iacr.org/2012/685.pdf (page 10)
|
|
110
158
|
if (P % _8n === _5n) {
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
159
|
+
const c1 = (P - _5n) / _8n;
|
|
160
|
+
return function sqrt5mod8(Fp, n) {
|
|
161
|
+
const n2 = Fp.mul(n, _2n);
|
|
162
|
+
const v = Fp.pow(n2, c1);
|
|
163
|
+
const nv = Fp.mul(n, v);
|
|
164
|
+
const i = Fp.mul(Fp.mul(nv, _2n), v);
|
|
165
|
+
const root = Fp.mul(nv, Fp.sub(i, Fp.ONE));
|
|
166
|
+
if (!Fp.equals(Fp.square(root), n))
|
|
167
|
+
throw new Error('Cannot find square root');
|
|
168
|
+
return root;
|
|
169
|
+
};
|
|
117
170
|
}
|
|
118
|
-
//
|
|
119
|
-
if (
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
;
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
let b = pow(c, BigInt(1 << (s - i - 1)), P);
|
|
141
|
-
r = mod(r * b, P);
|
|
142
|
-
c = mod(b * b, P);
|
|
143
|
-
t = mod(t * c, P);
|
|
144
|
-
s = i;
|
|
171
|
+
// P ≡ 9 (mod 16)
|
|
172
|
+
if (P % _16n === _9n) {
|
|
173
|
+
// NOTE: tonelli is too slow for bls-Fp2 calculations even on start
|
|
174
|
+
// Means we cannot use sqrt for constants at all!
|
|
175
|
+
//
|
|
176
|
+
// const c1 = Fp.sqrt(Fp.negate(Fp.ONE)); // 1. c1 = sqrt(-1) in F, i.e., (c1^2) == -1 in F
|
|
177
|
+
// const c2 = Fp.sqrt(c1); // 2. c2 = sqrt(c1) in F, i.e., (c2^2) == c1 in F
|
|
178
|
+
// const c3 = Fp.sqrt(Fp.negate(c1)); // 3. c3 = sqrt(-c1) in F, i.e., (c3^2) == -c1 in F
|
|
179
|
+
// const c4 = (P + _7n) / _16n; // 4. c4 = (q + 7) / 16 # Integer arithmetic
|
|
180
|
+
// sqrt = (x) => {
|
|
181
|
+
// let tv1 = Fp.pow(x, c4); // 1. tv1 = x^c4
|
|
182
|
+
// let tv2 = Fp.mul(c1, tv1); // 2. tv2 = c1 * tv1
|
|
183
|
+
// const tv3 = Fp.mul(c2, tv1); // 3. tv3 = c2 * tv1
|
|
184
|
+
// let tv4 = Fp.mul(c3, tv1); // 4. tv4 = c3 * tv1
|
|
185
|
+
// const e1 = Fp.equals(Fp.square(tv2), x); // 5. e1 = (tv2^2) == x
|
|
186
|
+
// const e2 = Fp.equals(Fp.square(tv3), x); // 6. e2 = (tv3^2) == x
|
|
187
|
+
// tv1 = Fp.cmov(tv1, tv2, e1); // 7. tv1 = CMOV(tv1, tv2, e1) # Select tv2 if (tv2^2) == x
|
|
188
|
+
// tv2 = Fp.cmov(tv4, tv3, e2); // 8. tv2 = CMOV(tv4, tv3, e2) # Select tv3 if (tv3^2) == x
|
|
189
|
+
// const e3 = Fp.equals(Fp.square(tv2), x); // 9. e3 = (tv2^2) == x
|
|
190
|
+
// return Fp.cmov(tv1, tv2, e3); // 10. z = CMOV(tv1, tv2, e3) # Select the sqrt from tv1 and tv2
|
|
191
|
+
// }
|
|
145
192
|
}
|
|
146
|
-
|
|
193
|
+
// Other cases: Tonelli-Shanks algorithm
|
|
194
|
+
return tonelliShanks(P);
|
|
147
195
|
}
|
|
148
|
-
exports.
|
|
196
|
+
exports.FpSqrt = FpSqrt;
|
|
149
197
|
// Little-endian check for first LE bit (last BE bit);
|
|
150
198
|
const isNegativeLE = (num, modulo) => (mod(num, modulo) & _1n) === _1n;
|
|
151
199
|
exports.isNegativeLE = isNegativeLE;
|
|
@@ -216,17 +264,22 @@ function FpDiv(f, lhs, rhs) {
|
|
|
216
264
|
return f.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, f.ORDER) : f.invert(rhs));
|
|
217
265
|
}
|
|
218
266
|
exports.FpDiv = FpDiv;
|
|
219
|
-
//
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
267
|
+
// This function returns True whenever the value x is a square in the field F.
|
|
268
|
+
function FpIsSquare(f) {
|
|
269
|
+
const legendreConst = (f.ORDER - _1n) / _2n; // Integer arithmetic
|
|
270
|
+
return (x) => {
|
|
271
|
+
const p = f.pow(x, legendreConst);
|
|
272
|
+
return f.equals(p, f.ZERO) || f.equals(p, f.ONE);
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
exports.FpIsSquare = FpIsSquare;
|
|
223
276
|
function Fp(ORDER, bitLen, isLE = false, redef = {}) {
|
|
224
277
|
if (ORDER <= _0n)
|
|
225
278
|
throw new Error(`Expected Fp ORDER > 0, got ${ORDER}`);
|
|
226
279
|
const { nBitLength: BITS, nByteLength: BYTES } = utils.nLength(ORDER, bitLen);
|
|
227
280
|
if (BYTES > 2048)
|
|
228
281
|
throw new Error('Field lengths over 2048 bytes are not supported');
|
|
229
|
-
const sqrtP = (
|
|
282
|
+
const sqrtP = FpSqrt(ORDER);
|
|
230
283
|
const f = Object.freeze({
|
|
231
284
|
ORDER,
|
|
232
285
|
BITS,
|
|
@@ -256,7 +309,7 @@ function Fp(ORDER, bitLen, isLE = false, redef = {}) {
|
|
|
256
309
|
subN: (lhs, rhs) => lhs - rhs,
|
|
257
310
|
mulN: (lhs, rhs) => lhs * rhs,
|
|
258
311
|
invert: (num) => invert(num, ORDER),
|
|
259
|
-
sqrt: redef.sqrt || sqrtP,
|
|
312
|
+
sqrt: redef.sqrt || ((n) => sqrtP(f, n)),
|
|
260
313
|
invertBatch: (lst) => FpInvertBatch(f, lst),
|
|
261
314
|
// TODO: do we really need constant cmov?
|
|
262
315
|
// We don't have const-time bigints anyway, so probably will be not very useful
|
|
@@ -271,88 +324,17 @@ function Fp(ORDER, bitLen, isLE = false, redef = {}) {
|
|
|
271
324
|
return Object.freeze(f);
|
|
272
325
|
}
|
|
273
326
|
exports.Fp = Fp;
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
// probably we can simply bls code using it
|
|
280
|
-
const q = Fp.ORDER;
|
|
281
|
-
const squareConst = (q - _1n) / _2n;
|
|
282
|
-
// is_square(x) := { True, if x^((q - 1) / 2) is 0 or 1 in F;
|
|
283
|
-
// { False, otherwise.
|
|
284
|
-
let isSquare = (x) => {
|
|
285
|
-
const p = Fp.pow(x, squareConst);
|
|
286
|
-
return Fp.equals(p, Fp.ZERO) || Fp.equals(p, Fp.ONE);
|
|
287
|
-
};
|
|
288
|
-
// Constant-time Tonelli-Shanks algorithm
|
|
289
|
-
let l = _0n;
|
|
290
|
-
for (let o = q - _1n; o % _2n === _0n; o /= _2n)
|
|
291
|
-
l += _1n;
|
|
292
|
-
const c1 = l; // 1. c1, the largest integer such that 2^c1 divides q - 1.
|
|
293
|
-
const c2 = (q - _1n) / _2n ** c1; // 2. c2 = (q - 1) / (2^c1) # Integer arithmetic
|
|
294
|
-
const c3 = (c2 - _1n) / _2n; // 3. c3 = (c2 - 1) / 2 # Integer arithmetic
|
|
295
|
-
// 4. c4, a non-square value in F
|
|
296
|
-
// 5. c5 = c4^c2 in F
|
|
297
|
-
let c4 = Fp.ONE;
|
|
298
|
-
while (isSquare(c4))
|
|
299
|
-
c4 = Fp.add(c4, Fp.ONE);
|
|
300
|
-
const c5 = Fp.pow(c4, c2);
|
|
301
|
-
let sqrt = (x) => {
|
|
302
|
-
let z = Fp.pow(x, c3); // 1. z = x^c3
|
|
303
|
-
let t = Fp.square(z); // 2. t = z * z
|
|
304
|
-
t = Fp.mul(t, x); // 3. t = t * x
|
|
305
|
-
z = Fp.mul(z, x); // 4. z = z * x
|
|
306
|
-
let b = t; // 5. b = t
|
|
307
|
-
let c = c5; // 6. c = c5
|
|
308
|
-
// 7. for i in (c1, c1 - 1, ..., 2):
|
|
309
|
-
for (let i = c1; i > 1; i--) {
|
|
310
|
-
// 8. for j in (1, 2, ..., i - 2):
|
|
311
|
-
// 9. b = b * b
|
|
312
|
-
for (let j = _1n; j < i - _1n; i++)
|
|
313
|
-
b = Fp.square(b);
|
|
314
|
-
const e = Fp.equals(b, Fp.ONE); // 10. e = b == 1
|
|
315
|
-
const zt = Fp.mul(z, c); // 11. zt = z * c
|
|
316
|
-
z = Fp.cmov(zt, z, e); // 12. z = CMOV(zt, z, e)
|
|
317
|
-
c = Fp.square(c); // 13. c = c * c
|
|
318
|
-
let tt = Fp.mul(t, c); // 14. tt = t * c
|
|
319
|
-
t = Fp.cmov(tt, t, e); // 15. t = CMOV(tt, t, e)
|
|
320
|
-
b = t; // 16. b = t
|
|
321
|
-
}
|
|
322
|
-
return z; // 17. return z
|
|
323
|
-
};
|
|
324
|
-
if (q % _4n === _3n) {
|
|
325
|
-
const c1 = (q + _1n) / _4n; // 1. c1 = (q + 1) / 4 # Integer arithmetic
|
|
326
|
-
sqrt = (x) => Fp.pow(x, c1);
|
|
327
|
-
}
|
|
328
|
-
else if (q % _8n === _5n) {
|
|
329
|
-
const c1 = Fp.sqrt(Fp.negate(Fp.ONE)); // 1. c1 = sqrt(-1) in F, i.e., (c1^2) == -1 in F
|
|
330
|
-
const c2 = (q + _3n) / _8n; // 2. c2 = (q + 3) / 8 # Integer arithmetic
|
|
331
|
-
sqrt = (x) => {
|
|
332
|
-
let tv1 = Fp.pow(x, c2); // 1. tv1 = x^c2
|
|
333
|
-
let tv2 = Fp.mul(tv1, c1); // 2. tv2 = tv1 * c1
|
|
334
|
-
let e = Fp.equals(Fp.square(tv1), x); // 3. e = (tv1^2) == x
|
|
335
|
-
return Fp.cmov(tv2, tv1, e); // 4. z = CMOV(tv2, tv1, e)
|
|
336
|
-
};
|
|
337
|
-
}
|
|
338
|
-
else if (Fp.ORDER % _16n === _9n) {
|
|
339
|
-
const c1 = Fp.sqrt(Fp.negate(Fp.ONE)); // 1. c1 = sqrt(-1) in F, i.e., (c1^2) == -1 in F
|
|
340
|
-
const c2 = Fp.sqrt(c1); // 2. c2 = sqrt(c1) in F, i.e., (c2^2) == c1 in F
|
|
341
|
-
const c3 = Fp.sqrt(Fp.negate(c1)); // 3. c3 = sqrt(-c1) in F, i.e., (c3^2) == -c1 in F
|
|
342
|
-
const c4 = (Fp.ORDER + _7n) / _16n; // 4. c4 = (q + 7) / 16 # Integer arithmetic
|
|
343
|
-
sqrt = (x) => {
|
|
344
|
-
let tv1 = Fp.pow(x, c4); // 1. tv1 = x^c4
|
|
345
|
-
let tv2 = Fp.mul(c1, tv1); // 2. tv2 = c1 * tv1
|
|
346
|
-
const tv3 = Fp.mul(c2, tv1); // 3. tv3 = c2 * tv1
|
|
347
|
-
let tv4 = Fp.mul(c3, tv1); // 4. tv4 = c3 * tv1
|
|
348
|
-
const e1 = Fp.equals(Fp.square(tv2), x); // 5. e1 = (tv2^2) == x
|
|
349
|
-
const e2 = Fp.equals(Fp.square(tv3), x); // 6. e2 = (tv3^2) == x
|
|
350
|
-
tv1 = Fp.cmov(tv1, tv2, e1); // 7. tv1 = CMOV(tv1, tv2, e1) # Select tv2 if (tv2^2) == x
|
|
351
|
-
tv2 = Fp.cmov(tv4, tv3, e2); // 8. tv2 = CMOV(tv4, tv3, e2) # Select tv3 if (tv3^2) == x
|
|
352
|
-
const e3 = Fp.equals(Fp.square(tv2), x); // 9. e3 = (tv2^2) == x
|
|
353
|
-
return Fp.cmov(tv1, tv2, e3); // 10. z = CMOV(tv1, tv2, e3) # Select the sqrt from tv1 and tv2
|
|
354
|
-
};
|
|
355
|
-
}
|
|
356
|
-
return { sqrt, isSquare };
|
|
327
|
+
function FpSqrtOdd(Fp, elm) {
|
|
328
|
+
if (!Fp.isOdd)
|
|
329
|
+
throw new Error(`Field doesn't have isOdd`);
|
|
330
|
+
const root = Fp.sqrt(elm);
|
|
331
|
+
return Fp.isOdd(root) ? root : Fp.negate(root);
|
|
357
332
|
}
|
|
358
|
-
exports.
|
|
333
|
+
exports.FpSqrtOdd = FpSqrtOdd;
|
|
334
|
+
function FpSqrtEven(Fp, elm) {
|
|
335
|
+
if (!Fp.isOdd)
|
|
336
|
+
throw new Error(`Field doesn't have isOdd`);
|
|
337
|
+
const root = Fp.sqrt(elm);
|
|
338
|
+
return Fp.isOdd(root) ? Fp.negate(root) : root;
|
|
339
|
+
}
|
|
340
|
+
exports.FpSqrtEven = FpSqrtEven;
|
|
@@ -14,7 +14,7 @@ function validateOpts(curve) {
|
|
|
14
14
|
for (const i of ['montgomeryBits', 'nByteLength']) {
|
|
15
15
|
if (curve[i] === undefined)
|
|
16
16
|
continue; // Optional
|
|
17
|
-
if (!
|
|
17
|
+
if (!(0, utils_js_1.isPositiveInt)(curve[i]))
|
|
18
18
|
throw new Error(`Invalid curve param ${i}=${curve[i]} (${typeof curve[i]})`);
|
|
19
19
|
}
|
|
20
20
|
for (const fn of ['adjustScalarBytes', 'domain', 'powPminus2']) {
|
package/lib/abstract/utils.d.ts
CHANGED
|
@@ -6,7 +6,9 @@ export declare type CHash = {
|
|
|
6
6
|
(message: Uint8Array | string): Uint8Array;
|
|
7
7
|
blockLen: number;
|
|
8
8
|
outputLen: number;
|
|
9
|
-
create(
|
|
9
|
+
create(opts?: {
|
|
10
|
+
dkLen?: number;
|
|
11
|
+
}): any;
|
|
10
12
|
};
|
|
11
13
|
export declare type BasicCurve<T> = {
|
|
12
14
|
Fp: mod.Field<T>;
|
|
@@ -20,6 +22,7 @@ export declare type BasicCurve<T> = {
|
|
|
20
22
|
wrapPrivateKey?: boolean;
|
|
21
23
|
allowInfinityPoint?: boolean;
|
|
22
24
|
};
|
|
25
|
+
export declare function isPositiveInt(num: any): num is number;
|
|
23
26
|
export declare function validateOpts<FP, T>(curve: BasicCurve<FP> & T): Readonly<{
|
|
24
27
|
readonly nBitLength: number;
|
|
25
28
|
readonly nByteLength: number;
|
|
@@ -39,14 +42,15 @@ export declare function nLength(n: bigint, nBitLength?: number): {
|
|
|
39
42
|
nByteLength: number;
|
|
40
43
|
};
|
|
41
44
|
/**
|
|
45
|
+
* FIPS 186 B.4.1-compliant "constant-time" private key generation utility.
|
|
42
46
|
* Can take (n+8) or more bytes of uniform input e.g. from CSPRNG or KDF
|
|
43
47
|
* and convert them into private scalar, with the modulo bias being neglible.
|
|
44
|
-
*
|
|
48
|
+
* Needs at least 40 bytes of input for 32-byte private key.
|
|
45
49
|
* https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
|
|
46
|
-
* @param hash hash output from
|
|
50
|
+
* @param hash hash output from SHA3 or a similar function
|
|
47
51
|
* @returns valid private scalar
|
|
48
52
|
*/
|
|
49
|
-
export declare function hashToPrivateScalar(hash: Hex,
|
|
53
|
+
export declare function hashToPrivateScalar(hash: Hex, groupOrder: bigint, isLE?: boolean): bigint;
|
|
50
54
|
export declare function equalBytes(b1: Uint8Array, b2: Uint8Array): boolean;
|
|
51
55
|
export declare function bitLen(n: bigint): number;
|
|
52
56
|
export declare const bitGet: (n: bigint, pos: number) => bigint;
|
package/lib/abstract/utils.js
CHANGED
|
@@ -1,26 +1,33 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.bitMask = exports.bitSet = exports.bitGet = exports.bitLen = exports.equalBytes = exports.hashToPrivateScalar = exports.nLength = exports.concatBytes = exports.ensureBytes = exports.numberToBytesLE = exports.numberToBytesBE = exports.bytesToNumberLE = exports.bytesToNumberBE = exports.hexToBytes = exports.hexToNumber = exports.numberToHexUnpadded = exports.bytesToHex = exports.validateOpts = void 0;
|
|
3
|
+
exports.bitMask = exports.bitSet = exports.bitGet = exports.bitLen = exports.equalBytes = exports.hashToPrivateScalar = exports.nLength = exports.concatBytes = exports.ensureBytes = exports.numberToBytesLE = exports.numberToBytesBE = exports.bytesToNumberLE = exports.bytesToNumberBE = exports.hexToBytes = exports.hexToNumber = exports.numberToHexUnpadded = exports.bytesToHex = exports.validateOpts = exports.isPositiveInt = void 0;
|
|
4
4
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
5
5
|
const mod = require("./modular.js");
|
|
6
6
|
const _0n = BigInt(0);
|
|
7
7
|
const _1n = BigInt(1);
|
|
8
8
|
const _2n = BigInt(2);
|
|
9
|
+
// Bans floats and integers above 2^53-1
|
|
10
|
+
function isPositiveInt(num) {
|
|
11
|
+
return typeof num === 'number' && Number.isSafeInteger(num) && num > 0;
|
|
12
|
+
}
|
|
13
|
+
exports.isPositiveInt = isPositiveInt;
|
|
9
14
|
function validateOpts(curve) {
|
|
10
15
|
mod.validateField(curve.Fp);
|
|
11
16
|
for (const i of ['n', 'h']) {
|
|
12
|
-
|
|
13
|
-
|
|
17
|
+
const val = curve[i];
|
|
18
|
+
if (typeof val !== 'bigint')
|
|
19
|
+
throw new Error(`Invalid curve param ${i}=${val} (${typeof val})`);
|
|
14
20
|
}
|
|
15
21
|
if (!curve.Fp.isValid(curve.Gx))
|
|
16
22
|
throw new Error('Invalid generator X coordinate Fp element');
|
|
17
23
|
if (!curve.Fp.isValid(curve.Gy))
|
|
18
24
|
throw new Error('Invalid generator Y coordinate Fp element');
|
|
19
25
|
for (const i of ['nBitLength', 'nByteLength']) {
|
|
20
|
-
|
|
26
|
+
const val = curve[i];
|
|
27
|
+
if (val === undefined)
|
|
21
28
|
continue; // Optional
|
|
22
|
-
if (!
|
|
23
|
-
throw new Error(`Invalid curve param ${i}=${
|
|
29
|
+
if (!isPositiveInt(val))
|
|
30
|
+
throw new Error(`Invalid curve param ${i}=${val} (${typeof val})`);
|
|
24
31
|
}
|
|
25
32
|
// Set defaults
|
|
26
33
|
return Object.freeze({ ...nLength(curve.n, curve.nBitLength), ...curve });
|
|
@@ -119,21 +126,22 @@ function nLength(n, nBitLength) {
|
|
|
119
126
|
}
|
|
120
127
|
exports.nLength = nLength;
|
|
121
128
|
/**
|
|
129
|
+
* FIPS 186 B.4.1-compliant "constant-time" private key generation utility.
|
|
122
130
|
* Can take (n+8) or more bytes of uniform input e.g. from CSPRNG or KDF
|
|
123
131
|
* and convert them into private scalar, with the modulo bias being neglible.
|
|
124
|
-
*
|
|
132
|
+
* Needs at least 40 bytes of input for 32-byte private key.
|
|
125
133
|
* https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
|
|
126
|
-
* @param hash hash output from
|
|
134
|
+
* @param hash hash output from SHA3 or a similar function
|
|
127
135
|
* @returns valid private scalar
|
|
128
136
|
*/
|
|
129
|
-
function hashToPrivateScalar(hash,
|
|
137
|
+
function hashToPrivateScalar(hash, groupOrder, isLE = false) {
|
|
130
138
|
hash = ensureBytes(hash);
|
|
131
|
-
const
|
|
132
|
-
const minLen =
|
|
133
|
-
if (
|
|
134
|
-
throw new Error(
|
|
139
|
+
const hashLen = hash.length;
|
|
140
|
+
const minLen = nLength(groupOrder).nByteLength + 8;
|
|
141
|
+
if (minLen < 24 || hashLen < minLen || hashLen > 1024)
|
|
142
|
+
throw new Error(`hashToPrivateScalar: expected ${minLen}-1024 bytes of input, got ${hashLen}`);
|
|
135
143
|
const num = isLE ? bytesToNumberLE(hash) : bytesToNumberBE(hash);
|
|
136
|
-
return mod.mod(num,
|
|
144
|
+
return mod.mod(num, groupOrder - _1n) + _1n;
|
|
137
145
|
}
|
|
138
146
|
exports.hashToPrivateScalar = hashToPrivateScalar;
|
|
139
147
|
function equalBytes(b1, b2) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
|
2
2
|
import * as mod from './modular.js';
|
|
3
|
+
import * as ut from './utils.js';
|
|
3
4
|
import { Hex, PrivKey } from './utils.js';
|
|
4
|
-
import * as utils from './utils.js';
|
|
5
5
|
import { htfOpts } from './hash-to-curve.js';
|
|
6
6
|
import { Group, GroupConstructor } from './group.js';
|
|
7
7
|
declare type HmacFnSync = (key: Uint8Array, ...messages: Uint8Array[]) => Uint8Array;
|
|
@@ -14,10 +14,11 @@ declare type EndomorphismOpts = {
|
|
|
14
14
|
k2: bigint;
|
|
15
15
|
};
|
|
16
16
|
};
|
|
17
|
-
export declare type BasicCurve<T> =
|
|
17
|
+
export declare type BasicCurve<T> = ut.BasicCurve<T> & {
|
|
18
18
|
a: T;
|
|
19
19
|
b: T;
|
|
20
20
|
normalizePrivateKey?: (key: PrivKey) => PrivKey;
|
|
21
|
+
wrapPrivateKey?: boolean;
|
|
21
22
|
endo?: EndomorphismOpts;
|
|
22
23
|
isTorsionFree?: (c: ProjectiveConstructor<T>, point: ProjectivePointType<T>) => boolean;
|
|
23
24
|
clearCofactor?: (c: ProjectiveConstructor<T>, point: ProjectivePointType<T>) => ProjectivePointType<T>;
|
|
@@ -28,7 +29,7 @@ export declare type BasicCurve<T> = utils.BasicCurve<T> & {
|
|
|
28
29
|
};
|
|
29
30
|
};
|
|
30
31
|
declare type Entropy = Hex | true;
|
|
31
|
-
declare type SignOpts = {
|
|
32
|
+
export declare type SignOpts = {
|
|
32
33
|
lowS?: boolean;
|
|
33
34
|
extraEntropy?: Entropy;
|
|
34
35
|
};
|
|
@@ -127,7 +128,7 @@ export declare type SignatureConstructor = {
|
|
|
127
128
|
export declare type PubKey = Hex | PointType<bigint>;
|
|
128
129
|
export declare type CurveType = BasicCurve<bigint> & {
|
|
129
130
|
lowS?: boolean;
|
|
130
|
-
hash:
|
|
131
|
+
hash: ut.CHash;
|
|
131
132
|
hmac: HmacFnSync;
|
|
132
133
|
randomBytes: (bytesLength?: number) => Uint8Array;
|
|
133
134
|
truncateHash?: (hash: Uint8Array, truncateOnly?: boolean) => bigint;
|
|
@@ -145,7 +146,7 @@ declare function validateOpts(curve: CurveType): Readonly<{
|
|
|
145
146
|
readonly allowInfinityPoint?: boolean | undefined;
|
|
146
147
|
readonly a: bigint;
|
|
147
148
|
readonly b: bigint;
|
|
148
|
-
readonly normalizePrivateKey?: ((key: PrivKey) => PrivKey) | undefined;
|
|
149
|
+
readonly normalizePrivateKey?: ((key: ut.PrivKey) => ut.PrivKey) | undefined;
|
|
149
150
|
readonly endo?: EndomorphismOpts | undefined;
|
|
150
151
|
readonly isTorsionFree?: ((c: ProjectiveConstructor<bigint>, point: ProjectivePointType<bigint>) => boolean) | undefined;
|
|
151
152
|
readonly clearCofactor?: ((c: ProjectiveConstructor<bigint>, point: ProjectivePointType<bigint>) => ProjectivePointType<bigint>) | undefined;
|
|
@@ -155,7 +156,7 @@ declare function validateOpts(curve: CurveType): Readonly<{
|
|
|
155
156
|
y: bigint;
|
|
156
157
|
}) | undefined;
|
|
157
158
|
lowS: boolean;
|
|
158
|
-
readonly hash:
|
|
159
|
+
readonly hash: ut.CHash;
|
|
159
160
|
readonly hmac: HmacFnSync;
|
|
160
161
|
readonly randomBytes: (bytesLength?: number | undefined) => Uint8Array;
|
|
161
162
|
readonly truncateHash?: ((hash: Uint8Array, truncateOnly?: boolean | undefined) => bigint) | undefined;
|
|
@@ -165,6 +166,7 @@ export declare type CurveFn = {
|
|
|
165
166
|
getPublicKey: (privateKey: PrivKey, isCompressed?: boolean) => Uint8Array;
|
|
166
167
|
getSharedSecret: (privateA: PrivKey, publicB: PubKey, isCompressed?: boolean) => Uint8Array;
|
|
167
168
|
sign: (msgHash: Hex, privKey: PrivKey, opts?: SignOpts) => SignatureType;
|
|
169
|
+
signUnhashed: (msg: Uint8Array, privKey: PrivKey, opts?: SignOpts) => SignatureType;
|
|
168
170
|
verify: (signature: Hex | SignatureType, msgHash: Hex, publicKey: PubKey, opts?: {
|
|
169
171
|
lowS?: boolean;
|
|
170
172
|
}) => boolean;
|
|
@@ -172,8 +174,6 @@ export declare type CurveFn = {
|
|
|
172
174
|
ProjectivePoint: ProjectiveConstructor<bigint>;
|
|
173
175
|
Signature: SignatureConstructor;
|
|
174
176
|
utils: {
|
|
175
|
-
mod: (a: bigint, b?: bigint) => bigint;
|
|
176
|
-
invert: (number: bigint, modulo?: bigint) => bigint;
|
|
177
177
|
_bigintToBytes: (num: bigint) => Uint8Array;
|
|
178
178
|
_bigintToString: (num: bigint) => string;
|
|
179
179
|
_normalizePrivateKey: (key: PrivKey) => bigint;
|