1use bellman::pairing::{
2 Engine,
3};
4
5use bellman::pairing::ff::{
6 Field,
7 PrimeField,
8 BitIterator
9};
10
11use bellman::{
12 ConstraintSystem,
13 SynthesisError,
14 LinearCombination,
15 Variable
16};
17
18use super::{
19 Assignment
20};
21
22#[derive(Clone)]
25pub struct AllocatedBit {
26 variable: Variable,
27 value: Option<bool>
28}
29
30impl AllocatedBit {
31 pub fn get_value(&self) -> Option<bool> {
32 self.value
33 }
34
35 pub fn get_variable(&self) -> Variable {
36 self.variable
37 }
38
39 pub fn alloc_conditionally<E, CS>(
43 mut cs: CS,
44 value: Option<bool>,
45 must_be_false: &AllocatedBit
46 ) -> Result<Self, SynthesisError>
47 where E: Engine,
48 CS: ConstraintSystem<E>
49 {
50 let var = cs.alloc(|| "boolean", || {
51 if *value.get()? {
52 Ok(E::Fr::one())
53 } else {
54 Ok(E::Fr::zero())
55 }
56 })?;
57
58 cs.enforce(
65 || "boolean constraint",
66 |lc| lc + CS::one() - must_be_false.variable - var,
67 |lc| lc + var,
68 |lc| lc
69 );
70
71 Ok(AllocatedBit {
72 variable: var,
73 value: value
74 })
75 }
76
77 pub fn alloc<E, CS>(
80 mut cs: CS,
81 value: Option<bool>,
82 ) -> Result<Self, SynthesisError>
83 where E: Engine,
84 CS: ConstraintSystem<E>
85 {
86 let var = cs.alloc(|| "boolean", || {
87 if *value.get()? {
88 Ok(E::Fr::one())
89 } else {
90 Ok(E::Fr::zero())
91 }
92 })?;
93
94 cs.enforce(
97 || "boolean constraint",
98 |lc| lc + CS::one() - var,
99 |lc| lc + var,
100 |lc| lc
101 );
102
103 Ok(AllocatedBit {
104 variable: var,
105 value: value
106 })
107 }
108
109 pub fn xor<E, CS>(
112 mut cs: CS,
113 a: &Self,
114 b: &Self
115 ) -> Result<Self, SynthesisError>
116 where E: Engine,
117 CS: ConstraintSystem<E>
118 {
119 let mut result_value = None;
120
121 let result_var = cs.alloc(|| "xor result", || {
122 if *a.value.get()? ^ *b.value.get()? {
123 result_value = Some(true);
124
125 Ok(E::Fr::one())
126 } else {
127 result_value = Some(false);
128
129 Ok(E::Fr::zero())
130 }
131 })?;
132
133 cs.enforce(
149 || "xor constraint",
150 |lc| lc + a.variable + a.variable,
151 |lc| lc + b.variable,
152 |lc| lc + a.variable + b.variable - result_var
153 );
154
155 Ok(AllocatedBit {
156 variable: result_var,
157 value: result_value
158 })
159 }
160
161 pub fn and<E, CS>(
164 mut cs: CS,
165 a: &Self,
166 b: &Self
167 ) -> Result<Self, SynthesisError>
168 where E: Engine,
169 CS: ConstraintSystem<E>
170 {
171 let mut result_value = None;
172
173 let result_var = cs.alloc(|| "and result", || {
174 if *a.value.get()? & *b.value.get()? {
175 result_value = Some(true);
176
177 Ok(E::Fr::one())
178 } else {
179 result_value = Some(false);
180
181 Ok(E::Fr::zero())
182 }
183 })?;
184
185 cs.enforce(
188 || "and constraint",
189 |lc| lc + a.variable,
190 |lc| lc + b.variable,
191 |lc| lc + result_var
192 );
193
194 Ok(AllocatedBit {
195 variable: result_var,
196 value: result_value
197 })
198 }
199
200 pub fn and_not<E, CS>(
202 mut cs: CS,
203 a: &Self,
204 b: &Self
205 ) -> Result<Self, SynthesisError>
206 where E: Engine,
207 CS: ConstraintSystem<E>
208 {
209 let mut result_value = None;
210
211 let result_var = cs.alloc(|| "and not result", || {
212 if *a.value.get()? & !*b.value.get()? {
213 result_value = Some(true);
214
215 Ok(E::Fr::one())
216 } else {
217 result_value = Some(false);
218
219 Ok(E::Fr::zero())
220 }
221 })?;
222
223 cs.enforce(
226 || "and not constraint",
227 |lc| lc + a.variable,
228 |lc| lc + CS::one() - b.variable,
229 |lc| lc + result_var
230 );
231
232 Ok(AllocatedBit {
233 variable: result_var,
234 value: result_value
235 })
236 }
237
238 pub fn nor<E, CS>(
240 mut cs: CS,
241 a: &Self,
242 b: &Self
243 ) -> Result<Self, SynthesisError>
244 where E: Engine,
245 CS: ConstraintSystem<E>
246 {
247 let mut result_value = None;
248
249 let result_var = cs.alloc(|| "nor result", || {
250 if !*a.value.get()? & !*b.value.get()? {
251 result_value = Some(true);
252
253 Ok(E::Fr::one())
254 } else {
255 result_value = Some(false);
256
257 Ok(E::Fr::zero())
258 }
259 })?;
260
261 cs.enforce(
264 || "nor constraint",
265 |lc| lc + CS::one() - a.variable,
266 |lc| lc + CS::one() - b.variable,
267 |lc| lc + result_var
268 );
269
270 Ok(AllocatedBit {
271 variable: result_var,
272 value: result_value
273 })
274 }
275}
276
277pub fn u64_into_boolean_vec_le<E: Engine, CS: ConstraintSystem<E>>(
278 mut cs: CS,
279 value: Option<u64>
280) -> Result<Vec<Boolean>, SynthesisError>
281{
282 let values = match value {
283 Some(ref value) => {
284 let mut tmp = Vec::with_capacity(64);
285
286 for i in 0..64 {
287 tmp.push(Some(*value >> i & 1 == 1));
288 }
289
290 tmp
291 },
292 None => {
293 vec![None; 64]
294 }
295 };
296
297 let bits = values.into_iter().enumerate().map(|(i, b)| {
298 Ok(Boolean::from(AllocatedBit::alloc(
299 cs.namespace(|| format!("bit {}", i)),
300 b
301 )?))
302 }).collect::<Result<Vec<_>, SynthesisError>>()?;
303
304 Ok(bits)
305}
306
307pub fn le_bits_into_le_bytes(bits: Vec<Boolean>) -> Vec<Boolean> {
310 assert_eq!(bits.len() % 8, 0);
311
312 let mut result = vec![];
313 for chunk in bits.chunks(8) {
314 for b in chunk.iter().rev() {
315 result.push(b.clone());
316 }
317 }
318
319 result
320}
321
322pub fn field_into_boolean_vec_le<E: Engine, CS: ConstraintSystem<E>, F: PrimeField>(
323 cs: CS,
324 value: Option<F>
325) -> Result<Vec<Boolean>, SynthesisError>
326{
327 let v = field_into_allocated_bits_le::<E, CS, F>(cs, value)?;
328
329 Ok(v.into_iter().map(|e| Boolean::from(e)).collect())
330}
331
332pub fn field_into_allocated_bits_le<E: Engine, CS: ConstraintSystem<E>, F: PrimeField>(
333 mut cs: CS,
334 value: Option<F>
335) -> Result<Vec<AllocatedBit>, SynthesisError>
336{
337 let values = match value {
339 Some(ref value) => {
340 let mut field_char = BitIterator::new(F::char());
341
342 let mut tmp = Vec::with_capacity(F::NUM_BITS as usize);
343
344 let mut found_one = false;
345 for b in BitIterator::new(value.into_repr()) {
346 found_one |= field_char.next().unwrap();
348 if !found_one {
349 continue;
350 }
351
352 tmp.push(Some(b));
353 }
354
355 assert_eq!(tmp.len(), F::NUM_BITS as usize);
356
357 tmp
358 },
359 None => {
360 vec![None; F::NUM_BITS as usize]
361 }
362 };
363
364 let bits = values.into_iter().rev().enumerate().map(|(i, b)| {
366 AllocatedBit::alloc(
367 cs.namespace(|| format!("bit {}", i)),
368 b
369 )
370 }).collect::<Result<Vec<_>, SynthesisError>>()?;
371
372 Ok(bits)
373}
374
375#[derive(Clone)]
378pub enum Boolean {
379 Is(AllocatedBit),
381 Not(AllocatedBit),
383 Constant(bool)
385}
386
387impl Boolean {
388 pub fn is_constant(&self) -> bool {
389 match *self {
390 Boolean::Constant(_) => true,
391 _ => false
392 }
393 }
394
395 pub fn get_variable(&self) -> Option<&AllocatedBit> {
396 match *self {
397 Boolean::Is(ref v) => Some(v),
398 Boolean::Not(ref v) => Some(v),
399 Boolean::Constant(_) => None
400 }
401 }
402
403 pub fn enforce_equal<E, CS>(
404 mut cs: CS,
405 a: &Self,
406 b: &Self
407 ) -> Result<(), SynthesisError>
408 where E: Engine,
409 CS: ConstraintSystem<E>
410 {
411 match (a, b) {
412 (&Boolean::Constant(a), &Boolean::Constant(b)) => {
413 if a == b {
414 Ok(())
415 } else {
416 Err(SynthesisError::Unsatisfiable)
417 }
418 },
419 (&Boolean::Constant(true), a) | (a, &Boolean::Constant(true)) => {
420 cs.enforce(
421 || "enforce equal to one",
422 |lc| lc,
423 |lc| lc,
424 |lc| lc + CS::one() - &a.lc(CS::one(), E::Fr::one())
425 );
426
427 Ok(())
428 },
429 (&Boolean::Constant(false), a) | (a, &Boolean::Constant(false)) => {
430 cs.enforce(
431 || "enforce equal to zero",
432 |lc| lc,
433 |lc| lc,
434 |_| a.lc(CS::one(), E::Fr::one())
435 );
436
437 Ok(())
438 },
439 (a, b) => {
440 cs.enforce(
441 || "enforce equal",
442 |lc| lc,
443 |lc| lc,
444 |_| a.lc(CS::one(), E::Fr::one()) - &b.lc(CS::one(), E::Fr::one())
445 );
446
447 Ok(())
448 }
449 }
450 }
451
452 pub fn get_value(&self) -> Option<bool> {
453 match self {
454 &Boolean::Constant(c) => Some(c),
455 &Boolean::Is(ref v) => v.get_value(),
456 &Boolean::Not(ref v) => v.get_value().map(|b| !b)
457 }
458 }
459
460 pub fn lc<E: Engine>(
461 &self,
462 one: Variable,
463 coeff: E::Fr
464 ) -> LinearCombination<E>
465 {
466 match self {
467 &Boolean::Constant(c) => {
468 if c {
469 LinearCombination::<E>::zero() + (coeff, one)
470 } else {
471 LinearCombination::<E>::zero()
472 }
473 },
474 &Boolean::Is(ref v) => {
475 LinearCombination::<E>::zero() + (coeff, v.get_variable())
476 },
477 &Boolean::Not(ref v) => {
478 LinearCombination::<E>::zero() + (coeff, one) - (coeff, v.get_variable())
479 }
480 }
481 }
482
483 pub fn constant(b: bool) -> Self {
485 Boolean::Constant(b)
486 }
487
488 pub fn not(&self) -> Self {
490 match self {
491 &Boolean::Constant(c) => Boolean::Constant(!c),
492 &Boolean::Is(ref v) => Boolean::Not(v.clone()),
493 &Boolean::Not(ref v) => Boolean::Is(v.clone())
494 }
495 }
496
497 pub fn xor<'a, E, CS>(
499 cs: CS,
500 a: &'a Self,
501 b: &'a Self
502 ) -> Result<Self, SynthesisError>
503 where E: Engine,
504 CS: ConstraintSystem<E>
505 {
506 match (a, b) {
507 (&Boolean::Constant(false), x) | (x, &Boolean::Constant(false)) => Ok(x.clone()),
508 (&Boolean::Constant(true), x) | (x, &Boolean::Constant(true)) => Ok(x.not()),
509 (is @ &Boolean::Is(_), not @ &Boolean::Not(_)) | (not @ &Boolean::Not(_), is @ &Boolean::Is(_)) => {
511 Ok(Boolean::xor(
512 cs,
513 is,
514 ¬.not()
515 )?.not())
516 },
517 (&Boolean::Is(ref a), &Boolean::Is(ref b)) | (&Boolean::Not(ref a), &Boolean::Not(ref b)) => {
519 Ok(Boolean::Is(AllocatedBit::xor(cs, a, b)?))
520 }
521 }
522 }
523
524 pub fn and<'a, E, CS>(
526 cs: CS,
527 a: &'a Self,
528 b: &'a Self
529 ) -> Result<Self, SynthesisError>
530 where E: Engine,
531 CS: ConstraintSystem<E>
532 {
533 match (a, b) {
534 (&Boolean::Constant(false), _) | (_, &Boolean::Constant(false)) => Ok(Boolean::Constant(false)),
536 (&Boolean::Constant(true), x) | (x, &Boolean::Constant(true)) => Ok(x.clone()),
538 (&Boolean::Is(ref is), &Boolean::Not(ref not)) | (&Boolean::Not(ref not), &Boolean::Is(ref is)) => {
540 Ok(Boolean::Is(AllocatedBit::and_not(cs, is, not)?))
541 },
542 (&Boolean::Not(ref a), &Boolean::Not(ref b)) => {
544 Ok(Boolean::Is(AllocatedBit::nor(cs, a, b)?))
545 },
546 (&Boolean::Is(ref a), &Boolean::Is(ref b)) => {
548 Ok(Boolean::Is(AllocatedBit::and(cs, a, b)?))
549 }
550 }
551 }
552
553 pub fn sha256_ch<'a, E, CS>(
555 mut cs: CS,
556 a: &'a Self,
557 b: &'a Self,
558 c: &'a Self
559 ) -> Result<Self, SynthesisError>
560 where E: Engine,
561 CS: ConstraintSystem<E>
562 {
563 let ch_value = match (a.get_value(), b.get_value(), c.get_value()) {
564 (Some(a), Some(b), Some(c)) => {
565 Some((a & b) ^ ((!a) & c))
567 },
568 _ => None
569 };
570
571 match (a, b, c) {
572 (&Boolean::Constant(_),
573 &Boolean::Constant(_),
574 &Boolean::Constant(_)) => {
575 return Ok(Boolean::Constant(ch_value.expect("they're all constants")));
578 },
579 (&Boolean::Constant(false), _, c) => {
580 return Ok(c.clone());
587 },
588 (a, &Boolean::Constant(false), c) => {
589 return Boolean::and(
594 cs,
595 &a.not(),
596 &c
597 );
598 },
599 (a, b, &Boolean::Constant(false)) => {
600 return Boolean::and(
605 cs,
606 &a,
607 &b
608 );
609 },
610 (a, b, &Boolean::Constant(true)) => {
611 return Ok(Boolean::and(
618 cs,
619 &a,
620 &b.not()
621 )?.not());
622 },
623 (a, &Boolean::Constant(true), c) => {
624 return Ok(Boolean::and(
631 cs,
632 &a.not(),
633 &c.not()
634 )?.not());
635 },
636 (&Boolean::Constant(true), _, _) => {
637 },
643 (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Is(_)) |
644 (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Not(_)) |
645 (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Is(_)) |
646 (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Not(_)) |
647 (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Is(_)) |
648 (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Not(_)) |
649 (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Is(_)) |
650 (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Not(_))
651 => {}
652 }
653
654 let ch = cs.alloc(|| "ch", || {
655 ch_value.get().map(|v| {
656 if *v {
657 E::Fr::one()
658 } else {
659 E::Fr::zero()
660 }
661 })
662 })?;
663
664 cs.enforce(
666 || "ch computation",
667 |_| b.lc(CS::one(), E::Fr::one())
668 - &c.lc(CS::one(), E::Fr::one()),
669 |_| a.lc(CS::one(), E::Fr::one()),
670 |lc| lc + ch - &c.lc(CS::one(), E::Fr::one())
671 );
672
673 Ok(AllocatedBit {
674 value: ch_value,
675 variable: ch
676 }.into())
677 }
678
679 pub fn sha256_maj<'a, E, CS>(
681 mut cs: CS,
682 a: &'a Self,
683 b: &'a Self,
684 c: &'a Self,
685 ) -> Result<Self, SynthesisError>
686 where E: Engine,
687 CS: ConstraintSystem<E>
688 {
689 let maj_value = match (a.get_value(), b.get_value(), c.get_value()) {
690 (Some(a), Some(b), Some(c)) => {
691 Some((a & b) ^ (a & c) ^ (b & c))
693 },
694 _ => None
695 };
696
697 match (a, b, c) {
698 (&Boolean::Constant(_),
699 &Boolean::Constant(_),
700 &Boolean::Constant(_)) => {
701 return Ok(Boolean::Constant(maj_value.expect("they're all constants")));
704 },
705 (&Boolean::Constant(false), b, c) => {
706 return Boolean::and(
711 cs,
712 b,
713 c
714 );
715 },
716 (a, &Boolean::Constant(false), c) => {
717 return Boolean::and(
722 cs,
723 a,
724 c
725 );
726 },
727 (a, b, &Boolean::Constant(false)) => {
728 return Boolean::and(
733 cs,
734 a,
735 b
736 );
737 },
738 (a, b, &Boolean::Constant(true)) => {
739 return Ok(Boolean::and(
746 cs,
747 &a.not(),
748 &b.not()
749 )?.not());
750 },
751 (a, &Boolean::Constant(true), c) => {
752 return Ok(Boolean::and(
757 cs,
758 &a.not(),
759 &c.not()
760 )?.not());
761 },
762 (&Boolean::Constant(true), b, c) => {
763 return Ok(Boolean::and(
768 cs,
769 &b.not(),
770 &c.not()
771 )?.not());
772 },
773 (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Is(_)) |
774 (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Not(_)) |
775 (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Is(_)) |
776 (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Not(_)) |
777 (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Is(_)) |
778 (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Not(_)) |
779 (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Is(_)) |
780 (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Not(_))
781 => {}
782 }
783
784 let maj = cs.alloc(|| "maj", || {
785 maj_value.get().map(|v| {
786 if *v {
787 E::Fr::one()
788 } else {
789 E::Fr::zero()
790 }
791 })
792 })?;
793
794 let bc = Self::and(
804 cs.namespace(|| "b and c"),
805 b,
806 c
807 )?;
808
809 cs.enforce(
810 || "maj computation",
811 |_| bc.lc(CS::one(), E::Fr::one())
812 + &bc.lc(CS::one(), E::Fr::one())
813 - &b.lc(CS::one(), E::Fr::one())
814 - &c.lc(CS::one(), E::Fr::one()),
815 |_| a.lc(CS::one(), E::Fr::one()),
816 |_| bc.lc(CS::one(), E::Fr::one()) - maj
817 );
818
819 Ok(AllocatedBit {
820 value: maj_value,
821 variable: maj
822 }.into())
823 }
824}
825
826impl From<AllocatedBit> for Boolean {
827 fn from(b: AllocatedBit) -> Boolean {
828 Boolean::Is(b)
829 }
830}
831
832#[cfg(test)]
833mod test {
834 use bellman::{ConstraintSystem};
835 use bellman::pairing::bls12_381::{Bls12, Fr};
836 use bellman::pairing::ff::{Field, PrimeField};
837 use ::circuit::test::*;
838 use super::{
839 AllocatedBit,
840 Boolean,
841 field_into_allocated_bits_le,
842 u64_into_boolean_vec_le
843 };
844
845 #[test]
846 fn test_allocated_bit() {
847 let mut cs = TestConstraintSystem::<Bls12>::new();
848
849 AllocatedBit::alloc(&mut cs, Some(true)).unwrap();
850 assert!(cs.get("boolean") == Fr::one());
851 assert!(cs.is_satisfied());
852 cs.set("boolean", Fr::zero());
853 assert!(cs.is_satisfied());
854 cs.set("boolean", Fr::from_str("2").unwrap());
855 assert!(!cs.is_satisfied());
856 assert!(cs.which_is_unsatisfied() == Some("boolean constraint"));
857 }
858
859 #[test]
860 fn test_xor() {
861 for a_val in [false, true].iter() {
862 for b_val in [false, true].iter() {
863 let mut cs = TestConstraintSystem::<Bls12>::new();
864 let a = AllocatedBit::alloc(cs.namespace(|| "a"), Some(*a_val)).unwrap();
865 let b = AllocatedBit::alloc(cs.namespace(|| "b"), Some(*b_val)).unwrap();
866 let c = AllocatedBit::xor(&mut cs, &a, &b).unwrap();
867 assert_eq!(c.value.unwrap(), *a_val ^ *b_val);
868
869 assert!(cs.is_satisfied());
870 assert!(cs.get("a/boolean") == if *a_val { Field::one() } else { Field::zero() });
871 assert!(cs.get("b/boolean") == if *b_val { Field::one() } else { Field::zero() });
872 assert!(cs.get("xor result") == if *a_val ^ *b_val { Field::one() } else { Field::zero() });
873
874 cs.set("xor result", if *a_val ^ *b_val { Field::zero() } else { Field::one() });
876 assert!(!cs.is_satisfied());
877 }
878 }
879 }
880
881 #[test]
882 fn test_and() {
883 for a_val in [false, true].iter() {
884 for b_val in [false, true].iter() {
885 let mut cs = TestConstraintSystem::<Bls12>::new();
886 let a = AllocatedBit::alloc(cs.namespace(|| "a"), Some(*a_val)).unwrap();
887 let b = AllocatedBit::alloc(cs.namespace(|| "b"), Some(*b_val)).unwrap();
888 let c = AllocatedBit::and(&mut cs, &a, &b).unwrap();
889 assert_eq!(c.value.unwrap(), *a_val & *b_val);
890
891 assert!(cs.is_satisfied());
892 assert!(cs.get("a/boolean") == if *a_val { Field::one() } else { Field::zero() });
893 assert!(cs.get("b/boolean") == if *b_val { Field::one() } else { Field::zero() });
894 assert!(cs.get("and result") == if *a_val & *b_val { Field::one() } else { Field::zero() });
895
896 cs.set("and result", if *a_val & *b_val { Field::zero() } else { Field::one() });
898 assert!(!cs.is_satisfied());
899 }
900 }
901 }
902
903 #[test]
904 fn test_and_not() {
905 for a_val in [false, true].iter() {
906 for b_val in [false, true].iter() {
907 let mut cs = TestConstraintSystem::<Bls12>::new();
908 let a = AllocatedBit::alloc(cs.namespace(|| "a"), Some(*a_val)).unwrap();
909 let b = AllocatedBit::alloc(cs.namespace(|| "b"), Some(*b_val)).unwrap();
910 let c = AllocatedBit::and_not(&mut cs, &a, &b).unwrap();
911 assert_eq!(c.value.unwrap(), *a_val & !*b_val);
912
913 assert!(cs.is_satisfied());
914 assert!(cs.get("a/boolean") == if *a_val { Field::one() } else { Field::zero() });
915 assert!(cs.get("b/boolean") == if *b_val { Field::one() } else { Field::zero() });
916 assert!(cs.get("and not result") == if *a_val & !*b_val { Field::one() } else { Field::zero() });
917
918 cs.set("and not result", if *a_val & !*b_val { Field::zero() } else { Field::one() });
920 assert!(!cs.is_satisfied());
921 }
922 }
923 }
924
925 #[test]
926 fn test_nor() {
927 for a_val in [false, true].iter() {
928 for b_val in [false, true].iter() {
929 let mut cs = TestConstraintSystem::<Bls12>::new();
930 let a = AllocatedBit::alloc(cs.namespace(|| "a"), Some(*a_val)).unwrap();
931 let b = AllocatedBit::alloc(cs.namespace(|| "b"), Some(*b_val)).unwrap();
932 let c = AllocatedBit::nor(&mut cs, &a, &b).unwrap();
933 assert_eq!(c.value.unwrap(), !*a_val & !*b_val);
934
935 assert!(cs.is_satisfied());
936 assert!(cs.get("a/boolean") == if *a_val { Field::one() } else { Field::zero() });
937 assert!(cs.get("b/boolean") == if *b_val { Field::one() } else { Field::zero() });
938 assert!(cs.get("nor result") == if !*a_val & !*b_val { Field::one() } else { Field::zero() });
939
940 cs.set("nor result", if !*a_val & !*b_val { Field::zero() } else { Field::one() });
942 assert!(!cs.is_satisfied());
943 }
944 }
945 }
946
947 #[test]
948 fn test_enforce_equal() {
949 for a_bool in [false, true].iter().cloned() {
950 for b_bool in [false, true].iter().cloned() {
951 for a_neg in [false, true].iter().cloned() {
952 for b_neg in [false, true].iter().cloned() {
953 {
954 let mut cs = TestConstraintSystem::<Bls12>::new();
955
956 let mut a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_bool)).unwrap());
957 let mut b = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_bool)).unwrap());
958
959 if a_neg {
960 a = a.not();
961 }
962 if b_neg {
963 b = b.not();
964 }
965
966 Boolean::enforce_equal(&mut cs, &a, &b).unwrap();
967
968 assert_eq!(
969 cs.is_satisfied(),
970 (a_bool ^ a_neg) == (b_bool ^ b_neg)
971 );
972 }
973 {
974 let mut cs = TestConstraintSystem::<Bls12>::new();
975
976 let mut a = Boolean::Constant(a_bool);
977 let mut b = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_bool)).unwrap());
978
979 if a_neg {
980 a = a.not();
981 }
982 if b_neg {
983 b = b.not();
984 }
985
986 Boolean::enforce_equal(&mut cs, &a, &b).unwrap();
987
988 assert_eq!(
989 cs.is_satisfied(),
990 (a_bool ^ a_neg) == (b_bool ^ b_neg)
991 );
992 }
993 {
994 let mut cs = TestConstraintSystem::<Bls12>::new();
995
996 let mut a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_bool)).unwrap());
997 let mut b = Boolean::Constant(b_bool);
998
999 if a_neg {
1000 a = a.not();
1001 }
1002 if b_neg {
1003 b = b.not();
1004 }
1005
1006 Boolean::enforce_equal(&mut cs, &a, &b).unwrap();
1007
1008 assert_eq!(
1009 cs.is_satisfied(),
1010 (a_bool ^ a_neg) == (b_bool ^ b_neg)
1011 );
1012 }
1013 {
1014 let mut cs = TestConstraintSystem::<Bls12>::new();
1015
1016 let mut a = Boolean::Constant(a_bool);
1017 let mut b = Boolean::Constant(b_bool);
1018
1019 if a_neg {
1020 a = a.not();
1021 }
1022 if b_neg {
1023 b = b.not();
1024 }
1025
1026 let result = Boolean::enforce_equal(&mut cs, &a, &b);
1027
1028 if (a_bool ^ a_neg) == (b_bool ^ b_neg) {
1029 assert!(result.is_ok());
1030 assert!(cs.is_satisfied());
1031 } else {
1032 assert!(result.is_err());
1033 }
1034 }
1035 }
1036 }
1037 }
1038 }
1039 }
1040
1041 #[test]
1042 fn test_boolean_negation() {
1043 let mut cs = TestConstraintSystem::<Bls12>::new();
1044
1045 let mut b = Boolean::from(AllocatedBit::alloc(&mut cs, Some(true)).unwrap());
1046
1047 match b {
1048 Boolean::Is(_) => {},
1049 _ => panic!("unexpected value")
1050 }
1051
1052 b = b.not();
1053
1054 match b {
1055 Boolean::Not(_) => {},
1056 _ => panic!("unexpected value")
1057 }
1058
1059 b = b.not();
1060
1061 match b {
1062 Boolean::Is(_) => {},
1063 _ => panic!("unexpected value")
1064 }
1065
1066 b = Boolean::constant(true);
1067
1068 match b {
1069 Boolean::Constant(true) => {},
1070 _ => panic!("unexpected value")
1071 }
1072
1073 b = b.not();
1074
1075 match b {
1076 Boolean::Constant(false) => {},
1077 _ => panic!("unexpected value")
1078 }
1079
1080 b = b.not();
1081
1082 match b {
1083 Boolean::Constant(true) => {},
1084 _ => panic!("unexpected value")
1085 }
1086 }
1087
1088 #[derive(Copy, Clone, Debug)]
1089 enum OperandType {
1090 True,
1091 False,
1092 AllocatedTrue,
1093 AllocatedFalse,
1094 NegatedAllocatedTrue,
1095 NegatedAllocatedFalse
1096 }
1097
1098 impl OperandType {
1099 fn is_constant(&self) -> bool {
1100 match *self {
1101 OperandType::True => true,
1102 OperandType::False => true,
1103 OperandType::AllocatedTrue => false,
1104 OperandType::AllocatedFalse => false,
1105 OperandType::NegatedAllocatedTrue => false,
1106 OperandType::NegatedAllocatedFalse => false
1107 }
1108 }
1109
1110 fn val(&self) -> bool {
1111 match *self {
1112 OperandType::True => true,
1113 OperandType::False => false,
1114 OperandType::AllocatedTrue => true,
1115 OperandType::AllocatedFalse => false,
1116 OperandType::NegatedAllocatedTrue => false,
1117 OperandType::NegatedAllocatedFalse => true
1118 }
1119 }
1120 }
1121
1122
1123 #[test]
1124 fn test_boolean_xor() {
1125 let variants = [
1126 OperandType::True,
1127 OperandType::False,
1128 OperandType::AllocatedTrue,
1129 OperandType::AllocatedFalse,
1130 OperandType::NegatedAllocatedTrue,
1131 OperandType::NegatedAllocatedFalse
1132 ];
1133
1134 for first_operand in variants.iter().cloned() {
1135 for second_operand in variants.iter().cloned() {
1136 let mut cs = TestConstraintSystem::<Bls12>::new();
1137
1138 let a;
1139 let b;
1140
1141 {
1142 let mut dyn_construct = |operand, name| {
1143 let cs = cs.namespace(|| name);
1144
1145 match operand {
1146 OperandType::True => Boolean::constant(true),
1147 OperandType::False => Boolean::constant(false),
1148 OperandType::AllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()),
1149 OperandType::AllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()),
1150 OperandType::NegatedAllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not(),
1151 OperandType::NegatedAllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not(),
1152 }
1153 };
1154
1155 a = dyn_construct(first_operand, "a");
1156 b = dyn_construct(second_operand, "b");
1157 }
1158
1159 let c = Boolean::xor(&mut cs, &a, &b).unwrap();
1160
1161 assert!(cs.is_satisfied());
1162
1163 match (first_operand, second_operand, c) {
1164 (OperandType::True, OperandType::True, Boolean::Constant(false)) => {},
1165 (OperandType::True, OperandType::False, Boolean::Constant(true)) => {},
1166 (OperandType::True, OperandType::AllocatedTrue, Boolean::Not(_)) => {},
1167 (OperandType::True, OperandType::AllocatedFalse, Boolean::Not(_)) => {},
1168 (OperandType::True, OperandType::NegatedAllocatedTrue, Boolean::Is(_)) => {},
1169 (OperandType::True, OperandType::NegatedAllocatedFalse, Boolean::Is(_)) => {},
1170
1171 (OperandType::False, OperandType::True, Boolean::Constant(true)) => {},
1172 (OperandType::False, OperandType::False, Boolean::Constant(false)) => {},
1173 (OperandType::False, OperandType::AllocatedTrue, Boolean::Is(_)) => {},
1174 (OperandType::False, OperandType::AllocatedFalse, Boolean::Is(_)) => {},
1175 (OperandType::False, OperandType::NegatedAllocatedTrue, Boolean::Not(_)) => {},
1176 (OperandType::False, OperandType::NegatedAllocatedFalse, Boolean::Not(_)) => {},
1177
1178 (OperandType::AllocatedTrue, OperandType::True, Boolean::Not(_)) => {},
1179 (OperandType::AllocatedTrue, OperandType::False, Boolean::Is(_)) => {},
1180 (OperandType::AllocatedTrue, OperandType::AllocatedTrue, Boolean::Is(ref v)) => {
1181 assert!(cs.get("xor result") == Field::zero());
1182 assert_eq!(v.value, Some(false));
1183 },
1184 (OperandType::AllocatedTrue, OperandType::AllocatedFalse, Boolean::Is(ref v)) => {
1185 assert!(cs.get("xor result") == Field::one());
1186 assert_eq!(v.value, Some(true));
1187 },
1188 (OperandType::AllocatedTrue, OperandType::NegatedAllocatedTrue, Boolean::Not(ref v)) => {
1189 assert!(cs.get("xor result") == Field::zero());
1190 assert_eq!(v.value, Some(false));
1191 },
1192 (OperandType::AllocatedTrue, OperandType::NegatedAllocatedFalse, Boolean::Not(ref v)) => {
1193 assert!(cs.get("xor result") == Field::one());
1194 assert_eq!(v.value, Some(true));
1195 },
1196
1197 (OperandType::AllocatedFalse, OperandType::True, Boolean::Not(_)) => {},
1198 (OperandType::AllocatedFalse, OperandType::False, Boolean::Is(_)) => {},
1199 (OperandType::AllocatedFalse, OperandType::AllocatedTrue, Boolean::Is(ref v)) => {
1200 assert!(cs.get("xor result") == Field::one());
1201 assert_eq!(v.value, Some(true));
1202 },
1203 (OperandType::AllocatedFalse, OperandType::AllocatedFalse, Boolean::Is(ref v)) => {
1204 assert!(cs.get("xor result") == Field::zero());
1205 assert_eq!(v.value, Some(false));
1206 },
1207 (OperandType::AllocatedFalse, OperandType::NegatedAllocatedTrue, Boolean::Not(ref v)) => {
1208 assert!(cs.get("xor result") == Field::one());
1209 assert_eq!(v.value, Some(true));
1210 },
1211 (OperandType::AllocatedFalse, OperandType::NegatedAllocatedFalse, Boolean::Not(ref v)) => {
1212 assert!(cs.get("xor result") == Field::zero());
1213 assert_eq!(v.value, Some(false));
1214 },
1215
1216 (OperandType::NegatedAllocatedTrue, OperandType::True, Boolean::Is(_)) => {},
1217 (OperandType::NegatedAllocatedTrue, OperandType::False, Boolean::Not(_)) => {},
1218 (OperandType::NegatedAllocatedTrue, OperandType::AllocatedTrue, Boolean::Not(ref v)) => {
1219 assert!(cs.get("xor result") == Field::zero());
1220 assert_eq!(v.value, Some(false));
1221 },
1222 (OperandType::NegatedAllocatedTrue, OperandType::AllocatedFalse, Boolean::Not(ref v)) => {
1223 assert!(cs.get("xor result") == Field::one());
1224 assert_eq!(v.value, Some(true));
1225 },
1226 (OperandType::NegatedAllocatedTrue, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => {
1227 assert!(cs.get("xor result") == Field::zero());
1228 assert_eq!(v.value, Some(false));
1229 },
1230 (OperandType::NegatedAllocatedTrue, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => {
1231 assert!(cs.get("xor result") == Field::one());
1232 assert_eq!(v.value, Some(true));
1233 },
1234
1235 (OperandType::NegatedAllocatedFalse, OperandType::True, Boolean::Is(_)) => {},
1236 (OperandType::NegatedAllocatedFalse, OperandType::False, Boolean::Not(_)) => {},
1237 (OperandType::NegatedAllocatedFalse, OperandType::AllocatedTrue, Boolean::Not(ref v)) => {
1238 assert!(cs.get("xor result") == Field::one());
1239 assert_eq!(v.value, Some(true));
1240 },
1241 (OperandType::NegatedAllocatedFalse, OperandType::AllocatedFalse, Boolean::Not(ref v)) => {
1242 assert!(cs.get("xor result") == Field::zero());
1243 assert_eq!(v.value, Some(false));
1244 },
1245 (OperandType::NegatedAllocatedFalse, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => {
1246 assert!(cs.get("xor result") == Field::one());
1247 assert_eq!(v.value, Some(true));
1248 },
1249 (OperandType::NegatedAllocatedFalse, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => {
1250 assert!(cs.get("xor result") == Field::zero());
1251 assert_eq!(v.value, Some(false));
1252 },
1253
1254 _ => panic!("this should never be encountered")
1255 }
1256 }
1257 }
1258 }
1259
1260 #[test]
1261 fn test_boolean_and() {
1262 let variants = [
1263 OperandType::True,
1264 OperandType::False,
1265 OperandType::AllocatedTrue,
1266 OperandType::AllocatedFalse,
1267 OperandType::NegatedAllocatedTrue,
1268 OperandType::NegatedAllocatedFalse
1269 ];
1270
1271 for first_operand in variants.iter().cloned() {
1272 for second_operand in variants.iter().cloned() {
1273 let mut cs = TestConstraintSystem::<Bls12>::new();
1274
1275 let a;
1276 let b;
1277
1278 {
1279 let mut dyn_construct = |operand, name| {
1280 let cs = cs.namespace(|| name);
1281
1282 match operand {
1283 OperandType::True => Boolean::constant(true),
1284 OperandType::False => Boolean::constant(false),
1285 OperandType::AllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()),
1286 OperandType::AllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()),
1287 OperandType::NegatedAllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not(),
1288 OperandType::NegatedAllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not(),
1289 }
1290 };
1291
1292 a = dyn_construct(first_operand, "a");
1293 b = dyn_construct(second_operand, "b");
1294 }
1295
1296 let c = Boolean::and(&mut cs, &a, &b).unwrap();
1297
1298 assert!(cs.is_satisfied());
1299
1300 match (first_operand, second_operand, c) {
1301 (OperandType::True, OperandType::True, Boolean::Constant(true)) => {},
1302 (OperandType::True, OperandType::False, Boolean::Constant(false)) => {},
1303 (OperandType::True, OperandType::AllocatedTrue, Boolean::Is(_)) => {},
1304 (OperandType::True, OperandType::AllocatedFalse, Boolean::Is(_)) => {},
1305 (OperandType::True, OperandType::NegatedAllocatedTrue, Boolean::Not(_)) => {},
1306 (OperandType::True, OperandType::NegatedAllocatedFalse, Boolean::Not(_)) => {},
1307
1308 (OperandType::False, OperandType::True, Boolean::Constant(false)) => {},
1309 (OperandType::False, OperandType::False, Boolean::Constant(false)) => {},
1310 (OperandType::False, OperandType::AllocatedTrue, Boolean::Constant(false)) => {},
1311 (OperandType::False, OperandType::AllocatedFalse, Boolean::Constant(false)) => {},
1312 (OperandType::False, OperandType::NegatedAllocatedTrue, Boolean::Constant(false)) => {},
1313 (OperandType::False, OperandType::NegatedAllocatedFalse, Boolean::Constant(false)) => {},
1314
1315 (OperandType::AllocatedTrue, OperandType::True, Boolean::Is(_)) => {},
1316 (OperandType::AllocatedTrue, OperandType::False, Boolean::Constant(false)) => {},
1317 (OperandType::AllocatedTrue, OperandType::AllocatedTrue, Boolean::Is(ref v)) => {
1318 assert!(cs.get("and result") == Field::one());
1319 assert_eq!(v.value, Some(true));
1320 },
1321 (OperandType::AllocatedTrue, OperandType::AllocatedFalse, Boolean::Is(ref v)) => {
1322 assert!(cs.get("and result") == Field::zero());
1323 assert_eq!(v.value, Some(false));
1324 },
1325 (OperandType::AllocatedTrue, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => {
1326 assert!(cs.get("and not result") == Field::zero());
1327 assert_eq!(v.value, Some(false));
1328 },
1329 (OperandType::AllocatedTrue, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => {
1330 assert!(cs.get("and not result") == Field::one());
1331 assert_eq!(v.value, Some(true));
1332 },
1333
1334 (OperandType::AllocatedFalse, OperandType::True, Boolean::Is(_)) => {},
1335 (OperandType::AllocatedFalse, OperandType::False, Boolean::Constant(false)) => {},
1336 (OperandType::AllocatedFalse, OperandType::AllocatedTrue, Boolean::Is(ref v)) => {
1337 assert!(cs.get("and result") == Field::zero());
1338 assert_eq!(v.value, Some(false));
1339 },
1340 (OperandType::AllocatedFalse, OperandType::AllocatedFalse, Boolean::Is(ref v)) => {
1341 assert!(cs.get("and result") == Field::zero());
1342 assert_eq!(v.value, Some(false));
1343 },
1344 (OperandType::AllocatedFalse, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => {
1345 assert!(cs.get("and not result") == Field::zero());
1346 assert_eq!(v.value, Some(false));
1347 },
1348 (OperandType::AllocatedFalse, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => {
1349 assert!(cs.get("and not result") == Field::zero());
1350 assert_eq!(v.value, Some(false));
1351 },
1352
1353 (OperandType::NegatedAllocatedTrue, OperandType::True, Boolean::Not(_)) => {},
1354 (OperandType::NegatedAllocatedTrue, OperandType::False, Boolean::Constant(false)) => {},
1355 (OperandType::NegatedAllocatedTrue, OperandType::AllocatedTrue, Boolean::Is(ref v)) => {
1356 assert!(cs.get("and not result") == Field::zero());
1357 assert_eq!(v.value, Some(false));
1358 },
1359 (OperandType::NegatedAllocatedTrue, OperandType::AllocatedFalse, Boolean::Is(ref v)) => {
1360 assert!(cs.get("and not result") == Field::zero());
1361 assert_eq!(v.value, Some(false));
1362 },
1363 (OperandType::NegatedAllocatedTrue, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => {
1364 assert!(cs.get("nor result") == Field::zero());
1365 assert_eq!(v.value, Some(false));
1366 },
1367 (OperandType::NegatedAllocatedTrue, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => {
1368 assert!(cs.get("nor result") == Field::zero());
1369 assert_eq!(v.value, Some(false));
1370 },
1371
1372 (OperandType::NegatedAllocatedFalse, OperandType::True, Boolean::Not(_)) => {},
1373 (OperandType::NegatedAllocatedFalse, OperandType::False, Boolean::Constant(false)) => {},
1374 (OperandType::NegatedAllocatedFalse, OperandType::AllocatedTrue, Boolean::Is(ref v)) => {
1375 assert!(cs.get("and not result") == Field::one());
1376 assert_eq!(v.value, Some(true));
1377 },
1378 (OperandType::NegatedAllocatedFalse, OperandType::AllocatedFalse, Boolean::Is(ref v)) => {
1379 assert!(cs.get("and not result") == Field::zero());
1380 assert_eq!(v.value, Some(false));
1381 },
1382 (OperandType::NegatedAllocatedFalse, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => {
1383 assert!(cs.get("nor result") == Field::zero());
1384 assert_eq!(v.value, Some(false));
1385 },
1386 (OperandType::NegatedAllocatedFalse, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => {
1387 assert!(cs.get("nor result") == Field::one());
1388 assert_eq!(v.value, Some(true));
1389 },
1390
1391 _ => {
1392 panic!("unexpected behavior at {:?} AND {:?}", first_operand, second_operand);
1393 }
1394 }
1395 }
1396 }
1397 }
1398
1399 #[test]
1400 fn test_u64_into_boolean_vec_le() {
1401 let mut cs = TestConstraintSystem::<Bls12>::new();
1402
1403 let bits = u64_into_boolean_vec_le(&mut cs, Some(17234652694787248421)).unwrap();
1404
1405 assert!(cs.is_satisfied());
1406
1407 assert_eq!(bits.len(), 64);
1408
1409 assert_eq!(bits[63 - 0].get_value().unwrap(), true);
1410 assert_eq!(bits[63 - 1].get_value().unwrap(), true);
1411 assert_eq!(bits[63 - 2].get_value().unwrap(), true);
1412 assert_eq!(bits[63 - 3].get_value().unwrap(), false);
1413 assert_eq!(bits[63 - 4].get_value().unwrap(), true);
1414 assert_eq!(bits[63 - 5].get_value().unwrap(), true);
1415 assert_eq!(bits[63 - 20].get_value().unwrap(), true);
1416 assert_eq!(bits[63 - 21].get_value().unwrap(), false);
1417 assert_eq!(bits[63 - 22].get_value().unwrap(), false);
1418 }
1419
1420 #[test]
1421 fn test_field_into_allocated_bits_le() {
1422 let mut cs = TestConstraintSystem::<Bls12>::new();
1423
1424 let r = Fr::from_str("9147677615426976802526883532204139322118074541891858454835346926874644257775").unwrap();
1425
1426 let bits = field_into_allocated_bits_le(&mut cs, Some(r)).unwrap();
1427
1428 assert!(cs.is_satisfied());
1429
1430 assert_eq!(bits.len(), 255);
1431
1432 assert_eq!(bits[254 - 0].value.unwrap(), false);
1433 assert_eq!(bits[254 - 1].value.unwrap(), false);
1434 assert_eq!(bits[254 - 2].value.unwrap(), true);
1435 assert_eq!(bits[254 - 3].value.unwrap(), false);
1436 assert_eq!(bits[254 - 4].value.unwrap(), true);
1437 assert_eq!(bits[254 - 5].value.unwrap(), false);
1438 assert_eq!(bits[254 - 20].value.unwrap(), true);
1439 assert_eq!(bits[254 - 23].value.unwrap(), true);
1440 }
1441
1442 #[test]
1443 fn test_boolean_sha256_ch() {
1444 let variants = [
1445 OperandType::True,
1446 OperandType::False,
1447 OperandType::AllocatedTrue,
1448 OperandType::AllocatedFalse,
1449 OperandType::NegatedAllocatedTrue,
1450 OperandType::NegatedAllocatedFalse
1451 ];
1452
1453 for first_operand in variants.iter().cloned() {
1454 for second_operand in variants.iter().cloned() {
1455 for third_operand in variants.iter().cloned() {
1456 let mut cs = TestConstraintSystem::<Bls12>::new();
1457
1458 let a;
1459 let b;
1460 let c;
1461
1462 let expected = (first_operand.val() & second_operand.val()) ^
1464 ((!first_operand.val()) & third_operand.val());
1465
1466 {
1467 let mut dyn_construct = |operand, name| {
1468 let cs = cs.namespace(|| name);
1469
1470 match operand {
1471 OperandType::True => Boolean::constant(true),
1472 OperandType::False => Boolean::constant(false),
1473 OperandType::AllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()),
1474 OperandType::AllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()),
1475 OperandType::NegatedAllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not(),
1476 OperandType::NegatedAllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not(),
1477 }
1478 };
1479
1480 a = dyn_construct(first_operand, "a");
1481 b = dyn_construct(second_operand, "b");
1482 c = dyn_construct(third_operand, "c");
1483 }
1484
1485 let maj = Boolean::sha256_ch(&mut cs, &a, &b, &c).unwrap();
1486
1487 assert!(cs.is_satisfied());
1488
1489 assert_eq!(maj.get_value().unwrap(), expected);
1490
1491 if first_operand.is_constant() ||
1492 second_operand.is_constant() ||
1493 third_operand.is_constant()
1494 {
1495 if first_operand.is_constant() &&
1496 second_operand.is_constant() &&
1497 third_operand.is_constant()
1498 {
1499 assert_eq!(cs.num_constraints(), 0);
1500 }
1501 }
1502 else
1503 {
1504 assert_eq!(cs.get("ch"), {
1505 if expected {
1506 Fr::one()
1507 } else {
1508 Fr::zero()
1509 }
1510 });
1511 cs.set("ch", {
1512 if expected {
1513 Fr::zero()
1514 } else {
1515 Fr::one()
1516 }
1517 });
1518 assert_eq!(cs.which_is_unsatisfied().unwrap(), "ch computation");
1519 }
1520 }
1521 }
1522 }
1523 }
1524
1525 #[test]
1526 fn test_boolean_sha256_maj() {
1527 let variants = [
1528 OperandType::True,
1529 OperandType::False,
1530 OperandType::AllocatedTrue,
1531 OperandType::AllocatedFalse,
1532 OperandType::NegatedAllocatedTrue,
1533 OperandType::NegatedAllocatedFalse
1534 ];
1535
1536 for first_operand in variants.iter().cloned() {
1537 for second_operand in variants.iter().cloned() {
1538 for third_operand in variants.iter().cloned() {
1539 let mut cs = TestConstraintSystem::<Bls12>::new();
1540
1541 let a;
1542 let b;
1543 let c;
1544
1545 let expected = (first_operand.val() & second_operand.val()) ^
1547 (first_operand.val() & third_operand.val()) ^
1548 (second_operand.val() & third_operand.val());
1549
1550 {
1551 let mut dyn_construct = |operand, name| {
1552 let cs = cs.namespace(|| name);
1553
1554 match operand {
1555 OperandType::True => Boolean::constant(true),
1556 OperandType::False => Boolean::constant(false),
1557 OperandType::AllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()),
1558 OperandType::AllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()),
1559 OperandType::NegatedAllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not(),
1560 OperandType::NegatedAllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not(),
1561 }
1562 };
1563
1564 a = dyn_construct(first_operand, "a");
1565 b = dyn_construct(second_operand, "b");
1566 c = dyn_construct(third_operand, "c");
1567 }
1568
1569 let maj = Boolean::sha256_maj(&mut cs, &a, &b, &c).unwrap();
1570
1571 assert!(cs.is_satisfied());
1572
1573 assert_eq!(maj.get_value().unwrap(), expected);
1574
1575 if first_operand.is_constant() ||
1576 second_operand.is_constant() ||
1577 third_operand.is_constant()
1578 {
1579 if first_operand.is_constant() &&
1580 second_operand.is_constant() &&
1581 third_operand.is_constant()
1582 {
1583 assert_eq!(cs.num_constraints(), 0);
1584 }
1585 }
1586 else
1587 {
1588 assert_eq!(cs.get("maj"), {
1589 if expected {
1590 Fr::one()
1591 } else {
1592 Fr::zero()
1593 }
1594 });
1595 cs.set("maj", {
1596 if expected {
1597 Fr::zero()
1598 } else {
1599 Fr::one()
1600 }
1601 });
1602 assert_eq!(cs.which_is_unsatisfied().unwrap(), "maj computation");
1603 }
1604 }
1605 }
1606 }
1607 }
1608}