arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
ark-r1cs-std/r1cs-std/src/groups/curves/short_weierstrass/mnt6/mod.rs
r1cs-std/src/groups/curves/short_weierstrass/mnt6/mod.rsRaw
  1use algebra::{
  2    curves::mnt6::{
  3        g2::{AteAdditionCoefficients, AteDoubleCoefficients},
  4        G1Prepared, G2Prepared, MNT6Parameters,
  5    },
  6    Field,
  7};
  8use r1cs_core::{Namespace, SynthesisError};
  9
 10use crate::{
 11    fields::{fp::FpVar, fp3::Fp3Var, FieldVar},
 12    groups::curves::short_weierstrass::ProjectiveVar,
 13    pairing::mnt6::PairingVar,
 14    prelude::*,
 15    Vec,
 16};
 17use core::borrow::Borrow;
 18
 19/// Represents a projective point in G1.
 20pub type G1Var<P> =
 21    ProjectiveVar<<P as MNT6Parameters>::G1Parameters, FpVar<<P as MNT6Parameters>::Fp>>;
 22
 23/// Represents a projective point in G2.
 24pub type G2Var<P> = ProjectiveVar<<P as MNT6Parameters>::G2Parameters, Fp3G<P>>;
 25
 26/// Represents the cached precomputation that can be performed on a G1 element
 27/// which enables speeding up pairing computation.
 28#[derive(Derivative)]
 29#[derivative(Clone(bound = "P: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))]
 30pub struct G1PreparedVar<P: MNT6Parameters> {
 31    #[doc(hidden)]
 32    pub x: FpVar<P::Fp>,
 33    #[doc(hidden)]
 34    pub y: FpVar<P::Fp>,
 35    #[doc(hidden)]
 36    pub x_twist: Fp3Var<P::Fp3Params>,
 37    #[doc(hidden)]
 38    pub y_twist: Fp3Var<P::Fp3Params>,
 39}
 40
 41impl<P: MNT6Parameters> G1PreparedVar<P> {
 42    /// Returns the value assigned to `self` in the underlying constraint system.
 43    pub fn value(&self) -> Result<G1Prepared<P>, SynthesisError> {
 44        let x = self.x.value()?;
 45        let y = self.y.value()?;
 46        let x_twist = self.x_twist.value()?;
 47        let y_twist = self.y_twist.value()?;
 48        Ok(G1Prepared {
 49            x,
 50            y,
 51            x_twist,
 52            y_twist,
 53        })
 54    }
 55
 56    /// Constructs `Self` from a `G1Var`.
 57    #[tracing::instrument(target = "r1cs")]
 58    pub fn from_group_var(q: &G1Var<P>) -> Result<Self, SynthesisError> {
 59        let q = q.to_affine()?;
 60        let zero = FpVar::<P::Fp>::zero();
 61        let x_twist = Fp3Var::new(q.x.clone(), zero.clone(), zero.clone()) * P::TWIST;
 62        let y_twist = Fp3Var::new(q.y.clone(), zero.clone(), zero.clone()) * P::TWIST;
 63        let result = G1PreparedVar {
 64            x: q.x.clone(),
 65            y: q.y.clone(),
 66            x_twist,
 67            y_twist,
 68        };
 69        Ok(result)
 70    }
 71}
 72
 73impl<P: MNT6Parameters> AllocVar<G1Prepared<P>, P::Fp> for G1PreparedVar<P> {
 74    #[tracing::instrument(target = "r1cs", skip(cs, f))]
 75    fn new_variable<T: Borrow<G1Prepared<P>>>(
 76        cs: impl Into<Namespace<P::Fp>>,
 77        f: impl FnOnce() -> Result<T, SynthesisError>,
 78        mode: AllocationMode,
 79    ) -> Result<Self, SynthesisError> {
 80        let ns = cs.into();
 81        let cs = ns.cs();
 82
 83        let g1_prep = f().map(|b| *b.borrow());
 84
 85        let x = FpVar::new_variable(r1cs_core::ns!(cs, "x"), || g1_prep.map(|g| g.x), mode)?;
 86        let y = FpVar::new_variable(r1cs_core::ns!(cs, "y"), || g1_prep.map(|g| g.y), mode)?;
 87        let x_twist = Fp3Var::new_variable(
 88            r1cs_core::ns!(cs, "x_twist"),
 89            || g1_prep.map(|g| g.x_twist),
 90            mode,
 91        )?;
 92        let y_twist = Fp3Var::new_variable(
 93            r1cs_core::ns!(cs, "y_twist"),
 94            || g1_prep.map(|g| g.y_twist),
 95            mode,
 96        )?;
 97        Ok(Self {
 98            x,
 99            y,
100            x_twist,
101            y_twist,
102        })
103    }
104}
105
106impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for G1PreparedVar<P> {
107    #[inline]
108    #[tracing::instrument(target = "r1cs")]
109    fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
110        let mut x = self.x.to_bytes()?;
111        let mut y = self.y.to_bytes()?;
112        let mut x_twist = self.x_twist.to_bytes()?;
113        let mut y_twist = self.y_twist.to_bytes()?;
114
115        x.append(&mut y);
116        x.append(&mut x_twist);
117        x.append(&mut y_twist);
118        Ok(x)
119    }
120
121    #[tracing::instrument(target = "r1cs")]
122    fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
123        let mut x = self.x.to_non_unique_bytes()?;
124        let mut y = self.y.to_non_unique_bytes()?;
125        let mut x_twist = self.x_twist.to_non_unique_bytes()?;
126        let mut y_twist = self.y_twist.to_non_unique_bytes()?;
127
128        x.append(&mut y);
129        x.append(&mut x_twist);
130        x.append(&mut y_twist);
131        Ok(x)
132    }
133}
134
135type Fp3G<P> = Fp3Var<<P as MNT6Parameters>::Fp3Params>;
136
137/// Represents the cached precomputation that can be performed on a G2 element
138/// which enables speeding up pairing computation.
139#[derive(Derivative)]
140#[derivative(Clone(bound = "P: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))]
141pub struct G2PreparedVar<P: MNT6Parameters> {
142    #[doc(hidden)]
143    pub x: Fp3Var<P::Fp3Params>,
144    #[doc(hidden)]
145    pub y: Fp3Var<P::Fp3Params>,
146    #[doc(hidden)]
147    pub x_over_twist: Fp3Var<P::Fp3Params>,
148    #[doc(hidden)]
149    pub y_over_twist: Fp3Var<P::Fp3Params>,
150    #[doc(hidden)]
151    pub double_coefficients: Vec<AteDoubleCoefficientsVar<P>>,
152    #[doc(hidden)]
153    pub addition_coefficients: Vec<AteAdditionCoefficientsVar<P>>,
154}
155
156impl<P: MNT6Parameters> AllocVar<G2Prepared<P>, P::Fp> for G2PreparedVar<P> {
157    #[tracing::instrument(target = "r1cs", skip(cs, f))]
158    fn new_variable<T: Borrow<G2Prepared<P>>>(
159        cs: impl Into<Namespace<P::Fp>>,
160        f: impl FnOnce() -> Result<T, SynthesisError>,
161        mode: AllocationMode,
162    ) -> Result<Self, SynthesisError> {
163        let ns = cs.into();
164        let cs = ns.cs();
165
166        let g2_prep = f().map(|b| b.borrow().clone());
167        let g2 = g2_prep.as_ref().map_err(|e| *e);
168
169        let x = Fp3Var::new_variable(r1cs_core::ns!(cs, "x"), || g2.map(|g| g.x), mode)?;
170        let y = Fp3Var::new_variable(r1cs_core::ns!(cs, "y"), || g2.map(|g| g.y), mode)?;
171        let x_over_twist = Fp3Var::new_variable(
172            r1cs_core::ns!(cs, "x_over_twist"),
173            || g2.map(|g| g.x_over_twist),
174            mode,
175        )?;
176        let y_over_twist = Fp3Var::new_variable(
177            r1cs_core::ns!(cs, "y_over_twist"),
178            || g2.map(|g| g.y_over_twist),
179            mode,
180        )?;
181        let double_coefficients = Vec::new_variable(
182            r1cs_core::ns!(cs, "double coeffs"),
183            || g2.map(|g| g.double_coefficients.clone()),
184            mode,
185        )?;
186        let addition_coefficients = Vec::new_variable(
187            r1cs_core::ns!(cs, "add coeffs"),
188            || g2.map(|g| g.addition_coefficients.clone()),
189            mode,
190        )?;
191        Ok(Self {
192            x,
193            y,
194            x_over_twist,
195            y_over_twist,
196            double_coefficients,
197            addition_coefficients,
198        })
199    }
200}
201
202impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for G2PreparedVar<P> {
203    #[inline]
204    #[tracing::instrument(target = "r1cs")]
205    fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
206        let mut x = self.x.to_bytes()?;
207        let mut y = self.y.to_bytes()?;
208        let mut x_over_twist = self.x_over_twist.to_bytes()?;
209        let mut y_over_twist = self.y_over_twist.to_bytes()?;
210
211        x.append(&mut y);
212        x.append(&mut x_over_twist);
213        x.append(&mut y_over_twist);
214
215        for coeff in self.double_coefficients.iter() {
216            x.extend_from_slice(&coeff.to_bytes()?);
217        }
218        for coeff in self.addition_coefficients.iter() {
219            x.extend_from_slice(&coeff.to_bytes()?);
220        }
221        Ok(x)
222    }
223
224    #[tracing::instrument(target = "r1cs")]
225    fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
226        let mut x = self.x.to_non_unique_bytes()?;
227        let mut y = self.y.to_non_unique_bytes()?;
228        let mut x_over_twist = self.x_over_twist.to_non_unique_bytes()?;
229        let mut y_over_twist = self.y_over_twist.to_non_unique_bytes()?;
230
231        x.append(&mut y);
232        x.append(&mut x_over_twist);
233        x.append(&mut y_over_twist);
234
235        for coeff in self.double_coefficients.iter() {
236            x.extend_from_slice(&coeff.to_non_unique_bytes()?);
237        }
238        for coeff in self.addition_coefficients.iter() {
239            x.extend_from_slice(&coeff.to_non_unique_bytes()?);
240        }
241        Ok(x)
242    }
243}
244
245impl<P: MNT6Parameters> G2PreparedVar<P> {
246    /// Returns the value assigned to `self` in the underlying constraint system.
247    pub fn value(&self) -> Result<G2Prepared<P>, SynthesisError> {
248        let x = self.x.value()?;
249        let y = self.y.value()?;
250        let x_over_twist = self.x_over_twist.value()?;
251        let y_over_twist = self.y_over_twist.value()?;
252        let double_coefficients = self
253            .double_coefficients
254            .iter()
255            .map(|coeff| coeff.value())
256            .collect::<Result<Vec<_>, SynthesisError>>()?;
257        let addition_coefficients = self
258            .addition_coefficients
259            .iter()
260            .map(|coeff| coeff.value())
261            .collect::<Result<Vec<_>, SynthesisError>>()?;
262        Ok(G2Prepared {
263            x,
264            y,
265            x_over_twist,
266            y_over_twist,
267            double_coefficients,
268            addition_coefficients,
269        })
270    }
271
272    /// Constructs `Self` from a `G2Var`.
273    #[tracing::instrument(target = "r1cs")]
274    pub fn from_group_var(q: &G2Var<P>) -> Result<Self, SynthesisError> {
275        let q = q.to_affine()?;
276        let twist_inv = P::TWIST.inverse().unwrap();
277
278        let mut g2p = G2PreparedVar {
279            x: q.x.clone(),
280            y: q.y.clone(),
281            x_over_twist: &q.x * twist_inv,
282            y_over_twist: &q.y * twist_inv,
283            double_coefficients: vec![],
284            addition_coefficients: vec![],
285        };
286
287        let mut r = G2ProjectiveExtendedVar {
288            x: q.x.clone(),
289            y: q.y.clone(),
290            z: Fp3G::<P>::one(),
291            t: Fp3G::<P>::one(),
292        };
293
294        for (idx, value) in P::ATE_LOOP_COUNT.iter().rev().enumerate() {
295            let mut tmp = *value;
296            let skip_extraneous_bits = 64 - value.leading_zeros();
297            let mut v = Vec::with_capacity(16);
298            for i in 0..64 {
299                if idx == 0 && (i == 0 || i >= skip_extraneous_bits) {
300                    continue;
301                }
302                v.push(tmp & 1 == 1);
303                tmp >>= 1;
304            }
305
306            for bit in v.iter().rev() {
307                let (r2, coeff) = PairingVar::<P>::doubling_step_for_flipped_miller_loop(&r)?;
308                g2p.double_coefficients.push(coeff);
309                r = r2;
310
311                if *bit {
312                    let (r2, coeff) = PairingVar::<P>::mixed_addition_step_for_flipped_miller_loop(
313                        &q.x, &q.y, &r,
314                    )?;
315                    g2p.addition_coefficients.push(coeff);
316                    r = r2;
317                }
318
319                tmp >>= 1;
320            }
321        }
322
323        if P::ATE_IS_LOOP_COUNT_NEG {
324            let rz_inv = r.z.inverse()?;
325            let rz2_inv = rz_inv.square()?;
326            let rz3_inv = &rz_inv * &rz2_inv;
327
328            let minus_r_affine_x = &r.x * &rz2_inv;
329            let minus_r_affine_y = r.y.negate()? * &rz3_inv;
330
331            let add_result = PairingVar::<P>::mixed_addition_step_for_flipped_miller_loop(
332                &minus_r_affine_x,
333                &minus_r_affine_y,
334                &r,
335            )?;
336            g2p.addition_coefficients.push(add_result.1);
337        }
338
339        Ok(g2p)
340    }
341}
342
343#[doc(hidden)]
344#[derive(Derivative)]
345#[derivative(Clone(bound = "P: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))]
346pub struct AteDoubleCoefficientsVar<P: MNT6Parameters> {
347    pub c_h: Fp3Var<P::Fp3Params>,
348    pub c_4c: Fp3Var<P::Fp3Params>,
349    pub c_j: Fp3Var<P::Fp3Params>,
350    pub c_l: Fp3Var<P::Fp3Params>,
351}
352
353impl<P: MNT6Parameters> AllocVar<AteDoubleCoefficients<P>, P::Fp> for AteDoubleCoefficientsVar<P> {
354    #[tracing::instrument(target = "r1cs", skip(cs, f))]
355    fn new_variable<T: Borrow<AteDoubleCoefficients<P>>>(
356        cs: impl Into<Namespace<P::Fp>>,
357        f: impl FnOnce() -> Result<T, SynthesisError>,
358        mode: AllocationMode,
359    ) -> Result<Self, SynthesisError> {
360        let ns = cs.into();
361        let cs = ns.cs();
362
363        let c_prep = f().map(|c| c.borrow().clone());
364        let c = c_prep.as_ref().map_err(|e| *e);
365
366        let c_h = Fp3Var::new_variable(r1cs_core::ns!(cs, "c_h"), || c.map(|c| c.c_h), mode)?;
367        let c_4c = Fp3Var::new_variable(r1cs_core::ns!(cs, "c_4c"), || c.map(|c| c.c_4c), mode)?;
368        let c_j = Fp3Var::new_variable(r1cs_core::ns!(cs, "c_j"), || c.map(|c| c.c_j), mode)?;
369        let c_l = Fp3Var::new_variable(r1cs_core::ns!(cs, "c_l"), || c.map(|c| c.c_l), mode)?;
370        Ok(Self {
371            c_h,
372            c_4c,
373            c_j,
374            c_l,
375        })
376    }
377}
378
379impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for AteDoubleCoefficientsVar<P> {
380    #[inline]
381    #[tracing::instrument(target = "r1cs")]
382    fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
383        let mut c_h = self.c_h.to_bytes()?;
384        let mut c_4c = self.c_4c.to_bytes()?;
385        let mut c_j = self.c_j.to_bytes()?;
386        let mut c_l = self.c_l.to_bytes()?;
387
388        c_h.append(&mut c_4c);
389        c_h.append(&mut c_j);
390        c_h.append(&mut c_l);
391        Ok(c_h)
392    }
393
394    #[tracing::instrument(target = "r1cs")]
395    fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
396        let mut c_h = self.c_h.to_non_unique_bytes()?;
397        let mut c_4c = self.c_4c.to_non_unique_bytes()?;
398        let mut c_j = self.c_j.to_non_unique_bytes()?;
399        let mut c_l = self.c_l.to_non_unique_bytes()?;
400
401        c_h.append(&mut c_4c);
402        c_h.append(&mut c_j);
403        c_h.append(&mut c_l);
404        Ok(c_h)
405    }
406}
407
408impl<P: MNT6Parameters> AteDoubleCoefficientsVar<P> {
409    /// Returns the value assigned to `self` in the underlying constraint system.
410    pub fn value(&self) -> Result<AteDoubleCoefficients<P>, SynthesisError> {
411        let c_h = self.c_h.value()?;
412        let c_4c = self.c_4c.value()?;
413        let c_j = self.c_j.value()?;
414        let c_l = self.c_l.value()?;
415        Ok(AteDoubleCoefficients {
416            c_h,
417            c_4c,
418            c_j,
419            c_l,
420        })
421    }
422}
423
424#[doc(hidden)]
425#[derive(Derivative)]
426#[derivative(Clone(bound = "P: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))]
427pub struct AteAdditionCoefficientsVar<P: MNT6Parameters> {
428    pub c_l1: Fp3Var<P::Fp3Params>,
429    pub c_rz: Fp3Var<P::Fp3Params>,
430}
431
432impl<P: MNT6Parameters> AllocVar<AteAdditionCoefficients<P>, P::Fp>
433    for AteAdditionCoefficientsVar<P>
434{
435    #[tracing::instrument(target = "r1cs", skip(cs, f))]
436    fn new_variable<T: Borrow<AteAdditionCoefficients<P>>>(
437        cs: impl Into<Namespace<P::Fp>>,
438        f: impl FnOnce() -> Result<T, SynthesisError>,
439        mode: AllocationMode,
440    ) -> Result<Self, SynthesisError> {
441        let ns = cs.into();
442        let cs = ns.cs();
443
444        let c_prep = f().map(|c| c.borrow().clone());
445        let c = c_prep.as_ref().map_err(|e| *e);
446
447        let c_l1 = Fp3Var::new_variable(r1cs_core::ns!(cs, "c_l1"), || c.map(|c| c.c_l1), mode)?;
448        let c_rz = Fp3Var::new_variable(r1cs_core::ns!(cs, "c_rz"), || c.map(|c| c.c_rz), mode)?;
449        Ok(Self { c_l1, c_rz })
450    }
451}
452
453impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for AteAdditionCoefficientsVar<P> {
454    #[inline]
455    #[tracing::instrument(target = "r1cs")]
456    fn to_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
457        let mut c_l1 = self.c_l1.to_bytes()?;
458        let mut c_rz = self.c_rz.to_bytes()?;
459
460        c_l1.append(&mut c_rz);
461        Ok(c_l1)
462    }
463
464    #[tracing::instrument(target = "r1cs")]
465    fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
466        let mut c_l1 = self.c_l1.to_non_unique_bytes()?;
467        let mut c_rz = self.c_rz.to_non_unique_bytes()?;
468
469        c_l1.append(&mut c_rz);
470        Ok(c_l1)
471    }
472}
473
474impl<P: MNT6Parameters> AteAdditionCoefficientsVar<P> {
475    /// Returns the value assigned to `self` in the underlying constraint system.
476    pub fn value(&self) -> Result<AteAdditionCoefficients<P>, SynthesisError> {
477        let c_l1 = self.c_l1.value()?;
478        let c_rz = self.c_rz.value()?;
479        Ok(AteAdditionCoefficients { c_l1, c_rz })
480    }
481}
482
483#[doc(hidden)]
484pub struct G2ProjectiveExtendedVar<P: MNT6Parameters> {
485    pub x: Fp3Var<P::Fp3Params>,
486    pub y: Fp3Var<P::Fp3Params>,
487    pub z: Fp3Var<P::Fp3Params>,
488    pub t: Fp3Var<P::Fp3Params>,
489}