|
|
@ -1,6 +1,7 @@ |
|
|
|
use pairing::{ |
|
|
|
use pairing::{ |
|
|
|
Engine, |
|
|
|
Engine, |
|
|
|
Field |
|
|
|
Field, |
|
|
|
|
|
|
|
PrimeField |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
use bellman::{ |
|
|
|
use bellman::{ |
|
|
@ -13,6 +14,10 @@ use super::{ |
|
|
|
Assignment |
|
|
|
Assignment |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
use super::boolean::{ |
|
|
|
|
|
|
|
Boolean |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
pub struct AllocatedNum<E: Engine, Var> { |
|
|
|
pub struct AllocatedNum<E: Engine, Var> { |
|
|
|
value: Option<E::Fr>, |
|
|
|
value: Option<E::Fr>, |
|
|
|
variable: Var |
|
|
|
variable: Var |
|
|
@ -41,6 +46,75 @@ impl<E: Engine, Var: Copy> AllocatedNum<E, Var> { |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn from_bits_strict<CS>( |
|
|
|
|
|
|
|
mut cs: CS, |
|
|
|
|
|
|
|
bits: &[Boolean<Var>] |
|
|
|
|
|
|
|
) -> Result<Self, SynthesisError> |
|
|
|
|
|
|
|
where CS: ConstraintSystem<E, Variable=Var> |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
assert_eq!(bits.len(), E::Fr::NUM_BITS as usize); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Boolean::enforce_in_field::<_, _, E::Fr>(&mut cs, bits)?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let one = cs.one(); |
|
|
|
|
|
|
|
let mut lc = LinearCombination::<Var, E>::zero(); |
|
|
|
|
|
|
|
let mut coeff = E::Fr::one(); |
|
|
|
|
|
|
|
let mut value = Some(E::Fr::zero()); |
|
|
|
|
|
|
|
for bit in bits.iter().rev() { |
|
|
|
|
|
|
|
match bit { |
|
|
|
|
|
|
|
&Boolean::Constant(false) => {}, |
|
|
|
|
|
|
|
&Boolean::Constant(true) => { |
|
|
|
|
|
|
|
value.as_mut().map(|value| value.add_assign(&coeff)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lc = lc + (coeff, one); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
&Boolean::Is(ref bit) => { |
|
|
|
|
|
|
|
match bit.get_value() { |
|
|
|
|
|
|
|
Some(bit) => { |
|
|
|
|
|
|
|
if bit { |
|
|
|
|
|
|
|
value.as_mut().map(|value| value.add_assign(&coeff)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
None => { |
|
|
|
|
|
|
|
value = None; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lc = lc + (coeff, bit.get_variable()); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
&Boolean::Not(ref bit) => { |
|
|
|
|
|
|
|
match bit.get_value() { |
|
|
|
|
|
|
|
Some(bit) => { |
|
|
|
|
|
|
|
if !bit { |
|
|
|
|
|
|
|
value.as_mut().map(|value| value.add_assign(&coeff)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
None => { |
|
|
|
|
|
|
|
value = None; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lc = lc + (coeff, one) - (coeff, bit.get_variable()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
coeff.double(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let num = Self::alloc(&mut cs, || value.get().map(|v| *v))?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lc = lc - num.get_variable(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cs.enforce( |
|
|
|
|
|
|
|
|| "packing constraint", |
|
|
|
|
|
|
|
LinearCombination::zero(), |
|
|
|
|
|
|
|
LinearCombination::zero(), |
|
|
|
|
|
|
|
lc |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ok(num) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub fn square<CS>( |
|
|
|
pub fn square<CS>( |
|
|
|
&self, |
|
|
|
&self, |
|
|
|
mut cs: CS |
|
|
|
mut cs: CS |
|
|
@ -114,10 +188,13 @@ impl<E: Engine, Var: Copy> AllocatedNum<E, Var> { |
|
|
|
|
|
|
|
|
|
|
|
#[cfg(test)] |
|
|
|
#[cfg(test)] |
|
|
|
mod test { |
|
|
|
mod test { |
|
|
|
|
|
|
|
use rand::{SeedableRng, Rand, Rng, XorShiftRng}; |
|
|
|
|
|
|
|
use bellman::{ConstraintSystem}; |
|
|
|
use pairing::bls12_381::{Bls12, Fr}; |
|
|
|
use pairing::bls12_381::{Bls12, Fr}; |
|
|
|
use pairing::{Field, PrimeField}; |
|
|
|
use pairing::{Field, PrimeField, BitIterator}; |
|
|
|
use ::circuit::test::*; |
|
|
|
use ::circuit::test::*; |
|
|
|
use super::{AllocatedNum}; |
|
|
|
use super::{AllocatedNum, Boolean}; |
|
|
|
|
|
|
|
use super::super::boolean::AllocatedBit; |
|
|
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
#[test] |
|
|
|
fn test_allocated_num() { |
|
|
|
fn test_allocated_num() { |
|
|
@ -161,4 +238,55 @@ mod test { |
|
|
|
assert!(n.assert_nonzero(&mut cs).is_err()); |
|
|
|
assert!(n.assert_nonzero(&mut cs).is_err()); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
|
|
|
fn test_from_bits_strict() { |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
let mut cs = TestConstraintSystem::<Bls12>::new(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mut bits = vec![]; |
|
|
|
|
|
|
|
for (i, b) in BitIterator::new(Fr::char()).skip(1).enumerate() { |
|
|
|
|
|
|
|
bits.push(Boolean::from(AllocatedBit::alloc( |
|
|
|
|
|
|
|
cs.namespace(|| format!("bit {}", i)), |
|
|
|
|
|
|
|
Some(b) |
|
|
|
|
|
|
|
).unwrap())); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let num = AllocatedNum::from_bits_strict(&mut cs, &bits).unwrap(); |
|
|
|
|
|
|
|
assert!(num.value.unwrap().is_zero()); |
|
|
|
|
|
|
|
assert!(!cs.is_satisfied()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for _ in 0..1000 { |
|
|
|
|
|
|
|
let r = Fr::rand(&mut rng); |
|
|
|
|
|
|
|
let mut cs = TestConstraintSystem::<Bls12>::new(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mut bits = vec![]; |
|
|
|
|
|
|
|
for (i, b) in BitIterator::new(r.into_repr()).skip(1).enumerate() { |
|
|
|
|
|
|
|
let parity: bool = rng.gen(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if parity { |
|
|
|
|
|
|
|
bits.push(Boolean::from(AllocatedBit::alloc( |
|
|
|
|
|
|
|
cs.namespace(|| format!("bit {}", i)), |
|
|
|
|
|
|
|
Some(b) |
|
|
|
|
|
|
|
).unwrap())); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
bits.push(Boolean::from(AllocatedBit::alloc( |
|
|
|
|
|
|
|
cs.namespace(|| format!("bit {}", i)), |
|
|
|
|
|
|
|
Some(!b) |
|
|
|
|
|
|
|
).unwrap()).not()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let num = AllocatedNum::from_bits_strict(&mut cs, &bits).unwrap(); |
|
|
|
|
|
|
|
assert!(cs.is_satisfied()); |
|
|
|
|
|
|
|
assert_eq!(num.value.unwrap(), r); |
|
|
|
|
|
|
|
assert_eq!(cs.get("num"), r); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cs.set("num", Fr::rand(&mut rng)); |
|
|
|
|
|
|
|
assert_eq!(cs.which_is_unsatisfied().unwrap(), "packing constraint"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|