Make UInt32::addmany produce constant results when fed constant inputs, to allow for blake2s block precomputation for group hash.
This commit is contained in:
parent
3a6e8d448f
commit
6b43a4ed10
|
@ -325,6 +325,32 @@ mod test {
|
||||||
assert_eq!(cs.num_constraints(), 21792);
|
assert_eq!(cs.num_constraints(), 21792);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_blake2s_precomp_constraints() {
|
||||||
|
// Test that 512 fixed leading bits (constants)
|
||||||
|
// doesn't result in more constraints.
|
||||||
|
|
||||||
|
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||||
|
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||||
|
let input_bits: Vec<_> = (0..512)
|
||||||
|
.map(|_| Boolean::constant(rng.gen()))
|
||||||
|
.chain((0..512)
|
||||||
|
.map(|i| AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true)).unwrap().into()))
|
||||||
|
.collect();
|
||||||
|
blake2s(&mut cs, &input_bits).unwrap();
|
||||||
|
assert!(cs.is_satisfied());
|
||||||
|
assert_eq!(cs.num_constraints(), 21792);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_blake2s_constant_constraints() {
|
||||||
|
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||||
|
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||||
|
let input_bits: Vec<_> = (0..512).map(|_| Boolean::constant(rng.gen())).collect();
|
||||||
|
blake2s(&mut cs, &input_bits).unwrap();
|
||||||
|
assert_eq!(cs.num_constraints(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_blake2s() {
|
fn test_blake2s() {
|
||||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||||
|
@ -366,7 +392,10 @@ mod test {
|
||||||
Boolean::Not(b) => {
|
Boolean::Not(b) => {
|
||||||
assert!(s.next().unwrap() != b.get_value().unwrap());
|
assert!(s.next().unwrap() != b.get_value().unwrap());
|
||||||
},
|
},
|
||||||
_ => panic!()
|
Boolean::Constant(b) => {
|
||||||
|
assert!(input_len == 0);
|
||||||
|
assert!(s.next().unwrap() == b);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -205,6 +205,8 @@ impl<Var: Copy> UInt32<Var> {
|
||||||
// This is a linear combination that we will enforce to be "zero"
|
// This is a linear combination that we will enforce to be "zero"
|
||||||
let mut lc = LinearCombination::zero();
|
let mut lc = LinearCombination::zero();
|
||||||
|
|
||||||
|
let mut all_constants = true;
|
||||||
|
|
||||||
// Iterate over the operands
|
// Iterate over the operands
|
||||||
for op in operands {
|
for op in operands {
|
||||||
// Accumulate the value
|
// Accumulate the value
|
||||||
|
@ -225,10 +227,14 @@ impl<Var: Copy> UInt32<Var> {
|
||||||
for bit in &op.bits {
|
for bit in &op.bits {
|
||||||
match bit {
|
match bit {
|
||||||
&Boolean::Is(ref bit) => {
|
&Boolean::Is(ref bit) => {
|
||||||
|
all_constants = false;
|
||||||
|
|
||||||
// Add coeff * bit
|
// Add coeff * bit
|
||||||
lc = lc + (coeff, bit.get_variable());
|
lc = lc + (coeff, bit.get_variable());
|
||||||
},
|
},
|
||||||
&Boolean::Not(ref bit) => {
|
&Boolean::Not(ref bit) => {
|
||||||
|
all_constants = false;
|
||||||
|
|
||||||
// Add coeff * (1 - bit) = coeff * ONE - coeff * bit
|
// Add coeff * (1 - bit) = coeff * ONE - coeff * bit
|
||||||
lc = lc + (coeff, cs.one()) - (coeff, bit.get_variable());
|
lc = lc + (coeff, cs.one()) - (coeff, bit.get_variable());
|
||||||
},
|
},
|
||||||
|
@ -246,6 +252,13 @@ impl<Var: Copy> UInt32<Var> {
|
||||||
// The value of the actual result is modulo 2^32
|
// The value of the actual result is modulo 2^32
|
||||||
let modular_value = result_value.map(|v| v as u32);
|
let modular_value = result_value.map(|v| v as u32);
|
||||||
|
|
||||||
|
if all_constants && modular_value.is_some() {
|
||||||
|
// We can just return a constant, rather than
|
||||||
|
// unpacking the result into allocated bits.
|
||||||
|
|
||||||
|
return Ok(UInt32::constant(modular_value.unwrap()));
|
||||||
|
}
|
||||||
|
|
||||||
// Storage area for the resulting bits
|
// Storage area for the resulting bits
|
||||||
let mut result_bits = vec![];
|
let mut result_bits = vec![];
|
||||||
|
|
||||||
|
@ -367,6 +380,41 @@ mod test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_uint32_addmany_constants() {
|
||||||
|
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||||
|
|
||||||
|
for _ in 0..1000 {
|
||||||
|
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||||
|
|
||||||
|
let a: u32 = rng.gen();
|
||||||
|
let b: u32 = rng.gen();
|
||||||
|
let c: u32 = rng.gen();
|
||||||
|
|
||||||
|
let a_bit = UInt32::constant(a);
|
||||||
|
let b_bit = UInt32::constant(b);
|
||||||
|
let c_bit = UInt32::constant(c);
|
||||||
|
|
||||||
|
let mut expected = a.wrapping_add(b).wrapping_add(c);
|
||||||
|
|
||||||
|
let r = UInt32::addmany(cs.namespace(|| "addition"), &[a_bit, b_bit, c_bit]).unwrap();
|
||||||
|
|
||||||
|
assert!(r.value == Some(expected));
|
||||||
|
|
||||||
|
for b in r.bits.iter() {
|
||||||
|
match b {
|
||||||
|
&Boolean::Is(_) => panic!(),
|
||||||
|
&Boolean::Not(_) => panic!(),
|
||||||
|
&Boolean::Constant(b) => {
|
||||||
|
assert!(b == (expected & 1 == 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expected >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_uint32_addmany() {
|
fn test_uint32_addmany() {
|
||||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||||
|
@ -401,8 +449,8 @@ mod test {
|
||||||
&Boolean::Not(ref b) => {
|
&Boolean::Not(ref b) => {
|
||||||
assert!(!b.get_value().unwrap() == (expected & 1 == 1));
|
assert!(!b.get_value().unwrap() == (expected & 1 == 1));
|
||||||
},
|
},
|
||||||
&Boolean::Constant(b) => {
|
&Boolean::Constant(_) => {
|
||||||
assert!(b == (expected & 1 == 1));
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue