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