@noble/curves 0.3.1 → 0.4.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 (70) hide show
  1. package/README.md +2 -1
  2. package/lib/bls.d.ts +79 -0
  3. package/lib/bls.js +304 -0
  4. package/lib/edwards.d.ts +10 -6
  5. package/lib/edwards.js +16 -11
  6. package/lib/esm/bls.js +300 -0
  7. package/lib/esm/edwards.js +17 -12
  8. package/lib/esm/group.js +2 -2
  9. package/lib/esm/hashToCurve.js +105 -0
  10. package/lib/esm/modular.js +131 -50
  11. package/lib/esm/utils.js +25 -19
  12. package/lib/esm/weierstrass.js +351 -272
  13. package/lib/group.js +2 -2
  14. package/lib/hashToCurve.d.ts +13 -0
  15. package/lib/hashToCurve.js +112 -0
  16. package/lib/modular.d.ts +37 -17
  17. package/lib/modular.js +138 -54
  18. package/lib/utils.d.ts +28 -10
  19. package/lib/utils.js +31 -22
  20. package/lib/weierstrass.d.ts +106 -69
  21. package/lib/weierstrass.js +352 -272
  22. package/package.json +23 -44
  23. package/lib/crypto.d.ts +0 -4
  24. package/lib/crypto.js +0 -8
  25. package/lib/cryptoBrowser.d.ts +0 -4
  26. package/lib/cryptoBrowser.js +0 -7
  27. package/lib/definitions/_shortw_utils.d.ts +0 -63
  28. package/lib/definitions/_shortw_utils.js +0 -18
  29. package/lib/definitions/bn.d.ts +0 -7
  30. package/lib/definitions/bn.js +0 -23
  31. package/lib/definitions/ed25519.d.ts +0 -49
  32. package/lib/definitions/ed25519.js +0 -308
  33. package/lib/definitions/ed448.d.ts +0 -3
  34. package/lib/definitions/ed448.js +0 -127
  35. package/lib/definitions/index.d.ts +0 -0
  36. package/lib/definitions/index.js +0 -2
  37. package/lib/definitions/jubjub.d.ts +0 -7
  38. package/lib/definitions/jubjub.js +0 -55
  39. package/lib/definitions/p192.d.ts +0 -112
  40. package/lib/definitions/p192.js +0 -23
  41. package/lib/definitions/p224.d.ts +0 -112
  42. package/lib/definitions/p224.js +0 -24
  43. package/lib/definitions/p256.d.ts +0 -112
  44. package/lib/definitions/p256.js +0 -23
  45. package/lib/definitions/p384.d.ts +0 -112
  46. package/lib/definitions/p384.js +0 -24
  47. package/lib/definitions/p521.d.ts +0 -113
  48. package/lib/definitions/p521.js +0 -36
  49. package/lib/definitions/pasta.d.ts +0 -2
  50. package/lib/definitions/pasta.js +0 -32
  51. package/lib/definitions/secp256k1.d.ts +0 -87
  52. package/lib/definitions/secp256k1.js +0 -245
  53. package/lib/definitions/stark.d.ts +0 -62
  54. package/lib/definitions/stark.js +0 -248
  55. package/lib/esm/crypto.js +0 -5
  56. package/lib/esm/cryptoBrowser.js +0 -4
  57. package/lib/esm/definitions/_shortw_utils.js +0 -13
  58. package/lib/esm/definitions/bn.js +0 -20
  59. package/lib/esm/definitions/ed25519.js +0 -304
  60. package/lib/esm/definitions/ed448.js +0 -124
  61. package/lib/esm/definitions/index.js +0 -2
  62. package/lib/esm/definitions/jubjub.js +0 -50
  63. package/lib/esm/definitions/p192.js +0 -20
  64. package/lib/esm/definitions/p224.js +0 -21
  65. package/lib/esm/definitions/p256.js +0 -20
  66. package/lib/esm/definitions/p384.js +0 -21
  67. package/lib/esm/definitions/p521.js +0 -33
  68. package/lib/esm/definitions/pasta.js +0 -29
  69. package/lib/esm/definitions/secp256k1.js +0 -241
  70. package/lib/esm/definitions/stark.js +0 -227
package/README.md CHANGED
@@ -45,9 +45,9 @@ The library does not have an entry point. It allows you to select specific primi
45
45
 
