Implementation of `from_bits_strict` for `Num`.
This commit is contained in:
parent
d04c5acdb8
commit
6c6a193551
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue