arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
ark-r1cs-std/r1cs-std/src/groups/curves/short_weierstrass/mod.rs
r1cs-std/src/groups/curves/short_weierstrass/mod.rsRaw
  1use algebra::{
  2    curves::{
  3        short_weierstrass_jacobian::{GroupAffine as SWAffine, GroupProjective as SWProjective},
  4        SWModelParameters,
  5    },
  6    AffineCurve, BitIterator, Field, One, PrimeField, ProjectiveCurve, Zero,
  7};
  8use core::{borrow::Borrow, marker::PhantomData, ops::Neg};
  9use r1cs_core::{ConstraintSystem, SynthesisError};
 10
 11use crate::{prelude::*, Assignment, Vec};
 12
 13pub mod bls12;
 14pub mod mnt4;
 15pub mod mnt6;
 16
 17#[derive(Derivative)]
 18#[derivative(Debug, Clone)]
 19#[must_use]
 20pub struct AffineGadget<
 21    P: SWModelParameters,
 22    ConstraintF: Field,
 23    F: FieldGadget<P::BaseField, ConstraintF>,
 24> {
 25    pub x: F,
 26    pub y: F,
 27    pub infinity: Boolean,
 28    _params: PhantomData<P>,
 29    _engine: PhantomData<ConstraintF>,
 30}
 31
 32impl<
 33        P: SWModelParameters,
 34        ConstraintF: PrimeField,
 35        F: FieldGadget<P::BaseField, ConstraintF> + ToConstraintFieldGadget<ConstraintF>,
 36    > ToConstraintFieldGadget<ConstraintF> for AffineGadget<P, ConstraintF, F>
 37{
 38    fn to_constraint_field<CS: ConstraintSystem<ConstraintF>>(
 39        &self,
 40        mut cs: CS,
 41    ) -> Result<Vec<FpGadget<ConstraintF>>, SynthesisError> {
 42        let mut res = Vec::new();
 43
 44        let mut x_gadget = self.x.to_constraint_field(&mut cs.ns(|| "x"))?;
 45        let mut y_gadget = self.y.to_constraint_field(&mut cs.ns(|| "y"))?;
 46
 47        let mut infinity_gadget = self
 48            .infinity
 49            .to_constraint_field(&mut cs.ns(|| "infinity"))?;
 50
 51        res.append(&mut x_gadget);
 52        res.append(&mut y_gadget);
 53        res.append(&mut infinity_gadget);
 54
 55        Ok(res)
 56    }
 57}
 58
 59impl<P: SWModelParameters, ConstraintF: Field, F: FieldGadget<P::BaseField, ConstraintF>>
 60    AffineGadget<P, ConstraintF, F>
 61{
 62    pub fn new(x: F, y: F, infinity: Boolean) -> Self {
 63        Self {
 64            x,
 65            y,
 66            infinity,
 67            _params: PhantomData,
 68            _engine: PhantomData,
 69        }
 70    }
 71
 72    pub fn alloc_without_check<FN, CS: ConstraintSystem<ConstraintF>>(
 73        mut cs: CS,
 74        value_gen: F,
 75    ) -> Result<Self, SynthesisError>
 76    where
 77        F: FnOnce() -> Result<SWProjective<P>, SynthesisError>,
 78    {
 79        let (x, y, infinity) = match value_gen() {
 80            Ok(ge) => {
 81                let ge = ge.into_affine();
 82                (Ok(ge.x), Ok(ge.y), Ok(ge.infinity))
 83            }
 84            _ => (
 85                Err(SynthesisError::AssignmentMissing),
 86                Err(SynthesisError::AssignmentMissing),
 87                Err(SynthesisError::AssignmentMissing),
 88            ),
 89        };
 90
 91        let x = F::alloc(&mut cs.ns(|| "x"), || x)?;
 92        let y = F::alloc(&mut cs.ns(|| "y"), || y)?;
 93        let infinity = Boolean::alloc(&mut cs.ns(|| "infinity"), || infinity)?;
 94
 95        Ok(Self::new(x, y, infinity))
 96    }
 97}
 98
 99impl<P, ConstraintF, F> PartialEq for AffineGadget<P, ConstraintF, F>
