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