@noble/curves 0.4.0 → 0.5.1

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 (75) hide show
  1. package/README.md +254 -162
  2. package/lib/_shortw_utils.d.ts +75 -0
  3. package/lib/_shortw_utils.js +20 -0
  4. package/lib/{bls.d.ts → abstract/bls.d.ts} +2 -1
  5. package/lib/{bls.js → abstract/bls.js} +28 -27
  6. package/lib/{edwards.d.ts → abstract/edwards.d.ts} +17 -0
  7. package/lib/{edwards.js → abstract/edwards.js} +45 -4
  8. package/lib/{group.d.ts → abstract/group.d.ts} +2 -1
  9. package/lib/{group.js → abstract/group.js} +4 -3
  10. package/lib/abstract/hash-to-curve.d.ts +28 -0
  11. package/lib/{hashToCurve.js → abstract/hash-to-curve.js} +46 -11
  12. package/lib/{modular.d.ts → abstract/modular.d.ts} +13 -16
  13. package/lib/abstract/modular.js +337 -0
  14. package/lib/{montgomery.d.ts → abstract/montgomery.d.ts} +2 -1
  15. package/lib/{montgomery.js → abstract/montgomery.js} +17 -8
  16. package/lib/{utils.d.ts → abstract/utils.d.ts} +4 -2
  17. package/lib/{utils.js → abstract/utils.js} +1 -1
  18. package/lib/{weierstrass.d.ts → abstract/weierstrass.d.ts} +28 -16
  19. package/lib/{weierstrass.js → abstract/weierstrass.js} +261 -127
  20. package/lib/bls12-381.d.ts +66 -0
  21. package/lib/bls12-381.js +1132 -0
  22. package/lib/bn.d.ts +7 -0
  23. package/lib/bn.js +24 -0
  24. package/lib/ed25519.d.ts +48 -0
  25. package/lib/ed25519.js +385 -0
  26. package/lib/ed448.d.ts +3 -0
  27. package/lib/ed448.js +211 -0
  28. package/lib/esm/_shortw_utils.js +15 -0
  29. package/lib/esm/{bls.js → abstract/bls.js} +25 -24
  30. package/lib/esm/{edwards.js → abstract/edwards.js} +45 -4
  31. package/lib/esm/{group.js → abstract/group.js} +4 -3
  32. package/lib/esm/{hashToCurve.js → abstract/hash-to-curve.js} +43 -10
  33. package/lib/esm/abstract/modular.js +319 -0
  34. package/lib/esm/{montgomery.js → abstract/montgomery.js} +17 -8
  35. package/lib/esm/{utils.js → abstract/utils.js} +1 -1
  36. package/lib/esm/{weierstrass.js → abstract/weierstrass.js} +255 -123
  37. package/lib/esm/bls12-381.js +1129 -0
  38. package/lib/esm/bn.js +21 -0
  39. package/lib/esm/ed25519.js +381 -0
  40. package/lib/esm/ed448.js +208 -0
  41. package/lib/esm/index.js +2 -0
  42. package/lib/esm/jubjub.js +52 -0
  43. package/lib/esm/p192.js +21 -0
  44. package/lib/esm/p224.js +21 -0
  45. package/lib/esm/p256.js +39 -0
  46. package/lib/esm/p384.js +44 -0
  47. package/lib/esm/p521.js +58 -0
  48. package/lib/esm/pasta.js +29 -0
  49. package/lib/esm/secp256k1.js +293 -0
  50. package/lib/esm/stark.js +224 -0
  51. package/lib/index.d.ts +0 -0
  52. package/lib/index.js +2 -0
  53. package/lib/jubjub.d.ts +7 -0
  54. package/lib/jubjub.js +57 -0
  55. package/lib/p192.d.ts +130 -0
  56. package/lib/p192.js +24 -0
  57. package/lib/p224.d.ts +130 -0
  58. package/lib/p224.js +24 -0
  59. package/lib/p256.d.ts +130 -0
  60. package/lib/p256.js +42 -0
  61. package/lib/p384.d.ts +130 -0
  62. package/lib/p384.js +47 -0
  63. package/lib/p521.d.ts +131 -0
  64. package/lib/p521.js +61 -0
  65. package/lib/pasta.d.ts +4 -0
  66. package/lib/pasta.js +32 -0
  67. package/lib/secp256k1.d.ts +96 -0
  68. package/lib/secp256k1.js +297 -0
  69. package/lib/stark.d.ts +72 -0
  70. package/lib/stark.js +245 -0
  71. package/package.json +146 -50
  72. package/index.js +0 -1
  73. package/lib/esm/modular.js +0 -252
  74. package/lib/hashToCurve.d.ts +0 -13
  75. package/lib/modular.js +0 -267
