sapling_crypto_ce/circuit/
boolean.rs

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