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