openvm_pairing_guest/bn254/
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::{Bn254, 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, &Bn254::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(), 384);
53        Self::from_coeffs([
54            Fp2::from_bytes(&bytes[0..64]),
55            Fp2::from_bytes(&bytes[64..128]),
56            Fp2::from_bytes(&bytes[128..192]),
57            Fp2::from_bytes(&bytes[192..256]),
58            Fp2::from_bytes(&bytes[256..320]),
59            Fp2::from_bytes(&bytes[320..384]),
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(384);
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() * &Bn254::FROBENIUS_COEFFS[power][0];
84            let c2 = self.c[2].clone().conjugate() * &Bn254::FROBENIUS_COEFFS[power][1];
85            let c3 = self.c[3].clone().conjugate() * &Bn254::FROBENIUS_COEFFS[power][2];
86            let c4 = self.c[4].clone().conjugate() * &Bn254::FROBENIUS_COEFFS[power][3];
87            let c5 = self.c[5].clone().conjugate() * &Bn254::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] * &Bn254::FROBENIUS_COEFFS[power][0];
92            let c2 = &self.c[2] * &Bn254::FROBENIUS_COEFFS[power][1];
93            let c3 = &self.c[3] * &Bn254::FROBENIUS_COEFFS[power][2];
94            let c4 = &self.c[4] * &Bn254::FROBENIUS_COEFFS[power][3];
95            let c5 = &self.c[5] * &Bn254::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    #[inline(always)]
115    fn conjugate(self) -> Self {
116        let [c0, c1, c2, c3, c4, c5] = self.c;
117        Self::new([c0, -c1, c2, -c3, c4, -c5])
118    }
119
120    fn conjugate_assign(&mut self) {
121        self.c[1].neg_assign();
122        self.c[3].neg_assign();
123        self.c[5].neg_assign();
124    }
125}
126
127impl<'a> MulAssign<&'a Fp12> for Fp12 {
128    #[inline(always)]
129    fn mul_assign(&mut self, other: &'a Fp12) {
130        *self = crate::pairing::sextic_tower_mul(self, other, &Bn254::XI);
131    }
132}
133
134impl<'a> Mul<&'a Fp12> for &'a Fp12 {
135    type Output = Fp12;
136    #[inline(always)]
137    fn mul(self, other: &'a Fp12) -> Self::Output {
138        crate::pairing::sextic_tower_mul(self, other, &Bn254::XI)
139    }
140}
141
142impl MulAssign for Fp12 {
143    #[inline(always)]
144    fn mul_assign(&mut self, other: Self) {
145        self.mul_assign(&other);
146    }
147}
148
149impl Mul for Fp12 {
150    type Output = Self;
151    #[inline(always)]
152    fn mul(mut self, other: Self) -> Self::Output {
153        self *= other;
154        self
155    }
156}
157
158impl<'a> Mul<&'a Fp12> for Fp12 {
159    type Output = Self;
160    #[inline(always)]
161    fn mul(mut self, other: &'a Fp12) -> Fp12 {
162        self *= other;
163        self
164    }
165}
166
167impl<'a> DivAssignUnsafe<&'a Fp12> for Fp12 {
168    #[inline(always)]
169    fn div_assign_unsafe(&mut self, other: &'a Fp12) {
170        *self *= other.invert();
171    }
172}
173
174impl<'a> DivUnsafe<&'a Fp12> for &'a Fp12 {
175    type Output = Fp12;
176    #[inline(always)]
177    fn div_unsafe(self, other: &'a Fp12) -> Self::Output {
178        let mut res = self.clone();
179        res.div_assign_unsafe(other);
180        res
181    }
182}
183
184impl DivAssignUnsafe for Fp12 {
185    #[inline(always)]
186    fn div_assign_unsafe(&mut self, other: Self) {
187        *self *= other.invert();
188    }
189}
190
191impl DivUnsafe for Fp12 {
192    type Output = Self;
193    #[inline(always)]
194    fn div_unsafe(mut self, other: Self) -> Self::Output {
195        self.div_assign_unsafe(other);
196        self
197    }
198}
199
200impl<'a> DivUnsafe<&'a Fp12> for Fp12 {
201    type Output = Self;
202    #[inline(always)]
203    fn div_unsafe(mut self, other: &'a Fp12) -> Self::Output {
204        self.div_assign_unsafe(other);
205        self
206    }
207}
208
209impl Neg for Fp12 {
210    type Output = Fp12;
211    #[inline(always)]
212    fn neg(self) -> Self::Output {
213        Self::ZERO - &self
214    }
215}