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