46
46
  ```ts
47
47
  import { weierstrass } from '@noble/curves/weierstrass'; // Short Weierstrass curve
48
- import { concatBytes, randomBytes } from '@noble/curves/utils';
49
48
  import { sha256 } from '@noble/hashes/sha256';
50
49
  import { hmac } from '@noble/hashes/hmac';
50
+ import { concatBytes, randomBytes } from '@noble/hashes/utils';
51
51
 
52
52
  const secp256k1 = weierstrass({
53
53
  a: 0n,
@@ -126,6 +126,7 @@ const ed25519 = twistedEdwards({
126
126
  Gx: 15112221349535400772501151409588531511454012693041857206046113283949847762202n,
127
127
  Gy: 46316835694926478169428394003475163141307993866256225615783033603165251855960n,
128
128
  hash: sha512,
129
+ randomBytes,
129
130
  adjustScalarBytes(bytes) { // optional
130
131
  bytes[0] &= 248;
131
132
  bytes[31] &= 127;
package/lib/bls.d.ts ADDED
@@ -0,0 +1,79 @@
1
+ import * as mod from './modular.js';
2
+ import * as utils from './utils.js';
3
+ import { Hex, PrivKey } from './utils.js';
4
+ import { htfOpts, stringToBytes, hash_to_field, expand_message_xmd } from './hashToCurve.js';
5
+ import { CurvePointsType, PointType, CurvePointsRes } from './weierstrass.js';
6
+ declare type Fp = bigint;
7
+ export declare type SignatureCoder<Fp2> = {
8
+ decode(hex: Hex): PointType<Fp2>;
9
+ encode(point: PointType<Fp2>): Uint8Array;
10
+ };
11
+ export declare type CurveType<Fp, Fp2, Fp6, Fp12> = {
12
+ r: bigint;
13
+ G1: Omit<CurvePointsType<Fp>, 'n'>;
14
+ G2: Omit<CurvePointsType<Fp2>, 'n'> & {
15
+ Signature: SignatureCoder<Fp2>;
16
+ };
17
+ x: bigint;
18
+ Fp: mod.Field<Fp>;
19
+ Fr: mod.Field<bigint>;
20
+ Fp2: mod.Field<Fp2> & {
21
+ reim: (num: Fp2) => {
22
+ re: bigint;
23
+ im: bigint;
24
+ };
25
+ multiplyByB: (num: Fp2) => Fp2;
26
+ frobeniusMap(num: Fp2, power: number): Fp2;
27
+ };
28
+ Fp6: mod.Field<Fp6>;
29
+ Fp12: mod.Field<Fp12> & {
30
+ frobeniusMap(num: Fp12, power: number): Fp12;
31
+ multiplyBy014(num: Fp12, o0: Fp2, o1: Fp2, o4: Fp2): Fp12;
32
+ conjugate(num: Fp12): Fp12;
33
+ finalExponentiate(num: Fp12): Fp12;
34
+ };
35
+ htfDefaults: htfOpts;
36
+ hash: utils.CHash;
37
+ randomBytes: (bytesLength?: number) => Uint8Array;
38
+ };
39
+ export declare type CurveFn<Fp, Fp2, Fp6, Fp12> = {
40
+ CURVE: CurveType<Fp, Fp2, Fp6, Fp12>;
41
+ Fr: mod.Field<bigint>;
42
+ Fp: mod.Field<Fp>;
43
+ Fp2: mod.Field<Fp2>;
44
+ Fp6: mod.Field<Fp6>;
45
+ Fp12: mod.Field<Fp12>;
46
+ G1: CurvePointsRes<Fp>;
47
+ G2: CurvePointsRes<Fp2>;
48
+ Signature: SignatureCoder<Fp2>;
49
+ millerLoop: (ell: [Fp2, Fp2, Fp2][], g1: [Fp, Fp]) => Fp12;
50
+ calcPairingPrecomputes: (x: Fp2, y: Fp2) => [Fp2, Fp2, Fp2][];
51
+ pairing: (P: PointType<Fp>, Q: PointType<Fp2>, withFinalExponent?: boolean) => Fp12;
52
+ getPublicKey: (privateKey: PrivKey) => Uint8Array;
53
+ sign: {
54
+ (message: Hex, privateKey: PrivKey): Uint8Array;
55
+ (message: PointType<Fp2>, privateKey: PrivKey): PointType<Fp2>;
56
+ };
57
+ verify: (signature: Hex | PointType<Fp2>, message: Hex | PointType<Fp2>, publicKey: Hex | PointType<Fp>) => boolean;
58
+ aggregatePublicKeys: {
59
+ (publicKeys: Hex[]): Uint8Array;
60
+ (publicKeys: PointType<Fp>[]): PointType<Fp>;
61
+ };
62
+ aggregateSignatures: {
63
+ (signatures: Hex[]): Uint8Array;
64
+ (signatures: PointType<Fp2>[]): PointType<Fp2>;
65
+ };
66
+ verifyBatch: (signature: Hex | PointType<Fp2>, messages: (Hex | PointType<Fp2>)[], publicKeys: (Hex | PointType<Fp>)[]) => boolean;
67
+ utils: {
68
+ bytesToHex: typeof utils.bytesToHex;
69
+ hexToBytes: typeof utils.hexToBytes;
70
+ stringToBytes: typeof stringToBytes;
71
+ hashToField: typeof hash_to_field;
72
+ expandMessageXMD: typeof expand_message_xmd;
73
+ mod: typeof mod.mod;
74
+ getDSTLabel: () => string;
75
+ setDSTLabel(newLabel: string): void;
76
+ };
77
+ };
78
+ export declare function bls<Fp2, Fp6, Fp12>(CURVE: CurveType<Fp, Fp2, Fp6, Fp12>): CurveFn<Fp, Fp2, Fp6, Fp12>;
79
+ export {};
package/lib/bls.js ADDED
@@ -0,0 +1,304 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.bls = void 0;
4
+ // Barreto-Lynn-Scott Curves. A family of pairing friendly curves, with embedding degree = 12 or 24
5
+ // NOTE: only 12 supported for now
6
+ // Constructed from pair of weierstrass curves, based pairing logic
7
+ const mod = require("./modular.js");
8
+ const utils_js_1 = require("./utils.js");
9
+ // Types
10
+ const utils_js_2 = require("./utils.js");
11
+ const hashToCurve_js_1 = require("./hashToCurve.js");
12
+ const weierstrass_js_1 = require("./weierstrass.js");
13
+ function bls(CURVE) {
14
+ // Fields looks pretty specific for curve, so for now we need to pass them with options
15
+ const Fp = CURVE.Fp;
16
+ const Fr = CURVE.Fr;
17
+ const Fp2 = CURVE.Fp2;
18
+ const Fp6 = CURVE.Fp6;
19
+ const Fp12 = CURVE.Fp12;
20
+ const BLS_X_LEN = (0, utils_js_1.bitLen)(CURVE.x);
21
+ // Pre-compute coefficients for sparse multiplication
22
+ // Point addition and point double calculations is reused for coefficients
23
+ function calcPairingPrecomputes(x, y) {
24
+ // prettier-ignore
25
+ const Qx = x, Qy = y, Qz = Fp2.ONE;
26
+ // prettier-ignore
27
+ let Rx = Qx, Ry = Qy, Rz = Qz;
28
+ let ell_coeff = [];
29
+ for (let i = BLS_X_LEN - 2; i >= 0; i--) {
30
+ // Double
31
+ let t0 = Fp2.square(Ry); // Ry²
32
+ let t1 = Fp2.square(Rz); // Rz²
33
+ let t2 = Fp2.multiplyByB(Fp2.multiply(t1, 3n)); // 3 * T1 * B
34
+ let t3 = Fp2.multiply(t2, 3n); // 3 * T2
35
+ let t4 = Fp2.subtract(Fp2.subtract(Fp2.square(Fp2.add(Ry, Rz)), t1), t0); // (Ry + Rz)² - T1 - T0
36
+ ell_coeff.push([
37
+ Fp2.subtract(t2, t0),
38
+ Fp2.multiply(Fp2.square(Rx), 3n),
39
+ Fp2.negate(t4), // -T4
40
+ ]);
41
+ Rx = Fp2.div(Fp2.multiply(Fp2.multiply(Fp2.subtract(t0, t3), Rx), Ry), 2n); // ((T0 - T3) * Rx * Ry) / 2
42
+ Ry = Fp2.subtract(Fp2.square(Fp2.div(Fp2.add(t0, t3), 2n)), Fp2.multiply(Fp2.square(t2), 3n)); // ((T0 + T3) / 2)² - 3 * T2²
43
+ Rz = Fp2.multiply(t0, t4); // T0 * T4
44
+ if ((0, utils_js_1.bitGet)(CURVE.x, i)) {
45
+ // Addition
46
+ let t0 = Fp2.subtract(Ry, Fp2.multiply(Qy, Rz)); // Ry - Qy * Rz
47
+ let t1 = Fp2.subtract(Rx, Fp2.multiply(Qx, Rz)); // Rx - Qx * Rz
48
+ ell_coeff.push([
49
+ Fp2.subtract(Fp2.multiply(t0, Qx), Fp2.multiply(t1, Qy)),
50
+ Fp2.negate(t0),
51
+ t1, // T1
52
+ ]);
53
+ let t2 = Fp2.square(t1); // T1²
54
+ let t3 = Fp2.multiply(t2, t1); // T2 * T1
55
+ let t4 = Fp2.multiply(t2, Rx); // T2 * Rx
56
+ let t5 = Fp2.add(Fp2.subtract(t3, Fp2.multiply(t4, 2n)), Fp2.multiply(Fp2.square(t0), Rz)); // T3 - 2 * T4 + T0² * Rz
57
+ Rx = Fp2.multiply(t1, t5); // T1 * T5
58
+ Ry = Fp2.subtract(Fp2.multiply(Fp2.subtract(t4, t5), t0), Fp2.multiply(t3, Ry)); // (T4 - T5) * T0 - T3 * Ry
59
+ Rz = Fp2.multiply(Rz, t3); // Rz * T3
60
+ }
61
+ }
62
+ return ell_coeff;
63
+ }
64
+ function millerLoop(ell, g1) {
65
+ const Px = g1[0];
66
+ const Py = g1[1];
67
+ let f12 = Fp12.ONE;
68
+ for (let j = 0, i = BLS_X_LEN - 2; i >= 0; i--, j++) {
69
+ const E = ell[j];
70
+ f12 = Fp12.multiplyBy014(f12, E[0], Fp2.multiply(E[1], Px), Fp2.multiply(E[2], Py));
71
+ if ((0, utils_js_1.bitGet)(CURVE.x, i)) {
72
+ j += 1;
73
+ const F = ell[j];
74
+ f12 = Fp12.multiplyBy014(f12, F[0], Fp2.multiply(F[1], Px), Fp2.multiply(F[2], Py));
75
+ }
76
+ if (i !== 0)
77
+ f12 = Fp12.square(f12);
78
+ }
79
+ return Fp12.conjugate(f12);
80
+ }
81
+ // bls12-381 is a construction of two curves:
82
+ // 1. Fp: (x, y)
83
+ // 2. Fp₂: ((x₁, x₂+i), (y₁, y₂+i)) - (complex numbers)
84
+ //
85
+ // Bilinear Pairing (ate pairing) is used to combine both elements into a paired one:
86
+ // Fp₁₂ = e(Fp, Fp2)
87
+ // where Fp₁₂ = 12-degree polynomial
88
+ // Pairing is used to verify signatures.
89
+ //
90
+ // We are using Fp for private keys (shorter) and Fp2 for signatures (longer).
91
+ // Some projects may prefer to swap this relation, it is not supported for now.
92
+ const htfDefaults = { ...CURVE.htfDefaults };
93
+ function isWithinCurveOrder(num) {
94
+ return 0 < num && num < CURVE.r;
95
+ }
96
+ const utils = {
97
+ hexToBytes: utils_js_2.hexToBytes,
98
+ bytesToHex: utils_js_2.bytesToHex,
99
+ mod: mod.mod,
100
+ stringToBytes: hashToCurve_js_1.stringToBytes,
101
+ // TODO: do we need to export it here?
102
+ hashToField: (msg, count, options = {}) => (0, hashToCurve_js_1.hash_to_field)(msg, count, { ...CURVE.htfDefaults, ...options }),
103
+ expandMessageXMD: (msg, DST, lenInBytes, H = CURVE.hash) => (0, hashToCurve_js_1.expand_message_xmd)(msg, DST, lenInBytes, H),
104
+ /**
105
+ * Can take 40 or more bytes of uniform input e.g. from CSPRNG or KDF
106
+ * and convert them into private key, with the modulo bias being negligible.
107
+ * As per FIPS 186 B.1.1.
108
+ * https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
109
+ * @param hash hash output from sha512, or a similar function
110
+ * @returns valid private key
111
+ */
112
+ hashToPrivateKey: (hash) => {
113
+ hash = (0, utils_js_1.ensureBytes)(hash);
114
+ if (hash.length < 40 || hash.length > 1024)
115
+ throw new Error('Expected 40-1024 bytes of private key as per FIPS 186');
116
+ // hashToPrivateScalar(hash, CURVE.r)
117
+ // NOTE: doesn't add +/-1
118
+ const num = mod.mod((0, utils_js_1.bytesToNumberBE)(hash), CURVE.r);
119
+ // This should never happen
120
+ if (num === 0n || num === 1n)
121
+ throw new Error('Invalid private key');
122
+ return (0, utils_js_1.numberToBytesBE)(num, 32);
123
+ },
124
+ randomBytes: (bytesLength = 32) => CURVE.randomBytes(bytesLength),
125
+ // NIST SP 800-56A rev 3, section 5.6.1.2.2
126
+ // https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to-modulo-bias-and-how-to-avoid-it/
127
+ randomPrivateKey: () => utils.hashToPrivateKey(utils.randomBytes(40)),
128
+ getDSTLabel: () => htfDefaults.DST,
129
+ setDSTLabel(newLabel) {
130
+ // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-3.1
131
+ if (typeof newLabel !== 'string' || newLabel.length > 2048 || newLabel.length === 0) {
132
+ throw new TypeError('Invalid DST');
133
+ }
134
+ htfDefaults.DST = newLabel;
135
+ },
136
+ };
137
+ function normalizePrivKey(key) {
138
+ let int;
139
+ if (key instanceof Uint8Array && key.length === 32)
140
+ int = (0, utils_js_1.bytesToNumberBE)(key);
141
+ else if (typeof key === 'string' && key.length === 64)
142
+ int = BigInt(`0x${key}`);
143
+ else if (typeof key === 'number' && key > 0 && Number.isSafeInteger(key))
144
+ int = BigInt(key);
145
+ else if (typeof key === 'bigint' && key > 0n)
146
+ int = key;
147
+ else
148
+ throw new TypeError('Expected valid private key');
149
+ int = mod.mod(int, CURVE.r);
150
+ if (!isWithinCurveOrder(int))
151
+ throw new Error('Private key must be 0 < key < CURVE.r');
152
+ return int;
153
+ }
154
+ // Point on G1 curve: (x, y)
155
+ const G1 = (0, weierstrass_js_1.weierstrassPoints)({
156
+ n: Fr.ORDER,
157
+ ...CURVE.G1,
158
+ });
159
+ function pairingPrecomputes(point) {
160
+ const p = point;
161
+ if (p._PPRECOMPUTES)
162
+ return p._PPRECOMPUTES;
163
+ p._PPRECOMPUTES = calcPairingPrecomputes(p.x, p.y);
164
+ return p._PPRECOMPUTES;
165
+ }
166
+ function clearPairingPrecomputes(point) {
167
+ const p = point;
168
+ p._PPRECOMPUTES = undefined;
169
+ }
170
+ clearPairingPrecomputes;
171
+ function millerLoopG1(Q, P) {
172
+ return millerLoop(pairingPrecomputes(P), [Q.x, Q.y]);
173
+ }
174
+ // Point on G2 curve (complex numbers): (x₁, x₂+i), (y₁, y₂+i)
175
+ const G2 = (0, weierstrass_js_1.weierstrassPoints)({
176
+ n: Fr.ORDER,
177
+ ...CURVE.G2,
178
+ });
179
+ const { Signature } = CURVE.G2;
180
+ // Calculates bilinear pairing
181
+ function pairing(P, Q, withFinalExponent = true) {
182
+ if (P.equals(G1.Point.ZERO) || Q.equals(G2.Point.ZERO))
183
+ throw new Error('No pairings at point of Infinity');
184
+ P.assertValidity();
185
+ Q.assertValidity();
186
+ // Performance: 9ms for millerLoop and ~14ms for exp.
187
+ const looped = millerLoopG1(P, Q);
188
+ return withFinalExponent ? Fp12.finalExponentiate(looped) : looped;
189
+ }
190
+ function normP1(point) {
191
+ return point instanceof G1.Point ? point : G1.Point.fromHex(point);
192
+ }
193
+ function normP2(point) {
194
+ return point instanceof G2.Point ? point : Signature.decode(point);
195
+ }
196
+ function normP2Hash(point) {
197
+ return point instanceof G2.Point ? point : G2.Point.hashToCurve(point);
198
+ }
199
+ // Multiplies generator by private key.
200
+ // P = pk x G
201
+ function getPublicKey(privateKey) {
202
+ return G1.Point.fromPrivateKey(privateKey).toRawBytes(true);
203
+ }
204
+ function sign(message, privateKey) {
205
+ const msgPoint = normP2Hash(message);
206
+ msgPoint.assertValidity();
207
+ const sigPoint = msgPoint.multiply(normalizePrivKey(privateKey));
208
+ if (message instanceof G2.Point)
209
+ return sigPoint;
210
+ return Signature.encode(sigPoint);
211
+ }
212
+ // Checks if pairing of public key & hash is equal to pairing of generator & signature.
213
+ // e(P, H(m)) == e(G, S)
214
+ function verify(signature, message, publicKey) {
215
+ const P = normP1(publicKey);
216
+ const Hm = normP2Hash(message);
217
+ const G = G1.Point.BASE;
218
+ const S = normP2(signature);
219
+ // Instead of doing 2 exponentiations, we use property of billinear maps
220
+ // and do one exp after multiplying 2 points.
221
+ const ePHm = pairing(P.negate(), Hm, false);
222
+ const eGS = pairing(G, S, false);
223
+ const exp = Fp12.finalExponentiate(Fp12.multiply(eGS, ePHm));
224
+ return Fp12.equals(exp, Fp12.ONE);
225
+ }
226
+ function aggregatePublicKeys(publicKeys) {
227
+ if (!publicKeys.length)
228
+ throw new Error('Expected non-empty array');
229
+ const agg = publicKeys
230
+ .map(normP1)
231
+ .reduce((sum, p) => sum.add(G1.JacobianPoint.fromAffine(p)), G1.JacobianPoint.ZERO);
232
+ const aggAffine = agg.toAffine();
233
+ if (publicKeys[0] instanceof G1.Point) {
234
+ aggAffine.assertValidity();
235
+ return aggAffine;
236
+ }
237
+ // toRawBytes ensures point validity
238
+ return aggAffine.toRawBytes(true);
239
+ }
240
+ function aggregateSignatures(signatures) {
241
+ if (!signatures.length)
242
+ throw new Error('Expected non-empty array');
243
+ const agg = signatures
244
+ .map(normP2)
245
+ .reduce((sum, s) => sum.add(G2.JacobianPoint.fromAffine(s)), G2.JacobianPoint.ZERO);
246
+ const aggAffine = agg.toAffine();
247
+ if (signatures[0] instanceof G2.Point) {
248
+ aggAffine.assertValidity();
249
+ return aggAffine;
250
+ }
251
+ return Signature.encode(aggAffine);
252
+ }
253
+ // https://ethresear.ch/t/fast-verification-of-multiple-bls-signatures/5407
254
+ // e(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))
255
+ function verifyBatch(signature, messages, publicKeys) {
256
+ if (!messages.length)
257
+ throw new Error('Expected non-empty messages array');
258
+ if (publicKeys.length !== messages.length)
259
+ throw new Error('Pubkey count should equal msg count');
260
+ const sig = normP2(signature);
261
+ const nMessages = messages.map(normP2Hash);
262
+ const nPublicKeys = publicKeys.map(normP1);
263
+ try {
264
+ const paired = [];
265
+ for (const message of new Set(nMessages)) {
266
+ const groupPublicKey = nMessages.reduce((groupPublicKey, subMessage, i) => subMessage === message ? groupPublicKey.add(nPublicKeys[i]) : groupPublicKey, G1.Point.ZERO);
267
+ // const msg = message instanceof PointG2 ? message : await PointG2.hashToCurve(message);
268
+ // Possible to batch pairing for same msg with different groupPublicKey here
269
+ paired.push(pairing(groupPublicKey, message, false));
270
+ }
271
+ paired.push(pairing(G1.Point.BASE.negate(), sig, false));
272
+ const product = paired.reduce((a, b) => Fp12.multiply(a, b), Fp12.ONE);
273
+ const exp = Fp12.finalExponentiate(product);
274
+ return Fp12.equals(exp, Fp12.ONE);
275
+ }
276
+ catch {
277
+ return false;
278
+ }
279
+ }
280
+ // Pre-compute points. Refer to README.
281
+ G1.Point.BASE._setWindowSize(4);
282
+ return {
283
+ CURVE,
284
+ Fr,
285
+ Fp,
286
+ Fp2,
287
+ Fp6,
288
+ Fp12,
289
+ G1,
290
+ G2,
291
+ Signature,
292
+ millerLoop,
293
+ calcPairingPrecomputes,
294
+ pairing,
295
+ getPublicKey,
296
+ sign,
297
+ verify,
298
+ aggregatePublicKeys,
299
+ aggregateSignatures,
300
+ verifyBatch,
301
+ utils,
302
+ };
303
+ }
304
+ exports.bls = bls;
package/lib/edwards.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
2
+ import * as mod from './modular.js';
2
3
  import { BasicCurve, Hex, PrivKey } from './utils.js';
3
4
  import { Group, GroupConstructor } from './group.js';
4
5
  export declare type CHash = {
@@ -7,11 +8,11 @@ export declare type CHash = {
7
8
  outputLen: number;
8
9
  create(): any;
9
10
  };
10
- export declare type CurveType = BasicCurve & {
11
+ export declare type CurveType = BasicCurve<bigint> & {
11
12
  a: bigint;
12
13
  d: bigint;
13
14
  hash: CHash;
14
- randomBytes?: (bytesLength?: number) => Uint8Array;
15
+ randomBytes: (bytesLength?: number) => Uint8Array;
15
16
  adjustScalarBytes?: (bytes: Uint8Array) => Uint8Array;
16
17
  domain?: (data: Uint8Array, ctx: Uint8Array, phflag: boolean) => Uint8Array;
17
18
  uvRatio?: (u: bigint, v: bigint) => {
@@ -23,15 +24,18 @@ export declare type CurveType = BasicCurve & {
23
24
  declare function validateOpts(curve: CurveType): Readonly<{
24
25
  readonly nBitLength: number;
25
26
  readonly nByteLength: number;
26
- readonly P: bigint;
27
+ readonly Fp: mod.Field<bigint>;
27
28
  readonly n: bigint;
28
29
  readonly h: bigint;
30
+ readonly hEff?: bigint | undefined;
29
31
  readonly Gx: bigint;
30
32
  readonly Gy: bigint;
33
+ readonly wrapPrivateKey?: boolean | undefined;
34
+ readonly allowInfinityPoint?: boolean | undefined;
31
35
  readonly a: bigint;
32
36
  readonly d: bigint;
33
37
  readonly hash: CHash;
34
- randomBytes: (bytesLength?: number | undefined) => Uint8Array;
38
+ readonly randomBytes: (bytesLength?: number | undefined) => Uint8Array;
35
39
  readonly adjustScalarBytes?: ((bytes: Uint8Array) => Uint8Array) | undefined;
36
40
  readonly domain?: ((data: Uint8Array, ctx: Uint8Array, phflag: boolean) => Uint8Array) | undefined;
37
41
  readonly uvRatio?: ((u: bigint, v: bigint) => {
@@ -92,8 +96,8 @@ export declare type CurveFn = {
92
96
  ExtendedPoint: ExtendedPointConstructor;
93
97
  Signature: SignatureConstructor;
94
98
  utils: {
95
- mod: (a: bigint, b?: bigint) => bigint;
96
- invert: (number: bigint, modulo?: bigint) => bigint;
99
+ mod: (a: bigint) => bigint;
100
+ invert: (number: bigint) => bigint;
97
101
  randomPrivateKey: () => Uint8Array;
98
102
  getExtendedPublicKey: (key: PrivKey) => {
99
103
  head: Uint8Array;
package/lib/edwards.js CHANGED
@@ -27,32 +27,37 @@ function validateOpts(curve) {
27
27
  if (typeof opts[i] !== 'bigint')
28
28
  throw new Error(`Invalid curve param ${i}=${opts[i]} (${typeof opts[i]})`);
29
29
  }
30
- for (const fn of ['adjustScalarBytes', 'domain', 'randomBytes', 'uvRatio']) {
30
+ for (const fn of ['randomBytes']) {
31
+ if (typeof opts[fn] !== 'function')
32
+ throw new Error(`Invalid ${fn} function`);
33
+ }
34
+ for (const fn of ['adjustScalarBytes', 'domain', 'uvRatio']) {
31
35
  if (opts[fn] === undefined)
32
36
  continue; // Optional
33
37
  if (typeof opts[fn] !== 'function')
34
38
  throw new Error(`Invalid ${fn} function`);
35
39
  }
36
40
  // Set defaults
37
- return Object.freeze({ randomBytes: utils_js_1.randomBytes, ...opts });
41
+ return Object.freeze({ ...opts });
38
42
  }
39
43
  // NOTE: it is not generic twisted curve for now, but ed25519/ed448 generic implementation
40
44
  function twistedEdwards(curveDef) {
41
45
  const CURVE = validateOpts(curveDef);
46
+ const Fp = CURVE.Fp;
42
47
  const CURVE_ORDER = CURVE.n;
43
- const fieldLen = CURVE.nByteLength; // 32 (length of one field element)
48
+ const fieldLen = Fp.BYTES; // 32 (length of one field element)
44
49
  if (fieldLen > 2048)
45
50
  throw new Error('Field lengths over 2048 are not supported');
46
51
  const groupLen = CURVE.nByteLength;
47
52
  // (2n ** 256n).toString(16);
48
53
  const maxGroupElement = _2n ** BigInt(groupLen * 8); // previous POW_2_256
49
54
  // Function overrides
50
- const { P, randomBytes } = CURVE;
51
- const modP = (a) => mod.mod(a, P);
55
+ const { randomBytes } = CURVE;
56
+ const modP = Fp.create;
52
57
  // sqrt(u/v)
53
58
  function _uvRatio(u, v) {
54
59
  try {
55
- const value = mod.sqrt(u * mod.invert(v, P), P);
60
+ const value = Fp.sqrt(u * Fp.invert(v));
56
61
  return { isValid: true, value };
57
62
  }
58
63
  catch (e) {
@@ -92,7 +97,7 @@ function twistedEdwards(curveDef) {
92
97
  // invert on all of them. invert is very slow operation,
93
98
  // so this improves performance massively.
94
99
  static toAffineBatch(points) {
95
- const toInv = mod.invertBatch(points.map((p) => p.z), P);
100
+ const toInv = Fp.invertBatch(points.map((p) => p.z));
96
101
  return points.map((p, i) => p.toAffine(toInv[i]));
97
102
  }
98
103
  static normalizeZ(points) {
@@ -232,7 +237,7 @@ function twistedEdwards(curveDef) {
232
237
  const { x, y, z } = this;
233
238
  const is0 = this.equals(ExtendedPoint.ZERO);
234
239
  if (invZ == null)
235
- invZ = is0 ? _8n : mod.invert(z, P); // 8 was chosen arbitrarily
240
+ invZ = is0 ? _8n : Fp.invert(z); // 8 was chosen arbitrarily
236
241
  const ax = modP(x * invZ);
237
242
  const ay = modP(y * invZ);
238
243
  const zz = modP(z * invZ);
@@ -268,7 +273,7 @@ function twistedEdwards(curveDef) {
268
273
  // Converts hash string or Uint8Array to Point.
269
274
  // Uses algo from RFC8032 5.1.3.
270
275
  static fromHex(hex, strict = true) {
271
- const { d, P, a } = CURVE;
276
+ const { d, a } = CURVE;
272
277
  hex = (0, utils_js_1.ensureBytes)(hex, fieldLen);
273
278
  // 1. First, interpret the string as an integer in little-endian
274
279
  // representation. Bit 255 of this number is the least significant
@@ -279,7 +284,7 @@ function twistedEdwards(curveDef) {
279
284
  const lastByte = hex[fieldLen - 1];
280
285
  normed[fieldLen - 1] = lastByte & ~0x80;
281
286
  const y = (0, utils_js_1.bytesToNumberLE)(normed);
282
- if (strict && y >= P)
287
+ if (strict && y >= Fp.ORDER)
283
288
  throw new Error('Expected 0 < hex < P');
284
289
  if (!strict && y >= maxGroupElement)
285
290
  throw new Error('Expected 0 < hex < 2**256');
@@ -513,7 +518,7 @@ function twistedEdwards(curveDef) {
513
518
  const utils = {
514
519
  getExtendedPublicKey,
515
520
  mod: modP,
516
- invert: (a, m = CURVE.P) => mod.invert(a, m),
521
+ invert: Fp.invert,
517
522
  /**
518
523
  * Not needed for ed25519 private keys. Needed if you use scalars directly (rare).
519
524
  */