@noble/curves 0.5.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +49 -8
  2. package/lib/_shortw_utils.d.ts +11 -26
  3. package/lib/abstract/bls.d.ts +51 -35
  4. package/lib/abstract/bls.js +77 -139
  5. package/lib/abstract/{group.d.ts → curve.d.ts} +31 -1
  6. package/lib/abstract/{group.js → curve.js} +39 -2
  7. package/lib/abstract/edwards.d.ts +30 -81
  8. package/lib/abstract/edwards.js +225 -420
  9. package/lib/abstract/hash-to-curve.d.ts +25 -6
  10. package/lib/abstract/hash-to-curve.js +40 -12
  11. package/lib/abstract/modular.d.ts +20 -7
  12. package/lib/abstract/modular.js +80 -51
  13. package/lib/abstract/montgomery.js +3 -4
  14. package/lib/abstract/poseidon.d.ts +29 -0
  15. package/lib/abstract/poseidon.js +115 -0
  16. package/lib/abstract/utils.d.ts +5 -34
  17. package/lib/abstract/utils.js +23 -63
  18. package/lib/abstract/weierstrass.d.ts +56 -79
  19. package/lib/abstract/weierstrass.js +509 -641
  20. package/lib/bls12-381.d.ts +1 -0
  21. package/lib/bls12-381.js +75 -65
  22. package/lib/bn.js +1 -1
  23. package/lib/ed25519.d.ts +7 -5
  24. package/lib/ed25519.js +87 -84
  25. package/lib/ed448.d.ts +3 -0
  26. package/lib/ed448.js +88 -84
  27. package/lib/esm/abstract/bls.js +77 -139
  28. package/lib/esm/abstract/{group.js → curve.js} +37 -1
  29. package/lib/esm/abstract/edwards.js +223 -418
  30. package/lib/esm/abstract/hash-to-curve.js +38 -11
  31. package/lib/esm/abstract/modular.js +77 -50
  32. package/lib/esm/abstract/montgomery.js +4 -7
  33. package/lib/esm/abstract/poseidon.js +109 -0
  34. package/lib/esm/abstract/utils.js +21 -59
  35. package/lib/esm/abstract/weierstrass.js +508 -640
  36. package/lib/esm/bls12-381.js +86 -76
  37. package/lib/esm/bn.js +1 -1
  38. package/lib/esm/ed25519.js +85 -83
  39. package/lib/esm/ed448.js +86 -83
  40. package/lib/esm/jubjub.js +6 -5
  41. package/lib/esm/p256.js +11 -9
  42. package/lib/esm/p384.js +11 -9
  43. package/lib/esm/p521.js +13 -12
  44. package/lib/esm/secp256k1.js +118 -157
  45. package/lib/esm/stark.js +104 -39
  46. package/lib/jubjub.d.ts +3 -2
  47. package/lib/jubjub.js +6 -5
  48. package/lib/p192.d.ts +22 -52
  49. package/lib/p224.d.ts +22 -52
  50. package/lib/p256.d.ts +25 -52
  51. package/lib/p256.js +13 -10
  52. package/lib/p384.d.ts +25 -52
  53. package/lib/p384.js +13 -10
  54. package/lib/p521.d.ts +25 -52
  55. package/lib/p521.js +15 -13
  56. package/lib/secp256k1.d.ts +26 -42
  57. package/lib/secp256k1.js +118 -157
  58. package/lib/stark.d.ts +36 -21
  59. package/lib/stark.js +107 -39
  60. package/package.json +14 -9