100where
101    P: SWModelParameters,
102    ConstraintF: Field,
103    F: FieldGadget<P::BaseField, ConstraintF>,
104{
105    fn eq(&self, other: &Self) -> bool {
106        self.x == other.x && self.y == other.y
107    }
108}
109
110impl<P, ConstraintF, F> Eq for AffineGadget<P, ConstraintF, F>
111where
112    P: SWModelParameters,
113    ConstraintF: Field,
114    F: FieldGadget<P::BaseField, ConstraintF>,
115{
116}
117
118impl<P, ConstraintF, F> GroupGadget<SWProjective<P>, ConstraintF>
119    for AffineGadget<P, ConstraintF, F>
120where
121    P: SWModelParameters,
122    ConstraintF: PrimeField,
123    F: FieldGadget<P::BaseField, ConstraintF>,
124{
125    type Value = SWProjective<P>;
126    type Variable = (F::Variable, F::Variable);
127
128    #[inline]
129    fn get_value(&self) -> Option<Self::Value> {
130        match (
131            self.x.get_value(),
132            self.y.get_value(),
133            self.infinity.get_value(),
134        ) {
135            (Some(x), Some(y), Some(infinity)) => {
136                Some(SWAffine::new(x, y, infinity).into_projective())
137            }
138            (None, None, None) => None,
139            _ => unreachable!(),
140        }
141    }
142
143    #[inline]
144    fn get_variable(&self) -> Self::Variable {
145        (self.x.get_variable(), self.y.get_variable())
146    }
147
148    #[inline]
149    fn zero<CS: ConstraintSystem<ConstraintF>>(mut cs: CS) -> Result<Self, SynthesisError> {
150        Ok(Self::new(
151            F::zero(cs.ns(|| "zero"))?,
152            F::one(cs.ns(|| "one"))?,
153            Boolean::Constant(true),
154        ))
155    }
156
157    #[inline]
158    /// Incomplete addition: neither `self` nor `other` can be the neutral
159    /// element.
160    fn add<CS: ConstraintSystem<ConstraintF>>(
161        &self,
162        mut cs: CS,
163        other: &Self,
164    ) -> Result<Self, SynthesisError> {
165        // lambda = (B.y - A.y)/(B.x - A.x)
166        // C.x = lambda^2 - A.x - B.x
167        // C.y = lambda(A.x - C.x) - A.y
168        //
169        // Special cases:
170        //
171        // doubling: if B.y = A.y and B.x = A.x then lambda is unbound and
172        // C = (lambda^2, lambda^3)
173        //
174        // addition of negative point: if B.y = -A.y and B.x = A.x then no
175        // lambda can satisfy the first equation unless B.y - A.y = 0. But
176        // then this reduces to doubling.
177        //
178        // So we need to check that A.x - B.x != 0, which can be done by
179        // enforcing I * (B.x - A.x) = 1
180        // This is done below when we calculate inv (by F::inverse)
181
182        let x2_minus_x1 = other.x.sub(cs.ns(|| "x2 - x1"), &self.x)?;
183        let y2_minus_y1 = other.y.sub(cs.ns(|| "y2 - y1"), &self.y)?;
184
185        let inv = x2_minus_x1.inverse(cs.ns(|| "compute inv"))?;
186
187        let lambda = F::alloc(cs.ns(|| "lambda"), || {
188            Ok(y2_minus_y1.get_value().get()? * &inv.get_value().get()?)
189        })?;
190
191        let x_3 = F::alloc(&mut cs.ns(|| "x_3"), || {
192            let lambda_val = lambda.get_value().get()?;
193            let x1 = self.x.get_value().get()?;
194            let x2 = other.x.get_value().get()?;
195            Ok((lambda_val.square() - &x1) - &x2)
196        })?;
197
198        let y_3 = F::alloc(&mut cs.ns(|| "y_3"), || {
199            let lambda_val = lambda.get_value().get()?;
200            let x_1 = self.x.get_value().get()?;
201            let y_1 = self.y.get_value().get()?;
202            let x_3 = x_3.get_value().get()?;
203            Ok(lambda_val * &(x_1 - &x_3) - &y_1)
204        })?;
205
206        // Check lambda
207        lambda.mul_equals(cs.ns(|| "check lambda"), &x2_minus_x1, &y2_minus_y1)?;
208
209        // Check x3
210        let x3_plus_x1_plus_x2 = x_3
211            .add(cs.ns(|| "x3 + x1"), &self.x)?
212            .add(cs.ns(|| "x3 + x1 + x2"), &other.x)?;
213        lambda.mul_equals(cs.ns(|| "check x3"), &lambda, &x3_plus_x1_plus_x2)?;
214
215        // Check y3
216        let y3_plus_y1 = y_3.add(cs.ns(|| "y3 + y1"), &self.y)?;
217        let x1_minus_x3 = self.x.sub(cs.ns(|| "x1 - x3"), &x_3)?;
218
219        lambda.mul_equals(cs.ns(|| ""), &x1_minus_x3, &y3_plus_y1)?;
220
221        Ok(Self::new(x_3, y_3, Boolean::Constant(false)))
222    }
223
224    /// Incomplete addition: neither `self` nor `other` can be the neutral
225    /// element.
226    fn add_constant<CS: ConstraintSystem<ConstraintF>>(
227        &self,
228        mut cs: CS,
229        other: &SWProjective<P>,
230    ) -> Result<Self, SynthesisError> {
231        // lambda = (B.y - A.y)/(B.x - A.x)
232        // C.x = lambda^2 - A.x - B.x
233        // C.y = lambda(A.x - C.x) - A.y
234        //
235        // Special cases:
236        //
237        // doubling: if B.y = A.y and B.x = A.x then lambda is unbound and
238        // C = (lambda^2, lambda^3)
239        //
240        // addition of negative point: if B.y = -A.y and B.x = A.x then no
241        // lambda can satisfy the first equation unless B.y - A.y = 0. But
242        // then this reduces to doubling.
243        //
244        // So we need to check that A.x - B.x != 0, which can be done by
245        // enforcing I * (B.x - A.x) = 1
246        if other.is_zero() {
247            return Err(SynthesisError::AssignmentMissing);
248        }
249        let other = other.into_affine();
250        let other_x = other.x;
251        let other_y = other.y;
252
253        let x2_minus_x1 = self
254            .x
255            .sub_constant(cs.ns(|| "x2 - x1"), &other_x)?
256            .negate(cs.ns(|| "neg1"))?;
257        let y2_minus_y1 = self
258            .y
259            .sub_constant(cs.ns(|| "y2 - y1"), &other_y)?
260            .negate(cs.ns(|| "neg2"))?;
261
262        let inv = x2_minus_x1.inverse(cs.ns(|| "compute inv"))?;
263
264        let lambda = F::alloc(cs.ns(|| "lambda"), || {
265            Ok(y2_minus_y1.get_value().get()? * &inv.get_value().get()?)
266        })?;
267
268        let x_3 = F::alloc(&mut cs.ns(|| "x_3"), || {
269            let lambda_val = lambda.get_value().get()?;
270            let x1 = self.x.get_value().get()?;
271            let x2 = other_x;
272            Ok((lambda_val.square() - &x1) - &x2)
273        })?;
274
275        let y_3 = F::alloc(&mut cs.ns(|| "y_3"), || {
276            let lambda_val = lambda.get_value().get()?;
277            let x_1 = self.x.get_value().get()?;
278            let y_1 = self.y.get_value().get()?;
279            let x_3 = x_3.get_value().get()?;
280            Ok(lambda_val * &(x_1 - &x_3) - &y_1)
281        })?;
282
283        // Check lambda
284        lambda.mul_equals(cs.ns(|| "check lambda"), &x2_minus_x1, &y2_minus_y1)?;
285
286        // Check x3
287        let x3_plus_x1_plus_x2 = x_3
288            .add(cs.ns(|| "x3 + x1"), &self.x)?
289            .add_constant(cs.ns(|| "x3 + x1 + x2"), &other_x)?;
290        lambda.mul_equals(cs.ns(|| "check x3"), &lambda, &x3_plus_x1_plus_x2)?;
291
292        // Check y3
293        let y3_plus_y1 = y_3.add(cs.ns(|| "y3 + y1"), &self.y)?;
294        let x1_minus_x3 = self.x.sub(cs.ns(|| "x1 - x3"), &x_3)?;
295
296        lambda.mul_equals(cs.ns(|| ""), &x1_minus_x3, &y3_plus_y1)?;
297
298        Ok(Self::new(x_3, y_3, Boolean::Constant(false)))
299    }
300
301    #[inline]
302    fn double_in_place<CS: ConstraintSystem<ConstraintF>>(
303        &mut self,
304        mut cs: CS,
305    ) -> Result<(), SynthesisError> {
306        let a = P::COEFF_A;
307        let x_squared = self.x.square(cs.ns(|| "x^2"))?;
308
309        let one = P::BaseField::one();
310        let two = one.double();
311        let three = two + &one;
312
313        let three_x_squared = x_squared.mul_by_constant(cs.ns(|| "3 * x^2"), &three)?;
314        let three_x_squared_plus_a = three_x_squared.add_constant(cs.ns(|| "3 * x^2 + a"), &a)?;
315
316        let two_y = self.y.double(cs.ns(|| "2y"))?;
317
318        let lambda = F::alloc(cs.ns(|| "lambda"), || {
319            let y_doubled_inv = two_y.get_value().get()?.inverse().get()?;
320            Ok(three_x_squared_plus_a.get_value().get()? * &y_doubled_inv)
321        })?;
322
323        // Check lambda
324        lambda.mul_equals(cs.ns(|| "check lambda"), &two_y, &three_x_squared_plus_a)?;
325
326        let x = lambda
327            .square(cs.ns(|| "lambda^2"))?
328            .sub(cs.ns(|| "lambda^2 - x"), &self.x)?
329            .sub(cs.ns(|| "lambda^2 - 2x"), &self.x)?;
330
331        let y = self
332            .x
333            .sub(cs.ns(|| "x - self.x"), &x)?
334            .mul(cs.ns(|| "times lambda"), &lambda)?
335            .sub(cs.ns(|| "plus self.y"), &self.y)?;
336
337        *self = Self::new(x, y, Boolean::Constant(false));
338        Ok(())
339    }
340
341    fn negate<CS: ConstraintSystem<ConstraintF>>(
342        &self,
343        mut cs: CS,
344    ) -> Result<Self, SynthesisError> {
345        Ok(Self::new(
346            self.x.clone(),
347            self.y.negate(cs.ns(|| "negate y"))?,
348            self.infinity,
349        ))
350    }
351
352    fn cost_of_add() -> usize {
353        3 * F::cost_of_mul_equals() + F::cost_of_inv()
354    }
355
356    fn cost_of_double() -> usize {
357        4 * F::cost_of_mul()
358    }
359}
360
361impl<P, ConstraintF, F> CondSelectGadget<ConstraintF> for AffineGadget<P, ConstraintF, F>
362where
363    P: SWModelParameters,
364    ConstraintF: PrimeField,
365    F: FieldGadget<P::BaseField, ConstraintF>,
366{
367    #[inline]
368    fn conditionally_select<CS: ConstraintSystem<ConstraintF>>(
369        mut cs: CS,
370        cond: &Boolean,
371        true_value: &Self,
372        false_value: &Self,
373    ) -> Result<Self, SynthesisError> {
374        let x = F::conditionally_select(&mut cs.ns(|| "x"), cond, &true_value.x, &false_value.x)?;
375        let y = F::conditionally_select(&mut cs.ns(|| "y"), cond, &true_value.y, &false_value.y)?;
376        let infinity = Boolean::conditionally_select(
377            &mut cs.ns(|| "infinity"),
378            cond,
379            &true_value.infinity,
380            &false_value.infinity,
381        )?;
382
383        Ok(Self::new(x, y, infinity))
384    }
385
386    fn cost() -> usize {
387        2 * <F as CondSelectGadget<ConstraintF>>::cost()
388            + <Boolean as CondSelectGadget<ConstraintF>>::cost()
389    }
390}
391
392impl<P, ConstraintF, F> EqGadget<ConstraintF> for AffineGadget<P, ConstraintF, F>
393where
394    P: SWModelParameters,
395    ConstraintF: Field,
396    F: FieldGadget<P::BaseField, ConstraintF>,
397{
398}
399
400impl<P, ConstraintF, F> ConditionalEqGadget<ConstraintF> for AffineGadget<P, ConstraintF, F>
401where
402    P: SWModelParameters,
403    ConstraintF: Field,
404    F: FieldGadget<P::BaseField, ConstraintF>,
405{
406    #[inline]
407    fn conditional_enforce_equal<CS: ConstraintSystem<ConstraintF>>(
408        &self,
409        mut cs: CS,
410        other: &Self,
411        condition: &Boolean,
412    ) -> Result<(), SynthesisError> {
413        self.x.conditional_enforce_equal(
414            &mut cs.ns(|| "X Coordinate Conditional Equality"),
415            &other.x,
416            condition,
417        )?;
418        self.y.conditional_enforce_equal(
419            &mut cs.ns(|| "Y Coordinate Conditional Equality"),
420            &other.y,
421            condition,
422        )?;
423        self.infinity.conditional_enforce_equal(
424            &mut cs.ns(|| "Infinity Conditional Equality"),
425            &other.infinity,
426            condition,
427        )?;
428        Ok(())
429    }
430
431    fn cost() -> usize {
432        2 * <F as ConditionalEqGadget<ConstraintF>>::cost()
433    }
434}
435
436impl<P, ConstraintF, F> NEqGadget<ConstraintF> for AffineGadget<P, ConstraintF, F>
437where
438    P: SWModelParameters,
439    ConstraintF: Field,
440    F: FieldGadget<P::BaseField, ConstraintF>,
441{
442    #[inline]
443    fn enforce_not_equal<CS: ConstraintSystem<ConstraintF>>(
444        &self,
445        mut cs: CS,
446        other: &Self,
447    ) -> Result<(), SynthesisError> {
448        self.x
449            .enforce_not_equal(&mut cs.ns(|| "X Coordinate Inequality"), &other.x)?;
450        self.y
451            .enforce_not_equal(&mut cs.ns(|| "Y Coordinate Inequality"), &other.y)?;
452        Ok(())
453    }
454
455    fn cost() -> usize {
456        2 * <F as NEqGadget<ConstraintF>>::cost()
457    }
458}
459
460impl<P, ConstraintF, F> AllocGadget<SWProjective<P>, ConstraintF>
461    for AffineGadget<P, ConstraintF, F>
462where
463    P: SWModelParameters,
464    ConstraintF: PrimeField,
465    F: FieldGadget<P::BaseField, ConstraintF>,
466{
467    #[inline]
468    fn alloc_constant<T, CS: ConstraintSystem<ConstraintF>>(
469        mut cs: CS,
470        t: T,
471    ) -> Result<Self, SynthesisError>
472    where
473        T: Borrow<SWProjective<P>>,
474    {
475        let p = t.borrow().into_affine();
476        Ok(Self {
477            x: F::alloc_constant(cs.ns(|| "x"), &p.x)?,
478            y: F::alloc_constant(cs.ns(|| "y"), &p.y)?,
479            infinity: Boolean::constant(p.infinity),
480            _params: PhantomData,
481            _engine: PhantomData,
482        })
483    }
484
485    #[inline]
486    fn alloc<FN, T, CS: ConstraintSystem<ConstraintF>>(
487        mut cs: CS,
488        value_gen: FN,
489    ) -> Result<Self, SynthesisError>
490    where
491        FN: FnOnce() -> Result<T, SynthesisError>,
492        T: Borrow<SWProjective<P>>,
493    {
494        let (x, y, infinity) = match value_gen() {
495            Ok(ge) => {
496                let ge = ge.borrow().into_affine();
497                (Ok(ge.x), Ok(ge.y), Ok(ge.infinity))
498            }
499            _ => (
500                Err(SynthesisError::AssignmentMissing),
501                Err(SynthesisError::AssignmentMissing),
502                Err(SynthesisError::AssignmentMissing),
503            ),
504        };
505
506        // Perform on-curve check.
507        let b = P::COEFF_B;
508        let a = P::COEFF_A;
509
510        let x = F::alloc(&mut cs.ns(|| "x"), || x)?;
511        let y = F::alloc(&mut cs.ns(|| "y"), || y)?;
512        let infinity = Boolean::alloc(&mut cs.ns(|| "infinity"), || infinity)?;
513
514        // Check that y^2 = x^3 + ax +b
515        // We do this by checking that y^2 - b = x * (x^2 +a)
516        let x2 = x.square(&mut cs.ns(|| "x^2"))?;
517        let y2 = y.square(&mut cs.ns(|| "y^2"))?;
518
519        let x2_plus_a = x2.add_constant(cs.ns(|| "x^2 + a"), &a)?;
520        let y2_minus_b = y2.add_constant(cs.ns(|| "y^2 - b"), &b.neg())?;
521
522        x2_plus_a.mul_equals(cs.ns(|| "on curve check"), &x, &y2_minus_b)?;
523
524        Ok(Self::new(x, y, infinity))
525    }
526
527    #[inline]
528    fn alloc_checked<FN, T, CS: ConstraintSystem<ConstraintF>>(
529        mut cs: CS,
530        value_gen: FN,
531    ) -> Result<Self, SynthesisError>
532    where
533        FN: FnOnce() -> Result<T, SynthesisError>,
534        T: Borrow<SWProjective<P>>,
535    {
536        let cofactor_weight = BitIterator::new(P::COFACTOR).filter(|b| *b).count();
537        // If we multiply by r, we actually multiply by r - 2.
538        let r_minus_1 = (-P::ScalarField::one()).into_repr();
539        let r_weight = BitIterator::new(&r_minus_1).filter(|b| *b).count();
540
541        // We pick the most efficient method of performing the prime order check:
542        // If the cofactor has lower hamming weight than the scalar field's modulus,
543        // we first multiply by the inverse of the cofactor, and then, after allocating,
544        // multiply by the cofactor. This ensures the resulting point has no cofactors
545        //
546        // Else, we multiply by the scalar field's modulus and ensure that the result
547        // is zero.
548        if cofactor_weight < r_weight {
549            let ge = Self::alloc(cs.ns(|| "Alloc checked"), || {
550                value_gen().map(|ge| {
551                    ge.borrow()
552                        .into_affine()
553                        .mul_by_cofactor_inv()
554                        .into_projective()
555                })
556            })?;
557            let mut seen_one = false;
558            let mut result = Self::zero(cs.ns(|| "result"))?;
559            for (i, b) in BitIterator::new(P::COFACTOR).enumerate() {
560                let mut cs = cs.ns(|| format!("Iteration {}", i));
561
562                let old_seen_one = seen_one;
563                if seen_one {
564                    result.double_in_place(cs.ns(|| "Double"))?;
565                } else {
566                    seen_one = b;
567                }
568
569                if b {
570                    result = if old_seen_one {
571                        result.add(cs.ns(|| "Add"), &ge)?
572                    } else {
573                        ge.clone()
574                    };
575                }
576            }
577            Ok(result)
578        } else {
579            let ge = Self::alloc(cs.ns(|| "Alloc checked"), value_gen)?;
580            let mut seen_one = false;
581            let mut result = Self::zero(cs.ns(|| "result"))?;
582            // Returns bits in big-endian order
583            for (i, b) in BitIterator::new(r_minus_1).enumerate() {
584                let mut cs = cs.ns(|| format!("Iteration {}", i));
585
586                let old_seen_one = seen_one;
587                if seen_one {
588                    result.double_in_place(cs.ns(|| "Double"))?;
589                } else {
590                    seen_one = b;
591                }
592
593                if b {
594                    result = if old_seen_one {
595                        result.add(cs.ns(|| "Add"), &ge)?
596                    } else {
597                        ge.clone()
598                    };
599                }
600            }
601            let neg_ge = ge.negate(cs.ns(|| "Negate ge"))?;
602            neg_ge.enforce_equal(cs.ns(|| "Check equals"), &result)?;
603            Ok(ge)
604        }
605    }
606
607    #[inline]
608    fn alloc_input<FN, T, CS: ConstraintSystem<ConstraintF>>(
609        mut cs: CS,
610        value_gen: FN,
611    ) -> Result<Self, SynthesisError>
612    where
613        FN: FnOnce() -> Result<T, SynthesisError>,
614        T: Borrow<SWProjective<P>>,
615    {
616        // When allocating the input we assume that the verifier has performed
617        // any on curve checks already.
618        let (x, y, infinity) = match value_gen() {
619            Ok(ge) => {
620                let ge = ge.borrow().into_affine();
621                (Ok(ge.x), Ok(ge.y), Ok(ge.infinity))
622            }
623            _ => (
624                Err(SynthesisError::AssignmentMissing),
625                Err(SynthesisError::AssignmentMissing),
626                Err(SynthesisError::AssignmentMissing),
627            ),
628        };
629
630        let x = F::alloc_input(&mut cs.ns(|| "x"), || x)?;
631        let y = F::alloc_input(&mut cs.ns(|| "y"), || y)?;
632        let infinity = Boolean::alloc_input(&mut cs.ns(|| "infinity"), || infinity)?;
633
634        Ok(Self::new(x, y, infinity))
635    }
636}
637
638impl<P, ConstraintF, F> ToBitsGadget<ConstraintF> for AffineGadget<P, ConstraintF, F>
639where
640    P: SWModelParameters,
641    ConstraintF: Field,
642    F: FieldGadget<P::BaseField, ConstraintF>,
643{
644    fn to_bits<CS: ConstraintSystem<ConstraintF>>(
645        &self,
646        mut cs: CS,
647    ) -> Result<Vec<Boolean>, SynthesisError> {
648        let mut x_bits = self.x.to_bits(&mut cs.ns(|| "X Coordinate To Bits"))?;
649        let y_bits = self.y.to_bits(&mut cs.ns(|| "Y Coordinate To Bits"))?;
650        x_bits.extend_from_slice(&y_bits);
651        x_bits.push(self.infinity);
652        Ok(x_bits)
653    }
654
655    fn to_non_unique_bits<CS: ConstraintSystem<ConstraintF>>(
656        &self,
657        mut cs: CS,
658    ) -> Result<Vec<Boolean>, SynthesisError> {
659        let mut x_bits = self
660            .x
661            .to_non_unique_bits(&mut cs.ns(|| "X Coordinate To Bits"))?;
662        let y_bits = self
663            .y
664            .to_non_unique_bits(&mut cs.ns(|| "Y Coordinate To Bits"))?;
665        x_bits.extend_from_slice(&y_bits);
666        x_bits.push(self.infinity);
667
668        Ok(x_bits)
669    }
670}
671
672impl<P, ConstraintF, F> ToBytesGadget<ConstraintF> for AffineGadget<P, ConstraintF, F>
673where
674    P: SWModelParameters,
675    ConstraintF: Field,
676    F: FieldGadget<P::BaseField, ConstraintF>,
677{
678    fn to_bytes<CS: ConstraintSystem<ConstraintF>>(
679        &self,
680        mut cs: CS,
681    ) -> Result<Vec<UInt8>, SynthesisError> {
682        let mut x_bytes = self.x.to_bytes(&mut cs.ns(|| "X Coordinate To Bytes"))?;
683        let y_bytes = self.y.to_bytes(&mut cs.ns(|| "Y Coordinate To Bytes"))?;
684        let inf_bytes = self.infinity.to_bytes(&mut cs.ns(|| "Infinity to Bytes"))?;
685        x_bytes.extend_from_slice(&y_bytes);
686        x_bytes.extend_from_slice(&inf_bytes);
687        Ok(x_bytes)
688    }
689
690    fn to_non_unique_bytes<CS: ConstraintSystem<ConstraintF>>(
691        &self,
692        mut cs: CS,
693    ) -> Result<Vec<UInt8>, SynthesisError> {
694        let mut x_bytes = self
695            .x
696            .to_non_unique_bytes(&mut cs.ns(|| "X Coordinate To Bytes"))?;
697        let y_bytes = self
698            .y
699            .to_non_unique_bytes(&mut cs.ns(|| "Y Coordinate To Bytes"))?;
700        let inf_bytes = self
701            .infinity
702            .to_non_unique_bytes(&mut cs.ns(|| "Infinity to Bytes"))?;
703        x_bytes.extend_from_slice(&y_bytes);
704        x_bytes.extend_from_slice(&inf_bytes);
705
706        Ok(x_bytes)
707    }
708}
709
710#[cfg(test)]
711#[allow(dead_code)]
712pub(crate) fn test<ConstraintF, P, GG>()
713where
714    ConstraintF: Field,
715    P: SWModelParameters,
716    GG: GroupGadget<SWProjective<P>, ConstraintF, Value = SWProjective<P>>,
717{
718    use crate::{boolean::AllocatedBit, prelude::*, test_constraint_system::TestConstraintSystem};
719    use algebra::{test_rng, Group, UniformRand};
720    use rand::Rng;
721
722    // Incomplete addition doesn't allow us to call the group_test.
723    // group_test::<ConstraintF, SWProjective<P>, GG>();
724
725    let mut rng = test_rng();
726
727    let mut cs = TestConstraintSystem::<ConstraintF>::new();
728
729    let a = SWProjective::<P>::rand(&mut rng);
730    let b = SWProjective::<P>::rand(&mut rng);
731    let a_affine = a.into_affine();
732    let b_affine = b.into_affine();
733    let mut gadget_a = GG::alloc(&mut cs.ns(|| "a"), || Ok(a)).unwrap();
734    let gadget_b = GG::alloc_checked(&mut cs.ns(|| "b"), || Ok(b)).unwrap();
735    assert_eq!(gadget_a.get_value().unwrap().x, a_affine.x);
736    assert_eq!(gadget_a.get_value().unwrap().y, a_affine.y);
737    assert_eq!(gadget_b.get_value().unwrap().x, b_affine.x);
738    assert_eq!(gadget_b.get_value().unwrap().y, b_affine.y);
739
740    // Check addition
741    let ab = a + &b;
742    let ab_affine = ab.into_affine();
743    let gadget_ab = gadget_a.add(&mut cs.ns(|| "ab"), &gadget_b).unwrap();
744    let gadget_ba = gadget_b.add(&mut cs.ns(|| "ba"), &gadget_a).unwrap();
745    gadget_ba
746        .enforce_equal(&mut cs.ns(|| "b + a == a + b?"), &gadget_ab)
747        .unwrap();
748
749    let ab_val = gadget_ab
750        .get_value()
751        .expect("Doubling should be successful")
752        .into_affine();
753    assert_eq!(ab_val, ab_affine, "Result of addition is unequal");
754
755    // Check doubling
756    let aa = Group::double(&a);
757    let aa_affine = aa.into_affine();
758    gadget_a.double_in_place(&mut cs.ns(|| "2a")).unwrap();
759    let aa_val = gadget_a
760        .get_value()
761        .expect("Doubling should be successful")
762        .into_affine();
763    assert_eq!(
764        aa_val, aa_affine,
765        "Gadget and native values are unequal after double."
766    );
767
768    // Check mul_bits
769    let scalar = P::ScalarField::rand(&mut rng);
770    let native_result = aa.into_affine().mul(scalar) + &b;
771    let native_result = native_result.into_affine();
772
773    let mut scalar: Vec<bool> = BitIterator::new(scalar.into_repr()).collect();
774    // Get the scalar bits into little-endian form.
775    scalar.reverse();
776    let input = Vec::<Boolean>::alloc(cs.ns(|| "Input"), || Ok(scalar)).unwrap();
777    let result = gadget_a
778        .mul_bits(cs.ns(|| "mul_bits"), &gadget_b, input.iter())
779        .unwrap();
780    let result_val = result.get_value().unwrap().into_affine();
781    assert_eq!(
782        result_val, native_result,
783        "gadget & native values are diff. after scalar mul"
784    );
785
786    if !cs.is_satisfied() {
787        println!("{:?}", cs.which_is_unsatisfied().unwrap());
788    }
789
790    assert!(cs.is_satisfied());
791
792    // Constraint cost etc.
793    let mut cs = TestConstraintSystem::<ConstraintF>::new();
794
795    let bit = AllocatedBit::alloc(&mut cs.ns(|| "bool"), || Ok(true))
796        .unwrap()
797        .into();
798
799    let mut rng = test_rng();
800    let a: SWProjective<P> = rng.gen();
801    let b: SWProjective<P> = rng.gen();
802    let gadget_a = GG::alloc(&mut cs.ns(|| "a"), || Ok(a)).unwrap();
803    let gadget_b = GG::alloc(&mut cs.ns(|| "b"), || Ok(b)).unwrap();
804    let alloc_cost = cs.num_constraints();
805    let _ =
806        GG::conditionally_select(&mut cs.ns(|| "cond_select"), &bit, &gadget_a, &gadget_b).unwrap();
807    let cond_select_cost = cs.num_constraints() - alloc_cost;
808
809    let _ = gadget_a.add(&mut cs.ns(|| "ab"), &gadget_b).unwrap();
810    let add_cost = cs.num_constraints() - cond_select_cost - alloc_cost;
811
812    assert!(cs.is_satisfied());
813    assert_eq!(
814        cond_select_cost,
815        <GG as CondSelectGadget<ConstraintF>>::cost()
816    );
817    assert_eq!(add_cost, GG::cost_of_add());
818}