1use core::fmt;
4use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
5use rand_core::RngCore;
6use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
7
8use crate::fp::Fp;
9
10#[derive(Copy, Clone)]
11pub struct Fp2 {
12 pub c0: Fp,
13 pub c1: Fp,
14}
15
16impl fmt::Debug for Fp2 {
17 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
18 write!(f, "{:?} + {:?}*u", self.c0, self.c1)
19 }
20}
21
22impl Default for Fp2 {
23 fn default() -> Self {
24 Fp2::zero()
25 }
26}
27
28#[cfg(feature = "zeroize")]
29impl zeroize::DefaultIsZeroes for Fp2 {}
30
31impl From<Fp> for Fp2 {
32 fn from(f: Fp) -> Fp2 {
33 Fp2 {
34 c0: f,
35 c1: Fp::zero(),
36 }
37 }
38}
39
40impl ConstantTimeEq for Fp2 {
41 fn ct_eq(&self, other: &Self) -> Choice {
42 self.c0.ct_eq(&other.c0) & self.c1.ct_eq(&other.c1)
43 }
44}
45
46impl Eq for Fp2 {}
47impl PartialEq for Fp2 {
48 #[inline]
49 fn eq(&self, other: &Self) -> bool {
50 bool::from(self.ct_eq(other))
51 }
52}
53
54impl ConditionallySelectable for Fp2 {
55 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
56 Fp2 {
57 c0: Fp::conditional_select(&a.c0, &b.c0, choice),
58 c1: Fp::conditional_select(&a.c1, &b.c1, choice),
59 }
60 }
61}
62
63impl<'a> Neg for &'a Fp2 {
64 type Output = Fp2;
65
66 #[inline]
67 fn neg(self) -> Fp2 {
68 self.neg()
69 }
70}
71
72impl Neg for Fp2 {
73 type Output = Fp2;
74
75 #[inline]
76 fn neg(self) -> Fp2 {
77 -&self
78 }
79}
80
81impl<'a, 'b> Sub<&'b Fp2> for &'a Fp2 {
82 type Output = Fp2;
83
84 #[inline]
85 fn sub(self, rhs: &'b Fp2) -> Fp2 {
86 self.sub(rhs)
87 }
88}
89
90impl<'a, 'b> Add<&'b Fp2> for &'a Fp2 {
91 type Output = Fp2;
92
93 #[inline]
94 fn add(self, rhs: &'b Fp2) -> Fp2 {
95 self.add(rhs)
96 }
97}
98
99impl<'a, 'b> Mul<&'b Fp2> for &'a Fp2 {
100 type Output = Fp2;
101
102 #[inline]
103 fn mul(self, rhs: &'b Fp2) -> Fp2 {
104 self.mul(rhs)
105 }
106}
107
108impl_binops_additive!(Fp2, Fp2);
109impl_binops_multiplicative!(Fp2, Fp2);
110
111impl Fp2 {
112 #[inline]
113 pub const fn zero() -> Fp2 {
114 Fp2 {
115 c0: Fp::zero(),
116 c1: Fp::zero(),
117 }
118 }
119
120 #[inline]
121 pub const fn one() -> Fp2 {
122 Fp2 {
123 c0: Fp::one(),
124 c1: Fp::zero(),
125 }
126 }
127
128 pub fn is_zero(&self) -> Choice {
129 self.c0.is_zero() & self.c1.is_zero()
130 }
131
132 pub(crate) fn random(mut rng: impl RngCore) -> Fp2 {
133 Fp2 {
134 c0: Fp::random(&mut rng),
135 c1: Fp::random(&mut rng),
136 }
137 }
138
139 #[inline(always)]
141 pub fn frobenius_map(&self) -> Self {
142 self.conjugate()
145 }
146
147 #[inline(always)]
148 pub fn conjugate(&self) -> Self {
149 Fp2 {
150 c0: self.c0,
151 c1: -self.c1,
152 }
153 }
154
155 #[inline(always)]
156 pub fn mul_by_nonresidue(&self) -> Fp2 {
157 Fp2 {
163 c0: self.c0 - self.c1,
164 c1: self.c0 + self.c1,
165 }
166 }
167
168 #[inline]
171 pub fn lexicographically_largest(&self) -> Choice {
172 self.c1.lexicographically_largest()
179 | (self.c1.is_zero() & self.c0.lexicographically_largest())
180 }
181
182 pub const fn square(&self) -> Fp2 {
183 let a = (&self.c0).add(&self.c1);
196 let b = (&self.c0).sub(&self.c1);
197 let c = (&self.c0).add(&self.c0);
198
199 Fp2 {
200 c0: (&a).mul(&b),
201 c1: (&c).mul(&self.c1),
202 }
203 }
204
205 pub fn mul(&self, rhs: &Fp2) -> Fp2 {
206 Fp2 {
219 c0: Fp::sum_of_products([self.c0, -self.c1], [rhs.c0, rhs.c1]),
220 c1: Fp::sum_of_products([self.c0, self.c1], [rhs.c1, rhs.c0]),
221 }
222 }
223
224 pub const fn add(&self, rhs: &Fp2) -> Fp2 {
225 Fp2 {
226 c0: (&self.c0).add(&rhs.c0),
227 c1: (&self.c1).add(&rhs.c1),
228 }
229 }
230
231 pub const fn sub(&self, rhs: &Fp2) -> Fp2 {
232 Fp2 {
233 c0: (&self.c0).sub(&rhs.c0),
234 c1: (&self.c1).sub(&rhs.c1),
235 }
236 }
237
238 pub const fn neg(&self) -> Fp2 {
239 Fp2 {
240 c0: (&self.c0).neg(),
241 c1: (&self.c1).neg(),
242 }
243 }
244
245 pub fn sqrt(&self) -> CtOption<Self> {
246 CtOption::new(Fp2::zero(), self.is_zero()).or_else(|| {
250 let a1 = self.pow_vartime(&[
252 0xee7f_bfff_ffff_eaaa,
253 0x07aa_ffff_ac54_ffff,
254 0xd9cc_34a8_3dac_3d89,
255 0xd91d_d2e1_3ce1_44af,
256 0x92c6_e9ed_90d2_eb35,
257 0x0680_447a_8e5f_f9a6,
258 ]);
259
260 let alpha = a1.square() * self;
262
263 let x0 = a1 * self;
265
266 CtOption::new(
271 Fp2 {
272 c0: -x0.c1,
273 c1: x0.c0,
274 },
275 alpha.ct_eq(&(&Fp2::one()).neg()),
276 )
277 .or_else(|| {
279 CtOption::new(
280 (alpha + Fp2::one()).pow_vartime(&[
281 0xdcff_7fff_ffff_d555,
282 0x0f55_ffff_58a9_ffff,
283 0xb398_6950_7b58_7b12,
284 0xb23b_a5c2_79c2_895f,
285 0x258d_d3db_21a5_d66b,
286 0x0d00_88f5_1cbf_f34d,
287 ]) * x0,
288 Choice::from(1),
289 )
290 })
291 .and_then(|sqrt| CtOption::new(sqrt, sqrt.square().ct_eq(self)))
294 })
295 }
296
297 pub fn invert(&self) -> CtOption<Self> {
301 (self.c0.square() + self.c1.square()).invert().map(|t| Fp2 {
316 c0: self.c0 * t,
317 c1: self.c1 * -t,
318 })
319 }
320
321 pub fn pow_vartime(&self, by: &[u64; 6]) -> Self {
325 let mut res = Self::one();
326 for e in by.iter().rev() {
327 for i in (0..64).rev() {
328 res = res.square();
329
330 if ((*e >> i) & 1) == 1 {
331 res *= self;
332 }
333 }
334 }
335 res
336 }
337
338 #[cfg(all(test, feature = "experimental"))]
341 pub(crate) fn pow_vartime_extended(&self, by: &[u64]) -> Self {
342 let mut res = Self::one();
343 for e in by.iter().rev() {
344 for i in (0..64).rev() {
345 res = res.square();
346
347 if ((*e >> i) & 1) == 1 {
348 res *= self;
349 }
350 }
351 }
352 res
353 }
354}
355
356#[test]
357fn test_conditional_selection() {
358 let a = Fp2 {
359 c0: Fp::from_raw_unchecked([1, 2, 3, 4, 5, 6]),
360 c1: Fp::from_raw_unchecked([7, 8, 9, 10, 11, 12]),
361 };
362 let b = Fp2 {
363 c0: Fp::from_raw_unchecked([13, 14, 15, 16, 17, 18]),
364 c1: Fp::from_raw_unchecked([19, 20, 21, 22, 23, 24]),
365 };
366
367 assert_eq!(
368 ConditionallySelectable::conditional_select(&a, &b, Choice::from(0u8)),
369 a
370 );
371 assert_eq!(
372 ConditionallySelectable::conditional_select(&a, &b, Choice::from(1u8)),
373 b
374 );
375}
376
377#[test]
378fn test_equality() {
379 fn is_equal(a: &Fp2, b: &Fp2) -> bool {
380 let eq = a == b;
381 let ct_eq = a.ct_eq(&b);
382
383 assert_eq!(eq, bool::from(ct_eq));
384
385 eq
386 }
387
388 assert!(is_equal(
389 &Fp2 {
390 c0: Fp::from_raw_unchecked([1, 2, 3, 4, 5, 6]),
391 c1: Fp::from_raw_unchecked([7, 8, 9, 10, 11, 12]),
392 },
393 &Fp2 {
394 c0: Fp::from_raw_unchecked([1, 2, 3, 4, 5, 6]),
395 c1: Fp::from_raw_unchecked([7, 8, 9, 10, 11, 12]),
396 }
397 ));
398
399 assert!(!is_equal(
400 &Fp2 {
401 c0: Fp::from_raw_unchecked([2, 2, 3, 4, 5, 6]),
402 c1: Fp::from_raw_unchecked([7, 8, 9, 10, 11, 12]),
403 },
404 &Fp2 {
405 c0: Fp::from_raw_unchecked([1, 2, 3, 4, 5, 6]),
406 c1: Fp::from_raw_unchecked([7, 8, 9, 10, 11, 12]),
407 }
408 ));
409
410 assert!(!is_equal(
411 &Fp2 {
412 c0: Fp::from_raw_unchecked([1, 2, 3, 4, 5, 6]),
413 c1: Fp::from_raw_unchecked([2, 8, 9, 10, 11, 12]),
414 },
415 &Fp2 {
416 c0: Fp::from_raw_unchecked([1, 2, 3, 4, 5, 6]),
417 c1: Fp::from_raw_unchecked([7, 8, 9, 10, 11, 12]),
418 }
419 ));
420}
421
422#[test]
423fn test_squaring() {
424 let a = Fp2 {
425 c0: Fp::from_raw_unchecked([
426 0xc9a2_1831_63ee_70d4,
427 0xbc37_70a7_196b_5c91,
428 0xa247_f8c1_304c_5f44,
429 0xb01f_c2a3_726c_80b5,
430 0xe1d2_93e5_bbd9_19c9,
431 0x04b7_8e80_020e_f2ca,
432 ]),
433 c1: Fp::from_raw_unchecked([
434 0x952e_a446_0462_618f,
435 0x238d_5edd_f025_c62f,
436 0xf6c9_4b01_2ea9_2e72,
437 0x03ce_24ea_c1c9_3808,
438 0x0559_50f9_45da_483c,
439 0x010a_768d_0df4_eabc,
440 ]),
441 };
442 let b = Fp2 {
443 c0: Fp::from_raw_unchecked([
444 0xa1e0_9175_a4d2_c1fe,
445 0x8b33_acfc_204e_ff12,
446 0xe244_15a1_1b45_6e42,
447 0x61d9_96b1_b6ee_1936,
448 0x1164_dbe8_667c_853c,
449 0x0788_557a_cc7d_9c79,
450 ]),
451 c1: Fp::from_raw_unchecked([
452 0xda6a_87cc_6f48_fa36,
453 0x0fc7_b488_277c_1903,
454 0x9445_ac4a_dc44_8187,
455 0x0261_6d5b_c909_9209,
456 0xdbed_4677_2db5_8d48,
457 0x11b9_4d50_76c7_b7b1,
458 ]),
459 };
460
461 assert_eq!(a.square(), b);
462}
463
464#[test]
465fn test_multiplication() {
466 let a = Fp2 {
467 c0: Fp::from_raw_unchecked([
468 0xc9a2_1831_63ee_70d4,
469 0xbc37_70a7_196b_5c91,
470 0xa247_f8c1_304c_5f44,
471 0xb01f_c2a3_726c_80b5,
472 0xe1d2_93e5_bbd9_19c9,
473 0x04b7_8e80_020e_f2ca,
474 ]),
475 c1: Fp::from_raw_unchecked([
476 0x952e_a446_0462_618f,
477 0x238d_5edd_f025_c62f,
478 0xf6c9_4b01_2ea9_2e72,
479 0x03ce_24ea_c1c9_3808,
480 0x0559_50f9_45da_483c,
481 0x010a_768d_0df4_eabc,
482 ]),
483 };
484 let b = Fp2 {
485 c0: Fp::from_raw_unchecked([
486 0xa1e0_9175_a4d2_c1fe,
487 0x8b33_acfc_204e_ff12,
488 0xe244_15a1_1b45_6e42,
489 0x61d9_96b1_b6ee_1936,
490 0x1164_dbe8_667c_853c,
491 0x0788_557a_cc7d_9c79,
492 ]),
493 c1: Fp::from_raw_unchecked([
494 0xda6a_87cc_6f48_fa36,
495 0x0fc7_b488_277c_1903,
496 0x9445_ac4a_dc44_8187,
497 0x0261_6d5b_c909_9209,
498 0xdbed_4677_2db5_8d48,
499 0x11b9_4d50_76c7_b7b1,
500 ]),
501 };
502 let c = Fp2 {
503 c0: Fp::from_raw_unchecked([
504 0xf597_483e_27b4_e0f7,
505 0x610f_badf_811d_ae5f,
506 0x8432_af91_7714_327a,
507 0x6a9a_9603_cf88_f09e,
508 0xf05a_7bf8_bad0_eb01,
509 0x0954_9131_c003_ffae,
510 ]),
511 c1: Fp::from_raw_unchecked([
512 0x963b_02d0_f93d_37cd,
513 0xc95c_e1cd_b30a_73d4,
514 0x3087_25fa_3126_f9b8,
515 0x56da_3c16_7fab_0d50,
516 0x6b50_86b5_f4b6_d6af,
517 0x09c3_9f06_2f18_e9f2,
518 ]),
519 };
520
521 assert_eq!(a * b, c);
522}
523
524#[test]
525fn test_addition() {
526 let a = Fp2 {
527 c0: Fp::from_raw_unchecked([
528 0xc9a2_1831_63ee_70d4,
529 0xbc37_70a7_196b_5c91,
530 0xa247_f8c1_304c_5f44,
531 0xb01f_c2a3_726c_80b5,
532 0xe1d2_93e5_bbd9_19c9,
533 0x04b7_8e80_020e_f2ca,
534 ]),
535 c1: Fp::from_raw_unchecked([
536 0x952e_a446_0462_618f,
537 0x238d_5edd_f025_c62f,
538 0xf6c9_4b01_2ea9_2e72,
539 0x03ce_24ea_c1c9_3808,
540 0x0559_50f9_45da_483c,
541 0x010a_768d_0df4_eabc,
542 ]),
543 };
544 let b = Fp2 {
545 c0: Fp::from_raw_unchecked([
546 0xa1e0_9175_a4d2_c1fe,
547 0x8b33_acfc_204e_ff12,
548 0xe244_15a1_1b45_6e42,
549 0x61d9_96b1_b6ee_1936,
550 0x1164_dbe8_667c_853c,
551 0x0788_557a_cc7d_9c79,
552 ]),
553 c1: Fp::from_raw_unchecked([
554 0xda6a_87cc_6f48_fa36,
555 0x0fc7_b488_277c_1903,
556 0x9445_ac4a_dc44_8187,
557 0x0261_6d5b_c909_9209,
558 0xdbed_4677_2db5_8d48,
559 0x11b9_4d50_76c7_b7b1,
560 ]),
561 };
562 let c = Fp2 {
563 c0: Fp::from_raw_unchecked([
564 0x6b82_a9a7_08c1_32d2,
565 0x476b_1da3_39ba_5ba4,
566 0x848c_0e62_4b91_cd87,
567 0x11f9_5955_295a_99ec,
568 0xf337_6fce_2255_9f06,
569 0x0c3f_e3fa_ce8c_8f43,
570 ]),
571 c1: Fp::from_raw_unchecked([
572 0x6f99_2c12_73ab_5bc5,
573 0x3355_1366_17a1_df33,
574 0x8b0e_f74c_0aed_aff9,
575 0x062f_9246_8ad2_ca12,
576 0xe146_9770_738f_d584,
577 0x12c3_c3dd_84bc_a26d,
578 ]),
579 };
580
581 assert_eq!(a + b, c);
582}
583
584#[test]
585fn test_subtraction() {
586 let a = Fp2 {
587 c0: Fp::from_raw_unchecked([
588 0xc9a2_1831_63ee_70d4,
589 0xbc37_70a7_196b_5c91,
590 0xa247_f8c1_304c_5f44,
591 0xb01f_c2a3_726c_80b5,
592 0xe1d2_93e5_bbd9_19c9,
593 0x04b7_8e80_020e_f2ca,
594 ]),
595 c1: Fp::from_raw_unchecked([
596 0x952e_a446_0462_618f,
597 0x238d_5edd_f025_c62f,
598 0xf6c9_4b01_2ea9_2e72,
599 0x03ce_24ea_c1c9_3808,
600 0x0559_50f9_45da_483c,
601 0x010a_768d_0df4_eabc,
602 ]),
603 };
604 let b = Fp2 {
605 c0: Fp::from_raw_unchecked([
606 0xa1e0_9175_a4d2_c1fe,
607 0x8b33_acfc_204e_ff12,
608 0xe244_15a1_1b45_6e42,
609 0x61d9_96b1_b6ee_1936,
610 0x1164_dbe8_667c_853c,
611 0x0788_557a_cc7d_9c79,
612 ]),
613 c1: Fp::from_raw_unchecked([
614 0xda6a_87cc_6f48_fa36,
615 0x0fc7_b488_277c_1903,
616 0x9445_ac4a_dc44_8187,
617 0x0261_6d5b_c909_9209,
618 0xdbed_4677_2db5_8d48,
619 0x11b9_4d50_76c7_b7b1,
620 ]),
621 };
622 let c = Fp2 {
623 c0: Fp::from_raw_unchecked([
624 0xe1c0_86bb_bf1b_5981,
625 0x4faf_c3a9_aa70_5d7e,
626 0x2734_b5c1_0bb7_e726,
627 0xb2bd_7776_af03_7a3e,
628 0x1b89_5fb3_98a8_4164,
629 0x1730_4aef_6f11_3cec,
630 ]),
631 c1: Fp::from_raw_unchecked([
632 0x74c3_1c79_9519_1204,
633 0x3271_aa54_79fd_ad2b,
634 0xc9b4_7157_4915_a30f,
635 0x65e4_0313_ec44_b8be,
636 0x7487_b238_5b70_67cb,
637 0x0952_3b26_d0ad_19a4,
638 ]),
639 };
640
641 assert_eq!(a - b, c);
642}
643
644#[test]
645fn test_negation() {
646 let a = Fp2 {
647 c0: Fp::from_raw_unchecked([
648 0xc9a2_1831_63ee_70d4,
649 0xbc37_70a7_196b_5c91,
650 0xa247_f8c1_304c_5f44,
651 0xb01f_c2a3_726c_80b5,
652 0xe1d2_93e5_bbd9_19c9,
653 0x04b7_8e80_020e_f2ca,
654 ]),
655 c1: Fp::from_raw_unchecked([
656 0x952e_a446_0462_618f,
657 0x238d_5edd_f025_c62f,
658 0xf6c9_4b01_2ea9_2e72,
659 0x03ce_24ea_c1c9_3808,
660 0x0559_50f9_45da_483c,
661 0x010a_768d_0df4_eabc,
662 ]),
663 };
664 let b = Fp2 {
665 c0: Fp::from_raw_unchecked([
666 0xf05c_e7ce_9c11_39d7,
667 0x6274_8f57_97e8_a36d,
668 0xc4e8_d9df_c664_96df,
669 0xb457_88e1_8118_9209,
670 0x6949_13d0_8772_930d,
671 0x1549_836a_3770_f3cf,
672 ]),
673 c1: Fp::from_raw_unchecked([
674 0x24d0_5bb9_fb9d_491c,
675 0xfb1e_a120_c12e_39d0,
676 0x7067_879f_c807_c7b1,
677 0x60a9_269a_31bb_dab6,
678 0x45c2_56bc_fd71_649b,
679 0x18f6_9b5d_2b8a_fbde,
680 ]),
681 };
682
683 assert_eq!(-a, b);
684}
685
686#[test]
687fn test_sqrt() {
688 let a = Fp2 {
690 c0: Fp::from_raw_unchecked([
691 0x2bee_d146_27d7_f9e9,
692 0xb661_4e06_660e_5dce,
693 0x06c4_cc7c_2f91_d42c,
694 0x996d_7847_4b7a_63cc,
695 0xebae_bc4c_820d_574e,
696 0x1886_5e12_d93f_d845,
697 ]),
698 c1: Fp::from_raw_unchecked([
699 0x7d82_8664_baf4_f566,
700 0xd17e_6639_96ec_7339,
701 0x679e_ad55_cb40_78d0,
702 0xfe3b_2260_e001_ec28,
703 0x3059_93d0_43d9_1b68,
704 0x0626_f03c_0489_b72d,
705 ]),
706 };
707
708 assert_eq!(a.sqrt().unwrap().square(), a);
709
710 let b = Fp2 {
713 c0: Fp::from_raw_unchecked([
714 0x6631_0000_0010_5545,
715 0x2114_0040_0eec_000d,
716 0x3fa7_af30_c820_e316,
717 0xc52a_8b8d_6387_695d,
718 0x9fb4_e61d_1e83_eac5,
719 0x005c_b922_afe8_4dc7,
720 ]),
721 c1: Fp::zero(),
722 };
723
724 assert_eq!(b.sqrt().unwrap().square(), b);
725
726 let c = Fp2 {
729 c0: Fp::from_raw_unchecked([
730 0x44f6_0000_0051_ffae,
731 0x86b8_0141_9948_0043,
732 0xd715_9952_f1f3_794a,
733 0x755d_6e3d_fe1f_fc12,
734 0xd36c_d6db_5547_e905,
735 0x02f8_c8ec_bf18_67bb,
736 ]),
737 c1: Fp::zero(),
738 };
739
740 assert_eq!(c.sqrt().unwrap().square(), c);
741
742 assert!(bool::from(
745 Fp2 {
746 c0: Fp::from_raw_unchecked([
747 0xc5fa_1bc8_fd00_d7f6,
748 0x3830_ca45_4606_003b,
749 0x2b28_7f11_04b1_02da,
750 0xa7fb_30f2_8230_f23e,
751 0x339c_db9e_e953_dbf0,
752 0x0d78_ec51_d989_fc57,
753 ]),
754 c1: Fp::from_raw_unchecked([
755 0x27ec_4898_cf87_f613,
756 0x9de1_394e_1abb_05a5,
757 0x0947_f85d_c170_fc14,
758 0x586f_bc69_6b61_14b7,
759 0x2b34_75a4_077d_7169,
760 0x13e1_c895_cc4b_6c22,
761 ])
762 }
763 .sqrt()
764 .is_none()
765 ));
766}
767
768#[test]
769fn test_inversion() {
770 let a = Fp2 {
771 c0: Fp::from_raw_unchecked([
772 0x1128_ecad_6754_9455,
773 0x9e7a_1cff_3a4e_a1a8,
774 0xeb20_8d51_e08b_cf27,
775 0xe98a_d408_11f5_fc2b,
776 0x736c_3a59_232d_511d,
777 0x10ac_d42d_29cf_cbb6,
778 ]),
779 c1: Fp::from_raw_unchecked([
780 0xd328_e37c_c2f5_8d41,
781 0x948d_f085_8a60_5869,
782 0x6032_f9d5_6f93_a573,
783 0x2be4_83ef_3fff_dc87,
784 0x30ef_61f8_8f48_3c2a,
785 0x1333_f55a_3572_5be0,
786 ]),
787 };
788
789 let b = Fp2 {
790 c0: Fp::from_raw_unchecked([
791 0x0581_a133_3d4f_48a6,
792 0x5824_2f6e_f074_8500,
793 0x0292_c955_349e_6da5,
794 0xba37_721d_dd95_fcd0,
795 0x70d1_6790_3aa5_dfc5,
796 0x1189_5e11_8b58_a9d5,
797 ]),
798 c1: Fp::from_raw_unchecked([
799 0x0eda_09d2_d7a8_5d17,
800 0x8808_e137_a7d1_a2cf,
801 0x43ae_2625_c1ff_21db,
802 0xf85a_c9fd_f7a7_4c64,
803 0x8fcc_dda5_b8da_9738,
804 0x08e8_4f0c_b32c_d17d,
805 ]),
806 };
807
808 assert_eq!(a.invert().unwrap(), b);
809
810 assert!(bool::from(Fp2::zero().invert().is_none()));
811}
812
813#[test]
814fn test_lexicographic_largest() {
815 assert!(!bool::from(Fp2::zero().lexicographically_largest()));
816 assert!(!bool::from(Fp2::one().lexicographically_largest()));
817 assert!(bool::from(
818 Fp2 {
819 c0: Fp::from_raw_unchecked([
820 0x1128_ecad_6754_9455,
821 0x9e7a_1cff_3a4e_a1a8,
822 0xeb20_8d51_e08b_cf27,
823 0xe98a_d408_11f5_fc2b,
824 0x736c_3a59_232d_511d,
825 0x10ac_d42d_29cf_cbb6,
826 ]),
827 c1: Fp::from_raw_unchecked([
828 0xd328_e37c_c2f5_8d41,
829 0x948d_f085_8a60_5869,
830 0x6032_f9d5_6f93_a573,
831 0x2be4_83ef_3fff_dc87,
832 0x30ef_61f8_8f48_3c2a,
833 0x1333_f55a_3572_5be0,
834 ]),
835 }
836 .lexicographically_largest()
837 ));
838 assert!(!bool::from(
839 Fp2 {
840 c0: -Fp::from_raw_unchecked([
841 0x1128_ecad_6754_9455,
842 0x9e7a_1cff_3a4e_a1a8,
843 0xeb20_8d51_e08b_cf27,
844 0xe98a_d408_11f5_fc2b,
845 0x736c_3a59_232d_511d,
846 0x10ac_d42d_29cf_cbb6,
847 ]),
848 c1: -Fp::from_raw_unchecked([
849 0xd328_e37c_c2f5_8d41,
850 0x948d_f085_8a60_5869,
851 0x6032_f9d5_6f93_a573,
852 0x2be4_83ef_3fff_dc87,
853 0x30ef_61f8_8f48_3c2a,
854 0x1333_f55a_3572_5be0,
855 ]),
856 }
857 .lexicographically_largest()
858 ));
859 assert!(!bool::from(
860 Fp2 {
861 c0: Fp::from_raw_unchecked([
862 0x1128_ecad_6754_9455,
863 0x9e7a_1cff_3a4e_a1a8,
864 0xeb20_8d51_e08b_cf27,
865 0xe98a_d408_11f5_fc2b,
866 0x736c_3a59_232d_511d,
867 0x10ac_d42d_29cf_cbb6,
868 ]),
869 c1: Fp::zero(),
870 }
871 .lexicographically_largest()
872 ));
873 assert!(bool::from(
874 Fp2 {
875 c0: -Fp::from_raw_unchecked([
876 0x1128_ecad_6754_9455,
877 0x9e7a_1cff_3a4e_a1a8,
878 0xeb20_8d51_e08b_cf27,
879 0xe98a_d408_11f5_fc2b,
880 0x736c_3a59_232d_511d,
881 0x10ac_d42d_29cf_cbb6,
882 ]),
883 c1: Fp::zero(),
884 }
885 .lexicographically_largest()
886 ));
887}
888
889#[cfg(feature = "zeroize")]
890#[test]
891fn test_zeroize() {
892 use zeroize::Zeroize;
893
894 let mut a = Fp2::one();
895 a.zeroize();
896 assert!(bool::from(a.is_zero()));
897}