1use bellman::pairing::{
2 Engine,
3};
4
5use bellman::pairing::ff::{Field};
6
7use bellman::{
8 SynthesisError,
9 ConstraintSystem
10};
11
12use super::{
13 Assignment
14};
15
16use super::num::{
17 AllocatedNum,
18 Num
19};
20
21use ::jubjub::{
22 edwards,
23 JubjubEngine,
24 JubjubParams,
25 FixedGenerators
26};
27
28use super::lookup::{
29 lookup3_xy
30};
31
32use super::boolean::Boolean;
33
34#[derive(Clone)]
35pub struct EdwardsPoint<E: Engine> {
36 x: AllocatedNum<E>,
37 y: AllocatedNum<E>
38}
39
40pub fn fixed_base_multiplication<E, CS>(
43 mut cs: CS,
44 base: FixedGenerators,
45 by: &[Boolean],
46 params: &E::Params
47) -> Result<EdwardsPoint<E>, SynthesisError>
48 where CS: ConstraintSystem<E>,
49 E: JubjubEngine
50{
51 let mut result = None;
53
54 for (i, (chunk, window)) in by.chunks(3)
55 .zip(params.circuit_generators(base).iter())
56 .enumerate()
57 {
58 let chunk_a = chunk.get(0).map(|e| e.clone()).unwrap_or(Boolean::constant(false));
59 let chunk_b = chunk.get(1).map(|e| e.clone()).unwrap_or(Boolean::constant(false));
60 let chunk_c = chunk.get(2).map(|e| e.clone()).unwrap_or(Boolean::constant(false));
61
62 let (x, y) = lookup3_xy(
63 cs.namespace(|| format!("window table lookup {}", i)),
64 &[chunk_a, chunk_b, chunk_c],
65 window
66 )?;
67
68 let p = EdwardsPoint {
69 x: x,
70 y: y
71 };
72
73 if result.is_none() {
74 result = Some(p);
75 } else {
76 result = Some(result.unwrap().add(
77 cs.namespace(|| format!("addition {}", i)),
78 &p,
79 params
80 )?);
81 }
82 }
83
84 Ok(result.get()?.clone())
85}
86
87impl<E: JubjubEngine> EdwardsPoint<E> {
88 pub fn get_x(&self) -> &AllocatedNum<E> {
89 &self.x
90 }
91
92 pub fn get_y(&self) -> &AllocatedNum<E> {
93 &self.y
94 }
95
96 pub fn assert_not_small_order<CS>(
97 &self,
98 mut cs: CS,
99 params: &E::Params
100 ) -> Result<(), SynthesisError>
101 where CS: ConstraintSystem<E>
102 {
103 let tmp = self.double(
104 cs.namespace(|| "first doubling"),
105 params
106 )?;
107 let tmp = tmp.double(
108 cs.namespace(|| "second doubling"),
109 params
110 )?;
111 let tmp = tmp.double(
112 cs.namespace(|| "third doubling"),
113 params
114 )?;
115
116 tmp.x.assert_nonzero(cs.namespace(|| "check x != 0"))?;
121
122 Ok(())
123 }
124
125 pub fn inputize<CS>(
126 &self,
127 mut cs: CS
128 ) -> Result<(), SynthesisError>
129 where CS: ConstraintSystem<E>
130 {
131 self.x.inputize(cs.namespace(|| "x"))?;
132 self.y.inputize(cs.namespace(|| "y"))?;
133
134 Ok(())
135 }
136
137 pub fn repr<CS>(
139 &self,
140 mut cs: CS
141 ) -> Result<Vec<Boolean>, SynthesisError>
142 where CS: ConstraintSystem<E>
143 {
144 let mut tmp = vec![];
145
146 let x = self.x.into_bits_le_strict(
147 cs.namespace(|| "unpack x")
148 )?;
149
150 let y = self.y.into_bits_le_strict(
151 cs.namespace(|| "unpack y")
152 )?;
153
154 tmp.extend(y);
155 tmp.push(x[0].clone());
156
157 Ok(tmp)
158 }
159
160 pub fn witness<Order, CS>(
163 mut cs: CS,
164 p: Option<edwards::Point<E, Order>>,
165 params: &E::Params
166 ) -> Result<Self, SynthesisError>
167 where CS: ConstraintSystem<E>
168 {
169 let p = p.map(|p| p.into_xy());
170
171 let x = AllocatedNum::alloc(
173 cs.namespace(|| "x"),
174 || {
175 Ok(p.get()?.0)
176 }
177 )?;
178
179 let y = AllocatedNum::alloc(
181 cs.namespace(|| "y"),
182 || {
183 Ok(p.get()?.1)
184 }
185 )?;
186
187 Self::interpret(
188 cs.namespace(|| "point interpretation"),
189 &x,
190 &y,
191 params
192 )
193 }
194
195 pub fn conditionally_select<CS>(
198 &self,
199 mut cs: CS,
200 condition: &Boolean
201 ) -> Result<Self, SynthesisError>
202 where CS: ConstraintSystem<E>
203 {
204 let x_prime = AllocatedNum::alloc(cs.namespace(|| "x'"), || {
206 if *condition.get_value().get()? {
207 Ok(*self.x.get_value().get()?)
208 } else {
209 Ok(E::Fr::zero())
210 }
211 })?;
212
213 let one = CS::one();
217 cs.enforce(
218 || "x' computation",
219 |lc| lc + self.x.get_variable(),
220 |_| condition.lc(one, E::Fr::one()),
221 |lc| lc + x_prime.get_variable()
222 );
223
224 let y_prime = AllocatedNum::alloc(cs.namespace(|| "y'"), || {
226 if *condition.get_value().get()? {
227 Ok(*self.y.get_value().get()?)
228 } else {
229 Ok(E::Fr::one())
230 }
231 })?;
232
233 cs.enforce(
237 || "y' computation",
238 |lc| lc + self.y.get_variable(),
239 |_| condition.lc(one, E::Fr::one()),
240 |lc| lc + y_prime.get_variable()
241 - &condition.not().lc(one, E::Fr::one())
242 );
243
244 Ok(EdwardsPoint {
245 x: x_prime,
246 y: y_prime
247 })
248 }
249
250 pub fn mul<CS>(
254 &self,
255 mut cs: CS,
256 by: &[Boolean],
257 params: &E::Params
258 ) -> Result<Self, SynthesisError>
259 where CS: ConstraintSystem<E>
260 {
261 let mut curbase = None;
265
266 let mut result = None;
268
269 for (i, bit) in by.iter().enumerate() {
270 if curbase.is_none() {
271 curbase = Some(self.clone());
272 } else {
273 curbase = Some(
275 curbase.unwrap()
276 .double(cs.namespace(|| format!("doubling {}", i)), params)?
277 );
278 }
279
280 let thisbase = curbase.as_ref()
285 .unwrap()
286 .conditionally_select(
287 cs.namespace(|| format!("selection {}", i)),
288 bit
289 )?;
290
291 if result.is_none() {
292 result = Some(thisbase);
293 } else {
294 result = Some(result.unwrap().add(
295 cs.namespace(|| format!("addition {}", i)),
296 &thisbase,
297 params
298 )?);
299 }
300 }
301
302 Ok(result.get()?.clone())
303 }
304
305 pub fn interpret<CS>(
306 mut cs: CS,
307 x: &AllocatedNum<E>,
308 y: &AllocatedNum<E>,
309 params: &E::Params
310 ) -> Result<Self, SynthesisError>
311 where CS: ConstraintSystem<E>
312 {
313 let x2 = x.square(cs.namespace(|| "x^2"))?;
316 let y2 = y.square(cs.namespace(|| "y^2"))?;
317 let x2y2 = x2.mul(cs.namespace(|| "x^2 y^2"), &y2)?;
318
319 let one = CS::one();
320 cs.enforce(
321 || "on curve check",
322 |lc| lc - x2.get_variable()
323 + y2.get_variable(),
324 |lc| lc + one,
325 |lc| lc + one
326 + (*params.edwards_d(), x2y2.get_variable())
327 );
328
329 Ok(EdwardsPoint {
330 x: x.clone(),
331 y: y.clone()
332 })
333 }
334
335 pub fn double<CS>(
336 &self,
337 mut cs: CS,
338 params: &E::Params
339 ) -> Result<Self, SynthesisError>
340 where CS: ConstraintSystem<E>
341 {
342 let t = AllocatedNum::alloc(cs.namespace(|| "T"), || {
344 let mut t0 = *self.x.get_value().get()?;
345 t0.add_assign(self.y.get_value().get()?);
346
347 let mut t1 = *self.x.get_value().get()?;
348 t1.add_assign(self.y.get_value().get()?);
349
350 t0.mul_assign(&t1);
351
352 Ok(t0)
353 })?;
354
355 cs.enforce(
356 || "T computation",
357 |lc| lc + self.x.get_variable()
358 + self.y.get_variable(),
359 |lc| lc + self.x.get_variable()
360 + self.y.get_variable(),
361 |lc| lc + t.get_variable()
362 );
363
364 let a = self.x.mul(cs.namespace(|| "A computation"), &self.y)?;
366
367 let c = AllocatedNum::alloc(cs.namespace(|| "C"), || {
369 let mut t0 = *a.get_value().get()?;
370 t0.square();
371 t0.mul_assign(params.edwards_d());
372
373 Ok(t0)
374 })?;
375
376 cs.enforce(
377 || "C computation",
378 |lc| lc + (*params.edwards_d(), a.get_variable()),
379 |lc| lc + a.get_variable(),
380 |lc| lc + c.get_variable()
381 );
382
383 let x3 = AllocatedNum::alloc(cs.namespace(|| "x3"), || {
385 let mut t0 = *a.get_value().get()?;
386 t0.double();
387
388 let mut t1 = E::Fr::one();
389 t1.add_assign(c.get_value().get()?);
390
391 match t1.inverse() {
392 Some(t1) => {
393 t0.mul_assign(&t1);
394
395 Ok(t0)
396 },
397 None => {
398 Err(SynthesisError::DivisionByZero)
399 }
400 }
401 })?;
402
403 let one = CS::one();
404 cs.enforce(
405 || "x3 computation",
406 |lc| lc + one + c.get_variable(),
407 |lc| lc + x3.get_variable(),
408 |lc| lc + a.get_variable()
409 + a.get_variable()
410 );
411
412 let y3 = AllocatedNum::alloc(cs.namespace(|| "y3"), || {
414 let mut t0 = *a.get_value().get()?;
415 t0.double();
416 t0.negate();
417 t0.add_assign(t.get_value().get()?);
418
419 let mut t1 = E::Fr::one();
420 t1.sub_assign(c.get_value().get()?);
421
422 match t1.inverse() {
423 Some(t1) => {
424 t0.mul_assign(&t1);
425
426 Ok(t0)
427 },
428 None => {
429 Err(SynthesisError::DivisionByZero)
430 }
431 }
432 })?;
433
434 cs.enforce(
435 || "y3 computation",
436 |lc| lc + one - c.get_variable(),
437 |lc| lc + y3.get_variable(),
438 |lc| lc + t.get_variable()
439 - a.get_variable()
440 - a.get_variable()
441 );
442
443 Ok(EdwardsPoint {
444 x: x3,
445 y: y3
446 })
447 }
448
449 pub fn add<CS>(
451 &self,
452 mut cs: CS,
453 other: &Self,
454 params: &E::Params
455 ) -> Result<Self, SynthesisError>
456 where CS: ConstraintSystem<E>
457 {
458 let u = AllocatedNum::alloc(cs.namespace(|| "U"), || {
460 let mut t0 = *self.x.get_value().get()?;
461 t0.add_assign(self.y.get_value().get()?);
462
463 let mut t1 = *other.x.get_value().get()?;
464 t1.add_assign(other.y.get_value().get()?);
465
466 t0.mul_assign(&t1);
467
468 Ok(t0)
469 })?;
470
471 cs.enforce(
472 || "U computation",
473 |lc| lc + self.x.get_variable()
474 + self.y.get_variable(),
475 |lc| lc + other.x.get_variable()
476 + other.y.get_variable(),
477 |lc| lc + u.get_variable()
478 );
479
480 let a = other.y.mul(cs.namespace(|| "A computation"), &self.x)?;
482
483 let b = other.x.mul(cs.namespace(|| "B computation"), &self.y)?;
485
486 let c = AllocatedNum::alloc(cs.namespace(|| "C"), || {
488 let mut t0 = *a.get_value().get()?;
489 t0.mul_assign(b.get_value().get()?);
490 t0.mul_assign(params.edwards_d());
491
492 Ok(t0)
493 })?;
494
495 cs.enforce(
496 || "C computation",
497 |lc| lc + (*params.edwards_d(), a.get_variable()),
498 |lc| lc + b.get_variable(),
499 |lc| lc + c.get_variable()
500 );
501
502 let x3 = AllocatedNum::alloc(cs.namespace(|| "x3"), || {
504 let mut t0 = *a.get_value().get()?;
505 t0.add_assign(b.get_value().get()?);
506
507 let mut t1 = E::Fr::one();
508 t1.add_assign(c.get_value().get()?);
509
510 match t1.inverse() {
511 Some(t1) => {
512 t0.mul_assign(&t1);
513
514 Ok(t0)
515 },
516 None => {
517 Err(SynthesisError::DivisionByZero)
518 }
519 }
520 })?;
521
522 let one = CS::one();
523 cs.enforce(
524 || "x3 computation",
525 |lc| lc + one + c.get_variable(),
526 |lc| lc + x3.get_variable(),
527 |lc| lc + a.get_variable()
528 + b.get_variable()
529 );
530
531 let y3 = AllocatedNum::alloc(cs.namespace(|| "y3"), || {
533 let mut t0 = *u.get_value().get()?;
534 t0.sub_assign(a.get_value().get()?);
535 t0.sub_assign(b.get_value().get()?);
536
537 let mut t1 = E::Fr::one();
538 t1.sub_assign(c.get_value().get()?);
539
540 match t1.inverse() {
541 Some(t1) => {
542 t0.mul_assign(&t1);
543
544 Ok(t0)
545 },
546 None => {
547 Err(SynthesisError::DivisionByZero)
548 }
549 }
550 })?;
551
552 cs.enforce(
553 || "y3 computation",
554 |lc| lc + one - c.get_variable(),
555 |lc| lc + y3.get_variable(),
556 |lc| lc + u.get_variable()
557 - a.get_variable()
558 - b.get_variable()
559 );
560
561 Ok(EdwardsPoint {
562 x: x3,
563 y: y3
564 })
565 }
566}
567
568pub struct MontgomeryPoint<E: Engine> {
569 x: Num<E>,
570 y: Num<E>
571}
572
573impl<E: JubjubEngine> MontgomeryPoint<E> {
574 pub fn into_edwards<CS>(
578 &self,
579 mut cs: CS,
580 params: &E::Params
581 ) -> Result<EdwardsPoint<E>, SynthesisError>
582 where CS: ConstraintSystem<E>
583 {
584 let u = AllocatedNum::alloc(cs.namespace(|| "u"), || {
586 let mut t0 = *self.x.get_value().get()?;
587 t0.mul_assign(params.scale());
588
589 match self.y.get_value().get()?.inverse() {
590 Some(invy) => {
591 t0.mul_assign(&invy);
592
593 Ok(t0)
594 },
595 None => {
596 Err(SynthesisError::DivisionByZero)
597 }
598 }
599 })?;
600
601 cs.enforce(
602 || "u computation",
603 |lc| lc + &self.y.lc(E::Fr::one()),
604 |lc| lc + u.get_variable(),
605 |lc| lc + &self.x.lc(*params.scale())
606 );
607
608 let v = AllocatedNum::alloc(cs.namespace(|| "v"), || {
610 let mut t0 = *self.x.get_value().get()?;
611 let mut t1 = t0;
612 t0.sub_assign(&E::Fr::one());
613 t1.add_assign(&E::Fr::one());
614
615 match t1.inverse() {
616 Some(t1) => {
617 t0.mul_assign(&t1);
618
619 Ok(t0)
620 },
621 None => {
622 Err(SynthesisError::DivisionByZero)
623 }
624 }
625 })?;
626
627 let one = CS::one();
628 cs.enforce(
629 || "v computation",
630 |lc| lc + &self.x.lc(E::Fr::one())
631 + one,
632 |lc| lc + v.get_variable(),
633 |lc| lc + &self.x.lc(E::Fr::one())
634 - one,
635 );
636
637 Ok(EdwardsPoint {
638 x: u,
639 y: v
640 })
641 }
642
643 pub fn interpret_unchecked(
648 x: Num<E>,
649 y: Num<E>
650 ) -> Self
651 {
652 MontgomeryPoint {
653 x: x,
654 y: y
655 }
656 }
657
658 pub fn add<CS>(
661 &self,
662 mut cs: CS,
663 other: &Self,
664 params: &E::Params
665 ) -> Result<Self, SynthesisError>
666 where CS: ConstraintSystem<E>
667 {
668 let lambda = AllocatedNum::alloc(cs.namespace(|| "lambda"), || {
670 let mut n = *other.y.get_value().get()?;
671 n.sub_assign(self.y.get_value().get()?);
672
673 let mut d = *other.x.get_value().get()?;
674 d.sub_assign(self.x.get_value().get()?);
675
676 match d.inverse() {
677 Some(d) => {
678 n.mul_assign(&d);
679 Ok(n)
680 },
681 None => {
682 Err(SynthesisError::DivisionByZero)
683 }
684 }
685 })?;
686
687 cs.enforce(
688 || "evaluate lambda",
689 |lc| lc + &other.x.lc(E::Fr::one())
690 - &self.x.lc(E::Fr::one()),
691
692 |lc| lc + lambda.get_variable(),
693
694 |lc| lc + &other.y.lc(E::Fr::one())
695 - &self.y.lc(E::Fr::one())
696 );
697
698 let xprime = AllocatedNum::alloc(cs.namespace(|| "xprime"), || {
700 let mut t0 = *lambda.get_value().get()?;
701 t0.square();
702 t0.sub_assign(params.montgomery_a());
703 t0.sub_assign(self.x.get_value().get()?);
704 t0.sub_assign(other.x.get_value().get()?);
705
706 Ok(t0)
707 })?;
708
709 let one = CS::one();
711 cs.enforce(
712 || "evaluate xprime",
713 |lc| lc + lambda.get_variable(),
714 |lc| lc + lambda.get_variable(),
715 |lc| lc + (*params.montgomery_a(), one)
716 + &self.x.lc(E::Fr::one())
717 + &other.x.lc(E::Fr::one())
718 + xprime.get_variable()
719 );
720
721 let yprime = AllocatedNum::alloc(cs.namespace(|| "yprime"), || {
723 let mut t0 = *xprime.get_value().get()?;
724 t0.sub_assign(self.x.get_value().get()?);
725 t0.mul_assign(lambda.get_value().get()?);
726 t0.add_assign(self.y.get_value().get()?);
727 t0.negate();
728
729 Ok(t0)
730 })?;
731
732 cs.enforce(
734 || "evaluate yprime",
735 |lc| lc + &self.x.lc(E::Fr::one())
736 - xprime.get_variable(),
737
738 |lc| lc + lambda.get_variable(),
739
740 |lc| lc + yprime.get_variable()
741 + &self.y.lc(E::Fr::one())
742 );
743
744 Ok(MontgomeryPoint {
745 x: xprime.into(),
746 y: yprime.into()
747 })
748 }
749}
750
751#[cfg(test)]
752mod test {
753 use bellman::{ConstraintSystem};
754 use rand::{XorShiftRng, SeedableRng, Rand, Rng};
755 use bellman::pairing::bls12_381::{Bls12, Fr};
756 use bellman::pairing::ff::{BitIterator, Field, PrimeField};
757 use ::circuit::test::*;
758 use ::jubjub::{
759 montgomery,
760 edwards,
761 JubjubBls12,
762 JubjubParams,
763 FixedGenerators
764 };
765 use ::jubjub::fs::Fs;
766 use super::{
767 MontgomeryPoint,
768 EdwardsPoint,
769 AllocatedNum,
770 fixed_base_multiplication
771 };
772 use super::super::boolean::{
773 Boolean,
774 AllocatedBit
775 };
776
777 #[test]
778 fn test_into_edwards() {
779 let params = &JubjubBls12::new();
780 let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
781
782 for _ in 0..100 {
783 let mut cs = TestConstraintSystem::<Bls12>::new();
784
785 let p = montgomery::Point::<Bls12, _>::rand(rng, params);
786 let (u, v) = edwards::Point::from_montgomery(&p, params).into_xy();
787 let (x, y) = p.into_xy().unwrap();
788
789 let numx = AllocatedNum::alloc(cs.namespace(|| "mont x"), || {
790 Ok(x)
791 }).unwrap();
792 let numy = AllocatedNum::alloc(cs.namespace(|| "mont y"), || {
793 Ok(y)
794 }).unwrap();
795
796 let p = MontgomeryPoint::interpret_unchecked(numx.into(), numy.into());
797
798 let q = p.into_edwards(&mut cs, params).unwrap();
799
800 assert!(cs.is_satisfied());
801 assert!(q.x.get_value().unwrap() == u);
802 assert!(q.y.get_value().unwrap() == v);
803
804 cs.set("u/num", rng.gen());
805 assert_eq!(cs.which_is_unsatisfied().unwrap(), "u computation");
806 cs.set("u/num", u);
807 assert!(cs.is_satisfied());
808
809 cs.set("v/num", rng.gen());
810 assert_eq!(cs.which_is_unsatisfied().unwrap(), "v computation");
811 cs.set("v/num", v);
812 assert!(cs.is_satisfied());
813 }
814 }
815
816 #[test]
817 fn test_interpret() {
818 let params = &JubjubBls12::new();
819 let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
820
821 for _ in 0..100 {
822 let p = edwards::Point::<Bls12, _>::rand(rng, ¶ms);
823
824 let mut cs = TestConstraintSystem::<Bls12>::new();
825 let q = EdwardsPoint::witness(
826 &mut cs,
827 Some(p.clone()),
828 ¶ms
829 ).unwrap();
830
831 let p = p.into_xy();
832
833 assert!(cs.is_satisfied());
834 assert_eq!(q.x.get_value().unwrap(), p.0);
835 assert_eq!(q.y.get_value().unwrap(), p.1);
836 }
837
838 for _ in 0..100 {
839 let p = edwards::Point::<Bls12, _>::rand(rng, ¶ms);
840 let (x, y) = p.into_xy();
841
842 let mut cs = TestConstraintSystem::<Bls12>::new();
843 let numx = AllocatedNum::alloc(cs.namespace(|| "x"), || {
844 Ok(x)
845 }).unwrap();
846 let numy = AllocatedNum::alloc(cs.namespace(|| "y"), || {
847 Ok(y)
848 }).unwrap();
849
850 let p = EdwardsPoint::interpret(&mut cs, &numx, &numy, ¶ms).unwrap();
851
852 assert!(cs.is_satisfied());
853 assert_eq!(p.x.get_value().unwrap(), x);
854 assert_eq!(p.y.get_value().unwrap(), y);
855 }
856
857 for _ in 0..100 {
859 let x = rng.gen();
860 let y = rng.gen();
861
862 let mut cs = TestConstraintSystem::<Bls12>::new();
863 let numx = AllocatedNum::alloc(cs.namespace(|| "x"), || {
864 Ok(x)
865 }).unwrap();
866 let numy = AllocatedNum::alloc(cs.namespace(|| "y"), || {
867 Ok(y)
868 }).unwrap();
869
870 EdwardsPoint::interpret(&mut cs, &numx, &numy, ¶ms).unwrap();
871
872 assert_eq!(cs.which_is_unsatisfied().unwrap(), "on curve check");
873 }
874 }
875
876 #[test]
877 fn test_edwards_fixed_base_multiplication() {
878 let params = &JubjubBls12::new();
879 let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
880
881 for _ in 0..100 {
882 let mut cs = TestConstraintSystem::<Bls12>::new();
883
884 let p = params.generator(FixedGenerators::NoteCommitmentRandomness);
885 let s = Fs::rand(rng);
886 let q = p.mul(s, params);
887 let (x1, y1) = q.into_xy();
888
889 let mut s_bits = BitIterator::new(s.into_repr()).collect::<Vec<_>>();
890 s_bits.reverse();
891 s_bits.truncate(Fs::NUM_BITS as usize);
892
893 let s_bits = s_bits.into_iter()
894 .enumerate()
895 .map(|(i, b)| AllocatedBit::alloc(cs.namespace(|| format!("scalar bit {}", i)), Some(b)).unwrap())
896 .map(|v| Boolean::from(v))
897 .collect::<Vec<_>>();
898
899 let q = fixed_base_multiplication(
900 cs.namespace(|| "multiplication"),
901 FixedGenerators::NoteCommitmentRandomness,
902 &s_bits,
903 params
904 ).unwrap();
905
906 assert_eq!(q.x.get_value().unwrap(), x1);
907 assert_eq!(q.y.get_value().unwrap(), y1);
908 }
909 }
910
911 #[test]
912 fn test_edwards_multiplication() {
913 let params = &JubjubBls12::new();
914 let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
915
916 for _ in 0..100 {
917 let mut cs = TestConstraintSystem::<Bls12>::new();
918
919 let p = edwards::Point::<Bls12, _>::rand(rng, params);
920 let s = Fs::rand(rng);
921 let q = p.mul(s, params);
922
923 let (x0, y0) = p.into_xy();
924 let (x1, y1) = q.into_xy();
925
926 let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || {
927 Ok(x0)
928 }).unwrap();
929 let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || {
930 Ok(y0)
931 }).unwrap();
932
933 let p = EdwardsPoint {
934 x: num_x0,
935 y: num_y0
936 };
937
938 let mut s_bits = BitIterator::new(s.into_repr()).collect::<Vec<_>>();
939 s_bits.reverse();
940 s_bits.truncate(Fs::NUM_BITS as usize);
941
942 let s_bits = s_bits.into_iter()
943 .enumerate()
944 .map(|(i, b)| AllocatedBit::alloc(cs.namespace(|| format!("scalar bit {}", i)), Some(b)).unwrap())
945 .map(|v| Boolean::from(v))
946 .collect::<Vec<_>>();
947
948 let q = p.mul(
949 cs.namespace(|| "scalar mul"),
950 &s_bits,
951 params
952 ).unwrap();
953
954 assert!(cs.is_satisfied());
955
956 assert_eq!(
957 q.x.get_value().unwrap(),
958 x1
959 );
960
961 assert_eq!(
962 q.y.get_value().unwrap(),
963 y1
964 );
965 }
966 }
967
968 #[test]
969 fn test_conditionally_select() {
970 let params = &JubjubBls12::new();
971 let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
972
973 for _ in 0..1000 {
974 let mut cs = TestConstraintSystem::<Bls12>::new();
975
976 let p = edwards::Point::<Bls12, _>::rand(rng, params);
977
978 let (x0, y0) = p.into_xy();
979
980 let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || {
981 Ok(x0)
982 }).unwrap();
983 let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || {
984 Ok(y0)
985 }).unwrap();
986
987 let p = EdwardsPoint {
988 x: num_x0,
989 y: num_y0
990 };
991
992 let mut should_we_select = rng.gen();
993
994 let mut b = if rng.gen() {
996 Boolean::from(AllocatedBit::alloc(
997 cs.namespace(|| "condition"),
998 Some(should_we_select)
999 ).unwrap())
1000 } else {
1001 Boolean::constant(should_we_select)
1002 };
1003
1004 if rng.gen() {
1006 b = b.not();
1007 should_we_select = !should_we_select;
1008 }
1009
1010 let q = p.conditionally_select(cs.namespace(|| "select"), &b).unwrap();
1011
1012 assert!(cs.is_satisfied());
1013
1014 if should_we_select {
1015 assert_eq!(q.x.get_value().unwrap(), x0);
1016 assert_eq!(q.y.get_value().unwrap(), y0);
1017
1018 cs.set("select/y'/num", Fr::one());
1019 assert_eq!(cs.which_is_unsatisfied().unwrap(), "select/y' computation");
1020 cs.set("select/x'/num", Fr::zero());
1021 assert_eq!(cs.which_is_unsatisfied().unwrap(), "select/x' computation");
1022 } else {
1023 assert_eq!(q.x.get_value().unwrap(), Fr::zero());
1024 assert_eq!(q.y.get_value().unwrap(), Fr::one());
1025
1026 cs.set("select/y'/num", x0);
1027 assert_eq!(cs.which_is_unsatisfied().unwrap(), "select/y' computation");
1028 cs.set("select/x'/num", y0);
1029 assert_eq!(cs.which_is_unsatisfied().unwrap(), "select/x' computation");
1030 }
1031 }
1032 }
1033
1034 #[test]
1035 fn test_edwards_addition() {
1036 let params = &JubjubBls12::new();
1037 let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
1038
1039 for _ in 0..100 {
1040 let p1 = edwards::Point::<Bls12, _>::rand(rng, params);
1041 let p2 = edwards::Point::<Bls12, _>::rand(rng, params);
1042
1043 let p3 = p1.add(&p2, params);
1044
1045 let (x0, y0) = p1.into_xy();
1046 let (x1, y1) = p2.into_xy();
1047 let (x2, y2) = p3.into_xy();
1048
1049 let mut cs = TestConstraintSystem::<Bls12>::new();
1050
1051 let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || {
1052 Ok(x0)
1053 }).unwrap();
1054 let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || {
1055 Ok(y0)
1056 }).unwrap();
1057
1058 let num_x1 = AllocatedNum::alloc(cs.namespace(|| "x1"), || {
1059 Ok(x1)
1060 }).unwrap();
1061 let num_y1 = AllocatedNum::alloc(cs.namespace(|| "y1"), || {
1062 Ok(y1)
1063 }).unwrap();
1064
1065 let p1 = EdwardsPoint {
1066 x: num_x0,
1067 y: num_y0
1068 };
1069
1070 let p2 = EdwardsPoint {
1071 x: num_x1,
1072 y: num_y1
1073 };
1074
1075 let p3 = p1.add(cs.namespace(|| "addition"), &p2, params).unwrap();
1076
1077 assert!(cs.is_satisfied());
1078
1079 assert!(p3.x.get_value().unwrap() == x2);
1080 assert!(p3.y.get_value().unwrap() == y2);
1081
1082 let u = cs.get("addition/U/num");
1083 cs.set("addition/U/num", rng.gen());
1084 assert_eq!(cs.which_is_unsatisfied(), Some("addition/U computation"));
1085 cs.set("addition/U/num", u);
1086 assert!(cs.is_satisfied());
1087
1088 let x3 = cs.get("addition/x3/num");
1089 cs.set("addition/x3/num", rng.gen());
1090 assert_eq!(cs.which_is_unsatisfied(), Some("addition/x3 computation"));
1091 cs.set("addition/x3/num", x3);
1092 assert!(cs.is_satisfied());
1093
1094 let y3 = cs.get("addition/y3/num");
1095 cs.set("addition/y3/num", rng.gen());
1096 assert_eq!(cs.which_is_unsatisfied(), Some("addition/y3 computation"));
1097 cs.set("addition/y3/num", y3);
1098 assert!(cs.is_satisfied());
1099 }
1100 }
1101
1102 #[test]
1103 fn test_edwards_doubling() {
1104 let params = &JubjubBls12::new();
1105 let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
1106
1107 for _ in 0..100 {
1108 let p1 = edwards::Point::<Bls12, _>::rand(rng, params);
1109 let p2 = p1.double(params);
1110
1111 let (x0, y0) = p1.into_xy();
1112 let (x1, y1) = p2.into_xy();
1113
1114 let mut cs = TestConstraintSystem::<Bls12>::new();
1115
1116 let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || {
1117 Ok(x0)
1118 }).unwrap();
1119 let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || {
1120 Ok(y0)
1121 }).unwrap();
1122
1123 let p1 = EdwardsPoint {
1124 x: num_x0,
1125 y: num_y0
1126 };
1127
1128 let p2 = p1.double(cs.namespace(|| "doubling"), params).unwrap();
1129
1130 assert!(cs.is_satisfied());
1131
1132 assert!(p2.x.get_value().unwrap() == x1);
1133 assert!(p2.y.get_value().unwrap() == y1);
1134 }
1135 }
1136
1137 #[test]
1138 fn test_montgomery_addition() {
1139 let params = &JubjubBls12::new();
1140 let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
1141
1142 for _ in 0..100 {
1143 let p1 = loop {
1144 let x: Fr = rng.gen();
1145 let s: bool = rng.gen();
1146
1147 if let Some(p) = montgomery::Point::<Bls12, _>::get_for_x(x, s, params) {
1148 break p;
1149 }
1150 };
1151
1152 let p2 = loop {
1153 let x: Fr = rng.gen();
1154 let s: bool = rng.gen();
1155
1156 if let Some(p) = montgomery::Point::<Bls12, _>::get_for_x(x, s, params) {
1157 break p;
1158 }
1159 };
1160
1161 let p3 = p1.add(&p2, params);
1162
1163 let (x0, y0) = p1.into_xy().unwrap();
1164 let (x1, y1) = p2.into_xy().unwrap();
1165 let (x2, y2) = p3.into_xy().unwrap();
1166
1167 let mut cs = TestConstraintSystem::<Bls12>::new();
1168
1169 let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || {
1170 Ok(x0)
1171 }).unwrap();
1172 let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || {
1173 Ok(y0)
1174 }).unwrap();
1175
1176 let num_x1 = AllocatedNum::alloc(cs.namespace(|| "x1"), || {
1177 Ok(x1)
1178 }).unwrap();
1179 let num_y1 = AllocatedNum::alloc(cs.namespace(|| "y1"), || {
1180 Ok(y1)
1181 }).unwrap();
1182
1183 let p1 = MontgomeryPoint {
1184 x: num_x0.into(),
1185 y: num_y0.into()
1186 };
1187
1188 let p2 = MontgomeryPoint {
1189 x: num_x1.into(),
1190 y: num_y1.into()
1191 };
1192
1193 let p3 = p1.add(cs.namespace(|| "addition"), &p2, params).unwrap();
1194
1195 assert!(cs.is_satisfied());
1196
1197 assert!(p3.x.get_value().unwrap() == x2);
1198 assert!(p3.y.get_value().unwrap() == y2);
1199
1200 cs.set("addition/yprime/num", rng.gen());
1201 assert_eq!(cs.which_is_unsatisfied(), Some("addition/evaluate yprime"));
1202 cs.set("addition/yprime/num", y2);
1203 assert!(cs.is_satisfied());
1204
1205 cs.set("addition/xprime/num", rng.gen());
1206 assert_eq!(cs.which_is_unsatisfied(), Some("addition/evaluate xprime"));
1207 cs.set("addition/xprime/num", x2);
1208 assert!(cs.is_satisfied());
1209
1210 cs.set("addition/lambda/num", rng.gen());
1211 assert_eq!(cs.which_is_unsatisfied(), Some("addition/evaluate lambda"));
1212 }
1213 }
1214}
1215
1216#[cfg(test)]
1217mod baby_test {
1218 use bellman::{ConstraintSystem};
1219 use rand::{XorShiftRng, SeedableRng, Rand, Rng};
1220 use bellman::pairing::bn256::{Bn256, Fr};
1221 use bellman::pairing::ff::{BitIterator, Field, PrimeField};
1222 use ::circuit::test::*;
1223 use ::alt_babyjubjub::{
1224 montgomery,
1225 edwards,
1226 AltJubjubBn256,
1227 JubjubParams,
1228 FixedGenerators
1229 };
1230 use ::alt_babyjubjub::fs::Fs;
1231
1232 use super::{
1233 MontgomeryPoint,
1234 EdwardsPoint,
1235 AllocatedNum,
1236 fixed_base_multiplication
1237 };
1238 use super::super::boolean::{
1239 Boolean,
1240 AllocatedBit
1241 };
1242
1243 #[test]
1244 fn test_into_edwards() {
1245 let params = &AltJubjubBn256::new();
1246 let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
1247
1248 for _ in 0..100 {
1249 let mut cs = TestConstraintSystem::<Bn256>::new();
1250
1251 let p = montgomery::Point::<Bn256, _>::rand(rng, params);
1252 let (u, v) = edwards::Point::from_montgomery(&p, params).into_xy();
1253 let (x, y) = p.into_xy().unwrap();
1254
1255 let numx = AllocatedNum::alloc(cs.namespace(|| "mont x"), || {
1256 Ok(x)
1257 }).unwrap();
1258 let numy = AllocatedNum::alloc(cs.namespace(|| "mont y"), || {
1259 Ok(y)
1260 }).unwrap();
1261
1262 let p = MontgomeryPoint::interpret_unchecked(numx.into(), numy.into());
1263
1264 let q = p.into_edwards(&mut cs, params).unwrap();
1265
1266 assert!(cs.is_satisfied());
1267 assert!(q.x.get_value().unwrap() == u);
1268 assert!(q.y.get_value().unwrap() == v);
1269
1270 cs.set("u/num", rng.gen());
1271 assert_eq!(cs.which_is_unsatisfied().unwrap(), "u computation");
1272 cs.set("u/num", u);
1273 assert!(cs.is_satisfied());
1274
1275 cs.set("v/num", rng.gen());
1276 assert_eq!(cs.which_is_unsatisfied().unwrap(), "v computation");
1277 cs.set("v/num", v);
1278 assert!(cs.is_satisfied());
1279 }
1280 }
1281
1282 #[test]
1283 fn test_interpret() {
1284 let params = &AltJubjubBn256::new();
1285 let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
1286
1287 for _ in 0..100 {
1288 let p = edwards::Point::<Bn256, _>::rand(rng, ¶ms);
1289
1290 let mut cs = TestConstraintSystem::<Bn256>::new();
1291 let q = EdwardsPoint::witness(
1292 &mut cs,
1293 Some(p.clone()),
1294 ¶ms
1295 ).unwrap();
1296
1297 let p = p.into_xy();
1298
1299 assert!(cs.is_satisfied());
1300 assert_eq!(q.x.get_value().unwrap(), p.0);
1301 assert_eq!(q.y.get_value().unwrap(), p.1);
1302 }
1303
1304 for _ in 0..100 {
1305 let p = edwards::Point::<Bn256, _>::rand(rng, ¶ms);
1306 let (x, y) = p.into_xy();
1307
1308 let mut cs = TestConstraintSystem::<Bn256>::new();
1309 let numx = AllocatedNum::alloc(cs.namespace(|| "x"), || {
1310 Ok(x)
1311 }).unwrap();
1312 let numy = AllocatedNum::alloc(cs.namespace(|| "y"), || {
1313 Ok(y)
1314 }).unwrap();
1315
1316 let p = EdwardsPoint::interpret(&mut cs, &numx, &numy, ¶ms).unwrap();
1317
1318 assert!(cs.is_satisfied());
1319 assert_eq!(p.x.get_value().unwrap(), x);
1320 assert_eq!(p.y.get_value().unwrap(), y);
1321 }
1322
1323 for _ in 0..100 {
1325 let x = rng.gen();
1326 let y = rng.gen();
1327
1328 let mut cs = TestConstraintSystem::<Bn256>::new();
1329 let numx = AllocatedNum::alloc(cs.namespace(|| "x"), || {
1330 Ok(x)
1331 }).unwrap();
1332 let numy = AllocatedNum::alloc(cs.namespace(|| "y"), || {
1333 Ok(y)
1334 }).unwrap();
1335
1336 EdwardsPoint::interpret(&mut cs, &numx, &numy, ¶ms).unwrap();
1337
1338 assert_eq!(cs.which_is_unsatisfied().unwrap(), "on curve check");
1339 }
1340 }
1341
1342 #[test]
1343 fn test_edwards_fixed_base_multiplication() {
1344 let params = &AltJubjubBn256::new();
1345 let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
1346
1347 for _ in 0..100 {
1348 let mut cs = TestConstraintSystem::<Bn256>::new();
1349
1350 let p = params.generator(FixedGenerators::NoteCommitmentRandomness);
1351 let s = Fs::rand(rng);
1352 let q = p.mul(s, params);
1353 let (x1, y1) = q.into_xy();
1354
1355 let mut s_bits = BitIterator::new(s.into_repr()).collect::<Vec<_>>();
1356 s_bits.reverse();
1357 s_bits.truncate(Fs::NUM_BITS as usize);
1358
1359 let s_bits = s_bits.into_iter()
1360 .enumerate()
1361 .map(|(i, b)| AllocatedBit::alloc(cs.namespace(|| format!("scalar bit {}", i)), Some(b)).unwrap())
1362 .map(|v| Boolean::from(v))
1363 .collect::<Vec<_>>();
1364
1365 let q = fixed_base_multiplication(
1366 cs.namespace(|| "multiplication"),
1367 FixedGenerators::NoteCommitmentRandomness,
1368 &s_bits,
1369 params
1370 ).unwrap();
1371
1372 assert_eq!(q.x.get_value().unwrap(), x1);
1373 assert_eq!(q.y.get_value().unwrap(), y1);
1374 }
1375 }
1376
1377 #[test]
1378 fn test_edwards_multiplication() {
1379 let params = &AltJubjubBn256::new();
1380 let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
1381
1382 for _ in 0..100 {
1383 let mut cs = TestConstraintSystem::<Bn256>::new();
1384
1385 let p = edwards::Point::<Bn256, _>::rand(rng, params);
1386 let s = Fs::rand(rng);
1387 let q = p.mul(s, params);
1388
1389 let (x0, y0) = p.into_xy();
1390 let (x1, y1) = q.into_xy();
1391
1392 let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || {
1393 Ok(x0)
1394 }).unwrap();
1395 let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || {
1396 Ok(y0)
1397 }).unwrap();
1398
1399 let p = EdwardsPoint {
1400 x: num_x0,
1401 y: num_y0
1402 };
1403
1404 let mut s_bits = BitIterator::new(s.into_repr()).collect::<Vec<_>>();
1405 s_bits.reverse();
1406 s_bits.truncate(Fs::NUM_BITS as usize);
1407
1408 let s_bits = s_bits.into_iter()
1409 .enumerate()
1410 .map(|(i, b)| AllocatedBit::alloc(cs.namespace(|| format!("scalar bit {}", i)), Some(b)).unwrap())
1411 .map(|v| Boolean::from(v))
1412 .collect::<Vec<_>>();
1413
1414 let q = p.mul(
1415 cs.namespace(|| "scalar mul"),
1416 &s_bits,
1417 params
1418 ).unwrap();
1419
1420 assert!(cs.is_satisfied());
1421
1422 assert_eq!(
1423 q.x.get_value().unwrap(),
1424 x1
1425 );
1426
1427 assert_eq!(
1428 q.y.get_value().unwrap(),
1429 y1
1430 );
1431 }
1432 }
1433
1434 #[test]
1435 fn test_conditionally_select() {
1436 let params = &AltJubjubBn256::new();
1437 let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
1438
1439 for _ in 0..1000 {
1440 let mut cs = TestConstraintSystem::<Bn256>::new();
1441
1442 let p = edwards::Point::<Bn256, _>::rand(rng, params);
1443
1444 let (x0, y0) = p.into_xy();
1445
1446 let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || {
1447 Ok(x0)
1448 }).unwrap();
1449 let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || {
1450 Ok(y0)
1451 }).unwrap();
1452
1453 let p = EdwardsPoint {
1454 x: num_x0,
1455 y: num_y0
1456 };
1457
1458 let mut should_we_select = rng.gen();
1459
1460 let mut b = if rng.gen() {
1462 Boolean::from(AllocatedBit::alloc(
1463 cs.namespace(|| "condition"),
1464 Some(should_we_select)
1465 ).unwrap())
1466 } else {
1467 Boolean::constant(should_we_select)
1468 };
1469
1470 if rng.gen() {
1472 b = b.not();
1473 should_we_select = !should_we_select;
1474 }
1475
1476 let q = p.conditionally_select(cs.namespace(|| "select"), &b).unwrap();
1477
1478 assert!(cs.is_satisfied());
1479
1480 if should_we_select {
1481 assert_eq!(q.x.get_value().unwrap(), x0);
1482 assert_eq!(q.y.get_value().unwrap(), y0);
1483
1484 cs.set("select/y'/num", Fr::one());
1485 assert_eq!(cs.which_is_unsatisfied().unwrap(), "select/y' computation");
1486 cs.set("select/x'/num", Fr::zero());
1487 assert_eq!(cs.which_is_unsatisfied().unwrap(), "select/x' computation");
1488 } else {
1489 assert_eq!(q.x.get_value().unwrap(), Fr::zero());
1490 assert_eq!(q.y.get_value().unwrap(), Fr::one());
1491
1492 cs.set("select/y'/num", x0);
1493 assert_eq!(cs.which_is_unsatisfied().unwrap(), "select/y' computation");
1494 cs.set("select/x'/num", y0);
1495 assert_eq!(cs.which_is_unsatisfied().unwrap(), "select/x' computation");
1496 }
1497 }
1498 }
1499
1500 #[test]
1501 fn test_edwards_addition() {
1502 let params = &AltJubjubBn256::new();
1503 let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
1504
1505 for _ in 0..100 {
1506 let p1 = edwards::Point::<Bn256, _>::rand(rng, params);
1507 let p2 = edwards::Point::<Bn256, _>::rand(rng, params);
1508
1509 let p3 = p1.add(&p2, params);
1510
1511 let (x0, y0) = p1.into_xy();
1512 let (x1, y1) = p2.into_xy();
1513 let (x2, y2) = p3.into_xy();
1514
1515 let mut cs = TestConstraintSystem::<Bn256>::new();
1516
1517 let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || {
1518 Ok(x0)
1519 }).unwrap();
1520 let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || {
1521 Ok(y0)
1522 }).unwrap();
1523
1524 let num_x1 = AllocatedNum::alloc(cs.namespace(|| "x1"), || {
1525 Ok(x1)
1526 }).unwrap();
1527 let num_y1 = AllocatedNum::alloc(cs.namespace(|| "y1"), || {
1528 Ok(y1)
1529 }).unwrap();
1530
1531 let p1 = EdwardsPoint {
1532 x: num_x0,
1533 y: num_y0
1534 };
1535
1536 let p2 = EdwardsPoint {
1537 x: num_x1,
1538 y: num_y1
1539 };
1540
1541 let p3 = p1.add(cs.namespace(|| "addition"), &p2, params).unwrap();
1542
1543 assert!(cs.is_satisfied());
1544
1545 assert!(p3.x.get_value().unwrap() == x2);
1546 assert!(p3.y.get_value().unwrap() == y2);
1547
1548 let u = cs.get("addition/U/num");
1549 cs.set("addition/U/num", rng.gen());
1550 assert_eq!(cs.which_is_unsatisfied(), Some("addition/U computation"));
1551 cs.set("addition/U/num", u);
1552 assert!(cs.is_satisfied());
1553
1554 let x3 = cs.get("addition/x3/num");
1555 cs.set("addition/x3/num", rng.gen());
1556 assert_eq!(cs.which_is_unsatisfied(), Some("addition/x3 computation"));
1557 cs.set("addition/x3/num", x3);
1558 assert!(cs.is_satisfied());
1559
1560 let y3 = cs.get("addition/y3/num");
1561 cs.set("addition/y3/num", rng.gen());
1562 assert_eq!(cs.which_is_unsatisfied(), Some("addition/y3 computation"));
1563 cs.set("addition/y3/num", y3);
1564 assert!(cs.is_satisfied());
1565 }
1566 }
1567
1568 #[test]
1569 fn test_edwards_doubling() {
1570 let params = &AltJubjubBn256::new();
1571 let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
1572
1573 for _ in 0..100 {
1574 let p1 = edwards::Point::<Bn256, _>::rand(rng, params);
1575 let p2 = p1.double(params);
1576
1577 let (x0, y0) = p1.into_xy();
1578 let (x1, y1) = p2.into_xy();
1579
1580 let mut cs = TestConstraintSystem::<Bn256>::new();
1581
1582 let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || {
1583 Ok(x0)
1584 }).unwrap();
1585 let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || {
1586 Ok(y0)
1587 }).unwrap();
1588
1589 let p1 = EdwardsPoint {
1590 x: num_x0,
1591 y: num_y0
1592 };
1593
1594 let p2 = p1.double(cs.namespace(|| "doubling"), params).unwrap();
1595
1596 assert!(cs.is_satisfied());
1597
1598 assert!(p2.x.get_value().unwrap() == x1);
1599 assert!(p2.y.get_value().unwrap() == y1);
1600 }
1601 }
1602
1603 #[test]
1604 fn test_montgomery_addition() {
1605 let params = &AltJubjubBn256::new();
1606 let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
1607
1608 for _ in 0..100 {
1609 let p1 = loop {
1610 let x: Fr = rng.gen();
1611 let s: bool = rng.gen();
1612
1613 if let Some(p) = montgomery::Point::<Bn256, _>::get_for_x(x, s, params) {
1614 break p;
1615 }
1616 };
1617
1618 let p2 = loop {
1619 let x: Fr = rng.gen();
1620 let s: bool = rng.gen();
1621
1622 if let Some(p) = montgomery::Point::<Bn256, _>::get_for_x(x, s, params) {
1623 break p;
1624 }
1625 };
1626
1627 let p3 = p1.add(&p2, params);
1628
1629 let (x0, y0) = p1.into_xy().unwrap();
1630 let (x1, y1) = p2.into_xy().unwrap();
1631 let (x2, y2) = p3.into_xy().unwrap();
1632
1633 let mut cs = TestConstraintSystem::<Bn256>::new();
1634
1635 let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || {
1636 Ok(x0)
1637 }).unwrap();
1638 let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || {
1639 Ok(y0)
1640 }).unwrap();
1641
1642 let num_x1 = AllocatedNum::alloc(cs.namespace(|| "x1"), || {
1643 Ok(x1)
1644 }).unwrap();
1645 let num_y1 = AllocatedNum::alloc(cs.namespace(|| "y1"), || {
1646 Ok(y1)
1647 }).unwrap();
1648
1649 let p1 = MontgomeryPoint {
1650 x: num_x0.into(),
1651 y: num_y0.into()
1652 };
1653
1654 let p2 = MontgomeryPoint {
1655 x: num_x1.into(),
1656 y: num_y1.into()
1657 };
1658
1659 let p3 = p1.add(cs.namespace(|| "addition"), &p2, params).unwrap();
1660
1661 assert!(cs.is_satisfied());
1662
1663 assert!(p3.x.get_value().unwrap() == x2);
1664 assert!(p3.y.get_value().unwrap() == y2);
1665
1666 cs.set("addition/yprime/num", rng.gen());
1667 assert_eq!(cs.which_is_unsatisfied(), Some("addition/evaluate yprime"));
1668 cs.set("addition/yprime/num", y2);
1669 assert!(cs.is_satisfied());
1670
1671 cs.set("addition/xprime/num", rng.gen());
1672 assert_eq!(cs.which_is_unsatisfied(), Some("addition/evaluate xprime"));
1673 cs.set("addition/xprime/num", x2);
1674 assert!(cs.is_satisfied());
1675
1676 cs.set("addition/lambda/num", rng.gen());
1677 assert_eq!(cs.which_is_unsatisfied(), Some("addition/evaluate lambda"));
1678 }
1679 }
1680}