@@ -1,24 +1,16 @@
1
- /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
- // Barreto-Lynn-Scott Curves. A family of pairing friendly curves, with embedding degree = 12 or 24
3
- // NOTE: only 12 supported for now
4
- // Constructed from pair of weierstrass curves, based pairing logic
5
- import * as mod from './modular.js';
6
- import { ensureBytes, numberToBytesBE, bytesToNumberBE, bitLen, bitGet } from './utils.js';
7
- // Types
8
- import { hexToBytes, bytesToHex } from './utils.js';
9
- import { stringToBytes, hash_to_field, expand_message_xmd } from './hash-to-curve.js';
10
- import { weierstrassPoints } from './weierstrass.js';
1
+ import { hashToPrivateScalar } from './modular.js';
2
+ import { bitLen, bitGet, hexToBytes, bytesToHex } from './utils.js';
3
+ import * as htf from './hash-to-curve.js';
4
+ import { weierstrassPoints, } from './weierstrass.js';
11
5
  export function bls(CURVE) {
12
6
  // Fields looks pretty specific for curve, so for now we need to pass them with options
13
- const Fp = CURVE.Fp;
14
- const Fr = CURVE.Fr;
15
- const Fp2 = CURVE.Fp2;
16
- const Fp6 = CURVE.Fp6;
17
- const Fp12 = CURVE.Fp12;
7
+ const { Fp, Fr, Fp2, Fp6, Fp12 } = CURVE;
18
8
  const BLS_X_LEN = bitLen(CURVE.x);
9
+ const groupLen = 32; // TODO: calculate; hardcoded for now
19
10
  // Pre-compute coefficients for sparse multiplication
20
11
  // Point addition and point double calculations is reused for coefficients
21
- function calcPairingPrecomputes(x, y) {
12
+ function calcPairingPrecomputes(p) {
13
+ const { x, y } = p;
22
14
  // prettier-ignore
23
15
  const Qx = x, Qy = y, Qz = Fp2.ONE;
24
16
  // prettier-ignore
@@ -26,18 +18,18 @@ export function bls(CURVE) {
26
18
  let ell_coeff = [];
27
19
  for (let i = BLS_X_LEN - 2; i >= 0; i--) {
28
20
  // Double
29
- let t0 = Fp2.square(Ry); // Ry²
30
- let t1 = Fp2.square(Rz); // Rz²
21
+ let t0 = Fp2.sqr(Ry); // Ry²
22
+ let t1 = Fp2.sqr(Rz); // Rz²
31
23
  let t2 = Fp2.multiplyByB(Fp2.mul(t1, 3n)); // 3 * T1 * B
32
24
  let t3 = Fp2.mul(t2, 3n); // 3 * T2
33
- let t4 = Fp2.sub(Fp2.sub(Fp2.square(Fp2.add(Ry, Rz)), t1), t0); // (Ry + Rz)² - T1 - T0
25
+ let t4 = Fp2.sub(Fp2.sub(Fp2.sqr(Fp2.add(Ry, Rz)), t1), t0); // (Ry + Rz)² - T1 - T0
34
26
  ell_coeff.push([
35
27
  Fp2.sub(t2, t0),
36
- Fp2.mul(Fp2.square(Rx), 3n),
37
- Fp2.negate(t4), // -T4
28
+ Fp2.mul(Fp2.sqr(Rx), 3n),
29
+ Fp2.neg(t4), // -T4
38
30
  ]);
39
31
  Rx = Fp2.div(Fp2.mul(Fp2.mul(Fp2.sub(t0, t3), Rx), Ry), 2n); // ((T0 - T3) * Rx * Ry) / 2
40
- Ry = Fp2.sub(Fp2.square(Fp2.div(Fp2.add(t0, t3), 2n)), Fp2.mul(Fp2.square(t2), 3n)); // ((T0 + T3) / 2)² - 3 * T2²
32
+ Ry = Fp2.sub(Fp2.sqr(Fp2.div(Fp2.add(t0, t3), 2n)), Fp2.mul(Fp2.sqr(t2), 3n)); // ((T0 + T3) / 2)² - 3 * T2²
41
33
  Rz = Fp2.mul(t0, t4); // T0 * T4
42
34
  if (bitGet(CURVE.x, i)) {
43
35
  // Addition
@@ -45,13 +37,13 @@ export function bls(CURVE) {
45
37
  let t1 = Fp2.sub(Rx, Fp2.mul(Qx, Rz)); // Rx - Qx * Rz
46
38
  ell_coeff.push([
47
39
  Fp2.sub(Fp2.mul(t0, Qx), Fp2.mul(t1, Qy)),
48
- Fp2.negate(t0),
40
+ Fp2.neg(t0),
49
41
  t1, // T1
50
42
  ]);
51
- let t2 = Fp2.square(t1); // T1²
43
+ let t2 = Fp2.sqr(t1); // T1²
52
44
  let t3 = Fp2.mul(t2, t1); // T2 * T1
53
45
  let t4 = Fp2.mul(t2, Rx); // T2 * Rx
54
- let t5 = Fp2.add(Fp2.sub(t3, Fp2.mul(t4, 2n)), Fp2.mul(Fp2.square(t0), Rz)); // T3 - 2 * T4 + T0² * Rz
46
+ let t5 = Fp2.add(Fp2.sub(t3, Fp2.mul(t4, 2n)), Fp2.mul(Fp2.sqr(t0), Rz)); // T3 - 2 * T4 + T0² * Rz
55
47
  Rx = Fp2.mul(t1, t5); // T1 * T5
56
48
  Ry = Fp2.sub(Fp2.mul(Fp2.sub(t4, t5), t0), Fp2.mul(t3, Ry)); // (T4 - T5) * T0 - T3 * Ry
57
49
  Rz = Fp2.mul(Rz, t3); // Rz * T3
@@ -60,175 +52,121 @@ export function bls(CURVE) {
60
52
  return ell_coeff;
61
53
  }
62
54
  function millerLoop(ell, g1) {
55
+ const { x } = CURVE;
63
56
  const Px = g1[0];
64
57
  const Py = g1[1];
65
58
  let f12 = Fp12.ONE;
66
59
  for (let j = 0, i = BLS_X_LEN - 2; i >= 0; i--, j++) {
67
60
  const E = ell[j];
68
61
  f12 = Fp12.multiplyBy014(f12, E[0], Fp2.mul(E[1], Px), Fp2.mul(E[2], Py));
69
- if (bitGet(CURVE.x, i)) {
62
+ if (bitGet(x, i)) {
70
63
  j += 1;
71
64
  const F = ell[j];
72
65
  f12 = Fp12.multiplyBy014(f12, F[0], Fp2.mul(F[1], Px), Fp2.mul(F[2], Py));
73
66
  }
74
67
  if (i !== 0)
75
- f12 = Fp12.square(f12);
68
+ f12 = Fp12.sqr(f12);
76
69
  }
77
70
  return Fp12.conjugate(f12);
78
71
  }
79
- // bls12-381 is a construction of two curves:
80
- // 1. Fp: (x, y)
81
- // 2. Fp₂: ((x₁, x₂+i), (y₁, y₂+i)) - (complex numbers)
82
- //
83
- // Bilinear Pairing (ate pairing) is used to combine both elements into a paired one:
84
- // Fp₁₂ = e(Fp, Fp2)
85
- // where Fp₁₂ = 12-degree polynomial
86
- // Pairing is used to verify signatures.
87
- //
88
- // We are using Fp for private keys (shorter) and Fp2 for signatures (longer).
89
- // Some projects may prefer to swap this relation, it is not supported for now.
90
- const htfDefaults = { ...CURVE.htfDefaults };
91
- function isWithinCurveOrder(num) {
92
- return 0 < num && num < CURVE.r;
93
- }
94
72
  const utils = {
95
73
  hexToBytes: hexToBytes,
96
74
  bytesToHex: bytesToHex,
97
- mod: mod.mod,
98
- stringToBytes,
75
+ stringToBytes: htf.stringToBytes,
99
76
  // TODO: do we need to export it here?
100
- hashToField: (msg, count, options = {}) => hash_to_field(msg, count, { ...CURVE.htfDefaults, ...options }),
101
- expandMessageXMD: (msg, DST, lenInBytes, H = CURVE.hash) => expand_message_xmd(msg, DST, lenInBytes, H),
102
- /**
103
- * Can take 40 or more bytes of uniform input e.g. from CSPRNG or KDF
104
- * and convert them into private key, with the modulo bias being negligible.
105
- * As per FIPS 186 B.1.1.
106
- * https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
107
- * @param hash hash output from sha512, or a similar function
108
- * @returns valid private key
109
- */
110
- hashToPrivateKey: (hash) => {
111
- hash = ensureBytes(hash);
112
- if (hash.length < 40 || hash.length > 1024)
113
- throw new Error('Expected 40-1024 bytes of private key as per FIPS 186');
114
- // hashToPrivateScalar(hash, CURVE.r)
115
- // NOTE: doesn't add +/-1
116
- const num = mod.mod(bytesToNumberBE(hash), CURVE.r);
117
- // This should never happen
118
- if (num === 0n || num === 1n)
119
- throw new Error('Invalid private key');
120
- return numberToBytesBE(num, 32);
121
- },
122
- randomBytes: (bytesLength = 32) => CURVE.randomBytes(bytesLength),
123
- // NIST SP 800-56A rev 3, section 5.6.1.2.2
124
- // https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
125
- randomPrivateKey: () => utils.hashToPrivateKey(utils.randomBytes(40)),
126
- getDSTLabel: () => htfDefaults.DST,
127
- setDSTLabel(newLabel) {
128
- // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-3.1
129
- if (typeof newLabel !== 'string' || newLabel.length > 2048 || newLabel.length === 0) {
130
- throw new TypeError('Invalid DST');
131
- }
132
- htfDefaults.DST = newLabel;
133
- },
77
+ hashToField: (msg, count, options = {}) => htf.hash_to_field(msg, count, { ...CURVE.htfDefaults, ...options }),
78
+ expandMessageXMD: (msg, DST, lenInBytes, H = CURVE.hash) => htf.expand_message_xmd(msg, DST, lenInBytes, H),
79
+ hashToPrivateKey: (hash) => Fr.toBytes(hashToPrivateScalar(hash, CURVE.r)),
80
+ randomBytes: (bytesLength = groupLen) => CURVE.randomBytes(bytesLength),
81
+ randomPrivateKey: () => utils.hashToPrivateKey(utils.randomBytes(groupLen + 8)),
134
82
  };
135
- function normalizePrivKey(key) {
136
- let int;
137
- if (key instanceof Uint8Array && key.length === 32)
138
- int = bytesToNumberBE(key);
139
- else if (typeof key === 'string' && key.length === 64)
140
- int = BigInt(`0x${key}`);
141
- else if (typeof key === 'number' && key > 0 && Number.isSafeInteger(key))
142
- int = BigInt(key);
143
- else if (typeof key === 'bigint' && key > 0n)
144
- int = key;
145
- else
146
- throw new TypeError('Expected valid private key');
147
- int = mod.mod(int, CURVE.r);
148
- if (!isWithinCurveOrder(int))
149
- throw new Error('Private key must be 0 < key < CURVE.r');
150
- return int;
151
- }
152
83
  // Point on G1 curve: (x, y)
153
84
  const G1 = weierstrassPoints({
154
85
  n: Fr.ORDER,
155
86
  ...CURVE.G1,
156
87
  });
88
+ const G1HashToCurve = htf.hashToCurve(G1.ProjectivePoint, CURVE.G1.mapToCurve, {
89
+ ...CURVE.htfDefaults,
90
+ ...CURVE.G1.htfDefaults,
91
+ });
157
92
  function pairingPrecomputes(point) {
158
93
  const p = point;
159
94
  if (p._PPRECOMPUTES)
160
95
  return p._PPRECOMPUTES;
161
- p._PPRECOMPUTES = calcPairingPrecomputes(p.x, p.y);
96
+ p._PPRECOMPUTES = calcPairingPrecomputes(point.toAffine());
162
97
  return p._PPRECOMPUTES;
163
98
  }
164
- function clearPairingPrecomputes(point) {
165
- const p = point;
166
- p._PPRECOMPUTES = undefined;
167
- }
168
- clearPairingPrecomputes;
169
- function millerLoopG1(Q, P) {
170
- return millerLoop(pairingPrecomputes(P), [Q.x, Q.y]);
171
- }
99
+ // TODO: export
100
+ // function clearPairingPrecomputes(point: G2) {
101
+ // const p = point as G2 & withPairingPrecomputes;
102
+ // p._PPRECOMPUTES = undefined;
103
+ // }
172
104
  // Point on G2 curve (complex numbers): (x₁, x₂+i), (y₁, y₂+i)
173
105
  const G2 = weierstrassPoints({
174
106
  n: Fr.ORDER,
175
107
  ...CURVE.G2,
176
108
  });
109
+ const C = G2.ProjectivePoint; // TODO: fix
110
+ const G2HashToCurve = htf.hashToCurve(C, CURVE.G2.mapToCurve, {
111
+ ...CURVE.htfDefaults,
112
+ ...CURVE.G2.htfDefaults,
113
+ });
177
114
  const { Signature } = CURVE.G2;
178
115
  // Calculates bilinear pairing
179
- function pairing(P, Q, withFinalExponent = true) {
180
- if (P.equals(G1.Point.ZERO) || Q.equals(G2.Point.ZERO))
181
- throw new Error('No pairings at point of Infinity');
182
- P.assertValidity();
116
+ function pairing(Q, P, withFinalExponent = true) {
117
+ if (Q.equals(G1.ProjectivePoint.ZERO) || P.equals(G2.ProjectivePoint.ZERO))
118
+ throw new Error('pairing is not available for ZERO point');
183
119
  Q.assertValidity();
120
+ P.assertValidity();
184
121
  // Performance: 9ms for millerLoop and ~14ms for exp.
185
- const looped = millerLoopG1(P, Q);
122
+ const Qa = Q.toAffine();
123
+ const looped = millerLoop(pairingPrecomputes(P), [Qa.x, Qa.y]);
186
124
  return withFinalExponent ? Fp12.finalExponentiate(looped) : looped;
187
125
  }
188
126
  function normP1(point) {
189
- return point instanceof G1.Point ? point : G1.Point.fromHex(point);
127
+ return point instanceof G1.ProjectivePoint ? point : G1.ProjectivePoint.fromHex(point);
190
128
  }
191
129
  function normP2(point) {
192
- return point instanceof G2.Point ? point : Signature.decode(point);
130
+ return point instanceof G2.ProjectivePoint ? point : Signature.decode(point);
193
131
  }
194
- function normP2Hash(point) {
195
- return point instanceof G2.Point ? point : G2.Point.hashToCurve(point);
132
+ function normP2Hash(point, htfOpts) {
133
+ return point instanceof G2.ProjectivePoint
134
+ ? point
135
+ : G2HashToCurve.hashToCurve(point, htfOpts);
196
136
  }
197
137
  // Multiplies generator by private key.
198
138
  // P = pk x G
199
139
  function getPublicKey(privateKey) {
200
- return G1.Point.fromPrivateKey(privateKey).toRawBytes(true);
140
+ return G1.ProjectivePoint.fromPrivateKey(privateKey).toRawBytes(true);
201
141
  }
202
- function sign(message, privateKey) {
203
- const msgPoint = normP2Hash(message);
142
+ function sign(message, privateKey, htfOpts) {
143
+ const msgPoint = normP2Hash(message, htfOpts);
204
144
  msgPoint.assertValidity();
205
- const sigPoint = msgPoint.multiply(normalizePrivKey(privateKey));
206
- if (message instanceof G2.Point)
145
+ const sigPoint = msgPoint.multiply(G1.normalizePrivateKey(privateKey));
146
+ if (message instanceof G2.ProjectivePoint)
207
147
  return sigPoint;
208
148
  return Signature.encode(sigPoint);
209
149
  }
210
150
  // Checks if pairing of public key & hash is equal to pairing of generator & signature.
211
151
  // e(P, H(m)) == e(G, S)
212
- function verify(signature, message, publicKey) {
152
+ function verify(signature, message, publicKey, htfOpts) {
213
153
  const P = normP1(publicKey);
214
- const Hm = normP2Hash(message);
215
- const G = G1.Point.BASE;
154
+ const Hm = normP2Hash(message, htfOpts);
155
+ const G = G1.ProjectivePoint.BASE;
216
156
  const S = normP2(signature);
217
157
  // Instead of doing 2 exponentiations, we use property of billinear maps
218
158
  // and do one exp after multiplying 2 points.
219
159
  const ePHm = pairing(P.negate(), Hm, false);
220
160
  const eGS = pairing(G, S, false);
221
161
  const exp = Fp12.finalExponentiate(Fp12.mul(eGS, ePHm));
222
- return Fp12.equals(exp, Fp12.ONE);
162
+ return Fp12.eql(exp, Fp12.ONE);
223
163
  }
224
164
  function aggregatePublicKeys(publicKeys) {
225
165
  if (!publicKeys.length)
226
166
  throw new Error('Expected non-empty array');
227
- const agg = publicKeys
228
- .map(normP1)
229
- .reduce((sum, p) => sum.add(G1.ProjectivePoint.fromAffine(p)), G1.ProjectivePoint.ZERO);
230
- const aggAffine = agg.toAffine();
231
- if (publicKeys[0] instanceof G1.Point) {
167
+ const agg = publicKeys.map(normP1).reduce((sum, p) => sum.add(p), G1.ProjectivePoint.ZERO);
168
+ const aggAffine = agg; //.toAffine();
169
+ if (publicKeys[0] instanceof G1.ProjectivePoint) {
232
170
  aggAffine.assertValidity();
233
171
  return aggAffine;
234
172
  }
@@ -238,11 +176,9 @@ export function bls(CURVE) {
238
176
  function aggregateSignatures(signatures) {
239
177
  if (!signatures.length)
240
178
  throw new Error('Expected non-empty array');
241
- const agg = signatures
242
- .map(normP2)
243
- .reduce((sum, s) => sum.add(G2.ProjectivePoint.fromAffine(s)), G2.ProjectivePoint.ZERO);
244
- const aggAffine = agg.toAffine();
245
- if (signatures[0] instanceof G2.Point) {
179
+ const agg = signatures.map(normP2).reduce((sum, s) => sum.add(s), G2.ProjectivePoint.ZERO);
180
+ const aggAffine = agg; //.toAffine();
181
+ if (signatures[0] instanceof G2.ProjectivePoint) {
246
182
  aggAffine.assertValidity();
247
183
  return aggAffine;
248
184
  }
@@ -250,33 +186,34 @@ export function bls(CURVE) {
250
186
  }
251
187
  // https://ethresear.ch/t/fast-verification-of-multiple-bls-signatures/5407
252
188
  // e(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))
253
- function verifyBatch(signature, messages, publicKeys) {
189
+ function verifyBatch(signature, messages, publicKeys, htfOpts) {
190
+ // @ts-ignore
191
+ // console.log('verifyBatch', bytesToHex(signature as any), messages, publicKeys.map(bytesToHex));
254
192
  if (!messages.length)
255
193
  throw new Error('Expected non-empty messages array');
256
194
  if (publicKeys.length !== messages.length)
257
195
  throw new Error('Pubkey count should equal msg count');
258
196
  const sig = normP2(signature);
259
- const nMessages = messages.map(normP2Hash);
197
+ const nMessages = messages.map((i) => normP2Hash(i, htfOpts));
260
198
  const nPublicKeys = publicKeys.map(normP1);
261
199
  try {
262
200
  const paired = [];
263
201
  for (const message of new Set(nMessages)) {
264
- const groupPublicKey = nMessages.reduce((groupPublicKey, subMessage, i) => subMessage === message ? groupPublicKey.add(nPublicKeys[i]) : groupPublicKey, G1.Point.ZERO);
202
+ const groupPublicKey = nMessages.reduce((groupPublicKey, subMessage, i) => subMessage === message ? groupPublicKey.add(nPublicKeys[i]) : groupPublicKey, G1.ProjectivePoint.ZERO);
265
203
  // const msg = message instanceof PointG2 ? message : await PointG2.hashToCurve(message);
266
204
  // Possible to batch pairing for same msg with different groupPublicKey here
267
205
  paired.push(pairing(groupPublicKey, message, false));
268
206
  }
269
- paired.push(pairing(G1.Point.BASE.negate(), sig, false));
207
+ paired.push(pairing(G1.ProjectivePoint.BASE.negate(), sig, false));
270
208
  const product = paired.reduce((a, b) => Fp12.mul(a, b), Fp12.ONE);
271
209
  const exp = Fp12.finalExponentiate(product);
272
- return Fp12.equals(exp, Fp12.ONE);
210
+ return Fp12.eql(exp, Fp12.ONE);
273
211
  }
274
212
  catch {
275
213
  return false;
276
214
  }
277
215
  }
278
- // Pre-compute points. Refer to README.
279
- G1.Point.BASE._setWindowSize(4);
216
+ G1.ProjectivePoint.BASE._setWindowSize(4);
280
217
  return {
281
218
  CURVE,
282
219
  Fr,
@@ -289,6 +226,7 @@ export function bls(CURVE) {
289
226
  Signature,
290
227
  millerLoop,
291
228
  calcPairingPrecomputes,
229
+ hashToCurve: { G1: G1HashToCurve, G2: G2HashToCurve },
292
230
  pairing,
293
231
  getPublicKey,
294
232
  sign,
@@ -1,8 +1,10 @@
1
1
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
2
  // Abelian group utilities
3
+ import { validateField, nLength } from './modular.js';
3
4
  const _0n = BigInt(0);
4
5
  const _1n = BigInt(1);
5
- // Not big, but pretty complex and it is easy to break stuff. To avoid too much copy paste
6
+ // Elliptic curve multiplication of Point by scalar. Complicated and fragile. Uses wNAF method.
7
+ // Windowed method is 10% faster, but takes 2x longer to generate & consumes 2x memory.
6
8
  export function wNAF(c, bits) {
7
9
  const constTimeNegate = (condition, item) => {
8
10
  const neg = item.negate();
@@ -104,5 +106,39 @@ export function wNAF(c, bits) {
104
106
  // which makes it less const-time: around 1 bigint multiply.
105
107
  return { p, f };
106
108
  },
109
+ wNAFCached(P, precomputesMap, n, transform) {
110
+ // @ts-ignore
111
+ const W = P._WINDOW_SIZE || 1;
112
+ // Calculate precomputes on a first run, reuse them after
113
+ let comp = precomputesMap.get(P);
114
+ if (!comp) {
115
+ comp = this.precomputeWindow(P, W);
116
+ if (W !== 1) {
117
+ precomputesMap.set(P, transform(comp));
118
+ }
119
+ }
120
+ return this.wNAF(W, comp, n);
121
+ },
107
122
  };
108
123
  }
124
+ export function validateAbsOpts(curve) {
125
+ validateField(curve.Fp);
126
+ for (const i of ['n', 'h']) {
127
+ const val = curve[i];
128
+ if (typeof val !== 'bigint')
129
+ throw new Error(`Invalid curve param ${i}=${val} (${typeof val})`);
130
+ }
131
+ if (!curve.Fp.isValid(curve.Gx))
132
+ throw new Error('Invalid generator X coordinate Fp element');
133
+ if (!curve.Fp.isValid(curve.Gy))
134
+ throw new Error('Invalid generator Y coordinate Fp element');
135
+ for (const i of ['nBitLength', 'nByteLength']) {
136
+ const val = curve[i];
137
+ if (val === undefined)
138
+ continue; // Optional
139
+ if (!Number.isSafeInteger(val))
140
+ throw new Error(`Invalid param ${i}=${val} (${typeof val})`);
141
+ }
142
+ // Set defaults
143
+ return Object.freeze({ ...nLength(curve.n, curve.nBitLength), ...curve });
144
+ }