openvm_pairing_guest/bn254/
fp2.rs

1use alloc::vec::Vec;
2use core::ops::Neg;
3
4use openvm_algebra_complex_macros::{complex_declare, complex_impl_field};
5use openvm_algebra_guest::{field::FieldExtension, Field, IntMod};
6
7use super::Fp;
8
9// The struct name needs to be globally unique for linking purposes.
10// The mod_type is a path used only in the struct definition.
11complex_declare! {
12    Bn254Fp2 { mod_type = Fp }
13}
14
15complex_impl_field! {
16    Bn254Fp2,
17}
18
19pub type Fp2 = Bn254Fp2;
20
21impl FieldExtension<Fp> for Fp2 {
22    const D: usize = 2;
23    type Coeffs = [Fp; 2];
24
25    fn from_coeffs([c0, c1]: Self::Coeffs) -> Self {
26        Self { c0, c1 }
27    }
28
29    fn from_bytes(bytes: &[u8]) -> Self {
30        assert_eq!(bytes.len(), 64);
31        Self::from_coeffs([
32            Fp::from_const_bytes(bytes[0..32].try_into().unwrap()),
33            Fp::from_const_bytes(bytes[32..64].try_into().unwrap()),
34        ])
35    }
36
37    fn to_coeffs(self) -> Self::Coeffs {
38        [self.c0, self.c1]
39    }
40
41    fn to_bytes(&self) -> Vec<u8> {
42        let mut bytes = Vec::with_capacity(64);
43        bytes.extend_from_slice(self.c0.as_le_bytes());
44        bytes.extend_from_slice(self.c1.as_le_bytes());
45        bytes
46    }
47
48    fn embed(c0: Fp) -> Self {
49        Self {
50            c0,
51            c1: <Fp as Field>::ZERO,
52        }
53    }
54
55    fn frobenius_map(&self, power: usize) -> Self {
56        if power % 2 == 0 {
57            self.clone()
58        } else {
59            Self {
60                c0: self.c0.clone(),
61                c1: (&self.c1).neg(),
62            }
63        }
64    }
65
66    fn mul_base(&self, rhs: &Fp) -> Self {
67        Self {
68            c0: &self.c0 * rhs,
69            c1: &self.c1 * rhs,
70        }
71    }
72}