halo2curves/pluto_eris/
fp6.rs

1use ff::Field;
2
3use super::{fp::Fp, fp2::Fp2};
4use crate::ff_ext::{
5    cubic::{CubicExtField, CubicExtFieldArith, CubicSparseMul},
6    ExtField,
7};
8
9// -BETA is a cubic non-residue in Fp2. Fp6 = Fp2[X]/(X^3 + BETA)
10// We introduce the variable v such that v^3 = -BETA
11// BETA = - 57/(z+3)
12crate::impl_binops_additive!(Fp6, Fp6);
13crate::impl_binops_multiplicative!(Fp6, Fp6);
14crate::impl_binops_calls!(Fp6);
15crate::impl_sum_prod!(Fp6);
16pub type Fp6 = CubicExtField<Fp2>;
17
18impl CubicExtFieldArith for Fp6 {
19    type Base = Fp2;
20}
21
22impl CubicSparseMul for Fp6 {
23    type Base = Fp2;
24}
25
26impl ExtField for Fp6 {
27    const NON_RESIDUE: Self = Fp6::new(Fp2::ZERO, Fp2::ONE, Fp2::ZERO);
28
29    fn frobenius_map(&mut self, power: usize) {
30        self.c0.frobenius_map(power);
31        self.c1.frobenius_map(power);
32        self.c2.frobenius_map(power);
33        self.c1.mul_assign(&FROBENIUS_COEFF_FP6_C1[power % 6]);
34        self.c2.mul_assign(&FROBENIUS_COEFF_FP6_C2[power % 6]);
35    }
36
37    fn mul_by_nonresidue(self: &Fp6) -> Fp6 {
38        let c0 = self.c2.mul_by_nonresidue();
39        let c1 = self.c0;
40        let c2 = self.c1;
41        Self { c0, c1, c2 }
42    }
43}
44
45/// Fp2 coefficients for the efficient computation of Frobenius Endomorphism in
46/// Fp6.
47pub(crate) const FROBENIUS_COEFF_FP6_C1: [Fp2; 6] = [
48    // Fp2(v^3)**(((p^0) - 1) / 3)
49    Fp2::ONE,
50    // Fp2(v^3)**(((p^1) - 1) / 3)
51    Fp2 {
52        // 0x120de97f024c55bc3bc0d351f4c70da1e3886170077a50986f93678bc921dcd5041bc4bb14cc42dc52e787634eccc335a001825382850d03
53        c0: Fp::from_raw([
54            0xa001825382850d03,
55            0x52e787634eccc335,
56            0x041bc4bb14cc42dc,
57            0x6f93678bc921dcd5,
58            0xe3886170077a5098,
59            0x3bc0d351f4c70da1,
60            0x120de97f024c55bc,
61        ]),
62        // 0x2096f3f804d973afd82becc2ef081b76132461908eadbe3da1a7f5502b7091965efa1ddf4658080413be1b7cd3c9ea0e2772fea378a9b322
63        c1: Fp::from_raw([
64            0x2772fea378a9b322,
65            0x13be1b7cd3c9ea0e,
66            0x5efa1ddf46580804,
67            0xa1a7f5502b709196,
68            0x132461908eadbe3d,
69            0xd82becc2ef081b76,
70            0x2096f3f804d973af,
71        ]),
72    },
73    // Fp2(v^3)**(((p^2) - 1) / 3)
74    Fp2 {
75        // 0x480000000000360001c950000d7ee0e4a803c956d01c903d720dc8ad8b38dffaf50c100004c37ffffffe
76        c0: Fp::from_raw([
77            0x100004c37ffffffe,
78            0xc8ad8b38dffaf50c,
79            0xc956d01c903d720d,
80            0x50000d7ee0e4a803,
81            0x00000000360001c9,
82            0x0000000000004800,
83            0x0000000000000000,
84        ]),
85        c1: Fp::ZERO,
86    },
87    // Fp2(v^3)**(((p^3) - 1) / 3)
88    Fp2 {
89        // 0x1f9cd069c59f50a72511749de232911d833b798e78bd98c02913e38315a71c287cd52ae30d09b78a8b43b17b4c3ea938a04518fa783eb497
90        c0: Fp::from_raw([
91            0xa04518fa783eb497,
92            0x8b43b17b4c3ea938,
93            0x7cd52ae30d09b78a,
94            0x2913e38315a71c28,
95            0x833b798e78bd98c0,
96            0x2511749de232911d,
97            0x1f9cd069c59f50a7,
98        ]),
99        // 0x23affd628747cbaec26943f93dc9eab63f4af36699fe6d74c0aa2122aa7cb689e8faacb3479a973a4a728fcb77b150ee77240d4066e42ac5
100        c1: Fp::from_raw([
101            0x77240d4066e42ac5,
102            0x4a728fcb77b150ee,
103            0xe8faacb3479a973a,
104            0xc0aa2122aa7cb689,
105            0x3f4af36699fe6d74,
106            0xc26943f93dc9eab6,
107            0x23affd628747cbae,
108        ]),
109    },
110    // Fp2(v^3)**(((p^4) - 1) / 3)
111    Fp2 {
112        // 0x24000000000024000130e0000d7f28e4a803ca76be3924a5f43f8cddf9a5c4781b50d5e1ff708dc8d9fa5d8a200bc4398ffff80f80000002
113        c0: Fp::from_raw([
114            0x8ffff80f80000002,
115            0xd9fa5d8a200bc439,
116            0x1b50d5e1ff708dc8,
117            0xf43f8cddf9a5c478,
118            0xa803ca76be3924a5,
119            0x0130e0000d7f28e4,
120            0x2400000000002400,
121        ]),
122        c1: Fp::ZERO,
123    },
124    // Fp2(v^3)**(((p^5) - 1) / 3)
125    Fp2 {
126        // 0x165546173814a19ca18f781044054309e943b9ef683a6385efd7e9aad64bdffa485e5c5efd860546672498a76502061cffb95e58053c3e68
127        c0: Fp::from_raw([
128            0xffb95e58053c3e68,
129            0x672498a76502061c,
130            0x485e5c5efd860546,
131            0xefd7e9aad64bdffa,
132            0xe943b9ef683a6385,
133            0xa18f781044054309,
134            0x165546173814a19c,
135        ]),
136        // 0x3b90ea573df08a167cc8f43ee2cdb9cfd983ff6bfc6212c262d1e46df2790d7815a816a9169606ee71f263db492378ea168edc22072221b
137        c1: Fp::from_raw([
138            0xa168edc22072221b,
139            0xe71f263db492378e,
140            0x815a816a9169606e,
141            0x262d1e46df2790d7,
142            0xfd983ff6bfc6212c,
143            0x67cc8f43ee2cdb9c,
144            0x03b90ea573df08a1,
145        ]),
146    },
147];
148
149/// Fp2 coefficients for the efficient computation of Frobenius Endomorphism in
150/// Fp6.
151pub(crate) const FROBENIUS_COEFF_FP6_C2: [Fp2; 6] = [
152    // Fp2(v^3)**(((2p^0) - 2) / 3)
153    Fp2::ONE,
154    // Fp2(v^3)**(((2p^1) - 2) / 3)
155    Fp2 {
156        // 0x93733692ce3cdcfc34610bac6bd22c4dc590efb038c82998c9549048e7b424cc00e17ffb4a61950d0ec132a7b38f09db0a818e422737f7c
157        c0: Fp::from_raw([
158            0xb0a818e422737f7c,
159            0xd0ec132a7b38f09d,
160            0xc00e17ffb4a61950,
161            0x8c9549048e7b424c,
162            0xdc590efb038c8299,
163            0xc34610bac6bd22c4,
164            0x093733692ce3cdcf,
165        ]),
166        // 0x12cb19daadc92882ba3593aa6f3e6bf426f29bd46039e3036f61d0bd35f39ebecdac3209d9df546061c90b4940d9031c240ce398421dc7dc
167        c1: Fp::from_raw([
168            0x240ce398421dc7dc,
169            0x61c90b4940d9031c,
170            0xcdac3209d9df5460,
171            0x6f61d0bd35f39ebe,
172            0x26f29bd46039e303,
173            0xba3593aa6f3e6bf4,
174            0x12cb19daadc92882,
175        ]),
176    },
177    // Fp2(v^3)**(((2p^2) - 2) / 3)
178    Fp2 {
179        // 0x24000000000024000130e0000d7f28e4a803ca76be3924a5f43f8cddf9a5c4781b50d5e1ff708dc8d9fa5d8a200bc4398ffff80f80000002
180        c0: Fp::from_raw([
181            0x8ffff80f80000002,
182            0xd9fa5d8a200bc439,
183            0x1b50d5e1ff708dc8,
184            0xf43f8cddf9a5c478,
185            0xa803ca76be3924a5,
186            0x0130e0000d7f28e4,
187            0x2400000000002400,
188        ]),
189        c1: Fp::ZERO,
190    },
191    // Fp2(v^3)**(((2p^3) - 2) / 3)
192    Fp2 {
193        // 0x85cc83a7eeba2ef5f7dd2f9f1405312b2ce0cbc85b8561e1657aaf1e85b82299aa5ace8b26b78d88f57e1c7a87f75556885980d6c8d2186
194        c0: Fp::from_raw([
195            0x6885980d6c8d2186,
196            0x8f57e1c7a87f7555,
197            0x9aa5ace8b26b78d8,
198            0x1657aaf1e85b8229,
199            0xb2ce0cbc85b8561e,
200            0x5f7dd2f9f1405312,
201            0x085cc83a7eeba2ef,
202        ]),
203        // 0xda3357ee4e6a9836af75e8ec0dbd23e7abc03d404620899ee0ea8b684b9400d58d5ebe487e523680bbe8a0dd9ea1d312bca2a953ab51c9b
204        c1: Fp::from_raw([
205            0x2bca2a953ab51c9b,
206            0x0bbe8a0dd9ea1d31,
207            0x58d5ebe487e52368,
208            0xee0ea8b684b9400d,
209            0x7abc03d404620899,
210            0x6af75e8ec0dbd23e,
211            0x0da3357ee4e6a983,
212        ]),
213    },
214    // Fp2(v^3)**(((2p^4) - 2) / 3)
215    Fp2 {
216        // 0x480000000000360001c950000d7ee0e4a803c956d01c903d720dc8ad8b38dffaf50c100004c37ffffffe
217        c0: Fp::from_raw([
218            0x100004c37ffffffe,
219            0xc8ad8b38dffaf50c,
220            0xc956d01c903d720d,
221            0x50000d7ee0e4a803,
222            0x00000000360001c9,
223            0x0000000000004800,
224            0x0000000000000000,
225        ]),
226        c1: Fp::ZERO,
227    },
228    // Fp2(v^3)**(((2p^5) - 2) / 3)
229    Fp2 {
230        // 0x126c045c5430b340de6cfc4b5581fb0d18dcaebf6af44db7a152a66663b3a80589f3e116289c6dad4263f3d0dc4e535286d24be170ff5eff
231        c0: Fp::from_raw([
232            0x86d24be170ff5eff,
233            0x4263f3d0dc4e5352,
234            0x89f3e116289c6dad,
235            0xa152a66663b3a805,
236            0x18dcaebf6af44db7,
237            0xde6cfc4b5581fb0d,
238            0x126c045c5430b340,
239        ]),
240        // 0x391b0a66d5051f9dc03edc6dd6532b206552ace8f9d3ad1e6cf20e91fdd8dafbe2588102de9880e3520536be54398f85028eea5832d1b8a
241        c1: Fp::from_raw([
242            0x5028eea5832d1b8a,
243            0x3520536be54398f8,
244            0xbe2588102de9880e,
245            0xe6cf20e91fdd8daf,
246            0x06552ace8f9d3ad1,
247            0xdc03edc6dd6532b2,
248            0x0391b0a66d5051f9,
249        ]),
250    },
251];
252
253#[cfg(test)]
254mod test {
255    use rand_core::RngCore;
256
257    use super::*;
258    use crate::{arith_test, frobenius_test, setup_f6_test_funcs, test};
259
260    macro_rules! test_fp6 {
261        ($test:ident, $size: expr) => {
262            paste::paste! {
263            #[test]
264            fn [< $test test >]() {
265                use rand::SeedableRng;
266                use rand_xorshift::XorShiftRng;
267                let mut rng = XorShiftRng::from_seed(crate::tests::SEED);
268                crate::pluto_eris::fp6::test::$test(&mut rng, $size);
269            }
270            }
271        };
272    }
273
274    arith_test!(Fp6);
275    setup_f6_test_funcs!(Fp6, Fp2);
276    test_fp6!(f6_mul_nonresidue_, 1000);
277    test_fp6!(f6_mul_by_1_, 1000);
278    test_fp6!(f6_mul_by_01_, 1000);
279    frobenius_test!(Fp6, Fp, 10);
280
281    #[test]
282    fn test_fp6_mul_nonresidue() {
283        let e = Fp6::random(rand_core::OsRng);
284        let a0 = e.mul_by_nonresidue();
285        let a1 = e * Fp6::NON_RESIDUE;
286
287        assert_eq!(a0, a1);
288    }
289}