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

1use ark_ec::{
2    bls12::{Bls12Config, G1Prepared, G2Prepared, TwistType},
3    short_weierstrass::Affine as GroupAffine,
4};
5use ark_ff::{BitIteratorBE, Field, One};
6use ark_relations::r1cs::{Namespace, SynthesisError};
7
8use crate::{
9    fields::{fp::FpVar, fp2::Fp2Var, FieldVar},
10    groups::curves::short_weierstrass::*,
11    Vec,
12};
13
14/// Represents a projective point in G1.
15pub type G1Var<P> = ProjectiveVar<<P as Bls12Config>::G1Config, FpVar<<P as Bls12Config>::Fp>>;
16
17/// Represents an affine point on G1. Should be used only for comparison and
18/// when a canonical representation of a point is required, and not for
19/// arithmetic.
20pub type G1AffineVar<P> = AffineVar<<P as Bls12Config>::G1Config, FpVar<<P as Bls12Config>::Fp>>;
21
22/// Represents a projective point in G2.
23pub type G2Var<P> = ProjectiveVar<<P as Bls12Config>::G2Config, Fp2G<P>>;
24/// Represents an affine point on G2. Should be used only for comparison and
25/// when a canonical representation of a point is required, and not for
26/// arithmetic.
27pub type G2AffineVar<P> = AffineVar<<P as Bls12Config>::G2Config, Fp2G<P>>;
28
29/// Represents the cached precomputation that can be performed on a G1 element
30/// which enables speeding up pairing computation.
31#[derive(Educe)]
32#[educe(Clone, Debug)]
33pub struct G1PreparedVar<P: Bls12Config>(pub AffineVar<P::G1Config, FpVar<P::Fp>>);
34
35impl<P: Bls12Config> G1PreparedVar<P> {
36    /// Returns the value assigned to `self` in the underlying constraint
37    /// system.
38    pub fn value(&self) -> Result<G1Prepared<P>, SynthesisError> {
39        let x = self.0.x.value()?;
40        let y = self.0.y.value()?;
41        let infinity = self.0.infinity.value()?;
42        let g = infinity
43            .then_some(GroupAffine::identity())
44            .unwrap_or(GroupAffine::new(x, y))
45            .into();
46        Ok(g)
47    }
48
49    /// Constructs `Self` from a `G1Var`.
50    pub fn from_group_var(q: &G1Var<P>) -> Result<Self, SynthesisError> {
51        let g = q.to_affine()?;
52        Ok(Self(g))
53    }
54}
55
56impl<P: Bls12Config> AllocVar<G1Prepared<P>, P::Fp> for G1PreparedVar<P> {
57    fn new_variable<T: Borrow<G1Prepared<P>>>(
58        cs: impl Into<Namespace<P::Fp>>,
59        f: impl FnOnce() -> Result<T, SynthesisError>,
60        mode: AllocationMode,
61    ) -> Result<Self, SynthesisError> {
62        let ns = cs.into();
63        let cs = ns.cs();
64        let g1_prep = f().map(|b| b.borrow().0);
65
66        let x = FpVar::new_variable(ark_relations::ns!(cs, "x"), || g1_prep.map(|g| g.x), mode)?;
67        let y = FpVar::new_variable(ark_relations::ns!(cs, "y"), || g1_prep.map(|g| g.y), mode)?;
68        let infinity = Boolean::new_variable(
69            ark_relations::ns!(cs, "inf"),
70            || g1_prep.map(|g| g.infinity),
71            mode,
72        )?;
73        let g = AffineVar::new(x, y, infinity);
74        Ok(Self(g))
75    }
76}
77
78impl<P: Bls12Config> ToBytesGadget<P::Fp> for G1PreparedVar<P> {
79    #[inline]
80    #[tracing::instrument(target = "r1cs")]
81    fn to_bytes_le(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
82        let mut bytes = self.0.x.to_bytes_le()?;
83        let y_bytes = self.0.y.to_bytes_le()?;
84        let inf_bytes = self.0.infinity.to_bytes_le()?;
85        bytes.extend_from_slice(&y_bytes);
86        bytes.extend_from_slice(&inf_bytes);
87        Ok(bytes)
88    }
89
90    #[tracing::instrument(target = "r1cs")]
91    fn to_non_unique_bytes_le(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
92        let mut bytes = self.0.x.to_non_unique_bytes_le()?;
93        let y_bytes = self.0.y.to_non_unique_bytes_le()?;
94        let inf_bytes = self.0.infinity.to_non_unique_bytes_le()?;
95        bytes.extend_from_slice(&y_bytes);
96        bytes.extend_from_slice(&inf_bytes);
97        Ok(bytes)
98    }
99}
100
101type Fp2G<P> = Fp2Var<<P as Bls12Config>::Fp2Config>;
102type LCoeff<P> = (Fp2G<P>, Fp2G<P>);
103/// Represents the cached precomputation that can be performed on a G2 element
104/// which enables speeding up pairing computation.
105#[derive(Educe)]
106#[educe(Clone, Debug)]
107pub struct G2PreparedVar<P: Bls12Config> {
108    #[doc(hidden)]
109    pub ell_coeffs: Vec<LCoeff<P>>,
110}
111
112impl<P: Bls12Config> AllocVar<G2Prepared<P>, P::Fp> for G2PreparedVar<P> {
113    #[tracing::instrument(target = "r1cs", skip(cs, f, mode))]
114    fn new_variable<T: Borrow<G2Prepared<P>>>(
115        cs: impl Into<Namespace<P::Fp>>,
116        f: impl FnOnce() -> Result<T, SynthesisError>,
117        mode: AllocationMode,
118    ) -> Result<Self, SynthesisError> {
119        let ns = cs.into();
120        let cs = ns.cs();
121        let g2_prep = f().map(|b| {
122            let projective_coeffs = &b.borrow().ell_coeffs;
123            match P::TWIST_TYPE {
124                TwistType::M => {
125                    let mut z_s = projective_coeffs
126                        .iter()
127                        .map(|(_, _, z)| *z)
128                        .collect::<Vec<_>>();
129                    ark_ff::fields::batch_inversion(&mut z_s);
130                    projective_coeffs
131                        .iter()
132                        .zip(z_s)
133                        .map(|((x, y, _), z_inv)| (*x * &z_inv, *y * &z_inv))
134                        .collect::<Vec<_>>()
135                },
136                TwistType::D => {
137                    let mut z_s = projective_coeffs
138                        .iter()
139                        .map(|(z, ..)| *z)
140                        .collect::<Vec<_>>();
141                    ark_ff::fields::batch_inversion(&mut z_s);
142                    projective_coeffs
143                        .iter()
144                        .zip(z_s)
145                        .map(|((_, x, y), z_inv)| (*x * &z_inv, *y * &z_inv))
146                        .collect::<Vec<_>>()
147                },
148            }
149        });
150
151        let l = Vec::new_variable(
152            ark_relations::ns!(cs, "l"),
153            || {
154                g2_prep
155                    .clone()
156                    .map(|c| c.iter().map(|(l, _)| *l).collect::<Vec<_>>())
157            },
158            mode,
159        )?;
160        let r = Vec::new_variable(
161            ark_relations::ns!(cs, "r"),
162            || g2_prep.map(|c| c.iter().map(|(_, r)| *r).collect::<Vec<_>>()),
163            mode,
164        )?;
165        let ell_coeffs = l.into_iter().zip(r).collect();
166        Ok(Self { ell_coeffs })
167    }
168}
169
170impl<P: Bls12Config> ToBytesGadget<P::Fp> for G2PreparedVar<P> {
171    #[inline]
172    #[tracing::instrument(target = "r1cs")]
173    fn to_bytes_le(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
174        let mut bytes = Vec::new();
175        for coeffs in &self.ell_coeffs {
176            bytes.extend_from_slice(&coeffs.0.to_bytes_le()?);
177            bytes.extend_from_slice(&coeffs.1.to_bytes_le()?);
178        }
179        Ok(bytes)
180    }
181
182    #[tracing::instrument(target = "r1cs")]
183    fn to_non_unique_bytes_le(&self) -> Result<Vec<UInt8<P::Fp>>, SynthesisError> {
184        let mut bytes = Vec::new();
185        for coeffs in &self.ell_coeffs {
186            bytes.extend_from_slice(&coeffs.0.to_non_unique_bytes_le()?);
187            bytes.extend_from_slice(&coeffs.1.to_non_unique_bytes_le()?);
188        }
189        Ok(bytes)
190    }
191}
192
193impl<P: Bls12Config> G2PreparedVar<P> {
194    /// Constructs `Self` from a `G2Var`.
195    #[tracing::instrument(target = "r1cs")]
196    pub fn from_group_var(q: &G2Var<P>) -> Result<Self, SynthesisError> {
197        let q = q.to_affine()?;
198        let two_inv = P::Fp::one().double().inverse().unwrap();
199        // Enforce that `q` is not the point at infinity.
200        q.infinity.enforce_not_equal(&Boolean::TRUE)?;
201        let mut ell_coeffs = vec![];
202        let mut r = q.clone();
203
204        for i in BitIteratorBE::new(P::X).skip(1) {
205            ell_coeffs.push(Self::double(&mut r, &two_inv)?);
206
207            if i {
208                ell_coeffs.push(Self::add(&mut r, &q)?);
209            }
210        }
211
212        Ok(Self { ell_coeffs })
213    }
214
215    #[tracing::instrument(target = "r1cs")]
216    fn double(r: &mut G2AffineVar<P>, two_inv: &P::Fp) -> Result<LCoeff<P>, SynthesisError> {
217        let a = r.y.inverse()?;
218        let mut b = r.x.square()?;
219        let b_tmp = b.clone();
220        b.mul_assign_by_base_field_constant(*two_inv);
221        b += &b_tmp;
222
223        let c = &a * &b;
224        let d = r.x.double()?;
225        let x3 = c.square()? - &d;
226        let e = &c * &r.x - &r.y;
227        let c_x3 = &c * &x3;
228        let y3 = &e - &c_x3;
229        let mut f = c;
230        f.negate_in_place()?;
231        r.x = x3;
232        r.y = y3;
233        match P::TWIST_TYPE {
234            TwistType::M => Ok((e, f)),
235            TwistType::D => Ok((f, e)),
236        }
237    }
238
239    #[tracing::instrument(target = "r1cs")]
240    fn add(r: &mut G2AffineVar<P>, q: &G2AffineVar<P>) -> Result<LCoeff<P>, SynthesisError> {
241        let a = (&q.x - &r.x).inverse()?;
242        let b = &q.y - &r.y;
243        let c = &a * &b;
244        let d = &r.x + &q.x;
245        let x3 = c.square()? - &d;
246
247        let e = (&r.x - &x3) * &c;
248        let y3 = e - &r.y;
249        let g = &c * &r.x - &r.y;
250        let mut f = c;
251        f.negate_in_place()?;
252        r.x = x3;
253        r.y = y3;
254        match P::TWIST_TYPE {
255            TwistType::M => Ok((g, f)),
256            TwistType::D => Ok((f, g)),
257        }
258    }
259}