@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.
Files changed (50) hide show
  1. package/README.md +62 -14
  2. package/lib/_shortw_utils.d.ts +2 -6
  3. package/lib/abstract/bls.d.ts +17 -8
  4. package/lib/abstract/bls.js +15 -78
  5. package/lib/abstract/edwards.d.ts +7 -16
  6. package/lib/abstract/edwards.js +89 -106
  7. package/lib/abstract/hash-to-curve.d.ts +10 -1
  8. package/lib/abstract/hash-to-curve.js +32 -10
  9. package/lib/abstract/modular.d.ts +8 -17
  10. package/lib/abstract/modular.js +134 -152
  11. package/lib/abstract/montgomery.js +1 -1
  12. package/lib/abstract/utils.d.ts +8 -4
  13. package/lib/abstract/utils.js +22 -14
  14. package/lib/abstract/weierstrass.d.ts +8 -8
  15. package/lib/abstract/weierstrass.js +209 -168
  16. package/lib/bls12-381.d.ts +2 -1
  17. package/lib/bls12-381.js +14 -9
  18. package/lib/ed25519.js +75 -12
  19. package/lib/ed448.js +86 -2
  20. package/lib/esm/abstract/bls.js +19 -82
  21. package/lib/esm/abstract/edwards.js +90 -107
  22. package/lib/esm/abstract/hash-to-curve.js +30 -9
  23. package/lib/esm/abstract/modular.js +128 -148
  24. package/lib/esm/abstract/montgomery.js +2 -4
  25. package/lib/esm/abstract/utils.js +20 -13
  26. package/lib/esm/abstract/weierstrass.js +210 -169
  27. package/lib/esm/bls12-381.js +13 -8
  28. package/lib/esm/ed25519.js +76 -13
  29. package/lib/esm/ed448.js +87 -3
  30. package/lib/esm/jubjub.js +5 -4
  31. package/lib/esm/p256.js +1 -1
  32. package/lib/esm/p384.js +1 -1
  33. package/lib/esm/p521.js +1 -1
  34. package/lib/esm/secp256k1.js +27 -27
  35. package/lib/esm/stark.js +5 -2
  36. package/lib/jubjub.d.ts +1 -0
  37. package/lib/jubjub.js +5 -4
  38. package/lib/p192.d.ts +4 -12
  39. package/lib/p224.d.ts +4 -12
  40. package/lib/p256.d.ts +4 -12
  41. package/lib/p256.js +1 -1
  42. package/lib/p384.d.ts +4 -12
  43. package/lib/p384.js +1 -1
  44. package/lib/p521.d.ts +4 -12
  45. package/lib/p521.js +1 -1
  46. package/lib/secp256k1.d.ts +2 -6
  47. package/lib/secp256k1.js +27 -27
  48. package/lib/stark.d.ts +1 -3
  49. package/lib/stark.js +5 -2
  50. package/package.json +2 -2
