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}