halo2curves_axiom/bls12_381/
fp2.rs

1//! This module implements arithmetic over the quadratic extension field Fp2.
2//! Source: <https://github.com/privacy-scaling-explorations/bls12_381>
3
4#![allow(clippy::needless_borrow)]
5use core::fmt;
6use core::ops::{Add, Mul, Neg, Sub};
7use ff::{Field, WithSmallOrderMulGroup};
8use rand_core::RngCore;
9use std::cmp::Ordering;
10use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
11
12use crate::{
13    impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output,
14    impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output,
15};
16
17use super::fp::Fp;
18
19#[derive(Copy, Clone)]
20pub struct Fp2 {
21    pub c0: Fp,
22    pub c1: Fp,
23}
24
25impl fmt::Debug for Fp2 {
26    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
27        write!(f, "{:?} + {:?}*u", self.c0, self.c1)
28    }
29}
30
31impl Default for Fp2 {
32    fn default() -> Self {
33        Fp2::zero()
34    }
35}
36
37#[cfg(feature = "zeroize")]
38impl zeroize::DefaultIsZeroes for Fp2 {}
39
40impl From<Fp> for Fp2 {
41    fn from(f: Fp) -> Fp2 {
42        Fp2 {
43            c0: f,
44            c1: Fp::zero(),
45        }
46    }
47}
48
49impl ConstantTimeEq for Fp2 {
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 Eq for Fp2 {}
56impl PartialEq for Fp2 {
57    #[inline]
58    fn eq(&self, other: &Self) -> bool {
59        bool::from(self.ct_eq(other))
60    }
61}
62
63impl Ord for Fp2 {
64    #[inline(always)]
65    fn cmp(&self, other: &Fp2) -> Ordering {
66        match self.c1.cmp(&other.c1) {
67            Ordering::Greater => Ordering::Greater,
68            Ordering::Less => Ordering::Less,
69            Ordering::Equal => self.c0.cmp(&other.c0),
70        }
71    }
72}
73
74impl PartialOrd for Fp2 {
75    #[inline(always)]
76    fn partial_cmp(&self, other: &Fp2) -> Option<Ordering> {
77        Some(self.cmp(other))
78    }
79}
80
81impl ConditionallySelectable for Fp2 {
82    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
83        Fp2 {
84            c0: Fp::conditional_select(&a.c0, &b.c0, choice),
85            c1: Fp::conditional_select(&a.c1, &b.c1, choice),
86        }
87    }
88}
89
90impl<'a> Neg for &'a Fp2 {
91    type Output = Fp2;
92
93    #[inline]
94    fn neg(self) -> Fp2 {
95        self.neg()
96    }
97}
98
99impl Neg for Fp2 {
100    type Output = Fp2;
101
102    #[inline]
103    fn neg(self) -> Fp2 {
104        -&self
105    }
106}
107
108impl<'a, 'b> Sub<&'b Fp2> for &'a Fp2 {
109    type Output = Fp2;
110
111    #[inline]
112    fn sub(self, rhs: &'b Fp2) -> Fp2 {
113        self.sub(rhs)
114    }
115}
116
117impl<'a, 'b> Add<&'b Fp2> for &'a Fp2 {
118    type Output = Fp2;
119
120    #[inline]
121    fn add(self, rhs: &'b Fp2) -> Fp2 {
122        self.add(rhs)
123    }
124}
125
126impl<'a, 'b> Mul<&'b Fp2> for &'a Fp2 {
127    type Output = Fp2;
128
129    #[inline]
130    fn mul(self, rhs: &'b Fp2) -> Fp2 {
131        self.mul(rhs)
132    }
133}
134
135impl_binops_additive!(Fp2, Fp2);
136impl_binops_multiplicative!(Fp2, Fp2);
137
138impl Fp2 {
139    #[inline]
140    pub const fn zero() -> Fp2 {
141        Fp2 {
142            c0: Fp::zero(),
143            c1: Fp::zero(),
144        }
145    }
146
147    #[inline]
148    pub const fn one() -> Fp2 {
149        Fp2 {
150            c0: Fp::one(),
151            c1: Fp::zero(),
152        }
153    }
154
155    pub fn is_zero(&self) -> Choice {
156        self.c0.is_zero() & self.c1.is_zero()
157    }
158
159    pub(crate) fn random(mut rng: impl RngCore) -> Fp2 {
160        Fp2 {
161            c0: Fp::random(&mut rng),
162            c1: Fp::random(&mut rng),
163        }
164    }
165
166    pub fn double(&self) -> Self {
167        Self {
168            c0: self.c0.double(),
169            c1: self.c1.double(),
170        }
171    }
172
173    /// Raises this element to p.
174    #[inline(always)]
175    pub fn frobenius_map(&self) -> Self {
176        // This is always just a conjugation. If you're curious why, here's
177        // an article about it: https://alicebob.cryptoland.net/the-frobenius-endomorphism-with-finite-fields/
178        self.conjugate()
179    }
180
181    #[inline(always)]
182    pub fn conjugate(&self) -> Self {
183        Fp2 {
184            c0: self.c0,
185            c1: -self.c1,
186        }
187    }
188
189    #[inline(always)]
190    pub fn mul_by_nonresidue(&self) -> Fp2 {
191        // Multiply a + bu by u + 1, getting
192        // au + a + bu^2 + bu
193        // and because u^2 = -1, we get
194        // (a - b) + (a + b)u
195
196        Fp2 {
197            c0: self.c0 - self.c1,
198            c1: self.c0 + self.c1,
199        }
200    }
201
202    /// Returns whether or not this element is strictly lexicographically
203    /// larger than its negation.
204    #[inline]
205    pub fn lexicographically_largest(&self) -> Choice {
206        // If this element's c1 coefficient is lexicographically largest
207        // then it is lexicographically largest. Otherwise, in the event
208        // the c1 coefficient is zero and the c0 coefficient is
209        // lexicographically largest, then this element is lexicographically
210        // largest.
211
212        self.c1.lexicographically_largest()
213            | (self.c1.is_zero() & self.c0.lexicographically_largest())
214    }
215
216    pub const fn square(&self) -> Fp2 {
217        // Complex squaring:
218        //
219        // v0  = c0 * c1
220        // c0' = (c0 + c1) * (c0 + \beta*c1) - v0 - \beta * v0
221        // c1' = 2 * v0
222        //
223        // In BLS12-381's F_{p^2}, our \beta is -1 so we
224        // can modify this formula:
225        //
226        // c0' = (c0 + c1) * (c0 - c1)
227        // c1' = 2 * c0 * c1
228
229        let a = (&self.c0).add(&self.c1);
230        let b = (&self.c0).sub(&self.c1);
231        let c = (&self.c0).add(&self.c0);
232
233        Fp2 {
234            c0: (&a).mul(&b),
235            c1: (&c).mul(&self.c1),
236        }
237    }
238
239    pub fn mul(&self, rhs: &Fp2) -> Fp2 {
240        // F_{p^2} x F_{p^2} multiplication implemented with operand scanning (schoolbook)
241        // computes the result as:
242        //
243        //   a·b = (a_0 b_0 + a_1 b_1 β) + (a_0 b_1 + a_1 b_0)i
244        //
245        // In BLS12-381's F_{p^2}, our β is -1, so the resulting F_{p^2} element is:
246        //
247        //   c_0 = a_0 b_0 - a_1 b_1
248        //   c_1 = a_0 b_1 + a_1 b_0
249        //
250        // Each of these is a "sum of products", which we can compute efficiently.
251
252        Fp2 {
253            c0: Fp::sum_of_products([self.c0, -self.c1], [rhs.c0, rhs.c1]),
254            c1: Fp::sum_of_products([self.c0, self.c1], [rhs.c1, rhs.c0]),
255        }
256    }
257
258    pub const fn add(&self, rhs: &Fp2) -> Fp2 {
259        Fp2 {
260            c0: (&self.c0).add(&rhs.c0),
261            c1: (&self.c1).add(&rhs.c1),
262        }
263    }
264
265    pub const fn sub(&self, rhs: &Fp2) -> Fp2 {
266        Fp2 {
267            c0: (&self.c0).sub(&rhs.c0),
268            c1: (&self.c1).sub(&rhs.c1),
269        }
270    }
271
272    pub const fn neg(&self) -> Fp2 {
273        Fp2 {
274            c0: (&self.c0).neg(),
275            c1: (&self.c1).neg(),
276        }
277    }
278
279    pub fn sqrt(&self) -> CtOption<Self> {
280        // Algorithm 9, https://eprint.iacr.org/2012/685.pdf
281        // with constant time modifications.
282
283        CtOption::new(Fp2::zero(), self.is_zero()).or_else(|| {
284            // a1 = self^((p - 3) / 4)
285            let a1 = self.pow_vartime(&[
286                0xee7f_bfff_ffff_eaaa,
287                0x07aa_ffff_ac54_ffff,
288                0xd9cc_34a8_3dac_3d89,
289                0xd91d_d2e1_3ce1_44af,
290                0x92c6_e9ed_90d2_eb35,
291                0x0680_447a_8e5f_f9a6,
292            ]);
293
294            // alpha = a1^2 * self = self^((p - 3) / 2 + 1) = self^((p - 1) / 2)
295            let alpha = a1.square() * self;
296
297            // x0 = self^((p + 1) / 4)
298            let x0 = a1 * self;
299
300            // In the event that alpha = -1, the element is order p - 1 and so
301            // we're just trying to get the square of an element of the subfield
302            // Fp. This is given by x0 * u, since u = sqrt(-1). Since the element
303            // x0 = a + bu has b = 0, the solution is therefore au.
304            CtOption::new(
305                Fp2 {
306                    c0: -x0.c1,
307                    c1: x0.c0,
308                },
309                alpha.ct_eq(&(&Fp2::one()).neg()),
310            )
311            // Otherwise, the correct solution is (1 + alpha)^((q - 1) // 2) * x0
312            .or_else(|| {
313                CtOption::new(
314                    (alpha + Fp2::one()).pow_vartime(&[
315                        0xdcff_7fff_ffff_d555,
316                        0x0f55_ffff_58a9_ffff,
317                        0xb398_6950_7b58_7b12,
318                        0xb23b_a5c2_79c2_895f,
319                        0x258d_d3db_21a5_d66b,
320                        0x0d00_88f5_1cbf_f34d,
321                    ]) * x0,
322                    Choice::from(1),
323                )
324            })
325            // Only return the result if it's really the square root (and so
326            // self is actually quadratic nonresidue)
327            .and_then(|sqrt| CtOption::new(sqrt, sqrt.square().ct_eq(self)))
328        })
329    }
330
331    /// Computes the multiplicative inverse of this field
332    /// element, returning None in the case that this element
333    /// is zero.
334    pub fn invert(&self) -> CtOption<Self> {
335        // We wish to find the multiplicative inverse of a nonzero
336        // element a + bu in Fp2. We leverage an identity
337        //
338        // (a + bu)(a - bu) = a^2 + b^2
339        //
340        // which holds because u^2 = -1. This can be rewritten as
341        //
342        // (a + bu)(a - bu)/(a^2 + b^2) = 1
343        //
344        // because a^2 + b^2 = 0 has no nonzero solutions for (a, b).
345        // This gives that (a - bu)/(a^2 + b^2) is the inverse
346        // of (a + bu). Importantly, this can be computing using
347        // only a single inversion in Fp.
348
349        (self.c0.square() + self.c1.square()).invert().map(|t| Fp2 {
350            c0: self.c0 * t,
351            c1: self.c1 * -t,
352        })
353    }
354
355    /// Although this is labeled "vartime", it is only
356    /// variable time with respect to the exponent. It
357    /// is also not exposed in the public API.
358    pub fn pow_vartime(&self, by: &[u64]) -> Self {
359        let mut res = Self::one();
360        for e in by.iter().rev() {
361            for i in (0..64).rev() {
362                res = res.square();
363
364                if ((*e >> i) & 1) == 1 {
365                    res *= self;
366                }
367            }
368        }
369        res
370    }
371
372    /// Vartime exponentiation for larger exponents, only
373    /// used in testing and not exposed through the public API.
374    pub fn pow_vartime_extended(&self, by: &[u64]) -> Self {
375        let mut res = Self::one();
376        for e in by.iter().rev() {
377            for i in (0..64).rev() {
378                res = res.square();
379
380                if ((*e >> i) & 1) == 1 {
381                    res *= self;
382                }
383            }
384        }
385        res
386    }
387
388    /// Attempts to convert a little-endian byte representation of
389    /// a scalar into a `Fp2`, failing if the input is not canonical.
390    pub fn from_bytes(bytes: &[u8; 96]) -> CtOption<Fp2> {
391        let c0 = Fp::from_bytes(bytes[0..48].try_into().unwrap());
392        let c1 = Fp::from_bytes(bytes[48..96].try_into().unwrap());
393        CtOption::new(
394            Fp2 {
395                c0: c0.unwrap(),
396                c1: c1.unwrap(),
397            },
398            c0.is_some() & c1.is_some(),
399        )
400    }
401
402    pub fn to_bytes(&self) -> [u8; 96] {
403        let mut res = [0u8; 96];
404        let c0_bytes = self.c0.to_bytes();
405        let c1_bytes = self.c1.to_bytes();
406        res[0..48].copy_from_slice(&c0_bytes[..]);
407        res[48..96].copy_from_slice(&c1_bytes[..]);
408        res
409    }
410}
411
412crate::impl_sum_prod!(Fp2);
413
414impl ff::Field for Fp2 {
415    const ZERO: Self = Self::zero();
416    const ONE: Self = Self::one();
417
418    fn random(mut rng: impl RngCore) -> Self {
419        Fp2 {
420            c0: Fp::random(&mut rng),
421            c1: Fp::random(&mut rng),
422        }
423    }
424
425    fn is_zero(&self) -> Choice {
426        self.c0.is_zero() & self.c1.is_zero()
427    }
428
429    fn square(&self) -> Self {
430        self.square()
431    }
432
433    fn double(&self) -> Self {
434        self.double()
435    }
436
437    fn sqrt(&self) -> CtOption<Self> {
438        // Algorithm 9, https://eprint.iacr.org/2012/685.pdf
439        // with constant time modifications.
440
441        CtOption::new(Fp2::zero(), self.is_zero()).or_else(|| {
442            // a1 = self^((p - 3) / 4)
443            let a1 = self.pow_vartime(&[
444                0xee7f_bfff_ffff_eaaa,
445                0x07aa_ffff_ac54_ffff,
446                0xd9cc_34a8_3dac_3d89,
447                0xd91d_d2e1_3ce1_44af,
448                0x92c6_e9ed_90d2_eb35,
449                0x0680_447a_8e5f_f9a6,
450            ]);
451
452            // alpha = a1^2 * self = self^((p - 3) / 2 + 1) = self^((p - 1) / 2)
453            let alpha = a1.square() * self;
454
455            // x0 = self^((p + 1) / 4)
456            let x0 = a1 * self;
457
458            // In the event that alpha = -1, the element is order p - 1 and so
459            // we're just trying to get the square of an element of the subfield
460            // Fp. This is given by x0 * u, since u = sqrt(-1). Since the element
461            // x0 = a + bu has b = 0, the solution is therefore au.
462            CtOption::new(
463                Fp2 {
464                    c0: -x0.c1,
465                    c1: x0.c0,
466                },
467                alpha.ct_eq(&(Fp2::one()).neg()),
468            )
469            // Otherwise, the correct solution is (1 + alpha)^((q - 1) // 2) * x0
470            .or_else(|| {
471                CtOption::new(
472                    (alpha + Fp2::one()).pow_vartime(&[
473                        0xdcff_7fff_ffff_d555,
474                        0x0f55_ffff_58a9_ffff,
475                        0xb398_6950_7b58_7b12,
476                        0xb23b_a5c2_79c2_895f,
477                        0x258d_d3db_21a5_d66b,
478                        0x0d00_88f5_1cbf_f34d,
479                    ]) * x0,
480                    Choice::from(1),
481                )
482            })
483            // Only return the result if it's really the square root (and so
484            // self is actually quadratic nonresidue)
485            .and_then(|sqrt| CtOption::new(sqrt, sqrt.square().ct_eq(self)))
486        })
487    }
488
489    fn invert(&self) -> CtOption<Self> {
490        self.invert()
491    }
492
493    fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
494        // 1. c1, the largest integer such that 2^c1 divides q - 1.
495        const C1: usize = 3;
496        // 2. c2 = (q - 1) / (2^c1)
497        // const C2: &[u64] = &[
498        //     7265783942635991495,
499        //     12654461171626608085,
500        //     7117242603539670943,
501        //     3231317604283856616,
502        //     7288461048012747785,
503        //     2570724377909988239,
504        //     16043555967369944544,
505        //     726422729336273229,
506        //     10150185336703275386,
507        //     4349230516827719894,
508        //     16823846345382421693,
509        //     23792283108797432,
510        // ];
511        // 3. c3 = (c2 - 1) / 2
512        const C3: &[u64] = &[
513            12856264008172771555,
514            15550602622668079850,
515            3558621301769835471,
516            10839030838996704116,
517            12867602560861149700,
518            1285362188954994119,
519            17245150020539748080,
520            363211364668136614,
521            5075092668351637693,
522            11397987295268635755,
523            8411923172691210846,
524            11896141554398716,
525        ];
526        // 4. c4 = 2^c1 - 1
527        const C4: &[u64] = &[7];
528        // 5. c5 = 2^(c1 - 1)
529        const C5: &[u64] = &[4];
530        // 6. c6 = Z^c2
531        const C6: Fp2 = Fp2 {
532            c0: Fp::from_raw_unchecked([
533                8921533702591418330,
534                15859389534032789116,
535                3389114680249073393,
536                15116930867080254631,
537                3288288975085550621,
538                1021049300055853010,
539            ]),
540            c1: Fp::from_raw_unchecked([
541                8921533702591418330,
542                15859389534032789116,
543                3389114680249073393,
544                15116930867080254631,
545                3288288975085550621,
546                1021049300055853010,
547            ]),
548        };
549        // 7. c7 = Z^((c2 + 1) / 2)
550        const C7: Fp2 = Fp2 {
551            c0: Fp::from_raw_unchecked([
552                1921729236329761493,
553                9193968980645934504,
554                9862280504246317678,
555                6861748847800817560,
556                10375788487011937166,
557                4460107375738415,
558            ]),
559            c1: Fp::from_raw_unchecked([
560                16821121318233475459,
561                10183025025229892778,
562                1779012082459463630,
563                3442292649700377418,
564                1061500799026501234,
565                1352426537312017168,
566            ]),
567        };
568        let mut tv1 = C6; // 1. tv1 = c6
569        let tv2 = div.pow_vartime(C4); // 2. tv2 = v^c4
570        let tv3 = tv2.square(); // 3. tv3 = tv2^2
571        let tv3 = tv3 * div; // 4. tv3 = tv3 * v
572        let tv5 = num * tv3; // 5. tv5 = u * tv3
573        let tv5 = tv5.pow_vartime(C3); // 6. tv5 = tv5^c3
574        let tv5 = tv5 * tv2; // 7. tv5 = tv5 * tv2
575        let tv2 = tv5 * div; // 8. tv2 = tv5 * v
576        let mut tv3 = tv5 * num; // 9. tv3 = tv5 * u
577        let mut tv4 = tv3 * tv2; // 10. tv4 = tv3 * tv2
578        let tv5 = tv4.pow_vartime(C5); // 11. tv5 = tv4^c5
579        let is_square = tv5.ct_eq(&Fp2::one()); // 12. isQR = tv5 == 1
580        let tv2 = tv3 * C7; // 13. tv2 = tv3 * c7
581        let tv5 = tv4 * tv1; // 14. tv5 = tv4 * tv1
582        tv3.conditional_assign(&tv2, !is_square); // 15. tv3 = CMOV(tv2, tv3, isQR)
583        tv4.conditional_assign(&tv5, !is_square); // 16. tv4 = CMOV(tv5, tv4, isQR)
584                                                  // 17. for i in (c1, c1 - 1, ..., 2):
585        for i in (2..=C1).rev() {
586            let tv5 = i as u32 - 2; // 18.    tv5 = i - 2
587            let tv5 = num_bigint::BigUint::from(2u64).pow(tv5); // 19.    tv5 = 2^tv5
588            let tv5 = tv4.pow_vartime(&tv5.to_u64_digits()); // 20.    tv5 = tv4^tv5
589            let e1 = tv5.ct_eq(&Fp2::one()); // 21.    e1 = tv5 == 1
590            let tv2 = tv3 * tv1; // 22.    tv2 = tv3 * tv1
591            tv1 = tv1 * tv1; // 23.    tv1 = tv1 * tv1
592            let tv5 = tv4 * tv1; // 24.    tv5 = tv4 * tv1
593            tv3.conditional_assign(&tv2, !e1); // 25.    tv3 = CMOV(tv2, tv3, e1)
594            tv4.conditional_assign(&tv5, !e1); // 26.    tv4 = CMOV(tv5, tv4, e1)
595        }
596        (is_square, tv3)
597    }
598}
599
600#[derive(Clone, Copy, Debug)]
601pub struct Fp2Bytes {
602    pub slice: [u8; 96],
603}
604
605impl Default for Fp2Bytes {
606    fn default() -> Self {
607        Self { slice: [0u8; 96] }
608    }
609}
610
611impl AsMut<[u8]> for Fp2Bytes {
612    fn as_mut(&mut self) -> &mut [u8] {
613        &mut self.slice
614    }
615}
616
617impl AsRef<[u8]> for Fp2Bytes {
618    fn as_ref(&self) -> &[u8] {
619        &self.slice
620    }
621}
622
623// While Fp2 is not a prime field we must implement as consequence of `CurveExt::Base` requiring `WithSmallOrderMulGroup`.
624impl ff::PrimeField for Fp2 {
625    type Repr = Fp2Bytes;
626
627    const NUM_BITS: u32 = 381;
628    const CAPACITY: u32 = 381 - 1;
629    const MODULUS: &'static str =
630        "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab";
631    #[doc(hidden)]
632    const MULTIPLICATIVE_GENERATOR: Self = unimplemented!();
633    const ROOT_OF_UNITY: Self = Self {
634        c0: Fp::from_raw_unchecked([
635            0x7bcf_a7a2_5aa3_0fda,
636            0xdc17_dec1_2a92_7e7c,
637            0x2f08_8dd8_6b4e_bef1,
638            0xd1ca_2087_da74_d4a7,
639            0x2da2_5966_96ce_bc1d,
640            0x0e2b_7eed_bbfd_87d2,
641        ]),
642        c1: Fp::from_raw_unchecked([
643            0x7bcf_a7a2_5aa3_0fda,
644            0xdc17_dec1_2a92_7e7c,
645            0x2f08_8dd8_6b4e_bef1,
646            0xd1ca_2087_da74_d4a7,
647            0x2da2_5966_96ce_bc1d,
648            0x0e2b_7eed_bbfd_87d2,
649        ]),
650    };
651    const ROOT_OF_UNITY_INV: Self = Fp2 {
652        c0: Fp::from_raw_unchecked([
653            0x3e2f_585d_a55c_9ad1,
654            0x4294_213d_86c1_8183,
655            0x3828_44c8_8b62_3732,
656            0x92ad_2afd_1910_3e18,
657            0x1d79_4e4f_ac7c_f0b9,
658            0x0bd5_92fc_7d82_5ec8,
659        ]),
660        c1: Fp::from_raw_unchecked([
661            0x7bcf_a7a2_5aa3_0fda,
662            0xdc17_dec1_2a92_7e7c,
663            0x2f08_8dd8_6b4e_bef1,
664            0xd1ca_2087_da74_d4a7,
665            0x2da2_5966_96ce_bc1d,
666            0x0e2b_7eed_bbfd_87d2,
667        ]),
668    };
669    const DELTA: Self = Fp2 {
670        c0: Fp::zero(),
671        c1: Fp::zero(),
672    };
673    const TWO_INV: Fp2 = Fp2 {
674        c0: Fp::from_raw_unchecked([
675            0x1804_0000_0001_5554,
676            0x8550_0005_3ab0_0001,
677            0x633c_b57c_253c_276f,
678            0x6e22_d1ec_31eb_b502,
679            0xd391_6126_f2d1_4ca2,
680            0x17fb_b857_1a00_6596,
681        ]),
682        c1: Fp::zero(),
683    };
684    const S: u32 = 0;
685
686    fn from_repr(r: Self::Repr) -> CtOption<Self> {
687        // This uses little endian and so, assumes the array passed in is
688        // in that format.
689        Self::from_bytes(&r.slice)
690    }
691
692    fn to_repr(&self) -> Self::Repr {
693        Fp2Bytes {
694            slice: self.to_bytes(),
695        }
696    }
697
698    fn is_odd(&self) -> Choice {
699        Choice::from(self.to_bytes()[0] & 1)
700    }
701}
702
703impl From<u64> for Fp2 {
704    fn from(val: u64) -> Self {
705        Fp2 {
706            c0: Fp::from(val),
707            c1: Fp::zero(),
708        }
709    }
710}
711
712// The only reason we implement this trait for Fp2 is so it can be used as base field of `CurveExt`` trait for `G2Affine`.
713// See: https://github.com/zcash/pasta_curves/blob/main/src/arithmetic/curves.rs#L32
714impl WithSmallOrderMulGroup<3> for Fp2 {
715    // Fq::ZETA ^2
716    const ZETA: Self = Fp2 {
717        c0: Fp::from_raw_unchecked([
718            0x30f1_361b_798a_64e8,
719            0xf3b8_ddab_7ece_5a2a,
720            0x16a8_ca3a_c615_77f7,
721            0xc26a_2ff8_74fd_029b,
722            0x3636_b766_6070_1c6e,
723            0x051b_a4ab_241b_6160,
724        ]),
725        c1: Fp::zero(),
726    };
727}
728
729#[test]
730fn test_conditional_selection() {
731    let a = Fp2 {
732        c0: Fp::from_raw_unchecked([1, 2, 3, 4, 5, 6]),
733        c1: Fp::from_raw_unchecked([7, 8, 9, 10, 11, 12]),
734    };
735    let b = Fp2 {
736        c0: Fp::from_raw_unchecked([13, 14, 15, 16, 17, 18]),
737        c1: Fp::from_raw_unchecked([19, 20, 21, 22, 23, 24]),
738    };
739
740    assert_eq!(
741        ConditionallySelectable::conditional_select(&a, &b, Choice::from(0u8)),
742        a
743    );
744    assert_eq!(
745        ConditionallySelectable::conditional_select(&a, &b, Choice::from(1u8)),
746        b
747    );
748}
749
750#[test]
751fn test_equality() {
752    fn is_equal(a: &Fp2, b: &Fp2) -> bool {
753        let eq = a == b;
754        let ct_eq = a.ct_eq(b);
755
756        assert_eq!(eq, bool::from(ct_eq));
757
758        eq
759    }
760
761    assert!(is_equal(
762        &Fp2 {
763            c0: Fp::from_raw_unchecked([1, 2, 3, 4, 5, 6]),
764            c1: Fp::from_raw_unchecked([7, 8, 9, 10, 11, 12]),
765        },
766        &Fp2 {
767            c0: Fp::from_raw_unchecked([1, 2, 3, 4, 5, 6]),
768            c1: Fp::from_raw_unchecked([7, 8, 9, 10, 11, 12]),
769        }
770    ));
771
772    assert!(!is_equal(
773        &Fp2 {
774            c0: Fp::from_raw_unchecked([2, 2, 3, 4, 5, 6]),
775            c1: Fp::from_raw_unchecked([7, 8, 9, 10, 11, 12]),
776        },
777        &Fp2 {
778            c0: Fp::from_raw_unchecked([1, 2, 3, 4, 5, 6]),
779            c1: Fp::from_raw_unchecked([7, 8, 9, 10, 11, 12]),
780        }
781    ));
782
783    assert!(!is_equal(
784        &Fp2 {
785            c0: Fp::from_raw_unchecked([1, 2, 3, 4, 5, 6]),
786            c1: Fp::from_raw_unchecked([2, 8, 9, 10, 11, 12]),
787        },
788        &Fp2 {
789            c0: Fp::from_raw_unchecked([1, 2, 3, 4, 5, 6]),
790            c1: Fp::from_raw_unchecked([7, 8, 9, 10, 11, 12]),
791        }
792    ));
793}
794
795#[test]
796fn test_squaring() {
797    let a = Fp2 {
798        c0: Fp::from_raw_unchecked([
799            0xc9a2_1831_63ee_70d4,
800            0xbc37_70a7_196b_5c91,
801            0xa247_f8c1_304c_5f44,
802            0xb01f_c2a3_726c_80b5,
803            0xe1d2_93e5_bbd9_19c9,
804            0x04b7_8e80_020e_f2ca,
805        ]),
806        c1: Fp::from_raw_unchecked([
807            0x952e_a446_0462_618f,
808            0x238d_5edd_f025_c62f,
809            0xf6c9_4b01_2ea9_2e72,
810            0x03ce_24ea_c1c9_3808,
811            0x0559_50f9_45da_483c,
812            0x010a_768d_0df4_eabc,
813        ]),
814    };
815    let b = Fp2 {
816        c0: Fp::from_raw_unchecked([
817            0xa1e0_9175_a4d2_c1fe,
818            0x8b33_acfc_204e_ff12,
819            0xe244_15a1_1b45_6e42,
820            0x61d9_96b1_b6ee_1936,
821            0x1164_dbe8_667c_853c,
822            0x0788_557a_cc7d_9c79,
823        ]),
824        c1: Fp::from_raw_unchecked([
825            0xda6a_87cc_6f48_fa36,
826            0x0fc7_b488_277c_1903,
827            0x9445_ac4a_dc44_8187,
828            0x0261_6d5b_c909_9209,
829            0xdbed_4677_2db5_8d48,
830            0x11b9_4d50_76c7_b7b1,
831        ]),
832    };
833
834    assert_eq!(a.square(), b);
835}
836
837#[test]
838fn test_multiplication() {
839    let a = Fp2 {
840        c0: Fp::from_raw_unchecked([
841            0xc9a2_1831_63ee_70d4,
842            0xbc37_70a7_196b_5c91,
843            0xa247_f8c1_304c_5f44,
844            0xb01f_c2a3_726c_80b5,
845            0xe1d2_93e5_bbd9_19c9,
846            0x04b7_8e80_020e_f2ca,
847        ]),
848        c1: Fp::from_raw_unchecked([
849            0x952e_a446_0462_618f,
850            0x238d_5edd_f025_c62f,
851            0xf6c9_4b01_2ea9_2e72,
852            0x03ce_24ea_c1c9_3808,
853            0x0559_50f9_45da_483c,
854            0x010a_768d_0df4_eabc,
855        ]),
856    };
857    let b = Fp2 {
858        c0: Fp::from_raw_unchecked([
859            0xa1e0_9175_a4d2_c1fe,
860            0x8b33_acfc_204e_ff12,
861            0xe244_15a1_1b45_6e42,
862            0x61d9_96b1_b6ee_1936,
863            0x1164_dbe8_667c_853c,
864            0x0788_557a_cc7d_9c79,
865        ]),
866        c1: Fp::from_raw_unchecked([
867            0xda6a_87cc_6f48_fa36,
868            0x0fc7_b488_277c_1903,
869            0x9445_ac4a_dc44_8187,
870            0x0261_6d5b_c909_9209,
871            0xdbed_4677_2db5_8d48,
872            0x11b9_4d50_76c7_b7b1,
873        ]),
874    };
875    let c = Fp2 {
876        c0: Fp::from_raw_unchecked([
877            0xf597_483e_27b4_e0f7,
878            0x610f_badf_811d_ae5f,
879            0x8432_af91_7714_327a,
880            0x6a9a_9603_cf88_f09e,
881            0xf05a_7bf8_bad0_eb01,
882            0x0954_9131_c003_ffae,
883        ]),
884        c1: Fp::from_raw_unchecked([
885            0x963b_02d0_f93d_37cd,
886            0xc95c_e1cd_b30a_73d4,
887            0x3087_25fa_3126_f9b8,
888            0x56da_3c16_7fab_0d50,
889            0x6b50_86b5_f4b6_d6af,
890            0x09c3_9f06_2f18_e9f2,
891        ]),
892    };
893
894    assert_eq!(a * b, c);
895}
896
897#[test]
898fn test_addition() {
899    let a = Fp2 {
900        c0: Fp::from_raw_unchecked([
901            0xc9a2_1831_63ee_70d4,
902            0xbc37_70a7_196b_5c91,
903            0xa247_f8c1_304c_5f44,
904            0xb01f_c2a3_726c_80b5,
905            0xe1d2_93e5_bbd9_19c9,
906            0x04b7_8e80_020e_f2ca,
907        ]),
908        c1: Fp::from_raw_unchecked([
909            0x952e_a446_0462_618f,
910            0x238d_5edd_f025_c62f,
911            0xf6c9_4b01_2ea9_2e72,
912            0x03ce_24ea_c1c9_3808,
913            0x0559_50f9_45da_483c,
914            0x010a_768d_0df4_eabc,
915        ]),
916    };
917    let b = Fp2 {
918        c0: Fp::from_raw_unchecked([
919            0xa1e0_9175_a4d2_c1fe,
920            0x8b33_acfc_204e_ff12,
921            0xe244_15a1_1b45_6e42,
922            0x61d9_96b1_b6ee_1936,
923            0x1164_dbe8_667c_853c,
924            0x0788_557a_cc7d_9c79,
925        ]),
926        c1: Fp::from_raw_unchecked([
927            0xda6a_87cc_6f48_fa36,
928            0x0fc7_b488_277c_1903,
929            0x9445_ac4a_dc44_8187,
930            0x0261_6d5b_c909_9209,
931            0xdbed_4677_2db5_8d48,
932            0x11b9_4d50_76c7_b7b1,
933        ]),
934    };
935    let c = Fp2 {
936        c0: Fp::from_raw_unchecked([
937            0x6b82_a9a7_08c1_32d2,
938            0x476b_1da3_39ba_5ba4,
939            0x848c_0e62_4b91_cd87,
940            0x11f9_5955_295a_99ec,
941            0xf337_6fce_2255_9f06,
942            0x0c3f_e3fa_ce8c_8f43,
943        ]),
944        c1: Fp::from_raw_unchecked([
945            0x6f99_2c12_73ab_5bc5,
946            0x3355_1366_17a1_df33,
947            0x8b0e_f74c_0aed_aff9,
948            0x062f_9246_8ad2_ca12,
949            0xe146_9770_738f_d584,
950            0x12c3_c3dd_84bc_a26d,
951        ]),
952    };
953
954    assert_eq!(a + b, c);
955}
956
957#[test]
958fn test_subtraction() {
959    let a = Fp2 {
960        c0: Fp::from_raw_unchecked([
961            0xc9a2_1831_63ee_70d4,
962            0xbc37_70a7_196b_5c91,
963            0xa247_f8c1_304c_5f44,
964            0xb01f_c2a3_726c_80b5,
965            0xe1d2_93e5_bbd9_19c9,
966            0x04b7_8e80_020e_f2ca,
967        ]),
968        c1: Fp::from_raw_unchecked([
969            0x952e_a446_0462_618f,
970            0x238d_5edd_f025_c62f,
971            0xf6c9_4b01_2ea9_2e72,
972            0x03ce_24ea_c1c9_3808,
973            0x0559_50f9_45da_483c,
974            0x010a_768d_0df4_eabc,
975        ]),
976    };
977    let b = Fp2 {
978        c0: Fp::from_raw_unchecked([
979            0xa1e0_9175_a4d2_c1fe,
980            0x8b33_acfc_204e_ff12,
981            0xe244_15a1_1b45_6e42,
982            0x61d9_96b1_b6ee_1936,
983            0x1164_dbe8_667c_853c,
984            0x0788_557a_cc7d_9c79,
985        ]),
986        c1: Fp::from_raw_unchecked([
987            0xda6a_87cc_6f48_fa36,
988            0x0fc7_b488_277c_1903,
989            0x9445_ac4a_dc44_8187,
990            0x0261_6d5b_c909_9209,
991            0xdbed_4677_2db5_8d48,
992            0x11b9_4d50_76c7_b7b1,
993        ]),
994    };
995    let c = Fp2 {
996        c0: Fp::from_raw_unchecked([
997            0xe1c0_86bb_bf1b_5981,
998            0x4faf_c3a9_aa70_5d7e,
999            0x2734_b5c1_0bb7_e726,
1000            0xb2bd_7776_af03_7a3e,
1001            0x1b89_5fb3_98a8_4164,
1002            0x1730_4aef_6f11_3cec,
1003        ]),
1004        c1: Fp::from_raw_unchecked([
1005            0x74c3_1c79_9519_1204,
1006            0x3271_aa54_79fd_ad2b,
1007            0xc9b4_7157_4915_a30f,
1008            0x65e4_0313_ec44_b8be,
1009            0x7487_b238_5b70_67cb,
1010            0x0952_3b26_d0ad_19a4,
1011        ]),
1012    };
1013
1014    assert_eq!(a - b, c);
1015}
1016
1017#[test]
1018fn test_negation() {
1019    let a = Fp2 {
1020        c0: Fp::from_raw_unchecked([
1021            0xc9a2_1831_63ee_70d4,
1022            0xbc37_70a7_196b_5c91,
1023            0xa247_f8c1_304c_5f44,
1024            0xb01f_c2a3_726c_80b5,
1025            0xe1d2_93e5_bbd9_19c9,
1026            0x04b7_8e80_020e_f2ca,
1027        ]),
1028        c1: Fp::from_raw_unchecked([
1029            0x952e_a446_0462_618f,
1030            0x238d_5edd_f025_c62f,
1031            0xf6c9_4b01_2ea9_2e72,
1032            0x03ce_24ea_c1c9_3808,
1033            0x0559_50f9_45da_483c,
1034            0x010a_768d_0df4_eabc,
1035        ]),
1036    };
1037    let b = Fp2 {
1038        c0: Fp::from_raw_unchecked([
1039            0xf05c_e7ce_9c11_39d7,
1040            0x6274_8f57_97e8_a36d,
1041            0xc4e8_d9df_c664_96df,
1042            0xb457_88e1_8118_9209,
1043            0x6949_13d0_8772_930d,
1044            0x1549_836a_3770_f3cf,
1045        ]),
1046        c1: Fp::from_raw_unchecked([
1047            0x24d0_5bb9_fb9d_491c,
1048            0xfb1e_a120_c12e_39d0,
1049            0x7067_879f_c807_c7b1,
1050            0x60a9_269a_31bb_dab6,
1051            0x45c2_56bc_fd71_649b,
1052            0x18f6_9b5d_2b8a_fbde,
1053        ]),
1054    };
1055
1056    assert_eq!(-a, b);
1057}
1058
1059#[test]
1060fn test_sqrt() {
1061    // a = 1488924004771393321054797166853618474668089414631333405711627789629391903630694737978065425271543178763948256226639*u + 784063022264861764559335808165825052288770346101304131934508881646553551234697082295473567906267937225174620141295
1062    let a = Fp2 {
1063        c0: Fp::from_raw_unchecked([
1064            0x2bee_d146_27d7_f9e9,
1065            0xb661_4e06_660e_5dce,
1066            0x06c4_cc7c_2f91_d42c,
1067            0x996d_7847_4b7a_63cc,
1068            0xebae_bc4c_820d_574e,
1069            0x1886_5e12_d93f_d845,
1070        ]),
1071        c1: Fp::from_raw_unchecked([
1072            0x7d82_8664_baf4_f566,
1073            0xd17e_6639_96ec_7339,
1074            0x679e_ad55_cb40_78d0,
1075            0xfe3b_2260_e001_ec28,
1076            0x3059_93d0_43d9_1b68,
1077            0x0626_f03c_0489_b72d,
1078        ]),
1079    };
1080
1081    assert_eq!(a.sqrt().unwrap().square(), a);
1082
1083    // b = 5, which is a generator of the p - 1 order
1084    // multiplicative subgroup
1085    let b = Fp2 {
1086        c0: Fp::from_raw_unchecked([
1087            0x6631_0000_0010_5545,
1088            0x2114_0040_0eec_000d,
1089            0x3fa7_af30_c820_e316,
1090            0xc52a_8b8d_6387_695d,
1091            0x9fb4_e61d_1e83_eac5,
1092            0x005c_b922_afe8_4dc7,
1093        ]),
1094        c1: Fp::zero(),
1095    };
1096
1097    assert_eq!(b.sqrt().unwrap().square(), b);
1098
1099    // c = 25, which is a generator of the (p - 1) / 2 order
1100    // multiplicative subgroup
1101    let c = Fp2 {
1102        c0: Fp::from_raw_unchecked([
1103            0x44f6_0000_0051_ffae,
1104            0x86b8_0141_9948_0043,
1105            0xd715_9952_f1f3_794a,
1106            0x755d_6e3d_fe1f_fc12,
1107            0xd36c_d6db_5547_e905,
1108            0x02f8_c8ec_bf18_67bb,
1109        ]),
1110        c1: Fp::zero(),
1111    };
1112
1113    assert_eq!(c.sqrt().unwrap().square(), c);
1114
1115    // 2155129644831861015726826462986972654175647013268275306775721078997042729172900466542651176384766902407257452753362*u + 2796889544896299244102912275102369318775038861758288697415827248356648685135290329705805931514906495247464901062529
1116    // is nonsquare.
1117    assert!(bool::from(
1118        Fp2 {
1119            c0: Fp::from_raw_unchecked([
1120                0xc5fa_1bc8_fd00_d7f6,
1121                0x3830_ca45_4606_003b,
1122                0x2b28_7f11_04b1_02da,
1123                0xa7fb_30f2_8230_f23e,
1124                0x339c_db9e_e953_dbf0,
1125                0x0d78_ec51_d989_fc57,
1126            ]),
1127            c1: Fp::from_raw_unchecked([
1128                0x27ec_4898_cf87_f613,
1129                0x9de1_394e_1abb_05a5,
1130                0x0947_f85d_c170_fc14,
1131                0x586f_bc69_6b61_14b7,
1132                0x2b34_75a4_077d_7169,
1133                0x13e1_c895_cc4b_6c22,
1134            ])
1135        }
1136        .sqrt()
1137        .is_none()
1138    ));
1139}
1140
1141#[test]
1142fn test_inversion() {
1143    let a = Fp2 {
1144        c0: Fp::from_raw_unchecked([
1145            0x1128_ecad_6754_9455,
1146            0x9e7a_1cff_3a4e_a1a8,
1147            0xeb20_8d51_e08b_cf27,
1148            0xe98a_d408_11f5_fc2b,
1149            0x736c_3a59_232d_511d,
1150            0x10ac_d42d_29cf_cbb6,
1151        ]),
1152        c1: Fp::from_raw_unchecked([
1153            0xd328_e37c_c2f5_8d41,
1154            0x948d_f085_8a60_5869,
1155            0x6032_f9d5_6f93_a573,
1156            0x2be4_83ef_3fff_dc87,
1157            0x30ef_61f8_8f48_3c2a,
1158            0x1333_f55a_3572_5be0,
1159        ]),
1160    };
1161
1162    let b = Fp2 {
1163        c0: Fp::from_raw_unchecked([
1164            0x0581_a133_3d4f_48a6,
1165            0x5824_2f6e_f074_8500,
1166            0x0292_c955_349e_6da5,
1167            0xba37_721d_dd95_fcd0,
1168            0x70d1_6790_3aa5_dfc5,
1169            0x1189_5e11_8b58_a9d5,
1170        ]),
1171        c1: Fp::from_raw_unchecked([
1172            0x0eda_09d2_d7a8_5d17,
1173            0x8808_e137_a7d1_a2cf,
1174            0x43ae_2625_c1ff_21db,
1175            0xf85a_c9fd_f7a7_4c64,
1176            0x8fcc_dda5_b8da_9738,
1177            0x08e8_4f0c_b32c_d17d,
1178        ]),
1179    };
1180
1181    assert_eq!(a.invert().unwrap(), b);
1182
1183    assert!(bool::from(Fp2::zero().invert().is_none()));
1184}
1185
1186#[test]
1187fn test_lexicographic_largest() {
1188    assert!(!bool::from(Fp2::zero().lexicographically_largest()));
1189    assert!(!bool::from(Fp2::one().lexicographically_largest()));
1190    assert!(bool::from(
1191        Fp2 {
1192            c0: Fp::from_raw_unchecked([
1193                0x1128_ecad_6754_9455,
1194                0x9e7a_1cff_3a4e_a1a8,
1195                0xeb20_8d51_e08b_cf27,
1196                0xe98a_d408_11f5_fc2b,
1197                0x736c_3a59_232d_511d,
1198                0x10ac_d42d_29cf_cbb6,
1199            ]),
1200            c1: Fp::from_raw_unchecked([
1201                0xd328_e37c_c2f5_8d41,
1202                0x948d_f085_8a60_5869,
1203                0x6032_f9d5_6f93_a573,
1204                0x2be4_83ef_3fff_dc87,
1205                0x30ef_61f8_8f48_3c2a,
1206                0x1333_f55a_3572_5be0,
1207            ]),
1208        }
1209        .lexicographically_largest()
1210    ));
1211    assert!(!bool::from(
1212        Fp2 {
1213            c0: -Fp::from_raw_unchecked([
1214                0x1128_ecad_6754_9455,
1215                0x9e7a_1cff_3a4e_a1a8,
1216                0xeb20_8d51_e08b_cf27,
1217                0xe98a_d408_11f5_fc2b,
1218                0x736c_3a59_232d_511d,
1219                0x10ac_d42d_29cf_cbb6,
1220            ]),
1221            c1: -Fp::from_raw_unchecked([
1222                0xd328_e37c_c2f5_8d41,
1223                0x948d_f085_8a60_5869,
1224                0x6032_f9d5_6f93_a573,
1225                0x2be4_83ef_3fff_dc87,
1226                0x30ef_61f8_8f48_3c2a,
1227                0x1333_f55a_3572_5be0,
1228            ]),
1229        }
1230        .lexicographically_largest()
1231    ));
1232    assert!(!bool::from(
1233        Fp2 {
1234            c0: Fp::from_raw_unchecked([
1235                0x1128_ecad_6754_9455,
1236                0x9e7a_1cff_3a4e_a1a8,
1237                0xeb20_8d51_e08b_cf27,
1238                0xe98a_d408_11f5_fc2b,
1239                0x736c_3a59_232d_511d,
1240                0x10ac_d42d_29cf_cbb6,
1241            ]),
1242            c1: Fp::zero(),
1243        }
1244        .lexicographically_largest()
1245    ));
1246    assert!(bool::from(
1247        Fp2 {
1248            c0: -Fp::from_raw_unchecked([
1249                0x1128_ecad_6754_9455,
1250                0x9e7a_1cff_3a4e_a1a8,
1251                0xeb20_8d51_e08b_cf27,
1252                0xe98a_d408_11f5_fc2b,
1253                0x736c_3a59_232d_511d,
1254                0x10ac_d42d_29cf_cbb6,
1255            ]),
1256            c1: Fp::zero(),
1257        }
1258        .lexicographically_largest()
1259    ));
1260}
1261
1262#[cfg(feature = "zeroize")]
1263#[test]
1264fn test_zeroize() {
1265    use zeroize::Zeroize;
1266
1267    let mut a = Fp2::one();
1268    a.zeroize();
1269    assert!(bool::from(a.is_zero()));
1270}
1271
1272#[test]
1273fn test_root_of_unity_inv() {
1274    use ff::PrimeField;
1275    assert_eq!(Fp2::ROOT_OF_UNITY * Fp2::ROOT_OF_UNITY_INV, Fp2::ONE)
1276}