@noble/curves 0.6.4 → 0.7.0

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