openvm_pairing_guest/bls12_381/
fp2.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
use alloc::vec::Vec;
use core::ops::Neg;

use openvm_algebra_complex_macros::{complex_declare, complex_impl_field};
use openvm_algebra_guest::{field::FieldExtension, DivUnsafe, Field, IntMod};

use super::Fp;

// The struct name needs to be globally unique for linking purposes.
// The mod_type is a path used only in the struct definition.
complex_declare! {
    Bls12_381Fp2 { mod_type = Fp }
}

complex_impl_field! {
    Bls12_381Fp2,
}

pub type Fp2 = Bls12_381Fp2;

impl FieldExtension<Fp> for Fp2 {
    const D: usize = 2;
    type Coeffs = [Fp; 2];

    fn from_coeffs([c0, c1]: Self::Coeffs) -> Self {
        Self { c0, c1 }
    }

    fn from_bytes(bytes: &[u8]) -> Self {
        assert_eq!(bytes.len(), 96);
        Self::from_coeffs([
            Fp::from_const_bytes(bytes[0..48].try_into().unwrap()),
            Fp::from_const_bytes(bytes[48..96].try_into().unwrap()),
        ])
    }

    fn to_coeffs(self) -> Self::Coeffs {
        [self.c0, self.c1]
    }

    fn to_bytes(&self) -> Vec<u8> {
        let mut bytes = Vec::with_capacity(96);
        bytes.extend_from_slice(self.c0.as_le_bytes());
        bytes.extend_from_slice(self.c1.as_le_bytes());
        bytes
    }

    fn embed(base_elem: Fp) -> Self {
        Self {
            c0: base_elem,
            c1: <Fp as Field>::ZERO,
        }
    }

    fn frobenius_map(&self, power: usize) -> Self {
        if power % 2 == 0 {
            self.clone()
        } else {
            Self {
                c0: self.c0.clone(),
                c1: (&self.c1).neg(),
            }
        }
    }

    fn mul_base(&self, rhs: &Fp) -> Self {
        Self {
            c0: &self.c0 * rhs,
            c1: &self.c1 * rhs,
        }
    }
}