arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
ark-r1cs-std/src/groups/curves/short_weierstrass/bls12/mod.rs
src/groups/curves/short_weierstrass/bls12/mod.rsRaw
  1use ark_ec::{
  2    bls12::{Bls12Parameters, G1Prepared, G2Prepared, TwistType},
  3    short_weierstrass::Affine as GroupAffine,
  4};
  5use ark_ff::{BitIteratorBE, Field, One};
  6use ark_relations::r1cs::{Namespace, SynthesisError};
  7
  8use crate::{
  9    fields::{fp::FpVar, fp2::Fp2Var, FieldVar},
 10    groups::curves::short_weierstrass::*,
 11    Vec,
 12};
 13use core::fmt::Debug;
 14
 15/// Represents a projective point in G1.
 16pub type G1Var<P> =
 17    ProjectiveVar<<P as Bls12Parameters>::G1Parameters, FpVar<<P as Bls12Parameters>::Fp>>;
 18
 19/// Represents an affine point on G1. Should be used only for comparison and
 20/// when a canonical representation of a point is required, and not for
 21/// arithmetic.
 22pub type G1AffineVar<P> =
 23    AffineVar<<P as Bls12Parameters>::G1Parameters, FpVar<<P as Bls12Parameters>::Fp>>;
 24
 25/// Represents a projective point in G2.
 26pub type G2Var<P> = ProjectiveVar<<P as Bls12Parameters>::G2Parameters, Fp2G<P>>;
 27/// Represents an affine point on G2. Should be used only for comparison and
 28/// when a canonical representation of a point is required, and not for
 29/// arithmetic.
 30pub type G2AffineVar<P> = AffineVar<<P as Bls12Parameters>::G2Parameters, Fp2G<P>>;
 31
 32/// Represents the cached precomputation that can be performed on a G1 element
 33/// which enables speeding up pairing computation.
 34#[derive(Derivative)]
 35#[derivative(Clone(bound = "G1Var<P>: Clone"), Debug(bound = "G1Var<P>: Debug"))]
 36pub struct G1PreparedVar<P: Bls12Parameters>(pub AffineVar<P::G1Parameters, FpVar<P::Fp>>);
 37
 38impl<P: Bls12Parameters> G1PreparedVar<P> {
 39    /// Returns the value assigned to `self` in the underlying constraint
 40    /// system.
 41    pub fn value(&self) -> Result<G1Prepared<P>, SynthesisError> {
 42        let x = self.0.x.value()?;
 43        let y = self.0.y.value()?;
 44        let infinity = self.0.infinity.value()?;
 45        let g = infinity
 46            .then_some(GroupAffine::zero())
 47            .unwrap_or(GroupAffine::new(x, y))
 48            .into();
 49        Ok(g)
 50    }
 51
 52    /// Constructs `Self` from a `G1Var`.
 53    pub fn from_group_var(q: &G1Var<P>) -> Result<Self, SynthesisError> {
 54        let g = q.to_affine()?;
 55        Ok(Self(g))
 56    }
 57}
 58
 59impl<P: Bls12Parameters> AllocVar<G1Prepared<P>, P::Fp> for G1PreparedVar<P> {
 60    fn new_variable<T: Borrow<G1Prepared<P>>>(
 61        cs: impl Into<Namespace<P::Fp>>,
 62        f: impl FnOnce() -> Result<T, SynthesisError>,
 63        mode: AllocationMode,
 64    ) -> Result<Self, SynthesisError> {
 65        let ns = cs.into();
 66        let cs = ns.cs();
 67        let g1_prep = f().map(|b| b.borrow().0);
 68
 69        let x = FpVar::new_variable(ark_relations::ns!(cs, "x"), || g1_prep.map(|g| g.x), mode)?;
 70        let y = FpVar::new_variable(ark_relations::ns!(cs, "y"), || g1_prep.map(|g| g.y), mode)?;
 71        let infinity = Boolean::new_variable(
 72            ark_relations::ns!(cs, "inf"),
 73            || g1_prep.map(|g| g.infinity),
 74            mode,
 75        )?;
 76        let g = AffineVar::new(x, y, infinity);
 77        Ok(Self(g))
 78    }
 79}
 80
 81impl<P: Bls12Parameters> ToBytesGadget<P::Fp> for G1PreparedVar<P> {
 82    #[inline]
 83    #[tracing::instrument(target = "r1cs")]
 84    fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
 85        let mut bytes = self.0.x.to_bytes()?;
 86        let y_bytes = self.0.y.to_bytes()?;
 87        let inf_bytes = self.0.infinity.to_bytes()?;
 88        bytes.extend_from_slice(&y_bytes);
 89        bytes.extend_from_slice(&inf_bytes);
 90        Ok(bytes)
 91    }
 92
 93    #[tracing::instrument(target = "r1cs")]
 94    fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
 95        let mut bytes = self.0.x.to_non_unique_bytes()?;
 96        let y_bytes = self.0.y.to_non_unique_bytes()?;
 97        let inf_bytes = self.0.infinity.to_non_unique_bytes()?;
 98        bytes.extend_from_slice(&y_bytes);
 99        bytes.extend_from_slice(&inf_bytes);
