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::{ConstraintSystem, SynthesisError};
  9
 10use crate::{
 11    fields::{fp::FpGadget, fp3::Fp3Gadget, FieldGadget},
 12    groups::curves::short_weierstrass::AffineGadget,
 13    pairing::mnt6::PairingGadget,
 14    prelude::*,
 15    Vec,
 16};
 17
 18pub type G1Gadget<P> = AffineGadget<
 19    <P as MNT6Parameters>::G1Parameters,
 20    <P as MNT6Parameters>::Fp,
 21    FpGadget<<P as MNT6Parameters>::Fp>,
 22>;
 23
 24pub type G2Gadget<P> =
 25    AffineGadget<<P as MNT6Parameters>::G2Parameters, <P as MNT6Parameters>::Fp, Fp3G<P>>;
 26
 27#[derive(Derivative)]
 28#[derivative(Clone(bound = "P: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))]
 29pub struct G1PreparedGadget<P: MNT6Parameters> {
 30    pub x:       FpGadget<P::Fp>,
 31    pub y:       FpGadget<P::Fp>,
 32    pub x_twist: Fp3Gadget<P::Fp3Params, P::Fp>,
 33    pub y_twist: Fp3Gadget<P::Fp3Params, P::Fp>,
 34}
 35
 36impl<P: MNT6Parameters> G1PreparedGadget<P> {
 37    pub fn get_value(&self) -> Option<G1Prepared<P>> {
 38        match (
 39            self.x.get_value(),
 40            self.y.get_value(),
 41            self.x_twist.get_value(),
 42            self.y_twist.get_value(),
 43        ) {
 44            (Some(x), Some(y), Some(x_twist), Some(y_twist)) => Some(G1Prepared {
 45                x,
 46                y,
 47                x_twist,
 48                y_twist,
 49            }),
 50            _ => None,
 51        }
 52    }
 53
 54    pub fn from_affine<CS: ConstraintSystem<P::Fp>>(
 55        mut cs: CS,
 56        q: &G1Gadget<P>,
 57    ) -> Result<Self, SynthesisError> {
 58        let x_twist = Fp3Gadget::new(
 59            q.x.mul_by_constant(cs.ns(|| "g1.x * twist.c0"), &P::TWIST.c0)?,
 60            q.x.mul_by_constant(cs.ns(|| "g1.x * twist.c1"), &P::TWIST.c1)?,
 61            q.x.mul_by_constant(cs.ns(|| "g1.x * twist.c2"), &P::TWIST.c2)?,
 62        );
 63        let y_twist = Fp3Gadget::new(
 64            q.y.mul_by_constant(cs.ns(|| "g1.y * twist.c0"), &P::TWIST.c0)?,
 65            q.y.mul_by_constant(cs.ns(|| "g1.y * twist.c1"), &P::TWIST.c1)?,
 66            q.y.mul_by_constant(cs.ns(|| "g1.y * twist.c2"), &P::TWIST.c2)?,
 67        );
 68        Ok(G1PreparedGadget {
 69            x: q.x.clone(),
 70            y: q.y.clone(),
 71            x_twist,
 72            y_twist,
 73        })
 74    }
 75}
 76
 77impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for G1PreparedGadget<P> {
 78    #[inline]
 79    fn to_bytes<CS: ConstraintSystem<P::Fp>>(
 80        &self,
 81        mut cs: CS,
 82    ) -> Result<Vec<UInt8>, SynthesisError> {
 83        let mut x = self.x.to_bytes(&mut cs.ns(|| "x to bytes"))?;
 84        let mut y = self.y.to_bytes(&mut cs.ns(|| "y to bytes"))?;
 85        let mut x_twist = self.x_twist.to_bytes(&mut cs.ns(|| "x_twist to bytes"))?;
 86        let mut y_twist = self.y_twist.to_bytes(&mut cs.ns(|| "y_twist to bytes"))?;
 87
 88        x.append(&mut y);
 89        x.append(&mut x_twist);
 90        x.append(&mut y_twist);
 91        Ok(x)
 92    }
 93
 94    fn to_non_unique_bytes<CS: ConstraintSystem<P::Fp>>(
 95        &self,
 96        mut cs: CS,
 97    ) -> Result<Vec<UInt8>, SynthesisError> {
 98        let mut x = self.x.to_non_unique_bytes(&mut cs.ns(|| "x to bytes"))?;
 99        let mut y = self.y.to_non_unique_bytes(&mut cs.ns(|| "y to bytes"))?;
100        let mut x_twist = self
101            .x_twist
102            .to_non_unique_bytes(&mut cs.ns(|| "x_twist to bytes"))?;
103        let mut y_twist = self
104            .y_twist
105            .to_non_unique_bytes(&mut cs.ns(|| "y_twist to bytes"))?;
106
107        x.append(&mut y);
108        x.append(&mut x_twist);
109        x.append(&mut y_twist);
110        Ok(x)
111    }
112}
113
114type Fp3G<P> = Fp3Gadget<<P as MNT6Parameters>::Fp3Params, <P as MNT6Parameters>::Fp>;
115#[derive(Derivative)]
116#[derivative(Clone(bound = "P: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))]
117pub struct G2PreparedGadget<P: MNT6Parameters> {
118    pub x:                     Fp3Gadget<P::Fp3Params, P::Fp>,
119    pub y:                     Fp3Gadget<P::Fp3Params, P::Fp>,
120    pub x_over_twist:          Fp3Gadget<P::Fp3Params, P::Fp>,
121    pub y_over_twist:          Fp3Gadget<P::Fp3Params, P::Fp>,
122    pub double_coefficients:   Vec<AteDoubleCoefficientsGadget<P>>,
123    pub addition_coefficients: Vec<AteAdditionCoefficientsGadget<P>>,
124}
125
126impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for G2PreparedGadget<P> {
127    #[inline]
128    fn to_bytes<CS: ConstraintSystem<P::Fp>>(
129        &self,
130        mut cs: CS,
131    ) -> Result<Vec<UInt8>, SynthesisError> {
132        let mut x = self.x.to_bytes(&mut cs.ns(|| "x to bytes"))?;
133        let mut y = self.y.to_bytes(&mut cs.ns(|| "y to bytes"))?;
134        let mut x_over_twist = self
135            .x_over_twist
136            .to_bytes(&mut cs.ns(|| "x_over_twist to bytes"))?;
137        let mut y_over_twist = self
138            .y_over_twist
139            .to_bytes(&mut cs.ns(|| "y_over_twist to bytes"))?;
140
141        x.append(&mut y);
142        x.append(&mut x_over_twist);
143        x.append(&mut y_over_twist);
144
145        for (i, coeff) in self.double_coefficients.iter().enumerate() {
146            x.extend_from_slice(&coeff.to_bytes(cs.ns(|| format!("double_coefficients {}", i)))?);
147        }
148        for (i, coeff) in self.addition_coefficients.iter().enumerate() {
149            x.extend_from_slice(&coeff.to_bytes(cs.ns(|| format!("addition_coefficients {}", i)))?);
150        }
151        Ok(x)
152    }
153
154    fn to_non_unique_bytes<CS: ConstraintSystem<P::Fp>>(
155        &self,
156        mut cs: CS,
157    ) -> Result<Vec<UInt8>, SynthesisError> {
158        let mut x = self.x.to_non_unique_bytes(&mut cs.ns(|| "x to bytes"))?;
159        let mut y = self.y.to_non_unique_bytes(&mut cs.ns(|| "y to bytes"))?;
160        let mut x_over_twist = self
161            .x_over_twist
162            .to_non_unique_bytes(&mut cs.ns(|| "x_over_twist to bytes"))?;
163        let mut y_over_twist = self
164            .y_over_twist
165            .to_non_unique_bytes(&mut cs.ns(|| "y_over_twist to bytes"))?;
166
167        x.append(&mut y);
168        x.append(&mut x_over_twist);
169        x.append(&mut y_over_twist);
170
171        for (i, coeff) in self.double_coefficients.iter().enumerate() {
172            x.extend_from_slice(
173                &coeff.to_non_unique_bytes(cs.ns(|| format!("double_coefficients {}", i)))?,
174            );
175        }
176        for (i, coeff) in self.addition_coefficients.iter().enumerate() {
177            x.extend_from_slice(
178                &coeff.to_non_unique_bytes(cs.ns(|| format!("addition_coefficients {}", i)))?,
179            );
180        }
181        Ok(x)
182    }
183}
184
185impl<P: MNT6Parameters> G2PreparedGadget<P> {
186    pub fn get_value(&self) -> Option<G2Prepared<P>> {
187        match (
188            self.x.get_value(),
189            self.y.get_value(),
190            self.x_over_twist.get_value(),
191            self.y_over_twist.get_value(),
192            self.double_coefficients
193                .iter()
194                .map(|coeff| coeff.get_value())
195                .collect::<Option<Vec<AteDoubleCoefficients<P>>>>(),
196            self.addition_coefficients
197                .iter()
198                .map(|coeff| coeff.get_value())
199                .collect::<Option<Vec<AteAdditionCoefficients<P>>>>(),
200        ) {
201            (
202                Some(x),
203                Some(y),
204                Some(x_over_twist),
205                Some(y_over_twist),
206                Some(double_coefficients),
207                Some(addition_coefficients),
208            ) => Some(G2Prepared {
209                x,
210                y,
211                x_over_twist,
212                y_over_twist,
213                double_coefficients,
214                addition_coefficients,
215            }),
216            _ => None,
217        }
218    }
219
220    pub fn from_affine<CS: ConstraintSystem<P::Fp>>(
221        mut cs: CS,
222        q: &G2Gadget<P>,
223    ) -> Result<Self, SynthesisError> {
224        let twist_inv = P::TWIST.inverse().unwrap();
225
226        let mut g2p = G2PreparedGadget {
227            x:                     q.x.clone(),
228            y:                     q.y.clone(),
229            x_over_twist:          q.x.mul_by_constant(cs.ns(|| "x over twist"), &twist_inv)?,
230            y_over_twist:          q.y.mul_by_constant(cs.ns(|| "y over twist"), &twist_inv)?,
231            double_coefficients:   vec![],
232            addition_coefficients: vec![],
233        };
234
235        let fp2_one = Fp3G::<P>::one(cs.ns(|| "one"))?;
236        let mut r = G2ProjectiveExtendedGadget {
237            x: q.x.clone(),
238            y: q.y.clone(),
239            z: fp2_one.clone(),
240            t: fp2_one,
241        };
242
243        for (idx, value) in P::ATE_LOOP_COUNT.iter().rev().enumerate() {
244            let mut tmp = *value;
245            let skip_extraneous_bits = 64 - value.leading_zeros();
246            let mut v = Vec::with_capacity(16);
247            for i in 0..64 {
248                if idx == 0 && (i == 0 || i >= skip_extraneous_bits) {
249                    continue;
250                }
251                v.push(tmp & 1 == 1);
252                tmp >>= 1;
253            }
254
255            let mut cs = cs.ns(|| format!("ate loop iteration {}", idx));
256
257            for (j, bit) in v.iter().rev().enumerate() {
258                let (r2, coeff) = PairingGadget::<P>::doubling_step_for_flipped_miller_loop(
259                    cs.ns(|| format!("doubling step {}", j)),
260                    &r,
261                )?;
262                g2p.double_coefficients.push(coeff);
263                r = r2;
264
265                if *bit {
266                    let (r2, coeff) =
267                        PairingGadget::<P>::mixed_addition_step_for_flipped_miller_loop(
268                            cs.ns(|| format!("mixed addition step {}", j)),
269                            &q.x,
270                            &q.y,
271                            &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(cs.ns(|| "inverse r.z"))?;
283            let rz2_inv = rz_inv.square(cs.ns(|| "rz_inv^2"))?;
284            let rz3_inv = rz_inv.mul(cs.ns(|| "rz_inv * rz_inv^2"), &rz2_inv)?;
285
286            let minus_r_affine_x = r.x.mul(cs.ns(|| "r.x * rz2_inv"), &rz2_inv)?;
287            let minus_r_affine_y =
288                r.y.negate(cs.ns(|| "-r.y"))?
289                    .mul(cs.ns(|| "-r.y * rz3_inv"), &rz3_inv)?;
290
291            let add_result = PairingGadget::<P>::mixed_addition_step_for_flipped_miller_loop(
292                cs.ns(|| "mixed_addition step"),
293                &minus_r_affine_x,
294                &minus_r_affine_y,
295                &r,
296            )?;
297            g2p.addition_coefficients.push(add_result.1);
298        }
299
300        Ok(g2p)
301    }
302}
303
304#[derive(Derivative)]
305#[derivative(Clone(bound = "P: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))]
306pub struct AteDoubleCoefficientsGadget<P: MNT6Parameters> {
307    pub c_h:  Fp3Gadget<P::Fp3Params, P::Fp>,
308    pub c_4c: Fp3Gadget<P::Fp3Params, P::Fp>,
309    pub c_j:  Fp3Gadget<P::Fp3Params, P::Fp>,
310    pub c_l:  Fp3Gadget<P::Fp3Params, P::Fp>,
311}
312
313impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for AteDoubleCoefficientsGadget<P> {
314    #[inline]
315    fn to_bytes<CS: ConstraintSystem<P::Fp>>(
316        &self,
317        mut cs: CS,
318    ) -> Result<Vec<UInt8>, SynthesisError> {
319        let mut c_h = self.c_h.to_bytes(&mut cs.ns(|| "c_h to bytes"))?;
320        let mut c_4c = self.c_4c.to_bytes(&mut cs.ns(|| "c_4c to bytes"))?;
321        let mut c_j = self.c_j.to_bytes(&mut cs.ns(|| "c_j to bytes"))?;
322        let mut c_l = self.c_l.to_bytes(&mut cs.ns(|| "c_l to bytes"))?;
323
324        c_h.append(&mut c_4c);
325        c_h.append(&mut c_j);
326        c_h.append(&mut c_l);
327        Ok(c_h)
328    }
329
330    fn to_non_unique_bytes<CS: ConstraintSystem<P::Fp>>(
331        &self,
332        mut cs: CS,
333    ) -> Result<Vec<UInt8>, SynthesisError> {
334        let mut c_h = self
335            .c_h
336            .to_non_unique_bytes(&mut cs.ns(|| "c_h to bytes"))?;
337        let mut c_4c = self
338            .c_4c
339            .to_non_unique_bytes(&mut cs.ns(|| "c_4c to bytes"))?;
340        let mut c_j = self
341            .c_j
342            .to_non_unique_bytes(&mut cs.ns(|| "c_j to bytes"))?;
343        let mut c_l = self
344            .c_l
345            .to_non_unique_bytes(&mut cs.ns(|| "c_l to bytes"))?;
346
347        c_h.append(&mut c_4c);
348        c_h.append(&mut c_j);
349        c_h.append(&mut c_l);
350        Ok(c_h)
351    }
352}
353
354impl<P: MNT6Parameters> AteDoubleCoefficientsGadget<P> {
355    pub fn get_value(&self) -> Option<AteDoubleCoefficients<P>> {
356        match (
357            self.c_h.get_value(),
358            self.c_4c.get_value(),
359            self.c_j.get_value(),
360            self.c_l.get_value(),
361        ) {
362            (Some(c_h), Some(c_4c), Some(c_j), Some(c_l)) => Some(AteDoubleCoefficients {
363                c_h,
364                c_4c,
365                c_j,
366                c_l,
367            }),
368            _ => None,
369        }
370    }
371}
372
373#[derive(Derivative)]
374#[derivative(Clone(bound = "P: MNT6Parameters"), Debug(bound = "P: MNT6Parameters"))]
375pub struct AteAdditionCoefficientsGadget<P: MNT6Parameters> {
376    pub c_l1: Fp3Gadget<P::Fp3Params, P::Fp>,
377    pub c_rz: Fp3Gadget<P::Fp3Params, P::Fp>,
378}
379
380impl<P: MNT6Parameters> ToBytesGadget<P::Fp> for AteAdditionCoefficientsGadget<P> {
381    #[inline]
382    fn to_bytes<CS: ConstraintSystem<P::Fp>>(
383        &self,
384        mut cs: CS,
385    ) -> Result<Vec<UInt8>, SynthesisError> {
386        let mut c_l1 = self.c_l1.to_bytes(&mut cs.ns(|| "c_l1 to bytes"))?;
387        let mut c_rz = self.c_rz.to_bytes(&mut cs.ns(|| "c_rz to bytes"))?;
388
389        c_l1.append(&mut c_rz);
390        Ok(c_l1)
391    }
392
393    fn to_non_unique_bytes<CS: ConstraintSystem<P::Fp>>(
394        &self,
395        mut cs: CS,
396    ) -> Result<Vec<UInt8>, SynthesisError> {
397        let mut c_l1 = self
398            .c_l1
399            .to_non_unique_bytes(&mut cs.ns(|| "c_l1 to bytes"))?;
400        let mut c_rz = self
401            .c_rz
402            .to_non_unique_bytes(&mut cs.ns(|| "c_rz to bytes"))?;
403
404        c_l1.append(&mut c_rz);
405        Ok(c_l1)
406    }
407}
408
409impl<P: MNT6Parameters> AteAdditionCoefficientsGadget<P> {
410    pub fn get_value(&self) -> Option<AteAdditionCoefficients<P>> {
411        match (self.c_l1.get_value(), self.c_rz.get_value()) {
412            (Some(c_l1), Some(c_rz)) => Some(AteAdditionCoefficients { c_l1, c_rz }),
413            _ => None,
414        }
415    }
416}
417
418pub struct G2ProjectiveExtendedGadget<P: MNT6Parameters> {
419    pub x: Fp3Gadget<P::Fp3Params, P::Fp>,
420    pub y: Fp3Gadget<P::Fp3Params, P::Fp>,
421    pub z: Fp3Gadget<P::Fp3Params, P::Fp>,
422    pub t: Fp3Gadget<P::Fp3Params, P::Fp>,
423}