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