halo2curves/pluto_eris/
fp2.rs

1use core::convert::TryInto;
2use std::cmp::Ordering;
3
4use subtle::{Choice, CtOption};
5
6use super::fp::Fp;
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!(Fp2, Fp2);
16crate::impl_binops_multiplicative!(Fp2, Fp2);
17crate::impl_binops_calls!(Fp2);
18crate::impl_sum_prod!(Fp2);
19crate::impl_tower2!(Fp, Fp2);
20crate::impl_tower2_from_uniform_bytes!(Fp, Fp2, 128);
21
22pub type Fp2 = QuadExtField<Fp>;
23
24impl QuadExtFieldArith for Fp2 {
25    type Base = Fp;
26    const SQRT: SQRT<Fp> = SQRT::Algorithm10 {
27        precompute_e: Fp2 {
28            c0: Fp::ZERO,
29            c1: Fp::from_raw([
30                0x67153f9701e19938,
31                0x5d232408689b4c6c,
32                0x021848271d63f087,
33                0x03b21f15823a404a,
34                0x667c70cf991a36e6,
35                0x7a82a3d83bc9e63a,
36                0x13e275a1fa6a13af,
37            ]),
38        },
39        precompute_f: Fp2 {
40            c0: Fp::from_raw([0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]),
41            c1: Fp::ZERO,
42        },
43        q_minus_1_over_4: &[
44            0x67ffff34c0000000,
45            0xa8a9fa30c001ae51,
46            0xf929e97fa3eb7ff5,
47            0xd10fe69736a29b1e,
48            0x2a00f29dbd0e499b,
49            0x004c3800035fdc39,
50            0x0900000000000900,
51        ],
52    };
53}
54
55impl ExtField for Fp2 {
56    const NON_RESIDUE: Self = Fp2 {
57        c0: Fp::from_raw([
58            0xddb6da4b5b6db6e8,
59            0x833bf7b35b701d98,
60            0x3f6072240ebe2483,
61            0x73cd928ee056022c,
62            0xce4a7f2a7bcb4495,
63            0xdbda9924971b3a9a,
64            0x0cdb6db6db6dc3b6,
65        ]),
66
67        c1: Fp::from_raw([
68            0xeb6db62d36db6db3,
69            0xb523fb0536dcde8e,
70            0x8c6d1148d5a5491b,
71            0x457b57ef5366ce1a,
72            0x489319197d79f5f3,
73            0xb71cc2492776bcc3,
74            0x07b6db6db6db756d,
75        ]),
76    };
77    fn frobenius_map(&mut self, power: usize) {
78        if power % 2 != 0 {
79            self.conjugate();
80        }
81    }
82}
83
84#[cfg(test)]
85mod test {
86
87    use rand_core::RngCore;
88
89    use super::*;
90    use crate::{arith_test, constants_test, legendre_test, serde_test, test};
91
92    constants_test!(Fp2);
93
94    arith_test!(Fp2);
95    legendre_test!(Fp2);
96    test!(arith, Fp2, sqrt_test, 1000);
97
98    serde_test!(Fp2);
99
100    crate::f2_test!(Fp2, Fp);
101    crate::frobenius_test!(Fp2, Fp, 20);
102
103    #[test]
104    fn test_fp2_squaring() {
105        // u + 1
106        let mut a = Fp2 {
107            c0: Fp::one(),
108            c1: Fp::one(),
109        };
110        // (u + 1) ^2 = 1 + u^2 + 2u = -4 + 2u
111        a.square_assign();
112        let minus_4 = -Fp::from(4u64);
113        assert_eq!(
114            a,
115            Fp2 {
116                c0: minus_4,
117                c1: Fp::one() + Fp::one(),
118            }
119        );
120
121        // u
122        let mut a = Fp2 {
123            c0: Fp::zero(),
124            c1: Fp::one(),
125        };
126        // u^2
127        a.square_assign();
128        assert_eq!(
129            a,
130            Fp2 {
131                c0: Fp::NON_RESIDUE,
132                c1: Fp::zero(),
133            }
134        );
135    }
136
137    #[test]
138    fn test_fp2_mul_nonresidue() {
139        use rand::SeedableRng;
140        use rand_xorshift::XorShiftRng;
141        let mut rng = XorShiftRng::from_seed(crate::tests::SEED);
142        for _ in 0..1000 {
143            let mut a = Fp2::random(&mut rng);
144            let mut b = a;
145            a = a.mul_by_nonresidue();
146            b.mul_assign(&Fp2::NON_RESIDUE);
147
148            assert_eq!(a, b);
149        }
150    }
151}