snarkvm_curves/templates/bls12/
g2.rs1use 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 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 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 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 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}