snarkvm_curves/templates/bls12/
g2.rs

1// Copyright (c) 2019-2025 Provable Inc.
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use crate::{
17    templates::{
18        bls12::{Bls12Parameters, TwistType},
19        short_weierstrass_jacobian::{Affine, Projective},
20    },
21    traits::{AffineCurve, ShortWeierstrassParameters},
22};
23use snarkvm_fields::{Field, Fp2, One, Zero};
24use snarkvm_utilities::{ToBytes, bititerator::BitIteratorBE, serialize::*};
25
26use std::io::{Result as IoResult, Write};
27
28pub type G2Affine<P> = Affine<<P as Bls12Parameters>::G2Parameters>;
29pub type G2Projective<P> = Projective<<P as Bls12Parameters>::G2Parameters>;
30type CoeffTriplet<T> = (Fp2<T>, Fp2<T>, Fp2<T>);
31
32#[allow(clippy::derive_partial_eq_without_eq)]
33#[derive(Clone, Debug, PartialEq, Eq, Hash, CanonicalSerialize, CanonicalDeserialize)]
34pub struct G2Prepared<P: Bls12Parameters> {
35    // Stores the coefficients of the line evaluations as calculated in
36    // https://eprint.iacr.org/2013/722.pdf
37    pub ell_coeffs: Vec<CoeffTriplet<P::Fp2Params>>,
38    pub infinity: bool,
39}
40
41#[derive(Copy, Clone, Debug)]
42struct G2HomProjective<P: Bls12Parameters> {
43    x: Fp2<P::Fp2Params>,
44    y: Fp2<P::Fp2Params>,
45    z: Fp2<P::Fp2Params>,
46}
47
48impl<P: Bls12Parameters> Default for G2Prepared<P> {
49    fn default() -> Self {
50        Self::from_affine(G2Affine::<P>::prime_subgroup_generator())
51    }
52}
53
54impl<P: Bls12Parameters> ToBytes for G2Prepared<P> {
55    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
56        (self.ell_coeffs.len() as u32).write_le(&mut writer)?;
57        for coeff in &self.ell_coeffs {
58            coeff.0.write_le(&mut writer)?;
59            coeff.1.write_le(&mut writer)?;
60            coeff.2.write_le(&mut writer)?;
61        }
62        self.infinity.write_le(writer)
63    }
64}
65
66impl<P: Bls12Parameters> FromBytes for G2Prepared<P> {
67    fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
68        let ell_coeffs_len: u32 = FromBytes::read_le(&mut reader)?;
69        let mut ell_coeffs = Vec::with_capacity(ell_coeffs_len as usize);
70        for _ in 0..ell_coeffs_len {
71            let coeff_1: Fp2<P::Fp2Params> = FromBytes::read_le(&mut reader)?;
72            let coeff_2: Fp2<P::Fp2Params> = FromBytes::read_le(&mut reader)?;
73            let coeff_3: Fp2<P::Fp2Params> = FromBytes::read_le(&mut reader)?;
74            ell_coeffs.push((coeff_1, coeff_2, coeff_3));
75        }
76
77        let infinity: bool = FromBytes::read_le(&mut reader)?;
78
79        Ok(Self { ell_coeffs, infinity })
80    }
81}
82
83impl<P: Bls12Parameters> G2Prepared<P> {
84    pub fn is_zero(&self) -> bool {
85        self.infinity
86    }
87
88    pub fn from_affine(q: G2Affine<P>) -> Self {
89        if q.is_zero() {
90            return Self { ell_coeffs: vec![], infinity: true };
91        }
92
93        let mut r = G2HomProjective { x: q.x, y: q.y, z: Fp2::one() };
94
95        let bit_iterator = BitIteratorBE::new(P::X);
96        let mut ell_coeffs = Vec::with_capacity(bit_iterator.len() * 3 / 2);
97
98        // `one_half` = 1/2 in the field.
99        let one_half = P::Fp::half();
100
101        for i in bit_iterator.skip(1) {
102            ell_coeffs.push(doubling_step::<P>(&mut r, &one_half));
103
104            if i {
105                ell_coeffs.push(addition_step::<P>(&mut r, &q));
106            }
107        }
108
109        Self { ell_coeffs, infinity: false }
110    }
111}
112
113#[allow(clippy::many_single_char_names)]
114fn doubling_step<B: Bls12Parameters>(r: &mut G2HomProjective<B>, two_inv: &B::Fp) -> CoeffTriplet<B::Fp2Params> {
115    // Formula for line function when working with
116    // homogeneous projective coordinates.
117
118    let mut a = r.x * r.y;
119    a.mul_by_fp(two_inv);
120    let b = r.y.square();
121    let c = r.z.square();
122    let e = B::G2Parameters::WEIERSTRASS_B * (c.double() + c);
123    let f = e.double() + e;
124    let mut g = b + f;
125    g.mul_by_fp(two_inv);
126    let h = (r.y + r.z).square() - (b + c);
127    let i = e - b;
128    let j = r.x.square();
129    let e_square = e.square();
130
131    r.x = a * (b - f);
132    r.y = g.square() - (e_square.double() + e_square);
133    r.z = b * h;
134    match B::TWIST_TYPE {
135        TwistType::M => (i, j.double() + j, -h),
136        TwistType::D => (-h, j.double() + j, i),
137    }
138}
139
140#[allow(clippy::many_single_char_names)]
141fn addition_step<B: Bls12Parameters>(r: &mut G2HomProjective<B>, q: &G2Affine<B>) -> CoeffTriplet<B::Fp2Params> {
142    // Formula for line function when working with
143    // homogeneous projective coordinates.
144    let theta = r.y - (q.y * r.z);
145    let lambda = r.x - (q.x * r.z);
146    let c = theta.square();
147    let d = lambda.square();
148    let e = lambda * d;
149    let f = r.z * c;
150    let g = r.x * d;
151    let h = e + f - g.double();
152    r.x = lambda * h;
153    r.y = theta * (g - h) - (e * r.y);
154    r.z *= &e;
155    let j = theta * q.x - (lambda * q.y);
156
157    match B::TWIST_TYPE {
158        TwistType::M => (j, -theta, lambda),
159        TwistType::D => (lambda, -theta, j),
160    }
161}