arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
ark-r1cs-std/src/groups/curves/short_weierstrass/mod.rs
src/groups/curves/short_weierstrass/mod.rsRaw
  1use ark_ec::{
  2    short_weierstrass_jacobian::{GroupAffine as SWAffine, GroupProjective as SWProjective},
  3    AffineCurve, ProjectiveCurve, SWModelParameters,
  4};
  5use ark_ff::{BigInteger, BitIteratorBE, Field, One, PrimeField, Zero};
  6use ark_relations::r1cs::{ConstraintSystemRef, Namespace, SynthesisError};
  7use core::{borrow::Borrow, marker::PhantomData};
  8
  9use crate::{fields::fp::FpVar, prelude::*, ToConstraintFieldGadget, Vec};
 10
 11/// This module provides a generic implementation of G1 and G2 for
 12/// the [[BLS12]](https://eprint.iacr.org/2002/088.pdf) family of bilinear groups.
 13pub mod bls12;
 14
 15/// This module provides a generic implementation of G1 and G2 for
 16/// the [[MNT4]](https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.20.8113&rep=rep1&type=pdf)
 17///  family of bilinear groups.
 18pub mod mnt4;
 19/// This module provides a generic implementation of G1 and G2 for
 20/// the [[MNT6]](https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.20.8113&rep=rep1&type=pdf)
 21///  family of bilinear groups.
 22pub mod mnt6;
 23
 24/// An implementation of arithmetic for Short Weierstrass curves that relies on
 25/// the complete formulae derived in the paper of
 26/// [[Renes, Costello, Batina 2015]](https://eprint.iacr.org/2015/1060).
 27#[derive(Derivative)]
 28#[derivative(Debug, Clone)]
 29#[must_use]
 30pub struct ProjectiveVar<
 31    P: SWModelParameters,
 32    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
 33> where
 34    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
 35{
 36    /// The x-coordinate.
 37    pub x: F,
 38    /// The y-coordinate.
 39    pub y: F,
 40    /// The z-coordinate.
 41    pub z: F,
 42    #[derivative(Debug = "ignore")]
 43    _params: PhantomData<P>,
 44}
 45
 46/// An affine representation of a curve point.
 47#[derive(Derivative)]
 48#[derivative(Debug, Clone)]
 49#[must_use]
 50pub struct AffineVar<
 51    P: SWModelParameters,
 52    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
 53> where
 54    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
 55{
 56    /// The x-coordinate.
 57    pub x: F,
 58    /// The y-coordinate.
 59    pub y: F,
 60    /// Is `self` the point at infinity.
 61    pub infinity: Boolean<<P::BaseField as Field>::BasePrimeField>,
 62    #[derivative(Debug = "ignore")]
 63    _params: PhantomData<P>,
 64}
 65
 66impl<P, F> AffineVar<P, F>
 67where
 68    P: SWModelParameters,
 69    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
 70    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
 71{
 72    fn new(x: F, y: F, infinity: Boolean<<P::BaseField as Field>::BasePrimeField>) -> Self {
 73        Self {
 74            x,
 75            y,
 76            infinity,
 77            _params: PhantomData,
 78        }
 79    }
 80
 81    /// Returns the value assigned to `self` in the underlying
 82    /// constraint system.
 83    pub fn value(&self) -> Result<SWAffine<P>, SynthesisError> {
 84        Ok(SWAffine::new(
 85            self.x.value()?,
 86            self.y.value()?,
 87            self.infinity.value()?,
 88        ))
 89    }
 90}
 91
 92impl<P, F> ToConstraintFieldGadget<<P::BaseField as Field>::BasePrimeField> for AffineVar<P, F>
 93where
 94    P: SWModelParameters,
 95    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
 96    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
 97    F: ToConstraintFieldGadget<<P::BaseField as Field>::BasePrimeField>,
 98{
 99    fn to_constraint_field(
100        &self,
101    ) -> Result<Vec<FpVar<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
102        let mut res = Vec::<FpVar<<P::BaseField as Field>::BasePrimeField>>::new();
103
104        res.extend_from_slice(&self.x.to_constraint_field()?);
105        res.extend_from_slice(&self.y.to_constraint_field()?);
106
107        Ok(res)
108    }
109}
110
111impl<P, F> R1CSVar<<P::BaseField as Field>::BasePrimeField> for ProjectiveVar<P, F>
112where
113    P: SWModelParameters,
114    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
115    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
116{
117    type Value = SWProjective<P>;
118
119    fn cs(&self) -> ConstraintSystemRef<<P::BaseField as Field>::BasePrimeField> {
120        self.x.cs().or(self.y.cs()).or(self.z.cs())
121    }
122
123    fn value(&self) -> Result<Self::Value, SynthesisError> {
124        let (x, y, z) = (self.x.value()?, self.y.value()?, self.z.value()?);
125        let result = if let Some(z_inv) = z.inverse() {
126            SWAffine::new(x * &z_inv, y * &z_inv, false)
127        } else {
128            SWAffine::zero()
129        };
130        Ok(result.into())
131    }
132}
133
134impl<P: SWModelParameters, F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>>
135    ProjectiveVar<P, F>
136where
137    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
138{
139    /// Constructs `Self` from an `(x, y, z)` coordinate triple.
140    pub fn new(x: F, y: F, z: F) -> Self {
141        Self {
142            x,
143            y,
144            z,
145            _params: PhantomData,
146        }
147    }
148
149    /// Convert this point into affine form.
150    #[tracing::instrument(target = "r1cs")]
151    pub fn to_affine(&self) -> Result<AffineVar<P, F>, SynthesisError> {
152        if self.is_constant() {
153            let point = self.value()?.into_affine();
154            let x = F::new_constant(ConstraintSystemRef::None, point.x)?;
155            let y = F::new_constant(ConstraintSystemRef::None, point.y)?;
156            let infinity = Boolean::constant(point.infinity);
157            Ok(AffineVar::new(x, y, infinity))
158        } else {
159            let infinity = self.is_zero()?;
160            let zero_x = F::zero();
161            let zero_y = F::one();
162
163            let non_zero_x = &self.x * &self.z;
164            let non_zero_y = &self.y * &self.z;
165
166            let x = infinity.select(&zero_x, &non_zero_x)?;
167            let y = infinity.select(&zero_y, &non_zero_y)?;
168
169            Ok(AffineVar::new(x, y, infinity))
170        }
171    }
172
173    /// Allocates a new variable without performing an on-curve check, which is
174    /// useful if the variable is known to be on the curve (eg., if the point
175    /// is a constant or is a public input).
176    #[tracing::instrument(target = "r1cs", skip(cs, f))]
177    pub fn new_variable_omit_on_curve_check(
178        cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>,
179        f: impl FnOnce() -> Result<SWProjective<P>, SynthesisError>,
180        mode: AllocationMode,
181    ) -> Result<Self, SynthesisError> {
182        let ns = cs.into();
183        let cs = ns.cs();
184
185        let (x, y, z) = match f() {
186            Ok(ge) => {
187                let ge = ge.into_affine();
188                if ge.is_zero() {
189                    (
190                        Ok(P::BaseField::zero()),
191                        Ok(P::BaseField::one()),
192                        Ok(P::BaseField::zero()),
193                    )
194                } else {
195                    (Ok(ge.x), Ok(ge.y), Ok(P::BaseField::one()))
196                }
197            }
198            _ => (
199                Err(SynthesisError::AssignmentMissing),
200                Err(SynthesisError::AssignmentMissing),
201                Err(SynthesisError::AssignmentMissing),
202            ),
203        };
204
205        let x = F::new_variable(ark_relations::ns!(cs, "x"), || x, mode)?;
206        let y = F::new_variable(ark_relations::ns!(cs, "y"), || y, mode)?;
207        let z = F::new_variable(ark_relations::ns!(cs, "z"), || z, mode)?;
208
209        Ok(Self::new(x, y, z))
210    }
211}
212
213impl<P, F> CurveVar<SWProjective<P>, <P::BaseField as Field>::BasePrimeField>
214    for ProjectiveVar<P, F>
215where
216    P: SWModelParameters,
217    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
218    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
219{
220    fn constant(g: SWProjective<P>) -> Self {
221        let cs = ConstraintSystemRef::None;
222        Self::new_variable_omit_on_curve_check(cs, || Ok(g), AllocationMode::Constant).unwrap()
223    }
224
225    fn zero() -> Self {
226        Self::new(F::zero(), F::one(), F::zero())
227    }
228
229    fn is_zero(&self) -> Result<Boolean<<P::BaseField as Field>::BasePrimeField>, SynthesisError> {
230        self.z.is_zero()
231    }
232
233    #[tracing::instrument(target = "r1cs", skip(cs, f))]
234    fn new_variable_omit_prime_order_check(
235        cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>,
236        f: impl FnOnce() -> Result<SWProjective<P>, SynthesisError>,
237        mode: AllocationMode,
238    ) -> Result<Self, SynthesisError> {
239        let ns = cs.into();
240        let cs = ns.cs();
241        // Curve equation in projective form:
242        // E: Y² * Z = X³ + aX * Z² + bZ³
243        //
244        // This can be re-written as
245        // E: Y² * Z - bZ³ = X³ + aX * Z²
246        // E: Z * (Y² - bZ²) = X * (X² + aZ²)
247        // so, compute X², Y², Z²,
248        //     compute temp = X * (X² + aZ²)
249        //     check Z.mul_equals((Y² - bZ²), temp)
250        //
251        //     A total of 5 multiplications
252
253        let g = Self::new_variable_omit_on_curve_check(cs, f, mode)?;
254
255        if mode != AllocationMode::Constant {
256            // Perform on-curve check.
257            let b = P::COEFF_B;
258            let a = P::COEFF_A;
259
260            let x2 = g.x.square()?;
261            let y2 = g.y.square()?;
262            let z2 = g.z.square()?;
263            let t = &g.x * (x2 + &z2 * a);
264
265            g.z.mul_equals(&(y2 - z2 * b), &t)?;
266        }
267        Ok(g)
268    }
269
270    /// Enforce that `self` is in the prime-order subgroup.
271    ///
272    /// Does so by multiplying by the prime order, and checking that the result
273    /// is unchanged.
274    // TODO: at the moment this doesn't work, because the addition and doubling
275    // formulae are incomplete for even-order points.
276    #[tracing::instrument(target = "r1cs")]
277    fn enforce_prime_order(&self) -> Result<(), SynthesisError> {
278        let r_minus_1 = (-P::ScalarField::one()).into_repr();
279
280        let mut result = Self::zero();
281        for b in BitIteratorBE::without_leading_zeros(r_minus_1) {
282            result.double_in_place()?;
283
284            if b {
285                result += self;
286            }
287        }
288        self.negate()?.enforce_equal(&result)?;
289        Ok(())
290    }
291
292    #[inline]
293    #[tracing::instrument(target = "r1cs")]
294    fn double_in_place(&mut self) -> Result<(), SynthesisError> {
295        // Complete doubling formula from Renes-Costello-Batina 2015
296        // Algorithm 3
297        // (https://eprint.iacr.org/2015/1060).
298        //
299        // Adapted from code in
300        // https://github.com/RustCrypto/elliptic-curves/blob/master/p256/src/arithmetic.rs
301        let three_b = P::COEFF_B.double() + &P::COEFF_B;
302
303        let xx = self.x.square()?; // 1
304        let yy = self.y.square()?; // 2
305        let zz = self.z.square()?; // 3
306        let xy2 = (&self.x * &self.y).double()?; // 4, 5
307        let xz2 = (&self.x * &self.z).double()?; // 6, 7
308
309        let axz2 = mul_by_coeff_a::<P, F>(&xz2); // 8
310
311        let bzz3_part = &axz2 + &zz * three_b; // 9, 10
312        let yy_m_bzz3 = &yy - &bzz3_part; // 11
313        let yy_p_bzz3 = &yy + &bzz3_part; // 12
314        let y_frag = yy_p_bzz3 * &yy_m_bzz3; // 13
315        let x_frag = yy_m_bzz3 * &xy2; // 14
316
317        let bxz3 = xz2 * three_b; // 15
318        let azz = mul_by_coeff_a::<P, F>(&zz); // 16
319        let b3_xz_pairs = mul_by_coeff_a::<P, F>(&(&xx - &azz)) + &bxz3; // 15, 16, 17, 18, 19
320        let xx3_p_azz = (xx.double()? + &xx + &azz) * &b3_xz_pairs; // 23, 24, 25
321
322        let y = y_frag + &xx3_p_azz; // 26, 27
323        let yz2 = (&self.y * &self.z).double()?; // 28, 29
324        let x = x_frag - &(b3_xz_pairs * &yz2); // 30, 31
325        let z = (yz2 * &yy).double()?.double()?; // 32, 33, 34
326        self.x = x;
327        self.y = y;
328        self.z = z;
329        Ok(())
330    }
331
332    #[tracing::instrument(target = "r1cs")]
333    fn negate(&self) -> Result<Self, SynthesisError> {
334        Ok(Self::new(self.x.clone(), self.y.negate()?, self.z.clone()))
335    }
336}
337
338fn mul_by_coeff_a<
339    P: SWModelParameters,
340    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
341>(
342    f: &F,
343) -> F
344where
345    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
346{
347    if !P::COEFF_A.is_zero() {
348        f * P::COEFF_A
349    } else {
350        F::zero()
351    }
352}
353
354impl_bounded_ops!(
355    ProjectiveVar<P, F>,
356    SWProjective<P>,
357    Add,
358    add,
359    AddAssign,
360    add_assign,
361    |this: &'a ProjectiveVar<P, F>, other: &'a ProjectiveVar<P, F>| {
362        // Complete addition formula from Renes-Costello-Batina 2015
363        // Algorithm 1
364        // (https://eprint.iacr.org/2015/1060).
365        //
366        // Adapted from code in
367        // https://github.com/RustCrypto/elliptic-curves/blob/master/p256/src/arithmetic.rs
368
369        let three_b = P::COEFF_B.double() + &P::COEFF_B;
370
371        let xx = &this.x * &other.x; // 1
372        let yy = &this.y * &other.y; // 2
373        let zz = &this.z * &other.z; // 3
374        let xy_pairs = ((&this.x + &this.y) * &(&other.x + &other.y)) - (&xx + &yy); // 4, 5, 6, 7, 8
375        let xz_pairs = ((&this.x + &this.z) * &(&other.x + &other.z)) - (&xx + &zz); // 9, 10, 11, 12, 13
376        let yz_pairs = ((&this.y + &this.z) * &(&other.y + &other.z)) - (&yy + &zz); // 14, 15, 16, 17, 18
377
378        let axz = mul_by_coeff_a::<P, F>(&xz_pairs); // 19
379
380        let bzz3_part = &axz + &zz * three_b; // 20, 21
381
382        let yy_m_bzz3 = &yy - &bzz3_part; // 22
383        let yy_p_bzz3 = &yy + &bzz3_part; // 23
384
385        let azz = mul_by_coeff_a::<P, F>(&zz);
386        let xx3_p_azz = xx.double().unwrap() + &xx + &azz; // 25, 26, 27, 29
387
388        let bxz3 = &xz_pairs * three_b; // 28
389        let b3_xz_pairs = mul_by_coeff_a::<P, F>(&(&xx - &azz)) + &bxz3; // 30, 31, 32
390
391        let x = (&yy_m_bzz3 * &xy_pairs) - &yz_pairs * &b3_xz_pairs; // 35, 39, 40
392        let y = (&yy_p_bzz3 * &yy_m_bzz3) + &xx3_p_azz * b3_xz_pairs; // 24, 36, 37, 38
393        let z = (&yy_p_bzz3 * &yz_pairs) + xy_pairs * xx3_p_azz; // 41, 42, 43
394
395        ProjectiveVar::new(x, y, z)
396    },
397    |this: &'a ProjectiveVar<P, F>, other: SWProjective<P>| {
398        this + ProjectiveVar::constant(other)
399    },
400    (F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, P: SWModelParameters),
401    for <'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
402);
403
404impl_bounded_ops!(
405    ProjectiveVar<P, F>,
406    SWProjective<P>,
407    Sub,
408    sub,
409    SubAssign,
410    sub_assign,
411    |this: &'a ProjectiveVar<P, F>, other: &'a ProjectiveVar<P, F>| this + other.negate().unwrap(),
412    |this: &'a ProjectiveVar<P, F>, other: SWProjective<P>| this - ProjectiveVar::constant(other),
413    (F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>, P: SWModelParameters),
414    for <'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>
415);
416
417impl<'a, P, F> GroupOpsBounds<'a, SWProjective<P>, ProjectiveVar<P, F>> for ProjectiveVar<P, F>
418where
419    P: SWModelParameters,
420    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
421    for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
422{
423}
424
425impl<'a, P, F> GroupOpsBounds<'a, SWProjective<P>, ProjectiveVar<P, F>> for &'a ProjectiveVar<P, F>
426where
427    P: SWModelParameters,
428    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
429    for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
430{
431}
432
433impl<P, F> CondSelectGadget<<P::BaseField as Field>::BasePrimeField> for ProjectiveVar<P, F>
434where
435    P: SWModelParameters,
436    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
437    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
438{
439    #[inline]
440    #[tracing::instrument(target = "r1cs")]
441    fn conditionally_select(
442        cond: &Boolean<<P::BaseField as Field>::BasePrimeField>,
443        true_value: &Self,
444        false_value: &Self,
445    ) -> Result<Self, SynthesisError> {
446        let x = cond.select(&true_value.x, &false_value.x)?;
447        let y = cond.select(&true_value.y, &false_value.y)?;
448        let z = cond.select(&true_value.z, &false_value.z)?;
449
450        Ok(Self::new(x, y, z))
451    }
452}
453
454impl<P, F> EqGadget<<P::BaseField as Field>::BasePrimeField> for ProjectiveVar<P, F>
455where
456    P: SWModelParameters,
457    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
458    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
459{
460    #[tracing::instrument(target = "r1cs")]
461    fn is_eq(
462        &self,
463        other: &Self,
464    ) -> Result<Boolean<<P::BaseField as Field>::BasePrimeField>, SynthesisError> {
465        let x_equal = (&self.x * &other.z).is_eq(&(&other.x * &self.z))?;
466        let y_equal = (&self.y * &other.z).is_eq(&(&other.y * &self.z))?;
467        let coordinates_equal = x_equal.and(&y_equal)?;
468        let both_are_zero = self.is_zero()?.and(&other.is_zero()?)?;
469        both_are_zero.or(&coordinates_equal)
470    }
471
472    #[inline]
473    #[tracing::instrument(target = "r1cs")]
474    fn conditional_enforce_equal(
475        &self,
476        other: &Self,
477        condition: &Boolean<<P::BaseField as Field>::BasePrimeField>,
478    ) -> Result<(), SynthesisError> {
479        let x_equal = (&self.x * &other.z).is_eq(&(&other.x * &self.z))?;
480        let y_equal = (&self.y * &other.z).is_eq(&(&other.y * &self.z))?;
481        let coordinates_equal = x_equal.and(&y_equal)?;
482        let both_are_zero = self.is_zero()?.and(&other.is_zero()?)?;
483        both_are_zero
484            .or(&coordinates_equal)?
485            .conditional_enforce_equal(&Boolean::Constant(true), condition)?;
486        Ok(())
487    }
488
489    #[inline]
490    #[tracing::instrument(target = "r1cs")]
491    fn conditional_enforce_not_equal(
492        &self,
493        other: &Self,
494        condition: &Boolean<<P::BaseField as Field>::BasePrimeField>,
495    ) -> Result<(), SynthesisError> {
496        let is_equal = self.is_eq(other)?;
497        is_equal
498            .and(condition)?
499            .enforce_equal(&Boolean::Constant(false))
500    }
501}
502
503impl<P, F> AllocVar<SWAffine<P>, <P::BaseField as Field>::BasePrimeField> for ProjectiveVar<P, F>
504where
505    P: SWModelParameters,
506    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
507    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
508{
509    fn new_variable<T: Borrow<SWAffine<P>>>(
510        cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>,
511        f: impl FnOnce() -> Result<T, SynthesisError>,
512        mode: AllocationMode,
513    ) -> Result<Self, SynthesisError> {
514        Self::new_variable(cs, || f().map(|b| b.borrow().into_projective()), mode)
515    }
516}
517
518impl<P, F> AllocVar<SWProjective<P>, <P::BaseField as Field>::BasePrimeField>
519    for ProjectiveVar<P, F>
520where
521    P: SWModelParameters,
522    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
523    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
524{
525    fn new_variable<T: Borrow<SWProjective<P>>>(
526        cs: impl Into<Namespace<<P::BaseField as Field>::BasePrimeField>>,
527        f: impl FnOnce() -> Result<T, SynthesisError>,
528        mode: AllocationMode,
529    ) -> Result<Self, SynthesisError> {
530        let ns = cs.into();
531        let cs = ns.cs();
532        let f = || Ok(*f()?.borrow());
533        match mode {
534            AllocationMode::Constant => Self::new_variable_omit_prime_order_check(cs, f, mode),
535            AllocationMode::Input => Self::new_variable_omit_prime_order_check(cs, f, mode),
536            AllocationMode::Witness => {
537                // if cofactor.is_even():
538                //   divide until you've removed all even factors
539                // else:
540                //   just directly use double and add.
541                let mut power_of_2: u32 = 0;
542                let mut cofactor = P::COFACTOR.to_vec();
543                while cofactor[0] % 2 == 0 {
544                    div2(&mut cofactor);
545                    power_of_2 += 1;
546                }
547
548                let cofactor_weight = BitIteratorBE::new(cofactor.as_slice())
549                    .filter(|b| *b)
550                    .count();
551                let modulus_minus_1 = (-P::ScalarField::one()).into_repr(); // r - 1
552                let modulus_minus_1_weight =
553                    BitIteratorBE::new(modulus_minus_1).filter(|b| *b).count();
554
555                // We pick the most efficient method of performing the prime order check:
556                // If the cofactor has lower hamming weight than the scalar field's modulus,
557                // we first multiply by the inverse of the cofactor, and then, after allocating,
558                // multiply by the cofactor. This ensures the resulting point has no cofactors
559                //
560                // Else, we multiply by the scalar field's modulus and ensure that the result
561                // equals the identity.
562
563                let (mut ge, iter) = if cofactor_weight < modulus_minus_1_weight {
564                    let ge = Self::new_variable_omit_prime_order_check(
565                        ark_relations::ns!(cs, "Witness without subgroup check with cofactor mul"),
566                        || f().map(|g| g.borrow().into_affine().mul_by_cofactor_inv().into()),
567                        mode,
568                    )?;
569                    (
570                        ge,
571                        BitIteratorBE::without_leading_zeros(cofactor.as_slice()),
572                    )
573                } else {
574                    let ge = Self::new_variable_omit_prime_order_check(
575                        ark_relations::ns!(cs, "Witness without subgroup check with `r` check"),
576                        || {
577                            f().map(|g| {
578                                let g = g.into_affine();
579                                let mut power_of_two = P::ScalarField::one().into_repr();
580                                power_of_two.muln(power_of_2);
581                                let power_of_two_inv = P::ScalarField::from_repr(power_of_two)
582                                    .and_then(|n| n.inverse())
583                                    .unwrap();
584                                g.mul(power_of_two_inv)
585                            })
586                        },
587                        mode,
588                    )?;
589
590                    (
591                        ge,
592                        BitIteratorBE::without_leading_zeros(modulus_minus_1.as_ref()),
593                    )
594                };
595                // Remove the even part of the cofactor
596                for _ in 0..power_of_2 {
597                    ge.double_in_place()?;
598                }
599
600                let mut result = Self::zero();
601                for b in iter {
602                    result.double_in_place()?;
603
604                    if b {
605                        result += &ge
606                    }
607                }
608                if cofactor_weight < modulus_minus_1_weight {
609                    Ok(result)
610                } else {
611                    ge.enforce_equal(&ge)?;
612                    Ok(ge)
613                }
614            }
615        }
616    }
617}
618
619#[inline]
620fn div2(limbs: &mut [u64]) {
621    let mut t = 0;
622    for i in limbs.iter_mut().rev() {
623        let t2 = *i << 63;
624        *i >>= 1;
625        *i |= t;
626        t = t2;
627    }
628}
629
630impl<P, F> ToBitsGadget<<P::BaseField as Field>::BasePrimeField> for ProjectiveVar<P, F>
631where
632    P: SWModelParameters,
633    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
634    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
635{
636    #[tracing::instrument(target = "r1cs")]
637    fn to_bits_le(
638        &self,
639    ) -> Result<Vec<Boolean<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
640        let g = self.to_affine()?;
641        let mut bits = g.x.to_bits_le()?;
642        let y_bits = g.y.to_bits_le()?;
643        bits.extend_from_slice(&y_bits);
644        bits.push(g.infinity);
645        Ok(bits)
646    }
647
648    #[tracing::instrument(target = "r1cs")]
649    fn to_non_unique_bits_le(
650        &self,
651    ) -> Result<Vec<Boolean<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
652        let g = self.to_affine()?;
653        let mut bits = g.x.to_non_unique_bits_le()?;
654        let y_bits = g.y.to_non_unique_bits_le()?;
655        bits.extend_from_slice(&y_bits);
656        bits.push(g.infinity);
657        Ok(bits)
658    }
659}
660
661impl<P, F> ToBytesGadget<<P::BaseField as Field>::BasePrimeField> for ProjectiveVar<P, F>
662where
663    P: SWModelParameters,
664    F: FieldVar<P::BaseField, <P::BaseField as Field>::BasePrimeField>,
665    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
666{
667    #[tracing::instrument(target = "r1cs")]
668    fn to_bytes(
669        &self,
670    ) -> Result<Vec<UInt8<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
671        let g = self.to_affine()?;
672        let mut bytes = g.x.to_bytes()?;
673        let y_bytes = g.y.to_bytes()?;
674        let inf_bytes = g.infinity.to_bytes()?;
675        bytes.extend_from_slice(&y_bytes);
676        bytes.extend_from_slice(&inf_bytes);
677        Ok(bytes)
678    }
679
680    #[tracing::instrument(target = "r1cs")]
681    fn to_non_unique_bytes(
682        &self,
683    ) -> Result<Vec<UInt8<<P::BaseField as Field>::BasePrimeField>>, SynthesisError> {
684        let g = self.to_affine()?;
685        let mut bytes = g.x.to_non_unique_bytes()?;
686        let y_bytes = g.y.to_non_unique_bytes()?;
687        let inf_bytes = g.infinity.to_non_unique_bytes()?;
688        bytes.extend_from_slice(&y_bytes);
689        bytes.extend_from_slice(&inf_bytes);
690        Ok(bytes)
691    }
692}