@@ -1,13 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.FpSqrt = exports.Fp = exports.FpDiv = exports.FpInvertBatch = exports.FpPow = exports.validateField = exports.isNegativeLE = exports.sqrt = exports.legendre = exports.invert = exports.pow2 = exports.pow = exports.mod = void 0;
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), _7n = BigInt(7), _8n = BigInt(8);
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
- * Calculates Legendre symbol (a | p), which denotes the value of a^((p-1)/2) (mod p).
78
- * * (a | p) 1 if a is a square (mod p)
79
- * * (a | p) ≡ -1 if a is not a square (mod p)
80
- * * (a | p) 0 if a 0 (mod p)
81
- */
82
- function legendre(num, fieldPrime) {
83
- return pow(num, (fieldPrime - _1n) / _2n, fieldPrime);
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.legendre = legendre;
86
- /**
87
- * Calculates square root of a number in a finite field.
88
- * √a mod P
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
- // TODO: fix sqrtMod in secp256k1
104
- const root = pow(n, p1div4, P);
105
- if (mod(root * root, modulo) !== number)
106
- throw new Error('Cannot find square root');
107
- return root;
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
- // P ≡ 5 (mod 8)
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 n2 = mod(n * _2n, P);
112
- const v = pow(n2, (P - _5n) / _8n, P);
113
- const nv = mod(n * v, P);
114
- const i = mod(_2n * nv * v, P);
115
- const r = mod(nv * (i - _1n), P);
116
- return r;
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
- // Other cases: Tonelli-Shanks algorithm
119
- if (legendre(n, P) !== _1n)
120
- throw new Error('Cannot find square root');
121
- let q, s, z;
122
- for (q = P - _1n, s = 0; q % _2n === _0n; q /= _2n, s++)
123
- ;
124
- if (s === 1)
125
- return pow(n, p1div4, P);
126
- for (z = _2n; z < P && legendre(z, P) !== P - _1n; z++)
127
- ;
128
- let c = pow(z, q, P);
129
- let r = pow(n, (q + _1n) / _2n, P);
130
- let t = pow(n, q, P);
131
- let t2 = _0n;
132
- while (mod(t - _1n, P) !== _0n) {
133
- t2 = mod(t * t, P);
134
- let i;
135
- for (i = 1; i < s; i++) {
136
- if (mod(t2 - _1n, P) === _0n)
137
- break;
138
- t2 = mod(t2 * t2, P);
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
- return r;
193
+ // Other cases: Tonelli-Shanks algorithm
194
+ return tonelliShanks(P);
147
195
  }
148
- exports.sqrt = sqrt;
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
- // NOTE: very fragile, always bench. Major performance points:
220
- // - NonNormalized ops
221
- // - Object.freeze
222
- // - same shape of object (don't add/remove keys)
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 = (num) => sqrt(num, ORDER);
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
- // TODO: re-use in bls/generic sqrt for field/etc?
275
- // Something like sqrtUnsafe which always returns value, but sqrt throws exception if non-square
276
- // From draft-irtf-cfrg-hash-to-curve-16
277
- function FpSqrt(Fp) {
278
- // NOTE: it requires another sqrt for constant precomputes, but no need for roots of unity,
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.FpSqrt = FpSqrt;
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 (!Number.isSafeInteger(curve[i]))
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']) {
@@ -6,7 +6,9 @@ export declare type CHash = {
6
6
  (message: Uint8Array | string): Uint8Array;
7
7
  blockLen: number;
8
8
  outputLen: number;
9
- create(): any;
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
- * As per FIPS 186 B.4.1.
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 sha512, or a similar function
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, CURVE_ORDER: bigint, isLE?: boolean): bigint;
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;
@@ -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
- if (typeof curve[i] !== 'bigint')
13
- throw new Error(`Invalid curve param ${i}=${curve[i]} (${typeof curve[i]})`);
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
- if (curve[i] === undefined)
26
+ const val = curve[i];
27
+ if (val === undefined)
21
28
  continue; // Optional
22
- if (!Number.isSafeInteger(curve[i]))
23
- throw new Error(`Invalid curve param ${i}=${curve[i]} (${typeof curve[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
- * As per FIPS 186 B.4.1.
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 sha512, or a similar function
134
+ * @param hash hash output from SHA3 or a similar function
127
135
  * @returns valid private scalar
128
136
  */
129
- function hashToPrivateScalar(hash, CURVE_ORDER, isLE = false) {
137
+ function hashToPrivateScalar(hash, groupOrder, isLE = false) {
130
138
  hash = ensureBytes(hash);
131
- const orderLen = nLength(CURVE_ORDER).nByteLength;
132
- const minLen = orderLen + 8;
133
- if (orderLen < 16 || hash.length < minLen || hash.length > 1024)
134
- throw new Error('Expected valid bytes of private key as per FIPS 186');
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, CURVE_ORDER - _1n) + _1n;
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> = utils.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: utils.CHash;
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: utils.CHash;
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;