bls.ts 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  1. /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
  2. // BLS (Barreto-Lynn-Scott) family of pairing-friendly curves.
  3. import { AffinePoint } from './curve.js';
  4. import { IField, getMinHashLength, mapHashToField } from './modular.js';
  5. import { Hex, PrivKey, CHash, bitLen, bitGet, ensureBytes } from './utils.js';
  6. // prettier-ignore
  7. import {
  8. MapToCurve, Opts as HTFOpts, H2CPointConstructor, htfBasicOpts,
  9. createHasher
  10. } from './hash-to-curve.js';
  11. import {
  12. CurvePointsType,
  13. ProjPointType as ProjPointType,
  14. CurvePointsRes,
  15. weierstrassPoints,
  16. } from './weierstrass.js';
  17. /**
  18. * BLS (Barreto-Lynn-Scott) family of pairing-friendly curves.
  19. * Implements BLS (Boneh-Lynn-Shacham) signatures.
  20. * Consists of two curves: G1 and G2:
  21. * - G1 is a subgroup of (x, y) E(Fq) over y² = x³ + 4.
  22. * - G2 is a subgroup of ((x₁, x₂+i), (y₁, y₂+i)) E(Fq²) over y² = x³ + 4(1 + i) where i is √-1
  23. * - Gt, created by bilinear (ate) pairing e(G1, G2), consists of p-th roots of unity in
  24. * Fq^k where k is embedding degree. Only degree 12 is currently supported, 24 is not.
  25. * Pairing is used to aggregate and verify signatures.
  26. * We are using Fp for private keys (shorter) and Fp₂ for signatures (longer).
  27. * Some projects may prefer to swap this relation, it is not supported for now.
  28. **/
  29. type Fp = bigint; // Can be different field?
  30. // prettier-ignore
  31. const _2n = BigInt(2), _3n = BigInt(3);
  32. export type ShortSignatureCoder<Fp> = {
  33. fromHex(hex: Hex): ProjPointType<Fp>;
  34. toRawBytes(point: ProjPointType<Fp>): Uint8Array;
  35. toHex(point: ProjPointType<Fp>): string;
  36. };
  37. export type SignatureCoder<Fp2> = {
  38. fromHex(hex: Hex): ProjPointType<Fp2>;
  39. toRawBytes(point: ProjPointType<Fp2>): Uint8Array;
  40. toHex(point: ProjPointType<Fp2>): string;
  41. };
  42. type Fp2Bls<Fp, Fp2> = IField<Fp2> & {
  43. reim: (num: Fp2) => { re: Fp; im: Fp };
  44. multiplyByB: (num: Fp2) => Fp2;
  45. frobeniusMap(num: Fp2, power: number): Fp2;
  46. };
  47. type Fp12Bls<Fp2, Fp12> = IField<Fp12> & {
  48. frobeniusMap(num: Fp12, power: number): Fp12;
  49. multiplyBy014(num: Fp12, o0: Fp2, o1: Fp2, o4: Fp2): Fp12;
  50. conjugate(num: Fp12): Fp12;
  51. finalExponentiate(num: Fp12): Fp12;
  52. };
  53. export type CurveType<Fp, Fp2, Fp6, Fp12> = {
  54. G1: Omit<CurvePointsType<Fp>, 'n'> & {
  55. ShortSignature: SignatureCoder<Fp>;
  56. mapToCurve: MapToCurve<Fp>;
  57. htfDefaults: HTFOpts;
  58. };
  59. G2: Omit<CurvePointsType<Fp2>, 'n'> & {
  60. Signature: SignatureCoder<Fp2>;
  61. mapToCurve: MapToCurve<Fp2>;
  62. htfDefaults: HTFOpts;
  63. };
  64. fields: {
  65. Fp: IField<Fp>;
  66. Fr: IField<bigint>;
  67. Fp2: Fp2Bls<Fp, Fp2>;
  68. Fp6: IField<Fp6>;
  69. Fp12: Fp12Bls<Fp2, Fp12>;
  70. };
  71. params: {
  72. x: bigint;
  73. r: bigint;
  74. };
  75. htfDefaults: HTFOpts;
  76. hash: CHash; // Because we need outputLen for DRBG
  77. randomBytes: (bytesLength?: number) => Uint8Array;
  78. };
  79. export type CurveFn<Fp, Fp2, Fp6, Fp12> = {
  80. getPublicKey: (privateKey: PrivKey) => Uint8Array;
  81. getPublicKeyForShortSignatures: (privateKey: PrivKey) => Uint8Array;
  82. sign: {
  83. (message: Hex, privateKey: PrivKey, htfOpts?: htfBasicOpts): Uint8Array;
  84. (message: ProjPointType<Fp2>, privateKey: PrivKey, htfOpts?: htfBasicOpts): ProjPointType<Fp2>;
  85. };
  86. signShortSignature: {
  87. (message: Hex, privateKey: PrivKey, htfOpts?: htfBasicOpts): Uint8Array;
  88. (message: ProjPointType<Fp>, privateKey: PrivKey, htfOpts?: htfBasicOpts): ProjPointType<Fp>;
  89. };
  90. verify: (
  91. signature: Hex | ProjPointType<Fp2>,
  92. message: Hex | ProjPointType<Fp2>,
  93. publicKey: Hex | ProjPointType<Fp>,
  94. htfOpts?: htfBasicOpts
  95. ) => boolean;
  96. verifyShortSignature: (
  97. signature: Hex | ProjPointType<Fp>,
  98. message: Hex | ProjPointType<Fp>,
  99. publicKey: Hex | ProjPointType<Fp2>,
  100. htfOpts?: htfBasicOpts
  101. ) => boolean;
  102. verifyBatch: (
  103. signature: Hex | ProjPointType<Fp2>,
  104. messages: (Hex | ProjPointType<Fp2>)[],
  105. publicKeys: (Hex | ProjPointType<Fp>)[],
  106. htfOpts?: htfBasicOpts
  107. ) => boolean;
  108. aggregatePublicKeys: {
  109. (publicKeys: Hex[]): Uint8Array;
  110. (publicKeys: ProjPointType<Fp>[]): ProjPointType<Fp>;
  111. };
  112. aggregateSignatures: {
  113. (signatures: Hex[]): Uint8Array;
  114. (signatures: ProjPointType<Fp2>[]): ProjPointType<Fp2>;
  115. };
  116. aggregateShortSignatures: {
  117. (signatures: Hex[]): Uint8Array;
  118. (signatures: ProjPointType<Fp>[]): ProjPointType<Fp>;
  119. };
  120. millerLoop: (ell: [Fp2, Fp2, Fp2][], g1: [Fp, Fp]) => Fp12;
  121. pairing: (P: ProjPointType<Fp>, Q: ProjPointType<Fp2>, withFinalExponent?: boolean) => Fp12;
  122. G1: CurvePointsRes<Fp> & ReturnType<typeof createHasher<Fp>>;
  123. G2: CurvePointsRes<Fp2> & ReturnType<typeof createHasher<Fp2>>;
  124. Signature: SignatureCoder<Fp2>;
  125. ShortSignature: ShortSignatureCoder<Fp>;
  126. params: {
  127. x: bigint;
  128. r: bigint;
  129. G1b: bigint;
  130. G2b: Fp2;
  131. };
  132. fields: {
  133. Fp: IField<Fp>;
  134. Fp2: Fp2Bls<Fp, Fp2>;
  135. Fp6: IField<Fp6>;
  136. Fp12: Fp12Bls<Fp2, Fp12>;
  137. Fr: IField<bigint>;
  138. };
  139. utils: {
  140. randomPrivateKey: () => Uint8Array;
  141. calcPairingPrecomputes: (p: AffinePoint<Fp2>) => [Fp2, Fp2, Fp2][];
  142. };
  143. };
  144. export function bls<Fp2, Fp6, Fp12>(
  145. CURVE: CurveType<Fp, Fp2, Fp6, Fp12>
  146. ): CurveFn<Fp, Fp2, Fp6, Fp12> {
  147. // Fields are specific for curve, so for now we'll need to pass them with opts
  148. const { Fp, Fr, Fp2, Fp6, Fp12 } = CURVE.fields;
  149. const BLS_X_LEN = bitLen(CURVE.params.x);
  150. // Pre-compute coefficients for sparse multiplication
  151. // Point addition and point double calculations is reused for coefficients
  152. function calcPairingPrecomputes(p: AffinePoint<Fp2>) {
  153. const { x, y } = p;
  154. // prettier-ignore
  155. const Qx = x, Qy = y, Qz = Fp2.ONE;
  156. // prettier-ignore
  157. let Rx = Qx, Ry = Qy, Rz = Qz;
  158. let ell_coeff: [Fp2, Fp2, Fp2][] = [];
  159. for (let i = BLS_X_LEN - 2; i >= 0; i--) {
  160. // Double
  161. let t0 = Fp2.sqr(Ry); // Ry²
  162. let t1 = Fp2.sqr(Rz); // Rz²
  163. let t2 = Fp2.multiplyByB(Fp2.mul(t1, _3n)); // 3 * T1 * B
  164. let t3 = Fp2.mul(t2, _3n); // 3 * T2
  165. let t4 = Fp2.sub(Fp2.sub(Fp2.sqr(Fp2.add(Ry, Rz)), t1), t0); // (Ry + Rz)² - T1 - T0
  166. ell_coeff.push([
  167. Fp2.sub(t2, t0), // T2 - T0
  168. Fp2.mul(Fp2.sqr(Rx), _3n), // 3 * Rx²
  169. Fp2.neg(t4), // -T4
  170. ]);
  171. Rx = Fp2.div(Fp2.mul(Fp2.mul(Fp2.sub(t0, t3), Rx), Ry), _2n); // ((T0 - T3) * Rx * Ry) / 2
  172. Ry = Fp2.sub(Fp2.sqr(Fp2.div(Fp2.add(t0, t3), _2n)), Fp2.mul(Fp2.sqr(t2), _3n)); // ((T0 + T3) / 2)² - 3 * T2²
  173. Rz = Fp2.mul(t0, t4); // T0 * T4
  174. if (bitGet(CURVE.params.x, i)) {
  175. // Addition
  176. let t0 = Fp2.sub(Ry, Fp2.mul(Qy, Rz)); // Ry - Qy * Rz
  177. let t1 = Fp2.sub(Rx, Fp2.mul(Qx, Rz)); // Rx - Qx * Rz
  178. ell_coeff.push([
  179. Fp2.sub(Fp2.mul(t0, Qx), Fp2.mul(t1, Qy)), // T0 * Qx - T1 * Qy
  180. Fp2.neg(t0), // -T0
  181. t1, // T1
  182. ]);
  183. let t2 = Fp2.sqr(t1); // T1²
  184. let t3 = Fp2.mul(t2, t1); // T2 * T1
  185. let t4 = Fp2.mul(t2, Rx); // T2 * Rx
  186. let t5 = Fp2.add(Fp2.sub(t3, Fp2.mul(t4, _2n)), Fp2.mul(Fp2.sqr(t0), Rz)); // T3 - 2 * T4 + T0² * Rz
  187. Rx = Fp2.mul(t1, t5); // T1 * T5
  188. Ry = Fp2.sub(Fp2.mul(Fp2.sub(t4, t5), t0), Fp2.mul(t3, Ry)); // (T4 - T5) * T0 - T3 * Ry
  189. Rz = Fp2.mul(Rz, t3); // Rz * T3
  190. }
  191. }
  192. return ell_coeff;
  193. }
  194. function millerLoop(ell: [Fp2, Fp2, Fp2][], g1: [Fp, Fp]): Fp12 {
  195. const { x } = CURVE.params;
  196. const Px = g1[0];
  197. const Py = g1[1];
  198. let f12 = Fp12.ONE;
  199. for (let j = 0, i = BLS_X_LEN - 2; i >= 0; i--, j++) {
  200. const E = ell[j];
  201. f12 = Fp12.multiplyBy014(f12, E[0], Fp2.mul(E[1], Px), Fp2.mul(E[2], Py));
  202. if (bitGet(x, i)) {
  203. j += 1;
  204. const F = ell[j];
  205. f12 = Fp12.multiplyBy014(f12, F[0], Fp2.mul(F[1], Px), Fp2.mul(F[2], Py));
  206. }
  207. if (i !== 0) f12 = Fp12.sqr(f12);
  208. }
  209. return Fp12.conjugate(f12);
  210. }
  211. const utils = {
  212. randomPrivateKey: (): Uint8Array => {
  213. const length = getMinHashLength(Fr.ORDER);
  214. return mapHashToField(CURVE.randomBytes(length), Fr.ORDER);
  215. },
  216. calcPairingPrecomputes,
  217. };
  218. // Point on G1 curve: (x, y)
  219. const G1_ = weierstrassPoints({ n: Fr.ORDER, ...CURVE.G1 });
  220. const G1 = Object.assign(
  221. G1_,
  222. createHasher(G1_.ProjectivePoint, CURVE.G1.mapToCurve, {
  223. ...CURVE.htfDefaults,
  224. ...CURVE.G1.htfDefaults,
  225. })
  226. );
  227. // Sparse multiplication against precomputed coefficients
  228. // TODO: replace with weakmap?
  229. type withPairingPrecomputes = { _PPRECOMPUTES: [Fp2, Fp2, Fp2][] | undefined };
  230. function pairingPrecomputes(point: G2): [Fp2, Fp2, Fp2][] {
  231. const p = point as G2 & withPairingPrecomputes;
  232. if (p._PPRECOMPUTES) return p._PPRECOMPUTES;
  233. p._PPRECOMPUTES = calcPairingPrecomputes(point.toAffine());
  234. return p._PPRECOMPUTES;
  235. }
  236. // TODO: export
  237. // function clearPairingPrecomputes(point: G2) {
  238. // const p = point as G2 & withPairingPrecomputes;
  239. // p._PPRECOMPUTES = undefined;
  240. // }
  241. // Point on G2 curve (complex numbers): (x₁, x₂+i), (y₁, y₂+i)
  242. const G2_ = weierstrassPoints({ n: Fr.ORDER, ...CURVE.G2 });
  243. const G2 = Object.assign(
  244. G2_,
  245. createHasher(G2_.ProjectivePoint as H2CPointConstructor<Fp2>, CURVE.G2.mapToCurve, {
  246. ...CURVE.htfDefaults,
  247. ...CURVE.G2.htfDefaults,
  248. })
  249. );
  250. const { ShortSignature } = CURVE.G1;
  251. const { Signature } = CURVE.G2;
  252. // Calculates bilinear pairing
  253. function pairing(Q: G1, P: G2, withFinalExponent: boolean = true): Fp12 {
  254. if (Q.equals(G1.ProjectivePoint.ZERO) || P.equals(G2.ProjectivePoint.ZERO))
  255. throw new Error('pairing is not available for ZERO point');
  256. Q.assertValidity();
  257. P.assertValidity();
  258. // Performance: 9ms for millerLoop and ~14ms for exp.
  259. const Qa = Q.toAffine();
  260. const looped = millerLoop(pairingPrecomputes(P), [Qa.x, Qa.y]);
  261. return withFinalExponent ? Fp12.finalExponentiate(looped) : looped;
  262. }
  263. type G1 = typeof G1.ProjectivePoint.BASE;
  264. type G2 = typeof G2.ProjectivePoint.BASE;
  265. type G1Hex = Hex | G1;
  266. type G2Hex = Hex | G2;
  267. function normP1(point: G1Hex): G1 {
  268. return point instanceof G1.ProjectivePoint ? (point as G1) : G1.ProjectivePoint.fromHex(point);
  269. }
  270. function normP1Hash(point: G1Hex, htfOpts?: htfBasicOpts): G1 {
  271. return point instanceof G1.ProjectivePoint
  272. ? point
  273. : (G1.hashToCurve(ensureBytes('point', point), htfOpts) as G1);
  274. }
  275. function normP2(point: G2Hex): G2 {
  276. return point instanceof G2.ProjectivePoint ? point : Signature.fromHex(point);
  277. }
  278. function normP2Hash(point: G2Hex, htfOpts?: htfBasicOpts): G2 {
  279. return point instanceof G2.ProjectivePoint
  280. ? point
  281. : (G2.hashToCurve(ensureBytes('point', point), htfOpts) as G2);
  282. }
  283. // Multiplies generator (G1) by private key.
  284. // P = pk x G
  285. function getPublicKey(privateKey: PrivKey): Uint8Array {
  286. return G1.ProjectivePoint.fromPrivateKey(privateKey).toRawBytes(true);
  287. }
  288. // Multiplies generator (G2) by private key.
  289. // P = pk x G
  290. function getPublicKeyForShortSignatures(privateKey: PrivKey): Uint8Array {
  291. return G2.ProjectivePoint.fromPrivateKey(privateKey).toRawBytes(true);
  292. }
  293. // Executes `hashToCurve` on the message and then multiplies the result by private key.
  294. // S = pk x H(m)
  295. function sign(message: Hex, privateKey: PrivKey, htfOpts?: htfBasicOpts): Uint8Array;
  296. function sign(message: G2, privateKey: PrivKey, htfOpts?: htfBasicOpts): G2;
  297. function sign(message: G2Hex, privateKey: PrivKey, htfOpts?: htfBasicOpts): Uint8Array | G2 {
  298. const msgPoint = normP2Hash(message, htfOpts);
  299. msgPoint.assertValidity();
  300. const sigPoint = msgPoint.multiply(G1.normPrivateKeyToScalar(privateKey));
  301. if (message instanceof G2.ProjectivePoint) return sigPoint;
  302. return Signature.toRawBytes(sigPoint);
  303. }
  304. function signShortSignature(
  305. message: Hex,
  306. privateKey: PrivKey,
  307. htfOpts?: htfBasicOpts
  308. ): Uint8Array;
  309. function signShortSignature(message: G1, privateKey: PrivKey, htfOpts?: htfBasicOpts): G1;
  310. function signShortSignature(
  311. message: G1Hex,
  312. privateKey: PrivKey,
  313. htfOpts?: htfBasicOpts
  314. ): Uint8Array | G1 {
  315. const msgPoint = normP1Hash(message, htfOpts);
  316. msgPoint.assertValidity();
  317. const sigPoint = msgPoint.multiply(G1.normPrivateKeyToScalar(privateKey));
  318. if (message instanceof G1.ProjectivePoint) return sigPoint;
  319. return ShortSignature.toRawBytes(sigPoint);
  320. }
  321. // Checks if pairing of public key & hash is equal to pairing of generator & signature.
  322. // e(P, H(m)) == e(G, S)
  323. function verify(
  324. signature: G2Hex,
  325. message: G2Hex,
  326. publicKey: G1Hex,
  327. htfOpts?: htfBasicOpts
  328. ): boolean {
  329. const P = normP1(publicKey);
  330. const Hm = normP2Hash(message, htfOpts);
  331. const G = G1.ProjectivePoint.BASE;
  332. const S = normP2(signature);
  333. // Instead of doing 2 exponentiations, we use property of billinear maps
  334. // and do one exp after multiplying 2 points.
  335. const ePHm = pairing(P.negate(), Hm, false);
  336. const eGS = pairing(G, S, false);
  337. const exp = Fp12.finalExponentiate(Fp12.mul(eGS, ePHm));
  338. return Fp12.eql(exp, Fp12.ONE);
  339. }
  340. // Checks if pairing of public key & hash is equal to pairing of generator & signature.
  341. // e(S, G) == e(H(m), P)
  342. function verifyShortSignature(
  343. signature: G1Hex,
  344. message: G1Hex,
  345. publicKey: G2Hex,
  346. htfOpts?: htfBasicOpts
  347. ): boolean {
  348. const P = normP2(publicKey);
  349. const Hm = normP1Hash(message, htfOpts);
  350. const G = G2.ProjectivePoint.BASE;
  351. const S = normP1(signature);
  352. // Instead of doing 2 exponentiations, we use property of billinear maps
  353. // and do one exp after multiplying 2 points.
  354. const eHmP = pairing(Hm, P, false);
  355. const eSG = pairing(S, G.negate(), false);
  356. const exp = Fp12.finalExponentiate(Fp12.mul(eSG, eHmP));
  357. return Fp12.eql(exp, Fp12.ONE);
  358. }
  359. // Adds a bunch of public key points together.
  360. // pk1 + pk2 + pk3 = pkA
  361. function aggregatePublicKeys(publicKeys: Hex[]): Uint8Array;
  362. function aggregatePublicKeys(publicKeys: G1[]): G1;
  363. function aggregatePublicKeys(publicKeys: G1Hex[]): Uint8Array | G1 {
  364. if (!publicKeys.length) throw new Error('Expected non-empty array');
  365. const agg = publicKeys.map(normP1).reduce((sum, p) => sum.add(p), G1.ProjectivePoint.ZERO);
  366. const aggAffine = agg; //.toAffine();
  367. if (publicKeys[0] instanceof G1.ProjectivePoint) {
  368. aggAffine.assertValidity();
  369. return aggAffine;
  370. }
  371. // toRawBytes ensures point validity
  372. return aggAffine.toRawBytes(true);
  373. }
  374. // Adds a bunch of signature points together.
  375. function aggregateSignatures(signatures: Hex[]): Uint8Array;
  376. function aggregateSignatures(signatures: G2[]): G2;
  377. function aggregateSignatures(signatures: G2Hex[]): Uint8Array | G2 {
  378. if (!signatures.length) throw new Error('Expected non-empty array');
  379. const agg = signatures.map(normP2).reduce((sum, s) => sum.add(s), G2.ProjectivePoint.ZERO);
  380. const aggAffine = agg; //.toAffine();
  381. if (signatures[0] instanceof G2.ProjectivePoint) {
  382. aggAffine.assertValidity();
  383. return aggAffine;
  384. }
  385. return Signature.toRawBytes(aggAffine);
  386. }
  387. // Adds a bunch of signature points together.
  388. function aggregateShortSignatures(signatures: Hex[]): Uint8Array;
  389. function aggregateShortSignatures(signatures: G1[]): G1;
  390. function aggregateShortSignatures(signatures: G1Hex[]): Uint8Array | G1 {
  391. if (!signatures.length) throw new Error('Expected non-empty array');
  392. const agg = signatures.map(normP1).reduce((sum, s) => sum.add(s), G1.ProjectivePoint.ZERO);
  393. const aggAffine = agg; //.toAffine();
  394. if (signatures[0] instanceof G1.ProjectivePoint) {
  395. aggAffine.assertValidity();
  396. return aggAffine;
  397. }
  398. return ShortSignature.toRawBytes(aggAffine);
  399. }
  400. // https://ethresear.ch/t/fast-verification-of-multiple-bls-signatures/5407
  401. // e(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))
  402. function verifyBatch(
  403. signature: G2Hex,
  404. messages: G2Hex[],
  405. publicKeys: G1Hex[],
  406. htfOpts?: htfBasicOpts
  407. ): boolean {
  408. // @ts-ignore
  409. // console.log('verifyBatch', bytesToHex(signature as any), messages, publicKeys.map(bytesToHex));
  410. if (!messages.length) throw new Error('Expected non-empty messages array');
  411. if (publicKeys.length !== messages.length)
  412. throw new Error('Pubkey count should equal msg count');
  413. const sig = normP2(signature);
  414. const nMessages = messages.map((i) => normP2Hash(i, htfOpts));
  415. const nPublicKeys = publicKeys.map(normP1);
  416. try {
  417. const paired = [];
  418. for (const message of new Set(nMessages)) {
  419. const groupPublicKey = nMessages.reduce(
  420. (groupPublicKey, subMessage, i) =>
  421. subMessage === message ? groupPublicKey.add(nPublicKeys[i]) : groupPublicKey,
  422. G1.ProjectivePoint.ZERO
  423. );
  424. // const msg = message instanceof PointG2 ? message : await PointG2.hashToCurve(message);
  425. // Possible to batch pairing for same msg with different groupPublicKey here
  426. paired.push(pairing(groupPublicKey, message, false));
  427. }
  428. paired.push(pairing(G1.ProjectivePoint.BASE.negate(), sig, false));
  429. const product = paired.reduce((a, b) => Fp12.mul(a, b), Fp12.ONE);
  430. const exp = Fp12.finalExponentiate(product);
  431. return Fp12.eql(exp, Fp12.ONE);
  432. } catch {
  433. return false;
  434. }
  435. }
  436. G1.ProjectivePoint.BASE._setWindowSize(4);
  437. return {
  438. getPublicKey,
  439. getPublicKeyForShortSignatures,
  440. sign,
  441. signShortSignature,
  442. verify,
  443. verifyBatch,
  444. verifyShortSignature,
  445. aggregatePublicKeys,
  446. aggregateSignatures,
  447. aggregateShortSignatures,
  448. millerLoop,
  449. pairing,
  450. G1,
  451. G2,
  452. Signature,
  453. ShortSignature,
  454. fields: {
  455. Fr,
  456. Fp,
  457. Fp2,
  458. Fp6,
  459. Fp12,
  460. },
  461. params: {
  462. x: CURVE.params.x,
  463. r: CURVE.params.r,
  464. G1b: CURVE.G1.b,
  465. G2b: CURVE.G2.b,
  466. },
  467. utils,
  468. };
  469. }