@noble/curves 1.9.5 → 2.0.0-beta.1

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 (211) hide show
  1. package/README.md +267 -421
  2. package/abstract/bls.d.ts +49 -111
  3. package/abstract/bls.d.ts.map +1 -1
  4. package/abstract/bls.js +108 -152
  5. package/abstract/bls.js.map +1 -1
  6. package/abstract/curve.d.ts +7 -48
  7. package/abstract/curve.d.ts.map +1 -1
  8. package/abstract/curve.js +22 -47
  9. package/abstract/curve.js.map +1 -1
  10. package/abstract/edwards.d.ts +17 -68
  11. package/abstract/edwards.d.ts.map +1 -1
  12. package/abstract/edwards.js +98 -175
  13. package/abstract/edwards.js.map +1 -1
  14. package/abstract/fft.js +14 -27
  15. package/abstract/fft.js.map +1 -1
  16. package/abstract/hash-to-curve.d.ts +11 -24
  17. package/abstract/hash-to-curve.d.ts.map +1 -1
  18. package/abstract/hash-to-curve.js +30 -35
  19. package/abstract/hash-to-curve.js.map +1 -1
  20. package/abstract/modular.d.ts +5 -17
  21. package/abstract/modular.d.ts.map +1 -1
  22. package/abstract/modular.js +166 -167
  23. package/abstract/modular.js.map +1 -1
  24. package/abstract/montgomery.d.ts +4 -9
  25. package/abstract/montgomery.d.ts.map +1 -1
  26. package/abstract/montgomery.js +17 -20
  27. package/abstract/montgomery.js.map +1 -1
  28. package/abstract/oprf.d.ts +282 -0
  29. package/abstract/oprf.d.ts.map +1 -0
  30. package/abstract/oprf.js +297 -0
  31. package/abstract/oprf.js.map +1 -0
  32. package/abstract/poseidon.js +20 -24
  33. package/abstract/poseidon.js.map +1 -1
  34. package/abstract/tower.d.ts +9 -7
  35. package/abstract/tower.d.ts.map +1 -1
  36. package/abstract/tower.js +600 -364
  37. package/abstract/tower.js.map +1 -1
  38. package/abstract/weierstrass.d.ts +12 -145
  39. package/abstract/weierstrass.d.ts.map +1 -1
  40. package/abstract/weierstrass.js +153 -377
  41. package/abstract/weierstrass.js.map +1 -1
  42. package/bls12-381.d.ts +2 -2
  43. package/bls12-381.d.ts.map +1 -1
  44. package/bls12-381.js +174 -216
  45. package/bls12-381.js.map +1 -1
  46. package/bn254.d.ts +58 -10
  47. package/bn254.d.ts.map +1 -1
  48. package/bn254.js +70 -130
  49. package/bn254.js.map +1 -1
  50. package/ed25519.d.ts +12 -31
  51. package/ed25519.d.ts.map +1 -1
  52. package/ed25519.js +104 -146
  53. package/ed25519.js.map +1 -1
  54. package/ed448.d.ts +14 -33
  55. package/ed448.d.ts.map +1 -1
  56. package/ed448.js +105 -132
  57. package/ed448.js.map +1 -1
  58. package/index.js +1 -1
  59. package/misc.d.ts +10 -14
  60. package/misc.d.ts.map +1 -1
  61. package/misc.js +51 -60
  62. package/misc.js.map +1 -1
  63. package/nist.d.ts +11 -14
  64. package/nist.d.ts.map +1 -1
  65. package/nist.js +46 -55
  66. package/nist.js.map +1 -1
  67. package/package.json +9 -224
  68. package/secp256k1.d.ts +7 -23
  69. package/secp256k1.d.ts.map +1 -1
  70. package/secp256k1.js +72 -83
  71. package/secp256k1.js.map +1 -1
  72. package/src/abstract/bls.ts +197 -344
  73. package/src/abstract/curve.ts +10 -83
  74. package/src/abstract/edwards.ts +96 -223
  75. package/src/abstract/hash-to-curve.ts +32 -45
  76. package/src/abstract/modular.ts +144 -130
  77. package/src/abstract/montgomery.ts +21 -22
  78. package/src/abstract/oprf.ts +600 -0
  79. package/src/abstract/tower.ts +627 -382
  80. package/src/abstract/weierstrass.ts +101 -482
  81. package/src/bls12-381.ts +148 -176
  82. package/src/bn254.ts +67 -122
  83. package/src/ed25519.ts +65 -118
  84. package/src/ed448.ts +63 -113
  85. package/src/index.ts +1 -1
  86. package/src/misc.ts +66 -49
  87. package/src/nist.ts +48 -57
  88. package/src/secp256k1.ts +56 -88
  89. package/src/utils.ts +41 -61
  90. package/src/webcrypto.ts +362 -0
  91. package/utils.d.ts +28 -19
  92. package/utils.d.ts.map +1 -1
  93. package/utils.js +45 -121
  94. package/utils.js.map +1 -1
  95. package/webcrypto.d.ts +47 -0
  96. package/webcrypto.d.ts.map +1 -0
  97. package/webcrypto.js +231 -0
  98. package/webcrypto.js.map +1 -0
  99. package/esm/_shortw_utils.d.ts +0 -19
  100. package/esm/_shortw_utils.d.ts.map +0 -1
  101. package/esm/_shortw_utils.js +0 -16
  102. package/esm/_shortw_utils.js.map +0 -1
  103. package/esm/abstract/bls.d.ts +0 -190
  104. package/esm/abstract/bls.d.ts.map +0 -1
  105. package/esm/abstract/bls.js +0 -408
  106. package/esm/abstract/bls.js.map +0 -1
  107. package/esm/abstract/curve.d.ts +0 -231
  108. package/esm/abstract/curve.d.ts.map +0 -1
  109. package/esm/abstract/curve.js +0 -465
  110. package/esm/abstract/curve.js.map +0 -1
  111. package/esm/abstract/edwards.d.ts +0 -237
  112. package/esm/abstract/edwards.d.ts.map +0 -1
  113. package/esm/abstract/edwards.js +0 -632
  114. package/esm/abstract/edwards.js.map +0 -1
  115. package/esm/abstract/fft.d.ts +0 -122
  116. package/esm/abstract/fft.d.ts.map +0 -1
  117. package/esm/abstract/fft.js +0 -425
  118. package/esm/abstract/fft.js.map +0 -1
  119. package/esm/abstract/hash-to-curve.d.ts +0 -102
  120. package/esm/abstract/hash-to-curve.d.ts.map +0 -1
  121. package/esm/abstract/hash-to-curve.js +0 -203
  122. package/esm/abstract/hash-to-curve.js.map +0 -1
  123. package/esm/abstract/modular.d.ts +0 -171
  124. package/esm/abstract/modular.d.ts.map +0 -1
  125. package/esm/abstract/modular.js +0 -530
  126. package/esm/abstract/modular.js.map +0 -1
  127. package/esm/abstract/montgomery.d.ts +0 -30
  128. package/esm/abstract/montgomery.d.ts.map +0 -1
  129. package/esm/abstract/montgomery.js +0 -157
  130. package/esm/abstract/montgomery.js.map +0 -1
  131. package/esm/abstract/poseidon.d.ts +0 -68
  132. package/esm/abstract/poseidon.d.ts.map +0 -1
  133. package/esm/abstract/poseidon.js +0 -296
  134. package/esm/abstract/poseidon.js.map +0 -1
  135. package/esm/abstract/tower.d.ts +0 -93
  136. package/esm/abstract/tower.d.ts.map +0 -1
  137. package/esm/abstract/tower.js +0 -502
  138. package/esm/abstract/tower.js.map +0 -1
  139. package/esm/abstract/utils.d.ts +0 -5
  140. package/esm/abstract/utils.d.ts.map +0 -1
  141. package/esm/abstract/utils.js +0 -7
  142. package/esm/abstract/utils.js.map +0 -1
  143. package/esm/abstract/weierstrass.d.ts +0 -412
  144. package/esm/abstract/weierstrass.d.ts.map +0 -1
  145. package/esm/abstract/weierstrass.js +0 -1428
  146. package/esm/abstract/weierstrass.js.map +0 -1
  147. package/esm/bls12-381.d.ts +0 -16
  148. package/esm/bls12-381.d.ts.map +0 -1
  149. package/esm/bls12-381.js +0 -738
  150. package/esm/bls12-381.js.map +0 -1
  151. package/esm/bn254.d.ts +0 -18
  152. package/esm/bn254.d.ts.map +0 -1
  153. package/esm/bn254.js +0 -246
  154. package/esm/bn254.js.map +0 -1
  155. package/esm/ed25519.d.ts +0 -106
  156. package/esm/ed25519.d.ts.map +0 -1
  157. package/esm/ed25519.js +0 -467
  158. package/esm/ed25519.js.map +0 -1
  159. package/esm/ed448.d.ts +0 -101
  160. package/esm/ed448.d.ts.map +0 -1
  161. package/esm/ed448.js +0 -448
  162. package/esm/ed448.js.map +0 -1
  163. package/esm/index.d.ts +0 -2
  164. package/esm/index.d.ts.map +0 -1
  165. package/esm/index.js +0 -17
  166. package/esm/index.js.map +0 -1
  167. package/esm/jubjub.d.ts +0 -12
  168. package/esm/jubjub.d.ts.map +0 -1
  169. package/esm/jubjub.js +0 -12
  170. package/esm/jubjub.js.map +0 -1
  171. package/esm/misc.d.ts +0 -19
  172. package/esm/misc.d.ts.map +0 -1
  173. package/esm/misc.js +0 -109
  174. package/esm/misc.js.map +0 -1
  175. package/esm/nist.d.ts +0 -21
  176. package/esm/nist.d.ts.map +0 -1
  177. package/esm/nist.js +0 -132
  178. package/esm/nist.js.map +0 -1
  179. package/esm/p256.d.ts +0 -16
  180. package/esm/p256.d.ts.map +0 -1
  181. package/esm/p256.js +0 -16
  182. package/esm/p256.js.map +0 -1
  183. package/esm/p384.d.ts +0 -16
  184. package/esm/p384.d.ts.map +0 -1
  185. package/esm/p384.js +0 -16
  186. package/esm/p384.js.map +0 -1
  187. package/esm/p521.d.ts +0 -16
  188. package/esm/p521.d.ts.map +0 -1
  189. package/esm/p521.js +0 -16
  190. package/esm/p521.js.map +0 -1
  191. package/esm/package.json +0 -4
  192. package/esm/pasta.d.ts +0 -10
  193. package/esm/pasta.d.ts.map +0 -1
  194. package/esm/pasta.js +0 -10
  195. package/esm/pasta.js.map +0 -1
  196. package/esm/secp256k1.d.ts +0 -89
  197. package/esm/secp256k1.d.ts.map +0 -1
  198. package/esm/secp256k1.js +0 -292
  199. package/esm/secp256k1.js.map +0 -1
  200. package/esm/utils.d.ts +0 -110
  201. package/esm/utils.d.ts.map +0 -1
  202. package/esm/utils.js +0 -322
  203. package/esm/utils.js.map +0 -1
  204. package/src/_shortw_utils.ts +0 -21
  205. package/src/abstract/utils.ts +0 -7
  206. package/src/jubjub.ts +0 -12
  207. package/src/p256.ts +0 -15
  208. package/src/p384.ts +0 -15
  209. package/src/p521.ts +0 -15
  210. package/src/package.json +0 -3
  211. package/src/pasta.ts +0 -9
