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