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