@@ -10,7 +10,7 @@
10
10
  * @module
11
11
  */
12
12
  /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
13
- import { bitLen, bitMask, concatBytes, notImplemented } from '../utils.ts';
13
+ import { bitGet, bitLen, concatBytes, notImplemented } from '../utils.ts';
14
14
  import * as mod from './modular.ts';
15
15
  import type { WeierstrassPoint, WeierstrassPointCons } from './weierstrass.ts';
16
16
 
@@ -34,15 +34,18 @@ export type BigintTwelve = [
34
34
  ];
35
35
 
36
36
  export type Fp2Bls = mod.IField<Fp2> & {
37
+ Fp: mod.IField<Fp>;
37
38
  frobeniusMap(num: Fp2, power: number): Fp2;
38
- fromBigTuple(num: [bigint, bigint]): Fp2;
39
+ fromBigTuple(num: BigintTuple): Fp2;
39
40
  mulByB: (num: Fp2) => Fp2;
40
41
  mulByNonresidue: (num: Fp2) => Fp2;
41
42
  reim: (num: Fp2) => { re: Fp; im: Fp };
43
+ Fp4Square: (a: Fp2, b: Fp2) => { first: Fp2; second: Fp2 };
42
44
  NONRESIDUE: Fp2;
43
45
  };
44
46
 
