|
| 1 | +use alloc::vec::Vec; |
| 2 | +use core::ops::{Mul, MulAssign, Neg}; |
| 3 | + |
| 4 | +use openvm_algebra_guest::{ |
| 5 | + field::{ComplexConjugate, FieldExtension}, |
| 6 | + DivAssignUnsafe, DivUnsafe, Field, |
| 7 | +}; |
| 8 | + |
| 9 | +use super::{Bls12_381, Fp, Fp2}; |
| 10 | +use crate::pairing::{fp12_invert_assign, PairingIntrinsics, SexticExtField}; |
| 11 | + |
| 12 | +pub type Fp12 = SexticExtField<Fp2>; |
| 13 | + |
| 14 | +impl 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 | + |
| 22 | +impl 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 | + |
| 43 | +impl 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. |
| 113 | +impl 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 | + |
| 126 | +impl<'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 | + |
| 133 | +impl<'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 | + |
| 141 | +impl MulAssign for Fp12 { |
| 142 | + #[inline(always)] |
| 143 | + fn mul_assign(&mut self, other: Self) { |
| 144 | + self.mul_assign(&other); |
| 145 | + } |
| 146 | +} |
| 147 | + |
| 148 | +impl 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 | + |
| 157 | +impl<'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 | + |
| 166 | +impl<'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 | + |
| 173 | +impl<'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 | + |
| 183 | +impl DivAssignUnsafe for Fp12 { |
| 184 | + #[inline(always)] |
| 185 | + fn div_assign_unsafe(&mut self, other: Self) { |
| 186 | + *self *= other.invert(); |
| 187 | + } |
| 188 | +} |
| 189 | + |
| 190 | +impl 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 | + |
| 199 | +impl<'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 | + |
| 208 | +impl Neg for Fp12 { |
| 209 | + type Output = Fp12; |
| 210 | + #[inline(always)] |
| 211 | + fn neg(self) -> Self::Output { |
| 212 | + Self::ZERO - &self |
| 213 | + } |
| 214 | +} |
0 commit comments