use super::*;
pub fn smart_and<E: Engine, CS: ConstraintSystem<E>>(cs: &mut CS, bools: &[Boolean]) -> Result<Boolean, SynthesisError> {
const LIMIT: usize = 4;
assert!(bools.len() > 0);
if bools.len() == 1 {
return Ok(bools[0]);
}
if bools.len() == 2 {
let result = Boolean::and(cs, &bools[0], &bools[1])?;
return Ok(result);
}
if bools.len() < LIMIT {
let mut result = Boolean::and(cs, &bools[0], &bools[1])?;
for b in bools[2..].iter() {
result = Boolean::and(cs, &result, &b)?;
}
return Ok(result);
}
let mut lc = LinearCombination::zero();
let num_elements_as_fr = E::Fr::from_str(&bools.len().to_string()).unwrap();
lc.sub_assign_constant(num_elements_as_fr);
for b in bools.iter() {
lc.add_assign_boolean_with_coeff(b, E::Fr::one());
}
let as_num = lc.into_num(cs)?;
let all_true = as_num.is_zero(cs)?;
Ok(all_true)
}
pub(crate) fn binary_select<E: Engine, CS: ConstraintSystem<E>>(cs: &mut CS, elements: &[GoldilocksField<E>], bits: &[Boolean]) -> Result<GoldilocksField<E>, SynthesisError> {
assert_eq!(elements.len(), 1 << bits.len());
assert!(bits.len() > 0);
let mut input_space = Vec::with_capacity(elements.len() / 2);
let mut dst_space = Vec::with_capacity(elements.len() / 2);
for (idx, bit) in bits.iter().enumerate() {
let src = if idx == 0 { elements } else { &input_space };
debug_assert_eq!(elements.len() % 2, 0);
dst_space.clear();
for src in src.array_chunks::<2>() {
let [a, b] = src;
let selected = GoldilocksField::conditionally_select(cs, *bit, b, a)?;
dst_space.push(selected);
}
std::mem::swap(&mut dst_space, &mut input_space);
}
assert_eq!(input_space.len(), 1);
Ok(input_space.pop().unwrap())
}
pub(crate) fn materialize_powers_serial<E: Engine, CS: ConstraintSystem<E> + 'static>(cs: &mut CS, base: GoldilocksExtAsFieldWrapper<E, CS>, size: usize) -> Vec<GoldilocksExtAsFieldWrapper<E, CS>> {
if size == 0 {
return Vec::new();
}
let mut storage = Vec::with_capacity(size);
let mut current = GoldilocksExtAsFieldWrapper::one(cs);
storage.push(current);
for idx in 1..size {
if idx == 1 {
current = base;
} else {
current.mul_assign(&base, cs);
}
storage.push(current);
}
storage
}