@@ -0,0 +1,319 @@
1
+ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
+ // TODO: remove circular imports
3
+ import * as utils from './utils.js';
4
+ // Utilities for modular arithmetics and finite fields
5
+ // prettier-ignore
6
+ const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3);
7
+ // prettier-ignore
8
+ const _4n = BigInt(4), _5n = BigInt(5), _8n = BigInt(8);
9
+ // prettier-ignore
10
+ const _9n = BigInt(9), _16n = BigInt(16);
11
+ // Calculates a modulo b
12
+ export function mod(a, b) {
13
+ const result = a % b;
14
+ return result >= _0n ? result : b + result;
15
+ }
16
+ /**
17
+ * Efficiently exponentiate num to power and do modular division.
18
+ * Unsafe in some contexts: uses ladder, so can expose bigint bits.
19
+ * @example
20
+ * powMod(2n, 6n, 11n) // 64n % 11n == 9n
21
+ */
22
+ // TODO: use field version && remove
23
+ export function pow(num, power, modulo) {
24
+ if (modulo <= _0n || power < _0n)
25
+ throw new Error('Expected power/modulo > 0');
26
+ if (modulo === _1n)
27
+ return _0n;
28
+ let res = _1n;
29
+ while (power > _0n) {
30
+ if (power & _1n)
31
+ res = (res * num) % modulo;
32
+ num = (num * num) % modulo;
33
+ power >>= _1n;
34
+ }
35
+ return res;
36
+ }
37
+ // Does x ^ (2 ^ power) mod p. pow2(30, 4) == 30 ^ (2 ^ 4)
38
+ // TODO: Fp version?
39
+ export function pow2(x, power, modulo) {
40
+ let res = x;
41
+ while (power-- > _0n) {
42
+ res *= res;
43
+ res %= modulo;
44
+ }
45
+ return res;
46
+ }
47
+ // Inverses number over modulo
48
+ export function invert(number, modulo) {
49
+ if (number === _0n || modulo <= _0n) {
50
+ throw new Error(`invert: expected positive integers, got n=${number} mod=${modulo}`);
51
+ }
52
+ // Eucledian GCD https://brilliant.org/wiki/extended-euclidean-algorithm/
53
+ let a = mod(number, modulo);
54
+ let b = modulo;
55
+ // prettier-ignore
56
+ let x = _0n, y = _1n, u = _1n, v = _0n;
57
+ while (a !== _0n) {
58
+ const q = b / a;
59
+ const r = b % a;
60
+ const m = x - u * q;
61
+ const n = y - v * q;
62
+ // prettier-ignore
63
+ b = a, a = r, x = u, y = v, u = m, v = n;
64
+ }
65
+ const gcd = b;
66
+ if (gcd !== _1n)
67
+ throw new Error('invert: does not exist');
68
+ return mod(x, modulo);
69
+ }
70
+ // Tonelli-Shanks algorithm
71
+ // https://eprint.iacr.org/2012/685.pdf (page 12)
72
+ export function tonelliShanks(P) {
73
+ // Legendre constant: used to calculate Legendre symbol (a | p),
74
+ // which denotes the value of a^((p-1)/2) (mod p).
75
+ // (a | p) ≡ 1 if a is a square (mod p)
76
+ // (a | p) ≡ -1 if a is not a square (mod p)
77
+ // (a | p) ≡ 0 if a ≡ 0 (mod p)
78
+ const legendreC = (P - _1n) / _2n;
79
+ let Q, S, Z;
80
+ // Step 1: By factoring out powers of 2 from p - 1,
81
+ // find q and s such that p - 1 = q2s with q odd
82
+ for (Q = P - _1n, S = 0; Q % _2n === _0n; Q /= _2n, S++)
83
+ ;
84
+ // Step 2: Select a non-square z such that (z | p) ≡ -1 and set c ≡ zq
85
+ for (Z = _2n; Z < P && pow(Z, legendreC, P) !== P - _1n; Z++)
86
+ ;
87
+ // Fast-path
88
+ if (S === 1) {
89
+ const p1div4 = (P + _1n) / _4n;
90
+ return function tonelliFast(Fp, n) {
91
+ const root = Fp.pow(n, p1div4);
92
+ if (!Fp.equals(Fp.square(root), n))
93
+ throw new Error('Cannot find square root');
94
+ return root;
95
+ };
96
+ }
97
+ // Slow-path
98
+ const Q1div2 = (Q + _1n) / _2n;
99
+ return function tonelliSlow(Fp, n) {
100
+ // Step 0: Check that n is indeed a square: (n | p) must be ≡ 1
101
+ if (Fp.pow(n, legendreC) !== Fp.ONE)
102
+ throw new Error('Cannot find square root');
103
+ let s = S;
104
+ let c = pow(Z, Q, P);
105
+ let r = Fp.pow(n, Q1div2);
106
+ let t = Fp.pow(n, Q);
107
+ let t2 = Fp.ZERO;
108
+ while (!Fp.equals(Fp.sub(t, Fp.ONE), Fp.ZERO)) {
109
+ t2 = Fp.square(t);
110
+ let i;
111
+ for (i = 1; i < s; i++) {
112
+ // stop if t2-1 == 0
113
+ if (Fp.equals(Fp.sub(t2, Fp.ONE), Fp.ZERO))
114
+ break;
115
+ // t2 *= t2
116
+ t2 = Fp.square(t2);
117
+ }
118
+ let b = pow(c, BigInt(1 << (s - i - 1)), P);
119
+ r = Fp.mul(r, b);
120
+ c = mod(b * b, P);
121
+ t = Fp.mul(t, c);
122
+ s = i;
123
+ }
124
+ return r;
125
+ };
126
+ }
127
+ export function FpSqrt(P) {
128
+ // NOTE: different algorithms can give different roots, it is up to user to decide which one they want.
129
+ // For example there is FpSqrtOdd/FpSqrtEven to choice root based on oddness (used for hash-to-curve).
130
+ // P ≡ 3 (mod 4)
131
+ // √n = n^((P+1)/4)
132
+ if (P % _4n === _3n) {
133
+ // Not all roots possible!
134
+ // const ORDER =
135
+ // 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn;
136
+ // const NUM = 72057594037927816n;
137
+ const p1div4 = (P + _1n) / _4n;
138
+ return function sqrt3mod4(Fp, n) {
139
+ const root = Fp.pow(n, p1div4);
140
+ // Throw if root**2 != n
141
+ if (!Fp.equals(Fp.square(root), n))
142
+ throw new Error('Cannot find square root');
143
+ return root;
144
+ };
145
+ }
146
+ // Atkin algorithm for q ≡ 5 (mod 8), https://eprint.iacr.org/2012/685.pdf (page 10)
147
+ if (P % _8n === _5n) {
148
+ const c1 = (P - _5n) / _8n;
149
+ return function sqrt5mod8(Fp, n) {
150
+ const n2 = Fp.mul(n, _2n);
151
+ const v = Fp.pow(n2, c1);
152
+ const nv = Fp.mul(n, v);
153
+ const i = Fp.mul(Fp.mul(nv, _2n), v);
154
+ const root = Fp.mul(nv, Fp.sub(i, Fp.ONE));
155
+ if (!Fp.equals(Fp.square(root), n))
156
+ throw new Error('Cannot find square root');
157
+ return root;
158
+ };
159
+ }
160
+ // P ≡ 9 (mod 16)
161
+ if (P % _16n === _9n) {
162
+ // NOTE: tonelli is too slow for bls-Fp2 calculations even on start
163
+ // Means we cannot use sqrt for constants at all!
164
+ //
165
+ // const c1 = Fp.sqrt(Fp.negate(Fp.ONE)); // 1. c1 = sqrt(-1) in F, i.e., (c1^2) == -1 in F
166
+ // const c2 = Fp.sqrt(c1); // 2. c2 = sqrt(c1) in F, i.e., (c2^2) == c1 in F
167
+ // const c3 = Fp.sqrt(Fp.negate(c1)); // 3. c3 = sqrt(-c1) in F, i.e., (c3^2) == -c1 in F
168
+ // const c4 = (P + _7n) / _16n; // 4. c4 = (q + 7) / 16 # Integer arithmetic
169
+ // sqrt = (x) => {
170
+ // let tv1 = Fp.pow(x, c4); // 1. tv1 = x^c4
171
+ // let tv2 = Fp.mul(c1, tv1); // 2. tv2 = c1 * tv1
172
+ // const tv3 = Fp.mul(c2, tv1); // 3. tv3 = c2 * tv1
173
+ // let tv4 = Fp.mul(c3, tv1); // 4. tv4 = c3 * tv1
174
+ // const e1 = Fp.equals(Fp.square(tv2), x); // 5. e1 = (tv2^2) == x
175
+ // const e2 = Fp.equals(Fp.square(tv3), x); // 6. e2 = (tv3^2) == x
176
+ // tv1 = Fp.cmov(tv1, tv2, e1); // 7. tv1 = CMOV(tv1, tv2, e1) # Select tv2 if (tv2^2) == x
177
+ // tv2 = Fp.cmov(tv4, tv3, e2); // 8. tv2 = CMOV(tv4, tv3, e2) # Select tv3 if (tv3^2) == x
178
+ // const e3 = Fp.equals(Fp.square(tv2), x); // 9. e3 = (tv2^2) == x
179
+ // return Fp.cmov(tv1, tv2, e3); // 10. z = CMOV(tv1, tv2, e3) # Select the sqrt from tv1 and tv2
180
+ // }
181
+ }
182
+ // Other cases: Tonelli-Shanks algorithm
183
+ return tonelliShanks(P);
184
+ }
185
+ // Little-endian check for first LE bit (last BE bit);
186
+ export const isNegativeLE = (num, modulo) => (mod(num, modulo) & _1n) === _1n;
187
+ // prettier-ignore
188
+ const FIELD_FIELDS = [
189
+ 'create', 'isValid', 'isZero', 'negate', 'invert', 'sqrt', 'square',
190
+ 'equals', 'add', 'sub', 'mul', 'pow', 'div',
191
+ 'addN', 'subN', 'mulN', 'squareN'
192
+ ];
193
+ export function validateField(field) {
194
+ for (const i of ['ORDER', 'MASK']) {
195
+ if (typeof field[i] !== 'bigint')
196
+ throw new Error(`Invalid field param ${i}=${field[i]} (${typeof field[i]})`);
197
+ }
198
+ for (const i of ['BYTES', 'BITS']) {
199
+ if (typeof field[i] !== 'number')
200
+ throw new Error(`Invalid field param ${i}=${field[i]} (${typeof field[i]})`);
201
+ }
202
+ for (const i of FIELD_FIELDS) {
203
+ if (typeof field[i] !== 'function')
204
+ throw new Error(`Invalid field param ${i}=${field[i]} (${typeof field[i]})`);
205
+ }
206
+ }
207
+ // Generic field functions
208
+ export function FpPow(f, num, power) {
209
+ // Should have same speed as pow for bigints
210
+ // TODO: benchmark!
211
+ if (power < _0n)
212
+ throw new Error('Expected power > 0');
213
+ if (power === _0n)
214
+ return f.ONE;
215
+ if (power === _1n)
216
+ return num;
217
+ let p = f.ONE;
218
+ let d = num;
219
+ while (power > _0n) {
220
+ if (power & _1n)
221
+ p = f.mul(p, d);
222
+ d = f.square(d);
223
+ power >>= 1n;
224
+ }
225
+ return p;
226
+ }
227
+ export function FpInvertBatch(f, nums) {
228
+ const tmp = new Array(nums.length);
229
+ // Walk from first to last, multiply them by each other MOD p
230
+ const lastMultiplied = nums.reduce((acc, num, i) => {
231
+ if (f.isZero(num))
232
+ return acc;
233
+ tmp[i] = acc;
234
+ return f.mul(acc, num);
235
+ }, f.ONE);
236
+ // Invert last element
237
+ const inverted = f.invert(lastMultiplied);
238
+ // Walk from last to first, multiply them by inverted each other MOD p
239
+ nums.reduceRight((acc, num, i) => {
240
+ if (f.isZero(num))
241
+ return acc;
242
+ tmp[i] = f.mul(acc, tmp[i]);
243
+ return f.mul(acc, num);
244
+ }, inverted);
245
+ return tmp;
246
+ }
247
+ export function FpDiv(f, lhs, rhs) {
248
+ return f.mul(lhs, typeof rhs === 'bigint' ? invert(rhs, f.ORDER) : f.invert(rhs));
249
+ }
250
+ // This function returns True whenever the value x is a square in the field F.
251
+ export function FpIsSquare(f) {
252
+ const legendreConst = (f.ORDER - _1n) / _2n; // Integer arithmetic
253
+ return (x) => {
254
+ const p = f.pow(x, legendreConst);
255
+ return f.equals(p, f.ZERO) || f.equals(p, f.ONE);
256
+ };
257
+ }
258
+ export function Fp(ORDER, bitLen, isLE = false, redef = {}) {
259
+ if (ORDER <= _0n)
260
+ throw new Error(`Expected Fp ORDER > 0, got ${ORDER}`);
261
+ const { nBitLength: BITS, nByteLength: BYTES } = utils.nLength(ORDER, bitLen);
262
+ if (BYTES > 2048)
263
+ throw new Error('Field lengths over 2048 bytes are not supported');
264
+ const sqrtP = FpSqrt(ORDER);
265
+ const f = Object.freeze({
266
+ ORDER,
267
+ BITS,
268
+ BYTES,
269
+ MASK: utils.bitMask(BITS),
270
+ ZERO: _0n,
271
+ ONE: _1n,
272
+ create: (num) => mod(num, ORDER),
273
+ isValid: (num) => {
274
+ if (typeof num !== 'bigint')
275
+ throw new Error(`Invalid field element: expected bigint, got ${typeof num}`);
276
+ return _0n <= num && num < ORDER;
277
+ },
278
+ isZero: (num) => num === _0n,
279
+ isOdd: (num) => (num & _1n) === _1n,
280
+ negate: (num) => mod(-num, ORDER),
281
+ equals: (lhs, rhs) => lhs === rhs,
282
+ square: (num) => mod(num * num, ORDER),
283
+ add: (lhs, rhs) => mod(lhs + rhs, ORDER),
284
+ sub: (lhs, rhs) => mod(lhs - rhs, ORDER),
285
+ mul: (lhs, rhs) => mod(lhs * rhs, ORDER),
286
+ pow: (num, power) => FpPow(f, num, power),
287
+ div: (lhs, rhs) => mod(lhs * invert(rhs, ORDER), ORDER),
288
+ // Same as above, but doesn't normalize
289
+ squareN: (num) => num * num,
290
+ addN: (lhs, rhs) => lhs + rhs,
291
+ subN: (lhs, rhs) => lhs - rhs,
292
+ mulN: (lhs, rhs) => lhs * rhs,
293
+ invert: (num) => invert(num, ORDER),
294
+ sqrt: redef.sqrt || ((n) => sqrtP(f, n)),
295
+ invertBatch: (lst) => FpInvertBatch(f, lst),
296
+ // TODO: do we really need constant cmov?
297
+ // We don't have const-time bigints anyway, so probably will be not very useful
298
+ cmov: (a, b, c) => (c ? b : a),
299
+ toBytes: (num) => isLE ? utils.numberToBytesLE(num, BYTES) : utils.numberToBytesBE(num, BYTES),
300
+ fromBytes: (bytes) => {
301
+ if (bytes.length !== BYTES)
302
+ throw new Error(`Fp.fromBytes: expected ${BYTES}, got ${bytes.length}`);
303
+ return isLE ? utils.bytesToNumberLE(bytes) : utils.bytesToNumberBE(bytes);
304
+ },
305
+ });
306
+ return Object.freeze(f);
307
+ }
308
+ export function FpSqrtOdd(Fp, elm) {
309
+ if (!Fp.isOdd)
310
+ throw new Error(`Field doesn't have isOdd`);
311
+ const root = Fp.sqrt(elm);
312
+ return Fp.isOdd(root) ? root : Fp.negate(root);
313
+ }
314
+ export function FpSqrtEven(Fp, elm) {
315
+ if (!Fp.isOdd)
316
+ throw new Error(`Field doesn't have isOdd`);
317
+ const root = Fp.sqrt(elm);
318
+ return Fp.isOdd(root) ? Fp.negate(root) : root;
319
+ }
@@ -1,3 +1,4 @@
1
+ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
1
2
  import * as mod from './modular.js';
