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 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
112impl 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}