45
47
  export type Fp6Bls = mod.IField<Fp6> & {
48
+ Fp2: Fp2Bls;
46
49
  frobeniusMap(num: Fp6, power: number): Fp6;
47
50
  fromBigSix: (tuple: BigintSix) => Fp6;
48
51
  mul1(num: Fp6, b1: Fp2): Fp6;
@@ -52,6 +55,7 @@ export type Fp6Bls = mod.IField<Fp6> & {
52
55
  };
53
56
 
54
57
  export type Fp12Bls = mod.IField<Fp12> & {
58
+ Fp6: Fp6Bls;
55
59
  frobeniusMap(num: Fp12, power: number): Fp12;
56
60
  fromBigTwelve: (t: BigintTwelve) => Fp12;
57
61
  mul014(num: Fp12, o0: Fp2, o1: Fp2, o4: Fp2): Fp12;
@@ -135,41 +139,109 @@ export function psiFrobenius(
135
139
 
136
140
  export type Tower12Opts = {
137
141
  ORDER: bigint;
142
+ X_LEN: number;
138
143
  NONRESIDUE?: Fp;
139
- // Fp2
140
144
  FP2_NONRESIDUE: BigintTuple;
141
145
  Fp2sqrt?: (num: Fp2) => Fp2;
142
146
  Fp2mulByB: (num: Fp2) => Fp2;
143
- // Fp12
144
- Fp12cyclotomicSquare: (num: Fp12) => Fp12;
145
- Fp12cyclotomicExp: (num: Fp12, n: bigint) => Fp12;
146
147
  Fp12finalExponentiate: (num: Fp12) => Fp12;
147
148
  };
148
149
 
149
- export function tower12(opts: Tower12Opts): {
150
- Fp: Readonly<mod.IField<bigint> & Required<Pick<mod.IField<bigint>, 'isOdd'>>>;
151
- Fp2: Fp2Bls;
152
- Fp6: Fp6Bls;
153
- Fp12: Fp12Bls;
154
- Fp4Square: (a: Fp2, b: Fp2) => { first: Fp2; second: Fp2 };
155
- } {
156
- const { ORDER } = opts;
157
- // Fp
158
- const Fp = mod.Field(ORDER);
159
- const FpNONRESIDUE = Fp.create(opts.NONRESIDUE || BigInt(-1));
160
- const Fpdiv2 = Fp.div(Fp.ONE, _2n); // 1/2
150
+ const Fp2fromBigTuple = (Fp: mod.IField<bigint>, tuple: BigintTuple | bigint[]) => {
151
+ if (tuple.length !== 2) throw new Error('invalid tuple');
152
+ const fps = tuple.map((n) => Fp.create(n)) as BigintTuple;
153
+ return { c0: fps[0], c1: fps[1] };
154
+ };
155
+
156
+ class _Field2 implements mod.IField<Fp2> {
157
+ readonly ORDER: bigint;
158
+ readonly BITS: number;
159
+ readonly BYTES: number;
160
+ readonly isLE: boolean;
161
+
162
+ readonly ZERO: Fp2;
163
+ readonly ONE: Fp2;
164
+ readonly Fp: mod.IField<bigint>;
161
165
 
162
- // Fp2
163
- const FP2_FROBENIUS_COEFFICIENTS = calcFrobeniusCoefficients(Fp, FpNONRESIDUE, Fp.ORDER, 2)[0];
164
- const Fp2Add = ({ c0, c1 }: Fp2, { c0: r0, c1: r1 }: Fp2) => ({
165
- c0: Fp.add(c0, r0),
166
- c1: Fp.add(c1, r1),
167
- });
168
- const Fp2Subtract = ({ c0, c1 }: Fp2, { c0: r0, c1: r1 }: Fp2) => ({
169
- c0: Fp.sub(c0, r0),
170
- c1: Fp.sub(c1, r1),
171
- });
172
- const Fp2Multiply = ({ c0, c1 }: Fp2, rhs: Fp2) => {
166
+ readonly NONRESIDUE: Fp2;
167
+ readonly mulByB: Tower12Opts['Fp2mulByB'];
168
+ readonly Fp_NONRESIDUE: bigint;
169
+ readonly Fp_div2: bigint;
170
+ readonly FROBENIUS_COEFFICIENTS: Fp[];
171
+
172
+ constructor(
173
+ Fp: mod.IField<bigint>,
174
+ opts: Partial<{
175
+ NONRESIDUE: bigint;
176
+ FP2_NONRESIDUE: BigintTuple;
177
+ Fp2mulByB: Tower12Opts['Fp2mulByB'];
178
+ }> = {}
179
+ ) {
180
+ const ORDER = Fp.ORDER;
181
+ const FP2_ORDER = ORDER * ORDER;
182
+ this.Fp = Fp;
183
+ this.ORDER = FP2_ORDER;
184
+ this.BITS = bitLen(FP2_ORDER);
185
+ this.BYTES = Math.ceil(bitLen(FP2_ORDER) / 8);
186
+ this.isLE = Fp.isLE;
187
+ this.ZERO = { c0: Fp.ZERO, c1: Fp.ZERO };
188
+ this.ONE = { c0: Fp.ONE, c1: Fp.ZERO };
189
+
190
+ this.Fp_NONRESIDUE = Fp.create(opts.NONRESIDUE || BigInt(-1));
191
+ this.Fp_div2 = Fp.div(Fp.ONE, _2n); // 1/2
192
+ this.NONRESIDUE = Fp2fromBigTuple(Fp, opts.FP2_NONRESIDUE!);
193
+ // const Fp2Nonresidue = Fp2fromBigTuple(opts.FP2_NONRESIDUE);
194
+ this.FROBENIUS_COEFFICIENTS = calcFrobeniusCoefficients(Fp, this.Fp_NONRESIDUE, Fp.ORDER, 2)[0];
195
+ this.mulByB = opts.Fp2mulByB!;
196
+ Object.seal(this);
197
+ }
198
+ fromBigTuple(tuple: BigintTuple) {
199
+ return Fp2fromBigTuple(this.Fp, tuple);
200
+ }
201
+ create(num: Fp2) {
202
+ return num;
203
+ }
204
+ isValid({ c0, c1 }: Fp2) {
205
+ function isValidC(num: bigint, ORDER: bigint) {
206
+ return typeof num === 'bigint' && _0n <= num && num < ORDER;
207
+ }
208
+ return isValidC(c0, this.ORDER) && isValidC(c1, this.ORDER);
209
+ }
210
+ is0({ c0, c1 }: Fp2) {
211
+ return this.Fp.is0(c0) && this.Fp.is0(c1);
212
+ }
213
+ isValidNot0(num: Fp2) {
214
+ return !this.is0(num) && this.isValid(num);
215
+ }
216
+ eql({ c0, c1 }: Fp2, { c0: r0, c1: r1 }: Fp2) {
217
+ return this.Fp.eql(c0, r0) && this.Fp.eql(c1, r1);
218
+ }
219
+ neg({ c0, c1 }: Fp2) {
220
+ return { c0: this.Fp.neg(c0), c1: this.Fp.neg(c1) };
221
+ }
222
+ pow(num: Fp2, power: bigint): Fp2 {
223
+ return mod.FpPow(this, num, power);
224
+ }
225
+ invertBatch(nums: Fp2[]): Fp2[] {
226
+ return mod.FpInvertBatch(this, nums);
227
+ }
228
+ // Normalized
229
+ add(f1: Fp2, f2: Fp2): Fp2 {
230
+ const { c0, c1 } = f1;
231
+ const { c0: r0, c1: r1 } = f2;
232
+ return {
233
+ c0: this.Fp.add(c0, r0),
234
+ c1: this.Fp.add(c1, r1),
235
+ };
236
+ }
237
+ sub({ c0, c1 }: Fp2, { c0: r0, c1: r1 }: Fp2) {
238
+ return {
239
+ c0: this.Fp.sub(c0, r0),
240
+ c1: this.Fp.sub(c1, r1),
241
+ };
242
+ }
243
+ mul({ c0, c1 }: Fp2, rhs: Fp2) {
244
+ const { Fp } = this;
173
245
  if (typeof rhs === 'bigint') return { c0: Fp.mul(c0, rhs), c1: Fp.mul(c1, rhs) };
174
246
  // (a+bi)(c+di) = (ac−bd) + (ad+bc)i
175
247
  const { c0: r0, c1: r1 } = rhs;
@@ -179,137 +251,168 @@ export function tower12(opts: Tower12Opts): {
179
251
  const o0 = Fp.sub(t1, t2);
180
252
  const o1 = Fp.sub(Fp.mul(Fp.add(c0, c1), Fp.add(r0, r1)), Fp.add(t1, t2));
181
253
  return { c0: o0, c1: o1 };
182
- };
183
- const Fp2Square = ({ c0, c1 }: Fp2) => {
254
+ }
255
+ sqr({ c0, c1 }: Fp2) {
256
+ const { Fp } = this;
184
257
  const a = Fp.add(c0, c1);
185
258
  const b = Fp.sub(c0, c1);
186
259
  const c = Fp.add(c0, c0);
187
260
  return { c0: Fp.mul(a, b), c1: Fp.mul(c, c1) };
188
- };
189
- const Fp2fromBigTuple = (tuple: BigintTuple | bigint[]) => {
190
- if (tuple.length !== 2) throw new Error('invalid tuple');
191
- const fps = tuple.map((n) => Fp.create(n)) as [Fp, Fp];
192
- return { c0: fps[0], c1: fps[1] };
193
- };
194
-
195
- function isValidC(num: bigint, ORDER: bigint) {
196
- return typeof num === 'bigint' && _0n <= num && num < ORDER;
197
261
  }
198
-
199
- const FP2_ORDER = ORDER * ORDER;
200
- const Fp2Nonresidue = Fp2fromBigTuple(opts.FP2_NONRESIDUE);
201
- const Fp2: Fp2Bls = {
202
- ORDER: FP2_ORDER,
203
- isLE: Fp.isLE,
204
- NONRESIDUE: Fp2Nonresidue,
205
- BITS: bitLen(FP2_ORDER),
206
- BYTES: Math.ceil(bitLen(FP2_ORDER) / 8),
207
- MASK: bitMask(bitLen(FP2_ORDER)),
208
- ZERO: { c0: Fp.ZERO, c1: Fp.ZERO },
209
- ONE: { c0: Fp.ONE, c1: Fp.ZERO },
210
- create: (num) => num,
211
- isValid: ({ c0, c1 }) => isValidC(c0, FP2_ORDER) && isValidC(c1, FP2_ORDER),
212
- is0: ({ c0, c1 }) => Fp.is0(c0) && Fp.is0(c1),
213
- isValidNot0: (num) => !Fp2.is0(num) && Fp2.isValid(num),
214
- eql: ({ c0, c1 }: Fp2, { c0: r0, c1: r1 }: Fp2) => Fp.eql(c0, r0) && Fp.eql(c1, r1),
215
- neg: ({ c0, c1 }) => ({ c0: Fp.neg(c0), c1: Fp.neg(c1) }),
216
- pow: (num, power) => mod.FpPow(Fp2, num, power),
217
- invertBatch: (nums) => mod.FpInvertBatch(Fp2, nums),
218
- // Normalized
219
- add: Fp2Add,
220
- sub: Fp2Subtract,
221
- mul: Fp2Multiply,
222
- sqr: Fp2Square,
223
- // NonNormalized stuff
224
- addN: Fp2Add,
225
- subN: Fp2Subtract,
226
- mulN: Fp2Multiply,
227
- sqrN: Fp2Square,
228
- // Why inversion for bigint inside Fp instead of Fp2? it is even used in that context?
229
- div: (lhs, rhs) =>
230
- Fp2.mul(lhs, typeof rhs === 'bigint' ? Fp.inv(Fp.create(rhs)) : Fp2.inv(rhs)),
231
- inv: ({ c0: a, c1: b }) => {
232
- // We wish to find the multiplicative inverse of a nonzero
233
- // element a + bu in Fp2. We leverage an identity
234
- //
235
- // (a + bu)(a - bu) = a² + b²
236
- //
237
- // which holds because = -1. This can be rewritten as
238
- //
239
- // (a + bu)(a - bu)/(a² + b²) = 1
240
- //
241
- // because + = 0 has no nonzero solutions for (a, b).
242
- // This gives that (a - bu)/( + ) is the inverse
243
- // of (a + bu). Importantly, this can be computing using
244
- // only a single inversion in Fp.
245
- const factor = Fp.inv(Fp.create(a * a + b * b));
246
- return { c0: Fp.mul(factor, Fp.create(a)), c1: Fp.mul(factor, Fp.create(-b)) };
247
- },
248
- sqrt: (num) => {
249
- if (opts.Fp2sqrt) return opts.Fp2sqrt(num);
250
- // This is generic for all quadratic extensions (Fp2)
251
- const { c0, c1 } = num;
252
- if (Fp.is0(c1)) {
253
- // if c0 is quadratic residue
254
- if (mod.FpLegendre(Fp, c0) === 1) return Fp2.create({ c0: Fp.sqrt(c0), c1: Fp.ZERO });
255
- else return Fp2.create({ c0: Fp.ZERO, c1: Fp.sqrt(Fp.div(c0, FpNONRESIDUE)) });
256
- }
257
- const a = Fp.sqrt(Fp.sub(Fp.sqr(c0), Fp.mul(Fp.sqr(c1), FpNONRESIDUE)));
258
- let d = Fp.mul(Fp.add(a, c0), Fpdiv2);
259
- const legendre = mod.FpLegendre(Fp, d);
260
- // -1, Quadratic non residue
261
- if (legendre === -1) d = Fp.sub(d, a);
262
- const a0 = Fp.sqrt(d);
263
- const candidateSqrt = Fp2.create({ c0: a0, c1: Fp.div(Fp.mul(c1, Fpdiv2), a0) });
264
- if (!Fp2.eql(Fp2.sqr(candidateSqrt), num)) throw new Error('Cannot find square root');
265
- // Normalize root: at this point candidateSqrt ** 2 = num, but also -candidateSqrt ** 2 = num
266
- const x1 = candidateSqrt;
267
- const x2 = Fp2.neg(x1);
268
- const { re: re1, im: im1 } = Fp2.reim(x1);
269
- const { re: re2, im: im2 } = Fp2.reim(x2);
270
- if (im1 > im2 || (im1 === im2 && re1 > re2)) return x1;
271
- return x2;
272
- },
273
- // Same as sgn0_m_eq_2 in RFC 9380
274
- isOdd: (x: Fp2) => {
275
- const { re: x0, im: x1 } = Fp2.reim(x);
276
- const sign_0 = x0 % _2n;
277
- const zero_0 = x0 === _0n;
278
- const sign_1 = x1 % _2n;
279
- return BigInt(sign_0 || (zero_0 && sign_1)) == _1n;
280
- },
281
- // Bytes util
282
- fromBytes(b: Uint8Array): Fp2 {
283
- if (b.length !== Fp2.BYTES) throw new Error('fromBytes invalid length=' + b.length);
284
- return { c0: Fp.fromBytes(b.subarray(0, Fp.BYTES)), c1: Fp.fromBytes(b.subarray(Fp.BYTES)) };
285
- },
286
- toBytes: ({ c0, c1 }) => concatBytes(Fp.toBytes(c0), Fp.toBytes(c1)),
287
- cmov: ({ c0, c1 }, { c0: r0, c1: r1 }, c) => ({
288
- c0: Fp.cmov(c0, r0, c),
289
- c1: Fp.cmov(c1, r1, c),
290
- }),
291
- reim: ({ c0, c1 }) => ({ re: c0, im: c1 }),
292
- // multiply by u + 1
293
- mulByNonresidue: ({ c0, c1 }) => Fp2.mul({ c0, c1 }, Fp2Nonresidue),
294
- mulByB: opts.Fp2mulByB,
295
- fromBigTuple: Fp2fromBigTuple,
296
- frobeniusMap: ({ c0, c1 }, power: number): Fp2 => ({
262
+ // NonNormalized stuff
263
+ addN(a: Fp2, b: Fp2): Fp2 {
264
+ return this.add(a, b);
265
+ }
266
+ subN(a: Fp2, b: Fp2): Fp2 {
267
+ return this.sub(a, b);
268
+ }
269
+ mulN(a: Fp2, b: Fp2): Fp2 {
270
+ return this.mul(a, b);
271
+ }
272
+ sqrN(a: Fp2): Fp2 {
273
+ return this.sqr(a);
274
+ }
275
+ // Why inversion for bigint inside Fp instead of Fp2? it is even used in that context?
276
+ div(lhs: Fp2, rhs: Fp2): Fp2 {
277
+ const { Fp } = this;
278
+ // @ts-ignore
279
+ return this.mul(lhs, typeof rhs === 'bigint' ? Fp.inv(Fp.create(rhs)) : this.inv(rhs));
280
+ }
281
+ inv({ c0: a, c1: b }: Fp2): Fp2 {
282
+ // We wish to find the multiplicative inverse of a nonzero
283
+ // element a + bu in Fp2. We leverage an identity
284
+ //
285
+ // (a + bu)(a - bu) = a² + b²
286
+ //
287
+ // which holds because u² = -1. This can be rewritten as
288
+ //
289
+ // (a + bu)(a - bu)/(a² + b²) = 1
290
+ //
291
+ // because a² + b² = 0 has no nonzero solutions for (a, b).
292
+ // This gives that (a - bu)/(a² + b²) is the inverse
293
+ // of (a + bu). Importantly, this can be computing using
294
+ // only a single inversion in Fp.
295
+ const { Fp } = this;
296
+ const factor = Fp.inv(Fp.create(a * a + b * b));
297
+ return { c0: Fp.mul(factor, Fp.create(a)), c1: Fp.mul(factor, Fp.create(-b)) };
298
+ }
299
+ sqrt(num: Fp2) {
300
+ // This is generic for all quadratic extensions (Fp2)
301
+ const { Fp } = this;
302
+ const Fp2 = this;
303
+ const { c0, c1 } = num;
304
+ if (Fp.is0(c1)) {
305
+ // if c0 is quadratic residue
306
+ if (mod.FpLegendre(Fp, c0) === 1) return Fp2.create({ c0: Fp.sqrt(c0), c1: Fp.ZERO });
307
+ else return Fp2.create({ c0: Fp.ZERO, c1: Fp.sqrt(Fp.div(c0, this.Fp_NONRESIDUE)) });
308
+ }
309
+ const a = Fp.sqrt(Fp.sub(Fp.sqr(c0), Fp.mul(Fp.sqr(c1), this.Fp_NONRESIDUE)));
310
+ let d = Fp.mul(Fp.add(a, c0), this.Fp_div2);
311
+ const legendre = mod.FpLegendre(Fp, d);
312
+ // -1, Quadratic non residue
313
+ if (legendre === -1) d = Fp.sub(d, a);
314
+ const a0 = Fp.sqrt(d);
315
+ const candidateSqrt = Fp2.create({ c0: a0, c1: Fp.div(Fp.mul(c1, this.Fp_div2), a0) });
316
+ if (!Fp2.eql(Fp2.sqr(candidateSqrt), num)) throw new Error('Cannot find square root');
317
+ // Normalize root: at this point candidateSqrt ** 2 = num, but also -candidateSqrt ** 2 = num
318
+ const x1 = candidateSqrt;
319
+ const x2 = Fp2.neg(x1);
320
+ const { re: re1, im: im1 } = Fp2.reim(x1);
321
+ const { re: re2, im: im2 } = Fp2.reim(x2);
322
+ if (im1 > im2 || (im1 === im2 && re1 > re2)) return x1;
323
+ return x2;
324
+ }
325
+ // Same as sgn0_m_eq_2 in RFC 9380
326
+ isOdd(x: Fp2) {
327
+ const { re: x0, im: x1 } = this.reim(x);
328
+ const sign_0 = x0 % _2n;
329
+ const zero_0 = x0 === _0n;
330
+ const sign_1 = x1 % _2n;
331
+ return BigInt(sign_0 || (zero_0 && sign_1)) == _1n;
332
+ }
333
+ // Bytes util
334
+ fromBytes(b: Uint8Array): Fp2 {
335
+ const { Fp } = this;
336
+ if (b.length !== this.BYTES) throw new Error('fromBytes invalid length=' + b.length);
337
+ return { c0: Fp.fromBytes(b.subarray(0, Fp.BYTES)), c1: Fp.fromBytes(b.subarray(Fp.BYTES)) };
338
+ }
339
+ toBytes({ c0, c1 }: Fp2) {
340
+ return concatBytes(this.Fp.toBytes(c0), this.Fp.toBytes(c1));
341
+ }
342
+ cmov({ c0, c1 }: Fp2, { c0: r0, c1: r1 }: Fp2, c: boolean) {
343
+ return {
344
+ c0: this.Fp.cmov(c0, r0, c),
345
+ c1: this.Fp.cmov(c1, r1, c),
346
+ };
347
+ }
348
+ reim({ c0, c1 }: Fp2) {
349
+ return { re: c0, im: c1 };
350
+ }
351
+ Fp4Square(a: Fp2, b: Fp2): { first: Fp2; second: Fp2 } {
352
+ const Fp2 = this;
353
+ const a2 = Fp2.sqr(a);
354
+ const b2 = Fp2.sqr(b);
355
+ return {
356
+ first: Fp2.add(Fp2.mulByNonresidue(b2), a2), // * Nonresidue +
357
+ second: Fp2.sub(Fp2.sub(Fp2.sqr(Fp2.add(a, b)), a2), b2), // (a + b)² - a² - b²
358
+ };
359
+ }
360
+ // multiply by u + 1
361
+ mulByNonresidue({ c0, c1 }: Fp2) {
362
+ return this.mul({ c0, c1 }, this.NONRESIDUE);
363
+ }
364
+ frobeniusMap({ c0, c1 }: Fp2, power: number): Fp2 {
365
+ return {
297
366
  c0,
298
- c1: Fp.mul(c1, FP2_FROBENIUS_COEFFICIENTS[power % 2]),
299
- }),
300
- };
301
- // Fp6
302
- const Fp6Add = ({ c0, c1, c2 }: Fp6, { c0: r0, c1: r1, c2: r2 }: Fp6) => ({
303
- c0: Fp2.add(c0, r0),
304
- c1: Fp2.add(c1, r1),
305
- c2: Fp2.add(c2, r2),
306
- });
307
- const Fp6Subtract = ({ c0, c1, c2 }: Fp6, { c0: r0, c1: r1, c2: r2 }: Fp6) => ({
308
- c0: Fp2.sub(c0, r0),
309
- c1: Fp2.sub(c1, r1),
310
- c2: Fp2.sub(c2, r2),
311
- });
312
- const Fp6Multiply = ({ c0, c1, c2 }: Fp6, rhs: Fp6 | bigint) => {
367
+ c1: this.Fp.mul(c1, this.FROBENIUS_COEFFICIENTS[power % 2]),
368
+ };
369
+ }
370
+ }
371
+
372
+ class _Field6 implements Fp6Bls {
373
+ readonly ORDER: bigint;
374
+ readonly BITS: number;
375
+ readonly BYTES: number;
376
+ readonly isLE: boolean;
377
+
378
+ readonly ZERO: Fp6;
379
+ readonly ONE: Fp6;
380
+ readonly Fp2: Fp2Bls;
381
+ readonly FROBENIUS_COEFFICIENTS_1: Fp2[];
382
+ readonly FROBENIUS_COEFFICIENTS_2: Fp2[];
383
+
384
+ constructor(Fp2: Fp2Bls) {
385
+ this.Fp2 = Fp2;
386
+ this.ORDER = Fp2.ORDER; // TODO: unused, but need to verify
387
+ this.BITS = 3 * Fp2.BITS;
388
+ this.BYTES = 3 * Fp2.BYTES;
389
+ this.isLE = Fp2.isLE;
390
+ this.ZERO = { c0: Fp2.ZERO, c1: Fp2.ZERO, c2: Fp2.ZERO };
391
+ this.ONE = { c0: Fp2.ONE, c1: Fp2.ZERO, c2: Fp2.ZERO };
392
+ const { Fp } = Fp2;
393
+ const frob = calcFrobeniusCoefficients(Fp2, Fp2.NONRESIDUE, Fp.ORDER, 6, 2, 3);
394
+ this.FROBENIUS_COEFFICIENTS_1 = frob[0];
395
+ this.FROBENIUS_COEFFICIENTS_2 = frob[1];
396
+ Object.seal(this);
397
+ }
398
+ add({ c0, c1, c2 }: Fp6, { c0: r0, c1: r1, c2: r2 }: Fp6) {
399
+ const { Fp2 } = this;
400
+ return {
401
+ c0: Fp2.add(c0, r0),
402
+ c1: Fp2.add(c1, r1),
403
+ c2: Fp2.add(c2, r2),
404
+ };
405
+ }
406
+ sub({ c0, c1, c2 }: Fp6, { c0: r0, c1: r1, c2: r2 }: Fp6) {
407
+ const { Fp2 } = this;
408
+ return {
409
+ c0: Fp2.sub(c0, r0),
410
+ c1: Fp2.sub(c1, r1),
411
+ c2: Fp2.sub(c2, r2),
412
+ };
413
+ }
414
+ mul({ c0, c1, c2 }: Fp6, rhs: Fp6 | bigint) {
415
+ const { Fp2 } = this;
313
416
  if (typeof rhs === 'bigint') {
314
417
  return {
315
418
  c0: Fp2.mul(c0, rhs),
@@ -335,8 +438,9 @@ export function tower12(opts: Tower12Opts): {
335
438
  // T1 + (c0 + c2) * (r0 + r2) - T0 + T2
336
439
  c2: Fp2.sub(Fp2.add(t1, Fp2.mul(Fp2.add(c0, c2), Fp2.add(r0, r2))), Fp2.add(t0, t2)),
337
440
  };
338
- };
339
- const Fp6Square = ({ c0, c1, c2 }: Fp6) => {
441
+ }
442
+ sqr({ c0, c1, c2 }: Fp6) {
443
+ const { Fp2 } = this;
340
444
  let t0 = Fp2.sqr(c0); // c0²
341
445
  let t1 = Fp2.mul(Fp2.mul(c0, c1), _2n); // 2 * c0 * c1
342
446
  let t3 = Fp2.mul(Fp2.mul(c1, c2), _2n); // 2 * c1 * c2
@@ -347,133 +451,244 @@ export function tower12(opts: Tower12Opts): {
347
451
  // T1 + (c0 - c1 + c2)² + T3 - T0 - T4
348
452
  c2: Fp2.sub(Fp2.sub(Fp2.add(Fp2.add(t1, Fp2.sqr(Fp2.add(Fp2.sub(c0, c1), c2))), t3), t0), t4),
349
453
  };
350
- };
351
- const [FP6_FROBENIUS_COEFFICIENTS_1, FP6_FROBENIUS_COEFFICIENTS_2] = calcFrobeniusCoefficients(
352
- Fp2,
353
- Fp2Nonresidue,
354
- Fp.ORDER,
355
- 6,
356
- 2,
357
- 3
358
- );
454
+ }
455
+ addN(a: Fp6, b: Fp6): Fp6 {
456
+ return this.add(a, b);
457
+ }
458
+ subN(a: Fp6, b: Fp6): Fp6 {
459
+ return this.sub(a, b);
460
+ }
461
+ mulN(a: Fp6, b: Fp6): Fp6 {
462
+ return this.mul(a, b);
463
+ }
464
+ sqrN(a: Fp6): Fp6 {
465
+ return this.sqr(a);
466
+ }
359
467
 
360
- const Fp6: Fp6Bls = {
361
- ORDER: Fp2.ORDER, // TODO: unused, but need to verify
362
- isLE: Fp2.isLE,
363
- BITS: 3 * Fp2.BITS,
364
- BYTES: 3 * Fp2.BYTES,
365
- MASK: bitMask(3 * Fp2.BITS),
366
- ZERO: { c0: Fp2.ZERO, c1: Fp2.ZERO, c2: Fp2.ZERO },
367
- ONE: { c0: Fp2.ONE, c1: Fp2.ZERO, c2: Fp2.ZERO },
368
- create: (num) => num,
369
- isValid: ({ c0, c1, c2 }) => Fp2.isValid(c0) && Fp2.isValid(c1) && Fp2.isValid(c2),
370
- is0: ({ c0, c1, c2 }) => Fp2.is0(c0) && Fp2.is0(c1) && Fp2.is0(c2),
371
- isValidNot0: (num) => !Fp6.is0(num) && Fp6.isValid(num),
372
- neg: ({ c0, c1, c2 }) => ({ c0: Fp2.neg(c0), c1: Fp2.neg(c1), c2: Fp2.neg(c2) }),
373
- eql: ({ c0, c1, c2 }, { c0: r0, c1: r1, c2: r2 }) =>
374
- Fp2.eql(c0, r0) && Fp2.eql(c1, r1) && Fp2.eql(c2, r2),
375
- sqrt: notImplemented,
376
- // Do we need division by bigint at all? Should be done via order:
377
- div: (lhs, rhs) =>
378
- Fp6.mul(lhs, typeof rhs === 'bigint' ? Fp.inv(Fp.create(rhs)) : Fp6.inv(rhs)),
379
- pow: (num, power) => mod.FpPow(Fp6, num, power),
380
- invertBatch: (nums) => mod.FpInvertBatch(Fp6, nums),
381
- // Normalized
382
- add: Fp6Add,
383
- sub: Fp6Subtract,
384
- mul: Fp6Multiply,
385
- sqr: Fp6Square,
386
- // NonNormalized stuff
387
- addN: Fp6Add,
388
- subN: Fp6Subtract,
389
- mulN: Fp6Multiply,
390
- sqrN: Fp6Square,
468
+ create(num: Fp6) {
469
+ return num;
470
+ }
391
471
 
392
- inv: ({ c0, c1, c2 }) => {
393
- let t0 = Fp2.sub(Fp2.sqr(c0), Fp2.mulByNonresidue(Fp2.mul(c2, c1))); // c0² - c2 * c1 * (u + 1)
394
- let t1 = Fp2.sub(Fp2.mulByNonresidue(Fp2.sqr(c2)), Fp2.mul(c0, c1)); // c2² * (u + 1) - c0 * c1
395
- let t2 = Fp2.sub(Fp2.sqr(c1), Fp2.mul(c0, c2)); // c1² - c0 * c2
396
- // 1/(((c2 * T1 + c1 * T2) * v) + c0 * T0)
397
- let t4 = Fp2.inv(
398
- Fp2.add(Fp2.mulByNonresidue(Fp2.add(Fp2.mul(c2, t1), Fp2.mul(c1, t2))), Fp2.mul(c0, t0))
399
- );
400
- return { c0: Fp2.mul(t4, t0), c1: Fp2.mul(t4, t1), c2: Fp2.mul(t4, t2) };
401
- },
402
- // Bytes utils
403
- fromBytes: (b: Uint8Array): Fp6 => {
404
- if (b.length !== Fp6.BYTES) throw new Error('fromBytes invalid length=' + b.length);
405
- return {
406
- c0: Fp2.fromBytes(b.subarray(0, Fp2.BYTES)),
407
- c1: Fp2.fromBytes(b.subarray(Fp2.BYTES, 2 * Fp2.BYTES)),
408
- c2: Fp2.fromBytes(b.subarray(2 * Fp2.BYTES)),
409
- };
410
- },
411
- toBytes: ({ c0, c1, c2 }): Uint8Array =>
412
- concatBytes(Fp2.toBytes(c0), Fp2.toBytes(c1), Fp2.toBytes(c2)),
413
- cmov: ({ c0, c1, c2 }: Fp6, { c0: r0, c1: r1, c2: r2 }: Fp6, c) => ({
472
+ isValid({ c0, c1, c2 }: Fp6) {
473
+ const { Fp2 } = this;
474
+ return Fp2.isValid(c0) && Fp2.isValid(c1) && Fp2.isValid(c2);
475
+ }
476
+ is0({ c0, c1, c2 }: Fp6) {
477
+ const { Fp2 } = this;
478
+ return Fp2.is0(c0) && Fp2.is0(c1) && Fp2.is0(c2);
479
+ }
480
+ isValidNot0(num: Fp6) {
481
+ return !this.is0(num) && this.isValid(num);
482
+ }
483
+ neg({ c0, c1, c2 }: Fp6) {
484
+ const { Fp2 } = this;
485
+ return { c0: Fp2.neg(c0), c1: Fp2.neg(c1), c2: Fp2.neg(c2) };
486
+ }
487
+ eql({ c0, c1, c2 }: Fp6, { c0: r0, c1: r1, c2: r2 }: Fp6) {
488
+ const { Fp2 } = this;
489
+ return Fp2.eql(c0, r0) && Fp2.eql(c1, r1) && Fp2.eql(c2, r2);
490
+ }
491
+ sqrt(_: Fp6) {
492
+ return notImplemented();
493
+ }
494
+ // Do we need division by bigint at all? Should be done via order:
495
+ div(lhs: Fp6, rhs: Fp6) {
496
+ const { Fp2 } = this;
497
+ const { Fp } = Fp2;
498
+ return this.mul(lhs, typeof rhs === 'bigint' ? Fp.inv(Fp.create(rhs)) : this.inv(rhs));
499
+ }
500
+ pow(num: Fp6, power: Fp): Fp6 {
501
+ return mod.FpPow(this, num, power);
502
+ }
503
+ invertBatch(nums: Fp6[]): Fp6[] {
504
+ return mod.FpInvertBatch(this, nums);
505
+ }
506
+
507
+ inv({ c0, c1, c2 }: Fp6) {
508
+ const { Fp2 } = this;
509
+ let t0 = Fp2.sub(Fp2.sqr(c0), Fp2.mulByNonresidue(Fp2.mul(c2, c1))); // c0² - c2 * c1 * (u + 1)
510
+ let t1 = Fp2.sub(Fp2.mulByNonresidue(Fp2.sqr(c2)), Fp2.mul(c0, c1)); // c2² * (u + 1) - c0 * c1
511
+ let t2 = Fp2.sub(Fp2.sqr(c1), Fp2.mul(c0, c2)); // c1² - c0 * c2
512
+ // 1/(((c2 * T1 + c1 * T2) * v) + c0 * T0)
513
+ let t4 = Fp2.inv(
514
+ Fp2.add(Fp2.mulByNonresidue(Fp2.add(Fp2.mul(c2, t1), Fp2.mul(c1, t2))), Fp2.mul(c0, t0))
515
+ );
516
+ return { c0: Fp2.mul(t4, t0), c1: Fp2.mul(t4, t1), c2: Fp2.mul(t4, t2) };
517
+ }
518
+ // Bytes utils
519
+ fromBytes(b: Uint8Array): Fp6 {
520
+ const { Fp2 } = this;
521
+ if (b.length !== this.BYTES) throw new Error('fromBytes invalid length=' + b.length);
522
+ const B2 = Fp2.BYTES;
523
+ return {
524
+ c0: Fp2.fromBytes(b.subarray(0, B2)),
525
+ c1: Fp2.fromBytes(b.subarray(B2, B2 * 2)),
526
+ c2: Fp2.fromBytes(b.subarray(2 * B2)),
527
+ };
528
+ }
529
+ toBytes({ c0, c1, c2 }: Fp6): Uint8Array {
530
+ const { Fp2 } = this;
531
+ return concatBytes(Fp2.toBytes(c0), Fp2.toBytes(c1), Fp2.toBytes(c2));
532
+ }
533
+ cmov({ c0, c1, c2 }: Fp6, { c0: r0, c1: r1, c2: r2 }: Fp6, c: boolean) {
534
+ const { Fp2 } = this;
535
+ return {
414
536
  c0: Fp2.cmov(c0, r0, c),
415
537
  c1: Fp2.cmov(c1, r1, c),
416
538
  c2: Fp2.cmov(c2, r2, c),
417
- }),
418
- fromBigSix: (t: BigintSix): Fp6 => {
419
- if (!Array.isArray(t) || t.length !== 6) throw new Error('invalid Fp6 usage');
420
- return {
421
- c0: Fp2.fromBigTuple(t.slice(0, 2) as BigintTuple),
422
- c1: Fp2.fromBigTuple(t.slice(2, 4) as BigintTuple),
423
- c2: Fp2.fromBigTuple(t.slice(4, 6) as BigintTuple),
424
- };
425
- },
426
- frobeniusMap: ({ c0, c1, c2 }, power: number) => ({
539
+ };
540
+ }
541
+ fromBigSix(t: BigintSix): Fp6 {
542
+ const { Fp2 } = this;
543
+ if (!Array.isArray(t) || t.length !== 6) throw new Error('invalid Fp6 usage');
544
+ return {
545
+ c0: Fp2.fromBigTuple(t.slice(0, 2) as BigintTuple),
546
+ c1: Fp2.fromBigTuple(t.slice(2, 4) as BigintTuple),
547
+ c2: Fp2.fromBigTuple(t.slice(4, 6) as BigintTuple),
548
+ };
549
+ }
550
+ frobeniusMap({ c0, c1, c2 }: Fp6, power: number) {
551
+ const { Fp2 } = this;
552
+ return {
427
553
  c0: Fp2.frobeniusMap(c0, power),
428
- c1: Fp2.mul(Fp2.frobeniusMap(c1, power), FP6_FROBENIUS_COEFFICIENTS_1[power % 6]),
429
- c2: Fp2.mul(Fp2.frobeniusMap(c2, power), FP6_FROBENIUS_COEFFICIENTS_2[power % 6]),
430
- }),
431
- mulByFp2: ({ c0, c1, c2 }, rhs: Fp2): Fp6 => ({
554
+ c1: Fp2.mul(Fp2.frobeniusMap(c1, power), this.FROBENIUS_COEFFICIENTS_1[power % 6]),
555
+ c2: Fp2.mul(Fp2.frobeniusMap(c2, power), this.FROBENIUS_COEFFICIENTS_2[power % 6]),
556
+ };
557
+ }
558
+ mulByFp2({ c0, c1, c2 }: Fp6, rhs: Fp2): Fp6 {
559
+ const { Fp2 } = this;
560
+ return {
432
561
  c0: Fp2.mul(c0, rhs),
433
562
  c1: Fp2.mul(c1, rhs),
434
563
  c2: Fp2.mul(c2, rhs),
435
- }),
436
- mulByNonresidue: ({ c0, c1, c2 }) => ({ c0: Fp2.mulByNonresidue(c2), c1: c0, c2: c1 }),
437
- // Sparse multiplication
438
- mul1: ({ c0, c1, c2 }, b1: Fp2): Fp6 => ({
564
+ };
565
+ }
566
+ mulByNonresidue({ c0, c1, c2 }: Fp6) {
567
+ const { Fp2 } = this;
568
+ return { c0: Fp2.mulByNonresidue(c2), c1: c0, c2: c1 };
569
+ }
570
+ // Sparse multiplication
571
+ mul1({ c0, c1, c2 }: Fp6, b1: Fp2): Fp6 {
572
+ const { Fp2 } = this;
573
+ return {
439
574
  c0: Fp2.mulByNonresidue(Fp2.mul(c2, b1)),
440
575
  c1: Fp2.mul(c0, b1),
441
576
  c2: Fp2.mul(c1, b1),
442
- }),
443
- // Sparse multiplication
444
- mul01({ c0, c1, c2 }, b0: Fp2, b1: Fp2): Fp6 {
445
- let t0 = Fp2.mul(c0, b0); // c0 * b0
446
- let t1 = Fp2.mul(c1, b1); // c1 * b1
447
- return {
448
- // ((c1 + c2) * b1 - T1) * (u + 1) + T0
449
- c0: Fp2.add(Fp2.mulByNonresidue(Fp2.sub(Fp2.mul(Fp2.add(c1, c2), b1), t1)), t0),
450
- // (b0 + b1) * (c0 + c1) - T0 - T1
451
- c1: Fp2.sub(Fp2.sub(Fp2.mul(Fp2.add(b0, b1), Fp2.add(c0, c1)), t0), t1),
452
- // (c0 + c2) * b0 - T0 + T1
453
- c2: Fp2.add(Fp2.sub(Fp2.mul(Fp2.add(c0, c2), b0), t0), t1),
454
- };
455
- },
456
- };
577
+ };
578
+ }
579
+ // Sparse multiplication
580
+ mul01({ c0, c1, c2 }: Fp6, b0: Fp2, b1: Fp2): Fp6 {
581
+ const { Fp2 } = this;
582
+ let t0 = Fp2.mul(c0, b0); // c0 * b0
583
+ let t1 = Fp2.mul(c1, b1); // c1 * b1
584
+ return {
585
+ // ((c1 + c2) * b1 - T1) * (u + 1) + T0
586
+ c0: Fp2.add(Fp2.mulByNonresidue(Fp2.sub(Fp2.mul(Fp2.add(c1, c2), b1), t1)), t0),
587
+ // (b0 + b1) * (c0 + c1) - T0 - T1
588
+ c1: Fp2.sub(Fp2.sub(Fp2.mul(Fp2.add(b0, b1), Fp2.add(c0, c1)), t0), t1),
589
+ // (c0 + c2) * b0 - T0 + T1
590
+ c2: Fp2.add(Fp2.sub(Fp2.mul(Fp2.add(c0, c2), b0), t0), t1),
591
+ };
592
+ }
593
+ }
594
+
595
+ class _Field12 implements Fp12Bls {
596
+ readonly ORDER: bigint;
597
+ readonly BITS: number;
598
+ readonly BYTES: number;
599
+ readonly isLE: boolean;
600
+
601
+ readonly ZERO: Fp12;
602
+ readonly ONE: Fp12;
603
+
604
+ readonly Fp6: Fp6Bls;
605
+ readonly FROBENIUS_COEFFICIENTS: Fp2[];
606
+ readonly X_LEN: number;
607
+ readonly finalExponentiate: Tower12Opts['Fp12finalExponentiate'];
457
608
 
458
- // Fp12
459
- const FP12_FROBENIUS_COEFFICIENTS = calcFrobeniusCoefficients(
460
- Fp2,
461
- Fp2Nonresidue,
462
- Fp.ORDER,
463
- 12,
464
- 1,
465
- 6
466
- )[0];
609
+ constructor(Fp6: Fp6Bls, opts: Tower12Opts) {
610
+ const { Fp2 } = Fp6;
611
+ const { Fp } = Fp2;
612
+ this.Fp6 = Fp6;
467
613
 
468
- const Fp12Add = ({ c0, c1 }: Fp12, { c0: r0, c1: r1 }: Fp12) => ({
469
- c0: Fp6.add(c0, r0),
470
- c1: Fp6.add(c1, r1),
471
- });
472
- const Fp12Subtract = ({ c0, c1 }: Fp12, { c0: r0, c1: r1 }: Fp12) => ({
473
- c0: Fp6.sub(c0, r0),
474
- c1: Fp6.sub(c1, r1),
475
- });
476
- const Fp12Multiply = ({ c0, c1 }: Fp12, rhs: Fp12 | bigint) => {
614
+ this.ORDER = Fp2.ORDER; // TODO: verify if it's unuesd
615
+ this.BITS = 2 * Fp6.BITS;
616
+ this.BYTES = 2 * Fp6.BYTES;
617
+ this.isLE = Fp6.isLE;
618
+ this.ZERO = { c0: Fp6.ZERO, c1: Fp6.ZERO };
619
+ this.ONE = { c0: Fp6.ONE, c1: Fp6.ZERO };
620
+
621
+ this.FROBENIUS_COEFFICIENTS = calcFrobeniusCoefficients(
622
+ Fp2,
623
+ Fp2.NONRESIDUE,
624
+ Fp.ORDER,
625
+ 12,
626
+ 1,
627
+ 6
628
+ )[0];
629
+ this.X_LEN = opts.X_LEN;
630
+ this.finalExponentiate = opts.Fp12finalExponentiate;
631
+ }
632
+ create(num: Fp12) {
633
+ return num;
634
+ }
635
+ isValid({ c0, c1 }: Fp12) {
636
+ const { Fp6 } = this;
637
+ return Fp6.isValid(c0) && Fp6.isValid(c1);
638
+ }
639
+ is0({ c0, c1 }: Fp12) {
640
+ const { Fp6 } = this;
641
+ return Fp6.is0(c0) && Fp6.is0(c1);
642
+ }
643
+ isValidNot0(num: Fp12) {
644
+ return !this.is0(num) && this.isValid(num);
645
+ }
646
+ neg({ c0, c1 }: Fp12) {
647
+ const { Fp6 } = this;
648
+ return { c0: Fp6.neg(c0), c1: Fp6.neg(c1) };
649
+ }
650
+ eql({ c0, c1 }: Fp12, { c0: r0, c1: r1 }: Fp12) {
651
+ const { Fp6 } = this;
652
+ return Fp6.eql(c0, r0) && Fp6.eql(c1, r1);
653
+ }
654
+ sqrt(_: any): any {
655
+ notImplemented();
656
+ }
657
+ inv({ c0, c1 }: Fp12) {
658
+ const { Fp6 } = this;
659
+ let t = Fp6.inv(Fp6.sub(Fp6.sqr(c0), Fp6.mulByNonresidue(Fp6.sqr(c1)))); // 1 / (c0² - c1² * v)
660
+ return { c0: Fp6.mul(c0, t), c1: Fp6.neg(Fp6.mul(c1, t)) }; // ((C0 * T) * T) + (-C1 * T) * w
661
+ }
662
+ div(lhs: Fp12, rhs: Fp12) {
663
+ const { Fp6 } = this;
664
+ const { Fp2 } = Fp6;
665
+ const { Fp } = Fp2;
666
+ return this.mul(lhs, typeof rhs === 'bigint' ? Fp.inv(Fp.create(rhs)) : this.inv(rhs));
667
+ }
668
+ pow(num: Fp12, power: bigint): Fp12 {
669
+ return mod.FpPow(this, num, power);
670
+ }
671
+ invertBatch(nums: Fp12[]): Fp12[] {
672
+ return mod.FpInvertBatch(this, nums);
673
+ }
674
+
675
+ // Normalized
676
+ add({ c0, c1 }: Fp12, { c0: r0, c1: r1 }: Fp12) {
677
+ const { Fp6 } = this;
678
+ return {
679
+ c0: Fp6.add(c0, r0),
680
+ c1: Fp6.add(c1, r1),
681
+ };
682
+ }
683
+ sub({ c0, c1 }: Fp12, { c0: r0, c1: r1 }: Fp12) {
684
+ const { Fp6 } = this;
685
+ return {
686
+ c0: Fp6.sub(c0, r0),
687
+ c1: Fp6.sub(c1, r1),
688
+ };
689
+ }
690
+ mul({ c0, c1 }: Fp12, rhs: Fp12 | bigint) {
691
+ const { Fp6 } = this;
477
692
  if (typeof rhs === 'bigint') return { c0: Fp6.mul(c0, rhs), c1: Fp6.mul(c1, rhs) };
478
693
  let { c0: r0, c1: r1 } = rhs;
479
694
  let t1 = Fp6.mul(c0, r0); // c0 * r0
@@ -483,8 +698,9 @@ export function tower12(opts: Tower12Opts): {
483
698
  // (c0 + c1) * (r0 + r1) - (T1 + T2)
484
699
  c1: Fp6.sub(Fp6.mul(Fp6.add(c0, c1), Fp6.add(r0, r1)), Fp6.add(t1, t2)),
485
700
  };
486
- };
487
- const Fp12Square = ({ c0, c1 }: Fp12) => {
701
+ }
702
+ sqr({ c0, c1 }: Fp12) {
703
+ const { Fp6 } = this;
488
704
  let ab = Fp6.mul(c0, c1); // c0 * c1
489
705
  return {
490
706
  // (c1 * v + c0) * (c0 + c1) - AB - AB * v
@@ -494,126 +710,155 @@ export function tower12(opts: Tower12Opts): {
494
710
  ),
495
711
  c1: Fp6.add(ab, ab),
496
712
  }; // AB + AB
497
- };
498
- function Fp4Square(a: Fp2, b: Fp2): { first: Fp2; second: Fp2 } {
499
- const a2 = Fp2.sqr(a);
500
- const b2 = Fp2.sqr(b);
713
+ }
714
+ // NonNormalized stuff
715
+ addN(a: Fp12, b: Fp12): Fp12 {
716
+ return this.add(a, b);
717
+ }
718
+ subN(a: Fp12, b: Fp12): Fp12 {
719
+ return this.sub(a, b);
720
+ }
721
+ mulN(a: Fp12, b: Fp12): Fp12 {
722
+ return this.mul(a, b);
723
+ }
724
+ sqrN(a: Fp12): Fp12 {
725
+ return this.sqr(a);
726
+ }
727
+
728
+ // Bytes utils
729
+ fromBytes(b: Uint8Array): Fp12 {
730
+ const { Fp6 } = this;
731
+ if (b.length !== this.BYTES) throw new Error('fromBytes invalid length=' + b.length);
501
732
  return {
502
- first: Fp2.add(Fp2.mulByNonresidue(b2), a2), // b² * Nonresidue + a²
503
- second: Fp2.sub(Fp2.sub(Fp2.sqr(Fp2.add(a, b)), a2), b2), // (a + b)² - a² - b²
733
+ c0: Fp6.fromBytes(b.subarray(0, Fp6.BYTES)),
734
+ c1: Fp6.fromBytes(b.subarray(Fp6.BYTES)),
504
735
  };
505
736
  }
506
-
507
- const Fp12: Fp12Bls = {
508
- ORDER: Fp2.ORDER, // TODO: unused, but need to verify
509
- isLE: Fp6.isLE,
510
- BITS: 2 * Fp6.BITS,
511
- BYTES: 2 * Fp6.BYTES,
512
- MASK: bitMask(2 * Fp6.BITS),
513
- ZERO: { c0: Fp6.ZERO, c1: Fp6.ZERO },
514
- ONE: { c0: Fp6.ONE, c1: Fp6.ZERO },
515
- create: (num) => num,
516
- isValid: ({ c0, c1 }) => Fp6.isValid(c0) && Fp6.isValid(c1),
517
- is0: ({ c0, c1 }) => Fp6.is0(c0) && Fp6.is0(c1),
518
- isValidNot0: (num) => !Fp12.is0(num) && Fp12.isValid(num),
519
- neg: ({ c0, c1 }) => ({ c0: Fp6.neg(c0), c1: Fp6.neg(c1) }),
520
- eql: ({ c0, c1 }, { c0: r0, c1: r1 }) => Fp6.eql(c0, r0) && Fp6.eql(c1, r1),
521
- sqrt: notImplemented,
522
- inv: ({ c0, c1 }) => {
523
- let t = Fp6.inv(Fp6.sub(Fp6.sqr(c0), Fp6.mulByNonresidue(Fp6.sqr(c1)))); // 1 / (c0² - c1² * v)
524
- return { c0: Fp6.mul(c0, t), c1: Fp6.neg(Fp6.mul(c1, t)) }; // ((C0 * T) * T) + (-C1 * T) * w
525
- },
526
- div: (lhs, rhs) =>
527
- Fp12.mul(lhs, typeof rhs === 'bigint' ? Fp.inv(Fp.create(rhs)) : Fp12.inv(rhs)),
528
- pow: (num, power) => mod.FpPow(Fp12, num, power),
529
- invertBatch: (nums) => mod.FpInvertBatch(Fp12, nums),
530
- // Normalized
531
- add: Fp12Add,
532
- sub: Fp12Subtract,
533
- mul: Fp12Multiply,
534
- sqr: Fp12Square,
535
- // NonNormalized stuff
536
- addN: Fp12Add,
537
- subN: Fp12Subtract,
538
- mulN: Fp12Multiply,
539
- sqrN: Fp12Square,
540
-
541
- // Bytes utils
542
- fromBytes: (b: Uint8Array): Fp12 => {
543
- if (b.length !== Fp12.BYTES) throw new Error('fromBytes invalid length=' + b.length);
544
- return {
545
- c0: Fp6.fromBytes(b.subarray(0, Fp6.BYTES)),
546
- c1: Fp6.fromBytes(b.subarray(Fp6.BYTES)),
547
- };
548
- },
549
- toBytes: ({ c0, c1 }): Uint8Array => concatBytes(Fp6.toBytes(c0), Fp6.toBytes(c1)),
550
- cmov: ({ c0, c1 }, { c0: r0, c1: r1 }, c) => ({
737
+ toBytes({ c0, c1 }: Fp12): Uint8Array {
738
+ const { Fp6 } = this;
739
+ return concatBytes(Fp6.toBytes(c0), Fp6.toBytes(c1));
740
+ }
741
+ cmov({ c0, c1 }: Fp12, { c0: r0, c1: r1 }: Fp12, c: boolean) {
742
+ const { Fp6 } = this;
743
+ return {
551
744
  c0: Fp6.cmov(c0, r0, c),
552
745
  c1: Fp6.cmov(c1, r1, c),
553
- }),
554
- // Utils
555
- // toString() {
556
- // return '' + 'Fp12(' + this.c0 + this.c1 + '* w');
557
- // },
558
- // fromTuple(c: [Fp6, Fp6]) {
559
- // return new Fp12(...c);
560
- // }
561
- fromBigTwelve: (t: BigintTwelve): Fp12 => ({
746
+ };
747
+ }
748
+ // Utils
749
+ // toString() {
750
+ // return '' + 'Fp12(' + this.c0 + this.c1 + '* w');
751
+ // },
752
+ // fromTuple(c: [Fp6, Fp6]) {
753
+ // return new Fp12(...c);
754
+ // }
755
+ fromBigTwelve(t: BigintTwelve): Fp12 {
756
+ const { Fp6 } = this;
757
+ return {
562
758
  c0: Fp6.fromBigSix(t.slice(0, 6) as BigintSix),
563
759
  c1: Fp6.fromBigSix(t.slice(6, 12) as BigintSix),
564
- }),
565
- // Raises to q**i -th power
566
- frobeniusMap(lhs, power: number) {
567
- const { c0, c1, c2 } = Fp6.frobeniusMap(lhs.c1, power);
568
- const coeff = FP12_FROBENIUS_COEFFICIENTS[power % 12];
569
- return {
570
- c0: Fp6.frobeniusMap(lhs.c0, power),
571
- c1: Fp6.create({
572
- c0: Fp2.mul(c0, coeff),
573
- c1: Fp2.mul(c1, coeff),
574
- c2: Fp2.mul(c2, coeff),
575
- }),
576
- };
577
- },
578
- mulByFp2: ({ c0, c1 }, rhs: Fp2): Fp12 => ({
760
+ };
761
+ }
762
+ // Raises to q**i -th power
763
+ frobeniusMap(lhs: Fp12, power: number) {
764
+ const { Fp6 } = this;
765
+ const { Fp2 } = Fp6;
766
+ const { c0, c1, c2 } = Fp6.frobeniusMap(lhs.c1, power);
767
+ const coeff = this.FROBENIUS_COEFFICIENTS[power % 12];
768
+ return {
769
+ c0: Fp6.frobeniusMap(lhs.c0, power),
770
+ c1: Fp6.create({
771
+ c0: Fp2.mul(c0, coeff),
772
+ c1: Fp2.mul(c1, coeff),
773
+ c2: Fp2.mul(c2, coeff),
774
+ }),
775
+ };
776
+ }
777
+ mulByFp2({ c0, c1 }: Fp12, rhs: Fp2): Fp12 {
778
+ const { Fp6 } = this;
779
+ return {
579
780
  c0: Fp6.mulByFp2(c0, rhs),
580
781
  c1: Fp6.mulByFp2(c1, rhs),
581
- }),
582
- conjugate: ({ c0, c1 }): Fp12 => ({ c0, c1: Fp6.neg(c1) }),
583
- // Sparse multiplication
584
- mul014: ({ c0, c1 }, o0: Fp2, o1: Fp2, o4: Fp2) => {
585
- let t0 = Fp6.mul01(c0, o0, o1);
586
- let t1 = Fp6.mul1(c1, o4);
587
- return {
588
- c0: Fp6.add(Fp6.mulByNonresidue(t1), t0), // T1 * v + T0
589
- // (c1 + c0) * [o0, o1+o4] - T0 - T1
590
- c1: Fp6.sub(Fp6.sub(Fp6.mul01(Fp6.add(c1, c0), o0, Fp2.add(o1, o4)), t0), t1),
591
- };
592
- },
593
- mul034: ({ c0, c1 }, o0: Fp2, o3: Fp2, o4: Fp2) => {
594
- const a = Fp6.create({
595
- c0: Fp2.mul(c0.c0, o0),
596
- c1: Fp2.mul(c0.c1, o0),
597
- c2: Fp2.mul(c0.c2, o0),
598
- });
599
- const b = Fp6.mul01(c1, o3, o4);
600
- const e = Fp6.mul01(Fp6.add(c0, c1), Fp2.add(o0, o3), o4);
601
- return {
602
- c0: Fp6.add(Fp6.mulByNonresidue(b), a),
603
- c1: Fp6.sub(e, Fp6.add(a, b)),
604
- };
605
- },
782
+ };
783
+ }
784
+ conjugate({ c0, c1 }: Fp12): Fp12 {
785
+ return { c0, c1: this.Fp6.neg(c1) };
786
+ }
787
+ // Sparse multiplication
788
+ mul014({ c0, c1 }: Fp12, o0: Fp2, o1: Fp2, o4: Fp2) {
789
+ const { Fp6 } = this;
790
+ const { Fp2 } = Fp6;
791
+ let t0 = Fp6.mul01(c0, o0, o1);
792
+ let t1 = Fp6.mul1(c1, o4);
793
+ return {
794
+ c0: Fp6.add(Fp6.mulByNonresidue(t1), t0), // T1 * v + T0
795
+ // (c1 + c0) * [o0, o1+o4] - T0 - T1
796
+ c1: Fp6.sub(Fp6.sub(Fp6.mul01(Fp6.add(c1, c0), o0, Fp2.add(o1, o4)), t0), t1),
797
+ };
798
+ }
799
+ mul034({ c0, c1 }: Fp12, o0: Fp2, o3: Fp2, o4: Fp2) {
800
+ const { Fp6 } = this;
801
+ const { Fp2 } = Fp6;
802
+ const a = Fp6.create({
803
+ c0: Fp2.mul(c0.c0, o0),
804
+ c1: Fp2.mul(c0.c1, o0),
805
+ c2: Fp2.mul(c0.c2, o0),
806
+ });
807
+ const b = Fp6.mul01(c1, o3, o4);
808
+ const e = Fp6.mul01(Fp6.add(c0, c1), Fp2.add(o0, o3), o4);
809
+ return {
810
+ c0: Fp6.add(Fp6.mulByNonresidue(b), a),
811
+ c1: Fp6.sub(e, Fp6.add(a, b)),
812
+ };
813
+ }
606
814
 
607
- // A cyclotomic group is a subgroup of Fp^n defined by
608
- // GΦₙ(p) = {α ∈ Fpⁿ : α^Φₙ(p) = 1}
609
- // The result of any pairing is in a cyclotomic subgroup
610
- // https://eprint.iacr.org/2009/565.pdf
611
- _cyclotomicSquare: opts.Fp12cyclotomicSquare,
612
- _cyclotomicExp: opts.Fp12cyclotomicExp,
613
- // https://eprint.iacr.org/2010/354.pdf
614
- // https://eprint.iacr.org/2009/565.pdf
615
- finalExponentiate: opts.Fp12finalExponentiate,
616
- };
815
+ // A cyclotomic group is a subgroup of Fp^n defined by
816
+ // GΦₙ(p) = {α ∈ Fpⁿ : α^Φₙ(p) = 1}
817
+ // The result of any pairing is in a cyclotomic subgroup
818
+ // https://eprint.iacr.org/2009/565.pdf
819
+ // https://eprint.iacr.org/2010/354.pdf
820
+ _cyclotomicSquare({ c0, c1 }: Fp12): Fp12 {
821
+ const { Fp6 } = this;
822
+ const { Fp2 } = Fp6;
823
+ const { c0: c0c0, c1: c0c1, c2: c0c2 } = c0;
824
+ const { c0: c1c0, c1: c1c1, c2: c1c2 } = c1;
825
+ const { first: t3, second: t4 } = Fp2.Fp4Square(c0c0, c1c1);
826
+ const { first: t5, second: t6 } = Fp2.Fp4Square(c1c0, c0c2);
827
+ const { first: t7, second: t8 } = Fp2.Fp4Square(c0c1, c1c2);
828
+ const t9 = Fp2.mulByNonresidue(t8); // T8 * (u + 1)
829
+ return {
830
+ c0: Fp6.create({
831
+ c0: Fp2.add(Fp2.mul(Fp2.sub(t3, c0c0), _2n), t3), // 2 * (T3 - c0c0) + T3
832
+ c1: Fp2.add(Fp2.mul(Fp2.sub(t5, c0c1), _2n), t5), // 2 * (T5 - c0c1) + T5
833
+ c2: Fp2.add(Fp2.mul(Fp2.sub(t7, c0c2), _2n), t7),
834
+ }), // 2 * (T7 - c0c2) + T7
835
+ c1: Fp6.create({
836
+ c0: Fp2.add(Fp2.mul(Fp2.add(t9, c1c0), _2n), t9), // 2 * (T9 + c1c0) + T9
837
+ c1: Fp2.add(Fp2.mul(Fp2.add(t4, c1c1), _2n), t4), // 2 * (T4 + c1c1) + T4
838
+ c2: Fp2.add(Fp2.mul(Fp2.add(t6, c1c2), _2n), t6),
839
+ }),
840
+ }; // 2 * (T6 + c1c2) + T6
841
+ }
842
+ // https://eprint.iacr.org/2009/565.pdf
843
+ _cyclotomicExp(num: Fp12, n: bigint): Fp12 {
844
+ let z = this.ONE;
845
+ for (let i = this.X_LEN - 1; i >= 0; i--) {
846
+ z = this._cyclotomicSquare(z);
847
+ if (bitGet(n, i)) z = this.mul(z, num);
848
+ }
849
+ return z;
850
+ }
851
+ }
617
852
 
618
- return { Fp, Fp2, Fp6, Fp12, Fp4Square };
853
+ export function tower12(opts: Tower12Opts): {
854
+ Fp: Readonly<mod.IField<bigint> & Required<Pick<mod.IField<bigint>, 'isOdd'>>>;
855
+ Fp2: Fp2Bls;
856
+ Fp6: Fp6Bls;
857
+ Fp12: Fp12Bls;
858
+ } {
859
+ const Fp = mod.Field(opts.ORDER);
860
+ const Fp2 = new _Field2(Fp, opts);
861
+ const Fp6 = new _Field6(Fp2);
862
+ const Fp12 = new _Field12(Fp6, opts);
863
+ return { Fp, Fp2, Fp6, Fp12 };
619
864
  }