Skip to content

Commit 1bf9ecb

Browse files
committed
Fix boolean ops
1 parent 7ceadfb commit 1bf9ecb

File tree

2 files changed

+40
-11
lines changed

2 files changed

+40
-11
lines changed

r1cs-std/src/bits/boolean.rs

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,29 @@ impl<F: Field> AllocatedBit<F> {
3232
self.variable
3333
}
3434

35+
/// Allocate a witness variable without a booleanity check.
36+
fn new_witness_without_booleanity_check<T: Borrow<bool>>(
37+
cs: ConstraintSystemRef<F>,
38+
f: impl FnOnce() -> Result<T, SynthesisError>,
39+
) -> Result<Self, SynthesisError> {
40+
let mut value = None;
41+
let variable = cs.new_witness_variable(|| {
42+
value = Some(*f()?.borrow());
43+
value.get().map(bool_to_field)
44+
})?;
45+
Ok(Self {
46+
value,
47+
variable,
48+
cs,
49+
})
50+
}
51+
3552
/// Performs an XOR operation over the two operands, returning
3653
/// an `AllocatedBit`.
3754
pub fn xor(&self, b: &Self) -> Result<Self, SynthesisError> {
38-
let result = Self::new_witness(self.cs.clone(), || Ok(self.value()? ^ b.value()?))?;
55+
let result = Self::new_witness_without_booleanity_check(self.cs.clone(), || {
56+
Ok(self.value()? ^ b.value()?)
57+
})?;
3958

4059
// Constrain (a + a) * (b) = (a + b - c)
4160
// Given that a and b are boolean constrained, if they
@@ -64,7 +83,9 @@ impl<F: Field> AllocatedBit<F> {
6483
/// Performs an AND operation over the two operands, returning
6584
/// an `AllocatedBit`.
6685
pub fn and(&self, b: &Self) -> Result<Self, SynthesisError> {
67-
let result = Self::new_witness(self.cs.clone(), || Ok(self.value()? & b.value()?))?;
86+
let result = Self::new_witness_without_booleanity_check(self.cs.clone(), || {
87+
Ok(self.value()? & b.value()?)
88+
})?;
6889

6990
// Constrain (a) * (b) = (c), ensuring c is 1 iff
7091
// a AND b are both 1.
@@ -80,7 +101,9 @@ impl<F: Field> AllocatedBit<F> {
80101
/// Performs an OR operation over the two operands, returning
81102
/// an `AllocatedBit`.
82103
pub fn or(&self, b: &Self) -> Result<Self, SynthesisError> {
83-
let result = Self::new_witness(self.cs.clone(), || Ok(self.value()? | b.value()?))?;
104+
let result = Self::new_witness_without_booleanity_check(self.cs.clone(), || {
105+
Ok(self.value()? | b.value()?)
106+
})?;
84107

85108
// Constrain (1 - a) * (1 - b) = (c), ensuring c is 1 iff
86109
// a and b are both false, and otherwise c is 0.
@@ -95,7 +118,9 @@ impl<F: Field> AllocatedBit<F> {
95118

96119
/// Calculates `a AND (NOT b)`.
97120
pub fn and_not(&self, b: &Self) -> Result<Self, SynthesisError> {
98-
let result = Self::new_witness(self.cs.clone(), || Ok(self.value()? & !b.value()?))?;
121+
let result = Self::new_witness_without_booleanity_check(self.cs.clone(), || {
122+
Ok(self.value()? & !b.value()?)
123+
})?;
99124

100125
// Constrain (a) * (1 - b) = (c), ensuring c is 1 iff
101126
// a is true and b is false, and otherwise c is 0.
@@ -110,7 +135,9 @@ impl<F: Field> AllocatedBit<F> {
110135

111136
/// Calculates `(NOT a) AND (NOT b)`.
112137
pub fn nor(&self, b: &Self) -> Result<Self, SynthesisError> {
113-
let result = Self::new_witness(self.cs.clone(), || Ok(!(self.value()? | b.value()?)))?;
138+
let result = Self::new_witness_without_booleanity_check(self.cs.clone(), || {
139+
Ok(!(self.value()? | b.value()?))
140+
})?;
114141

115142
// Constrain (1 - a) * (1 - b) = (c), ensuring c is 1 iff
116143
// a and b are both false, and otherwise c is 0.
@@ -596,10 +623,12 @@ impl<F: Field> CondSelectGadget<F> for Boolean<F> {
596623
(x, &Constant(true)) => cond.not().or(x),
597624
(a, b) => {
598625
let cs = cond.cs().unwrap();
599-
let result = Boolean::new_witness(cs.clone(), || {
600-
let cond = cond.value()?;
601-
Ok(if cond { a.value()? } else { b.value()? })
602-
})?;
626+
let result: Boolean<F> =
627+
AllocatedBit::new_witness_without_booleanity_check(cs.clone(), || {
628+
let cond = cond.value()?;
629+
Ok(if cond { a.value()? } else { b.value()? })
630+
})?
631+
.into();
603632
// a = self; b = other; c = cond;
604633
//
605634
// r = c * a + (1 - c) * b
@@ -1014,7 +1043,7 @@ mod test {
10141043
}
10151044

10161045
#[test]
1017-
fn test_boolean_cond_select() -> Result<(), r1cs_core::SynthesisError> {
1046+
fn test_boolean_cond_select() -> Result<(), SynthesisError> {
10181047
for condition in VARIANTS.iter().cloned() {
10191048
for first_operand in VARIANTS.iter().cloned() {
10201049
for second_operand in VARIANTS.iter().cloned() {

r1cs-std/src/fields/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ pub(crate) mod tests {
185185
#[allow(dead_code)]
186186
pub(crate) fn field_test<F: Field, AF: FieldVar<F>>() -> Result<(), SynthesisError>
187187
where
188-
AF: crate::select::TwoBitLookupGadget<<AF as FieldVar<F>>::ConstraintF, TableConstant = F>,
188+
AF: TwoBitLookupGadget<<AF as FieldVar<F>>::ConstraintF, TableConstant = F>,
189189
for<'a> &'a AF: FieldOpsBounds<'a, F, AF>,
190190
{
191191
let cs = ConstraintSystem::<AF::ConstraintF>::new_ref();

0 commit comments

Comments
 (0)