1use ff::{PrimeField, PrimeFieldBits};
4
5use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable};
6
7#[derive(Debug, Clone)]
10pub struct AllocatedBit {
11 variable: Variable,
12 value: Option<bool>,
13}
14
15impl AllocatedBit {
16 pub fn get_value(&self) -> Option<bool> {
17 self.value
18 }
19
20 pub fn get_variable(&self) -> Variable {
21 self.variable
22 }
23
24 pub fn alloc_conditionally<Scalar, CS>(
28 mut cs: CS,
29 value: Option<bool>,
30 must_be_false: &AllocatedBit,
31 ) -> Result<Self, SynthesisError>
32 where
33 Scalar: PrimeField,
34 CS: ConstraintSystem<Scalar>,
35 {
36 let var = cs.alloc(
37 || "boolean",
38 || {
39 if value.ok_or(SynthesisError::AssignmentMissing)? {
40 Ok(Scalar::ONE)
41 } else {
42 Ok(Scalar::ZERO)
43 }
44 },
45 )?;
46
47 cs.enforce(
54 || "boolean constraint",
55 |lc| lc + CS::one() - must_be_false.variable - var,
56 |lc| lc + var,
57 |lc| lc,
58 );
59
60 Ok(AllocatedBit {
61 variable: var,
62 value,
63 })
64 }
65
66 pub fn alloc<Scalar, CS>(mut cs: CS, value: Option<bool>) -> Result<Self, SynthesisError>
69 where
70 Scalar: PrimeField,
71 CS: ConstraintSystem<Scalar>,
72 {
73 let var = cs.alloc(
74 || "boolean",
75 || {
76 if value.ok_or(SynthesisError::AssignmentMissing)? {
77 Ok(Scalar::ONE)
78 } else {
79 Ok(Scalar::ZERO)
80 }
81 },
82 )?;
83
84 cs.enforce(
87 || "boolean constraint",
88 |lc| lc + CS::one() - var,
89 |lc| lc + var,
90 |lc| lc,
91 );
92
93 Ok(AllocatedBit {
94 variable: var,
95 value,
96 })
97 }
98
99 pub fn xor<Scalar, CS>(mut cs: CS, a: &Self, b: &Self) -> Result<Self, SynthesisError>
102 where
103 Scalar: PrimeField,
104 CS: ConstraintSystem<Scalar>,
105 {
106 let mut result_value = None;
107
108 let result_var = cs.alloc(
109 || "xor result",
110 || {
111 if a.value.ok_or(SynthesisError::AssignmentMissing)?
112 ^ b.value.ok_or(SynthesisError::AssignmentMissing)?
113 {
114 result_value = Some(true);
115
116 Ok(Scalar::ONE)
117 } else {
118 result_value = Some(false);
119
120 Ok(Scalar::ZERO)
121 }
122 },
123 )?;
124
125 cs.enforce(
141 || "xor constraint",
142 |lc| lc + a.variable + a.variable,
143 |lc| lc + b.variable,
144 |lc| lc + a.variable + b.variable - result_var,
145 );
146
147 Ok(AllocatedBit {
148 variable: result_var,
149 value: result_value,
150 })
151 }
152
153 pub fn and<Scalar, CS>(mut cs: CS, a: &Self, b: &Self) -> Result<Self, SynthesisError>
156 where
157 Scalar: PrimeField,
158 CS: ConstraintSystem<Scalar>,
159 {
160 let mut result_value = None;
161
162 let result_var = cs.alloc(
163 || "and result",
164 || {
165 if a.value.ok_or(SynthesisError::AssignmentMissing)?
166 & b.value.ok_or(SynthesisError::AssignmentMissing)?
167 {
168 result_value = Some(true);
169
170 Ok(Scalar::ONE)
171 } else {
172 result_value = Some(false);
173
174 Ok(Scalar::ZERO)
175 }
176 },
177 )?;
178
179 cs.enforce(
182 || "and constraint",
183 |lc| lc + a.variable,
184 |lc| lc + b.variable,
185 |lc| lc + result_var,
186 );
187
188 Ok(AllocatedBit {
189 variable: result_var,
190 value: result_value,
191 })
192 }
193
194 pub fn and_not<Scalar, CS>(mut cs: CS, a: &Self, b: &Self) -> Result<Self, SynthesisError>
196 where
197 Scalar: PrimeField,
198 CS: ConstraintSystem<Scalar>,
199 {
200 let mut result_value = None;
201
202 let result_var = cs.alloc(
203 || "and not result",
204 || {
205 if a.value.ok_or(SynthesisError::AssignmentMissing)?
206 & !b.value.ok_or(SynthesisError::AssignmentMissing)?
207 {
208 result_value = Some(true);
209
210 Ok(Scalar::ONE)
211 } else {
212 result_value = Some(false);
213
214 Ok(Scalar::ZERO)
215 }
216 },
217 )?;
218
219 cs.enforce(
222 || "and not constraint",
223 |lc| lc + a.variable,
224 |lc| lc + CS::one() - b.variable,
225 |lc| lc + result_var,
226 );
227
228 Ok(AllocatedBit {
229 variable: result_var,
230 value: result_value,
231 })
232 }
233
234 pub fn nor<Scalar, CS>(mut cs: CS, a: &Self, b: &Self) -> Result<Self, SynthesisError>
236 where
237 Scalar: PrimeField,
238 CS: ConstraintSystem<Scalar>,
239 {
240 let mut result_value = None;
241
242 let result_var = cs.alloc(
243 || "nor result",
244 || {
245 if !a.value.ok_or(SynthesisError::AssignmentMissing)?
246 & !b.value.ok_or(SynthesisError::AssignmentMissing)?
247 {
248 result_value = Some(true);
249
250 Ok(Scalar::ONE)
251 } else {
252 result_value = Some(false);
253
254 Ok(Scalar::ZERO)
255 }
256 },
257 )?;
258
259 cs.enforce(
262 || "nor constraint",
263 |lc| lc + CS::one() - a.variable,
264 |lc| lc + CS::one() - b.variable,
265 |lc| lc + result_var,
266 );
267
268 Ok(AllocatedBit {
269 variable: result_var,
270 value: result_value,
271 })
272 }
273}
274
275pub fn u64_into_boolean_vec_le<Scalar: PrimeField, CS: ConstraintSystem<Scalar>>(
276 mut cs: CS,
277 value: Option<u64>,
278) -> Result<Vec<Boolean>, SynthesisError> {
279 let values = match value {
280 Some(ref value) => {
281 let mut tmp = Vec::with_capacity(64);
282
283 for i in 0..64 {
284 tmp.push(Some(*value >> i & 1 == 1));
285 }
286
287 tmp
288 }
289 None => vec![None; 64],
290 };
291
292 let bits = values
293 .into_iter()
294 .enumerate()
295 .map(|(i, b)| {
296 Ok(Boolean::from(AllocatedBit::alloc(
297 cs.namespace(|| format!("bit {}", i)),
298 b,
299 )?))
300 })
301 .collect::<Result<Vec<_>, SynthesisError>>()?;
302
303 Ok(bits)
304}
305
306pub fn field_into_boolean_vec_le<Scalar, CS>(
307 cs: CS,
308 value: Option<Scalar>,
309) -> Result<Vec<Boolean>, SynthesisError>
310where
311 Scalar: PrimeField,
312 Scalar: PrimeFieldBits,
313 CS: ConstraintSystem<Scalar>,
314{
315 let v = field_into_allocated_bits_le::<Scalar, CS>(cs, value)?;
316
317 Ok(v.into_iter().map(Boolean::from).collect())
318}
319
320pub fn field_into_allocated_bits_le<Scalar, CS>(
321 mut cs: CS,
322 value: Option<Scalar>,
323) -> Result<Vec<AllocatedBit>, SynthesisError>
324where
325 Scalar: PrimeField,
326 Scalar: PrimeFieldBits,
327 CS: ConstraintSystem<Scalar>,
328{
329 let values = match value {
331 Some(ref value) => {
332 let field_char = Scalar::char_le_bits();
333 let mut field_char = field_char.into_iter().rev();
334
335 let mut tmp = Vec::with_capacity(Scalar::NUM_BITS as usize);
336
337 let mut found_one = false;
338 for b in value.to_le_bits().into_iter().rev() {
339 found_one |= field_char.next().unwrap();
341 if !found_one {
342 continue;
343 }
344
345 tmp.push(Some(b));
346 }
347
348 assert_eq!(tmp.len(), Scalar::NUM_BITS as usize);
349
350 tmp
351 }
352 None => vec![None; Scalar::NUM_BITS as usize],
353 };
354
355 let bits = values
357 .into_iter()
358 .rev()
359 .enumerate()
360 .map(|(i, b)| AllocatedBit::alloc(cs.namespace(|| format!("bit {}", i)), b))
361 .collect::<Result<Vec<_>, SynthesisError>>()?;
362
363 Ok(bits)
364}
365
366#[derive(Clone, Debug)]
369pub enum Boolean {
370 Is(AllocatedBit),
372 Not(AllocatedBit),
374 Constant(bool),
376}
377
378impl Boolean {
379 pub fn is_constant(&self) -> bool {
380 matches!(*self, Boolean::Constant(_))
381 }
382
383 pub fn enforce_equal<Scalar, CS>(mut cs: CS, a: &Self, b: &Self) -> Result<(), SynthesisError>
384 where
385 Scalar: PrimeField,
386 CS: ConstraintSystem<Scalar>,
387 {
388 match (a, b) {
389 (&Boolean::Constant(a), &Boolean::Constant(b)) => {
390 if a == b {
391 Ok(())
392 } else {
393 Err(SynthesisError::Unsatisfiable)
394 }
395 }
396 (&Boolean::Constant(true), a) | (a, &Boolean::Constant(true)) => {
397 cs.enforce(
398 || "enforce equal to one",
399 |lc| lc,
400 |lc| lc,
401 |lc| lc + CS::one() - &a.lc(CS::one(), Scalar::ONE),
402 );
403
404 Ok(())
405 }
406 (&Boolean::Constant(false), a) | (a, &Boolean::Constant(false)) => {
407 cs.enforce(
408 || "enforce equal to zero",
409 |lc| lc,
410 |lc| lc,
411 |_| a.lc(CS::one(), Scalar::ONE),
412 );
413
414 Ok(())
415 }
416 (a, b) => {
417 cs.enforce(
418 || "enforce equal",
419 |lc| lc,
420 |lc| lc,
421 |_| a.lc(CS::one(), Scalar::ONE) - &b.lc(CS::one(), Scalar::ONE),
422 );
423
424 Ok(())
425 }
426 }
427 }
428
429 pub fn get_value(&self) -> Option<bool> {
430 match *self {
431 Boolean::Constant(c) => Some(c),
432 Boolean::Is(ref v) => v.get_value(),
433 Boolean::Not(ref v) => v.get_value().map(|b| !b),
434 }
435 }
436
437 pub fn lc<Scalar: PrimeField>(
438 &self,
439 one: Variable,
440 coeff: Scalar,
441 ) -> LinearCombination<Scalar> {
442 match *self {
443 Boolean::Constant(c) => {
444 if c {
445 LinearCombination::<Scalar>::zero() + (coeff, one)
446 } else {
447 LinearCombination::<Scalar>::zero()
448 }
449 }
450 Boolean::Is(ref v) => LinearCombination::<Scalar>::zero() + (coeff, v.get_variable()),
451 Boolean::Not(ref v) => {
452 LinearCombination::<Scalar>::zero() + (coeff, one) - (coeff, v.get_variable())
453 }
454 }
455 }
456
457 pub fn constant(b: bool) -> Self {
459 Boolean::Constant(b)
460 }
461
462 pub fn not(&self) -> Self {
464 match *self {
465 Boolean::Constant(c) => Boolean::Constant(!c),
466 Boolean::Is(ref v) => Boolean::Not(v.clone()),
467 Boolean::Not(ref v) => Boolean::Is(v.clone()),
468 }
469 }
470
471 pub fn xor<'a, Scalar, CS>(cs: CS, a: &'a Self, b: &'a Self) -> Result<Self, SynthesisError>
473 where
474 Scalar: PrimeField,
475 CS: ConstraintSystem<Scalar>,
476 {
477 match (a, b) {
478 (&Boolean::Constant(false), x) | (x, &Boolean::Constant(false)) => Ok(x.clone()),
479 (&Boolean::Constant(true), x) | (x, &Boolean::Constant(true)) => Ok(x.not()),
480 (is @ &Boolean::Is(_), not @ &Boolean::Not(_))
482 | (not @ &Boolean::Not(_), is @ &Boolean::Is(_)) => {
483 Ok(Boolean::xor(cs, is, ¬.not())?.not())
484 }
485 (&Boolean::Is(ref a), &Boolean::Is(ref b))
487 | (&Boolean::Not(ref a), &Boolean::Not(ref b)) => {
488 Ok(Boolean::Is(AllocatedBit::xor(cs, a, b)?))
489 }
490 }
491 }
492
493 pub fn and<'a, Scalar, CS>(cs: CS, a: &'a Self, b: &'a Self) -> Result<Self, SynthesisError>
495 where
496 Scalar: PrimeField,
497 CS: ConstraintSystem<Scalar>,
498 {
499 match (a, b) {
500 (&Boolean::Constant(false), _) | (_, &Boolean::Constant(false)) => {
502 Ok(Boolean::Constant(false))
503 }
504 (&Boolean::Constant(true), x) | (x, &Boolean::Constant(true)) => Ok(x.clone()),
506 (&Boolean::Is(ref is), &Boolean::Not(ref not))
508 | (&Boolean::Not(ref not), &Boolean::Is(ref is)) => {
509 Ok(Boolean::Is(AllocatedBit::and_not(cs, is, not)?))
510 }
511 (Boolean::Not(a), Boolean::Not(b)) => Ok(Boolean::Is(AllocatedBit::nor(cs, a, b)?)),
513 (Boolean::Is(a), Boolean::Is(b)) => Ok(Boolean::Is(AllocatedBit::and(cs, a, b)?)),
515 }
516 }
517
518 pub fn or<'a, Scalar, CS>(
520 mut cs: CS,
521 a: &'a Boolean,
522 b: &'a Boolean,
523 ) -> Result<Boolean, SynthesisError>
524 where
525 Scalar: PrimeField,
526 CS: ConstraintSystem<Scalar>,
527 {
528 Ok(Boolean::not(&Boolean::and(
529 cs.namespace(|| "not and (not a) (not b)"),
530 &Boolean::not(a),
531 &Boolean::not(b),
532 )?))
533 }
534
535 pub fn sha256_ch<'a, Scalar, CS>(
537 mut cs: CS,
538 a: &'a Self,
539 b: &'a Self,
540 c: &'a Self,
541 ) -> Result<Self, SynthesisError>
542 where
543 Scalar: PrimeField,
544 CS: ConstraintSystem<Scalar>,
545 {
546 let ch_value = match (a.get_value(), b.get_value(), c.get_value()) {
547 (Some(a), Some(b), Some(c)) => {
548 Some((a & b) ^ ((!a) & c))
550 }
551 _ => None,
552 };
553
554 match (a, b, c) {
555 (&Boolean::Constant(_), &Boolean::Constant(_), &Boolean::Constant(_)) => {
556 return Ok(Boolean::Constant(ch_value.expect("they're all constants")));
559 }
560 (&Boolean::Constant(false), _, c) => {
561 return Ok(c.clone());
568 }
569 (a, &Boolean::Constant(false), c) => {
570 return Boolean::and(cs, &a.not(), c);
575 }
576 (a, b, &Boolean::Constant(false)) => {
577 return Boolean::and(cs, a, b);
582 }
583 (a, b, &Boolean::Constant(true)) => {
584 return Ok(Boolean::and(cs, a, &b.not())?.not());
591 }
592 (a, &Boolean::Constant(true), c) => {
593 return Ok(Boolean::and(cs, &a.not(), &c.not())?.not());
600 }
601 (&Boolean::Constant(true), _, _) => {
602 }
608 (
609 &Boolean::Is(_) | &Boolean::Not(_),
610 &Boolean::Is(_) | &Boolean::Not(_),
611 &Boolean::Is(_) | &Boolean::Not(_),
612 ) => {}
613 }
614
615 let ch = cs.alloc(
616 || "ch",
617 || {
618 ch_value.ok_or(SynthesisError::AssignmentMissing).map(|v| {
619 if v {
620 Scalar::ONE
621 } else {
622 Scalar::ZERO
623 }
624 })
625 },
626 )?;
627
628 cs.enforce(
630 || "ch computation",
631 |_| b.lc(CS::one(), Scalar::ONE) - &c.lc(CS::one(), Scalar::ONE),
632 |_| a.lc(CS::one(), Scalar::ONE),
633 |lc| lc + ch - &c.lc(CS::one(), Scalar::ONE),
634 );
635
636 Ok(AllocatedBit {
637 value: ch_value,
638 variable: ch,
639 }
640 .into())
641 }
642
643 pub fn sha256_maj<'a, Scalar, CS>(
645 mut cs: CS,
646 a: &'a Self,
647 b: &'a Self,
648 c: &'a Self,
649 ) -> Result<Self, SynthesisError>
650 where
651 Scalar: PrimeField,
652 CS: ConstraintSystem<Scalar>,
653 {
654 let maj_value = match (a.get_value(), b.get_value(), c.get_value()) {
655 (Some(a), Some(b), Some(c)) => {
656 Some((a & b) ^ (a & c) ^ (b & c))
658 }
659 _ => None,
660 };
661
662 match (a, b, c) {
663 (&Boolean::Constant(_), &Boolean::Constant(_), &Boolean::Constant(_)) => {
664 return Ok(Boolean::Constant(maj_value.expect("they're all constants")));
667 }
668 (&Boolean::Constant(false), b, c) => {
669 return Boolean::and(cs, b, c);
674 }
675 (a, &Boolean::Constant(false), c) => {
676 return Boolean::and(cs, a, c);
681 }
682 (a, b, &Boolean::Constant(false)) => {
683 return Boolean::and(cs, a, b);
688 }
689 (a, b, &Boolean::Constant(true)) => {
690 return Ok(Boolean::and(cs, &a.not(), &b.not())?.not());
697 }
698 (a, &Boolean::Constant(true), c) => {
699 return Ok(Boolean::and(cs, &a.not(), &c.not())?.not());
704 }
705 (&Boolean::Constant(true), b, c) => {
706 return Ok(Boolean::and(cs, &b.not(), &c.not())?.not());
711 }
712 (
713 &Boolean::Is(_) | &Boolean::Not(_),
714 &Boolean::Is(_) | &Boolean::Not(_),
715 &Boolean::Is(_) | &Boolean::Not(_),
716 ) => {}
717 }
718
719 let maj = cs.alloc(
720 || "maj",
721 || {
722 maj_value.ok_or(SynthesisError::AssignmentMissing).map(|v| {
723 if v {
724 Scalar::ONE
725 } else {
726 Scalar::ZERO
727 }
728 })
729 },
730 )?;
731
732 let bc = Self::and(cs.namespace(|| "b and c"), b, c)?;
742
743 cs.enforce(
744 || "maj computation",
745 |_| {
746 bc.lc(CS::one(), Scalar::ONE) + &bc.lc(CS::one(), Scalar::ONE)
747 - &b.lc(CS::one(), Scalar::ONE)
748 - &c.lc(CS::one(), Scalar::ONE)
749 },
750 |_| a.lc(CS::one(), Scalar::ONE),
751 |_| bc.lc(CS::one(), Scalar::ONE) - maj,
752 );
753
754 Ok(AllocatedBit {
755 value: maj_value,
756 variable: maj,
757 }
758 .into())
759 }
760}
761
762impl From<AllocatedBit> for Boolean {
763 fn from(b: AllocatedBit) -> Boolean {
764 Boolean::Is(b)
765 }
766}
767
768#[cfg(test)]
769mod test {
770 use super::{field_into_allocated_bits_le, u64_into_boolean_vec_le, AllocatedBit, Boolean};
771 use crate::test_cs::*;
772 use crate::ConstraintSystem;
773 use blstrs::Scalar as Fr;
774 use ff::{Field, PrimeField};
775
776 #[test]
777 fn test_allocated_bit() {
778 let mut cs = TestConstraintSystem::<Fr>::new();
779
780 AllocatedBit::alloc(&mut cs, Some(true)).unwrap();
781 assert!(cs.get("boolean") == Fr::ONE);
782 assert!(cs.is_satisfied());
783 cs.set("boolean", Fr::ZERO);
784 assert!(cs.is_satisfied());
785 cs.set("boolean", Fr::from(2u64));
786 assert!(!cs.is_satisfied());
787 assert!(cs.which_is_unsatisfied() == Some("boolean constraint"));
788 }
789
790 #[test]
791 fn test_xor() {
792 for a_val in [false, true].iter() {
793 for b_val in [false, true].iter() {
794 let mut cs = TestConstraintSystem::<Fr>::new();
795 let a = AllocatedBit::alloc(cs.namespace(|| "a"), Some(*a_val)).unwrap();
796 let b = AllocatedBit::alloc(cs.namespace(|| "b"), Some(*b_val)).unwrap();
797 let c = AllocatedBit::xor(&mut cs, &a, &b).unwrap();
798 assert_eq!(c.value.unwrap(), *a_val ^ *b_val);
799
800 assert!(cs.is_satisfied());
801 assert!(cs.get("a/boolean") == if *a_val { Field::ONE } else { Field::ZERO });
802 assert!(cs.get("b/boolean") == if *b_val { Field::ONE } else { Field::ZERO });
803 assert!(
804 cs.get("xor result")
805 == if *a_val ^ *b_val {
806 Field::ONE
807 } else {
808 Field::ZERO
809 }
810 );
811
812 cs.set(
814 "xor result",
815 if *a_val ^ *b_val {
816 Field::ZERO
817 } else {
818 Field::ONE
819 },
820 );
821 assert!(!cs.is_satisfied());
822 }
823 }
824 }
825
826 #[test]
827 fn test_and() {
828 for a_val in [false, true].iter() {
829 for b_val in [false, true].iter() {
830 let mut cs = TestConstraintSystem::<Fr>::new();
831 let a = AllocatedBit::alloc(cs.namespace(|| "a"), Some(*a_val)).unwrap();
832 let b = AllocatedBit::alloc(cs.namespace(|| "b"), Some(*b_val)).unwrap();
833 let c = AllocatedBit::and(&mut cs, &a, &b).unwrap();
834 assert_eq!(c.value.unwrap(), *a_val & *b_val);
835
836 assert!(cs.is_satisfied());
837 assert!(cs.get("a/boolean") == if *a_val { Field::ONE } else { Field::ZERO });
838 assert!(cs.get("b/boolean") == if *b_val { Field::ONE } else { Field::ZERO });
839 assert!(
840 cs.get("and result")
841 == if *a_val & *b_val {
842 Field::ONE
843 } else {
844 Field::ZERO
845 }
846 );
847
848 cs.set(
850 "and result",
851 if *a_val & *b_val {
852 Field::ZERO
853 } else {
854 Field::ONE
855 },
856 );
857 assert!(!cs.is_satisfied());
858 }
859 }
860 }
861
862 #[test]
863 fn test_and_not() {
864 for a_val in [false, true].iter() {
865 for b_val in [false, true].iter() {
866 let mut cs = TestConstraintSystem::<Fr>::new();
867 let a = AllocatedBit::alloc(cs.namespace(|| "a"), Some(*a_val)).unwrap();
868 let b = AllocatedBit::alloc(cs.namespace(|| "b"), Some(*b_val)).unwrap();
869 let c = AllocatedBit::and_not(&mut cs, &a, &b).unwrap();
870 assert_eq!(c.value.unwrap(), *a_val & !*b_val);
871
872 assert!(cs.is_satisfied());
873 assert!(cs.get("a/boolean") == if *a_val { Field::ONE } else { Field::ZERO });
874 assert!(cs.get("b/boolean") == if *b_val { Field::ONE } else { Field::ZERO });
875 assert!(
876 cs.get("and not result")
877 == if *a_val & !*b_val {
878 Field::ONE
879 } else {
880 Field::ZERO
881 }
882 );
883
884 cs.set(
886 "and not result",
887 if *a_val & !*b_val {
888 Field::ZERO
889 } else {
890 Field::ONE
891 },
892 );
893 assert!(!cs.is_satisfied());
894 }
895 }
896 }
897
898 #[test]
899 fn test_nor() {
900 for a_val in [false, true].iter() {
901 for b_val in [false, true].iter() {
902 let mut cs = TestConstraintSystem::<Fr>::new();
903 let a = AllocatedBit::alloc(cs.namespace(|| "a"), Some(*a_val)).unwrap();
904 let b = AllocatedBit::alloc(cs.namespace(|| "b"), Some(*b_val)).unwrap();
905 let c = AllocatedBit::nor(&mut cs, &a, &b).unwrap();
906 assert_eq!(c.value.unwrap(), !*a_val & !*b_val);
907
908 assert!(cs.is_satisfied());
909 assert!(cs.get("a/boolean") == if *a_val { Field::ONE } else { Field::ZERO });
910 assert!(cs.get("b/boolean") == if *b_val { Field::ONE } else { Field::ZERO });
911 assert!(
912 cs.get("nor result")
913 == if !*a_val & !*b_val {
914 Field::ONE
915 } else {
916 Field::ZERO
917 }
918 );
919
920 cs.set(
922 "nor result",
923 if !*a_val & !*b_val {
924 Field::ZERO
925 } else {
926 Field::ONE
927 },
928 );
929 assert!(!cs.is_satisfied());
930 }
931 }
932 }
933
934 #[test]
935 fn test_enforce_equal() {
936 for a_bool in [false, true].iter().cloned() {
937 for b_bool in [false, true].iter().cloned() {
938 for a_neg in [false, true].iter().cloned() {
939 for b_neg in [false, true].iter().cloned() {
940 {
941 let mut cs = TestConstraintSystem::<Fr>::new();
942
943 let mut a = Boolean::from(
944 AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_bool)).unwrap(),
945 );
946 let mut b = Boolean::from(
947 AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_bool)).unwrap(),
948 );
949
950 if a_neg {
951 a = a.not();
952 }
953 if b_neg {
954 b = b.not();
955 }
956
957 Boolean::enforce_equal(&mut cs, &a, &b).unwrap();
958
959 assert_eq!(cs.is_satisfied(), (a_bool ^ a_neg) == (b_bool ^ b_neg));
960 }
961 {
962 let mut cs = TestConstraintSystem::<Fr>::new();
963
964 let mut a = Boolean::Constant(a_bool);
965 let mut b = Boolean::from(
966 AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_bool)).unwrap(),
967 );
968
969 if a_neg {
970 a = a.not();
971 }
972 if b_neg {
973 b = b.not();
974 }
975
976 Boolean::enforce_equal(&mut cs, &a, &b).unwrap();
977
978 assert_eq!(cs.is_satisfied(), (a_bool ^ a_neg) == (b_bool ^ b_neg));
979 }
980 {
981 let mut cs = TestConstraintSystem::<Fr>::new();
982
983 let mut a = Boolean::from(
984 AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_bool)).unwrap(),
985 );
986 let mut b = Boolean::Constant(b_bool);
987
988 if a_neg {
989 a = a.not();
990 }
991 if b_neg {
992 b = b.not();
993 }
994
995 Boolean::enforce_equal(&mut cs, &a, &b).unwrap();
996
997 assert_eq!(cs.is_satisfied(), (a_bool ^ a_neg) == (b_bool ^ b_neg));
998 }
999 {
1000 let mut cs = TestConstraintSystem::<Fr>::new();
1001
1002 let mut a = Boolean::Constant(a_bool);
1003 let mut b = Boolean::Constant(b_bool);
1004
1005 if a_neg {
1006 a = a.not();
1007 }
1008 if b_neg {
1009 b = b.not();
1010 }
1011
1012 let result = Boolean::enforce_equal(&mut cs, &a, &b);
1013
1014 if (a_bool ^ a_neg) == (b_bool ^ b_neg) {
1015 assert!(result.is_ok());
1016 assert!(cs.is_satisfied());
1017 } else {
1018 assert!(result.is_err());
1019 }
1020 }
1021 }
1022 }
1023 }
1024 }
1025 }
1026
1027 #[test]
1028 fn test_boolean_negation() {
1029 let mut cs = TestConstraintSystem::<Fr>::new();
1030
1031 let mut b = Boolean::from(AllocatedBit::alloc(&mut cs, Some(true)).unwrap());
1032
1033 match b {
1034 Boolean::Is(_) => {}
1035 _ => panic!("unexpected value"),
1036 }
1037
1038 b = b.not();
1039
1040 match b {
1041 Boolean::Not(_) => {}
1042 _ => panic!("unexpected value"),
1043 }
1044
1045 b = b.not();
1046
1047 match b {
1048 Boolean::Is(_) => {}
1049 _ => panic!("unexpected value"),
1050 }
1051
1052 b = Boolean::constant(true);
1053
1054 match b {
1055 Boolean::Constant(true) => {}
1056 _ => panic!("unexpected value"),
1057 }
1058
1059 b = b.not();
1060
1061 match b {
1062 Boolean::Constant(false) => {}
1063 _ => panic!("unexpected value"),
1064 }
1065
1066 b = b.not();
1067
1068 match b {
1069 Boolean::Constant(true) => {}
1070 _ => panic!("unexpected value"),
1071 }
1072 }
1073
1074 #[derive(Copy, Clone, Debug)]
1075 enum OperandType {
1076 True,
1077 False,
1078 AllocatedTrue,
1079 AllocatedFalse,
1080 NegatedAllocatedTrue,
1081 NegatedAllocatedFalse,
1082 }
1083
1084 impl OperandType {
1085 fn is_constant(&self) -> bool {
1086 match *self {
1087 OperandType::True => true,
1088 OperandType::False => true,
1089 OperandType::AllocatedTrue => false,
1090 OperandType::AllocatedFalse => false,
1091 OperandType::NegatedAllocatedTrue => false,
1092 OperandType::NegatedAllocatedFalse => false,
1093 }
1094 }
1095
1096 fn val(&self) -> bool {
1097 match *self {
1098 OperandType::True => true,
1099 OperandType::False => false,
1100 OperandType::AllocatedTrue => true,
1101 OperandType::AllocatedFalse => false,
1102 OperandType::NegatedAllocatedTrue => false,
1103 OperandType::NegatedAllocatedFalse => true,
1104 }
1105 }
1106 }
1107
1108 #[test]
1109 fn test_boolean_xor() {
1110 let variants = [
1111 OperandType::True,
1112 OperandType::False,
1113 OperandType::AllocatedTrue,
1114 OperandType::AllocatedFalse,
1115 OperandType::NegatedAllocatedTrue,
1116 OperandType::NegatedAllocatedFalse,
1117 ];
1118
1119 for first_operand in variants.iter().cloned() {
1120 for second_operand in variants.iter().cloned() {
1121 let mut cs = TestConstraintSystem::<Fr>::new();
1122
1123 let a;
1124 let b;
1125
1126 {
1127 let mut dyn_construct = |operand, name| {
1128 let cs = cs.namespace(|| name);
1129
1130 match operand {
1131 OperandType::True => Boolean::constant(true),
1132 OperandType::False => Boolean::constant(false),
1133 OperandType::AllocatedTrue => {
1134 Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap())
1135 }
1136 OperandType::AllocatedFalse => {
1137 Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap())
1138 }
1139 OperandType::NegatedAllocatedTrue => {
1140 Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not()
1141 }
1142 OperandType::NegatedAllocatedFalse => {
1143 Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not()
1144 }
1145 }
1146 };
1147
1148 a = dyn_construct(first_operand, "a");
1149 b = dyn_construct(second_operand, "b");
1150 }
1151
1152 let c = Boolean::xor(&mut cs, &a, &b).unwrap();
1153
1154 assert!(cs.is_satisfied());
1155
1156 match (first_operand, second_operand, c) {
1157 (OperandType::True, OperandType::True, Boolean::Constant(false)) => {}
1158 (OperandType::True, OperandType::False, Boolean::Constant(true)) => {}
1159 (OperandType::True, OperandType::AllocatedTrue, Boolean::Not(_)) => {}
1160 (OperandType::True, OperandType::AllocatedFalse, Boolean::Not(_)) => {}
1161 (OperandType::True, OperandType::NegatedAllocatedTrue, Boolean::Is(_)) => {}
1162 (OperandType::True, OperandType::NegatedAllocatedFalse, Boolean::Is(_)) => {}
1163
1164 (OperandType::False, OperandType::True, Boolean::Constant(true)) => {}
1165 (OperandType::False, OperandType::False, Boolean::Constant(false)) => {}
1166 (OperandType::False, OperandType::AllocatedTrue, Boolean::Is(_)) => {}
1167 (OperandType::False, OperandType::AllocatedFalse, Boolean::Is(_)) => {}
1168 (OperandType::False, OperandType::NegatedAllocatedTrue, Boolean::Not(_)) => {}
1169 (OperandType::False, OperandType::NegatedAllocatedFalse, Boolean::Not(_)) => {}
1170
1171 (OperandType::AllocatedTrue, OperandType::True, Boolean::Not(_)) => {}
1172 (OperandType::AllocatedTrue, OperandType::False, Boolean::Is(_)) => {}
1173 (
1174 OperandType::AllocatedTrue,
1175 OperandType::AllocatedTrue,
1176 Boolean::Is(ref v),
1177 ) => {
1178 assert!(cs.get("xor result") == Field::ZERO);
1179 assert_eq!(v.value, Some(false));
1180 }
1181 (
1182 OperandType::AllocatedTrue,
1183 OperandType::AllocatedFalse,
1184 Boolean::Is(ref v),
1185 ) => {
1186 assert!(cs.get("xor result") == Field::ONE);
1187 assert_eq!(v.value, Some(true));
1188 }
1189 (
1190 OperandType::AllocatedTrue,
1191 OperandType::NegatedAllocatedTrue,
1192 Boolean::Not(ref v),
1193 ) => {
1194 assert!(cs.get("xor result") == Field::ZERO);
1195 assert_eq!(v.value, Some(false));
1196 }
1197 (
1198 OperandType::AllocatedTrue,
1199 OperandType::NegatedAllocatedFalse,
1200 Boolean::Not(ref v),
1201 ) => {
1202 assert!(cs.get("xor result") == Field::ONE);
1203 assert_eq!(v.value, Some(true));
1204 }
1205
1206 (OperandType::AllocatedFalse, OperandType::True, Boolean::Not(_)) => {}
1207 (OperandType::AllocatedFalse, OperandType::False, Boolean::Is(_)) => {}
1208 (
1209 OperandType::AllocatedFalse,
1210 OperandType::AllocatedTrue,
1211 Boolean::Is(ref v),
1212 ) => {
1213 assert!(cs.get("xor result") == Field::ONE);
1214 assert_eq!(v.value, Some(true));
1215 }
1216 (
1217 OperandType::AllocatedFalse,
1218 OperandType::AllocatedFalse,
1219 Boolean::Is(ref v),
1220 ) => {
1221 assert!(cs.get("xor result") == Field::ZERO);
1222 assert_eq!(v.value, Some(false));
1223 }
1224 (
1225 OperandType::AllocatedFalse,
1226 OperandType::NegatedAllocatedTrue,
1227 Boolean::Not(ref v),
1228 ) => {
1229 assert!(cs.get("xor result") == Field::ONE);
1230 assert_eq!(v.value, Some(true));
1231 }
1232 (
1233 OperandType::AllocatedFalse,
1234 OperandType::NegatedAllocatedFalse,
1235 Boolean::Not(ref v),
1236 ) => {
1237 assert!(cs.get("xor result") == Field::ZERO);
1238 assert_eq!(v.value, Some(false));
1239 }
1240
1241 (OperandType::NegatedAllocatedTrue, OperandType::True, Boolean::Is(_)) => {}
1242 (OperandType::NegatedAllocatedTrue, OperandType::False, Boolean::Not(_)) => {}
1243 (
1244 OperandType::NegatedAllocatedTrue,
1245 OperandType::AllocatedTrue,
1246 Boolean::Not(ref v),
1247 ) => {
1248 assert!(cs.get("xor result") == Field::ZERO);
1249 assert_eq!(v.value, Some(false));
1250 }
1251 (
1252 OperandType::NegatedAllocatedTrue,
1253 OperandType::AllocatedFalse,
1254 Boolean::Not(ref v),
1255 ) => {
1256 assert!(cs.get("xor result") == Field::ONE);
1257 assert_eq!(v.value, Some(true));
1258 }
1259 (
1260 OperandType::NegatedAllocatedTrue,
1261 OperandType::NegatedAllocatedTrue,
1262 Boolean::Is(ref v),
1263 ) => {
1264 assert!(cs.get("xor result") == Field::ZERO);
1265 assert_eq!(v.value, Some(false));
1266 }
1267 (
1268 OperandType::NegatedAllocatedTrue,
1269 OperandType::NegatedAllocatedFalse,
1270 Boolean::Is(ref v),
1271 ) => {
1272 assert!(cs.get("xor result") == Field::ONE);
1273 assert_eq!(v.value, Some(true));
1274 }
1275
1276 (OperandType::NegatedAllocatedFalse, OperandType::True, Boolean::Is(_)) => {}
1277 (OperandType::NegatedAllocatedFalse, OperandType::False, Boolean::Not(_)) => {}
1278 (
1279 OperandType::NegatedAllocatedFalse,
1280 OperandType::AllocatedTrue,
1281 Boolean::Not(ref v),
1282 ) => {
1283 assert!(cs.get("xor result") == Field::ONE);
1284 assert_eq!(v.value, Some(true));
1285 }
1286 (
1287 OperandType::NegatedAllocatedFalse,
1288 OperandType::AllocatedFalse,
1289 Boolean::Not(ref v),
1290 ) => {
1291 assert!(cs.get("xor result") == Field::ZERO);
1292 assert_eq!(v.value, Some(false));
1293 }
1294 (
1295 OperandType::NegatedAllocatedFalse,
1296 OperandType::NegatedAllocatedTrue,
1297 Boolean::Is(ref v),
1298 ) => {
1299 assert!(cs.get("xor result") == Field::ONE);
1300 assert_eq!(v.value, Some(true));
1301 }
1302 (
1303 OperandType::NegatedAllocatedFalse,
1304 OperandType::NegatedAllocatedFalse,
1305 Boolean::Is(ref v),
1306 ) => {
1307 assert!(cs.get("xor result") == Field::ZERO);
1308 assert_eq!(v.value, Some(false));
1309 }
1310
1311 _ => panic!("this should never be encountered"),
1312 }
1313 }
1314 }
1315 }
1316
1317 #[test]
1318 fn test_boolean_and() {
1319 let variants = [
1320 OperandType::True,
1321 OperandType::False,
1322 OperandType::AllocatedTrue,
1323 OperandType::AllocatedFalse,
1324 OperandType::NegatedAllocatedTrue,
1325 OperandType::NegatedAllocatedFalse,
1326 ];
1327
1328 for first_operand in variants.iter().cloned() {
1329 for second_operand in variants.iter().cloned() {
1330 let mut cs = TestConstraintSystem::<Fr>::new();
1331
1332 let a;
1333 let b;
1334
1335 {
1336 let mut dyn_construct = |operand, name| {
1337 let cs = cs.namespace(|| name);
1338
1339 match operand {
1340 OperandType::True => Boolean::constant(true),
1341 OperandType::False => Boolean::constant(false),
1342 OperandType::AllocatedTrue => {
1343 Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap())
1344 }
1345 OperandType::AllocatedFalse => {
1346 Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap())
1347 }
1348 OperandType::NegatedAllocatedTrue => {
1349 Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not()
1350 }
1351 OperandType::NegatedAllocatedFalse => {
1352 Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not()
1353 }
1354 }
1355 };
1356
1357 a = dyn_construct(first_operand, "a");
1358 b = dyn_construct(second_operand, "b");
1359 }
1360
1361 let c = Boolean::and(&mut cs, &a, &b).unwrap();
1362
1363 assert!(cs.is_satisfied());
1364
1365 match (first_operand, second_operand, c) {
1366 (OperandType::True, OperandType::True, Boolean::Constant(true)) => {}
1367 (OperandType::True, OperandType::False, Boolean::Constant(false)) => {}
1368 (OperandType::True, OperandType::AllocatedTrue, Boolean::Is(_)) => {}
1369 (OperandType::True, OperandType::AllocatedFalse, Boolean::Is(_)) => {}
1370 (OperandType::True, OperandType::NegatedAllocatedTrue, Boolean::Not(_)) => {}
1371 (OperandType::True, OperandType::NegatedAllocatedFalse, Boolean::Not(_)) => {}
1372
1373 (OperandType::False, OperandType::True, Boolean::Constant(false)) => {}
1374 (OperandType::False, OperandType::False, Boolean::Constant(false)) => {}
1375 (OperandType::False, OperandType::AllocatedTrue, Boolean::Constant(false)) => {}
1376 (OperandType::False, OperandType::AllocatedFalse, Boolean::Constant(false)) => {
1377 }
1378 (
1379 OperandType::False,
1380 OperandType::NegatedAllocatedTrue,
1381 Boolean::Constant(false),
1382 ) => {}
1383 (
1384 OperandType::False,
1385 OperandType::NegatedAllocatedFalse,
1386 Boolean::Constant(false),
1387 ) => {}
1388
1389 (OperandType::AllocatedTrue, OperandType::True, Boolean::Is(_)) => {}
1390 (OperandType::AllocatedTrue, OperandType::False, Boolean::Constant(false)) => {}
1391 (
1392 OperandType::AllocatedTrue,
1393 OperandType::AllocatedTrue,
1394 Boolean::Is(ref v),
1395 ) => {
1396 assert!(cs.get("and result") == Field::ONE);
1397 assert_eq!(v.value, Some(true));
1398 }
1399 (
1400 OperandType::AllocatedTrue,
1401 OperandType::AllocatedFalse,
1402 Boolean::Is(ref v),
1403 ) => {
1404 assert!(cs.get("and result") == Field::ZERO);
1405 assert_eq!(v.value, Some(false));
1406 }
1407 (
1408 OperandType::AllocatedTrue,
1409 OperandType::NegatedAllocatedTrue,
1410 Boolean::Is(ref v),
1411 ) => {
1412 assert!(cs.get("and not result") == Field::ZERO);
1413 assert_eq!(v.value, Some(false));
1414 }
1415 (
1416 OperandType::AllocatedTrue,
1417 OperandType::NegatedAllocatedFalse,
1418 Boolean::Is(ref v),
1419 ) => {
1420 assert!(cs.get("and not result") == Field::ONE);
1421 assert_eq!(v.value, Some(true));
1422 }
1423
1424 (OperandType::AllocatedFalse, OperandType::True, Boolean::Is(_)) => {}
1425 (OperandType::AllocatedFalse, OperandType::False, Boolean::Constant(false)) => {
1426 }
1427 (
1428 OperandType::AllocatedFalse,
1429 OperandType::AllocatedTrue,
1430 Boolean::Is(ref v),
1431 ) => {
1432 assert!(cs.get("and result") == Field::ZERO);
1433 assert_eq!(v.value, Some(false));
1434 }
1435 (
1436 OperandType::AllocatedFalse,
1437 OperandType::AllocatedFalse,
1438 Boolean::Is(ref v),
1439 ) => {
1440 assert!(cs.get("and result") == Field::ZERO);
1441 assert_eq!(v.value, Some(false));
1442 }
1443 (
1444 OperandType::AllocatedFalse,
1445 OperandType::NegatedAllocatedTrue,
1446 Boolean::Is(ref v),
1447 ) => {
1448 assert!(cs.get("and not result") == Field::ZERO);
1449 assert_eq!(v.value, Some(false));
1450 }
1451 (
1452 OperandType::AllocatedFalse,
1453 OperandType::NegatedAllocatedFalse,
1454 Boolean::Is(ref v),
1455 ) => {
1456 assert!(cs.get("and not result") == Field::ZERO);
1457 assert_eq!(v.value, Some(false));
1458 }
1459
1460 (OperandType::NegatedAllocatedTrue, OperandType::True, Boolean::Not(_)) => {}
1461 (
1462 OperandType::NegatedAllocatedTrue,
1463 OperandType::False,
1464 Boolean::Constant(false),
1465 ) => {}
1466 (
1467 OperandType::NegatedAllocatedTrue,
1468 OperandType::AllocatedTrue,
1469 Boolean::Is(ref v),
1470 ) => {
1471 assert!(cs.get("and not result") == Field::ZERO);
1472 assert_eq!(v.value, Some(false));
1473 }
1474 (
1475 OperandType::NegatedAllocatedTrue,
1476 OperandType::AllocatedFalse,
1477 Boolean::Is(ref v),
1478 ) => {
1479 assert!(cs.get("and not result") == Field::ZERO);
1480 assert_eq!(v.value, Some(false));
1481 }
1482 (
1483 OperandType::NegatedAllocatedTrue,
1484 OperandType::NegatedAllocatedTrue,
1485 Boolean::Is(ref v),
1486 ) => {
1487 assert!(cs.get("nor result") == Field::ZERO);
1488 assert_eq!(v.value, Some(false));
1489 }
1490 (
1491 OperandType::NegatedAllocatedTrue,
1492 OperandType::NegatedAllocatedFalse,
1493 Boolean::Is(ref v),
1494 ) => {
1495 assert!(cs.get("nor result") == Field::ZERO);
1496 assert_eq!(v.value, Some(false));
1497 }
1498
1499 (OperandType::NegatedAllocatedFalse, OperandType::True, Boolean::Not(_)) => {}
1500 (
1501 OperandType::NegatedAllocatedFalse,
1502 OperandType::False,
1503 Boolean::Constant(false),
1504 ) => {}
1505 (
1506 OperandType::NegatedAllocatedFalse,
1507 OperandType::AllocatedTrue,
1508 Boolean::Is(ref v),
1509 ) => {
1510 assert!(cs.get("and not result") == Field::ONE);
1511 assert_eq!(v.value, Some(true));
1512 }
1513 (
1514 OperandType::NegatedAllocatedFalse,
1515 OperandType::AllocatedFalse,
1516 Boolean::Is(ref v),
1517 ) => {
1518 assert!(cs.get("and not result") == Field::ZERO);
1519 assert_eq!(v.value, Some(false));
1520 }
1521 (
1522 OperandType::NegatedAllocatedFalse,
1523 OperandType::NegatedAllocatedTrue,
1524 Boolean::Is(ref v),
1525 ) => {
1526 assert!(cs.get("nor result") == Field::ZERO);
1527 assert_eq!(v.value, Some(false));
1528 }
1529 (
1530 OperandType::NegatedAllocatedFalse,
1531 OperandType::NegatedAllocatedFalse,
1532 Boolean::Is(ref v),
1533 ) => {
1534 assert!(cs.get("nor result") == Field::ONE);
1535 assert_eq!(v.value, Some(true));
1536 }
1537
1538 _ => {
1539 panic!(
1540 "unexpected behavior at {:?} AND {:?}",
1541 first_operand, second_operand
1542 );
1543 }
1544 }
1545 }
1546 }
1547 }
1548
1549 #[test]
1550 fn test_boolean_or() {
1551 let variants = [
1552 OperandType::True,
1553 OperandType::False,
1554 OperandType::AllocatedTrue,
1555 OperandType::AllocatedFalse,
1556 OperandType::NegatedAllocatedTrue,
1557 OperandType::NegatedAllocatedFalse,
1558 ];
1559
1560 for first_operand in variants.iter().cloned() {
1561 for second_operand in variants.iter().cloned() {
1562 let mut cs = TestConstraintSystem::<Fr>::new();
1563
1564 let a;
1565 let b;
1566
1567 {
1568 let mut dyn_construct = |operand, name| {
1569 let cs = cs.namespace(|| name);
1570
1571 match operand {
1572 OperandType::True => Boolean::constant(true),
1573 OperandType::False => Boolean::constant(false),
1574 OperandType::AllocatedTrue => {
1575 Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap())
1576 }
1577 OperandType::AllocatedFalse => {
1578 Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap())
1579 }
1580 OperandType::NegatedAllocatedTrue => {
1581 Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not()
1582 }
1583 OperandType::NegatedAllocatedFalse => {
1584 Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not()
1585 }
1586 }
1587 };
1588
1589 a = dyn_construct(first_operand, "a");
1590 b = dyn_construct(second_operand, "b");
1591 }
1592
1593 let c = Boolean::or(&mut cs, &a, &b).unwrap();
1594
1595 assert!(cs.is_satisfied());
1596
1597 match (first_operand, second_operand, c.clone()) {
1598 (OperandType::True, OperandType::True, Boolean::Constant(true)) => {}
1599 (OperandType::True, OperandType::False, Boolean::Constant(true)) => {}
1600 (OperandType::True, OperandType::AllocatedTrue, Boolean::Constant(true)) => {}
1601 (OperandType::True, OperandType::AllocatedFalse, Boolean::Constant(true)) => {}
1602 (
1603 OperandType::True,
1604 OperandType::NegatedAllocatedTrue,
1605 Boolean::Constant(true),
1606 ) => {}
1607 (
1608 OperandType::True,
1609 OperandType::NegatedAllocatedFalse,
1610 Boolean::Constant(true),
1611 ) => {}
1612
1613 (OperandType::False, OperandType::True, Boolean::Constant(true)) => {}
1614 (OperandType::False, OperandType::False, Boolean::Constant(false)) => {}
1615 (OperandType::False, OperandType::AllocatedTrue, Boolean::Is(_)) => {}
1616 (OperandType::False, OperandType::AllocatedFalse, Boolean::Is(_)) => {}
1617 (OperandType::False, OperandType::NegatedAllocatedTrue, Boolean::Not(_)) => {}
1618 (OperandType::False, OperandType::NegatedAllocatedFalse, Boolean::Not(_)) => {}
1619
1620 (OperandType::AllocatedTrue, OperandType::True, Boolean::Constant(true)) => {}
1621 (OperandType::AllocatedTrue, OperandType::False, Boolean::Is(_)) => {}
1622 (
1623 OperandType::AllocatedTrue,
1624 OperandType::AllocatedTrue,
1625 Boolean::Not(ref v),
1626 ) => {
1627 assert!(cs.get("not and (not a) (not b)/nor result") == Field::ZERO);
1628 assert_eq!(v.get_value(), Some(false));
1629 }
1630 (
1631 OperandType::AllocatedTrue,
1632 OperandType::AllocatedFalse,
1633 Boolean::Not(ref v),
1634 ) => {
1635 assert!(cs.get("not and (not a) (not b)/nor result") == Field::ZERO);
1636 assert_eq!(v.get_value(), Some(false));
1637 }
1638 (
1639 OperandType::AllocatedTrue,
1640 OperandType::NegatedAllocatedTrue,
1641 Boolean::Not(ref v),
1642 ) => {
1643 assert!(cs.get("not and (not a) (not b)/and not result") == Field::ZERO);
1644 assert_eq!(v.get_value(), Some(false));
1645 }
1646 (
1647 OperandType::AllocatedTrue,
1648 OperandType::NegatedAllocatedFalse,
1649 Boolean::Not(ref v),
1650 ) => {
1651 assert!(cs.get("not and (not a) (not b)/and not result") == Field::ZERO);
1652 assert_eq!(v.get_value(), Some(false));
1653 }
1654
1655 (OperandType::AllocatedFalse, OperandType::True, Boolean::Constant(true)) => {}
1656 (OperandType::AllocatedFalse, OperandType::False, Boolean::Is(_)) => {}
1657 (
1658 OperandType::AllocatedFalse,
1659 OperandType::AllocatedTrue,
1660 Boolean::Not(ref v),
1661 ) => {
1662 assert!(cs.get("not and (not a) (not b)/nor result") == Field::ZERO);
1663 assert_eq!(v.get_value(), Some(false));
1664 }
1665 (
1666 OperandType::AllocatedFalse,
1667 OperandType::AllocatedFalse,
1668 Boolean::Not(ref v),
1669 ) => {
1670 assert!(cs.get("not and (not a) (not b)/nor result") == Field::ONE);
1671 assert_eq!(v.get_value(), Some(true));
1672 }
1673 (
1674 OperandType::AllocatedFalse,
1675 OperandType::NegatedAllocatedTrue,
1676 Boolean::Not(ref v),
1677 ) => {
1678 assert!(cs.get("not and (not a) (not b)/and not result") == Field::ONE);
1679 assert_eq!(v.get_value(), Some(true));
1680 }
1681 (
1682 OperandType::AllocatedFalse,
1683 OperandType::NegatedAllocatedFalse,
1684 Boolean::Not(ref v),
1685 ) => {
1686 assert!(cs.get("not and (not a) (not b)/and not result") == Field::ZERO);
1687 assert_eq!(v.get_value(), Some(false));
1688 }
1689
1690 (
1691 OperandType::NegatedAllocatedTrue,
1692 OperandType::True,
1693 Boolean::Constant(true),
1694 ) => {}
1695 (OperandType::NegatedAllocatedTrue, OperandType::False, Boolean::Not(_)) => {}
1696 (
1697 OperandType::NegatedAllocatedTrue,
1698 OperandType::AllocatedTrue,
1699 Boolean::Not(ref v),
1700 ) => {
1701 assert!(cs.get("not and (not a) (not b)/and not result") == Field::ZERO);
1702 assert_eq!(v.get_value(), Some(false));
1703 }
1704 (
1705 OperandType::NegatedAllocatedTrue,
1706 OperandType::AllocatedFalse,
1707 Boolean::Not(ref v),
1708 ) => {
1709 assert!(cs.get("not and (not a) (not b)/and not result") == Field::ONE);
1710 assert_eq!(v.get_value(), Some(true));
1711 }
1712 (
1713 OperandType::NegatedAllocatedTrue,
1714 OperandType::NegatedAllocatedTrue,
1715 Boolean::Not(ref v),
1716 ) => {
1717 assert!(cs.get("not and (not a) (not b)/and result") == Field::ONE);
1718 assert_eq!(v.get_value(), Some(true));
1719 }
1720 (
1721 OperandType::NegatedAllocatedTrue,
1722 OperandType::NegatedAllocatedFalse,
1723 Boolean::Not(ref v),
1724 ) => {
1725 assert!(cs.get("not and (not a) (not b)/and result") == Field::ZERO);
1726 assert_eq!(v.get_value(), Some(false));
1727 }
1728
1729 (
1730 OperandType::NegatedAllocatedFalse,
1731 OperandType::True,
1732 Boolean::Constant(true),
1733 ) => {}
1734 (OperandType::NegatedAllocatedFalse, OperandType::False, Boolean::Not(_)) => {}
1735 (
1736 OperandType::NegatedAllocatedFalse,
1737 OperandType::AllocatedTrue,
1738 Boolean::Not(ref v),
1739 ) => {
1740 assert!(cs.get("not and (not a) (not b)/and not result") == Field::ZERO);
1741 assert_eq!(v.get_value(), Some(false));
1742 }
1743 (
1744 OperandType::NegatedAllocatedFalse,
1745 OperandType::AllocatedFalse,
1746 Boolean::Not(ref v),
1747 ) => {
1748 assert!(cs.get("not and (not a) (not b)/and not result") == Field::ZERO);
1749 assert_eq!(v.get_value(), Some(false));
1750 }
1751 (
1752 OperandType::NegatedAllocatedFalse,
1753 OperandType::NegatedAllocatedTrue,
1754 Boolean::Not(ref v),
1755 ) => {
1756 assert!(cs.get("not and (not a) (not b)/and result") == Field::ZERO);
1757 assert_eq!(v.get_value(), Some(false));
1758 }
1759 (
1760 OperandType::NegatedAllocatedFalse,
1761 OperandType::NegatedAllocatedFalse,
1762 Boolean::Not(ref v),
1763 ) => {
1764 assert!(cs.get("not and (not a) (not b)/and result") == Field::ZERO);
1765 assert_eq!(v.get_value(), Some(false));
1766 }
1767
1768 _ => panic!("this should never be encountered"),
1769 }
1770 }
1771 }
1772 }
1773
1774 #[allow(clippy::identity_op)]
1775 #[test]
1776 fn test_u64_into_boolean_vec_le() {
1777 let mut cs = TestConstraintSystem::<Fr>::new();
1778
1779 let bits = u64_into_boolean_vec_le(&mut cs, Some(17234652694787248421)).unwrap();
1780
1781 assert!(cs.is_satisfied());
1782
1783 assert_eq!(bits.len(), 64);
1784
1785 assert!(bits[63 - 0].get_value().unwrap());
1786 assert!(bits[63 - 1].get_value().unwrap());
1787 assert!(bits[63 - 2].get_value().unwrap());
1788 assert!(!bits[63 - 3].get_value().unwrap());
1789 assert!(bits[63 - 4].get_value().unwrap());
1790 assert!(bits[63 - 5].get_value().unwrap());
1791 assert!(bits[63 - 20].get_value().unwrap());
1792 assert!(!bits[63 - 21].get_value().unwrap());
1793 assert!(!bits[63 - 22].get_value().unwrap());
1794 }
1795
1796 #[allow(clippy::identity_op)]
1797 #[test]
1798 fn test_field_into_allocated_bits_le() {
1799 let mut cs = TestConstraintSystem::<Fr>::new();
1800
1801 let r = Fr::from_str_vartime(
1802 "9147677615426976802526883532204139322118074541891858454835346926874644257775",
1803 )
1804 .unwrap();
1805
1806 let bits = field_into_allocated_bits_le(&mut cs, Some(r)).unwrap();
1807
1808 assert!(cs.is_satisfied());
1809
1810 assert_eq!(bits.len(), 255);
1811
1812 assert!(!bits[254 - 0].value.unwrap());
1813 assert!(!bits[254 - 1].value.unwrap());
1814 assert!(bits[254 - 2].value.unwrap());
1815 assert!(!bits[254 - 3].value.unwrap());
1816 assert!(bits[254 - 4].value.unwrap());
1817 assert!(!bits[254 - 5].value.unwrap());
1818 assert!(bits[254 - 20].value.unwrap());
1819 assert!(bits[254 - 23].value.unwrap());
1820 }
1821
1822 #[test]
1823 fn test_boolean_sha256_ch() {
1824 let variants = [
1825 OperandType::True,
1826 OperandType::False,
1827 OperandType::AllocatedTrue,
1828 OperandType::AllocatedFalse,
1829 OperandType::NegatedAllocatedTrue,
1830 OperandType::NegatedAllocatedFalse,
1831 ];
1832
1833 for first_operand in variants.iter().cloned() {
1834 for second_operand in variants.iter().cloned() {
1835 for third_operand in variants.iter().cloned() {
1836 let mut cs = TestConstraintSystem::<Fr>::new();
1837
1838 let a;
1839 let b;
1840 let c;
1841
1842 let expected = (first_operand.val() & second_operand.val())
1844 ^ ((!first_operand.val()) & third_operand.val());
1845
1846 {
1847 let mut dyn_construct = |operand, name| {
1848 let cs = cs.namespace(|| name);
1849
1850 match operand {
1851 OperandType::True => Boolean::constant(true),
1852 OperandType::False => Boolean::constant(false),
1853 OperandType::AllocatedTrue => {
1854 Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap())
1855 }
1856 OperandType::AllocatedFalse => {
1857 Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap())
1858 }
1859 OperandType::NegatedAllocatedTrue => {
1860 Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap())
1861 .not()
1862 }
1863 OperandType::NegatedAllocatedFalse => {
1864 Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap())
1865 .not()
1866 }
1867 }
1868 };
1869
1870 a = dyn_construct(first_operand, "a");
1871 b = dyn_construct(second_operand, "b");
1872 c = dyn_construct(third_operand, "c");
1873 }
1874
1875 let maj = Boolean::sha256_ch(&mut cs, &a, &b, &c).unwrap();
1876
1877 assert!(cs.is_satisfied());
1878
1879 assert_eq!(maj.get_value().unwrap(), expected);
1880
1881 if first_operand.is_constant()
1882 || second_operand.is_constant()
1883 || third_operand.is_constant()
1884 {
1885 if first_operand.is_constant()
1886 && second_operand.is_constant()
1887 && third_operand.is_constant()
1888 {
1889 assert_eq!(cs.num_constraints(), 0);
1890 }
1891 } else {
1892 assert_eq!(cs.get("ch"), {
1893 if expected {
1894 Fr::ONE
1895 } else {
1896 Fr::ZERO
1897 }
1898 });
1899 cs.set("ch", {
1900 if expected {
1901 Fr::ZERO
1902 } else {
1903 Fr::ONE
1904 }
1905 });
1906 assert_eq!(cs.which_is_unsatisfied().unwrap(), "ch computation");
1907 }
1908 }
1909 }
1910 }
1911 }
1912
1913 #[test]
1914 fn test_boolean_sha256_maj() {
1915 let variants = [
1916 OperandType::True,
1917 OperandType::False,
1918 OperandType::AllocatedTrue,
1919 OperandType::AllocatedFalse,
1920 OperandType::NegatedAllocatedTrue,
1921 OperandType::NegatedAllocatedFalse,
1922 ];
1923
1924 for first_operand in variants.iter().cloned() {
1925 for second_operand in variants.iter().cloned() {
1926 for third_operand in variants.iter().cloned() {
1927 let mut cs = TestConstraintSystem::<Fr>::new();
1928
1929 let a;
1930 let b;
1931 let c;
1932
1933 let expected = (first_operand.val() & second_operand.val())
1935 ^ (first_operand.val() & third_operand.val())
1936 ^ (second_operand.val() & third_operand.val());
1937
1938 {
1939 let mut dyn_construct = |operand, name| {
1940 let cs = cs.namespace(|| name);
1941
1942 match operand {
1943 OperandType::True => Boolean::constant(true),
1944 OperandType::False => Boolean::constant(false),
1945 OperandType::AllocatedTrue => {
1946 Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap())
1947 }
1948 OperandType::AllocatedFalse => {
1949 Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap())
1950 }
1951 OperandType::NegatedAllocatedTrue => {
1952 Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap())
1953 .not()
1954 }
1955 OperandType::NegatedAllocatedFalse => {
1956 Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap())
1957 .not()
1958 }
1959 }
1960 };
1961
1962 a = dyn_construct(first_operand, "a");
1963 b = dyn_construct(second_operand, "b");
1964 c = dyn_construct(third_operand, "c");
1965 }
1966
1967 let maj = Boolean::sha256_maj(&mut cs, &a, &b, &c).unwrap();
1968
1969 assert!(cs.is_satisfied());
1970
1971 assert_eq!(maj.get_value().unwrap(), expected);
1972
1973 if first_operand.is_constant()
1974 || second_operand.is_constant()
1975 || third_operand.is_constant()
1976 {
1977 if first_operand.is_constant()
1978 && second_operand.is_constant()
1979 && third_operand.is_constant()
1980 {
1981 assert_eq!(cs.num_constraints(), 0);
1982 }
1983 } else {
1984 assert_eq!(cs.get("maj"), {
1985 if expected {
1986 Fr::ONE
1987 } else {
1988 Fr::ZERO
1989 }
1990 });
1991 cs.set("maj", {
1992 if expected {
1993 Fr::ZERO
1994 } else {
1995 Fr::ONE
1996 }
1997 });
1998 assert_eq!(cs.which_is_unsatisfied().unwrap(), "maj computation");
1999 }
2000 }
2001 }
2002 }
2003 }
2004
2005 #[test]
2006 fn test_alloc_conditionally() {
2007 {
2008 let mut cs = TestConstraintSystem::<Fr>::new();
2009 let b = AllocatedBit::alloc(&mut cs, Some(false)).unwrap();
2010
2011 let value = None;
2012 let is_err = AllocatedBit::alloc_conditionally(
2014 cs.namespace(|| "alloc_conditionally"),
2015 value,
2016 &b,
2017 )
2018 .is_err();
2019 assert!(is_err);
2020 }
2021
2022 {
2023 let mut cs = TestConstraintSystem::<Fr>::new();
2025
2026 let value = Some(true);
2027 let b = AllocatedBit::alloc(&mut cs, Some(false)).unwrap();
2028 let allocated_value = AllocatedBit::alloc_conditionally(
2029 cs.namespace(|| "alloc_conditionally"),
2030 value,
2031 &b,
2032 )
2033 .unwrap();
2034
2035 assert!(allocated_value.get_value().unwrap());
2036 assert!(cs.is_satisfied());
2037 }
2038
2039 {
2040 let mut cs = TestConstraintSystem::<Fr>::new();
2042
2043 let value = Some(true);
2044 let b = AllocatedBit::alloc(&mut cs, Some(true)).unwrap();
2045 AllocatedBit::alloc_conditionally(cs.namespace(|| "alloc_conditionally"), value, &b)
2046 .unwrap();
2047
2048 assert!(!cs.is_satisfied());
2049 }
2050
2051 {
2052 let value = Some(false);
2055 let mut cs = TestConstraintSystem::<Fr>::new();
2057 let b1 = AllocatedBit::alloc(&mut cs, Some(false)).unwrap();
2058 AllocatedBit::alloc_conditionally(cs.namespace(|| "alloc_conditionally"), value, &b1)
2059 .unwrap();
2060
2061 assert!(cs.is_satisfied());
2062
2063 let mut cs = TestConstraintSystem::<Fr>::new();
2065 let b2 = AllocatedBit::alloc(&mut cs, Some(true)).unwrap();
2066 AllocatedBit::alloc_conditionally(cs.namespace(|| "alloc_conditionally"), value, &b2)
2067 .unwrap();
2068
2069 assert!(cs.is_satisfied());
2070 }
2071 }
2072}