cargo fmt bellman

This commit is contained in:
Eirik Ogilvie-Wigley
2019-08-15 10:38:41 -06:00
parent bc7ea564d3
commit 9a4f6812f1
21 changed files with 2252 additions and 2165 deletions
+173 -65
View File
@@ -1,19 +1,10 @@
use pairing::{
Engine,
};
use pairing::Engine;
use crate::{
SynthesisError,
ConstraintSystem
};
use crate::{ConstraintSystem, SynthesisError};
use super::boolean::{
Boolean
};
use super::boolean::Boolean;
use super::uint32::{
UInt32
};
use super::uint32::UInt32;
use super::multieq::MultiEq;
@@ -65,7 +56,7 @@ const SIGMA: [[usize; 16]; 10] = [
[12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
[13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
[6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
[10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0]
[10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
];
/*
@@ -98,17 +89,30 @@ fn mixing_g<E: Engine, CS: ConstraintSystem<E>, M>(
c: usize,
d: usize,
x: &UInt32,
y: &UInt32
y: &UInt32,
) -> Result<(), SynthesisError>
where M: ConstraintSystem<E, Root=MultiEq<E, CS>>
where
M: ConstraintSystem<E, Root = MultiEq<E, CS>>,
{
v[a] = UInt32::addmany(cs.namespace(|| "mixing step 1"), &[v[a].clone(), v[b].clone(), x.clone()])?;
v[a] = UInt32::addmany(
cs.namespace(|| "mixing step 1"),
&[v[a].clone(), v[b].clone(), x.clone()],
)?;
v[d] = v[d].xor(cs.namespace(|| "mixing step 2"), &v[a])?.rotr(R1);
v[c] = UInt32::addmany(cs.namespace(|| "mixing step 3"), &[v[c].clone(), v[d].clone()])?;
v[c] = UInt32::addmany(
cs.namespace(|| "mixing step 3"),
&[v[c].clone(), v[d].clone()],
)?;
v[b] = v[b].xor(cs.namespace(|| "mixing step 4"), &v[c])?.rotr(R2);
v[a] = UInt32::addmany(cs.namespace(|| "mixing step 5"), &[v[a].clone(), v[b].clone(), y.clone()])?;
v[a] = UInt32::addmany(
cs.namespace(|| "mixing step 5"),
&[v[a].clone(), v[b].clone(), y.clone()],
)?;
v[d] = v[d].xor(cs.namespace(|| "mixing step 6"), &v[a])?.rotr(R3);
v[c] = UInt32::addmany(cs.namespace(|| "mixing step 7"), &[v[c].clone(), v[d].clone()])?;
v[c] = UInt32::addmany(
cs.namespace(|| "mixing step 7"),
&[v[c].clone(), v[d].clone()],
)?;
v[b] = v[b].xor(cs.namespace(|| "mixing step 8"), &v[c])?.rotr(R4);
Ok(())
@@ -162,15 +166,13 @@ fn mixing_g<E: Engine, CS: ConstraintSystem<E>, M>(
END FUNCTION.
*/
fn blake2s_compression<E: Engine, CS: ConstraintSystem<E>>(
mut cs: CS,
h: &mut [UInt32],
m: &[UInt32],
t: u64,
f: bool
) -> Result<(), SynthesisError>
{
f: bool,
) -> Result<(), SynthesisError> {
assert_eq!(h.len(), 8);
assert_eq!(m.len(), 16);
@@ -196,10 +198,16 @@ fn blake2s_compression<E: Engine, CS: ConstraintSystem<E>>(
assert_eq!(v.len(), 16);
v[12] = v[12].xor(cs.namespace(|| "first xor"), &UInt32::constant(t as u32))?;
v[13] = v[13].xor(cs.namespace(|| "second xor"), &UInt32::constant((t >> 32) as u32))?;
v[13] = v[13].xor(
cs.namespace(|| "second xor"),
&UInt32::constant((t >> 32) as u32),
)?;
if f {
v[14] = v[14].xor(cs.namespace(|| "third xor"), &UInt32::constant(u32::max_value()))?;
v[14] = v[14].xor(
cs.namespace(|| "third xor"),
&UInt32::constant(u32::max_value()),
)?;
}
{
@@ -210,20 +218,92 @@ fn blake2s_compression<E: Engine, CS: ConstraintSystem<E>>(
let s = SIGMA[i % 10];
mixing_g(cs.namespace(|| "mixing invocation 1"), &mut v, 0, 4, 8, 12, &m[s[ 0]], &m[s[ 1]])?;
mixing_g(cs.namespace(|| "mixing invocation 2"), &mut v, 1, 5, 9, 13, &m[s[ 2]], &m[s[ 3]])?;
mixing_g(cs.namespace(|| "mixing invocation 3"), &mut v, 2, 6, 10, 14, &m[s[ 4]], &m[s[ 5]])?;
mixing_g(cs.namespace(|| "mixing invocation 4"), &mut v, 3, 7, 11, 15, &m[s[ 6]], &m[s[ 7]])?;
mixing_g(
cs.namespace(|| "mixing invocation 1"),
&mut v,
0,
4,
8,
12,
&m[s[0]],
&m[s[1]],
)?;
mixing_g(
cs.namespace(|| "mixing invocation 2"),
&mut v,
1,
5,
9,
13,
&m[s[2]],
&m[s[3]],
)?;
mixing_g(
cs.namespace(|| "mixing invocation 3"),
&mut v,
2,
6,
10,
14,
&m[s[4]],
&m[s[5]],
)?;
mixing_g(
cs.namespace(|| "mixing invocation 4"),
&mut v,
3,
7,
11,
15,
&m[s[6]],
&m[s[7]],
)?;
mixing_g(cs.namespace(|| "mixing invocation 5"), &mut v, 0, 5, 10, 15, &m[s[ 8]], &m[s[ 9]])?;
mixing_g(cs.namespace(|| "mixing invocation 6"), &mut v, 1, 6, 11, 12, &m[s[10]], &m[s[11]])?;
mixing_g(cs.namespace(|| "mixing invocation 7"), &mut v, 2, 7, 8, 13, &m[s[12]], &m[s[13]])?;
mixing_g(cs.namespace(|| "mixing invocation 8"), &mut v, 3, 4, 9, 14, &m[s[14]], &m[s[15]])?;
mixing_g(
cs.namespace(|| "mixing invocation 5"),
&mut v,
0,
5,
10,
15,
&m[s[8]],
&m[s[9]],
)?;
mixing_g(
cs.namespace(|| "mixing invocation 6"),
&mut v,
1,
6,
11,
12,
&m[s[10]],
&m[s[11]],
)?;
mixing_g(
cs.namespace(|| "mixing invocation 7"),
&mut v,
2,
7,
8,
13,
&m[s[12]],
&m[s[13]],
)?;
mixing_g(
cs.namespace(|| "mixing invocation 8"),
&mut v,
3,
4,
9,
14,
&m[s[14]],
&m[s[15]],
)?;
}
}
for i in 0..8 {
let mut cs = cs.namespace(|| format!("h[{i}] ^ v[{i}] ^ v[{i} + 8]", i=i));
let mut cs = cs.namespace(|| format!("h[{i}] ^ v[{i}] ^ v[{i} + 8]", i = i));
h[i] = h[i].xor(cs.namespace(|| "first xor"), &v[i])?;
h[i] = h[i].xor(cs.namespace(|| "second xor"), &v[i + 8])?;
@@ -262,9 +342,8 @@ fn blake2s_compression<E: Engine, CS: ConstraintSystem<E>>(
pub fn blake2s<E: Engine, CS: ConstraintSystem<E>>(
mut cs: CS,
input: &[Boolean],
personalization: &[u8]
) -> Result<Vec<Boolean>, SynthesisError>
{
personalization: &[u8],
) -> Result<Vec<Boolean>, SynthesisError> {
use byteorder::{ByteOrder, LittleEndian};
assert_eq!(personalization.len(), 8);
@@ -279,8 +358,12 @@ pub fn blake2s<E: Engine, CS: ConstraintSystem<E>>(
h.push(UInt32::constant(0x9B05688C));
// Personalization is stored here
h.push(UInt32::constant(0x1F83D9AB ^ LittleEndian::read_u32(&personalization[0..4])));
h.push(UInt32::constant(0x5BE0CD19 ^ LittleEndian::read_u32(&personalization[4..8])));
h.push(UInt32::constant(
0x1F83D9AB ^ LittleEndian::read_u32(&personalization[0..4]),
));
h.push(UInt32::constant(
0x5BE0CD19 ^ LittleEndian::read_u32(&personalization[4..8]),
));
let mut blocks: Vec<Vec<UInt32>> = vec![];
@@ -312,7 +395,13 @@ pub fn blake2s<E: Engine, CS: ConstraintSystem<E>>(
{
let cs = cs.namespace(|| "final block");
blake2s_compression(cs, &mut h, &blocks[blocks.len() - 1], (input.len() / 8) as u64, true)?;
blake2s_compression(
cs,
&mut h,
&blocks[blocks.len() - 1],
(input.len() / 8) as u64,
true,
)?;
}
Ok(h.iter().flat_map(|b| b.into_bits()).collect())
@@ -321,14 +410,14 @@ pub fn blake2s<E: Engine, CS: ConstraintSystem<E>>(
#[cfg(test)]
mod test {
use blake2s_simd::Params as Blake2sParams;
use pairing::bls12_381::{Bls12};
use pairing::bls12_381::Bls12;
use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
use crate::gadgets::boolean::{Boolean, AllocatedBit};
use crate::gadgets::test::TestConstraintSystem;
use super::blake2s;
use crate::{ConstraintSystem};
use crate::gadgets::boolean::{AllocatedBit, Boolean};
use crate::gadgets::test::TestConstraintSystem;
use crate::ConstraintSystem;
#[test]
fn test_blank_hash() {
@@ -356,7 +445,13 @@ mod test {
#[test]
fn test_blake2s_constraints() {
let mut cs = TestConstraintSystem::<Bls12>::new();
let input_bits: Vec<_> = (0..512).map(|i| AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true)).unwrap().into()).collect();
let input_bits: Vec<_> = (0..512)
.map(|i| {
AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true))
.unwrap()
.into()
})
.collect();
blake2s(&mut cs, &input_bits, b"12345678").unwrap();
assert!(cs.is_satisfied());
assert_eq!(cs.num_constraints(), 21518);
@@ -369,14 +464,17 @@ mod test {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let input_bits: Vec<_> = (0..512)
.map(|_| Boolean::constant(rng.next_u32() % 2 != 0))
.chain((0..512)
.map(|i| AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true)).unwrap().into()))
.collect();
.map(|_| Boolean::constant(rng.next_u32() % 2 != 0))
.chain((0..512).map(|i| {
AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true))
.unwrap()
.into()
}))
.collect();
blake2s(&mut cs, &input_bits, b"12345678").unwrap();
assert!(cs.is_satisfied());
assert_eq!(cs.num_constraints(), 21518);
@@ -386,10 +484,12 @@ mod test {
fn test_blake2s_constant_constraints() {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let input_bits: Vec<_> = (0..512).map(|_| Boolean::constant(rng.next_u32() % 2 != 0)).collect();
let input_bits: Vec<_> = (0..512)
.map(|_| Boolean::constant(rng.next_u32() % 2 != 0))
.collect();
blake2s(&mut cs, &input_bits, b"12345678").unwrap();
assert_eq!(cs.num_constraints(), 0);
}
@@ -397,13 +497,15 @@ mod test {
#[test]
fn test_blake2s() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0))
{
let mut h = Blake2sParams::new().hash_length(32).personal(b"12345678").to_state();
for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0)) {
let mut h = Blake2sParams::new()
.hash_length(32)
.personal(b"12345678")
.to_state();
let data: Vec<u8> = (0..input_len).map(|_| rng.next_u32() as u8).collect();
@@ -419,7 +521,11 @@ mod test {
for bit_i in 0..8 {
let cs = cs.namespace(|| format!("input bit {} {}", byte_i, bit_i));
input_bits.push(AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)).unwrap().into());
input_bits.push(
AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8))
.unwrap()
.into(),
);
}
}
@@ -427,17 +533,19 @@ mod test {
assert!(cs.is_satisfied());
let mut s = hash_result.as_ref().iter()
.flat_map(|&byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8));
let mut s = hash_result
.as_ref()
.iter()
.flat_map(|&byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8));
for b in r {
match b {
Boolean::Is(b) => {
assert!(s.next().unwrap() == b.get_value().unwrap());
},
}
Boolean::Not(b) => {
assert!(s.next().unwrap() != b.get_value().unwrap());
},
}
Boolean::Constant(b) => {
assert!(input_len == 0);
assert!(s.next().unwrap() == b);
File diff suppressed because it is too large Load Diff
+95 -98
View File
@@ -1,23 +1,15 @@
use ff::Field;
use pairing::Engine;
use super::*;
use super::num::{
AllocatedNum,
Num
};
use super::boolean::Boolean;
use crate::{
ConstraintSystem
};
use super::num::{AllocatedNum, Num};
use super::*;
use crate::ConstraintSystem;
// Synthesize the constants for each base pattern.
fn synth<'a, E: Engine, I>(
window_size: usize,
constants: I,
assignment: &mut [E::Fr]
)
where I: IntoIterator<Item=&'a E::Fr>
fn synth<'a, E: Engine, I>(window_size: usize, constants: I, assignment: &mut [E::Fr])
where
I: IntoIterator<Item = &'a E::Fr>,
{
assert_eq!(assignment.len(), 1 << window_size);
@@ -39,16 +31,20 @@ fn synth<'a, E: Engine, I>(
pub fn lookup3_xy<E: Engine, CS>(
mut cs: CS,
bits: &[Boolean],
coords: &[(E::Fr, E::Fr)]
coords: &[(E::Fr, E::Fr)],
) -> Result<(AllocatedNum<E>, AllocatedNum<E>), SynthesisError>
where CS: ConstraintSystem<E>
where
CS: ConstraintSystem<E>,
{
assert_eq!(bits.len(), 3);
assert_eq!(coords.len(), 8);
// Calculate the index into `coords`
let i =
match (bits[0].get_value(), bits[1].get_value(), bits[2].get_value()) {
let i = match (
bits[0].get_value(),
bits[1].get_value(),
bits[2].get_value(),
) {
(Some(a_value), Some(b_value), Some(c_value)) => {
let mut tmp = 0;
if a_value {
@@ -61,25 +57,15 @@ pub fn lookup3_xy<E: Engine, CS>(
tmp += 4;
}
Some(tmp)
},
_ => None
}
_ => None,
};
// Allocate the x-coordinate resulting from the lookup
let res_x = AllocatedNum::alloc(
cs.namespace(|| "x"),
|| {
Ok(coords[*i.get()?].0)
}
)?;
let res_x = AllocatedNum::alloc(cs.namespace(|| "x"), || Ok(coords[*i.get()?].0))?;
// Allocate the y-coordinate resulting from the lookup
let res_y = AllocatedNum::alloc(
cs.namespace(|| "y"),
|| {
Ok(coords[*i.get()?].1)
}
)?;
let res_y = AllocatedNum::alloc(cs.namespace(|| "y"), || Ok(coords[*i.get()?].1))?;
// Compute the coefficients for the lookup constraints
let mut x_coeffs = [E::Fr::zero(); 8];
@@ -93,30 +79,38 @@ pub fn lookup3_xy<E: Engine, CS>(
cs.enforce(
|| "x-coordinate lookup",
|lc| lc + (x_coeffs[0b001], one)
|lc| {
lc + (x_coeffs[0b001], one)
+ &bits[1].lc::<E>(one, x_coeffs[0b011])
+ &bits[2].lc::<E>(one, x_coeffs[0b101])
+ &precomp.lc::<E>(one, x_coeffs[0b111]),
+ &precomp.lc::<E>(one, x_coeffs[0b111])
},
|lc| lc + &bits[0].lc::<E>(one, E::Fr::one()),
|lc| lc + res_x.get_variable()
|lc| {
lc + res_x.get_variable()
- (x_coeffs[0b000], one)
- &bits[1].lc::<E>(one, x_coeffs[0b010])
- &bits[2].lc::<E>(one, x_coeffs[0b100])
- &precomp.lc::<E>(one, x_coeffs[0b110]),
- &precomp.lc::<E>(one, x_coeffs[0b110])
},
);
cs.enforce(
|| "y-coordinate lookup",
|lc| lc + (y_coeffs[0b001], one)
|lc| {
lc + (y_coeffs[0b001], one)
+ &bits[1].lc::<E>(one, y_coeffs[0b011])
+ &bits[2].lc::<E>(one, y_coeffs[0b101])
+ &precomp.lc::<E>(one, y_coeffs[0b111]),
+ &precomp.lc::<E>(one, y_coeffs[0b111])
},
|lc| lc + &bits[0].lc::<E>(one, E::Fr::one()),
|lc| lc + res_y.get_variable()
|lc| {
lc + res_y.get_variable()
- (y_coeffs[0b000], one)
- &bits[1].lc::<E>(one, y_coeffs[0b010])
- &bits[2].lc::<E>(one, y_coeffs[0b100])
- &precomp.lc::<E>(one, y_coeffs[0b110]),
- &precomp.lc::<E>(one, y_coeffs[0b110])
},
);
Ok((res_x, res_y))
@@ -127,16 +121,16 @@ pub fn lookup3_xy<E: Engine, CS>(
pub fn lookup3_xy_with_conditional_negation<E: Engine, CS>(
mut cs: CS,
bits: &[Boolean],
coords: &[(E::Fr, E::Fr)]
coords: &[(E::Fr, E::Fr)],
) -> Result<(Num<E>, Num<E>), SynthesisError>
where CS: ConstraintSystem<E>
where
CS: ConstraintSystem<E>,
{
assert_eq!(bits.len(), 3);
assert_eq!(coords.len(), 4);
// Calculate the index into `coords`
let i =
match (bits[0].get_value(), bits[1].get_value()) {
let i = match (bits[0].get_value(), bits[1].get_value()) {
(Some(a_value), Some(b_value)) => {
let mut tmp = 0;
if a_value {
@@ -146,22 +140,19 @@ pub fn lookup3_xy_with_conditional_negation<E: Engine, CS>(
tmp += 2;
}
Some(tmp)
},
_ => None
}
_ => None,
};
// Allocate the y-coordinate resulting from the lookup
// and conditional negation
let y = AllocatedNum::alloc(
cs.namespace(|| "y"),
|| {
let mut tmp = coords[*i.get()?].1;
if *bits[2].get_value().get()? {
tmp.negate();
}
Ok(tmp)
let y = AllocatedNum::alloc(cs.namespace(|| "y"), || {
let mut tmp = coords[*i.get()?].1;
if *bits[2].get_value().get()? {
tmp.negate();
}
)?;
Ok(tmp)
})?;
let one = CS::one();
@@ -174,21 +165,21 @@ pub fn lookup3_xy_with_conditional_negation<E: Engine, CS>(
let precomp = Boolean::and(cs.namespace(|| "precomp"), &bits[0], &bits[1])?;
let x = Num::zero()
.add_bool_with_coeff(one, &Boolean::constant(true), x_coeffs[0b00])
.add_bool_with_coeff(one, &bits[0], x_coeffs[0b01])
.add_bool_with_coeff(one, &bits[1], x_coeffs[0b10])
.add_bool_with_coeff(one, &precomp, x_coeffs[0b11]);
.add_bool_with_coeff(one, &Boolean::constant(true), x_coeffs[0b00])
.add_bool_with_coeff(one, &bits[0], x_coeffs[0b01])
.add_bool_with_coeff(one, &bits[1], x_coeffs[0b10])
.add_bool_with_coeff(one, &precomp, x_coeffs[0b11]);
let y_lc = precomp.lc::<E>(one, y_coeffs[0b11]) +
&bits[1].lc::<E>(one, y_coeffs[0b10]) +
&bits[0].lc::<E>(one, y_coeffs[0b01]) +
(y_coeffs[0b00], one);
let y_lc = precomp.lc::<E>(one, y_coeffs[0b11])
+ &bits[1].lc::<E>(one, y_coeffs[0b10])
+ &bits[0].lc::<E>(one, y_coeffs[0b01])
+ (y_coeffs[0b00], one);
cs.enforce(
|| "y-coordinate lookup",
|lc| lc + &y_lc + &y_lc,
|lc| lc + &bits[2].lc::<E>(one, E::Fr::one()),
|lc| lc + &y_lc - y.get_variable()
|lc| lc + &y_lc - y.get_variable(),
);
Ok((x, y.into()))
@@ -197,8 +188,8 @@ pub fn lookup3_xy_with_conditional_negation<E: Engine, CS>(
#[cfg(test)]
mod test {
use super::*;
use crate::gadgets::boolean::{AllocatedBit, Boolean};
use crate::gadgets::test::*;
use crate::gadgets::boolean::{Boolean, AllocatedBit};
use pairing::bls12_381::{Bls12, Fr};
use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
@@ -206,40 +197,42 @@ mod test {
#[test]
fn test_lookup3_xy() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
for _ in 0..100 {
let mut cs = TestConstraintSystem::<Bls12>::new();
let a_val = rng.next_u32() % 2 != 0;
let a = Boolean::from(
AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap()
);
let a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap());
let b_val = rng.next_u32() % 2 != 0;
let b = Boolean::from(
AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap()
);
let b = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap());
let c_val = rng.next_u32() % 2 != 0;
let c = Boolean::from(
AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap()
);
let c = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap());
let bits = vec![a, b, c];
let points: Vec<(Fr, Fr)> = (0..8).map(|_| (Fr::random(&mut rng), Fr::random(&mut rng))).collect();
let points: Vec<(Fr, Fr)> = (0..8)
.map(|_| (Fr::random(&mut rng), Fr::random(&mut rng)))
.collect();
let res = lookup3_xy(&mut cs, &bits, &points).unwrap();
assert!(cs.is_satisfied());
let mut index = 0;
if a_val { index += 1 }
if b_val { index += 2 }
if c_val { index += 4 }
if a_val {
index += 1
}
if b_val {
index += 2
}
if c_val {
index += 4
}
assert_eq!(res.0.get_value().unwrap(), points[index].0);
assert_eq!(res.1.get_value().unwrap(), points[index].1);
@@ -249,43 +242,45 @@ mod test {
#[test]
fn test_lookup3_xy_with_conditional_negation() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
for _ in 0..100 {
let mut cs = TestConstraintSystem::<Bls12>::new();
let a_val = rng.next_u32() % 2 != 0;
let a = Boolean::from(
AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap()
);
let a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap());
let b_val = rng.next_u32() % 2 != 0;
let b = Boolean::from(
AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap()
);
let b = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap());
let c_val = rng.next_u32() % 2 != 0;
let c = Boolean::from(
AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap()
);
let c = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap());
let bits = vec![a, b, c];
let points: Vec<(Fr, Fr)> = (0..4).map(|_| (Fr::random(&mut rng), Fr::random(&mut rng))).collect();
let points: Vec<(Fr, Fr)> = (0..4)
.map(|_| (Fr::random(&mut rng), Fr::random(&mut rng)))
.collect();
let res = lookup3_xy_with_conditional_negation(&mut cs, &bits, &points).unwrap();
assert!(cs.is_satisfied());
let mut index = 0;
if a_val { index += 1 }
if b_val { index += 2 }
if a_val {
index += 1
}
if b_val {
index += 2
}
assert_eq!(res.0.get_value().unwrap(), points[index].0);
let mut tmp = points[index].1;
if c_val { tmp.negate() }
if c_val {
tmp.negate()
}
assert_eq!(res.1.get_value().unwrap(), tmp);
}
}
@@ -293,14 +288,16 @@ mod test {
#[test]
fn test_synth() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let window_size = 4;
let mut assignment = vec![Fr::zero(); 1 << window_size];
let constants: Vec<_> = (0..(1 << window_size)).map(|_| Fr::random(&mut rng)).collect();
let constants: Vec<_> = (0..(1 << window_size))
.map(|_| Fr::random(&mut rng))
.collect();
synth::<Bls12, _>(window_size, &constants, &mut assignment);
+31 -45
View File
@@ -1,14 +1,9 @@
use ff::{Field, PrimeField};
use pairing::Engine;
use crate::{
SynthesisError,
ConstraintSystem,
LinearCombination,
Variable
};
use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable};
pub struct MultiEq<E: Engine, CS: ConstraintSystem<E>>{
pub struct MultiEq<E: Engine, CS: ConstraintSystem<E>> {
cs: CS,
ops: usize,
bits_used: usize,
@@ -23,12 +18,11 @@ impl<E: Engine, CS: ConstraintSystem<E>> MultiEq<E, CS> {
ops: 0,
bits_used: 0,
lhs: LinearCombination::zero(),
rhs: LinearCombination::zero()
rhs: LinearCombination::zero(),
}
}
fn accumulate(&mut self)
{
fn accumulate(&mut self) {
let ops = self.ops;
let lhs = self.lhs.clone();
let rhs = self.rhs.clone();
@@ -36,7 +30,7 @@ impl<E: Engine, CS: ConstraintSystem<E>> MultiEq<E, CS> {
|| format!("multieq {}", ops),
|_| lhs,
|lc| lc + CS::one(),
|_| rhs
|_| rhs,
);
self.lhs = LinearCombination::zero();
self.rhs = LinearCombination::zero();
@@ -48,9 +42,8 @@ impl<E: Engine, CS: ConstraintSystem<E>> MultiEq<E, CS> {
&mut self,
num_bits: usize,
lhs: &LinearCombination<E>,
rhs: &LinearCombination<E>
)
{
rhs: &LinearCombination<E>,
) {
// Check if we will exceed the capacity
if (E::Fr::CAPACITY as usize) <= (self.bits_used + num_bits) {
self.accumulate();
@@ -68,67 +61,60 @@ impl<E: Engine, CS: ConstraintSystem<E>> MultiEq<E, CS> {
impl<E: Engine, CS: ConstraintSystem<E>> Drop for MultiEq<E, CS> {
fn drop(&mut self) {
if self.bits_used > 0 {
self.accumulate();
self.accumulate();
}
}
}
impl<E: Engine, CS: ConstraintSystem<E>> ConstraintSystem<E> for MultiEq<E, CS>
{
impl<E: Engine, CS: ConstraintSystem<E>> ConstraintSystem<E> for MultiEq<E, CS> {
type Root = Self;
fn one() -> Variable {
CS::one()
}
fn alloc<F, A, AR>(
&mut self,
annotation: A,
f: F
) -> Result<Variable, SynthesisError>
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
fn alloc<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
self.cs.alloc(annotation, f)
}
fn alloc_input<F, A, AR>(
&mut self,
annotation: A,
f: F
) -> Result<Variable, SynthesisError>
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
fn alloc_input<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
self.cs.alloc_input(annotation, f)
}
fn enforce<A, AR, LA, LB, LC>(
&mut self,
annotation: A,
a: LA,
b: LB,
c: LC
)
where A: FnOnce() -> AR, AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>
fn enforce<A, AR, LA, LB, LC>(&mut self, annotation: A, a: LA, b: LB, c: LC)
where
A: FnOnce() -> AR,
AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
{
self.cs.enforce(annotation, a, b, c)
}
fn push_namespace<NR, N>(&mut self, name_fn: N)
where NR: Into<String>, N: FnOnce() -> NR
where
NR: Into<String>,
N: FnOnce() -> NR,
{
self.cs.get_root().push_namespace(name_fn)
}
fn pop_namespace(&mut self)
{
fn pop_namespace(&mut self) {
self.cs.get_root().pop_namespace()
}
fn get_root(&mut self) -> &mut Self::Root
{
fn get_root(&mut self) -> &mut Self::Root {
self
}
}
+35 -44
View File
@@ -1,20 +1,18 @@
use ff::{Field, PrimeField};
use pairing::Engine;
use crate::{ConstraintSystem, SynthesisError};
use super::boolean::{Boolean};
use super::boolean::Boolean;
use super::num::Num;
use super::Assignment;
use crate::{ConstraintSystem, SynthesisError};
use ff::{Field, PrimeField};
use pairing::Engine;
/// Takes a sequence of booleans and exposes them as compact
/// public inputs
pub fn pack_into_inputs<E, CS>(
mut cs: CS,
bits: &[Boolean]
) -> Result<(), SynthesisError>
where E: Engine, CS: ConstraintSystem<E>
pub fn pack_into_inputs<E, CS>(mut cs: CS, bits: &[Boolean]) -> Result<(), SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
{
for (i, bits) in bits.chunks(E::Fr::CAPACITY as usize).enumerate()
{
for (i, bits) in bits.chunks(E::Fr::CAPACITY as usize).enumerate() {
let mut num = Num::<E>::zero();
let mut coeff = E::Fr::one();
for bit in bits {
@@ -23,44 +21,38 @@ pub fn pack_into_inputs<E, CS>(
coeff.double();
}
let input = cs.alloc_input(|| format!("input {}", i), || {
Ok(*num.get_value().get()?)
})?;
let input = cs.alloc_input(|| format!("input {}", i), || Ok(*num.get_value().get()?))?;
// num * 1 = input
cs.enforce(
|| format!("packing constraint {}", i),
|_| num.lc(E::Fr::one()),
|lc| lc + CS::one(),
|lc| lc + input
|lc| lc + input,
);
}
Ok(())
}
pub fn bytes_to_bits(bytes: &[u8]) -> Vec<bool>
{
bytes.iter()
.flat_map(|&v| (0..8).rev().map(move |i| (v >> i) & 1 == 1))
.collect()
pub fn bytes_to_bits(bytes: &[u8]) -> Vec<bool> {
bytes
.iter()
.flat_map(|&v| (0..8).rev().map(move |i| (v >> i) & 1 == 1))
.collect()
}
pub fn bytes_to_bits_le(bytes: &[u8]) -> Vec<bool>
{
bytes.iter()
.flat_map(|&v| (0..8).map(move |i| (v >> i) & 1 == 1))
.collect()
pub fn bytes_to_bits_le(bytes: &[u8]) -> Vec<bool> {
bytes
.iter()
.flat_map(|&v| (0..8).map(move |i| (v >> i) & 1 == 1))
.collect()
}
pub fn compute_multipacking<E: Engine>(
bits: &[bool]
) -> Vec<E::Fr>
{
pub fn compute_multipacking<E: Engine>(bits: &[bool]) -> Vec<E::Fr> {
let mut result = vec![];
for bits in bits.chunks(E::Fr::CAPACITY as usize)
{
for bits in bits.chunks(E::Fr::CAPACITY as usize) {
let mut cur = E::Fr::zero();
let mut coeff = E::Fr::one();
@@ -80,13 +72,13 @@ pub fn compute_multipacking<E: Engine>(
#[test]
fn test_multipacking() {
use crate::{ConstraintSystem};
use pairing::bls12_381::{Bls12};
use crate::ConstraintSystem;
use pairing::bls12_381::Bls12;
use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
use crate::gadgets::test::*;
use super::boolean::{AllocatedBit, Boolean};
use crate::gadgets::test::*;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
@@ -98,16 +90,15 @@ fn test_multipacking() {
let bits: Vec<bool> = (0..num_bits).map(|_| rng.next_u32() % 2 != 0).collect();
let circuit_bits = bits.iter().enumerate()
.map(|(i, &b)| {
Boolean::from(
AllocatedBit::alloc(
cs.namespace(|| format!("bit {}", i)),
Some(b)
).unwrap()
)
})
.collect::<Vec<_>>();
let circuit_bits = bits
.iter()
.enumerate()
.map(|(i, &b)| {
Boolean::from(
AllocatedBit::alloc(cs.namespace(|| format!("bit {}", i)), Some(b)).unwrap(),
)
})
.collect::<Vec<_>>();
let expected_inputs = compute_multipacking::<Bls12>(&bits);
+126 -163
View File
@@ -1,78 +1,61 @@
use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr};
use pairing::Engine;
use crate::{
SynthesisError,
ConstraintSystem,
LinearCombination,
Variable
};
use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable};
use super::{
Assignment
};
use super::Assignment;
use super::boolean::{
self,
Boolean,
AllocatedBit
};
use super::boolean::{self, AllocatedBit, Boolean};
pub struct AllocatedNum<E: Engine> {
value: Option<E::Fr>,
variable: Variable
variable: Variable,
}
impl<E: Engine> Clone for AllocatedNum<E> {
fn clone(&self) -> Self {
AllocatedNum {
value: self.value,
variable: self.variable
variable: self.variable,
}
}
}
impl<E: Engine> AllocatedNum<E> {
pub fn alloc<CS, F>(
mut cs: CS,
value: F,
) -> Result<Self, SynthesisError>
where CS: ConstraintSystem<E>,
F: FnOnce() -> Result<E::Fr, SynthesisError>
pub fn alloc<CS, F>(mut cs: CS, value: F) -> Result<Self, SynthesisError>
where
CS: ConstraintSystem<E>,
F: FnOnce() -> Result<E::Fr, SynthesisError>,
{
let mut new_value = None;
let var = cs.alloc(|| "num", || {
let tmp = value()?;
let var = cs.alloc(
|| "num",
|| {
let tmp = value()?;
new_value = Some(tmp);
new_value = Some(tmp);
Ok(tmp)
})?;
Ok(tmp)
},
)?;
Ok(AllocatedNum {
value: new_value,
variable: var
variable: var,
})
}
pub fn inputize<CS>(
&self,
mut cs: CS
) -> Result<(), SynthesisError>
where CS: ConstraintSystem<E>
pub fn inputize<CS>(&self, mut cs: CS) -> Result<(), SynthesisError>
where
CS: ConstraintSystem<E>,
{
let input = cs.alloc_input(
|| "input variable",
|| {
Ok(*self.value.get()?)
}
)?;
let input = cs.alloc_input(|| "input variable", || Ok(*self.value.get()?))?;
cs.enforce(
|| "enforce input is correct",
|lc| lc + input,
|lc| lc + CS::one(),
|lc| lc + self.variable
|lc| lc + self.variable,
);
Ok(())
@@ -83,18 +66,17 @@ impl<E: Engine> AllocatedNum<E> {
/// order, requiring that the representation
/// strictly exists "in the field" (i.e., a
/// congruency is not allowed.)
pub fn into_bits_le_strict<CS>(
&self,
mut cs: CS
) -> Result<Vec<Boolean>, SynthesisError>
where CS: ConstraintSystem<E>
pub fn into_bits_le_strict<CS>(&self, mut cs: CS) -> Result<Vec<Boolean>, SynthesisError>
where
CS: ConstraintSystem<E>,
{
pub fn kary_and<E, CS>(
mut cs: CS,
v: &[AllocatedBit]
v: &[AllocatedBit],
) -> Result<AllocatedBit, SynthesisError>
where E: Engine,
CS: ConstraintSystem<E>
where
E: Engine,
CS: ConstraintSystem<E>,
{
assert!(v.len() > 0);
@@ -109,7 +91,7 @@ impl<E: Engine> AllocatedNum<E> {
cur = Some(AllocatedBit::and(
cs.namespace(|| format!("and {}", i)),
cur.as_ref().unwrap(),
v
v,
)?);
}
}
@@ -145,10 +127,7 @@ impl<E: Engine> AllocatedNum<E> {
if b {
// This is part of a run of ones. Let's just
// allocate the boolean with the expected value.
let a_bit = AllocatedBit::alloc(
cs.namespace(|| format!("bit {}", i)),
a_bit
)?;
let a_bit = AllocatedBit::alloc(cs.namespace(|| format!("bit {}", i)), a_bit)?;
// ... and add it to the current run of ones.
current_run.push(a_bit.clone());
result.push(a_bit);
@@ -162,7 +141,7 @@ impl<E: Engine> AllocatedNum<E> {
}
last_run = Some(kary_and(
cs.namespace(|| format!("run ending at {}", i)),
&current_run
&current_run,
)?);
current_run.truncate(0);
}
@@ -175,7 +154,7 @@ impl<E: Engine> AllocatedNum<E> {
let a_bit = AllocatedBit::alloc_conditionally(
cs.namespace(|| format!("bit {}", i)),
a_bit,
&last_run.as_ref().expect("char always starts with a one")
&last_run.as_ref().expect("char always starts with a one"),
)?;
result.push(a_bit);
}
@@ -201,12 +180,7 @@ impl<E: Engine> AllocatedNum<E> {
lc = lc - self.variable;
cs.enforce(
|| "unpacking constraint",
|lc| lc,
|lc| lc,
|_| lc
);
cs.enforce(|| "unpacking constraint", |lc| lc, |lc| lc, |_| lc);
// Convert into booleans, and reverse for little-endian bit order
Ok(result.into_iter().map(|b| Boolean::from(b)).rev().collect())
@@ -215,16 +189,11 @@ impl<E: Engine> AllocatedNum<E> {
/// Convert the allocated number into its little-endian representation.
/// Note that this does not strongly enforce that the commitment is
/// "in the field."
pub fn into_bits_le<CS>(
&self,
mut cs: CS
) -> Result<Vec<Boolean>, SynthesisError>
where CS: ConstraintSystem<E>
pub fn into_bits_le<CS>(&self, mut cs: CS) -> Result<Vec<Boolean>, SynthesisError>
where
CS: ConstraintSystem<E>,
{
let bits = boolean::field_into_allocated_bits_le(
&mut cs,
self.value
)?;
let bits = boolean::field_into_allocated_bits_le(&mut cs, self.value)?;
let mut lc = LinearCombination::zero();
let mut coeff = E::Fr::one();
@@ -237,94 +206,91 @@ impl<E: Engine> AllocatedNum<E> {
lc = lc - self.variable;
cs.enforce(
|| "unpacking constraint",
|lc| lc,
|lc| lc,
|_| lc
);
cs.enforce(|| "unpacking constraint", |lc| lc, |lc| lc, |_| lc);
Ok(bits.into_iter().map(|b| Boolean::from(b)).collect())
}
pub fn mul<CS>(
&self,
mut cs: CS,
other: &Self
) -> Result<Self, SynthesisError>
where CS: ConstraintSystem<E>
pub fn mul<CS>(&self, mut cs: CS, other: &Self) -> Result<Self, SynthesisError>
where
CS: ConstraintSystem<E>,
{
let mut value = None;
let var = cs.alloc(|| "product num", || {
let mut tmp = *self.value.get()?;
tmp.mul_assign(other.value.get()?);
let var = cs.alloc(
|| "product num",
|| {
let mut tmp = *self.value.get()?;
tmp.mul_assign(other.value.get()?);
value = Some(tmp);
value = Some(tmp);
Ok(tmp)
})?;
Ok(tmp)
},
)?;
// Constrain: a * b = ab
cs.enforce(
|| "multiplication constraint",
|lc| lc + self.variable,
|lc| lc + other.variable,
|lc| lc + var
|lc| lc + var,
);
Ok(AllocatedNum {
value: value,
variable: var
variable: var,
})
}
pub fn square<CS>(
&self,
mut cs: CS
) -> Result<Self, SynthesisError>
where CS: ConstraintSystem<E>
pub fn square<CS>(&self, mut cs: CS) -> Result<Self, SynthesisError>
where
CS: ConstraintSystem<E>,
{
let mut value = None;
let var = cs.alloc(|| "squared num", || {
let mut tmp = *self.value.get()?;
tmp.square();
let var = cs.alloc(
|| "squared num",
|| {
let mut tmp = *self.value.get()?;
tmp.square();
value = Some(tmp);
value = Some(tmp);
Ok(tmp)
})?;
Ok(tmp)
},
)?;
// Constrain: a * a = aa
cs.enforce(
|| "squaring constraint",
|lc| lc + self.variable,
|lc| lc + self.variable,
|lc| lc + var
|lc| lc + var,
);
Ok(AllocatedNum {
value: value,
variable: var
variable: var,
})
}
pub fn assert_nonzero<CS>(
&self,
mut cs: CS
) -> Result<(), SynthesisError>
where CS: ConstraintSystem<E>
pub fn assert_nonzero<CS>(&self, mut cs: CS) -> Result<(), SynthesisError>
where
CS: ConstraintSystem<E>,
{
let inv = cs.alloc(|| "ephemeral inverse", || {
let tmp = *self.value.get()?;
if tmp.is_zero() {
Err(SynthesisError::DivisionByZero)
} else {
Ok(tmp.inverse().unwrap())
}
})?;
let inv = cs.alloc(
|| "ephemeral inverse",
|| {
let tmp = *self.value.get()?;
if tmp.is_zero() {
Err(SynthesisError::DivisionByZero)
} else {
Ok(tmp.inverse().unwrap())
}
},
)?;
// Constrain a * inv = 1, which is only valid
// iff a has a multiplicative inverse, untrue
@@ -333,7 +299,7 @@ impl<E: Engine> AllocatedNum<E> {
|| "nonzero assertion constraint",
|lc| lc + self.variable,
|lc| lc + inv,
|lc| lc + CS::one()
|lc| lc + CS::one(),
);
Ok(())
@@ -346,44 +312,39 @@ impl<E: Engine> AllocatedNum<E> {
mut cs: CS,
a: &Self,
b: &Self,
condition: &Boolean
condition: &Boolean,
) -> Result<(Self, Self), SynthesisError>
where CS: ConstraintSystem<E>
where
CS: ConstraintSystem<E>,
{
let c = Self::alloc(
cs.namespace(|| "conditional reversal result 1"),
|| {
if *condition.get_value().get()? {
Ok(*b.value.get()?)
} else {
Ok(*a.value.get()?)
}
let c = Self::alloc(cs.namespace(|| "conditional reversal result 1"), || {
if *condition.get_value().get()? {
Ok(*b.value.get()?)
} else {
Ok(*a.value.get()?)
}
)?;
})?;
cs.enforce(
|| "first conditional reversal",
|lc| lc + a.variable - b.variable,
|_| condition.lc(CS::one(), E::Fr::one()),
|lc| lc + a.variable - c.variable
|lc| lc + a.variable - c.variable,
);
let d = Self::alloc(
cs.namespace(|| "conditional reversal result 2"),
|| {
if *condition.get_value().get()? {
Ok(*a.value.get()?)
} else {
Ok(*b.value.get()?)
}
let d = Self::alloc(cs.namespace(|| "conditional reversal result 2"), || {
if *condition.get_value().get()? {
Ok(*a.value.get()?)
} else {
Ok(*b.value.get()?)
}
)?;
})?;
cs.enforce(
|| "second conditional reversal",
|lc| lc + b.variable - a.variable,
|_| condition.lc(CS::one(), E::Fr::one()),
|lc| lc + b.variable - d.variable
|lc| lc + b.variable - d.variable,
);
Ok((c, d))
@@ -400,14 +361,14 @@ impl<E: Engine> AllocatedNum<E> {
pub struct Num<E: Engine> {
value: Option<E::Fr>,
lc: LinearCombination<E>
lc: LinearCombination<E>,
}
impl<E: Engine> From<AllocatedNum<E>> for Num<E> {
fn from(num: AllocatedNum<E>) -> Num<E> {
Num {
value: num.value,
lc: LinearCombination::<E>::zero() + num.variable
lc: LinearCombination::<E>::zero() + num.variable,
}
}
}
@@ -416,7 +377,7 @@ impl<E: Engine> Num<E> {
pub fn zero() -> Self {
Num {
value: Some(E::Fr::zero()),
lc: LinearCombination::zero()
lc: LinearCombination::zero(),
}
}
@@ -428,13 +389,7 @@ impl<E: Engine> Num<E> {
LinearCombination::zero() + (coeff, &self.lc)
}
pub fn add_bool_with_coeff(
self,
one: Variable,
bit: &Boolean,
coeff: E::Fr
) -> Self
{
pub fn add_bool_with_coeff(self, one: Variable, bit: &Boolean, coeff: E::Fr) -> Self {
let newval = match (self.value, bit.get_value()) {
(Some(mut curval), Some(bval)) => {
if bval {
@@ -442,27 +397,27 @@ impl<E: Engine> Num<E> {
}
Some(curval)
},
_ => None
}
_ => None,
};
Num {
value: newval,
lc: self.lc + &bit.lc(one, coeff)
lc: self.lc + &bit.lc(one, coeff),
}
}
}
#[cfg(test)]
mod test {
use crate::{ConstraintSystem};
use crate::ConstraintSystem;
use ff::{BitIterator, Field, PrimeField};
use pairing::bls12_381::{Bls12, Fr};
use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng;
use crate::gadgets::test::*;
use super::{AllocatedNum, Boolean};
use crate::gadgets::test::*;
#[test]
fn test_allocated_num() {
@@ -491,8 +446,10 @@ mod test {
fn test_num_multiplication() {
let mut cs = TestConstraintSystem::<Bls12>::new();
let n = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::from_str("12").unwrap())).unwrap();
let n2 = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::from_str("10").unwrap())).unwrap();
let n =
AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::from_str("12").unwrap())).unwrap();
let n2 =
AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::from_str("10").unwrap())).unwrap();
let n3 = n.mul(&mut cs, &n2).unwrap();
assert!(cs.is_satisfied());
@@ -505,8 +462,8 @@ mod test {
#[test]
fn test_num_conditional_reversal() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
{
let mut cs = TestConstraintSystem::<Bls12>::new();
@@ -573,14 +530,17 @@ mod test {
cs.set("bit 254/boolean", Fr::one());
// this makes the conditional boolean constraint fail
assert_eq!(cs.which_is_unsatisfied().unwrap(), "bit 254/boolean constraint");
assert_eq!(
cs.which_is_unsatisfied().unwrap(),
"bit 254/boolean constraint"
);
}
#[test]
fn test_into_bits() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
for i in 0..200 {
@@ -597,7 +557,10 @@ mod test {
assert!(cs.is_satisfied());
for (b, a) in BitIterator::new(r.into_repr()).skip(1).zip(bits.iter().rev()) {
for (b, a) in BitIterator::new(r.into_repr())
.skip(1)
.zip(bits.iter().rev())
{
if let &Boolean::Is(ref a) = a {
assert_eq!(b, a.get_value().unwrap());
} else {
+95 -136
View File
@@ -1,6 +1,6 @@
use super::uint32::UInt32;
use super::multieq::MultiEq;
use super::boolean::Boolean;
use super::multieq::MultiEq;
use super::uint32::UInt32;
use crate::{ConstraintSystem, SynthesisError};
use pairing::Engine;
@@ -12,37 +12,35 @@ const ROUND_CONSTANTS: [u32; 64] = [
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
];
const IV: [u32; 8] = [
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
];
pub fn sha256_block_no_padding<E, CS>(
mut cs: CS,
input: &[Boolean]
input: &[Boolean],
) -> Result<Vec<Boolean>, SynthesisError>
where E: Engine, CS: ConstraintSystem<E>
where
E: Engine,
CS: ConstraintSystem<E>,
{
assert_eq!(input.len(), 512);
Ok(sha256_compression_function(
&mut cs,
&input,
&get_sha256_iv()
)?
.into_iter()
.flat_map(|e| e.into_bits_be())
.collect())
Ok(
sha256_compression_function(&mut cs, &input, &get_sha256_iv())?
.into_iter()
.flat_map(|e| e.into_bits_be())
.collect(),
)
}
pub fn sha256<E, CS>(
mut cs: CS,
input: &[Boolean]
) -> Result<Vec<Boolean>, SynthesisError>
where E: Engine, CS: ConstraintSystem<E>
pub fn sha256<E, CS>(mut cs: CS, input: &[Boolean]) -> Result<Vec<Boolean>, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
{
assert!(input.len() % 8 == 0);
@@ -62,16 +60,10 @@ pub fn sha256<E, CS>(
let mut cur = get_sha256_iv();
for (i, block) in padded.chunks(512).enumerate() {
cur = sha256_compression_function(
cs.namespace(|| format!("block {}", i)),
block,
&cur
)?;
cur = sha256_compression_function(cs.namespace(|| format!("block {}", i)), block, &cur)?;
}
Ok(cur.into_iter()
.flat_map(|e| e.into_bits_be())
.collect())
Ok(cur.into_iter().flat_map(|e| e.into_bits_be()).collect())
}
fn get_sha256_iv() -> Vec<UInt32> {
@@ -81,16 +73,19 @@ fn get_sha256_iv() -> Vec<UInt32> {
fn sha256_compression_function<E, CS>(
cs: CS,
input: &[Boolean],
current_hash_value: &[UInt32]
current_hash_value: &[UInt32],
) -> Result<Vec<UInt32>, SynthesisError>
where E: Engine, CS: ConstraintSystem<E>
where
E: Engine,
CS: ConstraintSystem<E>,
{
assert_eq!(input.len(), 512);
assert_eq!(current_hash_value.len(), 8);
let mut w = input.chunks(32)
.map(|e| UInt32::from_bits_be(e))
.collect::<Vec<_>>();
let mut w = input
.chunks(32)
.map(|e| UInt32::from_bits_be(e))
.collect::<Vec<_>>();
// We can save some constraints by combining some of
// the constraints in different u32 additions
@@ -100,30 +95,18 @@ fn sha256_compression_function<E, CS>(
let cs = &mut cs.namespace(|| format!("w extension {}", i));
// s0 := (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor (w[i-15] rightshift 3)
let mut s0 = w[i-15].rotr(7);
s0 = s0.xor(
cs.namespace(|| "first xor for s0"),
&w[i-15].rotr(18)
)?;
s0 = s0.xor(
cs.namespace(|| "second xor for s0"),
&w[i-15].shr(3)
)?;
let mut s0 = w[i - 15].rotr(7);
s0 = s0.xor(cs.namespace(|| "first xor for s0"), &w[i - 15].rotr(18))?;
s0 = s0.xor(cs.namespace(|| "second xor for s0"), &w[i - 15].shr(3))?;
// s1 := (w[i-2] rightrotate 17) xor (w[i-2] rightrotate 19) xor (w[i-2] rightshift 10)
let mut s1 = w[i-2].rotr(17);
s1 = s1.xor(
cs.namespace(|| "first xor for s1"),
&w[i-2].rotr(19)
)?;
s1 = s1.xor(
cs.namespace(|| "second xor for s1"),
&w[i-2].shr(10)
)?;
let mut s1 = w[i - 2].rotr(17);
s1 = s1.xor(cs.namespace(|| "first xor for s1"), &w[i - 2].rotr(19))?;
s1 = s1.xor(cs.namespace(|| "second xor for s1"), &w[i - 2].shr(10))?;
let tmp = UInt32::addmany(
cs.namespace(|| "computation of w[i]"),
&[w[i-16].clone(), s0, w[i-7].clone(), s1]
&[w[i - 16].clone(), s0, w[i - 7].clone(), s1],
)?;
// w[i] := w[i-16] + s0 + w[i-7] + s1
@@ -134,29 +117,21 @@ fn sha256_compression_function<E, CS>(
enum Maybe {
Deferred(Vec<UInt32>),
Concrete(UInt32)
Concrete(UInt32),
}
impl Maybe {
fn compute<E, CS, M>(
self,
cs: M,
others: &[UInt32]
) -> Result<UInt32, SynthesisError>
where E: Engine,
CS: ConstraintSystem<E>,
M: ConstraintSystem<E, Root=MultiEq<E, CS>>
fn compute<E, CS, M>(self, cs: M, others: &[UInt32]) -> Result<UInt32, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
M: ConstraintSystem<E, Root = MultiEq<E, CS>>,
{
Ok(match self {
Maybe::Concrete(ref v) => {
return Ok(v.clone())
},
Maybe::Concrete(ref v) => return Ok(v.clone()),
Maybe::Deferred(mut v) => {
v.extend(others.into_iter().cloned());
UInt32::addmany(
cs,
&v
)?
UInt32::addmany(cs, &v)?
}
})
}
@@ -177,22 +152,11 @@ fn sha256_compression_function<E, CS>(
// S1 := (e rightrotate 6) xor (e rightrotate 11) xor (e rightrotate 25)
let new_e = e.compute(cs.namespace(|| "deferred e computation"), &[])?;
let mut s1 = new_e.rotr(6);
s1 = s1.xor(
cs.namespace(|| "first xor for s1"),
&new_e.rotr(11)
)?;
s1 = s1.xor(
cs.namespace(|| "second xor for s1"),
&new_e.rotr(25)
)?;
s1 = s1.xor(cs.namespace(|| "first xor for s1"), &new_e.rotr(11))?;
s1 = s1.xor(cs.namespace(|| "second xor for s1"), &new_e.rotr(25))?;
// ch := (e and f) xor ((not e) and g)
let ch = UInt32::sha256_ch(
cs.namespace(|| "ch"),
&new_e,
&f,
&g
)?;
let ch = UInt32::sha256_ch(cs.namespace(|| "ch"), &new_e, &f, &g)?;
// temp1 := h + S1 + ch + k[i] + w[i]
let temp1 = vec![
@@ -200,28 +164,17 @@ fn sha256_compression_function<E, CS>(
s1,
ch,
UInt32::constant(ROUND_CONSTANTS[i]),
w[i].clone()
w[i].clone(),
];
// S0 := (a rightrotate 2) xor (a rightrotate 13) xor (a rightrotate 22)
let new_a = a.compute(cs.namespace(|| "deferred a computation"), &[])?;
let mut s0 = new_a.rotr(2);
s0 = s0.xor(
cs.namespace(|| "first xor for s0"),
&new_a.rotr(13)
)?;
s0 = s0.xor(
cs.namespace(|| "second xor for s0"),
&new_a.rotr(22)
)?;
s0 = s0.xor(cs.namespace(|| "first xor for s0"), &new_a.rotr(13))?;
s0 = s0.xor(cs.namespace(|| "second xor for s0"), &new_a.rotr(22))?;
// maj := (a and b) xor (a and c) xor (b and c)
let maj = UInt32::sha256_maj(
cs.namespace(|| "maj"),
&new_a,
&b,
&c
)?;
let maj = UInt32::sha256_maj(cs.namespace(|| "maj"), &new_a, &b, &c)?;
// temp2 := S0 + maj
let temp2 = vec![s0, maj];
@@ -244,7 +197,13 @@ fn sha256_compression_function<E, CS>(
d = c;
c = b;
b = new_a;
a = Maybe::Deferred(temp1.iter().cloned().chain(temp2.iter().cloned()).collect::<Vec<_>>());
a = Maybe::Deferred(
temp1
.iter()
.cloned()
.chain(temp2.iter().cloned())
.collect::<Vec<_>>(),
);
}
/*
@@ -261,42 +220,42 @@ fn sha256_compression_function<E, CS>(
let h0 = a.compute(
cs.namespace(|| "deferred h0 computation"),
&[current_hash_value[0].clone()]
&[current_hash_value[0].clone()],
)?;
let h1 = UInt32::addmany(
cs.namespace(|| "new h1"),
&[current_hash_value[1].clone(), b]
&[current_hash_value[1].clone(), b],
)?;
let h2 = UInt32::addmany(
cs.namespace(|| "new h2"),
&[current_hash_value[2].clone(), c]
&[current_hash_value[2].clone(), c],
)?;
let h3 = UInt32::addmany(
cs.namespace(|| "new h3"),
&[current_hash_value[3].clone(), d]
&[current_hash_value[3].clone(), d],
)?;
let h4 = e.compute(
cs.namespace(|| "deferred h4 computation"),
&[current_hash_value[4].clone()]
&[current_hash_value[4].clone()],
)?;
let h5 = UInt32::addmany(
cs.namespace(|| "new h5"),
&[current_hash_value[5].clone(), f]
&[current_hash_value[5].clone(), f],
)?;
let h6 = UInt32::addmany(
cs.namespace(|| "new h6"),
&[current_hash_value[6].clone(), g]
&[current_hash_value[6].clone(), g],
)?;
let h7 = UInt32::addmany(
cs.namespace(|| "new h7"),
&[current_hash_value[7].clone(), h]
&[current_hash_value[7].clone(), h],
)?;
Ok(vec![h0, h1, h2, h3, h4, h5, h6, h7])
@@ -306,8 +265,8 @@ fn sha256_compression_function<E, CS>(
mod test {
use super::*;
use crate::gadgets::boolean::AllocatedBit;
use pairing::bls12_381::Bls12;
use crate::gadgets::test::TestConstraintSystem;
use pairing::bls12_381::Bls12;
use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
@@ -318,11 +277,7 @@ mod test {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut input_bits: Vec<_> = (0..512).map(|_| Boolean::Constant(false)).collect();
input_bits[0] = Boolean::Constant(true);
let out = sha256_compression_function(
&mut cs,
&input_bits,
&iv
).unwrap();
let out = sha256_compression_function(&mut cs, &input_bits, &iv).unwrap();
let out_bits: Vec<_> = out.into_iter().flat_map(|e| e.into_bits_be()).collect();
assert!(cs.is_satisfied());
@@ -343,27 +298,26 @@ mod test {
#[test]
fn test_full_block() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let iv = get_sha256_iv();
let mut cs = TestConstraintSystem::<Bls12>::new();
let input_bits: Vec<_> = (0..512).map(|i| {
Boolean::from(
AllocatedBit::alloc(
cs.namespace(|| format!("input bit {}", i)),
Some(rng.next_u32() % 2 != 0)
).unwrap()
)
}).collect();
let input_bits: Vec<_> = (0..512)
.map(|i| {
Boolean::from(
AllocatedBit::alloc(
cs.namespace(|| format!("input bit {}", i)),
Some(rng.next_u32() % 2 != 0),
)
.unwrap(),
)
})
.collect();
sha256_compression_function(
cs.namespace(|| "sha256"),
&input_bits,
&iv
).unwrap();
sha256_compression_function(cs.namespace(|| "sha256"), &input_bits, &iv).unwrap();
assert!(cs.is_satisfied());
assert_eq!(cs.num_constraints() - 512, 25840);
@@ -374,12 +328,11 @@ mod test {
use sha2::{Digest, Sha256};
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0))
{
for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0)) {
let mut h = Sha256::new();
let data: Vec<u8> = (0..input_len).map(|_| rng.next_u32() as u8).collect();
h.input(&data);
@@ -392,7 +345,11 @@ mod test {
for bit_i in (0..8).rev() {
let cs = cs.namespace(|| format!("input bit {} {}", byte_i, bit_i));
input_bits.push(AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)).unwrap().into());
input_bits.push(
AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8))
.unwrap()
.into(),
);
}
}
@@ -400,17 +357,19 @@ mod test {
assert!(cs.is_satisfied());
let mut s = hash_result.as_ref().iter()
.flat_map(|&byte| (0..8).rev().map(move |i| (byte >> i) & 1u8 == 1u8));
let mut s = hash_result
.as_ref()
.iter()
.flat_map(|&byte| (0..8).rev().map(move |i| (byte >> i) & 1u8 == 1u8));
for b in r {
match b {
Boolean::Is(b) => {
assert!(s.next().unwrap() == b.get_value().unwrap());
},
}
Boolean::Not(b) => {
assert!(s.next().unwrap() != b.get_value().unwrap());
},
}
Boolean::Constant(b) => {
assert!(input_len == 0);
assert!(s.next().unwrap() == b);
+87 -112
View File
@@ -1,13 +1,7 @@
use ff::{Field, PrimeField, PrimeFieldRepr};
use pairing::Engine;
use crate::{
LinearCombination,
SynthesisError,
ConstraintSystem,
Variable,
Index
};
use crate::{ConstraintSystem, Index, LinearCombination, SynthesisError, Variable};
use std::collections::HashMap;
use std::fmt::Write;
@@ -22,7 +16,7 @@ use blake2s_simd::{Params as Blake2sParams, State as Blake2sState};
enum NamedObject {
Constraint(usize),
Var(Variable),
Namespace
Namespace,
}
/// Constraint system for testing purposes.
@@ -33,10 +27,10 @@ pub struct TestConstraintSystem<E: Engine> {
LinearCombination<E>,
LinearCombination<E>,
LinearCombination<E>,
String
String,
)>,
inputs: Vec<(E::Fr, String)>,
aux: Vec<(E::Fr, String)>
aux: Vec<(E::Fr, String)>,
}
#[derive(Clone, Copy)]
@@ -48,7 +42,7 @@ impl PartialEq for OrderedVariable {
match (self.0.get_unchecked(), other.0.get_unchecked()) {
(Index::Input(ref a), Index::Input(ref b)) => a == b,
(Index::Aux(ref a), Index::Aux(ref b)) => a == b,
_ => false
_ => false,
}
}
}
@@ -63,20 +57,17 @@ impl Ord for OrderedVariable {
(Index::Input(ref a), Index::Input(ref b)) => a.cmp(b),
(Index::Aux(ref a), Index::Aux(ref b)) => a.cmp(b),
(Index::Input(_), Index::Aux(_)) => Ordering::Less,
(Index::Aux(_), Index::Input(_)) => Ordering::Greater
(Index::Aux(_), Index::Input(_)) => Ordering::Greater,
}
}
}
fn proc_lc<E: Engine>(
terms: &[(Variable, E::Fr)],
) -> BTreeMap<OrderedVariable, E::Fr>
{
fn proc_lc<E: Engine>(terms: &[(Variable, E::Fr)]) -> BTreeMap<OrderedVariable, E::Fr> {
let mut map = BTreeMap::new();
for &(var, coeff) in terms {
map.entry(OrderedVariable(var))
.or_insert(E::Fr::zero())
.add_assign(&coeff);
.or_insert(E::Fr::zero())
.add_assign(&coeff);
}
// Remove terms that have a zero coefficient to normalize
@@ -94,11 +85,7 @@ fn proc_lc<E: Engine>(
map
}
fn hash_lc<E: Engine>(
terms: &[(Variable, E::Fr)],
h: &mut Blake2sState
)
{
fn hash_lc<E: Engine>(terms: &[(Variable, E::Fr)], h: &mut Blake2sState) {
let map = proc_lc::<E>(terms);
let mut buf = [0u8; 9 + 32];
@@ -110,13 +97,13 @@ fn hash_lc<E: Engine>(
Index::Input(i) => {
buf[0] = b'I';
BigEndian::write_u64(&mut buf[1..9], i as u64);
},
}
Index::Aux(i) => {
buf[0] = b'A';
BigEndian::write_u64(&mut buf[1..9], i as u64);
}
}
coeff.into_repr().write_be(&mut buf[9..]).unwrap();
h.update(&buf);
@@ -126,15 +113,14 @@ fn hash_lc<E: Engine>(
fn eval_lc<E: Engine>(
terms: &[(Variable, E::Fr)],
inputs: &[(E::Fr, String)],
aux: &[(E::Fr, String)]
) -> E::Fr
{
aux: &[(E::Fr, String)],
) -> E::Fr {
let mut acc = E::Fr::zero();
for &(var, ref coeff) in terms {
let mut tmp = match var.get_unchecked() {
Index::Input(index) => inputs[index].0,
Index::Aux(index) => aux[index].0
Index::Aux(index) => aux[index].0,
};
tmp.mul_assign(&coeff);
@@ -147,14 +133,17 @@ fn eval_lc<E: Engine>(
impl<E: Engine> TestConstraintSystem<E> {
pub fn new() -> TestConstraintSystem<E> {
let mut map = HashMap::new();
map.insert("ONE".into(), NamedObject::Var(TestConstraintSystem::<E>::one()));
map.insert(
"ONE".into(),
NamedObject::Var(TestConstraintSystem::<E>::one()),
);
TestConstraintSystem {
named_objects: map,
current_namespace: vec![],
constraints: vec![],
inputs: vec![(E::Fr::one(), "ONE".into())],
aux: vec![]
aux: vec![],
}
}
@@ -167,9 +156,9 @@ impl<E: Engine> TestConstraintSystem<E> {
tmp
};
let powers_of_two = (0..E::Fr::NUM_BITS).map(|i| {
E::Fr::from_str("2").unwrap().pow(&[i as u64])
}).collect::<Vec<_>>();
let powers_of_two = (0..E::Fr::NUM_BITS)
.map(|i| E::Fr::from_str("2").unwrap().pow(&[i as u64]))
.collect::<Vec<_>>();
let pp = |s: &mut String, lc: &LinearCombination<E>| {
write!(s, "(").unwrap();
@@ -196,7 +185,7 @@ impl<E: Engine> TestConstraintSystem<E> {
match var.0.get_unchecked() {
Index::Input(i) => {
write!(s, "`{}`", &self.inputs[i].1).unwrap();
},
}
Index::Aux(i) => {
write!(s, "`{}`", &self.aux[i].1).unwrap();
}
@@ -259,45 +248,41 @@ impl<E: Engine> TestConstraintSystem<E> {
a.mul_assign(&b);
if a != c {
return Some(&*path)
return Some(&*path);
}
}
None
}
pub fn is_satisfied(&self) -> bool
{
pub fn is_satisfied(&self) -> bool {
self.which_is_unsatisfied().is_none()
}
pub fn num_constraints(&self) -> usize
{
pub fn num_constraints(&self) -> usize {
self.constraints.len()
}
pub fn set(&mut self, path: &str, to: E::Fr)
{
pub fn set(&mut self, path: &str, to: E::Fr) {
match self.named_objects.get(path) {
Some(&NamedObject::Var(ref v)) => {
match v.get_unchecked() {
Index::Input(index) => self.inputs[index].0 = to,
Index::Aux(index) => self.aux[index].0 = to
}
}
Some(e) => panic!("tried to set path `{}` to value, but `{:?}` already exists there.", path, e),
_ => panic!("no variable exists at path: {}", path)
Some(&NamedObject::Var(ref v)) => match v.get_unchecked() {
Index::Input(index) => self.inputs[index].0 = to,
Index::Aux(index) => self.aux[index].0 = to,
},
Some(e) => panic!(
"tried to set path `{}` to value, but `{:?}` already exists there.",
path, e
),
_ => panic!("no variable exists at path: {}", path),
}
}
pub fn verify(&self, expected: &[E::Fr]) -> bool
{
pub fn verify(&self, expected: &[E::Fr]) -> bool {
assert_eq!(expected.len() + 1, self.inputs.len());
for (a, b) in self.inputs.iter().skip(1).zip(expected.iter())
{
for (a, b) in self.inputs.iter().skip(1).zip(expected.iter()) {
if &a.0 != b {
return false
return false;
}
}
@@ -308,8 +293,7 @@ impl<E: Engine> TestConstraintSystem<E> {
self.inputs.len()
}
pub fn get_input(&mut self, index: usize, path: &str) -> E::Fr
{
pub fn get_input(&mut self, index: usize, path: &str) -> E::Fr {
let (assignment, name) = self.inputs[index].clone();
assert_eq!(path, name);
@@ -317,17 +301,17 @@ impl<E: Engine> TestConstraintSystem<E> {
assignment
}
pub fn get(&mut self, path: &str) -> E::Fr
{
pub fn get(&mut self, path: &str) -> E::Fr {
match self.named_objects.get(path) {
Some(&NamedObject::Var(ref v)) => {
match v.get_unchecked() {
Index::Input(index) => self.inputs[index].0,
Index::Aux(index) => self.aux[index].0
}
}
Some(e) => panic!("tried to get value of path `{}`, but `{:?}` exists there (not a variable)", path, e),
_ => panic!("no variable exists at path: {}", path)
Some(&NamedObject::Var(ref v)) => match v.get_unchecked() {
Index::Input(index) => self.inputs[index].0,
Index::Aux(index) => self.aux[index].0,
},
Some(e) => panic!(
"tried to get value of path `{}`, but `{:?}` exists there (not a variable)",
path, e
),
_ => panic!("no variable exists at path: {}", path),
}
}
@@ -348,8 +332,7 @@ fn compute_path(ns: &[String], this: String) -> String {
let mut name = String::new();
let mut needs_separation = false;
for ns in ns.iter().chain(Some(&this).into_iter())
{
for ns in ns.iter().chain(Some(&this).into_iter()) {
if needs_separation {
name += "/";
}
@@ -364,12 +347,11 @@ fn compute_path(ns: &[String], this: String) -> String {
impl<E: Engine> ConstraintSystem<E> for TestConstraintSystem<E> {
type Root = Self;
fn alloc<F, A, AR>(
&mut self,
annotation: A,
f: F
) -> Result<Variable, SynthesisError>
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
fn alloc<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
let index = self.aux.len();
let path = compute_path(&self.current_namespace, annotation().into());
@@ -380,12 +362,11 @@ impl<E: Engine> ConstraintSystem<E> for TestConstraintSystem<E> {
Ok(var)
}
fn alloc_input<F, A, AR>(
&mut self,
annotation: A,
f: F
) -> Result<Variable, SynthesisError>
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
fn alloc_input<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
let index = self.inputs.len();
let path = compute_path(&self.current_namespace, annotation().into());
@@ -396,17 +377,13 @@ impl<E: Engine> ConstraintSystem<E> for TestConstraintSystem<E> {
Ok(var)
}
fn enforce<A, AR, LA, LB, LC>(
&mut self,
annotation: A,
a: LA,
b: LB,
c: LC
)
where A: FnOnce() -> AR, AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>
fn enforce<A, AR, LA, LB, LC>(&mut self, annotation: A, a: LA, b: LB, c: LC)
where
A: FnOnce() -> AR,
AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
{
let path = compute_path(&self.current_namespace, annotation().into());
let index = self.constraints.len();
@@ -420,7 +397,9 @@ impl<E: Engine> ConstraintSystem<E> for TestConstraintSystem<E> {
}
fn push_namespace<NR, N>(&mut self, name_fn: N)
where NR: Into<String>, N: FnOnce() -> NR
where
NR: Into<String>,
N: FnOnce() -> NR,
{
let name = name_fn().into();
let path = compute_path(&self.current_namespace, name.clone());
@@ -428,13 +407,11 @@ impl<E: Engine> ConstraintSystem<E> for TestConstraintSystem<E> {
self.current_namespace.push(name);
}
fn pop_namespace(&mut self)
{
fn pop_namespace(&mut self) {
assert!(self.current_namespace.pop().is_some());
}
fn get_root(&mut self) -> &mut Self::Root
{
fn get_root(&mut self) -> &mut Self::Root {
self
}
}
@@ -447,28 +424,26 @@ fn test_cs() {
let mut cs = TestConstraintSystem::<Bls12>::new();
assert!(cs.is_satisfied());
assert_eq!(cs.num_constraints(), 0);
let a = cs.namespace(|| "a").alloc(|| "var", || Ok(Fr::from_str("10").unwrap())).unwrap();
let b = cs.namespace(|| "b").alloc(|| "var", || Ok(Fr::from_str("4").unwrap())).unwrap();
let c = cs.alloc(|| "product", || Ok(Fr::from_str("40").unwrap())).unwrap();
let a = cs
.namespace(|| "a")
.alloc(|| "var", || Ok(Fr::from_str("10").unwrap()))
.unwrap();
let b = cs
.namespace(|| "b")
.alloc(|| "var", || Ok(Fr::from_str("4").unwrap()))
.unwrap();
let c = cs
.alloc(|| "product", || Ok(Fr::from_str("40").unwrap()))
.unwrap();
cs.enforce(
|| "mult",
|lc| lc + a,
|lc| lc + b,
|lc| lc + c
);
cs.enforce(|| "mult", |lc| lc + a, |lc| lc + b, |lc| lc + c);
assert!(cs.is_satisfied());
assert_eq!(cs.num_constraints(), 1);
cs.set("a/var", Fr::from_str("4").unwrap());
let one = TestConstraintSystem::<Bls12>::one();
cs.enforce(
|| "eq",
|lc| lc + a,
|lc| lc + one,
|lc| lc + b
);
cs.enforce(|| "eq", |lc| lc + a, |lc| lc + one, |lc| lc + b);
assert!(!cs.is_satisfied());
assert!(cs.which_is_unsatisfied() == Some("mult"));
+179 -204
View File
@@ -1,16 +1,9 @@
use ff::{Field, PrimeField};
use pairing::Engine;
use crate::{
SynthesisError,
ConstraintSystem,
LinearCombination
};
use crate::{ConstraintSystem, LinearCombination, SynthesisError};
use super::boolean::{
Boolean,
AllocatedBit
};
use super::boolean::{AllocatedBit, Boolean};
use super::multieq::MultiEq;
@@ -20,13 +13,12 @@ use super::multieq::MultiEq;
pub struct UInt32 {
// Least significant bit first
bits: Vec<Boolean>,
value: Option<u32>
value: Option<u32>,
}
impl UInt32 {
/// Construct a constant `UInt32` from a `u32`
pub fn constant(value: u32) -> Self
{
pub fn constant(value: u32) -> Self {
let mut bits = Vec::with_capacity(32);
let mut tmp = value;
@@ -42,17 +34,15 @@ impl UInt32 {
UInt32 {
bits: bits,
value: Some(value)
value: Some(value),
}
}
/// Allocate a `UInt32` in the constraint system
pub fn alloc<E, CS>(
mut cs: CS,
value: Option<u32>
) -> Result<Self, SynthesisError>
where E: Engine,
CS: ConstraintSystem<E>
pub fn alloc<E, CS>(mut cs: CS, value: Option<u32>) -> Result<Self, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
{
let values = match value {
Some(mut val) => {
@@ -64,23 +54,24 @@ impl UInt32 {
}
v
},
None => vec![None; 32]
}
None => vec![None; 32],
};
let bits = values.into_iter()
.enumerate()
.map(|(i, v)| {
Ok(Boolean::from(AllocatedBit::alloc(
cs.namespace(|| format!("allocated bit {}", i)),
v
)?))
})
.collect::<Result<Vec<_>, SynthesisError>>()?;
let bits = values
.into_iter()
.enumerate()
.map(|(i, v)| {
Ok(Boolean::from(AllocatedBit::alloc(
cs.namespace(|| format!("allocated bit {}", i)),
v,
)?))
})
.collect::<Result<Vec<_>, SynthesisError>>()?;
Ok(UInt32 {
bits: bits,
value: value
value: value,
})
}
@@ -96,19 +87,22 @@ impl UInt32 {
value.as_mut().map(|v| *v <<= 1);
match b.get_value() {
Some(true) => { value.as_mut().map(|v| *v |= 1); },
Some(false) => {},
None => { value = None; }
Some(true) => {
value.as_mut().map(|v| *v |= 1);
}
Some(false) => {}
None => {
value = None;
}
}
}
UInt32 {
value: value,
bits: bits.iter().rev().cloned().collect()
bits: bits.iter().rev().cloned().collect(),
}
}
/// Turns this `UInt32` into its little-endian byte order representation.
pub fn into_bits(&self) -> Vec<Boolean> {
self.bits.clone()
@@ -116,8 +110,7 @@ impl UInt32 {
/// Converts a little-endian byte order representation of bits into a
/// `UInt32`.
pub fn from_bits(bits: &[Boolean]) -> Self
{
pub fn from_bits(bits: &[Boolean]) -> Self {
assert_eq!(bits.len(), 32);
let new_bits = bits.to_vec();
@@ -131,43 +124,45 @@ impl UInt32 {
if b {
value.as_mut().map(|v| *v |= 1);
}
},
&Boolean::Is(ref b) => {
match b.get_value() {
Some(true) => { value.as_mut().map(|v| *v |= 1); },
Some(false) => {},
None => { value = None }
}
},
&Boolean::Not(ref b) => {
match b.get_value() {
Some(false) => { value.as_mut().map(|v| *v |= 1); },
Some(true) => {},
None => { value = None }
}
}
&Boolean::Is(ref b) => match b.get_value() {
Some(true) => {
value.as_mut().map(|v| *v |= 1);
}
Some(false) => {}
None => value = None,
},
&Boolean::Not(ref b) => match b.get_value() {
Some(false) => {
value.as_mut().map(|v| *v |= 1);
}
Some(true) => {}
None => value = None,
},
}
}
UInt32 {
value: value,
bits: new_bits
bits: new_bits,
}
}
pub fn rotr(&self, by: usize) -> Self {
let by = by % 32;
let new_bits = self.bits.iter()
.skip(by)
.chain(self.bits.iter())
.take(32)
.cloned()
.collect();
let new_bits = self
.bits
.iter()
.skip(by)
.chain(self.bits.iter())
.take(32)
.cloned()
.collect();
UInt32 {
bits: new_bits,
value: self.value.map(|v| v.rotate_right(by as u32))
value: self.value.map(|v| v.rotate_right(by as u32)),
}
}
@@ -176,17 +171,18 @@ impl UInt32 {
let fill = Boolean::constant(false);
let new_bits = self.bits
.iter() // The bits are least significant first
.skip(by) // Skip the bits that will be lost during the shift
.chain(Some(&fill).into_iter().cycle()) // Rest will be zeros
.take(32) // Only 32 bits needed!
.cloned()
.collect();
let new_bits = self
.bits
.iter() // The bits are least significant first
.skip(by) // Skip the bits that will be lost during the shift
.chain(Some(&fill).into_iter().cycle()) // Rest will be zeros
.take(32) // Only 32 bits needed!
.cloned()
.collect();
UInt32 {
bits: new_bits,
value: self.value.map(|v| v >> by as u32)
value: self.value.map(|v| v >> by as u32),
}
}
@@ -196,121 +192,99 @@ impl UInt32 {
b: &Self,
c: &Self,
tri_fn: F,
circuit_fn: U
circuit_fn: U,
) -> Result<Self, SynthesisError>
where E: Engine,
CS: ConstraintSystem<E>,
F: Fn(u32, u32, u32) -> u32,
U: Fn(&mut CS, usize, &Boolean, &Boolean, &Boolean) -> Result<Boolean, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
F: Fn(u32, u32, u32) -> u32,
U: Fn(&mut CS, usize, &Boolean, &Boolean, &Boolean) -> Result<Boolean, SynthesisError>,
{
let new_value = match (a.value, b.value, c.value) {
(Some(a), Some(b), Some(c)) => {
Some(tri_fn(a, b, c))
},
_ => None
(Some(a), Some(b), Some(c)) => Some(tri_fn(a, b, c)),
_ => None,
};
let bits = a.bits.iter()
.zip(b.bits.iter())
.zip(c.bits.iter())
.enumerate()
.map(|(i, ((a, b), c))| circuit_fn(&mut cs, i, a, b, c))
.collect::<Result<_, _>>()?;
let bits = a
.bits
.iter()
.zip(b.bits.iter())
.zip(c.bits.iter())
.enumerate()
.map(|(i, ((a, b), c))| circuit_fn(&mut cs, i, a, b, c))
.collect::<Result<_, _>>()?;
Ok(UInt32 {
bits: bits,
value: new_value
value: new_value,
})
}
/// Compute the `maj` value (a and b) xor (a and c) xor (b and c)
/// during SHA256.
pub fn sha256_maj<E, CS>(
cs: CS,
a: &Self,
b: &Self,
c: &Self
) -> Result<Self, SynthesisError>
where E: Engine,
CS: ConstraintSystem<E>
pub fn sha256_maj<E, CS>(cs: CS, a: &Self, b: &Self, c: &Self) -> Result<Self, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
{
Self::triop(cs, a, b, c, |a, b, c| (a & b) ^ (a & c) ^ (b & c),
|cs, i, a, b, c| {
Boolean::sha256_maj(
cs.namespace(|| format!("maj {}", i)),
a,
b,
c
)
}
Self::triop(
cs,
a,
b,
c,
|a, b, c| (a & b) ^ (a & c) ^ (b & c),
|cs, i, a, b, c| Boolean::sha256_maj(cs.namespace(|| format!("maj {}", i)), a, b, c),
)
}
/// Compute the `ch` value `(a and b) xor ((not a) and c)`
/// during SHA256.
pub fn sha256_ch<E, CS>(
cs: CS,
a: &Self,
b: &Self,
c: &Self
) -> Result<Self, SynthesisError>
where E: Engine,
CS: ConstraintSystem<E>
pub fn sha256_ch<E, CS>(cs: CS, a: &Self, b: &Self, c: &Self) -> Result<Self, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
{
Self::triop(cs, a, b, c, |a, b, c| (a & b) ^ ((!a) & c),
|cs, i, a, b, c| {
Boolean::sha256_ch(
cs.namespace(|| format!("ch {}", i)),
a,
b,
c
)
}
Self::triop(
cs,
a,
b,
c,
|a, b, c| (a & b) ^ ((!a) & c),
|cs, i, a, b, c| Boolean::sha256_ch(cs.namespace(|| format!("ch {}", i)), a, b, c),
)
}
/// XOR this `UInt32` with another `UInt32`
pub fn xor<E, CS>(
&self,
mut cs: CS,
other: &Self
) -> Result<Self, SynthesisError>
where E: Engine,
CS: ConstraintSystem<E>
pub fn xor<E, CS>(&self, mut cs: CS, other: &Self) -> Result<Self, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
{
let new_value = match (self.value, other.value) {
(Some(a), Some(b)) => {
Some(a ^ b)
},
_ => None
(Some(a), Some(b)) => Some(a ^ b),
_ => None,
};
let bits = self.bits.iter()
.zip(other.bits.iter())
.enumerate()
.map(|(i, (a, b))| {
Boolean::xor(
cs.namespace(|| format!("xor of bit {}", i)),
a,
b
)
})
.collect::<Result<_, _>>()?;
let bits = self
.bits
.iter()
.zip(other.bits.iter())
.enumerate()
.map(|(i, (a, b))| Boolean::xor(cs.namespace(|| format!("xor of bit {}", i)), a, b))
.collect::<Result<_, _>>()?;
Ok(UInt32 {
bits: bits,
value: new_value
value: new_value,
})
}
/// Perform modular addition of several `UInt32` objects.
pub fn addmany<E, CS, M>(
mut cs: M,
operands: &[Self]
) -> Result<Self, SynthesisError>
where E: Engine,
CS: ConstraintSystem<E>,
M: ConstraintSystem<E, Root=MultiEq<E, CS>>
pub fn addmany<E, CS, M>(mut cs: M, operands: &[Self]) -> Result<Self, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
M: ConstraintSystem<E, Root = MultiEq<E, CS>>,
{
// Make some arbitrary bounds for ourselves to avoid overflows
// in the scalar field
@@ -337,7 +311,7 @@ impl UInt32 {
match op.value {
Some(val) => {
result_value.as_mut().map(|v| *v += val as u64);
},
}
None => {
// If any of our operands have unknown value, we won't
// know the value of the result
@@ -381,7 +355,7 @@ impl UInt32 {
// Allocate the bit
let b = AllocatedBit::alloc(
cs.namespace(|| format!("result bit {}", i)),
result_value.map(|v| (v >> i) & 1 == 1)
result_value.map(|v| (v >> i) & 1 == 1),
)?;
// Add this bit to the result combination
@@ -402,32 +376,34 @@ impl UInt32 {
Ok(UInt32 {
bits: result_bits,
value: modular_value
value: modular_value,
})
}
}
#[cfg(test)]
mod test {
use crate::gadgets::boolean::{Boolean};
use super::{UInt32};
use ff::Field;
use pairing::bls12_381::{Bls12};
use crate::gadgets::test::*;
use crate::{ConstraintSystem};
use super::UInt32;
use crate::gadgets::boolean::Boolean;
use crate::gadgets::multieq::MultiEq;
use crate::gadgets::test::*;
use crate::ConstraintSystem;
use ff::Field;
use pairing::bls12_381::Bls12;
use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
#[test]
fn test_uint32_from_bits_be() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
for _ in 0..1000 {
let mut v = (0..32).map(|_| Boolean::constant(rng.next_u32() % 2 != 0)).collect::<Vec<_>>();
let mut v = (0..32)
.map(|_| Boolean::constant(rng.next_u32() % 2 != 0))
.collect::<Vec<_>>();
let b = UInt32::from_bits_be(&v);
@@ -435,19 +411,18 @@ mod test {
match bit {
&Boolean::Constant(bit) => {
assert!(bit == ((b.value.unwrap() >> i) & 1 == 1));
},
_ => unreachable!()
}
_ => unreachable!(),
}
}
let expected_to_be_same = b.into_bits_be();
for x in v.iter().zip(expected_to_be_same.iter())
{
for x in v.iter().zip(expected_to_be_same.iter()) {
match x {
(&Boolean::Constant(true), &Boolean::Constant(true)) => {},
(&Boolean::Constant(false), &Boolean::Constant(false)) => {},
_ => unreachable!()
(&Boolean::Constant(true), &Boolean::Constant(true)) => {}
(&Boolean::Constant(false), &Boolean::Constant(false)) => {}
_ => unreachable!(),
}
}
}
@@ -456,12 +431,14 @@ mod test {
#[test]
fn test_uint32_from_bits() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
for _ in 0..1000 {
let mut v = (0..32).map(|_| Boolean::constant(rng.next_u32() % 2 != 0)).collect::<Vec<_>>();
let mut v = (0..32)
.map(|_| Boolean::constant(rng.next_u32() % 2 != 0))
.collect::<Vec<_>>();
let b = UInt32::from_bits(&v);
@@ -469,19 +446,18 @@ mod test {
match bit {
&Boolean::Constant(bit) => {
assert!(bit == ((b.value.unwrap() >> i) & 1 == 1));
},
_ => unreachable!()
}
_ => unreachable!(),
}
}
let expected_to_be_same = b.into_bits();
for x in v.iter().zip(expected_to_be_same.iter())
{
for x in v.iter().zip(expected_to_be_same.iter()) {
match x {
(&Boolean::Constant(true), &Boolean::Constant(true)) => {},
(&Boolean::Constant(false), &Boolean::Constant(false)) => {},
_ => unreachable!()
(&Boolean::Constant(true), &Boolean::Constant(true)) => {}
(&Boolean::Constant(false), &Boolean::Constant(false)) => {}
_ => unreachable!(),
}
}
}
@@ -490,8 +466,8 @@ mod test {
#[test]
fn test_uint32_xor() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
for _ in 0..1000 {
@@ -518,10 +494,10 @@ mod test {
match b {
&Boolean::Is(ref b) => {
assert!(b.get_value().unwrap() == (expected & 1 == 1));
},
}
&Boolean::Not(ref b) => {
assert!(!b.get_value().unwrap() == (expected & 1 == 1));
},
}
&Boolean::Constant(b) => {
assert!(b == (expected & 1 == 1));
}
@@ -535,8 +511,8 @@ mod test {
#[test]
fn test_uint32_addmany_constants() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
for _ in 0..1000 {
@@ -554,7 +530,8 @@ mod test {
let r = {
let mut cs = MultiEq::new(&mut cs);
let r = UInt32::addmany(cs.namespace(|| "addition"), &[a_bit, b_bit, c_bit]).unwrap();
let r =
UInt32::addmany(cs.namespace(|| "addition"), &[a_bit, b_bit, c_bit]).unwrap();
r
};
@@ -577,8 +554,8 @@ mod test {
#[test]
fn test_uint32_addmany() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
for _ in 0..1000 {
@@ -611,13 +588,11 @@ mod test {
match b {
&Boolean::Is(ref b) => {
assert!(b.get_value().unwrap() == (expected & 1 == 1));
},
}
&Boolean::Not(ref b) => {
assert!(!b.get_value().unwrap() == (expected & 1 == 1));
},
&Boolean::Constant(_) => {
unreachable!()
}
&Boolean::Constant(_) => unreachable!(),
}
expected >>= 1;
@@ -637,8 +612,8 @@ mod test {
#[test]
fn test_uint32_rotr() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let mut num = rng.next_u32();
@@ -656,8 +631,8 @@ mod test {
match b {
&Boolean::Constant(b) => {
assert_eq!(b, tmp & 1 == 1);
},
_ => unreachable!()
}
_ => unreachable!(),
}
tmp >>= 1;
@@ -670,8 +645,8 @@ mod test {
#[test]
fn test_uint32_shr() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
for _ in 0..50 {
@@ -693,8 +668,8 @@ mod test {
#[test]
fn test_uint32_sha256_maj() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
for _ in 0..1000 {
@@ -720,10 +695,10 @@ mod test {
match b {
&Boolean::Is(ref b) => {
assert!(b.get_value().unwrap() == (expected & 1 == 1));
},
}
&Boolean::Not(ref b) => {
assert!(!b.get_value().unwrap() == (expected & 1 == 1));
},
}
&Boolean::Constant(b) => {
assert!(b == (expected & 1 == 1));
}
@@ -737,8 +712,8 @@ mod test {
#[test]
fn test_uint32_sha256_ch() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
for _ in 0..1000 {
@@ -764,10 +739,10 @@ mod test {
match b {
&Boolean::Is(ref b) => {
assert!(b.get_value().unwrap() == (expected & 1 == 1));
},
}
&Boolean::Not(ref b) => {
assert!(!b.get_value().unwrap() == (expected & 1 == 1));
},
}
&Boolean::Constant(b) => {
assert!(b == (expected & 1 == 1));
}