@leofcoin/chain 1.10.9 → 1.10.11

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 (44) hide show
  1. package/exports/beacon-envelope.js +68 -0
  2. package/exports/beacon-epoch.js +117 -0
  3. package/exports/beacon-lifecycle.js +155 -0
  4. package/exports/beacon-round.js +77 -0
  5. package/exports/beacon-wire.js +98 -0
  6. package/exports/beacon.js +141 -0
  7. package/exports/browser/beacon-envelope.js +163 -0
  8. package/exports/browser/beacon-epoch.js +116 -0
  9. package/exports/browser/beacon-lifecycle.js +154 -0
  10. package/exports/browser/beacon-round.js +76 -0
  11. package/exports/browser/beacon-wire.js +99 -0
  12. package/exports/browser/beacon.js +1706 -0
  13. package/exports/browser/{browser-D-r0O9Qn-BZDYY6cg.js → browser-CWeoyGUw-BabtHowB.js} +4 -2
  14. package/exports/browser/{browser-_hiyXwPp-DYI1tyUr.js → browser-DvU1xNFS-sdlKNCJc.js} +4 -2
  15. package/exports/browser/chain.js +174 -5008
  16. package/exports/browser/{client-BVhUamQG-D-D1e_x8.js → client-B-jyclOB-CsNYfj4Z.js} +6 -4
  17. package/exports/browser/constants-Cv0p224A.js +130 -0
  18. package/exports/browser/hkdf-DhdhLAAv.js +147 -0
  19. package/exports/browser/{index-BD0Anx7_-Dg4_tCeN.js → index-Bxr5Iztg-C6xBk0rK.js} +4 -2
  20. package/exports/browser/index-CvKt4UDE.js +464 -0
  21. package/exports/browser/index-D7FUx7Dd.js +4996 -0
  22. package/exports/browser/{messages-UKnuelZ7-DJT-98q-.js → messages-FMRAS8QX-CvlZBzy5.js} +4 -2
  23. package/exports/browser/{node-browser-DlzZ5CP_.js → node-browser-xlqSBOaN.js} +12 -5
  24. package/exports/browser/node-browser.js +4 -2
  25. package/exports/browser/{constants-gMYZLHKp.js → proposal.proto-BcUgd885.js} +61 -620
  26. package/exports/browser/quorum-S_qdgiAY.js +8 -0
  27. package/exports/browser/weierstrass-C-jX_jly.js +2156 -0
  28. package/exports/browser/workers/block-worker.js +1 -1
  29. package/exports/browser/workers/machine-worker.js +7142 -72
  30. package/exports/browser/workers/{worker-CZqErLI7-BxofVJAn.js → worker-DMCj1e6z-CTYVa2yX.js} +30 -1
  31. package/exports/chain.js +158 -75
  32. package/exports/{constants-D6gWzJZg.js → constants-CMYKv-Rt.js} +1 -1
  33. package/exports/node.js +1 -1
  34. package/exports/quorum-S_qdgiAY.js +8 -0
  35. package/exports/workers/block-worker.js +1 -1
  36. package/exports/workers/machine-worker.js +7142 -72
  37. package/exports/workers/{worker-CZqErLI7-BxofVJAn.js → worker-DMCj1e6z-CTYVa2yX.js} +30 -1
  38. package/package.json +29 -2
  39. package/types/beacon-envelope.d.ts +27 -0
  40. package/types/beacon-epoch.d.ts +28 -0
  41. package/types/beacon-lifecycle.d.ts +40 -0
  42. package/types/beacon-round.d.ts +18 -0
  43. package/types/beacon-wire.d.ts +31 -0
  44. package/types/beacon.d.ts +24 -0
