Skip to main content

ark_r1cs_std/groups/curves/twisted_edwards/
mod.rs

1use ark_ec::{
2    models::CurveConfig,
3    twisted_edwards::{
4        Affine as TEAffine, MontCurveConfig, Projective as TEProjective, TECurveConfig,
5    },
6    AdditiveGroup, AffineRepr, CurveGroup,
7};
8use ark_ff::{BitIteratorBE, Field, One, PrimeField, Zero};
9use ark_relations::gr1cs::{ConstraintSystemRef, Namespace, SynthesisError};
10
11use crate::{convert::ToConstraintFieldGadget, fields::emulated_fp::EmulatedFpVar, prelude::*};
12
13use crate::fields::fp::FpVar;
14use ark_std::{borrow::Borrow, marker::PhantomData, ops::Mul, vec::Vec};
15use educe::Educe;
16
17type BasePrimeField<P> = <<P as CurveConfig>::BaseField as Field>::BasePrimeField;
18
19/// An implementation of arithmetic for Montgomery curves that relies on
20/// incomplete addition formulae for the affine model, as outlined in the
21/// [EFD](https://www.hyperelliptic.org/EFD/g1p/auto-montgom.html).
22///
23/// This is intended for use primarily for implementing efficient
24/// multi-scalar-multiplication in the Bowe-Hopwood-Pedersen hash.
25#[derive(Educe)]
26#[educe(Debug, Clone)]
27#[must_use]
28pub struct MontgomeryAffineVar<P: TECurveConfig, F: FieldVar<P::BaseField, BasePrimeField<P>>>
29where
30    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
31{
32    /// The x-coordinate.
33    pub x: F,
34    /// The y-coordinate.
35    pub y: F,
36    #[educe(Debug(ignore))]
37    _params: PhantomData<P>,
38}
39
40mod montgomery_affine_impl {
41    use super::*;
42    use ark_ec::twisted_edwards::MontgomeryAffine as GroupAffine;
43    use core::ops::Add;
44
45    impl<P, F> GR1CSVar<BasePrimeField<P>> for MontgomeryAffineVar<P, F>
46    where
47        P: TECurveConfig,
48        F: FieldVar<P::BaseField, BasePrimeField<P>>,
49        for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
50    {
51        type Value = (P::BaseField, P::BaseField);
52
53        fn cs(&self) -> ConstraintSystemRef<BasePrimeField<P>> {
54            self.x.cs().or(self.y.cs())
55        }
56
57        fn value(&self) -> Result<Self::Value, SynthesisError> {
58            let x = self.x.value()?;
59            let y = self.y.value()?;
60            Ok((x, y))
61        }
62    }
63
64    impl<P: TECurveConfig, F: FieldVar<P::BaseField, BasePrimeField<P>>> MontgomeryAffineVar<P, F>
65    where
66        for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
67    {
68        /// Constructs `Self` from an `(x, y)` coordinate pair.
69        pub fn new(x: F, y: F) -> Self {
70            Self {
71                x,
72                y,
73                _params: PhantomData,
74            }
75        }
76
77        /// Converts a Twisted Edwards curve point to coordinates for the
78        /// corresponding affine Montgomery curve point.
79        #[tracing::instrument(target = "gr1cs")]
80        pub fn from_edwards_to_coords(
81            p: &TEAffine<P>,
82        ) -> Result<(P::BaseField, P::BaseField), SynthesisError> {
83            let montgomery_point: GroupAffine<P::MontCurveConfig> = if p.y == P::BaseField::one() {
84                return Err(SynthesisError::Unsatisfiable);
85            } else if p.x == P::BaseField::zero() {
86                GroupAffine::new(P::BaseField::zero(), P::BaseField::zero())
87            } else {
88                let u =
89                    (P::BaseField::one() + &p.y) * &(P::BaseField::one() - &p.y).inverse().unwrap();
90                let v = u * &p.x.inverse().unwrap();
91                GroupAffine::new(u, v)
92            };
93
94            Ok((montgomery_point.x, montgomery_point.y))
95        }
96
97        /// Converts a Twisted Edwards curve point to coordinates for the
98        /// corresponding affine Montgomery curve point.
99        #[tracing::instrument(target = "gr1cs")]
100        pub fn new_witness_from_edwards(
101            cs: ConstraintSystemRef<BasePrimeField<P>>,
102            p: &TEAffine<P>,
103        ) -> Result<Self, SynthesisError> {
104            let montgomery_coords = Self::from_edwards_to_coords(p)?;
105            let u = F::new_witness(ark_relations::ns!(cs, "u"), || Ok(montgomery_coords.0))?;
106            let v = F::new_witness(ark_relations::ns!(cs, "v"), || Ok(montgomery_coords.1))?;
107            Ok(Self::new(u, v))
108        }
109
110        /// Converts `self` into a Twisted Edwards curve point variable.
111        #[tracing::instrument(target = "gr1cs")]
112        pub fn into_edwards(&self) -> Result<AffineVar<P, F>, SynthesisError> {
113            let cs = self.cs();
114
115            let mode = if cs.is_none() {
116                AllocationMode::Constant
117            } else {
118                AllocationMode::Witness
119            };
120
121            // Compute u = x / y
122            let u = F::new_variable(
123                ark_relations::ns!(cs, "u"),
124                || {
125                    let y_inv = self
126                        .y
127                        .value()?
128                        .inverse()
129                        .ok_or(SynthesisError::DivisionByZero)?;
130                    Ok(self.x.value()? * &y_inv)
131                },
132                mode,
133            )?;
134
135            u.mul_equals(&self.y, &self.x)?;
136
137            let v = F::new_variable(
138                ark_relations::ns!(cs, "v"),
139                || {
140                    let mut t0 = self.x.value()?;
141                    let mut t1 = t0;
142                    t0 -= &P::BaseField::one();
143                    t1 += &P::BaseField::one();
144
145                    Ok(t0 * &t1.inverse().ok_or(SynthesisError::DivisionByZero)?)
146                },
147                mode,
148            )?;
149
150            let xplusone = &self.x + P::BaseField::one();
151            let xminusone = &self.x - P::BaseField::one();
152            v.mul_equals(&xplusone, &xminusone)?;
153
154            Ok(AffineVar::new(u, v))
155        }
156    }
157
158    impl<'a, P, F> Add<&'a MontgomeryAffineVar<P, F>> for MontgomeryAffineVar<P, F>
159    where
160        P: TECurveConfig,
161        F: FieldVar<P::BaseField, BasePrimeField<P>>,
162        for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
163    {
164        type Output = MontgomeryAffineVar<P, F>;
165
166        #[tracing::instrument(target = "gr1cs")]
167        fn add(self, other: &'a Self) -> Self::Output {
168            let cs = [&self, other].cs();
169            let mode = if cs.is_none() {
170                AllocationMode::Constant
171            } else {
172                AllocationMode::Witness
173            };
174
175            let coeff_b = P::MontCurveConfig::COEFF_B;
176            let coeff_a = P::MontCurveConfig::COEFF_A;
177
178            let lambda = F::new_variable(
179                ark_relations::ns!(cs, "lambda"),
180                || {
181                    let n = other.y.value()? - &self.y.value()?;
182                    let d = other.x.value()? - &self.x.value()?;
183                    Ok(n * &d.inverse().ok_or(SynthesisError::DivisionByZero)?)
184                },
185                mode,
186            )
187            .unwrap();
188            let lambda_n = &other.y - &self.y;
189            let lambda_d = &other.x - &self.x;
190            lambda_d.mul_equals(&lambda, &lambda_n).unwrap();
191
192            // Compute x'' = B*lambda^2 - A - x - x'
193            let xprime = F::new_variable(
194                ark_relations::ns!(cs, "xprime"),
195                || {
196                    Ok(lambda.value()?.square() * &coeff_b
197                        - &coeff_a
198                        - &self.x.value()?
199                        - &other.x.value()?)
200                },
201                mode,
202            )
203            .unwrap();
204
205            let xprime_lc = &self.x + &other.x + &xprime + coeff_a;
206            // (lambda) * (lambda) = (A + x + x' + x'')
207            let lambda_b = &lambda * coeff_b;
208            lambda_b.mul_equals(&lambda, &xprime_lc).unwrap();
209
210            let yprime = F::new_variable(
211                ark_relations::ns!(cs, "yprime"),
212                || {
213                    Ok(-(self.y.value()?
214                        + &(lambda.value()? * &(xprime.value()? - &self.x.value()?))))
215                },
216                mode,
217            )
218            .unwrap();
219
220            let xres = &self.x - &xprime;
221            let yres = &self.y + &yprime;
222            lambda.mul_equals(&xres, &yres).unwrap();
223            MontgomeryAffineVar::new(xprime, yprime)
224        }
225    }
226}
227
228/// An implementation of arithmetic for Twisted Edwards curves that relies on
229/// the complete formulae for the affine model, as outlined in the
230/// [EFD](https://www.hyperelliptic.org/EFD/g1p/auto-twisted.html).
231#[derive(Educe)]
232#[educe(Debug, Clone)]
233#[must_use]
234pub struct AffineVar<P: TECurveConfig, F: FieldVar<P::BaseField, BasePrimeField<P>>>
235where
236    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
237{
238    /// The x-coordinate.
239    pub x: F,
240    /// The y-coordinate.
241    pub y: F,
242    #[educe(Debug(ignore))]
243    _params: PhantomData<P>,
244}
245
246impl<P: TECurveConfig, F: FieldVar<P::BaseField, BasePrimeField<P>>> AffineVar<P, F>
247where
248    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
249{
250    /// Constructs `Self` from an `(x, y)` coordinate triple.
251    pub fn new(x: F, y: F) -> Self {
252        Self {
253            x,
254            y,
255            _params: PhantomData,
256        }
257    }
258
259    /// Allocates a new variable without performing an on-curve check, which is
260    /// useful if the variable is known to be on the curve (eg., if the point
261    /// is a constant or is a public input).
262    #[tracing::instrument(target = "gr1cs", skip(cs, f))]
263    pub fn new_variable_omit_on_curve_check<T: Into<TEAffine<P>>>(
264        cs: impl Into<Namespace<BasePrimeField<P>>>,
265        f: impl FnOnce() -> Result<T, SynthesisError>,
266        mode: AllocationMode,
267    ) -> Result<Self, SynthesisError> {
268        let ns = cs.into();
269        let cs = ns.cs();
270
271        let (x, y) = match f() {
272            Ok(ge) => {
273                let ge: TEAffine<P> = ge.into();
274                (Ok(ge.x), Ok(ge.y))
275            },
276            _ => (
277                Err(SynthesisError::AssignmentMissing),
278                Err(SynthesisError::AssignmentMissing),
279            ),
280        };
281
282        let x = F::new_variable(ark_relations::ns!(cs, "x"), || x, mode)?;
283        let y = F::new_variable(ark_relations::ns!(cs, "y"), || y, mode)?;
284
285        Ok(Self::new(x, y))
286    }
287}
288
289impl<P: TECurveConfig, F: FieldVar<P::BaseField, BasePrimeField<P>>> AffineVar<P, F>
290where
291    P: TECurveConfig,
292    F: FieldVar<P::BaseField, BasePrimeField<P>>
293        + TwoBitLookupGadget<BasePrimeField<P>, TableConstant = P::BaseField>
294        + ThreeBitCondNegLookupGadget<BasePrimeField<P>, TableConstant = P::BaseField>,
295    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
296{
297    /// Compute a scalar multiplication of `bases` with respect to `scalars`,
298    /// where the elements of `scalars` are length-three slices of bits, and
299    /// which such that the first two bits are use to select one of the
300    /// bases, while the third bit is used to conditionally negate the
301    /// selection.
302    #[tracing::instrument(target = "gr1cs", skip(bases, scalars))]
303    pub fn precomputed_base_3_bit_signed_digit_scalar_mul<J>(
304        bases: &[impl Borrow<[TEProjective<P>]>],
305        scalars: &[impl Borrow<[J]>],
306    ) -> Result<Self, SynthesisError>
307    where
308        J: Borrow<[Boolean<BasePrimeField<P>>]>,
309    {
310        const CHUNK_SIZE: usize = 3;
311        let mut ed_result: Option<AffineVar<P, F>> = None;
312        let mut result: Option<MontgomeryAffineVar<P, F>> = None;
313
314        let mut process_segment_result = |result: &MontgomeryAffineVar<P, F>| {
315            let sgmt_result = result.into_edwards()?;
316            ed_result = match ed_result.as_ref() {
317                None => Some(sgmt_result),
318                Some(r) => Some(sgmt_result + r),
319            };
320            Ok::<(), SynthesisError>(())
321        };
322
323        // Compute ∏(h_i^{m_i}) for all i.
324        for (segment_bits_chunks, segment_powers) in scalars.iter().zip(bases) {
325            for (bits, base_power) in segment_bits_chunks
326                .borrow()
327                .iter()
328                .zip(segment_powers.borrow())
329            {
330                let mut acc_power = *base_power;
331                let mut coords = vec![];
332                for _ in 0..4 {
333                    coords.push(acc_power);
334                    acc_power += base_power;
335                }
336
337                let bits = bits.borrow().to_bits_le()?;
338                if bits.len() != CHUNK_SIZE {
339                    return Err(SynthesisError::Unsatisfiable);
340                }
341
342                let coords = coords
343                    .iter()
344                    .map(|p| MontgomeryAffineVar::from_edwards_to_coords(&p.into_affine()))
345                    .collect::<Result<Vec<_>, _>>()?;
346
347                let x_coeffs = coords.iter().map(|p| p.0).collect::<Vec<_>>();
348                let y_coeffs = coords.iter().map(|p| p.1).collect::<Vec<_>>();
349
350                let precomp = &bits[0] & &bits[1];
351
352                let x = F::zero()
353                    + x_coeffs[0]
354                    + F::from(bits[0].clone()) * (x_coeffs[1] - &x_coeffs[0])
355                    + F::from(bits[1].clone()) * (x_coeffs[2] - &x_coeffs[0])
356                    + F::from(precomp.clone())
357                        * (x_coeffs[3] - &x_coeffs[2] - &x_coeffs[1] + &x_coeffs[0]);
358
359                let y = F::three_bit_cond_neg_lookup(&bits, &precomp, &y_coeffs)?;
360
361                let tmp = MontgomeryAffineVar::new(x, y);
362                result = match result.as_ref() {
363                    None => Some(tmp),
364                    Some(r) => Some(tmp + r),
365                };
366            }
367
368            process_segment_result(&result.unwrap())?;
369            result = None;
370        }
371        if result.is_some() {
372            process_segment_result(&result.unwrap())?;
373        }
374        Ok(ed_result.unwrap())
375    }
376}
377
378impl<P, F> GR1CSVar<BasePrimeField<P>> for AffineVar<P, F>
379where
380    P: TECurveConfig,
381    F: FieldVar<P::BaseField, BasePrimeField<P>>,
382    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
383{
384    type Value = TEProjective<P>;
385
386    fn cs(&self) -> ConstraintSystemRef<BasePrimeField<P>> {
387        self.x.cs().or(self.y.cs())
388    }
389
390    #[inline]
391    fn value(&self) -> Result<TEProjective<P>, SynthesisError> {
392        let (x, y) = (self.x.value()?, self.y.value()?);
393        let result = TEAffine::new(x, y);
394        Ok(result.into())
395    }
396}
397
398impl<P, F> CurveVar<TEProjective<P>, BasePrimeField<P>> for AffineVar<P, F>
399where
400    P: TECurveConfig,
401    F: FieldVar<P::BaseField, BasePrimeField<P>>
402        + TwoBitLookupGadget<BasePrimeField<P>, TableConstant = P::BaseField>,
403    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
404{
405    type BaseFieldVar = F;
406
407    fn constant(g: TEProjective<P>) -> Self {
408        let cs = ConstraintSystemRef::None;
409        Self::new_variable_omit_on_curve_check(cs, || Ok(g), AllocationMode::Constant).unwrap()
410    }
411
412    fn zero() -> Self {
413        Self::new(F::zero(), F::one())
414    }
415
416    fn is_zero(&self) -> Result<Boolean<BasePrimeField<P>>, SynthesisError> {
417        Ok(self.x.is_zero()? & &self.y.is_one()?)
418    }
419
420    #[tracing::instrument(target = "gr1cs", skip(cs, f))]
421    fn new_variable_omit_prime_order_check(
422        cs: impl Into<Namespace<BasePrimeField<P>>>,
423        f: impl FnOnce() -> Result<TEProjective<P>, SynthesisError>,
424        mode: AllocationMode,
425    ) -> Result<Self, SynthesisError> {
426        let ns = cs.into();
427        let cs = ns.cs();
428
429        let g = Self::new_variable_omit_on_curve_check(cs, f, mode)?;
430
431        if mode != AllocationMode::Constant {
432            let d = P::COEFF_D;
433            let a = P::COEFF_A;
434            // Check that ax^2 + y^2 = 1 + dx^2y^2
435            // We do this by checking that ax^2 - 1 = y^2 * (dx^2 - 1)
436            let x2 = g.x.square()?;
437            let y2 = g.y.square()?;
438
439            let one = P::BaseField::one();
440            let d_x2_minus_one = &x2 * d - one;
441            let a_x2_minus_one = &x2 * a - one;
442
443            d_x2_minus_one.mul_equals(&y2, &a_x2_minus_one)?;
444        }
445        Ok(g)
446    }
447
448    /// Enforce that `self` is in the prime-order subgroup.
449    ///
450    /// Does so by multiplying by the prime order, and checking that the result
451    /// is unchanged.
452    #[tracing::instrument(target = "gr1cs")]
453    fn enforce_prime_order(&self) -> Result<(), SynthesisError> {
454        let r_minus_1 = (-P::ScalarField::one()).into_bigint();
455
456        let mut result = Self::zero();
457        for b in BitIteratorBE::without_leading_zeros(r_minus_1) {
458            result.double_in_place()?;
459
460            if b {
461                result += self;
462            }
463        }
464        self.negate()?.enforce_equal(&result)?;
465        Ok(())
466    }
467
468    #[inline]
469    #[tracing::instrument(target = "gr1cs")]
470    fn double_in_place(&mut self) -> Result<(), SynthesisError> {
471        if self.is_constant() {
472            let value = self.value()?;
473            *self = Self::constant(value.double());
474        } else {
475            let cs = self.cs();
476            let a = P::COEFF_A;
477
478            // xy
479            let xy = &self.x * &self.y;
480            let x2 = self.x.square()?;
481            let y2 = self.y.square()?;
482
483            let a_x2 = &x2 * a;
484
485            // Compute x3 = (2xy) / (ax^2 + y^2)
486            let x3 = F::new_witness(ark_relations::ns!(cs, "x3"), || {
487                let t0 = xy.value()?.double();
488                let t1 = a * &x2.value()? + &y2.value()?;
489                Ok(t0 * &t1.inverse().ok_or(SynthesisError::DivisionByZero)?)
490            })?;
491
492            let a_x2_plus_y2 = &a_x2 + &y2;
493            let two_xy = xy.double()?;
494            x3.mul_equals(&a_x2_plus_y2, &two_xy)?;
495
496            // Compute y3 = (y^2 - ax^2) / (2 - ax^2 - y^2)
497            let two = P::BaseField::one().double();
498            let y3 = F::new_witness(ark_relations::ns!(cs, "y3"), || {
499                let a_x2 = a * &x2.value()?;
500                let t0 = y2.value()? - &a_x2;
501                let t1 = two - &a_x2 - &y2.value()?;
502                Ok(t0 * &t1.inverse().ok_or(SynthesisError::DivisionByZero)?)
503            })?;
504            let y2_minus_a_x2 = &y2 - &a_x2;
505            let two_minus_ax2_minus_y2 = (&a_x2 + &y2).negate()? + two;
506
507            y3.mul_equals(&two_minus_ax2_minus_y2, &y2_minus_a_x2)?;
508            self.x = x3;
509            self.y = y3;
510        }
511        Ok(())
512    }
513
514    #[tracing::instrument(target = "gr1cs")]
515    fn negate(&self) -> Result<Self, SynthesisError> {
516        Ok(Self::new(self.x.negate()?, self.y.clone()))
517    }
518
519    #[tracing::instrument(target = "gr1cs", skip(scalar_bits_with_base_multiples))]
520    fn precomputed_base_scalar_mul_le<'a, I, B>(
521        &mut self,
522        scalar_bits_with_base_multiples: I,
523    ) -> Result<(), SynthesisError>
524    where
525        I: Iterator<Item = (B, &'a TEProjective<P>)>,
526        B: Borrow<Boolean<BasePrimeField<P>>>,
527    {
528        let (bits, multiples): (Vec<_>, Vec<_>) = scalar_bits_with_base_multiples
529            .map(|(bit, base)| (bit.borrow().clone(), *base))
530            .unzip();
531        let zero: TEAffine<P> = TEProjective::zero().into_affine();
532        for (bits, multiples) in bits.chunks(2).zip(multiples.chunks(2)) {
533            if bits.len() == 2 {
534                let table_projective = [multiples[0], multiples[1], multiples[0] + multiples[1]];
535
536                let table = TEProjective::normalize_batch(&table_projective);
537                let x_s = [zero.x, table[0].x, table[1].x, table[2].x];
538                let y_s = [zero.y, table[0].y, table[1].y, table[2].y];
539
540                let x = F::two_bit_lookup(&bits, &x_s)?;
541                let y = F::two_bit_lookup(&bits, &y_s)?;
542                *self += Self::new(x, y);
543            } else if bits.len() == 1 {
544                let bit = &bits[0];
545                let tmp = &*self + multiples[0];
546                *self = bit.select(&tmp, &*self)?;
547            }
548        }
549
550        Ok(())
551    }
552
553    fn affine_xy(&self) -> Result<(F, F), SynthesisError> {
554        Ok((self.x.clone(), self.y.clone()))
555    }
556}
557
558impl<P, F> AllocVar<TEProjective<P>, BasePrimeField<P>> for AffineVar<P, F>
559where
560    P: TECurveConfig,
561    F: FieldVar<P::BaseField, BasePrimeField<P>>
562        + TwoBitLookupGadget<BasePrimeField<P>, TableConstant = P::BaseField>,
563    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
564{
565    #[tracing::instrument(target = "gr1cs", skip(cs, f))]
566    fn new_variable<Point: Borrow<TEProjective<P>>>(
567        cs: impl Into<Namespace<BasePrimeField<P>>>,
568        f: impl FnOnce() -> Result<Point, SynthesisError>,
569        mode: AllocationMode,
570    ) -> Result<Self, SynthesisError> {
571        let ns = cs.into();
572        let cs = ns.cs();
573        let f = || Ok(*f()?.borrow());
574        match mode {
575            AllocationMode::Constant => Self::new_variable_omit_prime_order_check(cs, f, mode),
576            AllocationMode::Input => Self::new_variable_omit_prime_order_check(cs, f, mode),
577            AllocationMode::Witness => {
578                // if cofactor.is_even():
579                //   divide until you've removed all even factors
580                // else:
581                //   just directly use double and add.
582                let mut power_of_2: u32 = 0;
583                let mut cofactor = P::COFACTOR.to_vec();
584                while cofactor[0] % 2 == 0 {
585                    div2(&mut cofactor);
586                    power_of_2 += 1;
587                }
588
589                let cofactor_weight = BitIteratorBE::new(cofactor.as_slice())
590                    .filter(|b| *b)
591                    .count();
592                let modulus_minus_1 = (-P::ScalarField::one()).into_bigint(); // r - 1
593                let modulus_minus_1_weight =
594                    BitIteratorBE::new(modulus_minus_1).filter(|b| *b).count();
595
596                // We pick the most efficient method of performing the prime order check:
597                // If the cofactor has lower hamming weight than the scalar field's modulus,
598                // we first multiply by the inverse of the cofactor, and then, after allocating,
599                // multiply by the cofactor. This ensures the resulting point has no cofactors
600                //
601                // Else, we multiply by the scalar field's modulus and ensure that the result
602                // equals the identity.
603
604                let (mut ge, iter) = if cofactor_weight < modulus_minus_1_weight {
605                    let ge = Self::new_variable_omit_prime_order_check(
606                        ark_relations::ns!(cs, "Witness without subgroup check with cofactor mul"),
607                        || f().map(|g| g.into_affine().mul_by_cofactor_inv().into()),
608                        mode,
609                    )?;
610                    (
611                        ge,
612                        BitIteratorBE::without_leading_zeros(cofactor.as_slice()),
613                    )
614                } else {
615                    let ge = Self::new_variable_omit_prime_order_check(
616                        ark_relations::ns!(cs, "Witness without subgroup check with `r` check"),
617                        || {
618                            f().map(|g| {
619                                let g = g.into_affine();
620                                let power_of_two = P::ScalarField::ONE.into_bigint() << power_of_2;
621                                let power_of_two_inv = P::ScalarField::from_bigint(power_of_two)
622                                    .and_then(|n| n.inverse())
623                                    .unwrap();
624                                g.mul(power_of_two_inv)
625                            })
626                        },
627                        mode,
628                    )?;
629
630                    (
631                        ge,
632                        BitIteratorBE::without_leading_zeros(modulus_minus_1.as_ref()),
633                    )
634                };
635                // Remove the even part of the cofactor
636                for _ in 0..power_of_2 {
637                    ge.double_in_place()?;
638                }
639
640                let mut result = Self::zero();
641                for b in iter {
642                    result.double_in_place()?;
643                    if b {
644                        result += &ge;
645                    }
646                }
647                if cofactor_weight < modulus_minus_1_weight {
648                    Ok(result)
649                } else {
650                    ge.enforce_equal(&ge)?;
651                    Ok(ge)
652                }
653            },
654        }
655    }
656}
657
658impl<P, F> AllocVar<TEAffine<P>, BasePrimeField<P>> for AffineVar<P, F>
659where
660    P: TECurveConfig,
661    F: FieldVar<P::BaseField, BasePrimeField<P>>
662        + TwoBitLookupGadget<BasePrimeField<P>, TableConstant = P::BaseField>,
663    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
664{
665    #[tracing::instrument(target = "gr1cs", skip(cs, f))]
666    fn new_variable<Point: Borrow<TEAffine<P>>>(
667        cs: impl Into<Namespace<BasePrimeField<P>>>,
668        f: impl FnOnce() -> Result<Point, SynthesisError>,
669        mode: AllocationMode,
670    ) -> Result<Self, SynthesisError> {
671        Self::new_variable(
672            cs,
673            || f().map(|b| TEProjective::<P>::from((*b.borrow()).clone())),
674            mode,
675        )
676    }
677}
678
679impl<P, F> ToConstraintFieldGadget<BasePrimeField<P>> for AffineVar<P, F>
680where
681    P: TECurveConfig,
682    F: FieldVar<P::BaseField, BasePrimeField<P>>,
683    for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
684    F: ToConstraintFieldGadget<BasePrimeField<P>>,
685{
686    fn to_constraint_field(&self) -> Result<Vec<FpVar<BasePrimeField<P>>>, SynthesisError> {
687        let mut res = Vec::new();
688
689        res.extend_from_slice(&self.x.to_constraint_field()?);
690        res.extend_from_slice(&self.y.to_constraint_field()?);
691
692        Ok(res)
693    }
694}
695
696#[inline]
697fn div2(limbs: &mut [u64]) {
698    let mut t = 0;
699    for i in limbs.iter_mut().rev() {
700        let t2 = *i << 63;
701        *i >>= 1;
702        *i |= t;
703        t = t2;
704    }
705}
706
707impl_bounded_ops!(
708    AffineVar<P, F>,
709    TEProjective<P>,
710    Add,
711    add,
712    AddAssign,
713    add_assign,
714    |this: &'a AffineVar<P, F>, other: &'a AffineVar<P, F>| {
715
716        if [this, other].is_constant() {
717            assert!(this.is_constant() && other.is_constant());
718            AffineVar::constant(this.value().unwrap() + &other.value().unwrap())
719        } else {
720            let cs = [this, other].cs();
721            let a = P::COEFF_A;
722            let d = P::COEFF_D;
723
724            // Compute U = (x1 + y1) * (x2 + y2)
725            let u1 = (&this.x * -a) + &this.y;
726            let u2 = &other.x + &other.y;
727
728            let u = u1 *  &u2;
729
730            // Compute v0 = x1 * y2
731            let v0 = &other.y * &this.x;
732
733            // Compute v1 = x2 * y1
734            let v1 = &other.x * &this.y;
735
736            // Compute C = d*v0*v1
737            let v2 = &v0 * &v1 * d;
738
739            // Compute x3 = (v0 + v1) / (1 + v2)
740            let x3 = F::new_witness(ark_relations::ns!(cs, "x3"), || {
741                let t0 = v0.value()? + &v1.value()?;
742                let t1 = P::BaseField::one() + &v2.value()?;
743                Ok(t0 * &t1.inverse().ok_or(SynthesisError::DivisionByZero)?)
744            }).unwrap();
745
746            let v2_plus_one = &v2 + P::BaseField::one();
747            let v0_plus_v1 = &v0 + &v1;
748            x3.mul_equals(&v2_plus_one, &v0_plus_v1).unwrap();
749
750            // Compute y3 = (U + a * v0 - v1) / (1 - v2)
751            let y3 = F::new_witness(ark_relations::ns!(cs, "y3"), || {
752                let t0 = u.value()? + &(a * &v0.value()?) - &v1.value()?;
753                let t1 = P::BaseField::one() - &v2.value()?;
754                Ok(t0 * &t1.inverse().ok_or(SynthesisError::DivisionByZero)?)
755            }).unwrap();
756
757            let one_minus_v2 = (&v2 - P::BaseField::one()).negate().unwrap();
758            let a_v0 = &v0 * a;
759            let u_plus_a_v0_minus_v1 = &u + &a_v0 - &v1;
760
761            y3.mul_equals(&one_minus_v2, &u_plus_a_v0_minus_v1).unwrap();
762
763            AffineVar::new(x3, y3)
764        }
765    },
766    |this: &'a AffineVar<P, F>, other: TEProjective<P>| this + AffineVar::constant(other),
767    (
768        F :FieldVar<P::BaseField, BasePrimeField<P>>
769            + TwoBitLookupGadget<BasePrimeField<P>, TableConstant = P::BaseField>,
770        P: TECurveConfig,
771    ),
772    for <'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
773);
774
775impl_bounded_ops!(
776    AffineVar<P, F>,
777    TEProjective<P>,
778    Sub,
779    sub,
780    SubAssign,
781    sub_assign,
782    |this: &'a AffineVar<P, F>, other: &'a AffineVar<P, F>| this + other.negate().unwrap(),
783    |this: &'a AffineVar<P, F>, other: TEProjective<P>| this - AffineVar::constant(other),
784    (
785        F :FieldVar<P::BaseField, BasePrimeField<P>>
786            + TwoBitLookupGadget<BasePrimeField<P>, TableConstant = P::BaseField>,
787        P: TECurveConfig,
788    ),
789    for <'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>
790);
791
792impl_bounded_ops_diff!(
793    AffineVar<P, F>,
794    TEProjective<P>,
795    EmulatedFpVar<P::ScalarField, BasePrimeField<P>>,
796    P::ScalarField,
797    Mul,
798    mul,
799    MulAssign,
800    mul_assign,
801    |this: &'a AffineVar<P, F>, other: &'a EmulatedFpVar<P::ScalarField, BasePrimeField<P>>| {
802        if this.is_constant() && other.is_constant() {
803            assert!(this.is_constant() && other.is_constant());
804            AffineVar::constant(this.value().unwrap() * &other.value().unwrap())
805        } else {
806            let bits = other.to_bits_le().unwrap();
807            this.scalar_mul_le(bits.iter()).unwrap()
808        }
809    },
810    |this: &'a AffineVar<P, F>, other: P::ScalarField| this * EmulatedFpVar::constant(other),
811    (
812        F :FieldVar<P::BaseField, BasePrimeField<P>>
813            + TwoBitLookupGadget<BasePrimeField<P>, TableConstant = P::BaseField>,
814        P: TECurveConfig,
815    ),
816    for <'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
817);
818
819impl<'a, P, F> GroupOpsBounds<'a, TEProjective<P>, AffineVar<P, F>> for AffineVar<P, F>
820where
821    P: TECurveConfig,
822    F: FieldVar<P::BaseField, BasePrimeField<P>>
823        + TwoBitLookupGadget<BasePrimeField<P>, TableConstant = P::BaseField>,
824    for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
825{
826}
827
828impl<'a, P, F> GroupOpsBounds<'a, TEProjective<P>, AffineVar<P, F>> for &'a AffineVar<P, F>
829where
830    P: TECurveConfig,
831    F: FieldVar<P::BaseField, BasePrimeField<P>>
832        + TwoBitLookupGadget<BasePrimeField<P>, TableConstant = P::BaseField>,
833    for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
834{
835}
836
837impl<P, F> CondSelectGadget<BasePrimeField<P>> for AffineVar<P, F>
838where
839    P: TECurveConfig,
840    F: FieldVar<P::BaseField, BasePrimeField<P>>,
841    for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
842{
843    #[inline]
844    #[tracing::instrument(target = "gr1cs")]
845    fn conditionally_select(
846        cond: &Boolean<BasePrimeField<P>>,
847        true_value: &Self,
848        false_value: &Self,
849    ) -> Result<Self, SynthesisError> {
850        let x = cond.select(&true_value.x, &false_value.x)?;
851        let y = cond.select(&true_value.y, &false_value.y)?;
852
853        Ok(Self::new(x, y))
854    }
855}
856
857impl<P, F> EqGadget<BasePrimeField<P>> for AffineVar<P, F>
858where
859    P: TECurveConfig,
860    F: FieldVar<P::BaseField, BasePrimeField<P>>,
861    for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
862{
863    #[tracing::instrument(target = "gr1cs")]
864    fn is_eq(&self, other: &Self) -> Result<Boolean<BasePrimeField<P>>, SynthesisError> {
865        let x_equal = self.x.is_eq(&other.x)?;
866        let y_equal = self.y.is_eq(&other.y)?;
867        Ok(x_equal & y_equal)
868    }
869
870    #[inline]
871    #[tracing::instrument(target = "gr1cs")]
872    fn conditional_enforce_equal(
873        &self,
874        other: &Self,
875        condition: &Boolean<BasePrimeField<P>>,
876    ) -> Result<(), SynthesisError> {
877        self.x.conditional_enforce_equal(&other.x, condition)?;
878        self.y.conditional_enforce_equal(&other.y, condition)?;
879        Ok(())
880    }
881
882    #[inline]
883    #[tracing::instrument(target = "gr1cs")]
884    fn conditional_enforce_not_equal(
885        &self,
886        other: &Self,
887        condition: &Boolean<BasePrimeField<P>>,
888    ) -> Result<(), SynthesisError> {
889        (self.is_eq(other)? & condition).enforce_equal(&Boolean::FALSE)
890    }
891}
892
893impl<P, F> ToBitsGadget<BasePrimeField<P>> for AffineVar<P, F>
894where
895    P: TECurveConfig,
896    F: FieldVar<P::BaseField, BasePrimeField<P>>,
897    for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
898{
899    #[tracing::instrument(target = "gr1cs")]
900    fn to_bits_le(&self) -> Result<Vec<Boolean<BasePrimeField<P>>>, SynthesisError> {
901        let mut x_bits = self.x.to_bits_le()?;
902        let y_bits = self.y.to_bits_le()?;
903        x_bits.extend_from_slice(&y_bits);
904        Ok(x_bits)
905    }
906
907    #[tracing::instrument(target = "gr1cs")]
908    fn to_non_unique_bits_le(&self) -> Result<Vec<Boolean<BasePrimeField<P>>>, SynthesisError> {
909        let mut x_bits = self.x.to_non_unique_bits_le()?;
910        let y_bits = self.y.to_non_unique_bits_le()?;
911        x_bits.extend_from_slice(&y_bits);
912
913        Ok(x_bits)
914    }
915}
916
917impl<P, F> ToBytesGadget<BasePrimeField<P>> for AffineVar<P, F>
918where
919    P: TECurveConfig,
920    F: FieldVar<P::BaseField, BasePrimeField<P>>,
921    for<'b> &'b F: FieldOpsBounds<'b, P::BaseField, F>,
922{
923    #[tracing::instrument(target = "gr1cs")]
924    fn to_bytes_le(&self) -> Result<Vec<UInt8<BasePrimeField<P>>>, SynthesisError> {
925        let mut x_bytes = self.x.to_bytes_le()?;
926        let y_bytes = self.y.to_bytes_le()?;
927        x_bytes.extend_from_slice(&y_bytes);
928        Ok(x_bytes)
929    }
930
931    #[tracing::instrument(target = "gr1cs")]
932    fn to_non_unique_bytes_le(&self) -> Result<Vec<UInt8<BasePrimeField<P>>>, SynthesisError> {
933        let mut x_bytes = self.x.to_non_unique_bytes_le()?;
934        let y_bytes = self.y.to_non_unique_bytes_le()?;
935        x_bytes.extend_from_slice(&y_bytes);
936
937        Ok(x_bytes)
938    }
939}