ark_ec/models/bls12/
g2.rs

1use ark_ff::{AdditiveGroup, BitIteratorBE, Field, Fp2};
2use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
3use ark_std::{vec::*, One};
4use educe::Educe;
5
6use crate::{
7    bls12::{Bls12Config, TwistType},
8    models::short_weierstrass::SWCurveConfig,
9    short_weierstrass::{Affine, Projective},
10    AffineRepr, CurveGroup,
11};
12
13pub type G2Affine<P> = Affine<<P as Bls12Config>::G2Config>;
14pub type G2Projective<P> = Projective<<P as Bls12Config>::G2Config>;
15
16#[derive(Educe, CanonicalSerialize, CanonicalDeserialize)]
17#[educe(Clone, Debug, PartialEq, Eq)]
18pub struct G2Prepared<P: Bls12Config> {
19    /// Stores the coefficients of the line evaluations as calculated in
20    /// <https://eprint.iacr.org/2013/722.pdf>
21    pub ell_coeffs: Vec<EllCoeff<P>>,
22    pub infinity: bool,
23}
24
25pub type EllCoeff<P> = (
26    Fp2<<P as Bls12Config>::Fp2Config>,
27    Fp2<<P as Bls12Config>::Fp2Config>,
28    Fp2<<P as Bls12Config>::Fp2Config>,
29);
30
31#[derive(Educe)]
32#[educe(Clone, Copy, Debug)]
33pub struct G2HomProjective<P: Bls12Config> {
34    x: Fp2<P::Fp2Config>,
35    y: Fp2<P::Fp2Config>,
36    z: Fp2<P::Fp2Config>,
37}
38
39impl<P: Bls12Config> Default for G2Prepared<P> {
40    fn default() -> Self {
41        Self::from(G2Affine::<P>::generator())
42    }
43}
44
45impl<P: Bls12Config> From<G2Affine<P>> for G2Prepared<P> {
46    fn from(q: G2Affine<P>) -> Self {
47        let two_inv = P::Fp::one().double().inverse().unwrap();
48        let zero = G2Prepared {
49            ell_coeffs: vec![],
50            infinity: true,
51        };
52        q.xy().map_or(zero, |(q_x, q_y)| {
53            let mut ell_coeffs = vec![];
54            let mut r = G2HomProjective::<P> {
55                x: q_x,
56                y: q_y,
57                z: Fp2::one(),
58            };
59
60            for i in BitIteratorBE::new(P::X).skip(1) {
61                ell_coeffs.push(r.double_in_place(&two_inv));
62
63                if i {
64                    ell_coeffs.push(r.add_in_place(&q));
65                }
66            }
67
68            Self {
69                ell_coeffs,
70                infinity: false,
71            }
72        })
73    }
74}
75
76impl<P: Bls12Config> From<G2Projective<P>> for G2Prepared<P> {
77    fn from(q: G2Projective<P>) -> Self {
78        q.into_affine().into()
79    }
80}
81
82impl<'a, P: Bls12Config> From<&'a G2Affine<P>> for G2Prepared<P> {
83    fn from(other: &'a G2Affine<P>) -> Self {
84        (*other).into()
85    }
86}
87
88impl<'a, P: Bls12Config> From<&'a G2Projective<P>> for G2Prepared<P> {
89    fn from(q: &'a G2Projective<P>) -> Self {
90        q.into_affine().into()
91    }
92}
93
94impl<P: Bls12Config> G2Prepared<P> {
95    pub fn is_zero(&self) -> bool {
96        self.infinity
97    }
98}
99
100impl<P: Bls12Config> G2HomProjective<P> {
101    fn double_in_place(&mut self, two_inv: &P::Fp) -> EllCoeff<P> {
102        // Formula for line function when working with
103        // homogeneous projective coordinates.
104
105        let mut a = self.x * &self.y;
106        a.mul_assign_by_fp(two_inv);
107        let b = self.y.square();
108        let c = self.z.square();
109        let e = P::G2Config::COEFF_B * &(c.double() + &c);
110        let f = e.double() + &e;
111        let mut g = b + &f;
112        g.mul_assign_by_fp(two_inv);
113        let h = (self.y + &self.z).square() - &(b + &c);
114        let i = e - &b;
115        let j = self.x.square();
116        let e_square = e.square();
117
118        self.x = a * &(b - &f);
119        self.y = g.square() - &(e_square.double() + &e_square);
120        self.z = b * &h;
121        match P::TWIST_TYPE {
122            TwistType::M => (i, j.double() + &j, -h),
123            TwistType::D => (-h, j.double() + &j, i),
124        }
125    }
126
127    fn add_in_place(&mut self, q: &G2Affine<P>) -> EllCoeff<P> {
128        let (qx, qy) = q.xy().unwrap();
129        // Formula for line function when working with
130        // homogeneous projective coordinates.
131        let theta = self.y - &(qy * &self.z);
132        let lambda = self.x - &(qx * &self.z);
133        let c = theta.square();
134        let d = lambda.square();
135        let e = lambda * &d;
136        let f = self.z * &c;
137        let g = self.x * &d;
138        let h = e + &f - &g.double();
139        self.x = lambda * &h;
140        self.y = theta * &(g - &h) - &(e * &self.y);
141        self.z *= &e;
142        let j = theta * &qx - &(lambda * &qy);
143
144        match P::TWIST_TYPE {
145            TwistType::M => (j, -theta, lambda),
146            TwistType::D => (lambda, -theta, j),
147        }
148    }
149}