bls12-381.ts 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410
  1. /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
  2. import { sha256 } from '@noble/hashes/sha256';
  3. import { randomBytes } from '@noble/hashes/utils';
  4. import { bls, CurveFn } from './abstract/bls.js';
  5. import * as mod from './abstract/modular.js';
  6. import {
  7. bitGet,
  8. bitLen,
  9. bitMask,
  10. bytesToHex,
  11. bytesToNumberBE,
  12. concatBytes as concatB,
  13. ensureBytes,
  14. Hex,
  15. numberToBytesBE,
  16. } from './abstract/utils.js';
  17. // Types
  18. import { isogenyMap } from './abstract/hash-to-curve.js';
  19. import {
  20. AffinePoint,
  21. mapToCurveSimpleSWU,
  22. ProjConstructor,
  23. ProjPointType,
  24. } from './abstract/weierstrass.js';
  25. /*
  26. bls12-381 is pairing-friendly Barreto-Lynn-Scott elliptic curve construction allowing to:
  27. - Construct zk-SNARKs at the 120-bit security
  28. - Efficiently verify N aggregate signatures with 1 pairing and N ec additions:
  29. the Boneh-Lynn-Shacham signature scheme is orders of magnitude more efficient than Schnorr
  30. ### Summary
  31. 1. BLS Relies on Bilinear Pairing (expensive)
  32. 2. Private Keys: 32 bytes
  33. 3. Public Keys: 48 bytes: 381 bit affine x coordinate, encoded into 48 big-endian bytes.
  34. 4. Signatures: 96 bytes: two 381 bit integers (affine x coordinate), encoded into two 48 big-endian byte arrays.
  35. - The signature is a point on the G2 subgroup, which is defined over a finite field
  36. with elements twice as big as the G1 curve (G2 is over Fp2 rather than Fp. Fp2 is analogous to the complex numbers).
  37. 5. The 12 stands for the Embedding degree.
  38. ### Formulas
  39. - `P = pk x G` - public keys
  40. - `S = pk x H(m)` - signing
  41. - `e(P, H(m)) == e(G, S)` - verification using pairings
  42. - `e(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))` - signature aggregation
  43. ### Compatibility and notes
  44. 1. It is compatible with Algorand, Chia, Dfinity, Ethereum, Filecoin, ZEC
  45. Filecoin uses little endian byte arrays for private keys - make sure to reverse byte order.
  46. 2. Some projects use G2 for public keys and G1 for signatures. It's called "short signature"
  47. 3. Curve security level is about 120 bits as per Barbulescu-Duquesne 2017
  48. https://hal.science/hal-01534101/file/main.pdf
  49. 4. Compatible with specs:
  50. [cfrg-pairing-friendly-curves-11](https://tools.ietf.org/html/draft-irtf-cfrg-pairing-friendly-curves-11),
  51. [cfrg-bls-signature-05](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-05),
  52. [RFC 9380](https://www.rfc-editor.org/rfc/rfc9380).
  53. */
  54. // Be friendly to bad ECMAScript parsers by not using bigint literals
  55. // prettier-ignore
  56. const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3), _4n = BigInt(4);
  57. // prettier-ignore
  58. const _8n = BigInt(8), _16n = BigInt(16);
  59. // CURVE FIELDS
  60. // Finite field over p.
  61. const Fp_raw = BigInt(
  62. '0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab'
  63. );
  64. const Fp = mod.Field(Fp_raw);
  65. type Fp = bigint;
  66. // Finite field over r.
  67. // This particular field is not used anywhere in bls12-381, but it is still useful.
  68. const Fr = mod.Field(BigInt('0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001'));
  69. // Fp₂ over complex plane
  70. type BigintTuple = [bigint, bigint];
  71. type Fp2 = { c0: bigint; c1: bigint };
  72. const Fp2Add = ({ c0, c1 }: Fp2, { c0: r0, c1: r1 }: Fp2) => ({
  73. c0: Fp.add(c0, r0),
  74. c1: Fp.add(c1, r1),
  75. });
  76. const Fp2Subtract = ({ c0, c1 }: Fp2, { c0: r0, c1: r1 }: Fp2) => ({
  77. c0: Fp.sub(c0, r0),
  78. c1: Fp.sub(c1, r1),
  79. });
  80. const Fp2Multiply = ({ c0, c1 }: Fp2, rhs: Fp2) => {
  81. if (typeof rhs === 'bigint') return { c0: Fp.mul(c0, rhs), c1: Fp.mul(c1, rhs) };
  82. // (a+bi)(c+di) = (ac−bd) + (ad+bc)i
  83. const { c0: r0, c1: r1 } = rhs;
  84. let t1 = Fp.mul(c0, r0); // c0 * o0
  85. let t2 = Fp.mul(c1, r1); // c1 * o1
  86. // (T1 - T2) + ((c0 + c1) * (r0 + r1) - (T1 + T2))*i
  87. const o0 = Fp.sub(t1, t2);
  88. const o1 = Fp.sub(Fp.mul(Fp.add(c0, c1), Fp.add(r0, r1)), Fp.add(t1, t2));
  89. return { c0: o0, c1: o1 };
  90. };
  91. const Fp2Square = ({ c0, c1 }: Fp2) => {
  92. const a = Fp.add(c0, c1);
  93. const b = Fp.sub(c0, c1);
  94. const c = Fp.add(c0, c0);
  95. return { c0: Fp.mul(a, b), c1: Fp.mul(c, c1) };
  96. };
  97. type Fp2Utils = {
  98. fromBigTuple: (tuple: BigintTuple | bigint[]) => Fp2;
  99. reim: (num: Fp2) => { re: bigint; im: bigint };
  100. mulByNonresidue: (num: Fp2) => Fp2;
  101. multiplyByB: (num: Fp2) => Fp2;
  102. frobeniusMap(num: Fp2, power: number): Fp2;
  103. };
  104. // G2 is the order-q subgroup of E2(Fp²) : y² = x³+4(1+√−1),
  105. // where Fp2 is Fp[√−1]/(x2+1). #E2(Fp2 ) = h2q, where
  106. // G² - 1
  107. // h2q
  108. // NOTE: ORDER was wrong!
  109. const FP2_ORDER = Fp_raw * Fp_raw;
  110. const Fp2: mod.IField<Fp2> & Fp2Utils = {
  111. ORDER: FP2_ORDER,
  112. BITS: bitLen(FP2_ORDER),
  113. BYTES: Math.ceil(bitLen(FP2_ORDER) / 8),
  114. MASK: bitMask(bitLen(FP2_ORDER)),
  115. ZERO: { c0: Fp.ZERO, c1: Fp.ZERO },
  116. ONE: { c0: Fp.ONE, c1: Fp.ZERO },
  117. create: (num) => num,
  118. isValid: ({ c0, c1 }) => typeof c0 === 'bigint' && typeof c1 === 'bigint',
  119. is0: ({ c0, c1 }) => Fp.is0(c0) && Fp.is0(c1),
  120. eql: ({ c0, c1 }: Fp2, { c0: r0, c1: r1 }: Fp2) => Fp.eql(c0, r0) && Fp.eql(c1, r1),
  121. neg: ({ c0, c1 }) => ({ c0: Fp.neg(c0), c1: Fp.neg(c1) }),
  122. pow: (num, power) => mod.FpPow(Fp2, num, power),
  123. invertBatch: (nums) => mod.FpInvertBatch(Fp2, nums),
  124. // Normalized
  125. add: Fp2Add,
  126. sub: Fp2Subtract,
  127. mul: Fp2Multiply,
  128. sqr: Fp2Square,
  129. // NonNormalized stuff
  130. addN: Fp2Add,
  131. subN: Fp2Subtract,
  132. mulN: Fp2Multiply,
  133. sqrN: Fp2Square,
  134. // Why inversion for bigint inside Fp instead of Fp2? it is even used in that context?
  135. div: (lhs, rhs) => Fp2.mul(lhs, typeof rhs === 'bigint' ? Fp.inv(Fp.create(rhs)) : Fp2.inv(rhs)),
  136. inv: ({ c0: a, c1: b }) => {
  137. // We wish to find the multiplicative inverse of a nonzero
  138. // element a + bu in Fp2. We leverage an identity
  139. //
  140. // (a + bu)(a - bu) = a² + b²
  141. //
  142. // which holds because u² = -1. This can be rewritten as
  143. //
  144. // (a + bu)(a - bu)/(a² + b²) = 1
  145. //
  146. // because a² + b² = 0 has no nonzero solutions for (a, b).
  147. // This gives that (a - bu)/(a² + b²) is the inverse
  148. // of (a + bu). Importantly, this can be computing using
  149. // only a single inversion in Fp.
  150. const factor = Fp.inv(Fp.create(a * a + b * b));
  151. return { c0: Fp.mul(factor, Fp.create(a)), c1: Fp.mul(factor, Fp.create(-b)) };
  152. },
  153. sqrt: (num) => {
  154. if (Fp2.eql(num, Fp2.ZERO)) return Fp2.ZERO; // Algo doesn't handles this case
  155. // TODO: Optimize this line. It's extremely slow.
  156. // Speeding this up would boost aggregateSignatures.
  157. // https://eprint.iacr.org/2012/685.pdf applicable?
  158. // https://github.com/zkcrypto/bls12_381/blob/080eaa74ec0e394377caa1ba302c8c121df08b07/src/fp2.rs#L250
  159. // https://github.com/supranational/blst/blob/aae0c7d70b799ac269ff5edf29d8191dbd357876/src/exp2.c#L1
  160. // Inspired by https://github.com/dalek-cryptography/curve25519-dalek/blob/17698df9d4c834204f83a3574143abacb4fc81a5/src/field.rs#L99
  161. const candidateSqrt = Fp2.pow(num, (Fp2.ORDER + _8n) / _16n);
  162. const check = Fp2.div(Fp2.sqr(candidateSqrt), num); // candidateSqrt.square().div(this);
  163. const R = FP2_ROOTS_OF_UNITY;
  164. const divisor = [R[0], R[2], R[4], R[6]].find((r) => Fp2.eql(r, check));
  165. if (!divisor) throw new Error('No root');
  166. const index = R.indexOf(divisor);
  167. const root = R[index / 2];
  168. if (!root) throw new Error('Invalid root');
  169. const x1 = Fp2.div(candidateSqrt, root);
  170. const x2 = Fp2.neg(x1);
  171. const { re: re1, im: im1 } = Fp2.reim(x1);
  172. const { re: re2, im: im2 } = Fp2.reim(x2);
  173. if (im1 > im2 || (im1 === im2 && re1 > re2)) return x1;
  174. return x2;
  175. },
  176. // Same as sgn0_m_eq_2 in RFC 9380
  177. isOdd: (x: Fp2) => {
  178. const { re: x0, im: x1 } = Fp2.reim(x);
  179. const sign_0 = x0 % _2n;
  180. const zero_0 = x0 === _0n;
  181. const sign_1 = x1 % _2n;
  182. return BigInt(sign_0 || (zero_0 && sign_1)) == _1n;
  183. },
  184. // Bytes util
  185. fromBytes(b: Uint8Array): Fp2 {
  186. if (b.length !== Fp2.BYTES) throw new Error(`fromBytes wrong length=${b.length}`);
  187. return { c0: Fp.fromBytes(b.subarray(0, Fp.BYTES)), c1: Fp.fromBytes(b.subarray(Fp.BYTES)) };
  188. },
  189. toBytes: ({ c0, c1 }) => concatB(Fp.toBytes(c0), Fp.toBytes(c1)),
  190. cmov: ({ c0, c1 }, { c0: r0, c1: r1 }, c) => ({
  191. c0: Fp.cmov(c0, r0, c),
  192. c1: Fp.cmov(c1, r1, c),
  193. }),
  194. // Specific utils
  195. // toString() {
  196. // return `Fp2(${this.c0} + ${this.c1}×i)`;
  197. // }
  198. reim: ({ c0, c1 }) => ({ re: c0, im: c1 }),
  199. // multiply by u + 1
  200. mulByNonresidue: ({ c0, c1 }) => ({ c0: Fp.sub(c0, c1), c1: Fp.add(c0, c1) }),
  201. multiplyByB: ({ c0, c1 }) => {
  202. let t0 = Fp.mul(c0, _4n); // 4 * c0
  203. let t1 = Fp.mul(c1, _4n); // 4 * c1
  204. // (T0-T1) + (T0+T1)*i
  205. return { c0: Fp.sub(t0, t1), c1: Fp.add(t0, t1) };
  206. },
  207. fromBigTuple: (tuple: BigintTuple | bigint[]) => {
  208. if (tuple.length !== 2) throw new Error('Invalid tuple');
  209. const fps = tuple.map((n) => Fp.create(n)) as [Fp, Fp];
  210. return { c0: fps[0], c1: fps[1] };
  211. },
  212. frobeniusMap: ({ c0, c1 }, power: number): Fp2 => ({
  213. c0,
  214. c1: Fp.mul(c1, FP2_FROBENIUS_COEFFICIENTS[power % 2]),
  215. }),
  216. };
  217. // Finite extension field over irreducible polynominal.
  218. // Fp(u) / (u² - β) where β = -1
  219. const FP2_FROBENIUS_COEFFICIENTS = [
  220. BigInt('0x1'),
  221. BigInt(
  222. '0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa'
  223. ),
  224. ].map((item) => Fp.create(item));
  225. // For Fp2 roots of unity.
  226. const rv1 = BigInt(
  227. '0x6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09'
  228. );
  229. // const ev1 =
  230. // BigInt('0x699be3b8c6870965e5bf892ad5d2cc7b0e85a117402dfd83b7f4a947e02d978498255a2aaec0ac627b5afbdf1bf1c90');
  231. // const ev2 =
  232. // BigInt('0x8157cd83046453f5dd0972b6e3949e4288020b5b8a9cc99ca07e27089a2ce2436d965026adad3ef7baba37f2183e9b5');
  233. // const ev3 =
  234. // BigInt('0xab1c2ffdd6c253ca155231eb3e71ba044fd562f6f72bc5bad5ec46a0b7a3b0247cf08ce6c6317f40edbc653a72dee17');
  235. // const ev4 =
  236. // BigInt('0xaa404866706722864480885d68ad0ccac1967c7544b447873cc37e0181271e006df72162a3d3e0287bf597fbf7f8fc1');
  237. // Eighth roots of unity, used for computing square roots in Fp2.
  238. // To verify or re-calculate:
  239. // Array(8).fill(new Fp2([1n, 1n])).map((fp2, k) => fp2.pow(Fp2.ORDER * BigInt(k) / 8n))
  240. const FP2_ROOTS_OF_UNITY = [
  241. [_1n, _0n],
  242. [rv1, -rv1],
  243. [_0n, _1n],
  244. [rv1, rv1],
  245. [-_1n, _0n],
  246. [-rv1, rv1],
  247. [_0n, -_1n],
  248. [-rv1, -rv1],
  249. ].map((pair) => Fp2.fromBigTuple(pair));
  250. // eta values, used for computing sqrt(g(X1(t)))
  251. // const FP2_ETAs = [
  252. // [ev1, ev2],
  253. // [-ev2, ev1],
  254. // [ev3, ev4],
  255. // [-ev4, ev3],
  256. // ].map((pair) => Fp2.fromBigTuple(pair));
  257. // Finite extension field over irreducible polynominal.
  258. // Fp2(v) / (v³ - ξ) where ξ = u + 1
  259. type BigintSix = [bigint, bigint, bigint, bigint, bigint, bigint];
  260. type Fp6 = { c0: Fp2; c1: Fp2; c2: Fp2 };
  261. const Fp6Add = ({ c0, c1, c2 }: Fp6, { c0: r0, c1: r1, c2: r2 }: Fp6) => ({
  262. c0: Fp2.add(c0, r0),
  263. c1: Fp2.add(c1, r1),
  264. c2: Fp2.add(c2, r2),
  265. });
  266. const Fp6Subtract = ({ c0, c1, c2 }: Fp6, { c0: r0, c1: r1, c2: r2 }: Fp6) => ({
  267. c0: Fp2.sub(c0, r0),
  268. c1: Fp2.sub(c1, r1),
  269. c2: Fp2.sub(c2, r2),
  270. });
  271. const Fp6Multiply = ({ c0, c1, c2 }: Fp6, rhs: Fp6 | bigint) => {
  272. if (typeof rhs === 'bigint') {
  273. return {
  274. c0: Fp2.mul(c0, rhs),
  275. c1: Fp2.mul(c1, rhs),
  276. c2: Fp2.mul(c2, rhs),
  277. };
  278. }
  279. const { c0: r0, c1: r1, c2: r2 } = rhs;
  280. const t0 = Fp2.mul(c0, r0); // c0 * o0
  281. const t1 = Fp2.mul(c1, r1); // c1 * o1
  282. const t2 = Fp2.mul(c2, r2); // c2 * o2
  283. return {
  284. // t0 + (c1 + c2) * (r1 * r2) - (T1 + T2) * (u + 1)
  285. c0: Fp2.add(
  286. t0,
  287. Fp2.mulByNonresidue(Fp2.sub(Fp2.mul(Fp2.add(c1, c2), Fp2.add(r1, r2)), Fp2.add(t1, t2)))
  288. ),
  289. // (c0 + c1) * (r0 + r1) - (T0 + T1) + T2 * (u + 1)
  290. c1: Fp2.add(
  291. Fp2.sub(Fp2.mul(Fp2.add(c0, c1), Fp2.add(r0, r1)), Fp2.add(t0, t1)),
  292. Fp2.mulByNonresidue(t2)
  293. ),
  294. // T1 + (c0 + c2) * (r0 + r2) - T0 + T2
  295. c2: Fp2.sub(Fp2.add(t1, Fp2.mul(Fp2.add(c0, c2), Fp2.add(r0, r2))), Fp2.add(t0, t2)),
  296. };
  297. };
  298. const Fp6Square = ({ c0, c1, c2 }: Fp6) => {
  299. let t0 = Fp2.sqr(c0); // c0²
  300. let t1 = Fp2.mul(Fp2.mul(c0, c1), _2n); // 2 * c0 * c1
  301. let t3 = Fp2.mul(Fp2.mul(c1, c2), _2n); // 2 * c1 * c2
  302. let t4 = Fp2.sqr(c2); // c2²
  303. return {
  304. c0: Fp2.add(Fp2.mulByNonresidue(t3), t0), // T3 * (u + 1) + T0
  305. c1: Fp2.add(Fp2.mulByNonresidue(t4), t1), // T4 * (u + 1) + T1
  306. // T1 + (c0 - c1 + c2)² + T3 - T0 - T4
  307. c2: Fp2.sub(Fp2.sub(Fp2.add(Fp2.add(t1, Fp2.sqr(Fp2.add(Fp2.sub(c0, c1), c2))), t3), t0), t4),
  308. };
  309. };
  310. type Fp6Utils = {
  311. fromBigSix: (tuple: BigintSix) => Fp6;
  312. mulByNonresidue: (num: Fp6) => Fp6;
  313. frobeniusMap(num: Fp6, power: number): Fp6;
  314. multiplyBy1(num: Fp6, b1: Fp2): Fp6;
  315. multiplyBy01(num: Fp6, b0: Fp2, b1: Fp2): Fp6;
  316. multiplyByFp2(lhs: Fp6, rhs: Fp2): Fp6;
  317. };
  318. const Fp6: mod.IField<Fp6> & Fp6Utils = {
  319. ORDER: Fp2.ORDER, // TODO: unused, but need to verify
  320. BITS: 3 * Fp2.BITS,
  321. BYTES: 3 * Fp2.BYTES,
  322. MASK: bitMask(3 * Fp2.BITS),
  323. ZERO: { c0: Fp2.ZERO, c1: Fp2.ZERO, c2: Fp2.ZERO },
  324. ONE: { c0: Fp2.ONE, c1: Fp2.ZERO, c2: Fp2.ZERO },
  325. create: (num) => num,
  326. isValid: ({ c0, c1, c2 }) => Fp2.isValid(c0) && Fp2.isValid(c1) && Fp2.isValid(c2),
  327. is0: ({ c0, c1, c2 }) => Fp2.is0(c0) && Fp2.is0(c1) && Fp2.is0(c2),
  328. neg: ({ c0, c1, c2 }) => ({ c0: Fp2.neg(c0), c1: Fp2.neg(c1), c2: Fp2.neg(c2) }),
  329. eql: ({ c0, c1, c2 }, { c0: r0, c1: r1, c2: r2 }) =>
  330. Fp2.eql(c0, r0) && Fp2.eql(c1, r1) && Fp2.eql(c2, r2),
  331. sqrt: () => {
  332. throw new Error('Not implemented');
  333. },
  334. // Do we need division by bigint at all? Should be done via order:
  335. div: (lhs, rhs) => Fp6.mul(lhs, typeof rhs === 'bigint' ? Fp.inv(Fp.create(rhs)) : Fp6.inv(rhs)),
  336. pow: (num, power) => mod.FpPow(Fp6, num, power),
  337. invertBatch: (nums) => mod.FpInvertBatch(Fp6, nums),
  338. // Normalized
  339. add: Fp6Add,
  340. sub: Fp6Subtract,
  341. mul: Fp6Multiply,
  342. sqr: Fp6Square,
  343. // NonNormalized stuff
  344. addN: Fp6Add,
  345. subN: Fp6Subtract,
  346. mulN: Fp6Multiply,
  347. sqrN: Fp6Square,
  348. inv: ({ c0, c1, c2 }) => {
  349. let t0 = Fp2.sub(Fp2.sqr(c0), Fp2.mulByNonresidue(Fp2.mul(c2, c1))); // c0² - c2 * c1 * (u + 1)
  350. let t1 = Fp2.sub(Fp2.mulByNonresidue(Fp2.sqr(c2)), Fp2.mul(c0, c1)); // c2² * (u + 1) - c0 * c1
  351. let t2 = Fp2.sub(Fp2.sqr(c1), Fp2.mul(c0, c2)); // c1² - c0 * c2
  352. // 1/(((c2 * T1 + c1 * T2) * v) + c0 * T0)
  353. let t4 = Fp2.inv(
  354. Fp2.add(Fp2.mulByNonresidue(Fp2.add(Fp2.mul(c2, t1), Fp2.mul(c1, t2))), Fp2.mul(c0, t0))
  355. );
  356. return { c0: Fp2.mul(t4, t0), c1: Fp2.mul(t4, t1), c2: Fp2.mul(t4, t2) };
  357. },
  358. // Bytes utils
  359. fromBytes: (b: Uint8Array): Fp6 => {
  360. if (b.length !== Fp6.BYTES) throw new Error(`fromBytes wrong length=${b.length}`);
  361. return {
  362. c0: Fp2.fromBytes(b.subarray(0, Fp2.BYTES)),
  363. c1: Fp2.fromBytes(b.subarray(Fp2.BYTES, 2 * Fp2.BYTES)),
  364. c2: Fp2.fromBytes(b.subarray(2 * Fp2.BYTES)),
  365. };
  366. },
  367. toBytes: ({ c0, c1, c2 }): Uint8Array =>
  368. concatB(Fp2.toBytes(c0), Fp2.toBytes(c1), Fp2.toBytes(c2)),
  369. cmov: ({ c0, c1, c2 }: Fp6, { c0: r0, c1: r1, c2: r2 }: Fp6, c) => ({
  370. c0: Fp2.cmov(c0, r0, c),
  371. c1: Fp2.cmov(c1, r1, c),
  372. c2: Fp2.cmov(c2, r2, c),
  373. }),
  374. // Utils
  375. // fromTriple(triple: [Fp2, Fp2, Fp2]) {
  376. // return new Fp6(...triple);
  377. // }
  378. // toString() {
  379. // return `Fp6(${this.c0} + ${this.c1} * v, ${this.c2} * v^2)`;
  380. // }
  381. fromBigSix: (t: BigintSix): Fp6 => {
  382. if (!Array.isArray(t) || t.length !== 6) throw new Error('Invalid Fp6 usage');
  383. return {
  384. c0: Fp2.fromBigTuple(t.slice(0, 2)),
  385. c1: Fp2.fromBigTuple(t.slice(2, 4)),
  386. c2: Fp2.fromBigTuple(t.slice(4, 6)),
  387. };
  388. },
  389. frobeniusMap: ({ c0, c1, c2 }, power: number) => ({
  390. c0: Fp2.frobeniusMap(c0, power),
  391. c1: Fp2.mul(Fp2.frobeniusMap(c1, power), FP6_FROBENIUS_COEFFICIENTS_1[power % 6]),
  392. c2: Fp2.mul(Fp2.frobeniusMap(c2, power), FP6_FROBENIUS_COEFFICIENTS_2[power % 6]),
  393. }),
  394. mulByNonresidue: ({ c0, c1, c2 }) => ({ c0: Fp2.mulByNonresidue(c2), c1: c0, c2: c1 }),
  395. // Sparse multiplication
  396. multiplyBy1: ({ c0, c1, c2 }, b1: Fp2): Fp6 => ({
  397. c0: Fp2.mulByNonresidue(Fp2.mul(c2, b1)),
  398. c1: Fp2.mul(c0, b1),
  399. c2: Fp2.mul(c1, b1),
  400. }),
  401. // Sparse multiplication
  402. multiplyBy01({ c0, c1, c2 }, b0: Fp2, b1: Fp2): Fp6 {
  403. let t0 = Fp2.mul(c0, b0); // c0 * b0
  404. let t1 = Fp2.mul(c1, b1); // c1 * b1
  405. return {
  406. // ((c1 + c2) * b1 - T1) * (u + 1) + T0
  407. c0: Fp2.add(Fp2.mulByNonresidue(Fp2.sub(Fp2.mul(Fp2.add(c1, c2), b1), t1)), t0),
  408. // (b0 + b1) * (c0 + c1) - T0 - T1
  409. c1: Fp2.sub(Fp2.sub(Fp2.mul(Fp2.add(b0, b1), Fp2.add(c0, c1)), t0), t1),
  410. // (c0 + c2) * b0 - T0 + T1
  411. c2: Fp2.add(Fp2.sub(Fp2.mul(Fp2.add(c0, c2), b0), t0), t1),
  412. };
  413. },
  414. multiplyByFp2: ({ c0, c1, c2 }, rhs: Fp2): Fp6 => ({
  415. c0: Fp2.mul(c0, rhs),
  416. c1: Fp2.mul(c1, rhs),
  417. c2: Fp2.mul(c2, rhs),
  418. }),
  419. };
  420. const FP6_FROBENIUS_COEFFICIENTS_1 = [
  421. [BigInt('0x1'), BigInt('0x0')],
  422. [
  423. BigInt('0x0'),
  424. BigInt(
  425. '0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'
  426. ),
  427. ],
  428. [
  429. BigInt(
  430. '0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'
  431. ),
  432. BigInt('0x0'),
  433. ],
  434. [BigInt('0x0'), BigInt('0x1')],
  435. [
  436. BigInt(
  437. '0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'
  438. ),
  439. BigInt('0x0'),
  440. ],
  441. [
  442. BigInt('0x0'),
  443. BigInt(
  444. '0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'
  445. ),
  446. ],
  447. ].map((pair) => Fp2.fromBigTuple(pair));
  448. const FP6_FROBENIUS_COEFFICIENTS_2 = [
  449. [BigInt('0x1'), BigInt('0x0')],
  450. [
  451. BigInt(
  452. '0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad'
  453. ),
  454. BigInt('0x0'),
  455. ],
  456. [
  457. BigInt(
  458. '0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'
  459. ),
  460. BigInt('0x0'),
  461. ],
  462. [
  463. BigInt(
  464. '0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa'
  465. ),
  466. BigInt('0x0'),
  467. ],
  468. [
  469. BigInt(
  470. '0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'
  471. ),
  472. BigInt('0x0'),
  473. ],
  474. [
  475. BigInt(
  476. '0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffeffff'
  477. ),
  478. BigInt('0x0'),
  479. ],
  480. ].map((pair) => Fp2.fromBigTuple(pair));
  481. // Finite extension field over irreducible polynominal.
  482. // Fp₁₂ = Fp₆² => Fp₂³
  483. // Fp₆(w) / (w² - γ) where γ = v
  484. type Fp12 = { c0: Fp6; c1: Fp6 };
  485. // The BLS parameter x for BLS12-381
  486. const BLS_X = BigInt('0xd201000000010000');
  487. const BLS_X_LEN = bitLen(BLS_X);
  488. // prettier-ignore
  489. type BigintTwelve = [
  490. bigint, bigint, bigint, bigint, bigint, bigint,
  491. bigint, bigint, bigint, bigint, bigint, bigint
  492. ];
  493. const Fp12Add = ({ c0, c1 }: Fp12, { c0: r0, c1: r1 }: Fp12) => ({
  494. c0: Fp6.add(c0, r0),
  495. c1: Fp6.add(c1, r1),
  496. });
  497. const Fp12Subtract = ({ c0, c1 }: Fp12, { c0: r0, c1: r1 }: Fp12) => ({
  498. c0: Fp6.sub(c0, r0),
  499. c1: Fp6.sub(c1, r1),
  500. });
  501. const Fp12Multiply = ({ c0, c1 }: Fp12, rhs: Fp12 | bigint) => {
  502. if (typeof rhs === 'bigint') return { c0: Fp6.mul(c0, rhs), c1: Fp6.mul(c1, rhs) };
  503. let { c0: r0, c1: r1 } = rhs;
  504. let t1 = Fp6.mul(c0, r0); // c0 * r0
  505. let t2 = Fp6.mul(c1, r1); // c1 * r1
  506. return {
  507. c0: Fp6.add(t1, Fp6.mulByNonresidue(t2)), // T1 + T2 * v
  508. // (c0 + c1) * (r0 + r1) - (T1 + T2)
  509. c1: Fp6.sub(Fp6.mul(Fp6.add(c0, c1), Fp6.add(r0, r1)), Fp6.add(t1, t2)),
  510. };
  511. };
  512. const Fp12Square = ({ c0, c1 }: Fp12) => {
  513. let ab = Fp6.mul(c0, c1); // c0 * c1
  514. return {
  515. // (c1 * v + c0) * (c0 + c1) - AB - AB * v
  516. c0: Fp6.sub(
  517. Fp6.sub(Fp6.mul(Fp6.add(Fp6.mulByNonresidue(c1), c0), Fp6.add(c0, c1)), ab),
  518. Fp6.mulByNonresidue(ab)
  519. ),
  520. c1: Fp6.add(ab, ab),
  521. }; // AB + AB
  522. };
  523. function Fp4Square(a: Fp2, b: Fp2): { first: Fp2; second: Fp2 } {
  524. const a2 = Fp2.sqr(a);
  525. const b2 = Fp2.sqr(b);
  526. return {
  527. first: Fp2.add(Fp2.mulByNonresidue(b2), a2), // b² * Nonresidue + a²
  528. second: Fp2.sub(Fp2.sub(Fp2.sqr(Fp2.add(a, b)), a2), b2), // (a + b)² - a² - b²
  529. };
  530. }
  531. type Fp12Utils = {
  532. fromBigTwelve: (t: BigintTwelve) => Fp12;
  533. frobeniusMap(num: Fp12, power: number): Fp12;
  534. multiplyBy014(num: Fp12, o0: Fp2, o1: Fp2, o4: Fp2): Fp12;
  535. multiplyByFp2(lhs: Fp12, rhs: Fp2): Fp12;
  536. conjugate(num: Fp12): Fp12;
  537. finalExponentiate(num: Fp12): Fp12;
  538. _cyclotomicSquare(num: Fp12): Fp12;
  539. _cyclotomicExp(num: Fp12, n: bigint): Fp12;
  540. };
  541. const Fp12: mod.IField<Fp12> & Fp12Utils = {
  542. ORDER: Fp2.ORDER, // TODO: unused, but need to verify
  543. BITS: 2 * Fp2.BITS,
  544. BYTES: 2 * Fp2.BYTES,
  545. MASK: bitMask(2 * Fp2.BITS),
  546. ZERO: { c0: Fp6.ZERO, c1: Fp6.ZERO },
  547. ONE: { c0: Fp6.ONE, c1: Fp6.ZERO },
  548. create: (num) => num,
  549. isValid: ({ c0, c1 }) => Fp6.isValid(c0) && Fp6.isValid(c1),
  550. is0: ({ c0, c1 }) => Fp6.is0(c0) && Fp6.is0(c1),
  551. neg: ({ c0, c1 }) => ({ c0: Fp6.neg(c0), c1: Fp6.neg(c1) }),
  552. eql: ({ c0, c1 }, { c0: r0, c1: r1 }) => Fp6.eql(c0, r0) && Fp6.eql(c1, r1),
  553. sqrt: () => {
  554. throw new Error('Not implemented');
  555. },
  556. inv: ({ c0, c1 }) => {
  557. let t = Fp6.inv(Fp6.sub(Fp6.sqr(c0), Fp6.mulByNonresidue(Fp6.sqr(c1)))); // 1 / (c0² - c1² * v)
  558. return { c0: Fp6.mul(c0, t), c1: Fp6.neg(Fp6.mul(c1, t)) }; // ((C0 * T) * T) + (-C1 * T) * w
  559. },
  560. div: (lhs, rhs) =>
  561. Fp12.mul(lhs, typeof rhs === 'bigint' ? Fp.inv(Fp.create(rhs)) : Fp12.inv(rhs)),
  562. pow: (num, power) => mod.FpPow(Fp12, num, power),
  563. invertBatch: (nums) => mod.FpInvertBatch(Fp12, nums),
  564. // Normalized
  565. add: Fp12Add,
  566. sub: Fp12Subtract,
  567. mul: Fp12Multiply,
  568. sqr: Fp12Square,
  569. // NonNormalized stuff
  570. addN: Fp12Add,
  571. subN: Fp12Subtract,
  572. mulN: Fp12Multiply,
  573. sqrN: Fp12Square,
  574. // Bytes utils
  575. fromBytes: (b: Uint8Array): Fp12 => {
  576. if (b.length !== Fp12.BYTES) throw new Error(`fromBytes wrong length=${b.length}`);
  577. return {
  578. c0: Fp6.fromBytes(b.subarray(0, Fp6.BYTES)),
  579. c1: Fp6.fromBytes(b.subarray(Fp6.BYTES)),
  580. };
  581. },
  582. toBytes: ({ c0, c1 }): Uint8Array => concatB(Fp6.toBytes(c0), Fp6.toBytes(c1)),
  583. cmov: ({ c0, c1 }, { c0: r0, c1: r1 }, c) => ({
  584. c0: Fp6.cmov(c0, r0, c),
  585. c1: Fp6.cmov(c1, r1, c),
  586. }),
  587. // Utils
  588. // toString() {
  589. // return `Fp12(${this.c0} + ${this.c1} * w)`;
  590. // },
  591. // fromTuple(c: [Fp6, Fp6]) {
  592. // return new Fp12(...c);
  593. // }
  594. fromBigTwelve: (t: BigintTwelve): Fp12 => ({
  595. c0: Fp6.fromBigSix(t.slice(0, 6) as BigintSix),
  596. c1: Fp6.fromBigSix(t.slice(6, 12) as BigintSix),
  597. }),
  598. // Raises to q**i -th power
  599. frobeniusMap(lhs, power: number) {
  600. const r0 = Fp6.frobeniusMap(lhs.c0, power);
  601. const { c0, c1, c2 } = Fp6.frobeniusMap(lhs.c1, power);
  602. const coeff = FP12_FROBENIUS_COEFFICIENTS[power % 12];
  603. return {
  604. c0: r0,
  605. c1: Fp6.create({
  606. c0: Fp2.mul(c0, coeff),
  607. c1: Fp2.mul(c1, coeff),
  608. c2: Fp2.mul(c2, coeff),
  609. }),
  610. };
  611. },
  612. // Sparse multiplication
  613. multiplyBy014: ({ c0, c1 }, o0: Fp2, o1: Fp2, o4: Fp2) => {
  614. let t0 = Fp6.multiplyBy01(c0, o0, o1);
  615. let t1 = Fp6.multiplyBy1(c1, o4);
  616. return {
  617. c0: Fp6.add(Fp6.mulByNonresidue(t1), t0), // T1 * v + T0
  618. // (c1 + c0) * [o0, o1+o4] - T0 - T1
  619. c1: Fp6.sub(Fp6.sub(Fp6.multiplyBy01(Fp6.add(c1, c0), o0, Fp2.add(o1, o4)), t0), t1),
  620. };
  621. },
  622. multiplyByFp2: ({ c0, c1 }, rhs: Fp2): Fp12 => ({
  623. c0: Fp6.multiplyByFp2(c0, rhs),
  624. c1: Fp6.multiplyByFp2(c1, rhs),
  625. }),
  626. conjugate: ({ c0, c1 }): Fp12 => ({ c0, c1: Fp6.neg(c1) }),
  627. // A cyclotomic group is a subgroup of Fp^n defined by
  628. // GΦₙ(p) = {α ∈ Fpⁿ : α^Φₙ(p) = 1}
  629. // The result of any pairing is in a cyclotomic subgroup
  630. // https://eprint.iacr.org/2009/565.pdf
  631. _cyclotomicSquare: ({ c0, c1 }): Fp12 => {
  632. const { c0: c0c0, c1: c0c1, c2: c0c2 } = c0;
  633. const { c0: c1c0, c1: c1c1, c2: c1c2 } = c1;
  634. const { first: t3, second: t4 } = Fp4Square(c0c0, c1c1);
  635. const { first: t5, second: t6 } = Fp4Square(c1c0, c0c2);
  636. const { first: t7, second: t8 } = Fp4Square(c0c1, c1c2);
  637. let t9 = Fp2.mulByNonresidue(t8); // T8 * (u + 1)
  638. return {
  639. c0: Fp6.create({
  640. c0: Fp2.add(Fp2.mul(Fp2.sub(t3, c0c0), _2n), t3), // 2 * (T3 - c0c0) + T3
  641. c1: Fp2.add(Fp2.mul(Fp2.sub(t5, c0c1), _2n), t5), // 2 * (T5 - c0c1) + T5
  642. c2: Fp2.add(Fp2.mul(Fp2.sub(t7, c0c2), _2n), t7),
  643. }), // 2 * (T7 - c0c2) + T7
  644. c1: Fp6.create({
  645. c0: Fp2.add(Fp2.mul(Fp2.add(t9, c1c0), _2n), t9), // 2 * (T9 + c1c0) + T9
  646. c1: Fp2.add(Fp2.mul(Fp2.add(t4, c1c1), _2n), t4), // 2 * (T4 + c1c1) + T4
  647. c2: Fp2.add(Fp2.mul(Fp2.add(t6, c1c2), _2n), t6),
  648. }),
  649. }; // 2 * (T6 + c1c2) + T6
  650. },
  651. _cyclotomicExp(num, n) {
  652. let z = Fp12.ONE;
  653. for (let i = BLS_X_LEN - 1; i >= 0; i--) {
  654. z = Fp12._cyclotomicSquare(z);
  655. if (bitGet(n, i)) z = Fp12.mul(z, num);
  656. }
  657. return z;
  658. },
  659. // https://eprint.iacr.org/2010/354.pdf
  660. // https://eprint.iacr.org/2009/565.pdf
  661. finalExponentiate: (num) => {
  662. const x = BLS_X;
  663. // this^(q⁶) / this
  664. const t0 = Fp12.div(Fp12.frobeniusMap(num, 6), num);
  665. // t0^(q²) * t0
  666. const t1 = Fp12.mul(Fp12.frobeniusMap(t0, 2), t0);
  667. const t2 = Fp12.conjugate(Fp12._cyclotomicExp(t1, x));
  668. const t3 = Fp12.mul(Fp12.conjugate(Fp12._cyclotomicSquare(t1)), t2);
  669. const t4 = Fp12.conjugate(Fp12._cyclotomicExp(t3, x));
  670. const t5 = Fp12.conjugate(Fp12._cyclotomicExp(t4, x));
  671. const t6 = Fp12.mul(Fp12.conjugate(Fp12._cyclotomicExp(t5, x)), Fp12._cyclotomicSquare(t2));
  672. const t7 = Fp12.conjugate(Fp12._cyclotomicExp(t6, x));
  673. const t2_t5_pow_q2 = Fp12.frobeniusMap(Fp12.mul(t2, t5), 2);
  674. const t4_t1_pow_q3 = Fp12.frobeniusMap(Fp12.mul(t4, t1), 3);
  675. const t6_t1c_pow_q1 = Fp12.frobeniusMap(Fp12.mul(t6, Fp12.conjugate(t1)), 1);
  676. const t7_t3c_t1 = Fp12.mul(Fp12.mul(t7, Fp12.conjugate(t3)), t1);
  677. // (t2 * t5)^(q²) * (t4 * t1)^(q³) * (t6 * t1.conj)^(q^1) * t7 * t3.conj * t1
  678. return Fp12.mul(Fp12.mul(Fp12.mul(t2_t5_pow_q2, t4_t1_pow_q3), t6_t1c_pow_q1), t7_t3c_t1);
  679. },
  680. };
  681. const FP12_FROBENIUS_COEFFICIENTS = [
  682. [BigInt('0x1'), BigInt('0x0')],
  683. [
  684. BigInt(
  685. '0x1904d3bf02bb0667c231beb4202c0d1f0fd603fd3cbd5f4f7b2443d784bab9c4f67ea53d63e7813d8d0775ed92235fb8'
  686. ),
  687. BigInt(
  688. '0x00fc3e2b36c4e03288e9e902231f9fb854a14787b6c7b36fec0c8ec971f63c5f282d5ac14d6c7ec22cf78a126ddc4af3'
  689. ),
  690. ],
  691. [
  692. BigInt(
  693. '0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffeffff'
  694. ),
  695. BigInt('0x0'),
  696. ],
  697. [
  698. BigInt(
  699. '0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2'
  700. ),
  701. BigInt(
  702. '0x06af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09'
  703. ),
  704. ],
  705. [
  706. BigInt(
  707. '0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'
  708. ),
  709. BigInt('0x0'),
  710. ],
  711. [
  712. BigInt(
  713. '0x144e4211384586c16bd3ad4afa99cc9170df3560e77982d0db45f3536814f0bd5871c1908bd478cd1ee605167ff82995'
  714. ),
  715. BigInt(
  716. '0x05b2cfd9013a5fd8df47fa6b48b1e045f39816240c0b8fee8beadf4d8e9c0566c63a3e6e257f87329b18fae980078116'
  717. ),
  718. ],
  719. [
  720. BigInt(
  721. '0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa'
  722. ),
  723. BigInt('0x0'),
  724. ],
  725. [
  726. BigInt(
  727. '0x00fc3e2b36c4e03288e9e902231f9fb854a14787b6c7b36fec0c8ec971f63c5f282d5ac14d6c7ec22cf78a126ddc4af3'
  728. ),
  729. BigInt(
  730. '0x1904d3bf02bb0667c231beb4202c0d1f0fd603fd3cbd5f4f7b2443d784bab9c4f67ea53d63e7813d8d0775ed92235fb8'
  731. ),
  732. ],
  733. [
  734. BigInt(
  735. '0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'
  736. ),
  737. BigInt('0x0'),
  738. ],
  739. [
  740. BigInt(
  741. '0x06af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09'
  742. ),
  743. BigInt(
  744. '0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2'
  745. ),
  746. ],
  747. [
  748. BigInt(
  749. '0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad'
  750. ),
  751. BigInt('0x0'),
  752. ],
  753. [
  754. BigInt(
  755. '0x05b2cfd9013a5fd8df47fa6b48b1e045f39816240c0b8fee8beadf4d8e9c0566c63a3e6e257f87329b18fae980078116'
  756. ),
  757. BigInt(
  758. '0x144e4211384586c16bd3ad4afa99cc9170df3560e77982d0db45f3536814f0bd5871c1908bd478cd1ee605167ff82995'
  759. ),
  760. ],
  761. ].map((n) => Fp2.fromBigTuple(n));
  762. // END OF CURVE FIELDS
  763. // HashToCurve
  764. // 3-isogeny map from E' to E https://www.rfc-editor.org/rfc/rfc9380#appendix-E.3
  765. const isogenyMapG2 = isogenyMap(
  766. Fp2,
  767. [
  768. // xNum
  769. [
  770. [
  771. '0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97d6',
  772. '0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97d6',
  773. ],
  774. [
  775. '0x0',
  776. '0x11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71a',
  777. ],
  778. [
  779. '0x11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71e',
  780. '0x8ab05f8bdd54cde190937e76bc3e447cc27c3d6fbd7063fcd104635a790520c0a395554e5c6aaaa9354ffffffffe38d',
  781. ],
  782. [
  783. '0x171d6541fa38ccfaed6dea691f5fb614cb14b4e7f4e810aa22d6108f142b85757098e38d0f671c7188e2aaaaaaaa5ed1',
  784. '0x0',
  785. ],
  786. ],
  787. // xDen
  788. [
  789. [
  790. '0x0',
  791. '0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa63',
  792. ],
  793. [
  794. '0xc',
  795. '0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa9f',
  796. ],
  797. ['0x1', '0x0'], // LAST 1
  798. ],
  799. // yNum
  800. [
  801. [
  802. '0x1530477c7ab4113b59a4c18b076d11930f7da5d4a07f649bf54439d87d27e500fc8c25ebf8c92f6812cfc71c71c6d706',
  803. '0x1530477c7ab4113b59a4c18b076d11930f7da5d4a07f649bf54439d87d27e500fc8c25ebf8c92f6812cfc71c71c6d706',
  804. ],
  805. [
  806. '0x0',
  807. '0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97be',
  808. ],
  809. [
  810. '0x11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71c',
  811. '0x8ab05f8bdd54cde190937e76bc3e447cc27c3d6fbd7063fcd104635a790520c0a395554e5c6aaaa9354ffffffffe38f',
  812. ],
  813. [
  814. '0x124c9ad43b6cf79bfbf7043de3811ad0761b0f37a1e26286b0e977c69aa274524e79097a56dc4bd9e1b371c71c718b10',
  815. '0x0',
  816. ],
  817. ],
  818. // yDen
  819. [
  820. [
  821. '0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa8fb',
  822. '0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa8fb',
  823. ],
  824. [
  825. '0x0',
  826. '0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa9d3',
  827. ],
  828. [
  829. '0x12',
  830. '0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa99',
  831. ],
  832. ['0x1', '0x0'], // LAST 1
  833. ],
  834. ].map((i) => i.map((pair) => Fp2.fromBigTuple(pair.map(BigInt)))) as [Fp2[], Fp2[], Fp2[], Fp2[]]
  835. );
  836. // 11-isogeny map from E' to E
  837. const isogenyMapG1 = isogenyMap(
  838. Fp,
  839. [
  840. // xNum
  841. [
  842. '0x11a05f2b1e833340b809101dd99815856b303e88a2d7005ff2627b56cdb4e2c85610c2d5f2e62d6eaeac1662734649b7',
  843. '0x17294ed3e943ab2f0588bab22147a81c7c17e75b2f6a8417f565e33c70d1e86b4838f2a6f318c356e834eef1b3cb83bb',
  844. '0xd54005db97678ec1d1048c5d10a9a1bce032473295983e56878e501ec68e25c958c3e3d2a09729fe0179f9dac9edcb0',
  845. '0x1778e7166fcc6db74e0609d307e55412d7f5e4656a8dbf25f1b33289f1b330835336e25ce3107193c5b388641d9b6861',
  846. '0xe99726a3199f4436642b4b3e4118e5499db995a1257fb3f086eeb65982fac18985a286f301e77c451154ce9ac8895d9',
  847. '0x1630c3250d7313ff01d1201bf7a74ab5db3cb17dd952799b9ed3ab9097e68f90a0870d2dcae73d19cd13c1c66f652983',
  848. '0xd6ed6553fe44d296a3726c38ae652bfb11586264f0f8ce19008e218f9c86b2a8da25128c1052ecaddd7f225a139ed84',
  849. '0x17b81e7701abdbe2e8743884d1117e53356de5ab275b4db1a682c62ef0f2753339b7c8f8c8f475af9ccb5618e3f0c88e',
  850. '0x80d3cf1f9a78fc47b90b33563be990dc43b756ce79f5574a2c596c928c5d1de4fa295f296b74e956d71986a8497e317',
  851. '0x169b1f8e1bcfa7c42e0c37515d138f22dd2ecb803a0c5c99676314baf4bb1b7fa3190b2edc0327797f241067be390c9e',
  852. '0x10321da079ce07e272d8ec09d2565b0dfa7dccdde6787f96d50af36003b14866f69b771f8c285decca67df3f1605fb7b',
  853. '0x6e08c248e260e70bd1e962381edee3d31d79d7e22c837bc23c0bf1bc24c6b68c24b1b80b64d391fa9c8ba2e8ba2d229',
  854. ],
  855. // xDen
  856. [
  857. '0x8ca8d548cff19ae18b2e62f4bd3fa6f01d5ef4ba35b48ba9c9588617fc8ac62b558d681be343df8993cf9fa40d21b1c',
  858. '0x12561a5deb559c4348b4711298e536367041e8ca0cf0800c0126c2588c48bf5713daa8846cb026e9e5c8276ec82b3bff',
  859. '0xb2962fe57a3225e8137e629bff2991f6f89416f5a718cd1fca64e00b11aceacd6a3d0967c94fedcfcc239ba5cb83e19',
  860. '0x3425581a58ae2fec83aafef7c40eb545b08243f16b1655154cca8abc28d6fd04976d5243eecf5c4130de8938dc62cd8',
  861. '0x13a8e162022914a80a6f1d5f43e7a07dffdfc759a12062bb8d6b44e833b306da9bd29ba81f35781d539d395b3532a21e',
  862. '0xe7355f8e4e667b955390f7f0506c6e9395735e9ce9cad4d0a43bcef24b8982f7400d24bc4228f11c02df9a29f6304a5',
  863. '0x772caacf16936190f3e0c63e0596721570f5799af53a1894e2e073062aede9cea73b3538f0de06cec2574496ee84a3a',
  864. '0x14a7ac2a9d64a8b230b3f5b074cf01996e7f63c21bca68a81996e1cdf9822c580fa5b9489d11e2d311f7d99bbdcc5a5e',
  865. '0xa10ecf6ada54f825e920b3dafc7a3cce07f8d1d7161366b74100da67f39883503826692abba43704776ec3a79a1d641',
  866. '0x95fc13ab9e92ad4476d6e3eb3a56680f682b4ee96f7d03776df533978f31c1593174e4b4b7865002d6384d168ecdd0a',
  867. '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001', // LAST 1
  868. ],
  869. // yNum
  870. [
  871. '0x90d97c81ba24ee0259d1f094980dcfa11ad138e48a869522b52af6c956543d3cd0c7aee9b3ba3c2be9845719707bb33',
  872. '0x134996a104ee5811d51036d776fb46831223e96c254f383d0f906343eb67ad34d6c56711962fa8bfe097e75a2e41c696',
  873. '0xcc786baa966e66f4a384c86a3b49942552e2d658a31ce2c344be4b91400da7d26d521628b00523b8dfe240c72de1f6',
  874. '0x1f86376e8981c217898751ad8746757d42aa7b90eeb791c09e4a3ec03251cf9de405aba9ec61deca6355c77b0e5f4cb',
  875. '0x8cc03fdefe0ff135caf4fe2a21529c4195536fbe3ce50b879833fd221351adc2ee7f8dc099040a841b6daecf2e8fedb',
  876. '0x16603fca40634b6a2211e11db8f0a6a074a7d0d4afadb7bd76505c3d3ad5544e203f6326c95a807299b23ab13633a5f0',
  877. '0x4ab0b9bcfac1bbcb2c977d027796b3ce75bb8ca2be184cb5231413c4d634f3747a87ac2460f415ec961f8855fe9d6f2',
  878. '0x987c8d5333ab86fde9926bd2ca6c674170a05bfe3bdd81ffd038da6c26c842642f64550fedfe935a15e4ca31870fb29',
  879. '0x9fc4018bd96684be88c9e221e4da1bb8f3abd16679dc26c1e8b6e6a1f20cabe69d65201c78607a360370e577bdba587',
  880. '0xe1bba7a1186bdb5223abde7ada14a23c42a0ca7915af6fe06985e7ed1e4d43b9b3f7055dd4eba6f2bafaaebca731c30',
  881. '0x19713e47937cd1be0dfd0b8f1d43fb93cd2fcbcb6caf493fd1183e416389e61031bf3a5cce3fbafce813711ad011c132',
  882. '0x18b46a908f36f6deb918c143fed2edcc523559b8aaf0c2462e6bfe7f911f643249d9cdf41b44d606ce07c8a4d0074d8e',
  883. '0xb182cac101b9399d155096004f53f447aa7b12a3426b08ec02710e807b4633f06c851c1919211f20d4c04f00b971ef8',
  884. '0x245a394ad1eca9b72fc00ae7be315dc757b3b080d4c158013e6632d3c40659cc6cf90ad1c232a6442d9d3f5db980133',
  885. '0x5c129645e44cf1102a159f748c4a3fc5e673d81d7e86568d9ab0f5d396a7ce46ba1049b6579afb7866b1e715475224b',
  886. '0x15e6be4e990f03ce4ea50b3b42df2eb5cb181d8f84965a3957add4fa95af01b2b665027efec01c7704b456be69c8b604',
  887. ],
  888. // yDen
  889. [
  890. '0x16112c4c3a9c98b252181140fad0eae9601a6de578980be6eec3232b5be72e7a07f3688ef60c206d01479253b03663c1',
  891. '0x1962d75c2381201e1a0cbd6c43c348b885c84ff731c4d59ca4a10356f453e01f78a4260763529e3532f6102c2e49a03d',
  892. '0x58df3306640da276faaae7d6e8eb15778c4855551ae7f310c35a5dd279cd2eca6757cd636f96f891e2538b53dbf67f2',
  893. '0x16b7d288798e5395f20d23bf89edb4d1d115c5dbddbcd30e123da489e726af41727364f2c28297ada8d26d98445f5416',
  894. '0xbe0e079545f43e4b00cc912f8228ddcc6d19c9f0f69bbb0542eda0fc9dec916a20b15dc0fd2ededda39142311a5001d',
  895. '0x8d9e5297186db2d9fb266eaac783182b70152c65550d881c5ecd87b6f0f5a6449f38db9dfa9cce202c6477faaf9b7ac',
  896. '0x166007c08a99db2fc3ba8734ace9824b5eecfdfa8d0cf8ef5dd365bc400a0051d5fa9c01a58b1fb93d1a1399126a775c',
  897. '0x16a3ef08be3ea7ea03bcddfabba6ff6ee5a4375efa1f4fd7feb34fd206357132b920f5b00801dee460ee415a15812ed9',
  898. '0x1866c8ed336c61231a1be54fd1d74cc4f9fb0ce4c6af5920abc5750c4bf39b4852cfe2f7bb9248836b233d9d55535d4a',
  899. '0x167a55cda70a6e1cea820597d94a84903216f763e13d87bb5308592e7ea7d4fbc7385ea3d529b35e346ef48bb8913f55',
  900. '0x4d2f259eea405bd48f010a01ad2911d9c6dd039bb61a6290e591b36e636a5c871a5c29f4f83060400f8b49cba8f6aa8',
  901. '0xaccbb67481d033ff5852c1e48c50c477f94ff8aefce42d28c0f9a88cea7913516f968986f7ebbea9684b529e2561092',
  902. '0xad6b9514c767fe3c3613144b45f1496543346d98adf02267d5ceef9a00d9b8693000763e3b90ac11e99b138573345cc',
  903. '0x2660400eb2e4f3b628bdd0d53cd76f2bf565b94e72927c1cb748df27942480e420517bd8714cc80d1fadc1326ed06f7',
  904. '0xe0fa1d816ddc03e6b24255e0d7819c171c40f65e273b853324efcd6356caa205ca2f570f13497804415473a1d634b8f',
  905. '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001', // LAST 1
  906. ],
  907. ].map((i) => i.map((j) => BigInt(j))) as [Fp[], Fp[], Fp[], Fp[]]
  908. );
  909. // SWU Map - Fp2 to G2': y² = x³ + 240i * x + 1012 + 1012i
  910. const G2_SWU = mapToCurveSimpleSWU(Fp2, {
  911. A: Fp2.create({ c0: Fp.create(_0n), c1: Fp.create(BigInt(240)) }), // A' = 240 * I
  912. B: Fp2.create({ c0: Fp.create(BigInt(1012)), c1: Fp.create(BigInt(1012)) }), // B' = 1012 * (1 + I)
  913. Z: Fp2.create({ c0: Fp.create(BigInt(-2)), c1: Fp.create(BigInt(-1)) }), // Z: -(2 + I)
  914. });
  915. // Optimized SWU Map - Fp to G1
  916. const G1_SWU = mapToCurveSimpleSWU(Fp, {
  917. A: Fp.create(
  918. BigInt(
  919. '0x144698a3b8e9433d693a02c96d4982b0ea985383ee66a8d8e8981aefd881ac98936f8da0e0f97f5cf428082d584c1d'
  920. )
  921. ),
  922. B: Fp.create(
  923. BigInt(
  924. '0x12e2908d11688030018b12e8753eee3b2016c1f0f24f4070a0b9c14fcef35ef55a23215a316ceaa5d1cc48e98e172be0'
  925. )
  926. ),
  927. Z: Fp.create(BigInt(11)),
  928. });
  929. // Endomorphisms (for fast cofactor clearing)
  930. // Ψ(P) endomorphism
  931. const ut_root = Fp6.create({ c0: Fp2.ZERO, c1: Fp2.ONE, c2: Fp2.ZERO });
  932. const wsq = Fp12.create({ c0: ut_root, c1: Fp6.ZERO });
  933. const wcu = Fp12.create({ c0: Fp6.ZERO, c1: ut_root });
  934. const [wsq_inv, wcu_inv] = Fp12.invertBatch([wsq, wcu]);
  935. function psi(x: Fp2, y: Fp2): [Fp2, Fp2] {
  936. // Untwist Fp2->Fp12 && frobenius(1) && twist back
  937. const x2 = Fp12.mul(Fp12.frobeniusMap(Fp12.multiplyByFp2(wsq_inv, x), 1), wsq).c0.c0;
  938. const y2 = Fp12.mul(Fp12.frobeniusMap(Fp12.multiplyByFp2(wcu_inv, y), 1), wcu).c0.c0;
  939. return [x2, y2];
  940. }
  941. // Ψ endomorphism
  942. function G2psi(c: ProjConstructor<Fp2>, P: ProjPointType<Fp2>) {
  943. const affine = P.toAffine();
  944. const p = psi(affine.x, affine.y);
  945. return new c(p[0], p[1], Fp2.ONE);
  946. }
  947. // Ψ²(P) endomorphism
  948. // 1 / F2(2)^((p-1)/3) in GF(p²)
  949. const PSI2_C1 = BigInt(
  950. '0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac'
  951. );
  952. function psi2(x: Fp2, y: Fp2): [Fp2, Fp2] {
  953. return [Fp2.mul(x, PSI2_C1), Fp2.neg(y)];
  954. }
  955. function G2psi2(c: ProjConstructor<Fp2>, P: ProjPointType<Fp2>) {
  956. const affine = P.toAffine();
  957. const p = psi2(affine.x, affine.y);
  958. return new c(p[0], p[1], Fp2.ONE);
  959. }
  960. // Default hash_to_field options are for hash to G2.
  961. //
  962. // Parameter definitions are in section 5.3 of the spec unless otherwise noted.
  963. // Parameter values come from section 8.8.2 of the spec.
  964. // https://www.rfc-editor.org/rfc/rfc9380#section-8.8.2
  965. //
  966. // Base field F is GF(p^m)
  967. // p = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab
  968. // m = 2 (or 1 for G1 see section 8.8.1)
  969. // k = 128
  970. const htfDefaults = Object.freeze({
  971. // DST: a domain separation tag
  972. // defined in section 2.2.5
  973. // Use utils.getDSTLabel(), utils.setDSTLabel(value)
  974. DST: 'BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_',
  975. encodeDST: 'BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_',
  976. // p: the characteristic of F
  977. // where F is a finite field of characteristic p and order q = p^m
  978. p: Fp.ORDER,
  979. // m: the extension degree of F, m >= 1
  980. // where F is a finite field of characteristic p and order q = p^m
  981. m: 2,
  982. // k: the target security level for the suite in bits
  983. // defined in section 5.1
  984. k: 128,
  985. // option to use a message that has already been processed by
  986. // expand_message_xmd
  987. expand: 'xmd',
  988. // Hash functions for: expand_message_xmd is appropriate for use with a
  989. // wide range of hash functions, including SHA-2, SHA-3, BLAKE2, and others.
  990. // BBS+ uses blake2: https://github.com/hyperledger/aries-framework-go/issues/2247
  991. hash: sha256,
  992. } as const);
  993. // Encoding utils
  994. // Point on G1 curve: (x, y)
  995. // Compressed point of infinity
  996. const COMPRESSED_ZERO = setMask(Fp.toBytes(_0n), { infinity: true, compressed: true }); // set compressed & point-at-infinity bits
  997. function parseMask(bytes: Uint8Array) {
  998. // Copy, so we can remove mask data. It will be removed also later, when Fp.create will call modulo.
  999. bytes = bytes.slice();
  1000. const mask = bytes[0] & 0b1110_0000;
  1001. const compressed = !!((mask >> 7) & 1); // compression bit (0b1000_0000)
  1002. const infinity = !!((mask >> 6) & 1); // point at infinity bit (0b0100_0000)
  1003. const sort = !!((mask >> 5) & 1); // sort bit (0b0010_0000)
  1004. bytes[0] &= 0b0001_1111; // clear mask (zero first 3 bits)
  1005. return { compressed, infinity, sort, value: bytes };
  1006. }
  1007. function setMask(
  1008. bytes: Uint8Array,
  1009. mask: { compressed?: boolean; infinity?: boolean; sort?: boolean }
  1010. ) {
  1011. if (bytes[0] & 0b1110_0000) throw new Error('setMask: non-empty mask');
  1012. if (mask.compressed) bytes[0] |= 0b1000_0000;
  1013. if (mask.infinity) bytes[0] |= 0b0100_0000;
  1014. if (mask.sort) bytes[0] |= 0b0010_0000;
  1015. return bytes;
  1016. }
  1017. function signatureG1ToRawBytes(point: ProjPointType<Fp>) {
  1018. point.assertValidity();
  1019. const isZero = point.equals(bls12_381.G1.ProjectivePoint.ZERO);
  1020. const { x, y } = point.toAffine();
  1021. if (isZero) return COMPRESSED_ZERO.slice();
  1022. const P = Fp.ORDER;
  1023. const sort = Boolean((y * _2n) / P);
  1024. return setMask(numberToBytesBE(x, Fp.BYTES), { compressed: true, sort });
  1025. }
  1026. function signatureG2ToRawBytes(point: ProjPointType<Fp2>) {
  1027. // NOTE: by some reasons it was missed in bls12-381, looks like bug
  1028. point.assertValidity();
  1029. const len = Fp.BYTES;
  1030. if (point.equals(bls12_381.G2.ProjectivePoint.ZERO))
  1031. return concatB(COMPRESSED_ZERO, numberToBytesBE(_0n, len));
  1032. const { x, y } = point.toAffine();
  1033. const { re: x0, im: x1 } = Fp2.reim(x);
  1034. const { re: y0, im: y1 } = Fp2.reim(y);
  1035. const tmp = y1 > _0n ? y1 * _2n : y0 * _2n;
  1036. const sort = Boolean((tmp / Fp.ORDER) & _1n);
  1037. const z2 = x0;
  1038. return concatB(
  1039. setMask(numberToBytesBE(x1, len), { sort, compressed: true }),
  1040. numberToBytesBE(z2, len)
  1041. );
  1042. }
  1043. // To verify curve parameters, see pairing-friendly-curves spec:
  1044. // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-11
  1045. // Basic math is done over finite fields over p.
  1046. // More complicated math is done over polynominal extension fields.
  1047. // To simplify calculations in Fp12, we construct extension tower:
  1048. // Fp₁₂ = Fp₆² => Fp₂³
  1049. // Fp(u) / (u² - β) where β = -1
  1050. // Fp₂(v) / (v³ - ξ) where ξ = u + 1
  1051. // Fp₆(w) / (w² - γ) where γ = v
  1052. // Here goes constants && point encoding format
  1053. export const bls12_381: CurveFn<Fp, Fp2, Fp6, Fp12> = bls({
  1054. // Fields
  1055. fields: {
  1056. Fp,
  1057. Fp2,
  1058. Fp6,
  1059. Fp12,
  1060. Fr,
  1061. },
  1062. // G1 is the order-q subgroup of E1(Fp) : y² = x³ + 4, #E1(Fp) = h1q, where
  1063. // characteristic; z + (z⁴ - z² + 1)(z - 1)²/3
  1064. G1: {
  1065. Fp,
  1066. // cofactor; (z - 1)²/3
  1067. h: BigInt('0x396c8c005555e1568c00aaab0000aaab'),
  1068. // generator's coordinates
  1069. // x = 3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507
  1070. // y = 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569
  1071. Gx: BigInt(
  1072. '0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb'
  1073. ),
  1074. Gy: BigInt(
  1075. '0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1'
  1076. ),
  1077. a: Fp.ZERO,
  1078. b: _4n,
  1079. htfDefaults: { ...htfDefaults, m: 1, DST: 'BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_' },
  1080. wrapPrivateKey: true,
  1081. allowInfinityPoint: true,
  1082. // Checks is the point resides in prime-order subgroup.
  1083. // point.isTorsionFree() should return true for valid points
  1084. // It returns false for shitty points.
  1085. // https://eprint.iacr.org/2021/1130.pdf
  1086. isTorsionFree: (c, point): boolean => {
  1087. // φ endomorphism
  1088. const cubicRootOfUnityModP = BigInt(
  1089. '0x5f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe'
  1090. );
  1091. const phi = new c(Fp.mul(point.px, cubicRootOfUnityModP), point.py, point.pz);
  1092. // todo: unroll
  1093. const xP = point.multiplyUnsafe(bls12_381.params.x).negate(); // [x]P
  1094. const u2P = xP.multiplyUnsafe(bls12_381.params.x); // [u2]P
  1095. return u2P.equals(phi);
  1096. // https://eprint.iacr.org/2019/814.pdf
  1097. // (z² − 1)/3
  1098. // const c1 = BigInt('0x396c8c005555e1560000000055555555');
  1099. // const P = this;
  1100. // const S = P.sigma();
  1101. // const Q = S.double();
  1102. // const S2 = S.sigma();
  1103. // // [(z² − 1)/3](2σ(P) − P − σ²(P)) − σ²(P) = O
  1104. // const left = Q.subtract(P).subtract(S2).multiplyUnsafe(c1);
  1105. // const C = left.subtract(S2);
  1106. // return C.isZero();
  1107. },
  1108. // Clear cofactor of G1
  1109. // https://eprint.iacr.org/2019/403
  1110. clearCofactor: (_c, point) => {
  1111. // return this.multiplyUnsafe(CURVE.h);
  1112. return point.multiplyUnsafe(bls12_381.params.x).add(point); // x*P + P
  1113. },
  1114. mapToCurve: (scalars: bigint[]) => {
  1115. const { x, y } = G1_SWU(Fp.create(scalars[0]));
  1116. return isogenyMapG1(x, y);
  1117. },
  1118. fromBytes: (bytes: Uint8Array): AffinePoint<Fp> => {
  1119. const { compressed, infinity, sort, value } = parseMask(bytes);
  1120. if (value.length === 48 && compressed) {
  1121. // TODO: Fp.bytes
  1122. const P = Fp.ORDER;
  1123. const compressedValue = bytesToNumberBE(value);
  1124. // Zero
  1125. const x = Fp.create(compressedValue & Fp.MASK);
  1126. if (infinity) {
  1127. if (x !== _0n) throw new Error('G1: non-empty compressed point at infinity');
  1128. return { x: _0n, y: _0n };
  1129. }
  1130. const right = Fp.add(Fp.pow(x, _3n), Fp.create(bls12_381.params.G1b)); // y² = x³ + b
  1131. let y = Fp.sqrt(right);
  1132. if (!y) throw new Error('Invalid compressed G1 point');
  1133. if ((y * _2n) / P !== BigInt(sort)) y = Fp.neg(y);
  1134. return { x: Fp.create(x), y: Fp.create(y) };
  1135. } else if (value.length === 96 && !compressed) {
  1136. // Check if the infinity flag is set
  1137. const x = bytesToNumberBE(value.subarray(0, Fp.BYTES));
  1138. const y = bytesToNumberBE(value.subarray(Fp.BYTES));
  1139. if (infinity) {
  1140. if (x !== _0n || y !== _0n) throw new Error('G1: non-empty point at infinity');
  1141. return bls12_381.G1.ProjectivePoint.ZERO.toAffine();
  1142. }
  1143. return { x: Fp.create(x), y: Fp.create(y) };
  1144. } else {
  1145. throw new Error('Invalid point G1, expected 48/96 bytes');
  1146. }
  1147. },
  1148. toBytes: (c, point, isCompressed) => {
  1149. const isZero = point.equals(c.ZERO);
  1150. const { x, y } = point.toAffine();
  1151. if (isCompressed) {
  1152. if (isZero) return COMPRESSED_ZERO.slice();
  1153. const P = Fp.ORDER;
  1154. const sort = Boolean((y * _2n) / P);
  1155. return setMask(numberToBytesBE(x, Fp.BYTES), { compressed: true, sort });
  1156. } else {
  1157. if (isZero) {
  1158. // 2x PUBLIC_KEY_LENGTH
  1159. const x = concatB(new Uint8Array([0x40]), new Uint8Array(2 * Fp.BYTES - 1));
  1160. return x;
  1161. } else {
  1162. return concatB(numberToBytesBE(x, Fp.BYTES), numberToBytesBE(y, Fp.BYTES));
  1163. }
  1164. }
  1165. },
  1166. ShortSignature: {
  1167. fromHex(hex: Hex): ProjPointType<Fp> {
  1168. const { infinity, sort, value } = parseMask(ensureBytes('signatureHex', hex, 48));
  1169. const P = Fp.ORDER;
  1170. const compressedValue = bytesToNumberBE(value);
  1171. // Zero
  1172. if (infinity) return bls12_381.G1.ProjectivePoint.ZERO;
  1173. const x = Fp.create(compressedValue & Fp.MASK);
  1174. const right = Fp.add(Fp.pow(x, _3n), Fp.create(bls12_381.params.G1b)); // y² = x³ + b
  1175. let y = Fp.sqrt(right);
  1176. if (!y) throw new Error('Invalid compressed G1 point');
  1177. const aflag = BigInt(sort);
  1178. if ((y * _2n) / P !== aflag) y = Fp.neg(y);
  1179. const point = bls12_381.G1.ProjectivePoint.fromAffine({ x, y });
  1180. point.assertValidity();
  1181. return point;
  1182. },
  1183. toRawBytes(point: ProjPointType<Fp>) {
  1184. return signatureG1ToRawBytes(point);
  1185. },
  1186. toHex(point: ProjPointType<Fp>) {
  1187. return bytesToHex(signatureG1ToRawBytes(point));
  1188. },
  1189. },
  1190. },
  1191. // G2 is the order-q subgroup of E2(Fp²) : y² = x³+4(1+√−1),
  1192. // where Fp2 is Fp[√−1]/(x2+1). #E2(Fp2 ) = h2q, where
  1193. // G² - 1
  1194. // h2q
  1195. G2: {
  1196. Fp: Fp2,
  1197. // cofactor
  1198. h: BigInt(
  1199. '0x5d543a95414e7f1091d50792876a202cd91de4547085abaa68a205b2e5a7ddfa628f1cb4d9e82ef21537e293a6691ae1616ec6e786f0c70cf1c38e31c7238e5'
  1200. ),
  1201. Gx: Fp2.fromBigTuple([
  1202. BigInt(
  1203. '0x024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8'
  1204. ),
  1205. BigInt(
  1206. '0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e'
  1207. ),
  1208. ]),
  1209. // y =
  1210. // 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582,
  1211. // 1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905
  1212. Gy: Fp2.fromBigTuple([
  1213. BigInt(
  1214. '0x0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801'
  1215. ),
  1216. BigInt(
  1217. '0x0606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be'
  1218. ),
  1219. ]),
  1220. a: Fp2.ZERO,
  1221. b: Fp2.fromBigTuple([_4n, _4n]),
  1222. hEff: BigInt(
  1223. '0xbc69f08f2ee75b3584c6a0ea91b352888e2a8e9145ad7689986ff031508ffe1329c2f178731db956d82bf015d1212b02ec0ec69d7477c1ae954cbc06689f6a359894c0adebbf6b4e8020005aaa95551'
  1224. ),
  1225. htfDefaults: { ...htfDefaults },
  1226. wrapPrivateKey: true,
  1227. allowInfinityPoint: true,
  1228. mapToCurve: (scalars: bigint[]) => {
  1229. const { x, y } = G2_SWU(Fp2.fromBigTuple(scalars));
  1230. return isogenyMapG2(x, y);
  1231. },
  1232. // Checks is the point resides in prime-order subgroup.
  1233. // point.isTorsionFree() should return true for valid points
  1234. // It returns false for shitty points.
  1235. // https://eprint.iacr.org/2021/1130.pdf
  1236. isTorsionFree: (c, P): boolean => {
  1237. return P.multiplyUnsafe(bls12_381.params.x).negate().equals(G2psi(c, P)); // ψ(P) == [u](P)
  1238. // Older version: https://eprint.iacr.org/2019/814.pdf
  1239. // Ψ²(P) => Ψ³(P) => [z]Ψ³(P) where z = -x => [z]Ψ³(P) - Ψ²(P) + P == O
  1240. // return P.psi2().psi().mulNegX().subtract(psi2).add(P).isZero();
  1241. },
  1242. // Maps the point into the prime-order subgroup G2.
  1243. // clear_cofactor_bls12381_g2 from cfrg-hash-to-curve-11
  1244. // https://eprint.iacr.org/2017/419.pdf
  1245. // prettier-ignore
  1246. clearCofactor: (c, P) => {
  1247. const x = bls12_381.params.x;
  1248. let t1 = P.multiplyUnsafe(x).negate(); // [-x]P
  1249. let t2 = G2psi(c, P); // Ψ(P)
  1250. let t3 = P.double(); // 2P
  1251. t3 = G2psi2(c, t3); // Ψ²(2P)
  1252. t3 = t3.subtract(t2); // Ψ²(2P) - Ψ(P)
  1253. t2 = t1.add(t2); // [-x]P + Ψ(P)
  1254. t2 = t2.multiplyUnsafe(x).negate(); // [x²]P - [x]Ψ(P)
  1255. t3 = t3.add(t2); // Ψ²(2P) - Ψ(P) + [x²]P - [x]Ψ(P)
  1256. t3 = t3.subtract(t1); // Ψ²(2P) - Ψ(P) + [x²]P - [x]Ψ(P) + [x]P
  1257. const Q = t3.subtract(P); // Ψ²(2P) - Ψ(P) + [x²]P - [x]Ψ(P) + [x]P - 1P
  1258. return Q; // [x²-x-1]P + [x-1]Ψ(P) + Ψ²(2P)
  1259. },
  1260. fromBytes: (bytes: Uint8Array): AffinePoint<Fp2> => {
  1261. const { compressed, infinity, sort, value } = parseMask(bytes);
  1262. if (
  1263. (!compressed && !infinity && sort) || // 00100000
  1264. (!compressed && infinity && sort) || // 01100000
  1265. (sort && infinity && compressed) // 11100000
  1266. ) {
  1267. throw new Error('Invalid encoding flag: ' + (bytes[0] & 0b1110_0000));
  1268. }
  1269. const L = Fp.BYTES;
  1270. const slc = (b: Uint8Array, from: number, to?: number) => bytesToNumberBE(b.slice(from, to));
  1271. if (value.length === 96 && compressed) {
  1272. const b = bls12_381.params.G2b;
  1273. const P = Fp.ORDER;
  1274. if (infinity) {
  1275. // check that all bytes are 0
  1276. if (value.reduce((p, c) => (p !== 0 ? c + 1 : c), 0) > 0) {
  1277. throw new Error('Invalid compressed G2 point');
  1278. }
  1279. return { x: Fp2.ZERO, y: Fp2.ZERO };
  1280. }
  1281. const x_1 = slc(value, 0, L);
  1282. const x_0 = slc(value, L, 2 * L);
  1283. const x = Fp2.create({ c0: Fp.create(x_0), c1: Fp.create(x_1) });
  1284. const right = Fp2.add(Fp2.pow(x, _3n), b); // y² = x³ + 4 * (u+1) = x³ + b
  1285. let y = Fp2.sqrt(right);
  1286. const Y_bit = y.c1 === _0n ? (y.c0 * _2n) / P : (y.c1 * _2n) / P ? _1n : _0n;
  1287. y = sort && Y_bit > 0 ? y : Fp2.neg(y);
  1288. return { x, y };
  1289. } else if (value.length === 192 && !compressed) {
  1290. if (infinity) {
  1291. if (value.reduce((p, c) => (p !== 0 ? c + 1 : c), 0) > 0) {
  1292. throw new Error('Invalid uncompressed G2 point');
  1293. }
  1294. return { x: Fp2.ZERO, y: Fp2.ZERO };
  1295. }
  1296. const x1 = slc(value, 0, L);
  1297. const x0 = slc(value, L, 2 * L);
  1298. const y1 = slc(value, 2 * L, 3 * L);
  1299. const y0 = slc(value, 3 * L, 4 * L);
  1300. return { x: Fp2.fromBigTuple([x0, x1]), y: Fp2.fromBigTuple([y0, y1]) };
  1301. } else {
  1302. throw new Error('Invalid point G2, expected 96/192 bytes');
  1303. }
  1304. },
  1305. toBytes: (c, point, isCompressed) => {
  1306. const { BYTES: len, ORDER: P } = Fp;
  1307. const isZero = point.equals(c.ZERO);
  1308. const { x, y } = point.toAffine();
  1309. if (isCompressed) {
  1310. if (isZero) return concatB(COMPRESSED_ZERO, numberToBytesBE(_0n, len));
  1311. const flag = Boolean(y.c1 === _0n ? (y.c0 * _2n) / P : (y.c1 * _2n) / P);
  1312. return concatB(
  1313. setMask(numberToBytesBE(x.c1, len), { compressed: true, sort: flag }),
  1314. numberToBytesBE(x.c0, len)
  1315. );
  1316. } else {
  1317. if (isZero) return concatB(new Uint8Array([0x40]), new Uint8Array(4 * len - 1)); // bytes[0] |= 1 << 6;
  1318. const { re: x0, im: x1 } = Fp2.reim(x);
  1319. const { re: y0, im: y1 } = Fp2.reim(y);
  1320. return concatB(
  1321. numberToBytesBE(x1, len),
  1322. numberToBytesBE(x0, len),
  1323. numberToBytesBE(y1, len),
  1324. numberToBytesBE(y0, len)
  1325. );
  1326. }
  1327. },
  1328. Signature: {
  1329. // TODO: Optimize, it's very slow because of sqrt.
  1330. fromHex(hex: Hex): ProjPointType<Fp2> {
  1331. const { infinity, sort, value } = parseMask(ensureBytes('signatureHex', hex));
  1332. const P = Fp.ORDER;
  1333. const half = value.length / 2;
  1334. if (half !== 48 && half !== 96)
  1335. throw new Error('Invalid compressed signature length, must be 96 or 192');
  1336. const z1 = bytesToNumberBE(value.slice(0, half));
  1337. const z2 = bytesToNumberBE(value.slice(half));
  1338. // Indicates the infinity point
  1339. if (infinity) return bls12_381.G2.ProjectivePoint.ZERO;
  1340. const x1 = Fp.create(z1 & Fp.MASK);
  1341. const x2 = Fp.create(z2);
  1342. const x = Fp2.create({ c0: x2, c1: x1 });
  1343. const y2 = Fp2.add(Fp2.pow(x, _3n), bls12_381.params.G2b); // y² = x³ + 4
  1344. // The slow part
  1345. let y = Fp2.sqrt(y2);
  1346. if (!y) throw new Error('Failed to find a square root');
  1347. // Choose the y whose leftmost bit of the imaginary part is equal to the a_flag1
  1348. // If y1 happens to be zero, then use the bit of y0
  1349. const { re: y0, im: y1 } = Fp2.reim(y);
  1350. const aflag1 = BigInt(sort);
  1351. const isGreater = y1 > _0n && (y1 * _2n) / P !== aflag1;
  1352. const isZero = y1 === _0n && (y0 * _2n) / P !== aflag1;
  1353. if (isGreater || isZero) y = Fp2.neg(y);
  1354. const point = bls12_381.G2.ProjectivePoint.fromAffine({ x, y });
  1355. point.assertValidity();
  1356. return point;
  1357. },
  1358. toRawBytes(point: ProjPointType<Fp2>) {
  1359. return signatureG2ToRawBytes(point);
  1360. },
  1361. toHex(point: ProjPointType<Fp2>) {
  1362. return bytesToHex(signatureG2ToRawBytes(point));
  1363. },
  1364. },
  1365. },
  1366. params: {
  1367. x: BLS_X, // The BLS parameter x for BLS12-381
  1368. r: Fr.ORDER, // order; z⁴ − z² + 1; CURVE.n from other curves
  1369. },
  1370. htfDefaults,
  1371. hash: sha256,
  1372. randomBytes,
  1373. });