@@ -0,0 +1,1706 @@
1
+ import { v as validateObject, m as mod, u as utf8ToBytes, a as concatBytes, d as bytesToNumberBE, f as bitLen, g as weierstrassPoints, i as getMinHashLength, j as mapHashToField, k as bitGet, l as ensureBytes, F as Field, s as sha256, o as FpInvertBatch, q as FpPow, x as bitMask, y as mapToCurveSimpleSWU, z as bitSet, r as randomBytes, A as bytesToHex, B as numberToBytesBE } from './weierstrass-C-jX_jly.js';
2
+
3
+ function validateDST(dst) {
4
+ if (dst instanceof Uint8Array)
5
+ return dst;
6
+ if (typeof dst === 'string')
7
+ return utf8ToBytes(dst);
8
+ throw new Error('DST must be Uint8Array or string');
9
+ }
10
+ // Octet Stream to Integer. "spec" implementation of os2ip is 2.5x slower vs bytesToNumberBE.
11
+ const os2ip = bytesToNumberBE;
12
+ // Integer to Octet Stream (numberToBytesBE)
13
+ function i2osp(value, length) {
14
+ if (value < 0 || value >= 1 << (8 * length)) {
15
+ throw new Error(`bad I2OSP call: value=${value} length=${length}`);
16
+ }
17
+ const res = Array.from({ length }).fill(0);
18
+ for (let i = length - 1; i >= 0; i--) {
19
+ res[i] = value & 0xff;
20
+ value >>>= 8;
21
+ }
22
+ return new Uint8Array(res);
23
+ }
24
+ function strxor(a, b) {
25
+ const arr = new Uint8Array(a.length);
26
+ for (let i = 0; i < a.length; i++) {
27
+ arr[i] = a[i] ^ b[i];
28
+ }
29
+ return arr;
30
+ }
31
+ function isBytes(item) {
32
+ if (!(item instanceof Uint8Array))
33
+ throw new Error('Uint8Array expected');
34
+ }
35
+ function isNum(item) {
36
+ if (!Number.isSafeInteger(item))
37
+ throw new Error('number expected');
38
+ }
39
+ // Produces a uniformly random byte string using a cryptographic hash function H that outputs b bits
40
+ // https://www.rfc-editor.org/rfc/rfc9380#section-5.3.1
41
+ function expand_message_xmd(msg, DST, lenInBytes, H) {
42
+ isBytes(msg);
43
+ isBytes(DST);
44
+ isNum(lenInBytes);
45
+ // https://www.rfc-editor.org/rfc/rfc9380#section-5.3.3
46
+ if (DST.length > 255)
47
+ DST = H(concatBytes(utf8ToBytes('H2C-OVERSIZE-DST-'), DST));
48
+ const { outputLen: b_in_bytes, blockLen: r_in_bytes } = H;
49
+ const ell = Math.ceil(lenInBytes / b_in_bytes);
50
+ if (ell > 255)
51
+ throw new Error('Invalid xmd length');
52
+ const DST_prime = concatBytes(DST, i2osp(DST.length, 1));
53
+ const Z_pad = i2osp(0, r_in_bytes);
54
+ const l_i_b_str = i2osp(lenInBytes, 2); // len_in_bytes_str
55
+ const b = new Array(ell);
56
+ const b_0 = H(concatBytes(Z_pad, msg, l_i_b_str, i2osp(0, 1), DST_prime));
57
+ b[0] = H(concatBytes(b_0, i2osp(1, 1), DST_prime));
58
+ for (let i = 1; i <= ell; i++) {
59
+ const args = [strxor(b_0, b[i - 1]), i2osp(i + 1, 1), DST_prime];
60
+ b[i] = H(concatBytes(...args));
61
+ }
62
+ const pseudo_random_bytes = concatBytes(...b);
63
+ return pseudo_random_bytes.slice(0, lenInBytes);
64
+ }
65
+ // Produces a uniformly random byte string using an extendable-output function (XOF) H.
66
+ // 1. The collision resistance of H MUST be at least k bits.
67
+ // 2. H MUST be an XOF that has been proved indifferentiable from
68
+ // a random oracle under a reasonable cryptographic assumption.
69
+ // https://www.rfc-editor.org/rfc/rfc9380#section-5.3.2
70
+ function expand_message_xof(msg, DST, lenInBytes, k, H) {
71
+ isBytes(msg);
72
+ isBytes(DST);
73
+ isNum(lenInBytes);
74
+ // https://www.rfc-editor.org/rfc/rfc9380#section-5.3.3
75
+ // DST = H('H2C-OVERSIZE-DST-' || a_very_long_DST, Math.ceil((lenInBytes * k) / 8));
76
+ if (DST.length > 255) {
77
+ const dkLen = Math.ceil((2 * k) / 8);
78
+ DST = H.create({ dkLen }).update(utf8ToBytes('H2C-OVERSIZE-DST-')).update(DST).digest();
79
+ }
80
+ if (lenInBytes > 65535 || DST.length > 255)
81
+ throw new Error('expand_message_xof: invalid lenInBytes');
82
+ return (H.create({ dkLen: lenInBytes })
83
+ .update(msg)
84
+ .update(i2osp(lenInBytes, 2))
85
+ // 2. DST_prime = DST || I2OSP(len(DST), 1)
86
+ .update(DST)
87
+ .update(i2osp(DST.length, 1))
88
+ .digest());
89
+ }
90
+ /**
91
+ * Hashes arbitrary-length byte strings to a list of one or more elements of a finite field F
92
+ * https://www.rfc-editor.org/rfc/rfc9380#section-5.2
93
+ * @param msg a byte string containing the message to hash
94
+ * @param count the number of elements of F to output
95
+ * @param options `{DST: string, p: bigint, m: number, k: number, expand: 'xmd' | 'xof', hash: H}`, see above
96
+ * @returns [u_0, ..., u_(count - 1)], a list of field elements.
97
+ */
98
+ function hash_to_field(msg, count, options) {
99
+ validateObject(options, {
100
+ DST: 'stringOrUint8Array',
101
+ p: 'bigint',
102
+ m: 'isSafeInteger',
103
+ k: 'isSafeInteger',
104
+ hash: 'hash',
105
+ });
106
+ const { p, k, m, hash, expand, DST: _DST } = options;
107
+ isBytes(msg);
108
+ isNum(count);
109
+ const DST = validateDST(_DST);
110
+ const log2p = p.toString(2).length;
111
+ const L = Math.ceil((log2p + k) / 8); // section 5.1 of ietf draft link above
112
+ const len_in_bytes = count * m * L;
113
+ let prb; // pseudo_random_bytes
114
+ if (expand === 'xmd') {
115
+ prb = expand_message_xmd(msg, DST, len_in_bytes, hash);
116
+ }
117
+ else if (expand === 'xof') {
118
+ prb = expand_message_xof(msg, DST, len_in_bytes, k, hash);
119
+ }
120
+ else if (expand === '_internal_pass') {
121
+ // for internal tests only
122
+ prb = msg;
123
+ }
124
+ else {
125
+ throw new Error('expand must be "xmd" or "xof"');
126
+ }
127
+ const u = new Array(count);
128
+ for (let i = 0; i < count; i++) {
129
+ const e = new Array(m);
130
+ for (let j = 0; j < m; j++) {
131
+ const elm_offset = L * (j + i * m);
132
+ const tv = prb.subarray(elm_offset, elm_offset + L);
133
+ e[j] = mod(os2ip(tv), p);
134
+ }
135
+ u[i] = e;
136
+ }
137
+ return u;
138
+ }
139
+ function isogenyMap(field, map) {
140
+ // Make same order as in spec
141
+ const COEFF = map.map((i) => Array.from(i).reverse());
142
+ return (x, y) => {
143
+ const [xNum, xDen, yNum, yDen] = COEFF.map((val) => val.reduce((acc, i) => field.add(field.mul(acc, x), i)));
144
+ x = field.div(xNum, xDen); // xNum / xDen
145
+ y = field.mul(y, field.div(yNum, yDen)); // y * (yNum / yDev)
146
+ return { x, y };
147
+ };
148
+ }
149
+ function createHasher(Point, mapToCurve, def) {
150
+ if (typeof mapToCurve !== 'function')
151
+ throw new Error('mapToCurve() must be defined');
152
+ return {
153
+ // Encodes byte string to elliptic curve.
154
+ // hash_to_curve from https://www.rfc-editor.org/rfc/rfc9380#section-3
155
+ hashToCurve(msg, options) {
156
+ const u = hash_to_field(msg, 2, { ...def, DST: def.DST, ...options });
157
+ const u0 = Point.fromAffine(mapToCurve(u[0]));
158
+ const u1 = Point.fromAffine(mapToCurve(u[1]));
159
+ const P = u0.add(u1).clearCofactor();
160
+ P.assertValidity();
161
+ return P;
162
+ },
163
+ // Encodes byte string to elliptic curve.
164
+ // encode_to_curve from https://www.rfc-editor.org/rfc/rfc9380#section-3
165
+ encodeToCurve(msg, options) {
166
+ const u = hash_to_field(msg, 1, { ...def, DST: def.encodeDST, ...options });
167
+ const P = Point.fromAffine(mapToCurve(u[0])).clearCofactor();
168
+ P.assertValidity();
169
+ return P;
170
+ },
171
+ };
172
+ }
173
+
174
+ // prettier-ignore
175
+ const _2n$1 = BigInt(2), _3n$1 = BigInt(3);
176
+ function bls(CURVE) {
177
+ // Fields are specific for curve, so for now we'll need to pass them with opts
178
+ const { Fp, Fr, Fp2, Fp6, Fp12 } = CURVE.fields;
179
+ const BLS_X_LEN = bitLen(CURVE.params.x);
180
+ // Pre-compute coefficients for sparse multiplication
181
+ // Point addition and point double calculations is reused for coefficients
182
+ function calcPairingPrecomputes(p) {
183
+ const { x, y } = p;
184
+ // prettier-ignore
185
+ const Qx = x, Qy = y, Qz = Fp2.ONE;
186
+ // prettier-ignore
187
+ let Rx = Qx, Ry = Qy, Rz = Qz;
188
+ let ell_coeff = [];
189
+ for (let i = BLS_X_LEN - 2; i >= 0; i--) {
190
+ // Double
191
+ let t0 = Fp2.sqr(Ry); // Ry²
192
+ let t1 = Fp2.sqr(Rz); // Rz²
193
+ let t2 = Fp2.multiplyByB(Fp2.mul(t1, _3n$1)); // 3 * T1 * B
194
+ let t3 = Fp2.mul(t2, _3n$1); // 3 * T2
195
+ let t4 = Fp2.sub(Fp2.sub(Fp2.sqr(Fp2.add(Ry, Rz)), t1), t0); // (Ry + Rz)² - T1 - T0
196
+ ell_coeff.push([
197
+ Fp2.sub(t2, t0),
198
+ Fp2.mul(Fp2.sqr(Rx), _3n$1),
199
+ Fp2.neg(t4), // -T4
200
+ ]);
201
+ Rx = Fp2.div(Fp2.mul(Fp2.mul(Fp2.sub(t0, t3), Rx), Ry), _2n$1); // ((T0 - T3) * Rx * Ry) / 2
202
+ Ry = Fp2.sub(Fp2.sqr(Fp2.div(Fp2.add(t0, t3), _2n$1)), Fp2.mul(Fp2.sqr(t2), _3n$1)); // ((T0 + T3) / 2)² - 3 * T2²
203
+ Rz = Fp2.mul(t0, t4); // T0 * T4
204
+ if (bitGet(CURVE.params.x, i)) {
205
+ // Addition
206
+ let t0 = Fp2.sub(Ry, Fp2.mul(Qy, Rz)); // Ry - Qy * Rz
207
+ let t1 = Fp2.sub(Rx, Fp2.mul(Qx, Rz)); // Rx - Qx * Rz
208
+ ell_coeff.push([
209
+ Fp2.sub(Fp2.mul(t0, Qx), Fp2.mul(t1, Qy)),
210
+ Fp2.neg(t0),
211
+ t1, // T1
212
+ ]);
213
+ let t2 = Fp2.sqr(t1); // T1²
214
+ let t3 = Fp2.mul(t2, t1); // T2 * T1
215
+ let t4 = Fp2.mul(t2, Rx); // T2 * Rx
216
+ let t5 = Fp2.add(Fp2.sub(t3, Fp2.mul(t4, _2n$1)), Fp2.mul(Fp2.sqr(t0), Rz)); // T3 - 2 * T4 + T0² * Rz
217
+ Rx = Fp2.mul(t1, t5); // T1 * T5
218
+ Ry = Fp2.sub(Fp2.mul(Fp2.sub(t4, t5), t0), Fp2.mul(t3, Ry)); // (T4 - T5) * T0 - T3 * Ry
219
+ Rz = Fp2.mul(Rz, t3); // Rz * T3
220
+ }
221
+ }
222
+ return ell_coeff;
223
+ }
224
+ function millerLoop(ell, g1) {
225
+ const { x } = CURVE.params;
226
+ const Px = g1[0];
227
+ const Py = g1[1];
228
+ let f12 = Fp12.ONE;
229
+ for (let j = 0, i = BLS_X_LEN - 2; i >= 0; i--, j++) {
230
+ const E = ell[j];
231
+ f12 = Fp12.multiplyBy014(f12, E[0], Fp2.mul(E[1], Px), Fp2.mul(E[2], Py));
232
+ if (bitGet(x, i)) {
233
+ j += 1;
234
+ const F = ell[j];
235
+ f12 = Fp12.multiplyBy014(f12, F[0], Fp2.mul(F[1], Px), Fp2.mul(F[2], Py));
236
+ }
237
+ if (i !== 0)
238
+ f12 = Fp12.sqr(f12);
239
+ }
240
+ return Fp12.conjugate(f12);
241
+ }
242
+ const utils = {
243
+ randomPrivateKey: () => {
244
+ const length = getMinHashLength(Fr.ORDER);
245
+ return mapHashToField(CURVE.randomBytes(length), Fr.ORDER);
246
+ },
247
+ calcPairingPrecomputes,
248
+ };
249
+ // Point on G1 curve: (x, y)
250
+ const G1_ = weierstrassPoints({ n: Fr.ORDER, ...CURVE.G1 });
251
+ const G1 = Object.assign(G1_, createHasher(G1_.ProjectivePoint, CURVE.G1.mapToCurve, {
252
+ ...CURVE.htfDefaults,
253
+ ...CURVE.G1.htfDefaults,
254
+ }));
255
+ function pairingPrecomputes(point) {
256
+ const p = point;
257
+ if (p._PPRECOMPUTES)
258
+ return p._PPRECOMPUTES;
259
+ p._PPRECOMPUTES = calcPairingPrecomputes(point.toAffine());
260
+ return p._PPRECOMPUTES;
261
+ }
262
+ // TODO: export
263
+ // function clearPairingPrecomputes(point: G2) {
264
+ // const p = point as G2 & withPairingPrecomputes;
265
+ // p._PPRECOMPUTES = undefined;
266
+ // }
267
+ // Point on G2 curve (complex numbers): (x₁, x₂+i), (y₁, y₂+i)
268
+ const G2_ = weierstrassPoints({ n: Fr.ORDER, ...CURVE.G2 });
269
+ const G2 = Object.assign(G2_, createHasher(G2_.ProjectivePoint, CURVE.G2.mapToCurve, {
270
+ ...CURVE.htfDefaults,
271
+ ...CURVE.G2.htfDefaults,
272
+ }));
273
+ const { Signature } = CURVE.G2;
274
+ // Calculates bilinear pairing
275
+ function pairing(Q, P, withFinalExponent = true) {
276
+ if (Q.equals(G1.ProjectivePoint.ZERO) || P.equals(G2.ProjectivePoint.ZERO))
277
+ throw new Error('pairing is not available for ZERO point');
278
+ Q.assertValidity();
279
+ P.assertValidity();
280
+ // Performance: 9ms for millerLoop and ~14ms for exp.
281
+ const Qa = Q.toAffine();
282
+ const looped = millerLoop(pairingPrecomputes(P), [Qa.x, Qa.y]);
283
+ return withFinalExponent ? Fp12.finalExponentiate(looped) : looped;
284
+ }
285
+ function normP1(point) {
286
+ return point instanceof G1.ProjectivePoint ? point : G1.ProjectivePoint.fromHex(point);
287
+ }
288
+ function normP2(point) {
289
+ return point instanceof G2.ProjectivePoint ? point : Signature.fromHex(point);
290
+ }
291
+ function normP2Hash(point, htfOpts) {
292
+ return point instanceof G2.ProjectivePoint
293
+ ? point
294
+ : G2.hashToCurve(ensureBytes('point', point), htfOpts);
295
+ }
296
+ // Multiplies generator by private key.
297
+ // P = pk x G
298
+ function getPublicKey(privateKey) {
299
+ return G1.ProjectivePoint.fromPrivateKey(privateKey).toRawBytes(true);
300
+ }
301
+ function sign(message, privateKey, htfOpts) {
302
+ const msgPoint = normP2Hash(message, htfOpts);
303
+ msgPoint.assertValidity();
304
+ const sigPoint = msgPoint.multiply(G1.normPrivateKeyToScalar(privateKey));
305
+ if (message instanceof G2.ProjectivePoint)
306
+ return sigPoint;
307
+ return Signature.toRawBytes(sigPoint);
308
+ }
309
+ // Checks if pairing of public key & hash is equal to pairing of generator & signature.
310
+ // e(P, H(m)) == e(G, S)
311
+ function verify(signature, message, publicKey, htfOpts) {
312
+ const P = normP1(publicKey);
313
+ const Hm = normP2Hash(message, htfOpts);
314
+ const G = G1.ProjectivePoint.BASE;
315
+ const S = normP2(signature);
316
+ // Instead of doing 2 exponentiations, we use property of billinear maps
317
+ // and do one exp after multiplying 2 points.
318
+ const ePHm = pairing(P.negate(), Hm, false);
319
+ const eGS = pairing(G, S, false);
320
+ const exp = Fp12.finalExponentiate(Fp12.mul(eGS, ePHm));
321
+ return Fp12.eql(exp, Fp12.ONE);
322
+ }
323
+ function aggregatePublicKeys(publicKeys) {
324
+ if (!publicKeys.length)
325
+ throw new Error('Expected non-empty array');
326
+ const agg = publicKeys.map(normP1).reduce((sum, p) => sum.add(p), G1.ProjectivePoint.ZERO);
327
+ const aggAffine = agg; //.toAffine();
328
+ if (publicKeys[0] instanceof G1.ProjectivePoint) {
329
+ aggAffine.assertValidity();
330
+ return aggAffine;
331
+ }
332
+ // toRawBytes ensures point validity
333
+ return aggAffine.toRawBytes(true);
334
+ }
335
+ function aggregateSignatures(signatures) {
336
+ if (!signatures.length)
337
+ throw new Error('Expected non-empty array');
338
+ const agg = signatures.map(normP2).reduce((sum, s) => sum.add(s), G2.ProjectivePoint.ZERO);
339
+ const aggAffine = agg; //.toAffine();
340
+ if (signatures[0] instanceof G2.ProjectivePoint) {
341
+ aggAffine.assertValidity();
342
+ return aggAffine;
343
+ }
344
+ return Signature.toRawBytes(aggAffine);
345
+ }
346
+ // https://ethresear.ch/t/fast-verification-of-multiple-bls-signatures/5407
347
+ // e(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))
348
+ function verifyBatch(signature, messages, publicKeys, htfOpts) {
349
+ // @ts-ignore
350
+ // console.log('verifyBatch', bytesToHex(signature as any), messages, publicKeys.map(bytesToHex));
351
+ if (!messages.length)
352
+ throw new Error('Expected non-empty messages array');
353
+ if (publicKeys.length !== messages.length)
354
+ throw new Error('Pubkey count should equal msg count');
355
+ const sig = normP2(signature);
356
+ const nMessages = messages.map((i) => normP2Hash(i, htfOpts));
357
+ const nPublicKeys = publicKeys.map(normP1);
358
+ try {
359
+ const paired = [];
360
+ for (const message of new Set(nMessages)) {
361
+ const groupPublicKey = nMessages.reduce((groupPublicKey, subMessage, i) => subMessage === message ? groupPublicKey.add(nPublicKeys[i]) : groupPublicKey, G1.ProjectivePoint.ZERO);
362
+ // const msg = message instanceof PointG2 ? message : await PointG2.hashToCurve(message);
363
+ // Possible to batch pairing for same msg with different groupPublicKey here
364
+ paired.push(pairing(groupPublicKey, message, false));
365
+ }
366
+ paired.push(pairing(G1.ProjectivePoint.BASE.negate(), sig, false));
367
+ const product = paired.reduce((a, b) => Fp12.mul(a, b), Fp12.ONE);
368
+ const exp = Fp12.finalExponentiate(product);
369
+ return Fp12.eql(exp, Fp12.ONE);
370
+ }
371
+ catch {
372
+ return false;
373
+ }
374
+ }
375
+ G1.ProjectivePoint.BASE._setWindowSize(4);
376
+ return {
377
+ getPublicKey,
378
+ sign,
379
+ verify,
380
+ verifyBatch,
381
+ aggregatePublicKeys,
382
+ aggregateSignatures,
383
+ millerLoop,
384
+ pairing,
385
+ G1,
386
+ G2,
387
+ Signature,
388
+ fields: {
389
+ Fr,
390
+ Fp,
391
+ Fp2,
392
+ Fp6,
393
+ Fp12,
394
+ },
395
+ params: {
396
+ x: CURVE.params.x,
397
+ r: CURVE.params.r,
398
+ G1b: CURVE.G1.b,
399
+ G2b: CURVE.G2.b,
400
+ },
401
+ utils,
402
+ };
403
+ }
404
+
405
+ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
406
+ // bls12-381 pairing-friendly Barreto-Lynn-Scott elliptic curve construction allows to:
407
+ // - Construct zk-SNARKs at the 128-bit security
408
+ // - Use threshold signatures, which allows a user to sign lots of messages with one signature and
409
+ // verify them swiftly in a batch, using Boneh-Lynn-Shacham signature scheme.
410
+ //
411
+ // The library uses G1 for public keys and G2 for signatures. Support for G1 signatures is planned.
412
+ // Compatible with Algorand, Chia, Dfinity, Ethereum, FIL, Zcash. Matches specs
413
+ // [pairing-curves-11](https://tools.ietf.org/html/draft-irtf-cfrg-pairing-friendly-curves-11),
414
+ // [bls-sigs-04](https:/cfrg-hash-to/tools.ietf.org/html/draft-irtf-cfrg-bls-signature-04),
415
+ // [hash-to-curve-12](https://tools.ietf.org/html/draft-irtf--curve-12).
416
+ //
417
+ // ### Summary
418
+ // 1. BLS Relies on Bilinear Pairing (expensive)
419
+ // 2. Private Keys: 32 bytes
420
+ // 3. Public Keys: 48 bytes: 381 bit affine x coordinate, encoded into 48 big-endian bytes.
421
+ // 4. Signatures: 96 bytes: two 381 bit integers (affine x coordinate), encoded into two 48 big-endian byte arrays.
422
+ // - The signature is a point on the G2 subgroup, which is defined over a finite field
423
+ // with elements twice as big as the G1 curve (G2 is over Fp2 rather than Fp. Fp2 is analogous to the complex numbers).
424
+ // 5. The 12 stands for the Embedding degree.
425
+ //
426
+ // ### Formulas
427
+ // - `P = pk x G` - public keys
428
+ // - `S = pk x H(m)` - signing
429
+ // - `e(P, H(m)) == e(G, S)` - verification using pairings
430
+ // - `e(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))` - signature aggregation
431
+ // Filecoin uses little endian byte arrays for private keys -
432
+ // so ensure to reverse byte order if you'll use it with FIL.
433
+ // Be friendly to bad ECMAScript parsers by not using bigint literals
434
+ // prettier-ignore
435
+ const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3), _4n = BigInt(4);
436
+ // prettier-ignore
437
+ const _8n = BigInt(8), _16n = BigInt(16);
438
+ // CURVE FIELDS
439
+ // Finite field over p.
440
+ const Fp_raw = BigInt('0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab');
441
+ const Fp = Field(Fp_raw);
442
+ // Finite field over r.
443
+ // This particular field is not used anywhere in bls12-381, but it is still useful.
444
+ const Fr$1 = Field(BigInt('0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001'));
445
+ const Fp2Add = ({ c0, c1 }, { c0: r0, c1: r1 }) => ({
446
+ c0: Fp.add(c0, r0),
447
+ c1: Fp.add(c1, r1),
448
+ });
449
+ const Fp2Subtract = ({ c0, c1 }, { c0: r0, c1: r1 }) => ({
450
+ c0: Fp.sub(c0, r0),
451
+ c1: Fp.sub(c1, r1),
452
+ });
453
+ const Fp2Multiply = ({ c0, c1 }, rhs) => {
454
+ if (typeof rhs === 'bigint')
455
+ return { c0: Fp.mul(c0, rhs), c1: Fp.mul(c1, rhs) };
456
+ // (a+bi)(c+di) = (ac−bd) + (ad+bc)i
457
+ const { c0: r0, c1: r1 } = rhs;
458
+ let t1 = Fp.mul(c0, r0); // c0 * o0
459
+ let t2 = Fp.mul(c1, r1); // c1 * o1
460
+ // (T1 - T2) + ((c0 + c1) * (r0 + r1) - (T1 + T2))*i
461
+ const o0 = Fp.sub(t1, t2);
462
+ const o1 = Fp.sub(Fp.mul(Fp.add(c0, c1), Fp.add(r0, r1)), Fp.add(t1, t2));
463
+ return { c0: o0, c1: o1 };
464
+ };
465
+ const Fp2Square = ({ c0, c1 }) => {
466
+ const a = Fp.add(c0, c1);
467
+ const b = Fp.sub(c0, c1);
468
+ const c = Fp.add(c0, c0);
469
+ return { c0: Fp.mul(a, b), c1: Fp.mul(c, c1) };
470
+ };
471
+ // G2 is the order-q subgroup of E2(Fp²) : y² = x³+4(1+√−1),
472
+ // where Fp2 is Fp[√−1]/(x2+1). #E2(Fp2 ) = h2q, where
473
+ // G² - 1
474
+ // h2q
475
+ // NOTE: ORDER was wrong!
476
+ const FP2_ORDER = Fp_raw * Fp_raw;
477
+ const Fp2 = {
478
+ ORDER: FP2_ORDER,
479
+ BITS: bitLen(FP2_ORDER),
480
+ BYTES: Math.ceil(bitLen(FP2_ORDER) / 8),
481
+ MASK: bitMask(bitLen(FP2_ORDER)),
482
+ ZERO: { c0: Fp.ZERO, c1: Fp.ZERO },
483
+ ONE: { c0: Fp.ONE, c1: Fp.ZERO },
484
+ create: (num) => num,
485
+ isValid: ({ c0, c1 }) => typeof c0 === 'bigint' && typeof c1 === 'bigint',
486
+ is0: ({ c0, c1 }) => Fp.is0(c0) && Fp.is0(c1),
487
+ eql: ({ c0, c1 }, { c0: r0, c1: r1 }) => Fp.eql(c0, r0) && Fp.eql(c1, r1),
488
+ neg: ({ c0, c1 }) => ({ c0: Fp.neg(c0), c1: Fp.neg(c1) }),
489
+ pow: (num, power) => FpPow(Fp2, num, power),
490
+ invertBatch: (nums) => FpInvertBatch(Fp2, nums),
491
+ // Normalized
492
+ add: Fp2Add,
493
+ sub: Fp2Subtract,
494
+ mul: Fp2Multiply,
495
+ sqr: Fp2Square,
496
+ // NonNormalized stuff
497
+ addN: Fp2Add,
498
+ subN: Fp2Subtract,
499
+ mulN: Fp2Multiply,
500
+ sqrN: Fp2Square,
501
+ // Why inversion for bigint inside Fp instead of Fp2? it is even used in that context?
502
+ div: (lhs, rhs) => Fp2.mul(lhs, typeof rhs === 'bigint' ? Fp.inv(Fp.create(rhs)) : Fp2.inv(rhs)),
503
+ inv: ({ c0: a, c1: b }) => {
504
+ // We wish to find the multiplicative inverse of a nonzero
505
+ // element a + bu in Fp2. We leverage an identity
506
+ //
507
+ // (a + bu)(a - bu) = a² + b²
508
+ //
509
+ // which holds because u² = -1. This can be rewritten as
510
+ //
511
+ // (a + bu)(a - bu)/(a² + b²) = 1
512
+ //
513
+ // because a² + b² = 0 has no nonzero solutions for (a, b).
514
+ // This gives that (a - bu)/(a² + b²) is the inverse
515
+ // of (a + bu). Importantly, this can be computing using
516
+ // only a single inversion in Fp.
517
+ const factor = Fp.inv(Fp.create(a * a + b * b));
518
+ return { c0: Fp.mul(factor, Fp.create(a)), c1: Fp.mul(factor, Fp.create(-b)) };
519
+ },
520
+ sqrt: (num) => {
521
+ if (Fp2.eql(num, Fp2.ZERO))
522
+ return Fp2.ZERO; // Algo doesn't handles this case
523
+ // TODO: Optimize this line. It's extremely slow.
524
+ // Speeding this up would boost aggregateSignatures.
525
+ // https://eprint.iacr.org/2012/685.pdf applicable?
526
+ // https://github.com/zkcrypto/bls12_381/blob/080eaa74ec0e394377caa1ba302c8c121df08b07/src/fp2.rs#L250
527
+ // https://github.com/supranational/blst/blob/aae0c7d70b799ac269ff5edf29d8191dbd357876/src/exp2.c#L1
528
+ // Inspired by https://github.com/dalek-cryptography/curve25519-dalek/blob/17698df9d4c834204f83a3574143abacb4fc81a5/src/field.rs#L99
529
+ const candidateSqrt = Fp2.pow(num, (Fp2.ORDER + _8n) / _16n);
530
+ const check = Fp2.div(Fp2.sqr(candidateSqrt), num); // candidateSqrt.square().div(this);
531
+ const R = FP2_ROOTS_OF_UNITY;
532
+ const divisor = [R[0], R[2], R[4], R[6]].find((r) => Fp2.eql(r, check));
533
+ if (!divisor)
534
+ throw new Error('No root');
535
+ const index = R.indexOf(divisor);
536
+ const root = R[index / 2];
537
+ if (!root)
538
+ throw new Error('Invalid root');
539
+ const x1 = Fp2.div(candidateSqrt, root);
540
+ const x2 = Fp2.neg(x1);
541
+ const { re: re1, im: im1 } = Fp2.reim(x1);
542
+ const { re: re2, im: im2 } = Fp2.reim(x2);
543
+ if (im1 > im2 || (im1 === im2 && re1 > re2))
544
+ return x1;
545
+ return x2;
546
+ },
547
+ // Same as sgn0_m_eq_2 in RFC 9380
548
+ isOdd: (x) => {
549
+ const { re: x0, im: x1 } = Fp2.reim(x);
550
+ const sign_0 = x0 % _2n;
551
+ const zero_0 = x0 === _0n;
552
+ const sign_1 = x1 % _2n;
553
+ return BigInt(sign_0 || (zero_0 && sign_1)) == _1n;
554
+ },
555
+ // Bytes util
556
+ fromBytes(b) {
557
+ if (b.length !== Fp2.BYTES)
558
+ throw new Error(`fromBytes wrong length=${b.length}`);
559
+ return { c0: Fp.fromBytes(b.subarray(0, Fp.BYTES)), c1: Fp.fromBytes(b.subarray(Fp.BYTES)) };
560
+ },
561
+ toBytes: ({ c0, c1 }) => concatBytes(Fp.toBytes(c0), Fp.toBytes(c1)),
562
+ cmov: ({ c0, c1 }, { c0: r0, c1: r1 }, c) => ({
563
+ c0: Fp.cmov(c0, r0, c),
564
+ c1: Fp.cmov(c1, r1, c),
565
+ }),
566
+ // Specific utils
567
+ // toString() {
568
+ // return `Fp2(${this.c0} + ${this.c1}×i)`;
569
+ // }
570
+ reim: ({ c0, c1 }) => ({ re: c0, im: c1 }),
571
+ // multiply by u + 1
572
+ mulByNonresidue: ({ c0, c1 }) => ({ c0: Fp.sub(c0, c1), c1: Fp.add(c0, c1) }),
573
+ multiplyByB: ({ c0, c1 }) => {
574
+ let t0 = Fp.mul(c0, _4n); // 4 * c0
575
+ let t1 = Fp.mul(c1, _4n); // 4 * c1
576
+ // (T0-T1) + (T0+T1)*i
577
+ return { c0: Fp.sub(t0, t1), c1: Fp.add(t0, t1) };
578
+ },
579
+ fromBigTuple: (tuple) => {
580
+ if (tuple.length !== 2)
581
+ throw new Error('Invalid tuple');
582
+ const fps = tuple.map((n) => Fp.create(n));
583
+ return { c0: fps[0], c1: fps[1] };
584
+ },
585
+ frobeniusMap: ({ c0, c1 }, power) => ({
586
+ c0,
587
+ c1: Fp.mul(c1, FP2_FROBENIUS_COEFFICIENTS[power % 2]),
588
+ }),
589
+ };
590
+ // Finite extension field over irreducible polynominal.
591
+ // Fp(u) / (u² - β) where β = -1
592
+ const FP2_FROBENIUS_COEFFICIENTS = [
593
+ BigInt('0x1'),
594
+ BigInt('0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa'),
595
+ ].map((item) => Fp.create(item));
596
+ // For Fp2 roots of unity.
597
+ const rv1 = BigInt('0x6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09');
598
+ // const ev1 =
599
+ // BigInt('0x699be3b8c6870965e5bf892ad5d2cc7b0e85a117402dfd83b7f4a947e02d978498255a2aaec0ac627b5afbdf1bf1c90');
600
+ // const ev2 =
601
+ // BigInt('0x8157cd83046453f5dd0972b6e3949e4288020b5b8a9cc99ca07e27089a2ce2436d965026adad3ef7baba37f2183e9b5');
602
+ // const ev3 =
603
+ // BigInt('0xab1c2ffdd6c253ca155231eb3e71ba044fd562f6f72bc5bad5ec46a0b7a3b0247cf08ce6c6317f40edbc653a72dee17');
604
+ // const ev4 =
605
+ // BigInt('0xaa404866706722864480885d68ad0ccac1967c7544b447873cc37e0181271e006df72162a3d3e0287bf597fbf7f8fc1');
606
+ // Eighth roots of unity, used for computing square roots in Fp2.
607
+ // To verify or re-calculate:
608
+ // Array(8).fill(new Fp2([1n, 1n])).map((fp2, k) => fp2.pow(Fp2.ORDER * BigInt(k) / 8n))
609
+ const FP2_ROOTS_OF_UNITY = [
610
+ [_1n, _0n],
611
+ [rv1, -rv1],
612
+ [_0n, _1n],
613
+ [rv1, rv1],
614
+ [-_1n, _0n],
615
+ [-rv1, rv1],
616
+ [_0n, -_1n],
617
+ [-rv1, -rv1],
618
+ ].map((pair) => Fp2.fromBigTuple(pair));
619
+ const Fp6Add = ({ c0, c1, c2 }, { c0: r0, c1: r1, c2: r2 }) => ({
620
+ c0: Fp2.add(c0, r0),
621
+ c1: Fp2.add(c1, r1),
622
+ c2: Fp2.add(c2, r2),
623
+ });
624
+ const Fp6Subtract = ({ c0, c1, c2 }, { c0: r0, c1: r1, c2: r2 }) => ({
625
+ c0: Fp2.sub(c0, r0),
626
+ c1: Fp2.sub(c1, r1),
627
+ c2: Fp2.sub(c2, r2),
628
+ });
629
+ const Fp6Multiply = ({ c0, c1, c2 }, rhs) => {
630
+ if (typeof rhs === 'bigint') {
631
+ return {
632
+ c0: Fp2.mul(c0, rhs),
633
+ c1: Fp2.mul(c1, rhs),
634
+ c2: Fp2.mul(c2, rhs),
635
+ };
636
+ }
637
+ const { c0: r0, c1: r1, c2: r2 } = rhs;
638
+ const t0 = Fp2.mul(c0, r0); // c0 * o0
639
+ const t1 = Fp2.mul(c1, r1); // c1 * o1
640
+ const t2 = Fp2.mul(c2, r2); // c2 * o2
641
+ return {
642
+ // t0 + (c1 + c2) * (r1 * r2) - (T1 + T2) * (u + 1)
643
+ c0: Fp2.add(t0, Fp2.mulByNonresidue(Fp2.sub(Fp2.mul(Fp2.add(c1, c2), Fp2.add(r1, r2)), Fp2.add(t1, t2)))),
644
+ // (c0 + c1) * (r0 + r1) - (T0 + T1) + T2 * (u + 1)
645
+ c1: Fp2.add(Fp2.sub(Fp2.mul(Fp2.add(c0, c1), Fp2.add(r0, r1)), Fp2.add(t0, t1)), Fp2.mulByNonresidue(t2)),
646
+ // T1 + (c0 + c2) * (r0 + r2) - T0 + T2
647
+ c2: Fp2.sub(Fp2.add(t1, Fp2.mul(Fp2.add(c0, c2), Fp2.add(r0, r2))), Fp2.add(t0, t2)),
648
+ };
649
+ };
650
+ const Fp6Square = ({ c0, c1, c2 }) => {
651
+ let t0 = Fp2.sqr(c0); // c0²
652
+ let t1 = Fp2.mul(Fp2.mul(c0, c1), _2n); // 2 * c0 * c1
653
+ let t3 = Fp2.mul(Fp2.mul(c1, c2), _2n); // 2 * c1 * c2
654
+ let t4 = Fp2.sqr(c2); // c2²
655
+ return {
656
+ c0: Fp2.add(Fp2.mulByNonresidue(t3), t0),
657
+ c1: Fp2.add(Fp2.mulByNonresidue(t4), t1),
658
+ // T1 + (c0 - c1 + c2)² + T3 - T0 - T4
659
+ c2: Fp2.sub(Fp2.sub(Fp2.add(Fp2.add(t1, Fp2.sqr(Fp2.add(Fp2.sub(c0, c1), c2))), t3), t0), t4),
660
+ };
661
+ };
662
+ const Fp6 = {
663
+ ORDER: Fp2.ORDER,
664
+ BITS: 3 * Fp2.BITS,
665
+ BYTES: 3 * Fp2.BYTES,
666
+ MASK: bitMask(3 * Fp2.BITS),
667
+ ZERO: { c0: Fp2.ZERO, c1: Fp2.ZERO, c2: Fp2.ZERO },
668
+ ONE: { c0: Fp2.ONE, c1: Fp2.ZERO, c2: Fp2.ZERO },
669
+ create: (num) => num,
670
+ isValid: ({ c0, c1, c2 }) => Fp2.isValid(c0) && Fp2.isValid(c1) && Fp2.isValid(c2),
671
+ is0: ({ c0, c1, c2 }) => Fp2.is0(c0) && Fp2.is0(c1) && Fp2.is0(c2),
672
+ neg: ({ c0, c1, c2 }) => ({ c0: Fp2.neg(c0), c1: Fp2.neg(c1), c2: Fp2.neg(c2) }),
673
+ eql: ({ c0, c1, c2 }, { c0: r0, c1: r1, c2: r2 }) => Fp2.eql(c0, r0) && Fp2.eql(c1, r1) && Fp2.eql(c2, r2),
674
+ sqrt: () => {
675
+ throw new Error('Not implemented');
676
+ },
677
+ // Do we need division by bigint at all? Should be done via order:
678
+ div: (lhs, rhs) => Fp6.mul(lhs, typeof rhs === 'bigint' ? Fp.inv(Fp.create(rhs)) : Fp6.inv(rhs)),
679
+ pow: (num, power) => FpPow(Fp6, num, power),
680
+ invertBatch: (nums) => FpInvertBatch(Fp6, nums),
681
+ // Normalized
682
+ add: Fp6Add,
683
+ sub: Fp6Subtract,
684
+ mul: Fp6Multiply,
685
+ sqr: Fp6Square,
686
+ // NonNormalized stuff
687
+ addN: Fp6Add,
688
+ subN: Fp6Subtract,
689
+ mulN: Fp6Multiply,
690
+ sqrN: Fp6Square,
691
+ inv: ({ c0, c1, c2 }) => {
692
+ let t0 = Fp2.sub(Fp2.sqr(c0), Fp2.mulByNonresidue(Fp2.mul(c2, c1))); // c0² - c2 * c1 * (u + 1)
693
+ let t1 = Fp2.sub(Fp2.mulByNonresidue(Fp2.sqr(c2)), Fp2.mul(c0, c1)); // c2² * (u + 1) - c0 * c1
694
+ let t2 = Fp2.sub(Fp2.sqr(c1), Fp2.mul(c0, c2)); // c1² - c0 * c2
695
+ // 1/(((c2 * T1 + c1 * T2) * v) + c0 * T0)
696
+ let t4 = Fp2.inv(Fp2.add(Fp2.mulByNonresidue(Fp2.add(Fp2.mul(c2, t1), Fp2.mul(c1, t2))), Fp2.mul(c0, t0)));
697
+ return { c0: Fp2.mul(t4, t0), c1: Fp2.mul(t4, t1), c2: Fp2.mul(t4, t2) };
698
+ },
699
+ // Bytes utils
700
+ fromBytes: (b) => {
701
+ if (b.length !== Fp6.BYTES)
702
+ throw new Error(`fromBytes wrong length=${b.length}`);
703
+ return {
704
+ c0: Fp2.fromBytes(b.subarray(0, Fp2.BYTES)),
705
+ c1: Fp2.fromBytes(b.subarray(Fp2.BYTES, 2 * Fp2.BYTES)),
706
+ c2: Fp2.fromBytes(b.subarray(2 * Fp2.BYTES)),
707
+ };
708
+ },
709
+ toBytes: ({ c0, c1, c2 }) => concatBytes(Fp2.toBytes(c0), Fp2.toBytes(c1), Fp2.toBytes(c2)),
710
+ cmov: ({ c0, c1, c2 }, { c0: r0, c1: r1, c2: r2 }, c) => ({
711
+ c0: Fp2.cmov(c0, r0, c),
712
+ c1: Fp2.cmov(c1, r1, c),
713
+ c2: Fp2.cmov(c2, r2, c),
714
+ }),
715
+ // Utils
716
+ // fromTriple(triple: [Fp2, Fp2, Fp2]) {
717
+ // return new Fp6(...triple);
718
+ // }
719
+ // toString() {
720
+ // return `Fp6(${this.c0} + ${this.c1} * v, ${this.c2} * v^2)`;
721
+ // }
722
+ fromBigSix: (t) => {
723
+ if (!Array.isArray(t) || t.length !== 6)
724
+ throw new Error('Invalid Fp6 usage');
725
+ return {
726
+ c0: Fp2.fromBigTuple(t.slice(0, 2)),
727
+ c1: Fp2.fromBigTuple(t.slice(2, 4)),
728
+ c2: Fp2.fromBigTuple(t.slice(4, 6)),
729
+ };
730
+ },
731
+ frobeniusMap: ({ c0, c1, c2 }, power) => ({
732
+ c0: Fp2.frobeniusMap(c0, power),
733
+ c1: Fp2.mul(Fp2.frobeniusMap(c1, power), FP6_FROBENIUS_COEFFICIENTS_1[power % 6]),
734
+ c2: Fp2.mul(Fp2.frobeniusMap(c2, power), FP6_FROBENIUS_COEFFICIENTS_2[power % 6]),
735
+ }),
736
+ mulByNonresidue: ({ c0, c1, c2 }) => ({ c0: Fp2.mulByNonresidue(c2), c1: c0, c2: c1 }),
737
+ // Sparse multiplication
738
+ multiplyBy1: ({ c0, c1, c2 }, b1) => ({
739
+ c0: Fp2.mulByNonresidue(Fp2.mul(c2, b1)),
740
+ c1: Fp2.mul(c0, b1),
741
+ c2: Fp2.mul(c1, b1),
742
+ }),
743
+ // Sparse multiplication
744
+ multiplyBy01({ c0, c1, c2 }, b0, b1) {
745
+ let t0 = Fp2.mul(c0, b0); // c0 * b0
746
+ let t1 = Fp2.mul(c1, b1); // c1 * b1
747
+ return {
748
+ // ((c1 + c2) * b1 - T1) * (u + 1) + T0
749
+ c0: Fp2.add(Fp2.mulByNonresidue(Fp2.sub(Fp2.mul(Fp2.add(c1, c2), b1), t1)), t0),
750
+ // (b0 + b1) * (c0 + c1) - T0 - T1
751
+ c1: Fp2.sub(Fp2.sub(Fp2.mul(Fp2.add(b0, b1), Fp2.add(c0, c1)), t0), t1),
752
+ // (c0 + c2) * b0 - T0 + T1
753
+ c2: Fp2.add(Fp2.sub(Fp2.mul(Fp2.add(c0, c2), b0), t0), t1),
754
+ };
755
+ },
756
+ multiplyByFp2: ({ c0, c1, c2 }, rhs) => ({
757
+ c0: Fp2.mul(c0, rhs),
758
+ c1: Fp2.mul(c1, rhs),
759
+ c2: Fp2.mul(c2, rhs),
760
+ }),
761
+ };
762
+ const FP6_FROBENIUS_COEFFICIENTS_1 = [
763
+ [BigInt('0x1'), BigInt('0x0')],
764
+ [
765
+ BigInt('0x0'),
766
+ BigInt('0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'),
767
+ ],
768
+ [
769
+ BigInt('0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'),
770
+ BigInt('0x0'),
771
+ ],
772
+ [BigInt('0x0'), BigInt('0x1')],
773
+ [
774
+ BigInt('0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'),
775
+ BigInt('0x0'),
776
+ ],
777
+ [
778
+ BigInt('0x0'),
779
+ BigInt('0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'),
780
+ ],
781
+ ].map((pair) => Fp2.fromBigTuple(pair));
782
+ const FP6_FROBENIUS_COEFFICIENTS_2 = [
783
+ [BigInt('0x1'), BigInt('0x0')],
784
+ [
785
+ BigInt('0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad'),
786
+ BigInt('0x0'),
787
+ ],
788
+ [
789
+ BigInt('0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'),
790
+ BigInt('0x0'),
791
+ ],
792
+ [
793
+ BigInt('0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa'),
794
+ BigInt('0x0'),
795
+ ],
796
+ [
797
+ BigInt('0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'),
798
+ BigInt('0x0'),
799
+ ],
800
+ [
801
+ BigInt('0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffeffff'),
802
+ BigInt('0x0'),
803
+ ],
804
+ ].map((pair) => Fp2.fromBigTuple(pair));
805
+ // The BLS parameter x for BLS12-381
806
+ const BLS_X = BigInt('0xd201000000010000');
807
+ const BLS_X_LEN = bitLen(BLS_X);
808
+ const Fp12Add = ({ c0, c1 }, { c0: r0, c1: r1 }) => ({
809
+ c0: Fp6.add(c0, r0),
810
+ c1: Fp6.add(c1, r1),
811
+ });
812
+ const Fp12Subtract = ({ c0, c1 }, { c0: r0, c1: r1 }) => ({
813
+ c0: Fp6.sub(c0, r0),
814
+ c1: Fp6.sub(c1, r1),
815
+ });
816
+ const Fp12Multiply = ({ c0, c1 }, rhs) => {
817
+ if (typeof rhs === 'bigint')
818
+ return { c0: Fp6.mul(c0, rhs), c1: Fp6.mul(c1, rhs) };
819
+ let { c0: r0, c1: r1 } = rhs;
820
+ let t1 = Fp6.mul(c0, r0); // c0 * r0
821
+ let t2 = Fp6.mul(c1, r1); // c1 * r1
822
+ return {
823
+ c0: Fp6.add(t1, Fp6.mulByNonresidue(t2)),
824
+ // (c0 + c1) * (r0 + r1) - (T1 + T2)
825
+ c1: Fp6.sub(Fp6.mul(Fp6.add(c0, c1), Fp6.add(r0, r1)), Fp6.add(t1, t2)),
826
+ };
827
+ };
828
+ const Fp12Square = ({ c0, c1 }) => {
829
+ let ab = Fp6.mul(c0, c1); // c0 * c1
830
+ return {
831
+ // (c1 * v + c0) * (c0 + c1) - AB - AB * v
832
+ c0: Fp6.sub(Fp6.sub(Fp6.mul(Fp6.add(Fp6.mulByNonresidue(c1), c0), Fp6.add(c0, c1)), ab), Fp6.mulByNonresidue(ab)),
833
+ c1: Fp6.add(ab, ab),
834
+ }; // AB + AB
835
+ };
836
+ function Fp4Square(a, b) {
837
+ const a2 = Fp2.sqr(a);
838
+ const b2 = Fp2.sqr(b);
839
+ return {
840
+ first: Fp2.add(Fp2.mulByNonresidue(b2), a2),
841
+ second: Fp2.sub(Fp2.sub(Fp2.sqr(Fp2.add(a, b)), a2), b2), // (a + b)² - a² - b²
842
+ };
843
+ }
844
+ const Fp12 = {
845
+ ORDER: Fp2.ORDER,
846
+ BITS: 2 * Fp2.BITS,
847
+ BYTES: 2 * Fp2.BYTES,
848
+ MASK: bitMask(2 * Fp2.BITS),
849
+ ZERO: { c0: Fp6.ZERO, c1: Fp6.ZERO },
850
+ ONE: { c0: Fp6.ONE, c1: Fp6.ZERO },
851
+ create: (num) => num,
852
+ isValid: ({ c0, c1 }) => Fp6.isValid(c0) && Fp6.isValid(c1),
853
+ is0: ({ c0, c1 }) => Fp6.is0(c0) && Fp6.is0(c1),
854
+ neg: ({ c0, c1 }) => ({ c0: Fp6.neg(c0), c1: Fp6.neg(c1) }),
855
+ eql: ({ c0, c1 }, { c0: r0, c1: r1 }) => Fp6.eql(c0, r0) && Fp6.eql(c1, r1),
856
+ sqrt: () => {
857
+ throw new Error('Not implemented');
858
+ },
859
+ inv: ({ c0, c1 }) => {
860
+ let t = Fp6.inv(Fp6.sub(Fp6.sqr(c0), Fp6.mulByNonresidue(Fp6.sqr(c1)))); // 1 / (c0² - c1² * v)
861
+ return { c0: Fp6.mul(c0, t), c1: Fp6.neg(Fp6.mul(c1, t)) }; // ((C0 * T) * T) + (-C1 * T) * w
862
+ },
863
+ div: (lhs, rhs) => Fp12.mul(lhs, typeof rhs === 'bigint' ? Fp.inv(Fp.create(rhs)) : Fp12.inv(rhs)),
864
+ pow: (num, power) => FpPow(Fp12, num, power),
865
+ invertBatch: (nums) => FpInvertBatch(Fp12, nums),
866
+ // Normalized
867
+ add: Fp12Add,
868
+ sub: Fp12Subtract,
869
+ mul: Fp12Multiply,
870
+ sqr: Fp12Square,
871
+ // NonNormalized stuff
872
+ addN: Fp12Add,
873
+ subN: Fp12Subtract,
874
+ mulN: Fp12Multiply,
875
+ sqrN: Fp12Square,
876
+ // Bytes utils
877
+ fromBytes: (b) => {
878
+ if (b.length !== Fp12.BYTES)
879
+ throw new Error(`fromBytes wrong length=${b.length}`);
880
+ return {
881
+ c0: Fp6.fromBytes(b.subarray(0, Fp6.BYTES)),
882
+ c1: Fp6.fromBytes(b.subarray(Fp6.BYTES)),
883
+ };
884
+ },
885
+ toBytes: ({ c0, c1 }) => concatBytes(Fp6.toBytes(c0), Fp6.toBytes(c1)),
886
+ cmov: ({ c0, c1 }, { c0: r0, c1: r1 }, c) => ({
887
+ c0: Fp6.cmov(c0, r0, c),
888
+ c1: Fp6.cmov(c1, r1, c),
889
+ }),
890
+ // Utils
891
+ // toString() {
892
+ // return `Fp12(${this.c0} + ${this.c1} * w)`;
893
+ // },
894
+ // fromTuple(c: [Fp6, Fp6]) {
895
+ // return new Fp12(...c);
896
+ // }
897
+ fromBigTwelve: (t) => ({
898
+ c0: Fp6.fromBigSix(t.slice(0, 6)),
899
+ c1: Fp6.fromBigSix(t.slice(6, 12)),
900
+ }),
901
+ // Raises to q**i -th power
902
+ frobeniusMap(lhs, power) {
903
+ const r0 = Fp6.frobeniusMap(lhs.c0, power);
904
+ const { c0, c1, c2 } = Fp6.frobeniusMap(lhs.c1, power);
905
+ const coeff = FP12_FROBENIUS_COEFFICIENTS[power % 12];
906
+ return {
907
+ c0: r0,
908
+ c1: Fp6.create({
909
+ c0: Fp2.mul(c0, coeff),
910
+ c1: Fp2.mul(c1, coeff),
911
+ c2: Fp2.mul(c2, coeff),
912
+ }),
913
+ };
914
+ },
915
+ // Sparse multiplication
916
+ multiplyBy014: ({ c0, c1 }, o0, o1, o4) => {
917
+ let t0 = Fp6.multiplyBy01(c0, o0, o1);
918
+ let t1 = Fp6.multiplyBy1(c1, o4);
919
+ return {
920
+ c0: Fp6.add(Fp6.mulByNonresidue(t1), t0),
921
+ // (c1 + c0) * [o0, o1+o4] - T0 - T1
922
+ c1: Fp6.sub(Fp6.sub(Fp6.multiplyBy01(Fp6.add(c1, c0), o0, Fp2.add(o1, o4)), t0), t1),
923
+ };
924
+ },
925
+ multiplyByFp2: ({ c0, c1 }, rhs) => ({
926
+ c0: Fp6.multiplyByFp2(c0, rhs),
927
+ c1: Fp6.multiplyByFp2(c1, rhs),
928
+ }),
929
+ conjugate: ({ c0, c1 }) => ({ c0, c1: Fp6.neg(c1) }),
930
+ // A cyclotomic group is a subgroup of Fp^n defined by
931
+ // GΦₙ(p) = {α ∈ Fpⁿ : α^Φₙ(p) = 1}
932
+ // The result of any pairing is in a cyclotomic subgroup
933
+ // https://eprint.iacr.org/2009/565.pdf
934
+ _cyclotomicSquare: ({ c0, c1 }) => {
935
+ const { c0: c0c0, c1: c0c1, c2: c0c2 } = c0;
936
+ const { c0: c1c0, c1: c1c1, c2: c1c2 } = c1;
937
+ const { first: t3, second: t4 } = Fp4Square(c0c0, c1c1);
938
+ const { first: t5, second: t6 } = Fp4Square(c1c0, c0c2);
939
+ const { first: t7, second: t8 } = Fp4Square(c0c1, c1c2);
940
+ let t9 = Fp2.mulByNonresidue(t8); // T8 * (u + 1)
941
+ return {
942
+ c0: Fp6.create({
943
+ c0: Fp2.add(Fp2.mul(Fp2.sub(t3, c0c0), _2n), t3),
944
+ c1: Fp2.add(Fp2.mul(Fp2.sub(t5, c0c1), _2n), t5),
945
+ c2: Fp2.add(Fp2.mul(Fp2.sub(t7, c0c2), _2n), t7),
946
+ }),
947
+ c1: Fp6.create({
948
+ c0: Fp2.add(Fp2.mul(Fp2.add(t9, c1c0), _2n), t9),
949
+ c1: Fp2.add(Fp2.mul(Fp2.add(t4, c1c1), _2n), t4),
950
+ c2: Fp2.add(Fp2.mul(Fp2.add(t6, c1c2), _2n), t6),
951
+ }),
952
+ }; // 2 * (T6 + c1c2) + T6
953
+ },
954
+ _cyclotomicExp(num, n) {
955
+ let z = Fp12.ONE;
956
+ for (let i = BLS_X_LEN - 1; i >= 0; i--) {
957
+ z = Fp12._cyclotomicSquare(z);
958
+ if (bitGet(n, i))
959
+ z = Fp12.mul(z, num);
960
+ }
961
+ return z;
962
+ },
963
+ // https://eprint.iacr.org/2010/354.pdf
964
+ // https://eprint.iacr.org/2009/565.pdf
965
+ finalExponentiate: (num) => {
966
+ const x = BLS_X;
967
+ // this^(q⁶) / this
968
+ const t0 = Fp12.div(Fp12.frobeniusMap(num, 6), num);
969
+ // t0^(q²) * t0
970
+ const t1 = Fp12.mul(Fp12.frobeniusMap(t0, 2), t0);
971
+ const t2 = Fp12.conjugate(Fp12._cyclotomicExp(t1, x));
972
+ const t3 = Fp12.mul(Fp12.conjugate(Fp12._cyclotomicSquare(t1)), t2);
973
+ const t4 = Fp12.conjugate(Fp12._cyclotomicExp(t3, x));
974
+ const t5 = Fp12.conjugate(Fp12._cyclotomicExp(t4, x));
975
+ const t6 = Fp12.mul(Fp12.conjugate(Fp12._cyclotomicExp(t5, x)), Fp12._cyclotomicSquare(t2));
976
+ const t7 = Fp12.conjugate(Fp12._cyclotomicExp(t6, x));
977
+ const t2_t5_pow_q2 = Fp12.frobeniusMap(Fp12.mul(t2, t5), 2);
978
+ const t4_t1_pow_q3 = Fp12.frobeniusMap(Fp12.mul(t4, t1), 3);
979
+ const t6_t1c_pow_q1 = Fp12.frobeniusMap(Fp12.mul(t6, Fp12.conjugate(t1)), 1);
980
+ const t7_t3c_t1 = Fp12.mul(Fp12.mul(t7, Fp12.conjugate(t3)), t1);
981
+ // (t2 * t5)^(q²) * (t4 * t1)^(q³) * (t6 * t1.conj)^(q^1) * t7 * t3.conj * t1
982
+ return Fp12.mul(Fp12.mul(Fp12.mul(t2_t5_pow_q2, t4_t1_pow_q3), t6_t1c_pow_q1), t7_t3c_t1);
983
+ },
984
+ };
985
+ const FP12_FROBENIUS_COEFFICIENTS = [
986
+ [BigInt('0x1'), BigInt('0x0')],
987
+ [
988
+ BigInt('0x1904d3bf02bb0667c231beb4202c0d1f0fd603fd3cbd5f4f7b2443d784bab9c4f67ea53d63e7813d8d0775ed92235fb8'),
989
+ BigInt('0x00fc3e2b36c4e03288e9e902231f9fb854a14787b6c7b36fec0c8ec971f63c5f282d5ac14d6c7ec22cf78a126ddc4af3'),
990
+ ],
991
+ [
992
+ BigInt('0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffeffff'),
993
+ BigInt('0x0'),
994
+ ],
995
+ [
996
+ BigInt('0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2'),
997
+ BigInt('0x06af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09'),
998
+ ],
999
+ [
1000
+ BigInt('0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'),
1001
+ BigInt('0x0'),
1002
+ ],
1003
+ [
1004
+ BigInt('0x144e4211384586c16bd3ad4afa99cc9170df3560e77982d0db45f3536814f0bd5871c1908bd478cd1ee605167ff82995'),
1005
+ BigInt('0x05b2cfd9013a5fd8df47fa6b48b1e045f39816240c0b8fee8beadf4d8e9c0566c63a3e6e257f87329b18fae980078116'),
1006
+ ],
1007
+ [
1008
+ BigInt('0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa'),
1009
+ BigInt('0x0'),
1010
+ ],
1011
+ [
1012
+ BigInt('0x00fc3e2b36c4e03288e9e902231f9fb854a14787b6c7b36fec0c8ec971f63c5f282d5ac14d6c7ec22cf78a126ddc4af3'),
1013
+ BigInt('0x1904d3bf02bb0667c231beb4202c0d1f0fd603fd3cbd5f4f7b2443d784bab9c4f67ea53d63e7813d8d0775ed92235fb8'),
1014
+ ],
1015
+ [
1016
+ BigInt('0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'),
1017
+ BigInt('0x0'),
1018
+ ],
1019
+ [
1020
+ BigInt('0x06af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09'),
1021
+ BigInt('0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2'),
1022
+ ],
1023
+ [
1024
+ BigInt('0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad'),
1025
+ BigInt('0x0'),
1026
+ ],
1027
+ [
1028
+ BigInt('0x05b2cfd9013a5fd8df47fa6b48b1e045f39816240c0b8fee8beadf4d8e9c0566c63a3e6e257f87329b18fae980078116'),
1029
+ BigInt('0x144e4211384586c16bd3ad4afa99cc9170df3560e77982d0db45f3536814f0bd5871c1908bd478cd1ee605167ff82995'),
1030
+ ],
1031
+ ].map((n) => Fp2.fromBigTuple(n));
1032
+ // END OF CURVE FIELDS
1033
+ // HashToCurve
1034
+ // 3-isogeny map from E' to E https://www.rfc-editor.org/rfc/rfc9380#appendix-E.3
1035
+ const isogenyMapG2 = isogenyMap(Fp2, [
1036
+ // xNum
1037
+ [
1038
+ [
1039
+ '0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97d6',
1040
+ '0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97d6',
1041
+ ],
1042
+ [
1043
+ '0x0',
1044
+ '0x11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71a',
1045
+ ],
1046
+ [
1047
+ '0x11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71e',
1048
+ '0x8ab05f8bdd54cde190937e76bc3e447cc27c3d6fbd7063fcd104635a790520c0a395554e5c6aaaa9354ffffffffe38d',
1049
+ ],
1050
+ [
1051
+ '0x171d6541fa38ccfaed6dea691f5fb614cb14b4e7f4e810aa22d6108f142b85757098e38d0f671c7188e2aaaaaaaa5ed1',
1052
+ '0x0',
1053
+ ],
1054
+ ],
1055
+ // xDen
1056
+ [
1057
+ [
1058
+ '0x0',
1059
+ '0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa63',
1060
+ ],
1061
+ [
1062
+ '0xc',
1063
+ '0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa9f',
1064
+ ],
1065
+ ['0x1', '0x0'], // LAST 1
1066
+ ],
1067
+ // yNum
1068
+ [
1069
+ [
1070
+ '0x1530477c7ab4113b59a4c18b076d11930f7da5d4a07f649bf54439d87d27e500fc8c25ebf8c92f6812cfc71c71c6d706',
1071
+ '0x1530477c7ab4113b59a4c18b076d11930f7da5d4a07f649bf54439d87d27e500fc8c25ebf8c92f6812cfc71c71c6d706',
1072
+ ],
1073
+ [
1074
+ '0x0',
1075
+ '0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97be',
1076
+ ],
1077
+ [
1078
+ '0x11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71c',
1079
+ '0x8ab05f8bdd54cde190937e76bc3e447cc27c3d6fbd7063fcd104635a790520c0a395554e5c6aaaa9354ffffffffe38f',
1080
+ ],
1081
+ [
1082
+ '0x124c9ad43b6cf79bfbf7043de3811ad0761b0f37a1e26286b0e977c69aa274524e79097a56dc4bd9e1b371c71c718b10',
1083
+ '0x0',
1084
+ ],
1085
+ ],
1086
+ // yDen
1087
+ [
1088
+ [
1089
+ '0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa8fb',
1090
+ '0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa8fb',
1091
+ ],
1092
+ [
1093
+ '0x0',
1094
+ '0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa9d3',
1095
+ ],
1096
+ [
1097
+ '0x12',
1098
+ '0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa99',
1099
+ ],
1100
+ ['0x1', '0x0'], // LAST 1
1101
+ ],
1102
+ ].map((i) => i.map((pair) => Fp2.fromBigTuple(pair.map(BigInt)))));
1103
+ // 11-isogeny map from E' to E
1104
+ const isogenyMapG1 = isogenyMap(Fp, [
1105
+ // xNum
1106
+ [
1107
+ '0x11a05f2b1e833340b809101dd99815856b303e88a2d7005ff2627b56cdb4e2c85610c2d5f2e62d6eaeac1662734649b7',
1108
+ '0x17294ed3e943ab2f0588bab22147a81c7c17e75b2f6a8417f565e33c70d1e86b4838f2a6f318c356e834eef1b3cb83bb',
1109
+ '0xd54005db97678ec1d1048c5d10a9a1bce032473295983e56878e501ec68e25c958c3e3d2a09729fe0179f9dac9edcb0',
1110
+ '0x1778e7166fcc6db74e0609d307e55412d7f5e4656a8dbf25f1b33289f1b330835336e25ce3107193c5b388641d9b6861',
1111
+ '0xe99726a3199f4436642b4b3e4118e5499db995a1257fb3f086eeb65982fac18985a286f301e77c451154ce9ac8895d9',
1112
+ '0x1630c3250d7313ff01d1201bf7a74ab5db3cb17dd952799b9ed3ab9097e68f90a0870d2dcae73d19cd13c1c66f652983',
1113
+ '0xd6ed6553fe44d296a3726c38ae652bfb11586264f0f8ce19008e218f9c86b2a8da25128c1052ecaddd7f225a139ed84',
1114
+ '0x17b81e7701abdbe2e8743884d1117e53356de5ab275b4db1a682c62ef0f2753339b7c8f8c8f475af9ccb5618e3f0c88e',
1115
+ '0x80d3cf1f9a78fc47b90b33563be990dc43b756ce79f5574a2c596c928c5d1de4fa295f296b74e956d71986a8497e317',
1116
+ '0x169b1f8e1bcfa7c42e0c37515d138f22dd2ecb803a0c5c99676314baf4bb1b7fa3190b2edc0327797f241067be390c9e',
1117
+ '0x10321da079ce07e272d8ec09d2565b0dfa7dccdde6787f96d50af36003b14866f69b771f8c285decca67df3f1605fb7b',
1118
+ '0x6e08c248e260e70bd1e962381edee3d31d79d7e22c837bc23c0bf1bc24c6b68c24b1b80b64d391fa9c8ba2e8ba2d229',
1119
+ ],
1120
+ // xDen
1121
+ [
1122
+ '0x8ca8d548cff19ae18b2e62f4bd3fa6f01d5ef4ba35b48ba9c9588617fc8ac62b558d681be343df8993cf9fa40d21b1c',
1123
+ '0x12561a5deb559c4348b4711298e536367041e8ca0cf0800c0126c2588c48bf5713daa8846cb026e9e5c8276ec82b3bff',
1124
+ '0xb2962fe57a3225e8137e629bff2991f6f89416f5a718cd1fca64e00b11aceacd6a3d0967c94fedcfcc239ba5cb83e19',
1125
+ '0x3425581a58ae2fec83aafef7c40eb545b08243f16b1655154cca8abc28d6fd04976d5243eecf5c4130de8938dc62cd8',
1126
+ '0x13a8e162022914a80a6f1d5f43e7a07dffdfc759a12062bb8d6b44e833b306da9bd29ba81f35781d539d395b3532a21e',
1127
+ '0xe7355f8e4e667b955390f7f0506c6e9395735e9ce9cad4d0a43bcef24b8982f7400d24bc4228f11c02df9a29f6304a5',
1128
+ '0x772caacf16936190f3e0c63e0596721570f5799af53a1894e2e073062aede9cea73b3538f0de06cec2574496ee84a3a',
1129
+ '0x14a7ac2a9d64a8b230b3f5b074cf01996e7f63c21bca68a81996e1cdf9822c580fa5b9489d11e2d311f7d99bbdcc5a5e',
1130
+ '0xa10ecf6ada54f825e920b3dafc7a3cce07f8d1d7161366b74100da67f39883503826692abba43704776ec3a79a1d641',
1131
+ '0x95fc13ab9e92ad4476d6e3eb3a56680f682b4ee96f7d03776df533978f31c1593174e4b4b7865002d6384d168ecdd0a',
1132
+ '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001', // LAST 1
1133
+ ],
1134
+ // yNum
1135
+ [
1136
+ '0x90d97c81ba24ee0259d1f094980dcfa11ad138e48a869522b52af6c956543d3cd0c7aee9b3ba3c2be9845719707bb33',
1137
+ '0x134996a104ee5811d51036d776fb46831223e96c254f383d0f906343eb67ad34d6c56711962fa8bfe097e75a2e41c696',
1138
+ '0xcc786baa966e66f4a384c86a3b49942552e2d658a31ce2c344be4b91400da7d26d521628b00523b8dfe240c72de1f6',
1139
+ '0x1f86376e8981c217898751ad8746757d42aa7b90eeb791c09e4a3ec03251cf9de405aba9ec61deca6355c77b0e5f4cb',
1140
+ '0x8cc03fdefe0ff135caf4fe2a21529c4195536fbe3ce50b879833fd221351adc2ee7f8dc099040a841b6daecf2e8fedb',
1141
+ '0x16603fca40634b6a2211e11db8f0a6a074a7d0d4afadb7bd76505c3d3ad5544e203f6326c95a807299b23ab13633a5f0',
1142
+ '0x4ab0b9bcfac1bbcb2c977d027796b3ce75bb8ca2be184cb5231413c4d634f3747a87ac2460f415ec961f8855fe9d6f2',
1143
+ '0x987c8d5333ab86fde9926bd2ca6c674170a05bfe3bdd81ffd038da6c26c842642f64550fedfe935a15e4ca31870fb29',
1144
+ '0x9fc4018bd96684be88c9e221e4da1bb8f3abd16679dc26c1e8b6e6a1f20cabe69d65201c78607a360370e577bdba587',
1145
+ '0xe1bba7a1186bdb5223abde7ada14a23c42a0ca7915af6fe06985e7ed1e4d43b9b3f7055dd4eba6f2bafaaebca731c30',
1146
+ '0x19713e47937cd1be0dfd0b8f1d43fb93cd2fcbcb6caf493fd1183e416389e61031bf3a5cce3fbafce813711ad011c132',
1147
+ '0x18b46a908f36f6deb918c143fed2edcc523559b8aaf0c2462e6bfe7f911f643249d9cdf41b44d606ce07c8a4d0074d8e',
1148
+ '0xb182cac101b9399d155096004f53f447aa7b12a3426b08ec02710e807b4633f06c851c1919211f20d4c04f00b971ef8',
1149
+ '0x245a394ad1eca9b72fc00ae7be315dc757b3b080d4c158013e6632d3c40659cc6cf90ad1c232a6442d9d3f5db980133',
1150
+ '0x5c129645e44cf1102a159f748c4a3fc5e673d81d7e86568d9ab0f5d396a7ce46ba1049b6579afb7866b1e715475224b',
1151
+ '0x15e6be4e990f03ce4ea50b3b42df2eb5cb181d8f84965a3957add4fa95af01b2b665027efec01c7704b456be69c8b604',
1152
+ ],
1153
+ // yDen
1154
+ [
1155
+ '0x16112c4c3a9c98b252181140fad0eae9601a6de578980be6eec3232b5be72e7a07f3688ef60c206d01479253b03663c1',
1156
+ '0x1962d75c2381201e1a0cbd6c43c348b885c84ff731c4d59ca4a10356f453e01f78a4260763529e3532f6102c2e49a03d',
1157
+ '0x58df3306640da276faaae7d6e8eb15778c4855551ae7f310c35a5dd279cd2eca6757cd636f96f891e2538b53dbf67f2',
1158
+ '0x16b7d288798e5395f20d23bf89edb4d1d115c5dbddbcd30e123da489e726af41727364f2c28297ada8d26d98445f5416',
1159
+ '0xbe0e079545f43e4b00cc912f8228ddcc6d19c9f0f69bbb0542eda0fc9dec916a20b15dc0fd2ededda39142311a5001d',
1160
+ '0x8d9e5297186db2d9fb266eaac783182b70152c65550d881c5ecd87b6f0f5a6449f38db9dfa9cce202c6477faaf9b7ac',
1161
+ '0x166007c08a99db2fc3ba8734ace9824b5eecfdfa8d0cf8ef5dd365bc400a0051d5fa9c01a58b1fb93d1a1399126a775c',
1162
+ '0x16a3ef08be3ea7ea03bcddfabba6ff6ee5a4375efa1f4fd7feb34fd206357132b920f5b00801dee460ee415a15812ed9',
1163
+ '0x1866c8ed336c61231a1be54fd1d74cc4f9fb0ce4c6af5920abc5750c4bf39b4852cfe2f7bb9248836b233d9d55535d4a',
1164
+ '0x167a55cda70a6e1cea820597d94a84903216f763e13d87bb5308592e7ea7d4fbc7385ea3d529b35e346ef48bb8913f55',
1165
+ '0x4d2f259eea405bd48f010a01ad2911d9c6dd039bb61a6290e591b36e636a5c871a5c29f4f83060400f8b49cba8f6aa8',
1166
+ '0xaccbb67481d033ff5852c1e48c50c477f94ff8aefce42d28c0f9a88cea7913516f968986f7ebbea9684b529e2561092',
1167
+ '0xad6b9514c767fe3c3613144b45f1496543346d98adf02267d5ceef9a00d9b8693000763e3b90ac11e99b138573345cc',
1168
+ '0x2660400eb2e4f3b628bdd0d53cd76f2bf565b94e72927c1cb748df27942480e420517bd8714cc80d1fadc1326ed06f7',
1169
+ '0xe0fa1d816ddc03e6b24255e0d7819c171c40f65e273b853324efcd6356caa205ca2f570f13497804415473a1d634b8f',
1170
+ '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001', // LAST 1
1171
+ ],
1172
+ ].map((i) => i.map((j) => BigInt(j))));
1173
+ // SWU Map - Fp2 to G2': y² = x³ + 240i * x + 1012 + 1012i
1174
+ const G2_SWU = mapToCurveSimpleSWU(Fp2, {
1175
+ A: Fp2.create({ c0: Fp.create(_0n), c1: Fp.create(BigInt(240)) }),
1176
+ B: Fp2.create({ c0: Fp.create(BigInt(1012)), c1: Fp.create(BigInt(1012)) }),
1177
+ Z: Fp2.create({ c0: Fp.create(BigInt(-2)), c1: Fp.create(BigInt(-1)) }), // Z: -(2 + I)
1178
+ });
1179
+ // Optimized SWU Map - Fp to G1
1180
+ const G1_SWU = mapToCurveSimpleSWU(Fp, {
1181
+ A: Fp.create(BigInt('0x144698a3b8e9433d693a02c96d4982b0ea985383ee66a8d8e8981aefd881ac98936f8da0e0f97f5cf428082d584c1d')),
1182
+ B: Fp.create(BigInt('0x12e2908d11688030018b12e8753eee3b2016c1f0f24f4070a0b9c14fcef35ef55a23215a316ceaa5d1cc48e98e172be0')),
1183
+ Z: Fp.create(BigInt(11)),
1184
+ });
1185
+ // Endomorphisms (for fast cofactor clearing)
1186
+ // Ψ(P) endomorphism
1187
+ const ut_root = Fp6.create({ c0: Fp2.ZERO, c1: Fp2.ONE, c2: Fp2.ZERO });
1188
+ const wsq = Fp12.create({ c0: ut_root, c1: Fp6.ZERO });
1189
+ const wcu = Fp12.create({ c0: Fp6.ZERO, c1: ut_root });
1190
+ const [wsq_inv, wcu_inv] = Fp12.invertBatch([wsq, wcu]);
1191
+ function psi(x, y) {
1192
+ // Untwist Fp2->Fp12 && frobenius(1) && twist back
1193
+ const x2 = Fp12.mul(Fp12.frobeniusMap(Fp12.multiplyByFp2(wsq_inv, x), 1), wsq).c0.c0;
1194
+ const y2 = Fp12.mul(Fp12.frobeniusMap(Fp12.multiplyByFp2(wcu_inv, y), 1), wcu).c0.c0;
1195
+ return [x2, y2];
1196
+ }
1197
+ // Ψ endomorphism
1198
+ function G2psi(c, P) {
1199
+ const affine = P.toAffine();
1200
+ const p = psi(affine.x, affine.y);
1201
+ return new c(p[0], p[1], Fp2.ONE);
1202
+ }
1203
+ // Ψ²(P) endomorphism
1204
+ // 1 / F2(2)^((p-1)/3) in GF(p²)
1205
+ const PSI2_C1 = BigInt('0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac');
1206
+ function psi2(x, y) {
1207
+ return [Fp2.mul(x, PSI2_C1), Fp2.neg(y)];
1208
+ }
1209
+ function G2psi2(c, P) {
1210
+ const affine = P.toAffine();
1211
+ const p = psi2(affine.x, affine.y);
1212
+ return new c(p[0], p[1], Fp2.ONE);
1213
+ }
1214
+ // Default hash_to_field options are for hash to G2.
1215
+ //
1216
+ // Parameter definitions are in section 5.3 of the spec unless otherwise noted.
1217
+ // Parameter values come from section 8.8.2 of the spec.
1218
+ // https://www.rfc-editor.org/rfc/rfc9380#section-8.8.2
1219
+ //
1220
+ // Base field F is GF(p^m)
1221
+ // p = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab
1222
+ // m = 2 (or 1 for G1 see section 8.8.1)
1223
+ // k = 128
1224
+ const htfDefaults = Object.freeze({
1225
+ // DST: a domain separation tag
1226
+ // defined in section 2.2.5
1227
+ // Use utils.getDSTLabel(), utils.setDSTLabel(value)
1228
+ DST: 'BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_',
1229
+ encodeDST: 'BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_',
1230
+ // p: the characteristic of F
1231
+ // where F is a finite field of characteristic p and order q = p^m
1232
+ p: Fp.ORDER,
1233
+ // m: the extension degree of F, m >= 1
1234
+ // where F is a finite field of characteristic p and order q = p^m
1235
+ m: 2,
1236
+ // k: the target security level for the suite in bits
1237
+ // defined in section 5.1
1238
+ k: 128,
1239
+ // option to use a message that has already been processed by
1240
+ // expand_message_xmd
1241
+ expand: 'xmd',
1242
+ // Hash functions for: expand_message_xmd is appropriate for use with a
1243
+ // wide range of hash functions, including SHA-2, SHA-3, BLAKE2, and others.
1244
+ // BBS+ uses blake2: https://github.com/hyperledger/aries-framework-go/issues/2247
1245
+ hash: sha256,
1246
+ });
1247
+ // Encoding utils
1248
+ // Point on G1 curve: (x, y)
1249
+ const C_BIT_POS = Fp.BITS; // C_bit, compression bit for serialization flag
1250
+ const I_BIT_POS = Fp.BITS + 1; // I_bit, point-at-infinity bit for serialization flag
1251
+ const S_BIT_POS = Fp.BITS + 2; // S_bit, sign bit for serialization flag
1252
+ // Compressed point of infinity
1253
+ const COMPRESSED_ZERO = Fp.toBytes(bitSet(bitSet(_0n, I_BIT_POS, true), S_BIT_POS, true)); // set compressed & point-at-infinity bits
1254
+ function signatureG2ToRawBytes(point) {
1255
+ // NOTE: by some reasons it was missed in bls12-381, looks like bug
1256
+ point.assertValidity();
1257
+ const len = Fp.BYTES;
1258
+ if (point.equals(bls12_381.G2.ProjectivePoint.ZERO))
1259
+ return concatBytes(COMPRESSED_ZERO, numberToBytesBE(_0n, len));
1260
+ const { x, y } = point.toAffine();
1261
+ const { re: x0, im: x1 } = Fp2.reim(x);
1262
+ const { re: y0, im: y1 } = Fp2.reim(y);
1263
+ const tmp = y1 > _0n ? y1 * _2n : y0 * _2n;
1264
+ const aflag1 = Boolean((tmp / Fp.ORDER) & _1n);
1265
+ const z1 = bitSet(bitSet(x1, 381, aflag1), S_BIT_POS, true);
1266
+ const z2 = x0;
1267
+ return concatBytes(numberToBytesBE(z1, len), numberToBytesBE(z2, len));
1268
+ }
1269
+ // To verify curve parameters, see pairing-friendly-curves spec:
1270
+ // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-11
1271
+ // Basic math is done over finite fields over p.
1272
+ // More complicated math is done over polynominal extension fields.
1273
+ // To simplify calculations in Fp12, we construct extension tower:
1274
+ // Fp₁₂ = Fp₆² => Fp₂³
1275
+ // Fp(u) / (u² - β) where β = -1
1276
+ // Fp₂(v) / (v³ - ξ) where ξ = u + 1
1277
+ // Fp₆(w) / (w² - γ) where γ = v
1278
+ // Here goes constants && point encoding format
1279
+ const bls12_381 = bls({
1280
+ // Fields
1281
+ fields: {
1282
+ Fp,
1283
+ Fp2,
1284
+ Fp6,
1285
+ Fp12,
1286
+ Fr: Fr$1,
1287
+ },
1288
+ // G1 is the order-q subgroup of E1(Fp) : y² = x³ + 4, #E1(Fp) = h1q, where
1289
+ // characteristic; z + (z⁴ - z² + 1)(z - 1)²/3
1290
+ G1: {
1291
+ Fp,
1292
+ // cofactor; (z - 1)²/3
1293
+ h: BigInt('0x396c8c005555e1568c00aaab0000aaab'),
1294
+ // generator's coordinates
1295
+ // x = 3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507
1296
+ // y = 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569
1297
+ Gx: BigInt('0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb'),
1298
+ Gy: BigInt('0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1'),
1299
+ a: Fp.ZERO,
1300
+ b: _4n,
1301
+ htfDefaults: { ...htfDefaults, m: 1 },
1302
+ wrapPrivateKey: true,
1303
+ allowInfinityPoint: true,
1304
+ // Checks is the point resides in prime-order subgroup.
1305
+ // point.isTorsionFree() should return true for valid points
1306
+ // It returns false for shitty points.
1307
+ // https://eprint.iacr.org/2021/1130.pdf
1308
+ isTorsionFree: (c, point) => {
1309
+ // φ endomorphism
1310
+ const cubicRootOfUnityModP = BigInt('0x5f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe');
1311
+ const phi = new c(Fp.mul(point.px, cubicRootOfUnityModP), point.py, point.pz);
1312
+ // todo: unroll
1313
+ const xP = point.multiplyUnsafe(bls12_381.params.x).negate(); // [x]P
1314
+ const u2P = xP.multiplyUnsafe(bls12_381.params.x); // [u2]P
1315
+ return u2P.equals(phi);
1316
+ // https://eprint.iacr.org/2019/814.pdf
1317
+ // (z² − 1)/3
1318
+ // const c1 = BigInt('0x396c8c005555e1560000000055555555');
1319
+ // const P = this;
1320
+ // const S = P.sigma();
1321
+ // const Q = S.double();
1322
+ // const S2 = S.sigma();
1323
+ // // [(z² − 1)/3](2σ(P) − P − σ²(P)) − σ²(P) = O
1324
+ // const left = Q.subtract(P).subtract(S2).multiplyUnsafe(c1);
1325
+ // const C = left.subtract(S2);
1326
+ // return C.isZero();
1327
+ },
1328
+ // Clear cofactor of G1
1329
+ // https://eprint.iacr.org/2019/403
1330
+ clearCofactor: (_c, point) => {
1331
+ // return this.multiplyUnsafe(CURVE.h);
1332
+ return point.multiplyUnsafe(bls12_381.params.x).add(point); // x*P + P
1333
+ },
1334
+ mapToCurve: (scalars) => {
1335
+ const { x, y } = G1_SWU(Fp.create(scalars[0]));
1336
+ return isogenyMapG1(x, y);
1337
+ },
1338
+ fromBytes: (bytes) => {
1339
+ bytes = bytes.slice();
1340
+ if (bytes.length === 48) {
1341
+ // TODO: Fp.bytes
1342
+ const P = Fp.ORDER;
1343
+ const compressedValue = bytesToNumberBE(bytes);
1344
+ const bflag = bitGet(compressedValue, I_BIT_POS);
1345
+ // Zero
1346
+ if (bflag === _1n)
1347
+ return { x: _0n, y: _0n };
1348
+ const x = Fp.create(compressedValue & Fp.MASK);
1349
+ const right = Fp.add(Fp.pow(x, _3n), Fp.create(bls12_381.params.G1b)); // y² = x³ + b
1350
+ let y = Fp.sqrt(right);
1351
+ if (!y)
1352
+ throw new Error('Invalid compressed G1 point');
1353
+ const aflag = bitGet(compressedValue, C_BIT_POS);
1354
+ if ((y * _2n) / P !== aflag)
1355
+ y = Fp.neg(y);
1356
+ return { x: Fp.create(x), y: Fp.create(y) };
1357
+ }
1358
+ else if (bytes.length === 96) {
1359
+ // Check if the infinity flag is set
1360
+ if ((bytes[0] & (1 << 6)) !== 0)
1361
+ return bls12_381.G1.ProjectivePoint.ZERO.toAffine();
1362
+ const x = bytesToNumberBE(bytes.subarray(0, Fp.BYTES));
1363
+ const y = bytesToNumberBE(bytes.subarray(Fp.BYTES));
1364
+ return { x: Fp.create(x), y: Fp.create(y) };
1365
+ }
1366
+ else {
1367
+ throw new Error('Invalid point G1, expected 48/96 bytes');
1368
+ }
1369
+ },
1370
+ toBytes: (c, point, isCompressed) => {
1371
+ const isZero = point.equals(c.ZERO);
1372
+ const { x, y } = point.toAffine();
1373
+ if (isCompressed) {
1374
+ if (isZero)
1375
+ return COMPRESSED_ZERO.slice();
1376
+ const P = Fp.ORDER;
1377
+ let num;
1378
+ num = bitSet(x, C_BIT_POS, Boolean((y * _2n) / P)); // set aflag
1379
+ num = bitSet(num, S_BIT_POS, true);
1380
+ return numberToBytesBE(num, Fp.BYTES);
1381
+ }
1382
+ else {
1383
+ if (isZero) {
1384
+ // 2x PUBLIC_KEY_LENGTH
1385
+ const x = concatBytes(new Uint8Array([0x40]), new Uint8Array(2 * Fp.BYTES - 1));
1386
+ return x;
1387
+ }
1388
+ else {
1389
+ return concatBytes(numberToBytesBE(x, Fp.BYTES), numberToBytesBE(y, Fp.BYTES));
1390
+ }
1391
+ }
1392
+ },
1393
+ },
1394
+ // G2 is the order-q subgroup of E2(Fp²) : y² = x³+4(1+√−1),
1395
+ // where Fp2 is Fp[√−1]/(x2+1). #E2(Fp2 ) = h2q, where
1396
+ // G² - 1
1397
+ // h2q
1398
+ G2: {
1399
+ Fp: Fp2,
1400
+ // cofactor
1401
+ h: BigInt('0x5d543a95414e7f1091d50792876a202cd91de4547085abaa68a205b2e5a7ddfa628f1cb4d9e82ef21537e293a6691ae1616ec6e786f0c70cf1c38e31c7238e5'),
1402
+ Gx: Fp2.fromBigTuple([
1403
+ BigInt('0x024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8'),
1404
+ BigInt('0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e'),
1405
+ ]),
1406
+ // y =
1407
+ // 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582,
1408
+ // 1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905
1409
+ Gy: Fp2.fromBigTuple([
1410
+ BigInt('0x0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801'),
1411
+ BigInt('0x0606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be'),
1412
+ ]),
1413
+ a: Fp2.ZERO,
1414
+ b: Fp2.fromBigTuple([_4n, _4n]),
1415
+ hEff: BigInt('0xbc69f08f2ee75b3584c6a0ea91b352888e2a8e9145ad7689986ff031508ffe1329c2f178731db956d82bf015d1212b02ec0ec69d7477c1ae954cbc06689f6a359894c0adebbf6b4e8020005aaa95551'),
1416
+ htfDefaults: { ...htfDefaults },
1417
+ wrapPrivateKey: true,
1418
+ allowInfinityPoint: true,
1419
+ mapToCurve: (scalars) => {
1420
+ const { x, y } = G2_SWU(Fp2.fromBigTuple(scalars));
1421
+ return isogenyMapG2(x, y);
1422
+ },
1423
+ // Checks is the point resides in prime-order subgroup.
1424
+ // point.isTorsionFree() should return true for valid points
1425
+ // It returns false for shitty points.
1426
+ // https://eprint.iacr.org/2021/1130.pdf
1427
+ isTorsionFree: (c, P) => {
1428
+ return P.multiplyUnsafe(bls12_381.params.x).negate().equals(G2psi(c, P)); // ψ(P) == [u](P)
1429
+ // Older version: https://eprint.iacr.org/2019/814.pdf
1430
+ // Ψ²(P) => Ψ³(P) => [z]Ψ³(P) where z = -x => [z]Ψ³(P) - Ψ²(P) + P == O
1431
+ // return P.psi2().psi().mulNegX().subtract(psi2).add(P).isZero();
1432
+ },
1433
+ // Maps the point into the prime-order subgroup G2.
1434
+ // clear_cofactor_bls12381_g2 from cfrg-hash-to-curve-11
1435
+ // https://eprint.iacr.org/2017/419.pdf
1436
+ // prettier-ignore
1437
+ clearCofactor: (c, P) => {
1438
+ const x = bls12_381.params.x;
1439
+ let t1 = P.multiplyUnsafe(x).negate(); // [-x]P
1440
+ let t2 = G2psi(c, P); // Ψ(P)
1441
+ let t3 = P.double(); // 2P
1442
+ t3 = G2psi2(c, t3); // Ψ²(2P)
1443
+ t3 = t3.subtract(t2); // Ψ²(2P) - Ψ(P)
1444
+ t2 = t1.add(t2); // [-x]P + Ψ(P)
1445
+ t2 = t2.multiplyUnsafe(x).negate(); // [x²]P - [x]Ψ(P)
1446
+ t3 = t3.add(t2); // Ψ²(2P) - Ψ(P) + [x²]P - [x]Ψ(P)
1447
+ t3 = t3.subtract(t1); // Ψ²(2P) - Ψ(P) + [x²]P - [x]Ψ(P) + [x]P
1448
+ const Q = t3.subtract(P); // Ψ²(2P) - Ψ(P) + [x²]P - [x]Ψ(P) + [x]P - 1P
1449
+ return Q; // [x²-x-1]P + [x-1]Ψ(P) + Ψ²(2P)
1450
+ },
1451
+ fromBytes: (bytes) => {
1452
+ bytes = bytes.slice();
1453
+ const m_byte = bytes[0] & 0xe0;
1454
+ if (m_byte === 0x20 || m_byte === 0x60 || m_byte === 0xe0) {
1455
+ throw new Error('Invalid encoding flag: ' + m_byte);
1456
+ }
1457
+ const bitC = m_byte & 0x80; // compression bit
1458
+ const bitI = m_byte & 0x40; // point at infinity bit
1459
+ const bitS = m_byte & 0x20; // sign bit
1460
+ const L = Fp.BYTES;
1461
+ const slc = (b, from, to) => bytesToNumberBE(b.slice(from, to));
1462
+ if (bytes.length === 96 && bitC) {
1463
+ const b = bls12_381.params.G2b;
1464
+ const P = Fp.ORDER;
1465
+ bytes[0] = bytes[0] & 0x1f; // clear flags
1466
+ if (bitI) {
1467
+ // check that all bytes are 0
1468
+ if (bytes.reduce((p, c) => (p !== 0 ? c + 1 : c), 0) > 0) {
1469
+ throw new Error('Invalid compressed G2 point');
1470
+ }
1471
+ return { x: Fp2.ZERO, y: Fp2.ZERO };
1472
+ }
1473
+ const x_1 = slc(bytes, 0, L);
1474
+ const x_0 = slc(bytes, L, 2 * L);
1475
+ const x = Fp2.create({ c0: Fp.create(x_0), c1: Fp.create(x_1) });
1476
+ const right = Fp2.add(Fp2.pow(x, _3n), b); // y² = x³ + 4 * (u+1) = x³ + b
1477
+ let y = Fp2.sqrt(right);
1478
+ const Y_bit = y.c1 === _0n ? (y.c0 * _2n) / P : (y.c1 * _2n) / P ? _1n : _0n;
1479
+ y = bitS > 0 && Y_bit > 0 ? y : Fp2.neg(y);
1480
+ return { x, y };
1481
+ }
1482
+ else if (bytes.length === 192 && !bitC) {
1483
+ // Check if the infinity flag is set
1484
+ if ((bytes[0] & (1 << 6)) !== 0) {
1485
+ return { x: Fp2.ZERO, y: Fp2.ZERO };
1486
+ }
1487
+ const x1 = slc(bytes, 0, L);
1488
+ const x0 = slc(bytes, L, 2 * L);
1489
+ const y1 = slc(bytes, 2 * L, 3 * L);
1490
+ const y0 = slc(bytes, 3 * L, 4 * L);
1491
+ return { x: Fp2.fromBigTuple([x0, x1]), y: Fp2.fromBigTuple([y0, y1]) };
1492
+ }
1493
+ else {
1494
+ throw new Error('Invalid point G2, expected 96/192 bytes');
1495
+ }
1496
+ },
1497
+ toBytes: (c, point, isCompressed) => {
1498
+ const { BYTES: len, ORDER: P } = Fp;
1499
+ const isZero = point.equals(c.ZERO);
1500
+ const { x, y } = point.toAffine();
1501
+ if (isCompressed) {
1502
+ if (isZero)
1503
+ return concatBytes(COMPRESSED_ZERO, numberToBytesBE(_0n, len));
1504
+ const flag = Boolean(y.c1 === _0n ? (y.c0 * _2n) / P : (y.c1 * _2n) / P);
1505
+ // set compressed & sign bits (looks like different offsets than for G1/Fp?)
1506
+ let x_1 = bitSet(x.c1, C_BIT_POS, flag);
1507
+ x_1 = bitSet(x_1, S_BIT_POS, true);
1508
+ return concatBytes(numberToBytesBE(x_1, len), numberToBytesBE(x.c0, len));
1509
+ }
1510
+ else {
1511
+ if (isZero)
1512
+ return concatBytes(new Uint8Array([0x40]), new Uint8Array(4 * len - 1)); // bytes[0] |= 1 << 6;
1513
+ const { re: x0, im: x1 } = Fp2.reim(x);
1514
+ const { re: y0, im: y1 } = Fp2.reim(y);
1515
+ return concatBytes(numberToBytesBE(x1, len), numberToBytesBE(x0, len), numberToBytesBE(y1, len), numberToBytesBE(y0, len));
1516
+ }
1517
+ },
1518
+ Signature: {
1519
+ // TODO: Optimize, it's very slow because of sqrt.
1520
+ fromHex(hex) {
1521
+ hex = ensureBytes('signatureHex', hex);
1522
+ const P = Fp.ORDER;
1523
+ const half = hex.length / 2;
1524
+ if (half !== 48 && half !== 96)
1525
+ throw new Error('Invalid compressed signature length, must be 96 or 192');
1526
+ const z1 = bytesToNumberBE(hex.slice(0, half));
1527
+ const z2 = bytesToNumberBE(hex.slice(half));
1528
+ // Indicates the infinity point
1529
+ const bflag1 = bitGet(z1, I_BIT_POS);
1530
+ if (bflag1 === _1n)
1531
+ return bls12_381.G2.ProjectivePoint.ZERO;
1532
+ const x1 = Fp.create(z1 & Fp.MASK);
1533
+ const x2 = Fp.create(z2);
1534
+ const x = Fp2.create({ c0: x2, c1: x1 });
1535
+ const y2 = Fp2.add(Fp2.pow(x, _3n), bls12_381.params.G2b); // y² = x³ + 4
1536
+ // The slow part
1537
+ let y = Fp2.sqrt(y2);
1538
+ if (!y)
1539
+ throw new Error('Failed to find a square root');
1540
+ // Choose the y whose leftmost bit of the imaginary part is equal to the a_flag1
1541
+ // If y1 happens to be zero, then use the bit of y0
1542
+ const { re: y0, im: y1 } = Fp2.reim(y);
1543
+ const aflag1 = bitGet(z1, 381);
1544
+ const isGreater = y1 > _0n && (y1 * _2n) / P !== aflag1;
1545
+ const isZero = y1 === _0n && (y0 * _2n) / P !== aflag1;
1546
+ if (isGreater || isZero)
1547
+ y = Fp2.neg(y);
1548
+ const point = bls12_381.G2.ProjectivePoint.fromAffine({ x, y });
1549
+ point.assertValidity();
1550
+ return point;
1551
+ },
1552
+ toRawBytes(point) {
1553
+ return signatureG2ToRawBytes(point);
1554
+ },
1555
+ toHex(point) {
1556
+ return bytesToHex(signatureG2ToRawBytes(point));
1557
+ },
1558
+ },
1559
+ },
1560
+ params: {
1561
+ x: BLS_X,
1562
+ r: Fr$1.ORDER, // order; z⁴ − z² + 1; CURVE.n from other curves
1563
+ },
1564
+ htfDefaults,
1565
+ hash: sha256,
1566
+ randomBytes,
1567
+ });
1568
+
1569
+ const encoder = new TextEncoder();
1570
+ const Fr = bls12_381.fields.Fr;
1571
+ const G1 = bls12_381.G1.ProjectivePoint;
1572
+ const G2 = bls12_381.G2.ProjectivePoint;
1573
+ const assertParticipant = (participant) => {
1574
+ if (typeof participant !== "bigint" || participant <= 0n || participant >= Fr.ORDER) {
1575
+ throw new TypeError("beacon participant identifiers must be non-zero field elements");
1576
+ }
1577
+ };
1578
+ const assertThreshold = (threshold, participantCount) => {
1579
+ if (!Number.isSafeInteger(threshold) || threshold < 2 || threshold > participantCount) {
1580
+ throw new RangeError("beacon threshold must be between 2 and the participant count");
1581
+ }
1582
+ };
1583
+ const assertUniqueParticipants = (participants) => {
1584
+ for (const participant of participants) assertParticipant(participant);
1585
+ if (new Set(participants).size !== participants.length) throw new Error("duplicate beacon participant");
1586
+ };
1587
+ const evaluatePolynomial = (coefficients, x) => {
1588
+ let result = 0n;
1589
+ for (let index = coefficients.length - 1; index >= 0; index -= 1) {
1590
+ result = Fr.add(Fr.mul(result, x), coefficients[index]);
1591
+ }
1592
+ return result;
1593
+ };
1594
+ const evaluateCommitments = (commitments, x) => {
1595
+ let result = G1.ZERO;
1596
+ let power = 1n;
1597
+ for (const encoded of commitments) {
1598
+ const commitment = G1.fromHex(encoded);
1599
+ commitment.assertValidity();
1600
+ result = result.add(commitment.multiply(power));
1601
+ power = Fr.mul(power, x);
1602
+ }
1603
+ return result;
1604
+ };
1605
+ const sumPoints = (points) => {
1606
+ let result = G1.ZERO;
1607
+ for (const encoded of points) {
1608
+ const point = G1.fromHex(encoded);
1609
+ point.assertValidity();
1610
+ result = result.add(point);
1611
+ }
1612
+ return result;
1613
+ };
1614
+ const lagrangeAtZero = (participant, participants) => {
1615
+ let numerator = 1n;
1616
+ let denominator = 1n;
1617
+ for (const other of participants) {
1618
+ if (other === participant) continue;
1619
+ numerator = Fr.mul(numerator, Fr.neg(other));
1620
+ denominator = Fr.mul(denominator, Fr.sub(participant, other));
1621
+ }
1622
+ return Fr.mul(numerator, Fr.inv(denominator));
1623
+ };
1624
+ const createBeaconContribution = (participants, threshold, randomScalar) => {
1625
+ assertUniqueParticipants(participants);
1626
+ assertThreshold(threshold, participants.length);
1627
+ const coefficients = Array.from({ length: threshold }, () => {
1628
+ const scalar = Fr.create(randomScalar());
1629
+ if (scalar === 0n) throw new Error("beacon contribution contains a zero coefficient");
1630
+ return scalar;
1631
+ });
1632
+ return {
1633
+ commitments: coefficients.map((coefficient) => G1.BASE.multiply(coefficient).toRawBytes(true)),
1634
+ shares: new Map(participants.map((participant) => [participant, evaluatePolynomial(coefficients, participant)]))
1635
+ };
1636
+ };
1637
+ const verifyBeaconShare = (participant, share, commitments) => {
1638
+ try {
1639
+ assertParticipant(participant);
1640
+ if (commitments.length < 2) return false;
1641
+ return G1.BASE.multiply(Fr.create(share)).equals(evaluateCommitments(commitments, participant));
1642
+ } catch {
1643
+ return false;
1644
+ }
1645
+ };
1646
+ const combineBeaconShares = (shares) => {
1647
+ if (shares.length < 2) throw new Error("at least two dealer shares are required");
1648
+ return shares.reduce((total, share) => Fr.add(total, Fr.create(share)), 0n);
1649
+ };
1650
+ const deriveBeaconPublicShare = (participant, dealerCommitments) => {
1651
+ assertParticipant(participant);
1652
+ if (dealerCommitments.length < 2) throw new Error("at least two dealer commitments are required");
1653
+ return sumPoints(
1654
+ dealerCommitments.map((commitments) => evaluateCommitments(commitments, participant).toRawBytes(true))
1655
+ ).toRawBytes(true);
1656
+ };
1657
+ const deriveBeaconGroupPublicKey = (dealerCommitments) => {
1658
+ if (dealerCommitments.length < 2 || dealerCommitments.some((commitments) => commitments.length < 2)) {
1659
+ throw new Error("invalid beacon dealer commitments");
1660
+ }
1661
+ return sumPoints(dealerCommitments.map((commitments) => commitments[0])).toRawBytes(true);
1662
+ };
1663
+ const beaconMessage = (network, epoch, round, previousProof) => {
1664
+ if (!network || epoch < 0n || round < 0n) throw new TypeError("invalid beacon round");
1665
+ const prefix = encoder.encode(`leofcoin-beacon-v1:${network}:${epoch}:${round}:`);
1666
+ const message = new Uint8Array(prefix.length + previousProof.length);
1667
+ message.set(prefix);
1668
+ message.set(previousProof, prefix.length);
1669
+ return message;
1670
+ };
1671
+ const signBeaconRound = (secretShare, message) => bls12_381.sign(message, Fr.create(secretShare));
1672
+ const verifyBeaconSignatureShare = (signature, message, publicShare) => {
1673
+ try {
1674
+ return bls12_381.verify(signature, message, publicShare);
1675
+ } catch {
1676
+ return false;
1677
+ }
1678
+ };
1679
+ const reconstructBeaconSignature = (rawShares, threshold) => {
1680
+ if (!Number.isSafeInteger(threshold) || threshold < 2) throw new RangeError("invalid beacon threshold");
1681
+ const shares = [...rawShares].sort((left, right) => left.participant < right.participant ? -1 : 1);
1682
+ if (shares.length < threshold) throw new Error("not enough beacon signature shares");
1683
+ const selected = shares.slice(0, threshold);
1684
+ const participants = selected.map(({ participant }) => participant);
1685
+ assertUniqueParticipants(participants);
1686
+ let signature = G2.ZERO;
1687
+ for (const share of selected) {
1688
+ const point = bls12_381.Signature.fromHex(share.signature);
1689
+ point.assertValidity();
1690
+ signature = signature.add(point.multiply(lagrangeAtZero(share.participant, participants)));
1691
+ }
1692
+ return bls12_381.Signature.toRawBytes(signature);
1693
+ };
1694
+ const verifyBeaconProof = (proof, message, groupPublicKey) => {
1695
+ try {
1696
+ return bls12_381.verify(proof, message, groupPublicKey);
1697
+ } catch {
1698
+ return false;
1699
+ }
1700
+ };
1701
+ const beaconRandomness = (proof) => {
1702
+ if (proof.length !== 96) throw new Error("invalid BLS beacon proof length");
1703
+ return sha256(proof);
1704
+ };
1705
+
1706
+ export { beaconMessage, beaconRandomness, combineBeaconShares, createBeaconContribution, deriveBeaconGroupPublicKey, deriveBeaconPublicShare, reconstructBeaconSignature, signBeaconRound, verifyBeaconProof, verifyBeaconShare, verifyBeaconSignatureShare };