Skip to main content

bellpepper_core/gadgets/
boolean.rs

1//! Gadgets for allocating bits in the circuit and performing boolean logic.
2
3use ff::{PrimeField, PrimeFieldBits};
4
5use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable};
6
7/// Represents a variable in the constraint system which is guaranteed
8/// to be either zero or one.
9#[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    /// Allocate a variable in the constraint system which can only be a
25    /// boolean value. Further, constrain that the boolean is false
26    /// unless the condition is false.
27    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        // Constrain: (1 - must_be_false - a) * a = 0
48        // if must_be_false is true, the equation
49        // reduces to -a * a = 0, which implies a = 0.
50        // if must_be_false is false, the equation
51        // reduces to (1 - a) * a = 0, which is a
52        // traditional boolean constraint.
53        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    /// Allocate a variable in the constraint system which can only be a
67    /// boolean value.
68    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        // Constrain: (1 - a) * a = 0
85        // This constrains a to be either 0 or 1.
86        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    /// Performs an XOR operation over the two operands, returning
100    /// an `AllocatedBit`.
101    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        // Constrain (a + a) * (b) = (a + b - c)
126        // Given that a and b are boolean constrained, if they
127        // are equal, the only solution for c is 0, and if they
128        // are different, the only solution for c is 1.
129        //
130        // ¬(a ∧ b) ∧ ¬(¬a ∧ ¬b) = c
131        // (1 - (a * b)) * (1 - ((1 - a) * (1 - b))) = c
132        // (1 - ab) * (1 - (1 - a - b + ab)) = c
133        // (1 - ab) * (a + b - ab) = c
134        // a + b - ab - (a^2)b - (b^2)a + (a^2)(b^2) = c
135        // a + b - ab - ab - ab + ab = c
136        // a + b - 2ab = c
137        // -2a * b = c - a - b
138        // 2a * b = a + b - c
139        // (a + a) * b = a + b - c
140        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    /// Performs an AND operation over the two operands, returning
154    /// an `AllocatedBit`.
155    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        // Constrain (a) * (b) = (c), ensuring c is 1 iff
180        // a AND b are both 1.
181        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    /// Calculates `a AND (NOT b)`.
195    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        // Constrain (a) * (1 - b) = (c), ensuring c is 1 iff
220        // a is true and b is false, and otherwise c is 0.
221        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    /// Calculates `(NOT a) AND (NOT b)`.
235    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        // Constrain (1 - a) * (1 - b) = (c), ensuring c is 1 iff
260        // a and b are both false, and otherwise c is 0.
261        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    // Deconstruct in big-endian bit order
330    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                // Skip leading bits
340                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    // Allocate in little-endian order
356    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/// This is a boolean value which may be either a constant or
367/// an interpretation of an `AllocatedBit`.
368#[derive(Clone, Debug)]
369pub enum Boolean {
370    /// Existential view of the boolean variable
371    Is(AllocatedBit),
372    /// Negated view of the boolean variable
373    Not(AllocatedBit),
374    /// Constant (not an allocated variable)
375    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    /// Construct a boolean from a known constant
458    pub fn constant(b: bool) -> Self {
459        Boolean::Constant(b)
460    }
461
462    /// Return a negated interpretation of this boolean.
463    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    /// Perform XOR over two boolean operands
472    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            // a XOR (NOT b) = NOT(a XOR b)
481            (is @ &Boolean::Is(_), not @ &Boolean::Not(_))
482            | (not @ &Boolean::Not(_), is @ &Boolean::Is(_)) => {
483                Ok(Boolean::xor(cs, is, &not.not())?.not())
484            }
485            // a XOR b = (NOT a) XOR (NOT b)
486            (&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    /// Perform AND over two boolean operands
494    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            // false AND x is always false
501            (&Boolean::Constant(false), _) | (_, &Boolean::Constant(false)) => {
502                Ok(Boolean::Constant(false))
503            }
504            // true AND x is always x
505            (&Boolean::Constant(true), x) | (x, &Boolean::Constant(true)) => Ok(x.clone()),
506            // a AND (NOT b)
507            (&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            // (NOT a) AND (NOT b) = a NOR b
512            (Boolean::Not(a), Boolean::Not(b)) => Ok(Boolean::Is(AllocatedBit::nor(cs, a, b)?)),
513            // a AND b
514            (Boolean::Is(a), Boolean::Is(b)) => Ok(Boolean::Is(AllocatedBit::and(cs, a, b)?)),
515        }
516    }
517
518    /// Perform OR over two boolean operands
519    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    /// Computes (a and b) xor ((not a) and c)
536    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                // (a and b) xor ((not a) and c)
549                Some((a & b) ^ ((!a) & c))
550            }
551            _ => None,
552        };
553
554        match (a, b, c) {
555            (&Boolean::Constant(_), &Boolean::Constant(_), &Boolean::Constant(_)) => {
556                // They're all constants, so we can just compute the value.
557
558                return Ok(Boolean::Constant(ch_value.expect("they're all constants")));
559            }
560            (&Boolean::Constant(false), _, c) => {
561                // If a is false
562                // (a and b) xor ((not a) and c)
563                // equals
564                // (false) xor (c)
565                // equals
566                // c
567                return Ok(c.clone());
568            }
569            (a, &Boolean::Constant(false), c) => {
570                // If b is false
571                // (a and b) xor ((not a) and c)
572                // equals
573                // ((not a) and c)
574                return Boolean::and(cs, &a.not(), c);
575            }
576            (a, b, &Boolean::Constant(false)) => {
577                // If c is false
578                // (a and b) xor ((not a) and c)
579                // equals
580                // (a and b)
581                return Boolean::and(cs, a, b);
582            }
583            (a, b, &Boolean::Constant(true)) => {
584                // If c is true
585                // (a and b) xor ((not a) and c)
586                // equals
587                // (a and b) xor (not a)
588                // equals
589                // not (a and (not b))
590                return Ok(Boolean::and(cs, a, &b.not())?.not());
591            }
592            (a, &Boolean::Constant(true), c) => {
593                // If b is true
594                // (a and b) xor ((not a) and c)
595                // equals
596                // a xor ((not a) and c)
597                // equals
598                // not ((not a) and (not c))
599                return Ok(Boolean::and(cs, &a.not(), &c.not())?.not());
600            }
601            (&Boolean::Constant(true), _, _) => {
602                // If a is true
603                // (a and b) xor ((not a) and c)
604                // equals
605                // b xor ((not a) and c)
606                // So we just continue!
607            }
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        // a(b - c) = ch - c
629        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    /// Computes (a and b) xor (a and c) xor (b and c)
644    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                // (a and b) xor (a and c) xor (b and c)
657                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                // They're all constants, so we can just compute the value.
665
666                return Ok(Boolean::Constant(maj_value.expect("they're all constants")));
667            }
668            (&Boolean::Constant(false), b, c) => {
669                // If a is false,
670                // (a and b) xor (a and c) xor (b and c)
671                // equals
672                // (b and c)
673                return Boolean::and(cs, b, c);
674            }
675            (a, &Boolean::Constant(false), c) => {
676                // If b is false,
677                // (a and b) xor (a and c) xor (b and c)
678                // equals
679                // (a and c)
680                return Boolean::and(cs, a, c);
681            }
682            (a, b, &Boolean::Constant(false)) => {
683                // If c is false,
684                // (a and b) xor (a and c) xor (b and c)
685                // equals
686                // (a and b)
687                return Boolean::and(cs, a, b);
688            }
689            (a, b, &Boolean::Constant(true)) => {
690                // If c is true,
691                // (a and b) xor (a and c) xor (b and c)
692                // equals
693                // (a and b) xor (a) xor (b)
694                // equals
695                // not ((not a) and (not b))
696                return Ok(Boolean::and(cs, &a.not(), &b.not())?.not());
697            }
698            (a, &Boolean::Constant(true), c) => {
699                // If b is true,
700                // (a and b) xor (a and c) xor (b and c)
701                // equals
702                // (a) xor (a and c) xor (c)
703                return Ok(Boolean::and(cs, &a.not(), &c.not())?.not());
704            }
705            (&Boolean::Constant(true), b, c) => {
706                // If a is true,
707                // (a and b) xor (a and c) xor (b and c)
708                // equals
709                // (b) xor (c) xor (b and c)
710                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        // ¬(¬a ∧ ¬b) ∧ ¬(¬a ∧ ¬c) ∧ ¬(¬b ∧ ¬c)
733        // (1 - ((1 - a) * (1 - b))) * (1 - ((1 - a) * (1 - c))) * (1 - ((1 - b) * (1 - c)))
734        // (a + b - ab) * (a + c - ac) * (b + c - bc)
735        // -2abc + ab + ac + bc
736        // a (-2bc + b + c) + bc
737        //
738        // (b) * (c) = (bc)
739        // (2bc - b - c) * (a) = bc - maj
740
741        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                // Invert the result and check if the constraint system is still satisfied
813                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                // Invert the result and check if the constraint system is still satisfied
849                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                // Invert the result and check if the constraint system is still satisfied
885                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                // Invert the result and check if the constraint system is still satisfied
921                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                    // ch = (a and b) xor ((not a) and c)
1843                    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                    // maj = (a and b) xor (a and c) xor (b and c)
1934                    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            // if value is none, fail with SynthesisError
2013            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            // since value is true, b must be false, so it should succeed
2024            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            // since value is true, b must be false, so it should fail
2041            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            // since value is false, we don't care about the value of the bit
2053
2054            let value = Some(false);
2055            //check with false bit
2056            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            //check with true bit
2064            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}