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