100        Ok(bytes)
101    }
102}
103
104type Fp2G<P> = Fp2Var<<P as Bls12Parameters>::Fp2Config>;
105type LCoeff<P> = (Fp2G<P>, Fp2G<P>);
106/// Represents the cached precomputation that can be performed on a G2 element
107/// which enables speeding up pairing computation.
108#[derive(Derivative)]
109#[derivative(
110    Clone(bound = "Fp2Var<P::Fp2Config>: Clone"),
111    Debug(bound = "Fp2Var<P::Fp2Config>: Debug")
112)]
113pub struct G2PreparedVar<P: Bls12Parameters> {
114    #[doc(hidden)]
115    pub ell_coeffs: Vec<LCoeff<P>>,
116}
117
118impl<P: Bls12Parameters> AllocVar<G2Prepared<P>, P::Fp> for G2PreparedVar<P> {
119    #[tracing::instrument(target = "r1cs", skip(cs, f, mode))]
120    fn new_variable<T: Borrow<G2Prepared<P>>>(
121        cs: impl Into<Namespace<P::Fp>>,
122        f: impl FnOnce() -> Result<T, SynthesisError>,
123        mode: AllocationMode,
124    ) -> Result<Self, SynthesisError> {
125        let ns = cs.into();
126        let cs = ns.cs();
127        let g2_prep = f().map(|b| {
128            let projective_coeffs = &b.borrow().ell_coeffs;
129            match P::TWIST_TYPE {
130                TwistType::M => {
131                    let mut z_s = projective_coeffs
132                        .iter()
133                        .map(|(_, _, z)| *z)
134                        .collect::<Vec<_>>();
135                    ark_ff::fields::batch_inversion(&mut z_s);
136                    projective_coeffs
137                        .iter()
138                        .zip(z_s)
139                        .map(|((x, y, _), z_inv)| (*x * &z_inv, *y * &z_inv))
140                        .collect::<Vec<_>>()
141                },
142                TwistType::D => {
143                    let mut z_s = projective_coeffs
144                        .iter()
145                        .map(|(z, ..)| *z)
146                        .collect::<Vec<_>>();
147                    ark_ff::fields::batch_inversion(&mut z_s);
148                    projective_coeffs
149                        .iter()
150                        .zip(z_s)
151                        .map(|((_, x, y), z_inv)| (*x * &z_inv, *y * &z_inv))
152                        .collect::<Vec<_>>()
153                },
154            }
155        });
156
157        let l = Vec::new_variable(
158            ark_relations::ns!(cs, "l"),
159            || {
160                g2_prep
161                    .clone()
162                    .map(|c| c.iter().map(|(l, _)| *l).collect::<Vec<_>>())
163            },
164            mode,
165        )?;
166        let r = Vec::new_variable(
167            ark_relations::ns!(cs, "r"),
168            || g2_prep.map(|c| c.iter().map(|(_, r)| *r).collect::<Vec<_>>()),
169            mode,
170        )?;
171        let ell_coeffs = l.into_iter().zip(r).collect();
172        Ok(Self { ell_coeffs })
173    }
174}
175
176impl<P: Bls12Parameters> ToBytesGadget<P::Fp> for G2PreparedVar<P> {
177    #[inline]
178    #[tracing::instrument(target = "r1cs")]
179    fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
180        let mut bytes = Vec::new();
181        for coeffs in &self.ell_coeffs {
182            bytes.extend_from_slice(&coeffs.0.to_bytes()?);
183            bytes.extend_from_slice(&coeffs.1.to_bytes()?);
184        }
185        Ok(bytes)
186    }
187
188    #[tracing::instrument(target = "r1cs")]
189    fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
190        let mut bytes = Vec::new();
191        for coeffs in &self.ell_coeffs {
192            bytes.extend_from_slice(&coeffs.0.to_non_unique_bytes()?);
193            bytes.extend_from_slice(&coeffs.1.to_non_unique_bytes()?);
194        }
195        Ok(bytes)
196    }
197}
198
199impl<P: Bls12Parameters> G2PreparedVar<P> {
200    /// Constructs `Self` from a `G2Var`.
201    #[tracing::instrument(target = "r1cs")]
202    pub fn from_group_var(q: &G2Var<P>) -> Result<Self, SynthesisError> {
203        let q = q.to_affine()?;
204        let two_inv = P::Fp::one().double().inverse().unwrap();
205        // Enforce that `q` is not the point at infinity.
206        q.infinity.enforce_not_equal(&Boolean::Constant(true))?;
207        let mut ell_coeffs = vec![];
208        let mut r = q.clone();
209
210        for i in BitIteratorBE::new(P::X).skip(1) {
211            ell_coeffs.push(Self::double(&mut r, &two_inv)?);
212
213            if i {
214                ell_coeffs.push(Self::add(&mut r, &q)?);
215            }
216        }
217
218        Ok(Self { ell_coeffs })
219    }
220
221    #[tracing::instrument(target = "r1cs")]
222    fn double(r: &mut G2AffineVar<P>, two_inv: &P::Fp) -> Result<LCoeff<P>, SynthesisError> {
223        let a = r.y.inverse()?;
224        let mut b = r.x.square()?;
225        let b_tmp = b.clone();
226        b.mul_assign_by_base_field_constant(*two_inv);
227        b += &b_tmp;
228
229        let c = &a * &b;
230        let d = r.x.double()?;
231        let x3 = c.square()? - &d;
232        let e = &c * &r.x - &r.y;
233        let c_x3 = &c * &x3;
234        let y3 = &e - &c_x3;
235        let mut f = c;
236        f.negate_in_place()?;
237        r.x = x3;
238        r.y = y3;
239        match P::TWIST_TYPE {
240            TwistType::M => Ok((e, f)),
241            TwistType::D => Ok((f, e)),
242        }
243    }
244
245    #[tracing::instrument(target = "r1cs")]
246    fn add(r: &mut G2AffineVar<P>, q: &G2AffineVar<P>) -> Result<LCoeff<P>, SynthesisError> {
247        let a = (&q.x - &r.x).inverse()?;
248        let b = &q.y - &r.y;
249        let c = &a * &b;
250        let d = &r.x + &q.x;
251        let x3 = c.square()? - &d;
252
253        let e = (&r.x - &x3) * &c;
254        let y3 = e - &r.y;
255        let g = &c * &r.x - &r.y;
256        let mut f = c;
257        f.negate_in_place()?;
258        r.x = x3;
259        r.y = y3;
260        match P::TWIST_TYPE {
261            TwistType::M => Ok((g, f)),
262            TwistType::D => Ok((f, g)),
263        }
264    }
265}