ark_r1cs_std/groups/curves/short_weierstrass/mnt4/
mod.rs

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