ark_ff/fields/models/
fp4.rs

1use ark_std::Zero;
2
3use super::quadratic_extension::*;
4use core::{marker::PhantomData, ops::Not};
5
6use crate::{
7    fields::{Fp2, Fp2Config},
8    CyclotomicMultSubgroup,
9};
10
11pub trait Fp4Config: 'static + Send + Sync {
12    type Fp2Config: Fp2Config;
13
14    /// This *must* equal (0, 1);
15    /// see [[DESD06, Section 5.1]](https://eprint.iacr.org/2006/471.pdf).
16    const NONRESIDUE: Fp2<Self::Fp2Config>;
17
18    /// Coefficients for the Frobenius automorphism.
19    /// non_residue^((modulus^i-1)/4) for i=0,1,2,3
20    const FROBENIUS_COEFF_FP4_C1: &'static [<Self::Fp2Config as Fp2Config>::Fp];
21
22    #[inline(always)]
23    fn mul_fp2_by_nonresidue_in_place(fe: &mut Fp2<Self::Fp2Config>) -> &mut Fp2<Self::Fp2Config> {
24        // see [[DESD06, Section 5.1]](https://eprint.iacr.org/2006/471.pdf).
25        let new_c1 = fe.c0;
26        Self::Fp2Config::mul_fp_by_nonresidue_in_place(&mut fe.c1);
27        fe.c0 = fe.c1;
28        fe.c1 = new_c1;
29        fe
30    }
31}
32
33pub struct Fp4ConfigWrapper<P: Fp4Config>(PhantomData<P>);
34
35impl<P: Fp4Config> QuadExtConfig for Fp4ConfigWrapper<P> {
36    type BasePrimeField = <P::Fp2Config as Fp2Config>::Fp;
37    type BaseField = Fp2<P::Fp2Config>;
38    type FrobCoeff = Self::BasePrimeField;
39
40    const DEGREE_OVER_BASE_PRIME_FIELD: usize = 4;
41
42    const NONRESIDUE: Self::BaseField = P::NONRESIDUE;
43
44    const FROBENIUS_COEFF_C1: &'static [Self::FrobCoeff] = P::FROBENIUS_COEFF_FP4_C1;
45
46    #[inline(always)]
47    fn mul_base_field_by_nonresidue_in_place(fe: &mut Self::BaseField) -> &mut Self::BaseField {
48        P::mul_fp2_by_nonresidue_in_place(fe)
49    }
50
51    fn mul_base_field_by_frob_coeff(fe: &mut Self::BaseField, power: usize) {
52        fe.mul_assign_by_fp(&Self::FROBENIUS_COEFF_C1[power % Self::DEGREE_OVER_BASE_PRIME_FIELD]);
53    }
54}
55
56pub type Fp4<P> = QuadExtField<Fp4ConfigWrapper<P>>;
57
58impl<P: Fp4Config> Fp4<P> {
59    pub fn mul_by_fp(&mut self, element: &<P::Fp2Config as Fp2Config>::Fp) {
60        self.c0.mul_assign_by_fp(element);
61        self.c1.mul_assign_by_fp(element);
62    }
63
64    pub fn mul_by_fp2(&mut self, element: &Fp2<P::Fp2Config>) {
65        self.c0 *= element;
66        self.c1 *= element;
67    }
68}
69
70impl<P: Fp4Config> CyclotomicMultSubgroup for Fp4<P> {
71    const INVERSE_IS_FAST: bool = true;
72    fn cyclotomic_inverse_in_place(&mut self) -> Option<&mut Self> {
73        self.is_zero().not().then(|| {
74            self.conjugate_in_place();
75            self
76        })
77    }
78}