1use super::fp::{Fp, MODULUS_STR};
2use crate::ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup};
3use crate::ff_ext::Legendre;
4use core::convert::TryInto;
5use core::ops::{Add, Mul, Neg, Sub};
6use rand::RngCore;
7use std::cmp::Ordering;
8use std::ops::MulAssign;
9use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
10
11#[cfg(feature = "derive_serde")]
12use serde::{Deserialize, Serialize};
13
14const U_SQUARE: Fp = Fp::from_raw([
20 0x9ffffcd2fffffffc,
21 0xa2a7e8c30006b945,
22 0xe4a7a5fe8fadffd6,
23 0x443f9a5cda8a6c7b,
24 0xa803ca76f439266f,
25 0x0130e0000d7f70e4,
26 0x2400000000002400,
27]);
28
29const NEG_ONE: Fp2 = Fp2 {
30 c0: super::fp::NEG_ONE,
31 c1: Fp::ZERO,
32};
33
34#[derive(Copy, Clone, Debug, Eq, PartialEq)]
36#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))]
37pub struct Fp2 {
38 pub c0: Fp,
39 pub c1: Fp,
40}
41
42impl Ord for Fp2 {
44 #[inline(always)]
45 fn cmp(&self, other: &Fp2) -> Ordering {
46 match self.c1.cmp(&other.c1) {
47 Ordering::Greater => Ordering::Greater,
48 Ordering::Less => Ordering::Less,
49 Ordering::Equal => self.c0.cmp(&other.c0),
50 }
51 }
52}
53
54impl PartialOrd for Fp2 {
55 #[inline(always)]
56 fn partial_cmp(&self, other: &Fp2) -> Option<Ordering> {
57 Some(self.cmp(other))
58 }
59}
60
61impl ConditionallySelectable for Fp2 {
62 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
63 Fp2 {
64 c0: Fp::conditional_select(&a.c0, &b.c0, choice),
65 c1: Fp::conditional_select(&a.c1, &b.c1, choice),
66 }
67 }
68}
69
70impl ConstantTimeEq for Fp2 {
71 fn ct_eq(&self, other: &Self) -> Choice {
72 self.c0.ct_eq(&other.c0) & self.c1.ct_eq(&other.c1)
73 }
74}
75
76impl Default for Fp2 {
77 #[inline]
78 fn default() -> Self {
79 Self::ZERO
80 }
81}
82
83impl From<Fp2> for [u8; 112] {
84 fn from(value: Fp2) -> [u8; 112] {
85 value.to_bytes()
86 }
87}
88
89impl<'a> From<&'a Fp2> for [u8; 112] {
90 fn from(value: &'a Fp2) -> [u8; 112] {
91 value.to_bytes()
92 }
93}
94
95impl Neg for Fp2 {
96 type Output = Fp2;
97
98 #[inline]
99 fn neg(self) -> Fp2 {
100 -&self
101 }
102}
103
104impl<'a> Neg for &'a Fp2 {
105 type Output = Fp2;
106
107 #[inline]
108 fn neg(self) -> Fp2 {
109 self.neg()
110 }
111}
112
113impl<'a, 'b> Sub<&'b Fp2> for &'a Fp2 {
114 type Output = Fp2;
115
116 #[inline]
117 fn sub(self, rhs: &'b Fp2) -> Fp2 {
118 self.sub(rhs)
119 }
120}
121
122impl<'a, 'b> Add<&'b Fp2> for &'a Fp2 {
123 type Output = Fp2;
124
125 #[inline]
126 fn add(self, rhs: &'b Fp2) -> Fp2 {
127 self.add(rhs)
128 }
129}
130
131impl<'a, 'b> Mul<&'b Fp2> for &'a Fp2 {
132 type Output = Fp2;
133
134 #[inline]
135 fn mul(self, rhs: &'b Fp2) -> Fp2 {
136 self.mul(rhs)
137 }
138}
139
140use crate::{
141 impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output,
142 impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output,
143 impl_sum_prod,
144};
145impl_binops_additive!(Fp2, Fp2);
146impl_binops_multiplicative!(Fp2, Fp2);
147impl_sum_prod!(Fp2);
148
149const SIZE: usize = 112;
151const COEF_SIZE: usize = 56;
153
154impl Fp2 {
155 #[inline]
157 pub const fn zero() -> Fp2 {
158 Fp2 {
159 c0: Fp::zero(),
160 c1: Fp::zero(),
161 }
162 }
163
164 #[inline]
166 pub const fn one() -> Fp2 {
167 Fp2 {
168 c0: Fp::one(),
169 c1: Fp::zero(),
170 }
171 }
172
173 pub const fn new(c0: Fp, c1: Fp) -> Self {
175 Fp2 { c0, c1 }
176 }
177
178 pub const fn size() -> usize {
180 SIZE
181 }
182
183 pub fn from_bytes(bytes: &[u8; SIZE]) -> CtOption<Fp2> {
186 let c0 = Fp::from_bytes(bytes[0..COEF_SIZE].try_into().unwrap());
187 let c1 = Fp::from_bytes(bytes[COEF_SIZE..SIZE].try_into().unwrap());
188 CtOption::new(
189 Fp2 {
190 c0: c0.unwrap(),
191 c1: c1.unwrap(),
192 },
193 c0.is_some() & c1.is_some(),
194 )
195 }
196
197 pub fn to_bytes(self) -> [u8; SIZE] {
200 let mut res = [0u8; SIZE];
201 let c0_bytes = self.c0.to_bytes();
202 let c1_bytes = self.c1.to_bytes();
203 res[0..COEF_SIZE].copy_from_slice(&c0_bytes[..]);
204 res[COEF_SIZE..SIZE].copy_from_slice(&c1_bytes[..]);
205 res
206 }
207
208 pub fn mul_assign(&mut self, other: &Self) {
210 let t0 = self.c0 * other.c0;
214 let t1 = self.c0 * other.c1;
215 let t2 = self.c1 * other.c0;
216 let t3 = self.c1 * other.c1;
217
218 self.c0 = t0 + U_SQUARE * t3;
219 self.c1 = t1 + t2
220 }
221
222 pub fn square_assign(&mut self) {
224 let ab = self.c0 * self.c1;
228 let a2 = self.c0 * self.c0;
229 let b2 = self.c1 * self.c1;
230
231 self.c1 = ab.double();
232 self.c0 = a2 + U_SQUARE * b2;
233 }
234
235 pub fn double(&self) -> Self {
236 Self {
237 c0: self.c0.double(),
238 c1: self.c1.double(),
239 }
240 }
241
242 pub fn double_assign(&mut self) {
243 self.c0 = self.c0.double();
244 self.c1 = self.c1.double();
245 }
246
247 pub fn add(&self, other: &Self) -> Self {
248 Self {
249 c0: self.c0.add(&other.c0),
250 c1: self.c1.add(&other.c1),
251 }
252 }
253
254 pub fn sub(&self, other: &Self) -> Self {
255 Self {
256 c0: self.c0.sub(&other.c0),
257 c1: self.c1.sub(&other.c1),
258 }
259 }
260
261 pub fn mul(&self, other: &Self) -> Self {
262 let mut t = *other;
263 t.mul_assign(self);
264 t
265 }
266
267 pub fn square(&self) -> Self {
268 let mut t = *self;
269 t.square_assign();
270 t
271 }
272
273 pub fn neg(&self) -> Self {
274 Self {
275 c0: self.c0.neg(),
276 c1: self.c1.neg(),
277 }
278 }
279
280 pub fn conjugate(&mut self) {
282 self.c1 = -self.c1;
283 }
284
285 pub fn frobenius_map(&mut self, power: usize) {
286 if power % 2 != 0 {
288 self.conjugate()
289 }
290 }
291
292 pub fn mul_by_nonresidue(&mut self) {
294 self.mul_assign(&super::fp6::V_CUBE)
296 }
297
298 pub fn invert(&self) -> CtOption<Self> {
299 let mut t1 = self.c1;
300 t1 = t1.square();
301 t1 *= U_SQUARE;
302 let mut t0 = self.c0;
303 t0 = t0.square();
304 t0 -= &t1;
306 t0.invert().map(|t| {
307 let mut tmp = Fp2 {
308 c0: self.c0,
309 c1: self.c1,
310 };
311 tmp.c0 *= &t;
312 tmp.c1 *= &t;
313 tmp.c1 = -tmp.c1;
314
315 tmp
316 })
317 }
318
319 fn norm(&self) -> Fp {
321 let t0 = self.c0.square();
323 let t1 = self.c1.square() * U_SQUARE;
324 t1 - t0
325 }
326}
327
328impl Legendre for Fp2 {
329 fn legendre(&self) -> i64 {
330 self.norm().legendre()
331 }
332}
333
334impl Field for Fp2 {
335 const ZERO: Self = Self::zero();
336 const ONE: Self = Self::one();
337
338 fn random(mut rng: impl RngCore) -> Self {
339 Fp2 {
340 c0: Fp::random(&mut rng),
341 c1: Fp::random(&mut rng),
342 }
343 }
344
345 fn is_zero(&self) -> Choice {
346 self.c0.is_zero() & self.c1.is_zero()
347 }
348
349 fn square(&self) -> Self {
350 self.square()
351 }
352
353 fn double(&self) -> Self {
354 self.double()
355 }
356
357 fn sqrt(&self) -> CtOption<Self> {
358 const E: Fp2 = Fp2 {
364 c0: Fp::ZERO,
365 c1: Fp::from_raw([
366 0x67153f9701e19938,
367 0x5d232408689b4c6c,
368 0x021848271d63f087,
369 0x03b21f15823a404a,
370 0x667c70cf991a36e6,
371 0x7a82a3d83bc9e63a,
372 0x13e275a1fa6a13af,
373 ]),
374 };
375
376 const F: Fp2 = Fp2 {
379 c0: Fp::from_raw([0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
380 c1: Fp::ZERO,
381 };
382
383 let b = self.pow_vartime([
385 0x67ffff34c0000000,
388 0xa8a9fa30c001ae51,
389 0xf929e97fa3eb7ff5,
390 0xd10fe69736a29b1e,
391 0x2a00f29dbd0e499b,
392 0x004c3800035fdc39,
393 0x0900000000000900,
394 ]);
395
396 let b_2 = b.square();
397 let mut b_2_q = b_2;
398 b_2_q.frobenius_map(1);
399
400 let a0 = b_2_q * b_2;
401 if a0 == NEG_ONE {
402 CtOption::new(a0, Choice::from(0))
403 } else {
404 let mut x = b;
405 x.frobenius_map(1);
406 if x * b == Fp2::ONE {
407 let x0 = (b_2 * self).c0.sqrt().unwrap();
408 x.c0.mul_assign(x0);
409 x.c1.mul_assign(x0);
410 CtOption::new(x, Choice::from(1))
411 } else {
412 let x0 = (self * b_2 * F).sqrt().unwrap();
413 x *= x0 * E;
414 CtOption::new(x, Choice::from(1))
415 }
416 }
417 }
418
419 fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
420 ff::helpers::sqrt_ratio_generic(num, div)
421 }
422
423 fn invert(&self) -> CtOption<Self> {
424 self.invert()
425 }
426}
427
428impl From<bool> for Fp2 {
429 fn from(bit: bool) -> Fp2 {
430 if bit {
431 Fp2::ONE
432 } else {
433 Fp2::ZERO
434 }
435 }
436}
437
438impl From<u64> for Fp2 {
439 fn from(val: u64) -> Self {
440 Fp2 {
441 c0: Fp::from(val),
442 c1: Fp::zero(),
443 }
444 }
445}
446
447impl PrimeField for Fp2 {
449 type Repr = Fp2Bytes;
450
451 const MODULUS: &'static str = MODULUS_STR;
452 const MULTIPLICATIVE_GENERATOR: Self = Fp2 {
453 c0: Fp::MULTIPLICATIVE_GENERATOR,
454 c1: Fp::ZERO,
455 };
456 const NUM_BITS: u32 = 446;
457 const CAPACITY: u32 = 445;
458 const S: u32 = 0;
459
460 const ROOT_OF_UNITY: Self = Fp2::zero();
462 const ROOT_OF_UNITY_INV: Self = Fp2 {
463 c0: Fp::zero(),
464 c1: Fp::zero(),
465 };
466 const DELTA: Self = Fp2 {
467 c0: Fp::zero(),
468 c1: Fp::zero(),
469 };
470 const TWO_INV: Self = Fp2 {
471 c0: Fp::TWO_INV,
472 c1: Fp::zero(),
473 };
474
475 fn from_repr(repr: Self::Repr) -> CtOption<Self> {
476 let c0 = Fp::from_bytes(&repr.0[..COEF_SIZE].try_into().unwrap());
477 let c1 = Fp::from_bytes(&repr.0[COEF_SIZE..].try_into().unwrap());
478 CtOption::new(Fp2::new(c0.unwrap(), c1.unwrap()), Choice::from(1))
480 }
481
482 fn to_repr(&self) -> Self::Repr {
483 Fp2Bytes(self.to_bytes())
484 }
485
486 fn is_odd(&self) -> Choice {
487 Choice::from(self.to_repr().as_ref()[0] & 1)
488 }
489}
490
491impl FromUniformBytes<64> for Fp2 {
492 fn from_uniform_bytes(bytes: &[u8; 64]) -> Self {
493 Self::new(Fp::from_uniform_bytes(bytes), Fp::zero())
494 }
495}
496#[derive(Clone, Copy, Debug)]
497pub struct Fp2Bytes([u8; SIZE]);
500
501impl Default for Fp2Bytes {
502 fn default() -> Self {
503 Self([0u8; SIZE])
504 }
505}
506
507impl AsMut<[u8]> for Fp2Bytes {
508 fn as_mut(&mut self) -> &mut [u8] {
509 &mut self.0
510 }
511}
512
513impl AsRef<[u8]> for Fp2Bytes {
514 fn as_ref(&self) -> &[u8] {
515 &self.0
516 }
517}
518
519impl crate::serde::SerdeObject for Fp2 {
520 fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self {
521 debug_assert_eq!(bytes.len(), 112);
522 let [c0, c1] = [0, 56].map(|i| Fp::from_raw_bytes_unchecked(&bytes[i..i + 56]));
523 Self { c0, c1 }
524 }
525 fn from_raw_bytes(bytes: &[u8]) -> Option<Self> {
526 if bytes.len() != SIZE {
527 return None;
528 }
529 let [c0, c1] = [0, COEF_SIZE].map(|i| Fp::from_raw_bytes(&bytes[i..i + COEF_SIZE]));
530 c0.zip(c1).map(|(c0, c1)| Self { c0, c1 })
531 }
532 fn to_raw_bytes(&self) -> Vec<u8> {
533 let mut res = Vec::with_capacity(SIZE);
534 for limb in self.c0.0.iter().chain(self.c1.0.iter()) {
535 res.extend_from_slice(&limb.to_le_bytes());
536 }
537 res
538 }
539 fn read_raw_unchecked<R: std::io::Read>(reader: &mut R) -> Self {
540 let [c0, c1] = [(); 2].map(|_| Fp::read_raw_unchecked(reader));
541 Self { c0, c1 }
542 }
543 fn read_raw<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
544 let c0 = Fp::read_raw(reader)?;
545 let c1 = Fp::read_raw(reader)?;
546 Ok(Self { c0, c1 })
547 }
548 fn write_raw<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
549 self.c0.write_raw(writer)?;
550 self.c1.write_raw(writer)
551 }
552}
553
554impl WithSmallOrderMulGroup<3> for Fp2 {
555 const ZETA: Self = Fp2 {
556 c0: Fp::from_raw([
558 0x8ffff80f80000002,
559 0xd9fa5d8a200bc439,
560 0x1b50d5e1ff708dc8,
561 0xf43f8cddf9a5c478,
562 0xa803ca76be3924a5,
563 0x0130e0000d7f28e4,
564 0x2400000000002400,
565 ]),
566 c1: Fp::zero(),
567 };
568}
569
570#[cfg(test)]
571use rand::SeedableRng;
572#[cfg(test)]
573use rand_xorshift::XorShiftRng;
574
575#[test]
576fn test_ser() {
577 let mut rng = XorShiftRng::from_seed([
578 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
579 0xe5,
580 ]);
581
582 let a0 = Fp2::random(&mut rng);
583 let a_bytes = a0.to_bytes();
584 let a1 = Fp2::from_bytes(&a_bytes).unwrap();
585 assert_eq!(a0, a1);
586}
587
588#[test]
589fn test_fp2_ordering() {
590 let mut a = Fp2 {
591 c0: Fp::zero(),
592 c1: Fp::zero(),
593 };
594
595 let mut b = a;
596
597 assert!(a.cmp(&b) == Ordering::Equal);
598 b.c0 += &Fp::one();
599 assert!(a.cmp(&b) == Ordering::Less);
600 a.c0 += &Fp::one();
601 assert!(a.cmp(&b) == Ordering::Equal);
602 b.c1 += &Fp::one();
603 assert!(a.cmp(&b) == Ordering::Less);
604 a.c0 += &Fp::one();
605 assert!(a.cmp(&b) == Ordering::Less);
606 a.c1 += &Fp::one();
607 assert!(a.cmp(&b) == Ordering::Greater);
608 b.c0 += &Fp::one();
609 assert!(a.cmp(&b) == Ordering::Equal);
610}
611
612#[test]
613fn test_fp2_basics() {
614 assert_eq!(
615 Fp2 {
616 c0: Fp::zero(),
617 c1: Fp::zero(),
618 },
619 Fp2::ZERO
620 );
621 assert_eq!(
622 Fp2 {
623 c0: Fp::one(),
624 c1: Fp::zero(),
625 },
626 Fp2::ONE
627 );
628 assert_eq!(Fp2::ZERO.is_zero().unwrap_u8(), 1);
629 assert_eq!(Fp2::ONE.is_zero().unwrap_u8(), 0);
630 assert_eq!(
631 Fp2 {
632 c0: Fp::zero(),
633 c1: Fp::one(),
634 }
635 .is_zero()
636 .unwrap_u8(),
637 0
638 );
639}
640
641#[test]
642fn test_fp2_squaring() {
643 let mut a = Fp2 {
645 c0: Fp::one(),
646 c1: Fp::one(),
647 };
648 a.square_assign();
650 let minus_4 = -Fp::from(4u64);
651 assert_eq!(
652 a,
653 Fp2 {
654 c0: minus_4,
655 c1: Fp::one() + Fp::one(),
656 }
657 );
658
659 let mut a = Fp2 {
661 c0: Fp::zero(),
662 c1: Fp::one(),
663 };
664 a.square_assign();
666 assert_eq!(
667 a,
668 Fp2 {
669 c0: U_SQUARE,
670 c1: Fp::zero(),
671 }
672 );
673}
674
675#[test]
676fn test_fp2_mul_nonresidue() {
677 let mut rng = XorShiftRng::from_seed([
678 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
679 0xe5,
680 ]);
681 let nqr = super::fp6::V_CUBE;
682 for _ in 0..1000 {
683 let mut a = Fp2::random(&mut rng);
684 let mut b = a;
685 a.mul_by_nonresidue();
686 b.mul_assign(&nqr);
687
688 assert_eq!(a, b);
689 }
690}
691
692#[test]
693pub fn test_sqrt() {
694 let mut rng = XorShiftRng::from_seed([
695 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
696 0xe5,
697 ]);
698 const N_ITER: usize = 1000;
699 for _ in 0..N_ITER {
700 let a = Fp2::random(&mut rng);
701 if a.legendre() == -1 {
702 assert!(bool::from(a.sqrt().is_none()));
703 }
704 }
705
706 for _ in 0..N_ITER {
707 let a = Fp2::random(&mut rng);
708 let mut b = a;
709 b.square_assign();
710 assert_eq!(b.legendre(), 1);
711
712 let b = b.sqrt().unwrap();
713 let mut negb = b;
714 negb = negb.neg();
715
716 assert!(a == b || a == negb);
717 }
718
719 let mut c = Fp2::ONE;
720 for _ in 0..N_ITER {
721 let mut b = c;
722 b.square_assign();
723 assert_eq!(b.legendre(), 1);
724
725 b = b.sqrt().unwrap();
726
727 if b != c {
728 b = b.neg();
729 }
730
731 assert_eq!(b, c);
732
733 c += &Fp2::ONE;
734 }
735}
736
737#[test]
738fn test_frobenius() {
739 let mut rng = XorShiftRng::from_seed([
740 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
741 0xe5,
742 ]);
743
744 for _ in 0..50 {
745 for i in 0..8 {
746 let mut a = Fp2::random(&mut rng);
747 let mut b = a;
748
749 for _ in 0..i {
750 a = a.pow_vartime([
751 0x9ffffcd300000001,
752 0xa2a7e8c30006b945,
753 0xe4a7a5fe8fadffd6,
754 0x443f9a5cda8a6c7b,
755 0xa803ca76f439266f,
756 0x0130e0000d7f70e4,
757 0x2400000000002400,
758 ]);
759 }
760 b.frobenius_map(i);
761
762 assert_eq!(a, b);
763 }
764 }
765}
766
767#[test]
768fn test_field() {
769 crate::tests::field::random_field_tests::<Fp2>("fp2".to_string());
770}
771
772#[test]
773fn test_serialization() {
774 crate::tests::field::random_serialization_test::<Fp2>("fp2".to_string());
775 #[cfg(feature = "derive_serde")]
776 crate::tests::field::random_serde_test::<Fp2>("fp2".to_string());
777}