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