|
|
@ -1,7 +1,7 @@ |
|
|
|
use algebra::{BitIterator, Field, FpParameters, PrimeField};
|
|
|
|
|
|
|
|
use crate::{prelude::*, Assignment};
|
|
|
|
use r1cs_core::{ConstraintSystem, LinearCombination, SynthesisError, Variable, ConstraintVar};
|
|
|
|
use r1cs_core::{ConstraintSystem, ConstraintVar, LinearCombination, SynthesisError, Variable};
|
|
|
|
use std::borrow::Borrow;
|
|
|
|
|
|
|
|
/// Represents a variable in the constraint system which is guaranteed
|
|
|
@ -336,11 +336,14 @@ fn cond_select_helper>( |
|
|
|
) -> Result<AllocatedBit, SynthesisError> {
|
|
|
|
let mut result_val = None;
|
|
|
|
let result_var = cs.alloc(
|
|
|
|
|| "cond_select_result",
|
|
|
|
|| "cond_select_result",
|
|
|
|
|| {
|
|
|
|
result_val = cond.get_value().and_then(|c| if c { first.0 } else { second.0 });
|
|
|
|
result_val = cond
|
|
|
|
.get_value()
|
|
|
|
.and_then(|c| if c { first.0 } else { second.0 });
|
|
|
|
result_val.get().map(|v| F::from(v as u8))
|
|
|
|
})?;
|
|
|
|
},
|
|
|
|
)?;
|
|
|
|
|
|
|
|
let first_var = first.1.into();
|
|
|
|
let second_var = second.1.into();
|
|
|
@ -358,8 +361,10 @@ fn cond_select_helper>( |
|
|
|
|lc| ConstraintVar::from(result_var) - &second_var + lc,
|
|
|
|
);
|
|
|
|
|
|
|
|
Ok(AllocatedBit { value: result_val, variable: result_var })
|
|
|
|
|
|
|
|
Ok(AllocatedBit {
|
|
|
|
value: result_val,
|
|
|
|
variable: result_var,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// This is a boolean value which may be either a constant or
|
|
|
@ -800,31 +805,23 @@ impl CondSelectGadget for Boolean { |
|
|
|
Boolean::Constant(true) => Ok(first.clone()),
|
|
|
|
Boolean::Constant(false) => Ok(second.clone()),
|
|
|
|
cond @ Boolean::Not(_) => Self::conditionally_select(cs, &cond.not(), second, first),
|
|
|
|
cond @ Boolean::Is(_) => {
|
|
|
|
match (first, second) {
|
|
|
|
(x, &Boolean::Constant(false)) => {
|
|
|
|
Boolean::and(cs.ns(|| "and"), cond, x).into()
|
|
|
|
},
|
|
|
|
(&Boolean::Constant(false), x) => {
|
|
|
|
Boolean::and(cs.ns(|| "and"), &cond.not(), x)
|
|
|
|
},
|
|
|
|
(&Boolean::Constant(true), x) => {
|
|
|
|
Boolean::or(cs.ns(|| "or"), cond, x).into()
|
|
|
|
},
|
|
|
|
(x, &Boolean::Constant(true)) => {
|
|
|
|
Boolean::or(cs.ns(|| "or"), &cond.not(), x)
|
|
|
|
},
|
|
|
|
(a @ Boolean::Is(_), b @ Boolean::Is(_))
|
|
|
|
| (a @ Boolean::Not(_), b @ Boolean::Not(_))
|
|
|
|
| (a @ Boolean::Is(_), b @ Boolean::Not(_))
|
|
|
|
| (a @ Boolean::Not(_), b @ Boolean::Is(_)) => {
|
|
|
|
let a_lc = a.lc(CS::one(), ConstraintF::one());
|
|
|
|
let b_lc = b.lc(CS::one(), ConstraintF::one());
|
|
|
|
Ok(cond_select_helper(cs, cond, (a.get_value(), a_lc), (b.get_value(), b_lc))?.into())
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
cond @ Boolean::Is(_) => match (first, second) {
|
|
|
|
(x, &Boolean::Constant(false)) => Boolean::and(cs.ns(|| "and"), cond, x).into(),
|
|
|
|
(&Boolean::Constant(false), x) => Boolean::and(cs.ns(|| "and"), &cond.not(), x),
|
|
|
|
(&Boolean::Constant(true), x) => Boolean::or(cs.ns(|| "or"), cond, x).into(),
|
|
|
|
(x, &Boolean::Constant(true)) => Boolean::or(cs.ns(|| "or"), &cond.not(), x),
|
|
|
|
(a @ Boolean::Is(_), b @ Boolean::Is(_))
|
|
|
|
| (a @ Boolean::Not(_), b @ Boolean::Not(_))
|
|
|
|
| (a @ Boolean::Is(_), b @ Boolean::Not(_))
|
|
|
|
| (a @ Boolean::Not(_), b @ Boolean::Is(_)) => {
|
|
|
|
let a_lc = a.lc(CS::one(), ConstraintF::one());
|
|
|
|
let b_lc = b.lc(CS::one(), ConstraintF::one());
|
|
|
|
Ok(
|
|
|
|
cond_select_helper(cs, cond, (a.get_value(), a_lc), (b.get_value(), b_lc))?
|
|
|
|
.into(),
|
|
|
|
)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
@ -837,8 +834,7 @@ impl CondSelectGadget for Boolean { |
|
|
|
mod test {
|
|
|
|
use super::{AllocatedBit, Boolean};
|
|
|
|
use crate::{prelude::*, test_constraint_system::TestConstraintSystem};
|
|
|
|
use algebra::{fields::bls12_381::Fr, BitIterator, Field, PrimeField, UniformRand};
|
|
|
|
use algebra::{One, Zero};
|
|
|
|
use algebra::{fields::bls12_381::Fr, BitIterator, Field, One, PrimeField, UniformRand, Zero};
|
|
|
|
use r1cs_core::ConstraintSystem;
|
|
|
|
use rand::SeedableRng;
|
|
|
|
use rand_xorshift::XorShiftRng;
|
|
|
@ -1408,10 +1404,12 @@ mod test { |
|
|
|
Boolean::from(AllocatedBit::alloc(cs, || Ok(false)).unwrap())
|
|
|
|
},
|
|
|
|
OperandType::NegatedAllocatedTrue => {
|
|
|
|
Boolean::from(AllocatedBit::alloc(cs, || Ok(true)).unwrap()).not()
|
|
|
|
Boolean::from(AllocatedBit::alloc(cs, || Ok(true)).unwrap())
|
|
|
|
.not()
|
|
|
|
},
|
|
|
|
OperandType::NegatedAllocatedFalse => {
|
|
|
|
Boolean::from(AllocatedBit::alloc(cs, || Ok(false)).unwrap()).not()
|
|
|
|
Boolean::from(AllocatedBit::alloc(cs, || Ok(false)).unwrap())
|
|
|
|
.not()
|
|
|
|
},
|
|
|
|
}
|
|
|
|
};
|
|
|
@ -1432,7 +1430,14 @@ mod test { |
|
|
|
first_operand,
|
|
|
|
second_operand,
|
|
|
|
);
|
|
|
|
assert_eq!(c.get_value(), if cond.get_value().unwrap() { a.get_value() } else { b.get_value() });
|
|
|
|
assert_eq!(
|
|
|
|
c.get_value(),
|
|
|
|
if cond.get_value().unwrap() {
|
|
|
|
a.get_value()
|
|
|
|
} else {
|
|
|
|
b.get_value()
|
|
|
|
}
|
|
|
|
);
|
|
|
|
assert!(<Boolean as CondSelectGadget<Fr>>::cost() >= after - before);
|
|
|
|
}
|
|
|
|
}
|
|
|
|