1use core::{
2 cmp,
3 fmt::Debug,
4 iter::Sum,
5 ops::{Add, Mul, Neg, Sub},
6};
7
8use rand::RngCore;
9use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
10
11use crate::{
12 bls12381::{fq::Fq, fq2::Fq2, fr::Fr},
13 ff::{Field, PrimeField, WithSmallOrderMulGroup},
14 ff_ext::ExtField,
15 group::{cofactor::CofactorGroup, prime::PrimeCurveAffine, Curve, Group, GroupEncoding},
16 impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative,
17 impl_binops_multiplicative_mixed, new_curve_impl,
18 serde::{Compressed, CompressedFlagConfig},
19 Coordinates, CurveAffine, CurveExt,
20};
21
22const G2_GENERATOR_X: Fq2 = Fq2 {
23 c0: Fq([
24 0xf5f2_8fa2_0294_0a10,
25 0xb3f5_fb26_87b4_961a,
26 0xa1a8_93b5_3e2a_e580,
27 0x9894_999d_1a3c_aee9,
28 0x6f67_b763_1863_366b,
29 0x0581_9192_4350_bcd7,
30 ]),
31 c1: Fq([
32 0xa5a9_c075_9e23_f606,
33 0xaaa0_c59d_bccd_60c3,
34 0x3bb1_7e18_e286_7806,
35 0x1b1a_b6cc_8541_b367,
36 0xc2b6_ed0e_f215_8547,
37 0x1192_2a09_7360_edf3,
38 ]),
39};
40
41const G2_GENERATOR_Y: Fq2 = Fq2 {
42 c0: Fq([
43 0x4c73_0af8_6049_4c4a,
44 0x597c_fa1f_5e36_9c5a,
45 0xe7e6_856c_aa0a_635a,
46 0xbbef_b5e9_6e0d_495f,
47 0x07d3_a975_f0ef_25a2,
48 0x0083_fd8e_7e80_dae5,
49 ]),
50 c1: Fq([
51 0xadc0_fc92_df64_b05d,
52 0x18aa_270a_2b14_61dc,
53 0x86ad_ac6a_3be4_eba0,
54 0x7949_5c4e_c93d_a33a,
55 0xe717_5850_a43c_caed,
56 0x0b2b_c2a1_63de_1bf2,
57 ]),
58};
59
60const G2_B: Fq2 = Fq2 {
61 c0: Fq::from_raw([4, 0, 0, 0, 0, 0]),
62 c1: Fq::from_raw([4, 0, 0, 0, 0, 0]),
63};
64
65const G2_A: Fq2 = Fq2::ZERO;
66
67new_curve_impl!(
68 (pub),
69 G2,
70 G2Affine,
71 Fq2,
72 Fr,
73 (G2_GENERATOR_X, G2_GENERATOR_Y),
74 G2_A,
75 G2_B,
76 "bls12381_g2",
77 |domain_prefix| hash_to_curve(domain_prefix, hash_to_curve_suite(b"BLS12381G2_XMD:SHA-256_SSWU_RO_")),
78 crate::serde::CompressedFlagConfig::ThreeSpare
79
80);
81
82impl crate::serde::endian::EndianRepr for Fq2 {
83 const ENDIAN: crate::serde::endian::Endian = Fq::ENDIAN;
84
85 fn to_bytes(&self) -> Vec<u8> {
86 self.to_bytes().to_vec()
87 }
88
89 fn from_bytes(bytes: &[u8]) -> subtle::CtOption<Self> {
90 Fq2::from_bytes(bytes[..Fq2::SIZE].try_into().unwrap())
91 }
92}
93
94impl Compressed<G2Affine> for G2Compressed {
95 const CONFIG: CompressedFlagConfig = CompressedFlagConfig::ThreeSpare;
96 fn sign(c: &G2Affine) -> Choice {
97 c.y.lexicographically_largest() & !c.is_identity()
98 }
99 fn resolve(x: Fq2, sign_set: Choice) -> CtOption<G2Affine> {
100 G2Affine::y2(x).sqrt().map(|y| {
101 let y = Fq2::conditional_select(&y, &-y, sign_set ^ y.lexicographically_largest());
102 G2Affine { x, y }
103 })
104 }
105}
106
107impl group::cofactor::CofactorGroup for G2 {
108 type Subgroup = G2;
109
110 fn clear_cofactor(&self) -> G2 {
115 let t1 = self.mul_by_x(); let t2 = self.psi(); self.double().psi2() + (t1 + t2).mul_by_x() - t1 - t2 - self }
124
125 fn into_subgroup(self) -> CtOption<Self::Subgroup> {
126 CtOption::new(self, 1.into())
127 }
128
129 fn is_torsion_free(&self) -> Choice {
133 self.psi().ct_eq(&self.mul_by_x())
138 }
139}
140
141impl G2 {
142 fn mul_by_x(&self) -> G2 {
145 let mut acc = G2::identity();
146 for (i, b) in super::BLS_X.into_iter().enumerate() {
147 (i != 0).then(|| acc = acc.double());
148 (b == 1).then(|| acc += self);
149 }
150 acc.neg()
151 }
152
153 fn psi(&self) -> G2 {
154 let psi_coeff_x = Fq2 {
156 c0: Fq::zero(),
157 c1: Fq([
158 0x890dc9e4867545c3,
159 0x2af322533285a5d5,
160 0x50880866309b7e2c,
161 0xa20d1b8c7e881024,
162 0x14e4f04fe2db9068,
163 0x14e56d3f1564853a,
164 ]),
165 };
166 let psi_coeff_y = Fq2 {
168 c0: Fq([
169 0x3e2f585da55c9ad1,
170 0x4294213d86c18183,
171 0x382844c88b623732,
172 0x92ad2afd19103e18,
173 0x1d794e4fac7cf0b9,
174 0x0bd592fc7d825ec8,
175 ]),
176 c1: Fq([
177 0x7bcfa7a25aa30fda,
178 0xdc17dec12a927e7c,
179 0x2f088dd86b4ebef1,
180 0xd1ca2087da74d4a7,
181 0x2da2596696cebc1d,
182 0x0e2b7eedbbfd87d2,
183 ]),
184 };
185
186 let mut x = self.x;
188 x.frobenius_map(1);
189 x.mul_assign(&psi_coeff_x);
190
191 let mut y = self.y;
193 y.frobenius_map(1);
194 y.mul_assign(&psi_coeff_y);
195
196 let mut z = self.z;
198 z.frobenius_map(1);
199
200 G2 { x, y, z }
201 }
202
203 fn psi2(&self) -> G2 {
204 let psi2_coeff_x = Fq2 {
206 c0: Fq([
207 0xcd03c9e48671f071,
208 0x5dab22461fcda5d2,
209 0x587042afd3851b95,
210 0x8eb60ebe01bacb9e,
211 0x03f97d6e83d050d2,
212 0x18f0206554638741,
213 ]),
214 c1: Fq::zero(),
215 };
216
217 G2 {
218 x: self.x * psi2_coeff_x,
220 y: self.y.neg(),
222 z: self.z,
224 }
225 }
226}
227
228fn hash_to_curve_suite(domain: &[u8]) -> crate::hash_to_curve::Suite<G2, sha2::Sha256, 128> {
229 const SSWU_Z: Fq2 = Fq2 {
230 c0: Fq([
231 0x87eb_ffff_fff9_555c,
232 0x656f_ffe5_da8f_fffa,
233 0x0fd0_7493_45d3_3ad2,
234 0xd951_e663_0665_76f4,
235 0xde29_1a3d_41e9_80d3,
236 0x0815_664c_7dfe_040d,
237 ]),
238 c1: Fq([
239 0x43f5_ffff_fffc_aaae,
240 0x32b7_fff2_ed47_fffd,
241 0x07e8_3a49_a2e9_9d69,
242 0xeca8_f331_8332_bb7a,
243 0xef14_8d1e_a0f4_c069,
244 0x040a_b326_3eff_0206,
245 ]),
246 };
247
248 const ISO_A: Fq2 = Fq2 {
249 c0: Fq::zero(),
250 c1: Fq([
251 0xe53a_0000_0313_5242,
252 0x0108_0c0f_def8_0285,
253 0xe788_9edb_e340_f6bd,
254 0x0b51_3751_2631_0601,
255 0x02d6_9857_17c7_44ab,
256 0x1220_b4e9_79ea_5467,
257 ]),
258 };
259
260 const ISO_B: Fq2 = Fq2 {
261 c0: Fq([
262 0x22ea_0000_0cf8_9db2,
263 0x6ec8_32df_7138_0aa4,
264 0x6e1b_9440_3db5_a66e,
265 0x75bf_3c53_a794_73ba,
266 0x3dd3_a569_412c_0a34,
267 0x125c_db5e_74dc_4fd1,
268 ]),
269 c1: Fq([
270 0x22ea_0000_0cf8_9db2,
271 0x6ec8_32df_7138_0aa4,
272 0x6e1b_9440_3db5_a66e,
273 0x75bf_3c53_a794_73ba,
274 0x3dd3_a569_412c_0a34,
275 0x125c_db5e_74dc_4fd1,
276 ]),
277 };
278 let iso_map = crate::hash_to_curve::Iso {
279 a: ISO_A,
280 b: ISO_B,
281 map: Box::new(iso_map),
282 };
283
284 crate::hash_to_curve::Suite::new(domain, SSWU_Z, crate::hash_to_curve::Method::SSWU(iso_map))
285}
286
287fn iso_map(x: Fq2, y: Fq2, z: Fq2) -> G2 {
289 const COEFFS: [&[Fq2]; 4] = [&ISO3_XNUM, &ISO3_XDEN, &ISO3_YNUM, &ISO3_YDEN];
290
291 let mut mapvals = [Fq2::ZERO; 4];
293
294 let zsq = z.square();
296 let zpows = [z, zsq, zsq * z];
297
298 for idx in 0..4 {
300 let coeff = COEFFS[idx];
301 let clast = coeff.len() - 1;
302 mapvals[idx] = coeff[clast];
303 for jdx in 0..clast {
304 mapvals[idx] = mapvals[idx] * x + zpows[jdx] * coeff[clast - 1 - jdx];
305 }
306 }
307
308 mapvals[1] *= z;
311
312 mapvals[2] *= y;
314 mapvals[3] *= z;
315
316 G2 {
317 x: mapvals[0] * mapvals[3], y: mapvals[2] * mapvals[1], z: mapvals[1] * mapvals[3], }
321}
322
323#[allow(clippy::type_complexity)]
324pub(crate) fn hash_to_curve<'a>(
325 domain_prefix: &'a str,
326 suite: crate::hash_to_curve::Suite<G2, sha2::Sha256, 128>,
327) -> Box<dyn Fn(&[u8]) -> G2 + 'a> {
328 Box::new(move |message| suite.hash_to_curve(domain_prefix, message).clear_cofactor())
329}
330
331#[cfg(test)]
332mod test {
333 use group::UncompressedEncoding;
334 use rand_core::OsRng;
335
336 use super::*;
337 use crate::{arithmetic::CurveEndo, serde::SerdeObject};
338
339 crate::curve_testing_suite!(G2);
340 crate::curve_testing_suite!(G2, "endo_consistency");
341 crate::curve_testing_suite!(G2, "endo");
342
343 #[test]
344 fn test_cofactor() {
345 assert!(bool::from(
346 G2Affine::identity().to_curve().is_torsion_free()
347 ));
348 assert!(bool::from(
349 G2Affine::generator().to_curve().is_torsion_free()
350 ));
351 }
352
353 #[test]
354 fn test_hash_to_curve() {
355 pub(crate) fn point_from_hex(x0: &str, x1: &str, y0: &str, y1: &str) -> G2Affine {
356 let x0: Fq = crate::tests::hex_to_field(x0);
357 let x1: Fq = crate::tests::hex_to_field(x1);
358 let x = Fq2 { c0: x0, c1: x1 };
359 let y0: Fq = crate::tests::hex_to_field(y0);
360 let y1: Fq = crate::tests::hex_to_field(y1);
361 let y = Fq2 { c0: y0, c1: y1 };
362 G2Affine::from_xy(x, y).unwrap()
363 }
364
365 struct Test {
366 msg: &'static [u8],
367 expect: G2Affine,
368 }
369
370 impl Test {
371 fn new(msg: &'static [u8], expect: G2Affine) -> Self {
372 Self { msg, expect }
373 }
374
375 fn run(&self, domain_prefix: &str) {
376 let r0 = G2::hash_to_curve(domain_prefix)(self.msg);
377 assert_eq!(r0.to_affine(), self.expect);
378 }
379 }
380
381 let tests = [
382 Test::new(
383 b"",
384 point_from_hex(
385 "0141ebfbdca40eb85b87142e130ab689c673cf60f1a3e98d69335266f30d9b8d4ac44c1038e9dcdd5393faf5c41fb78a",
386 "05cb8437535e20ecffaef7752baddf98034139c38452458baeefab379ba13dff5bf5dd71b72418717047f5b0f37da03d",
387 "0503921d7f6a12805e72940b963c0cf3471c7b2a524950ca195d11062ee75ec076daf2d4bc358c4b190c0c98064fdd92",
388 "12424ac32561493f3fe3c260708a12b7c620e7be00099a974e259ddc7d1f6395c3c811cdd19f1e8dbf3e9ecfdcbab8d6",
389 ),
390 ),
391 Test::new(
392 b"abc",
393 point_from_hex(
394 "02c2d18e033b960562aae3cab37a27ce00d80ccd5ba4b7fe0e7a210245129dbec7780ccc7954725f4168aff2787776e6",
395 "139cddbccdc5e91b9623efd38c49f81a6f83f175e80b06fc374de9eb4b41dfe4ca3a230ed250fbe3a2acf73a41177fd8",
396 "1787327b68159716a37440985269cf584bcb1e621d3a7202be6ea05c4cfe244aeb197642555a0645fb87bf7466b2ba48",
397 "00aa65dae3c8d732d10ecd2c50f8a1baf3001578f71c694e03866e9f3d49ac1e1ce70dd94a733534f106d4cec0eddd16",
398 ),
399 ),
400 Test::new(
401 b"abcdef0123456789",
402 point_from_hex(
403 "121982811d2491fde9ba7ed31ef9ca474f0e1501297f68c298e9f4c0028add35aea8bb83d53c08cfc007c1e005723cd0",
404 "190d119345b94fbd15497bcba94ecf7db2cbfd1e1fe7da034d26cbba169fb3968288b3fafb265f9ebd380512a71c3f2c",
405 "05571a0f8d3c08d094576981f4a3b8eda0a8e771fcdcc8ecceaf1356a6acf17574518acb506e435b639353c2e14827c8",
406 "0bb5e7572275c567462d91807de765611490205a941a5a6af3b1691bfe596c31225d3aabdf15faff860cb4ef17c7c3be",
407 ),
408 ),
409 Test::new(
410 b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
411 point_from_hex(
412 "19a84dd7248a1066f737cc34502ee5555bd3c19f2ecdb3c7d9e24dc65d4e25e50d83f0f77105e955d78f4762d33c17da",
413 "0934aba516a52d8ae479939a91998299c76d39cc0c035cd18813bec433f587e2d7a4fef038260eef0cef4d02aae3eb91",
414 "14f81cd421617428bc3b9fe25afbb751d934a00493524bc4e065635b0555084dd54679df1536101b2c979c0152d09192",
415 "09bcccfa036b4847c9950780733633f13619994394c23ff0b32fa6b795844f4a0673e20282d07bc69641cee04f5e5662",
416 ),
417 ),
418 Test::new(
419 b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
420 point_from_hex(
421 "01a6ba2f9a11fa5598b2d8ace0fbe0a0eacb65deceb476fbbcb64fd24557c2f4b18ecfc5663e54ae16a84f5ab7f62534",
422 "11fca2ff525572795a801eed17eb12785887c7b63fb77a42be46ce4a34131d71f7a73e95fee3f812aea3de78b4d01569",
423 "0b6798718c8aed24bc19cb27f866f1c9effcdbf92397ad6448b5c9db90d2b9da6cbabf48adc1adf59a1a28344e79d57e",
424 "03a47f8e6d1763ba0cad63d6114c0accbef65707825a511b251a660a9b3994249ae4e63fac38b23da0c398689ee2ab52",
425 ),
426 ),
427 ];
428
429 tests.iter().for_each(|test| {
430 test.run("QUUX-V01-CS02-with-");
431 });
432 }
433}
434
435const ISO3_XNUM: [Fq2; 4] = [
437 Fq2 {
438 c0: Fq([
439 0x47f6_71c7_1ce0_5e62,
440 0x06dd_5707_1206_393e,
441 0x7c80_cd2a_f3fd_71a2,
442 0x0481_03ea_9e6c_d062,
443 0xc545_16ac_c8d0_37f6,
444 0x1380_8f55_0920_ea41,
445 ]),
446 c1: Fq([
447 0x47f6_71c7_1ce0_5e62,
448 0x06dd_5707_1206_393e,
449 0x7c80_cd2a_f3fd_71a2,
450 0x0481_03ea_9e6c_d062,
451 0xc545_16ac_c8d0_37f6,
452 0x1380_8f55_0920_ea41,
453 ]),
454 },
455 Fq2 {
456 c0: Fq::zero(),
457 c1: Fq([
458 0x5fe5_5555_554c_71d0,
459 0x873f_ffdd_236a_aaa3,
460 0x6a6b_4619_b26e_f918,
461 0x21c2_8884_0887_4945,
462 0x2836_cda7_028c_abc5,
463 0x0ac7_3310_a7fd_5abd,
464 ]),
465 },
466 Fq2 {
467 c0: Fq([
468 0x0a0c_5555_5559_71c3,
469 0xdb0c_0010_1f9e_aaae,
470 0xb1fb_2f94_1d79_7997,
471 0xd396_0742_ef41_6e1c,
472 0xb700_40e2_c205_56f4,
473 0x149d_7861_e581_393b,
474 ]),
475 c1: Fq([
476 0xaff2_aaaa_aaa6_38e8,
477 0x439f_ffee_91b5_5551,
478 0xb535_a30c_d937_7c8c,
479 0x90e1_4442_0443_a4a2,
480 0x941b_66d3_8146_55e2,
481 0x0563_9988_53fe_ad5e,
482 ]),
483 },
484 Fq2 {
485 c0: Fq([
486 0x40aa_c71c_71c7_25ed,
487 0x1909_5555_7a84_e38e,
488 0xd817_050a_8f41_abc3,
489 0xd864_85d4_c87f_6fb1,
490 0x696e_b479_f885_d059,
491 0x198e_1a74_3280_02d2,
492 ]),
493 c1: Fq::zero(),
494 },
495];
496
497const ISO3_XDEN: [Fq2; 3] = [
499 Fq2 {
500 c0: Fq::zero(),
501 c1: Fq([
502 0x1f3a_ffff_ff13_ab97,
503 0xf25b_fc61_1da3_ff3e,
504 0xca37_57cb_3819_b208,
505 0x3e64_2736_6f8c_ec18,
506 0x0397_7bc8_6095_b089,
507 0x04f6_9db1_3f39_a952,
508 ]),
509 },
510 Fq2 {
511 c0: Fq([
512 0x4476_0000_0027_552e,
513 0xdcb8_009a_4348_0020,
514 0x6f7e_e9ce_4a6e_8b59,
515 0xb103_30b7_c0a9_5bc6,
516 0x6140_b1fc_fb1e_54b7,
517 0x0381_be09_7f0b_b4e1,
518 ]),
519 c1: Fq([
520 0x7588_ffff_ffd8_557d,
521 0x41f3_ff64_6e0b_ffdf,
522 0xf7b1_e8d2_ac42_6aca,
523 0xb374_1acd_32db_b6f8,
524 0xe9da_f5b9_482d_581f,
525 0x167f_53e0_ba74_31b8,
526 ]),
527 },
528 Fq2::one(),
529];
530
531const ISO3_YNUM: [Fq2; 4] = [
533 Fq2 {
534 c0: Fq([
535 0x96d8_f684_bdfc_77be,
536 0xb530_e4f4_3b66_d0e2,
537 0x184a_88ff_3796_52fd,
538 0x57cb_23ec_fae8_04e1,
539 0x0fd2_e39e_ada3_eba9,
540 0x08c8_055e_31c5_d5c3,
541 ]),
542 c1: Fq([
543 0x96d8_f684_bdfc_77be,
544 0xb530_e4f4_3b66_d0e2,
545 0x184a_88ff_3796_52fd,
546 0x57cb_23ec_fae8_04e1,
547 0x0fd2_e39e_ada3_eba9,
548 0x08c8_055e_31c5_d5c3,
549 ]),
550 },
551 Fq2 {
552 c0: Fq::zero(),
553 c1: Fq([
554 0xbf0a_71c7_1c91_b406,
555 0x4d6d_55d2_8b76_38fd,
556 0x9d82_f98e_5f20_5aee,
557 0xa27a_a27b_1d1a_18d5,
558 0x02c3_b2b2_d293_8e86,
559 0x0c7d_1342_0b09_807f,
560 ]),
561 },
562 Fq2 {
563 c0: Fq([
564 0xd7f9_5555_5553_1c74,
565 0x21cf_fff7_48da_aaa8,
566 0x5a9a_d186_6c9b_be46,
567 0x4870_a221_0221_d251,
568 0x4a0d_b369_c0a3_2af1,
569 0x02b1_ccc4_29ff_56af,
570 ]),
571 c1: Fq([
572 0xe205_aaaa_aaac_8e37,
573 0xfcdc_0007_6879_5556,
574 0x0c96_011a_8a15_37dd,
575 0x1c06_a963_f163_406e,
576 0x010d_f44c_82a8_81e6,
577 0x174f_4526_0f80_8feb,
578 ]),
579 },
580 Fq2 {
581 c0: Fq([
582 0xa470_bda1_2f67_f35c,
583 0xc0fe_38e2_3327_b425,
584 0xc9d3_d0f2_c6f0_678d,
585 0x1c55_c993_5b5a_982e,
586 0x27f6_c0e2_f074_6764,
587 0x117c_5e6e_28aa_9054,
588 ]),
589 c1: Fq::zero(),
590 },
591];
592
593const ISO3_YDEN: [Fq2; 4] = [
595 Fq2 {
596 c0: Fq([
597 0x0162_ffff_fa76_5adf,
598 0x8f7b_ea48_0083_fb75,
599 0x561b_3c22_59e9_3611,
600 0x11e1_9fc1_a9c8_75d5,
601 0xca71_3efc_0036_7660,
602 0x03c6_a03d_41da_1151,
603 ]),
604 c1: Fq([
605 0x0162_ffff_fa76_5adf,
606 0x8f7b_ea48_0083_fb75,
607 0x561b_3c22_59e9_3611,
608 0x11e1_9fc1_a9c8_75d5,
609 0xca71_3efc_0036_7660,
610 0x03c6_a03d_41da_1151,
611 ]),
612 },
613 Fq2 {
614 c0: Fq::zero(),
615 c1: Fq([
616 0x5db0_ffff_fd3b_02c5,
617 0xd713_f523_58eb_fdba,
618 0x5ea6_0761_a84d_161a,
619 0xbb2c_75a3_4ea6_c44a,
620 0x0ac6_7359_21c1_119b,
621 0x0ee3_d913_bdac_fbf6,
622 ]),
623 },
624 Fq2 {
625 c0: Fq([
626 0x66b1_0000_003a_ffc5,
627 0xcb14_00e7_64ec_0030,
628 0xa73e_5eb5_6fa5_d106,
629 0x8984_c913_a0fe_09a9,
630 0x11e1_0afb_78ad_7f13,
631 0x0542_9d0e_3e91_8f52,
632 ]),
633 c1: Fq([
634 0x534d_ffff_ffc4_aae6,
635 0x5397_ff17_4c67_ffcf,
636 0xbff2_73eb_870b_251d,
637 0xdaf2_8271_5287_0915,
638 0x393a_9cba_ca9e_2dc3,
639 0x14be_74db_faee_5748,
640 ]),
641 },
642 Fq2::one(),
643];