Skip to main content

sapling_crypto_ce/circuit/
ecc.rs

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
40/// Perform a fixed-base scalar multiplication with
41/// `by` being in little-endian bit order.
42pub 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    // Represents the result of the multiplication
52    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        // (0, -1) is a small order point, but won't ever appear here
117        // because cofactor is 2^3, and we performed three doublings.
118        // (0, 1) is the neutral element, so checking if x is nonzero
119        // is sufficient to prevent small order points here.
120        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    /// This converts the point into a representation.
138    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    /// This 'witnesses' a point inside the constraint system.
161    /// It guarantees the point is on the curve.
162    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        // Allocate x
172        let x = AllocatedNum::alloc(
173            cs.namespace(|| "x"),
174            || {
175                Ok(p.get()?.0)
176            }
177        )?;
178
179        // Allocate y
180        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    /// Returns `self` if condition is true, and the neutral
196    /// element (0, 1) otherwise.
197    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        // Compute x' = self.x if condition, and 0 otherwise
205        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        // condition * x = x'
214        // if condition is 0, x' must be 0
215        // if condition is 1, x' must be x
216        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        // Compute y' = self.y if condition, and 1 otherwise
225        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        // condition * y = y' - (1 - condition)
234        // if condition is 0, y' must be 1
235        // if condition is 1, y' must be y
236        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    /// Performs a scalar multiplication of this twisted Edwards
251    /// point by a scalar represented as a sequence of booleans
252    /// in little-endian bit order.
253    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        // Represents the current "magnitude" of the base
262        // that we're operating over. Starts at self,
263        // then 2*self, then 4*self, ...
264        let mut curbase = None;
265
266        // Represents the result of the multiplication
267        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                // Double the previous value
274                curbase = Some(
275                    curbase.unwrap()
276                           .double(cs.namespace(|| format!("doubling {}", i)), params)?
277                );
278            }
279
280            // Represents the select base. If the bit for this magnitude
281            // is true, this will return `curbase`. Otherwise it will
282            // return the neutral element, which will have no effect on
283            // the result.
284            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        // -x^2 + y^2 = 1 + dx^2y^2
314
315        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        // Compute T = (x1 + y1) * (x1 + y1)
343        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        // Compute A = x1 * y1
365        let a = self.x.mul(cs.namespace(|| "A computation"), &self.y)?;
366
367        // Compute C = d*A*A
368        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        // Compute x3 = (2.A) / (1 + C)
384        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        // Compute y3 = (U - 2.A) / (1 - C)
413        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    /// Perform addition between any two points
450    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        // Compute U = (x1 + y1) * (x2 + y2)
459        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        // Compute A = y2 * x1
481        let a = other.y.mul(cs.namespace(|| "A computation"), &self.x)?;
482
483        // Compute B = x2 * y1
484        let b = other.x.mul(cs.namespace(|| "B computation"), &self.y)?;
485
486        // Compute C = d*A*B
487        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        // Compute x3 = (A + B) / (1 + C)
503        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        // Compute y3 = (U - A - B) / (1 - C)
532        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    /// Converts an element in the prime order subgroup into
575    /// a point in the birationally equivalent twisted
576    /// Edwards curve.
577    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        // Compute u = (scale*x) / y
585        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        // Compute v = (x - 1) / (x + 1)
609        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    /// Interprets an (x, y) pair as a point
644    /// in Montgomery, does not check that it's
645    /// on the curve. Useful for constants and
646    /// window table lookups.
647    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    /// Performs an affine point addition, not defined for
659    /// coincident points.
660    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        // Compute lambda = (y' - y) / (x' - x)
669        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        // Compute x'' = lambda^2 - A - x - x'
699        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        // (lambda) * (lambda) = (A + x + x' + x'')
710        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        // Compute y' = -(y + lambda(x' - x))
722        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        // y' + y = lambda(x - x')
733        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, &params);
823
824            let mut cs = TestConstraintSystem::<Bls12>::new();
825            let q = EdwardsPoint::witness(
826                &mut cs,
827                Some(p.clone()),
828                &params
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, &params);
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, &params).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        // Random (x, y) are unlikely to be on the curve.
858        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, &params).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            // Conditionally allocate
995            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            // Conditionally negate
1005            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, &params);
1289
1290            let mut cs = TestConstraintSystem::<Bn256>::new();
1291            let q = EdwardsPoint::witness(
1292                &mut cs,
1293                Some(p.clone()),
1294                &params
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, &params);
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, &params).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        // Random (x, y) are unlikely to be on the curve.
1324        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, &params).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            // Conditionally allocate
1461            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            // Conditionally negate
1471            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}