openvm_pairing_guest/bls12_381/
fp12.rs

1use alloc::vec::Vec;
2use core::ops::{Mul, MulAssign, Neg};
3
4use openvm_algebra_guest::{
5    field::{ComplexConjugate, FieldExtension},
6    DivAssignUnsafe, DivUnsafe, Field,
7};
8
9use super::{Bls12_381, Fp, Fp2};
10use crate::pairing::{fp12_invert_assign, PairingIntrinsics, SexticExtField};
11
12pub type Fp12 = SexticExtField<Fp2>;
13
14impl Fp12 {
15    pub fn invert(&self) -> Self {
16        let mut s = self.clone();
17        fp12_invert_assign::<Fp, Fp2>(&mut s.c, &Bls12_381::XI);
18        s
19    }
20}
21
22impl Field for Fp12 {
23    type SelfRef<'a> = &'a Self;
24    const ZERO: Self = Self::new([Fp2::ZERO; 6]);
25    const ONE: Self = Self::new([
26        Fp2::ONE,
27        Fp2::ZERO,
28        Fp2::ZERO,
29        Fp2::ZERO,
30        Fp2::ZERO,
31        Fp2::ZERO,
32    ]);
33
34    fn double_assign(&mut self) {
35        *self += self.clone();
36    }
37
38    fn square_assign(&mut self) {
39        *self *= self.clone();
40    }
41}
42
43impl FieldExtension<Fp2> for Fp12 {
44    const D: usize = 6;
45    type Coeffs = [Fp2; 6];
46
47    fn from_coeffs(coeffs: Self::Coeffs) -> Self {
48        Self::new(coeffs)
49    }
50
51    fn from_bytes(bytes: &[u8]) -> Self {
52        assert_eq!(bytes.len(), 576);
53        Self::from_coeffs([
54            Fp2::from_bytes(&bytes[0..96]),
55            Fp2::from_bytes(&bytes[96..192]),
56            Fp2::from_bytes(&bytes[192..288]),
57            Fp2::from_bytes(&bytes[288..384]),
58            Fp2::from_bytes(&bytes[384..480]),
59            Fp2::from_bytes(&bytes[480..576]),
60        ])
61    }
62
63    fn to_coeffs(self) -> Self::Coeffs {
64        self.c
65    }
66
67    fn to_bytes(&self) -> Vec<u8> {
68        let mut bytes = Vec::with_capacity(576);
69        for coeff in self.clone().to_coeffs() {
70            bytes.extend_from_slice(&coeff.to_bytes());
71        }
72        bytes
73    }
74
75    fn embed(c0: Fp2) -> Self {
76        Self::new([c0, Fp2::ZERO, Fp2::ZERO, Fp2::ZERO, Fp2::ZERO, Fp2::ZERO])
77    }
78
79    /// We assume that the frobenius map power is < 12
80    fn frobenius_map(&self, power: usize) -> Self {
81        if power & 1 != 0 {
82            let c0 = self.c[0].clone().conjugate();
83            let c1 = self.c[1].clone().conjugate() * &Bls12_381::FROBENIUS_COEFFS[power][0];
84            let c2 = self.c[2].clone().conjugate() * &Bls12_381::FROBENIUS_COEFFS[power][1];
85            let c3 = self.c[3].clone().conjugate() * &Bls12_381::FROBENIUS_COEFFS[power][2];
86            let c4 = self.c[4].clone().conjugate() * &Bls12_381::FROBENIUS_COEFFS[power][3];
87            let c5 = self.c[5].clone().conjugate() * &Bls12_381::FROBENIUS_COEFFS[power][4];
88            Self::new([c0, c1, c2, c3, c4, c5])
89        } else {
90            let c0 = self.c[0].clone();
91            let c1 = &self.c[1] * &Bls12_381::FROBENIUS_COEFFS[power][0];
92            let c2 = &self.c[2] * &Bls12_381::FROBENIUS_COEFFS[power][1];
93            let c3 = &self.c[3] * &Bls12_381::FROBENIUS_COEFFS[power][2];
94            let c4 = &self.c[4] * &Bls12_381::FROBENIUS_COEFFS[power][3];
95            let c5 = &self.c[5] * &Bls12_381::FROBENIUS_COEFFS[power][4];
96            Self::new([c0, c1, c2, c3, c4, c5])
97        }
98    }
99
100    fn mul_base(&self, rhs: &Fp2) -> Self {
101        Self::new([
102            &self.c[0] * rhs,
103            &self.c[1] * rhs,
104            &self.c[2] * rhs,
105            &self.c[3] * rhs,
106            &self.c[4] * rhs,
107            &self.c[5] * rhs,
108        ])
109    }
110}
111
112// This is ambiguous. It is conjugation for Fp12 over Fp6.
113impl ComplexConjugate for Fp12 {
114    fn conjugate(self) -> Self {
115        let [c0, c1, c2, c3, c4, c5] = self.c;
116        Self::new([c0, -c1, c2, -c3, c4, -c5])
117    }
118
119    fn conjugate_assign(&mut self) {
120        self.c[1].neg_assign();
121        self.c[3].neg_assign();
122        self.c[5].neg_assign();
123    }
124}
125
126impl<'a> MulAssign<&'a Fp12> for Fp12 {
127    #[inline(always)]
128    fn mul_assign(&mut self, other: &'a Fp12) {
129        *self = crate::pairing::sextic_tower_mul(self, other, &Bls12_381::XI);
130    }
131}
132
133impl<'a> Mul<&'a Fp12> for &'a Fp12 {
134    type Output = Fp12;
135    #[inline(always)]
136    fn mul(self, other: &'a Fp12) -> Self::Output {
137        crate::pairing::sextic_tower_mul(self, other, &Bls12_381::XI)
138    }
139}
140
141impl MulAssign for Fp12 {
142    #[inline(always)]
143    fn mul_assign(&mut self, other: Self) {
144        self.mul_assign(&other);
145    }
146}
147
148impl Mul for Fp12 {
149    type Output = Self;
150    #[inline(always)]
151    fn mul(mut self, other: Self) -> Self::Output {
152        self *= other;
153        self
154    }
155}
156
157impl<'a> Mul<&'a Fp12> for Fp12 {
158    type Output = Self;
159    #[inline(always)]
160    fn mul(mut self, other: &'a Fp12) -> Self::Output {
161        self *= other;
162        self
163    }
164}
165
166impl<'a> DivAssignUnsafe<&'a Fp12> for Fp12 {
167    #[inline(always)]
168    fn div_assign_unsafe(&mut self, other: &'a Fp12) {
169        *self *= other.invert();
170    }
171}
172
173impl<'a> DivUnsafe<&'a Fp12> for &'a Fp12 {
174    type Output = Fp12;
175    #[inline(always)]
176    fn div_unsafe(self, other: &'a Fp12) -> Self::Output {
177        let mut res = self.clone();
178        res.div_assign_unsafe(other);
179        res
180    }
181}
182
183impl DivAssignUnsafe for Fp12 {
184    #[inline(always)]
185    fn div_assign_unsafe(&mut self, other: Self) {
186        *self *= other.invert();
187    }
188}
189
190impl DivUnsafe for Fp12 {
191    type Output = Self;
192    #[inline(always)]
193    fn div_unsafe(mut self, other: Self) -> Self::Output {
194        self.div_assign_unsafe(other);
195        self
196    }
197}
198
199impl<'a> DivUnsafe<&'a Fp12> for Fp12 {
200    type Output = Self;
201    #[inline(always)]
202    fn div_unsafe(mut self, other: &'a Fp12) -> Self::Output {
203        self.div_assign_unsafe(other);
204        self
205    }
206}
207
208impl Neg for Fp12 {
209    type Output = Fp12;
210    #[inline(always)]
211    fn neg(self) -> Self::Output {
212        Self::ZERO - &self
213    }
214}