halo2curves/bls12381/
fq2.rs

1use core::convert::TryInto;
2use std::cmp::Ordering;
3
4use subtle::{Choice, CtOption};
5
6use super::fq::Fq;
7use crate::{
8    ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup},
9    ff_ext::{
10        quadratic::{QuadExtField, QuadExtFieldArith, SQRT},
11        ExtField, Legendre,
12    },
13};
14
15crate::impl_binops_additive!(Fq2, Fq2);
16crate::impl_binops_multiplicative!(Fq2, Fq2);
17crate::impl_binops_calls!(Fq2);
18crate::impl_sum_prod!(Fq2);
19crate::impl_tower2!(Fq, Fq2);
20crate::impl_tower2_from_uniform_bytes!(Fq, Fq2, 128);
21
22pub type Fq2 = QuadExtField<Fq>;
23impl QuadExtFieldArith for Fq2 {
24    type Base = Fq;
25    const SQRT: SQRT<Fq> = SQRT::Algorithm9 {
26        q_minus_3_over_4: &[
27            0xee7fbfffffffeaaa,
28            0x07aaffffac54ffff,
29            0xd9cc34a83dac3d89,
30            0xd91dd2e13ce144af,
31            0x92c6e9ed90d2eb35,
32            0x0680447a8e5ff9a6,
33        ],
34        q_minus_1_over_2: &[
35            0xdcff7fffffffd555,
36            0x0f55ffff58a9ffff,
37            0xb39869507b587b12,
38            0xb23ba5c279c2895f,
39            0x258dd3db21a5d66b,
40            0x0d0088f51cbff34d,
41        ],
42    };
43
44    fn square_assign(el: &mut QuadExtField<Self::Base>) {
45        let a = el.c0 + el.c1;
46        let b = el.c0 - el.c1;
47        let c = el.c0.double();
48        el.c0 = a * b;
49        el.c1 = c * el.c1;
50    }
51}
52
53impl ExtField for Fq2 {
54    const NON_RESIDUE: Self = Fq2::new(Fq::ONE, Fq::ONE);
55
56    fn mul_by_nonresidue(&self) -> Self {
57        Self {
58            c0: self.c0 - self.c1,
59            c1: self.c0 + self.c1,
60        }
61    }
62
63    fn frobenius_map(&mut self, power: usize) {
64        if power % 2 != 0 {
65            self.conjugate();
66        }
67    }
68}
69
70#[cfg(test)]
71mod test {
72
73    use rand_core::RngCore;
74
75    use super::*;
76    use crate::{
77        arith_test, constants_test, f2_test, frobenius_test, legendre_test, serde_test, test,
78    };
79
80    constants_test!(Fq2);
81
82    arith_test!(Fq2);
83    legendre_test!(Fq2);
84    test!(arith, Fq2, sqrt_test, 1000);
85
86    serde_test!(Fq2);
87
88    f2_test!(Fq2, Fq);
89    frobenius_test!(Fq2, Fq, 20);
90
91    #[test]
92    fn test_fq2_mul_nonresidue() {
93        let e = Fq2::random(rand_core::OsRng);
94        let a0 = e.mul_by_nonresidue();
95        let a1 = e * Fq2::NON_RESIDUE;
96        assert_eq!(a0, a1);
97    }
98}