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