2
3
  import { ensureBytes, numberToBytesLE, bytesToNumberLE,
3
4
  // nLength,
@@ -161,8 +162,14 @@ export function montgomery(curveDef) {
161
162
  throw new Error(`Expected ${montgomeryBytes} or ${fieldLen} bytes, got ${bytes.length}`);
162
163
  return bytesToNumberLE(adjustScalarBytes(bytes));
163
164
  }
164
- // Multiply point u by scalar
165
- function scalarMult(u, scalar) {
165
+ /**
166
+ * Computes shared secret between private key "scalar" and public key's "u" (x) coordinate.
167
+ * We can get 'y' coordinate from 'u',
168
+ * but Point.fromHex also wants 'x' coordinate oddity flag,
169
+ * and we cannot get 'x' without knowing 'v'.
170
+ * Need to add generic conversion between twisted edwards and complimentary curve for JubJub.
171
+ */
172
+ function scalarMult(scalar, u) {
166
173
  const pointU = decodeUCoordinate(u);
167
174
  const _scalar = decodeScalar(scalar);
168
175
  const pu = montgomeryLadder(pointU, _scalar);
@@ -172,17 +179,19 @@ export function montgomery(curveDef) {
172
179
  throw new Error('Invalid private or public key received');
173
180
  return encodeUCoordinate(pu);
174
181
  }
175
- // Multiply base point by scalar
182
+ /**
183
+ * Computes public key from private.
184
+ * Executes scalar multiplication of curve's base point by scalar.
185
+ * @param scalar private key
186
+ * @returns new public key
187
+ */
176
188
  function scalarMultBase(scalar) {
177
- return scalarMult(CURVE.Gu, scalar);
189
+ return scalarMult(scalar, CURVE.Gu);
178
190
  }
179
191
  return {
180
- // NOTE: we can get 'y' coordinate from 'u', but Point.fromHex also wants 'x' coordinate oddity flag, and we cannot get 'x' without knowing 'v'
181
- // Need to add generic conversion between twisted edwards and complimentary curve for JubJub
182
192
  scalarMult,
183
193
  scalarMultBase,
184
- // NOTE: these function work on complimentary montgomery curve
185
- // getSharedSecret: (privateKey: Hex, publicKey: Hex) => scalarMult(publicKey, privateKey),
194
+ getSharedSecret: (privateKey, publicKey) => scalarMult(privateKey, publicKey),
186
195
  getPublicKey: (privateKey) => scalarMultBase(privateKey),
187
196
  Gu: CURVE.Gu,
188
197
  };
@@ -1,4 +1,4 @@
1
- /*! @noble/curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
1
+ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
2
  import * as mod from './modular.js';
3
3
  const _0n = BigInt(0);
4
4
  const _1n = BigInt(1);