Merge pull request #32 from ebfull/bellman-update

Bellman update
This commit is contained in:
ebfull 2018-02-16 09:09:27 -07:00 committed by GitHub
commit c091e274ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 367 additions and 334 deletions

View File

@ -16,7 +16,7 @@ features = ["expose-arith"]
rand = "0.3" rand = "0.3"
blake2 = "0.7" blake2 = "0.7"
digest = "0.7" digest = "0.7"
bellman = "0.0.7" bellman = "0.0.8"
[features] [features]
default = ["u128-support"] default = ["u128-support"]

View File

@ -90,13 +90,13 @@ const SIGMA: [[usize; 16]; 10] = [
fn mixing_g<E: Engine, CS: ConstraintSystem<E>>( fn mixing_g<E: Engine, CS: ConstraintSystem<E>>(
mut cs: CS, mut cs: CS,
v: &mut [UInt32<CS::Variable>], v: &mut [UInt32],
a: usize, a: usize,
b: usize, b: usize,
c: usize, c: usize,
d: usize, d: usize,
x: &UInt32<CS::Variable>, x: &UInt32,
y: &UInt32<CS::Variable> y: &UInt32
) -> Result<(), SynthesisError> ) -> Result<(), SynthesisError>
{ {
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()])?;
@ -162,8 +162,8 @@ fn mixing_g<E: Engine, CS: ConstraintSystem<E>>(
fn blake2s_compression<E: Engine, CS: ConstraintSystem<E>>( fn blake2s_compression<E: Engine, CS: ConstraintSystem<E>>(
mut cs: CS, mut cs: CS,
h: &mut [UInt32<CS::Variable>], h: &mut [UInt32],
m: &[UInt32<CS::Variable>], m: &[UInt32],
t: u64, t: u64,
f: bool f: bool
) -> Result<(), SynthesisError> ) -> Result<(), SynthesisError>
@ -254,8 +254,8 @@ fn blake2s_compression<E: Engine, CS: ConstraintSystem<E>>(
pub fn blake2s<E: Engine, CS: ConstraintSystem<E>>( pub fn blake2s<E: Engine, CS: ConstraintSystem<E>>(
mut cs: CS, mut cs: CS,
input: &[Boolean<CS::Variable>] input: &[Boolean]
) -> Result<Vec<Boolean<CS::Variable>>, SynthesisError> ) -> Result<Vec<Boolean>, SynthesisError>
{ {
assert!(input.len() % 8 == 0); assert!(input.len() % 8 == 0);
@ -269,7 +269,7 @@ pub fn blake2s<E: Engine, CS: ConstraintSystem<E>>(
h.push(UInt32::constant(0x1F83D9AB)); h.push(UInt32::constant(0x1F83D9AB));
h.push(UInt32::constant(0x5BE0CD19)); h.push(UInt32::constant(0x5BE0CD19));
let mut blocks: Vec<Vec<UInt32<CS::Variable>>> = vec![]; let mut blocks: Vec<Vec<UInt32>> = vec![];
for block in input.chunks(512) { for block in input.chunks(512) {
let mut this_block = Vec::with_capacity(16); let mut this_block = Vec::with_capacity(16);

View File

@ -9,7 +9,8 @@ use pairing::{
use bellman::{ use bellman::{
ConstraintSystem, ConstraintSystem,
SynthesisError, SynthesisError,
LinearCombination LinearCombination,
Variable
}; };
use super::{ use super::{
@ -19,17 +20,17 @@ use super::{
/// Represents a variable in the constraint system which is guaranteed /// Represents a variable in the constraint system which is guaranteed
/// to be either zero or one. /// to be either zero or one.
#[derive(Clone)] #[derive(Clone)]
pub struct AllocatedBit<Var> { pub struct AllocatedBit {
variable: Var, variable: Variable,
value: Option<bool> value: Option<bool>
} }
impl<Var: Copy> AllocatedBit<Var> { impl AllocatedBit {
pub fn get_value(&self) -> Option<bool> { pub fn get_value(&self) -> Option<bool> {
self.value self.value
} }
pub fn get_variable(&self) -> Var { pub fn get_variable(&self) -> Variable {
self.variable self.variable
} }
@ -40,7 +41,7 @@ impl<Var: Copy> AllocatedBit<Var> {
value: Option<bool>, value: Option<bool>,
) -> Result<Self, SynthesisError> ) -> Result<Self, SynthesisError>
where E: Engine, where E: Engine,
CS: ConstraintSystem<E, Variable=Var> CS: ConstraintSystem<E>
{ {
let var = cs.alloc(|| "boolean", || { let var = cs.alloc(|| "boolean", || {
if *value.get()? { if *value.get()? {
@ -52,12 +53,11 @@ impl<Var: Copy> AllocatedBit<Var> {
// Constrain: (1 - a) * a = 0 // Constrain: (1 - a) * a = 0
// This constrains a to be either 0 or 1. // This constrains a to be either 0 or 1.
let one = cs.one();
cs.enforce( cs.enforce(
|| "boolean constraint", || "boolean constraint",
LinearCombination::zero() + one - var, |lc| lc + CS::one() - var,
LinearCombination::zero() + var, |lc| lc + var,
LinearCombination::zero() |lc| lc
); );
Ok(AllocatedBit { Ok(AllocatedBit {
@ -74,7 +74,7 @@ impl<Var: Copy> AllocatedBit<Var> {
b: &Self b: &Self
) -> Result<Self, SynthesisError> ) -> Result<Self, SynthesisError>
where E: Engine, where E: Engine,
CS: ConstraintSystem<E, Variable=Var> CS: ConstraintSystem<E>
{ {
let mut result_value = None; let mut result_value = None;
@ -107,9 +107,9 @@ impl<Var: Copy> AllocatedBit<Var> {
// (a + a) * b = a + b - c // (a + a) * b = a + b - c
cs.enforce( cs.enforce(
|| "xor constraint", || "xor constraint",
LinearCombination::zero() + a.variable + a.variable, |lc| lc + a.variable + a.variable,
LinearCombination::zero() + b.variable, |lc| lc + b.variable,
LinearCombination::zero() + a.variable + b.variable - result_var |lc| lc + a.variable + b.variable - result_var
); );
Ok(AllocatedBit { Ok(AllocatedBit {
@ -126,7 +126,7 @@ impl<Var: Copy> AllocatedBit<Var> {
b: &Self b: &Self
) -> Result<Self, SynthesisError> ) -> Result<Self, SynthesisError>
where E: Engine, where E: Engine,
CS: ConstraintSystem<E, Variable=Var> CS: ConstraintSystem<E>
{ {
let mut result_value = None; let mut result_value = None;
@ -146,9 +146,9 @@ impl<Var: Copy> AllocatedBit<Var> {
// a AND b are both 1. // a AND b are both 1.
cs.enforce( cs.enforce(
|| "and constraint", || "and constraint",
LinearCombination::zero() + a.variable, |lc| lc + a.variable,
LinearCombination::zero() + b.variable, |lc| lc + b.variable,
LinearCombination::zero() + result_var |lc| lc + result_var
); );
Ok(AllocatedBit { Ok(AllocatedBit {
@ -164,7 +164,7 @@ impl<Var: Copy> AllocatedBit<Var> {
b: &Self b: &Self
) -> Result<Self, SynthesisError> ) -> Result<Self, SynthesisError>
where E: Engine, where E: Engine,
CS: ConstraintSystem<E, Variable=Var> CS: ConstraintSystem<E>
{ {
let mut result_value = None; let mut result_value = None;
@ -182,12 +182,11 @@ impl<Var: Copy> AllocatedBit<Var> {
// Constrain (a) * (1 - b) = (c), ensuring c is 1 iff // Constrain (a) * (1 - b) = (c), ensuring c is 1 iff
// a is true and b is false, and otherwise c is 0. // a is true and b is false, and otherwise c is 0.
let one = cs.one();
cs.enforce( cs.enforce(
|| "and not constraint", || "and not constraint",
LinearCombination::zero() + a.variable, |lc| lc + a.variable,
LinearCombination::zero() + one - b.variable, |lc| lc + CS::one() - b.variable,
LinearCombination::zero() + result_var |lc| lc + result_var
); );
Ok(AllocatedBit { Ok(AllocatedBit {
@ -203,7 +202,7 @@ impl<Var: Copy> AllocatedBit<Var> {
b: &Self b: &Self
) -> Result<Self, SynthesisError> ) -> Result<Self, SynthesisError>
where E: Engine, where E: Engine,
CS: ConstraintSystem<E, Variable=Var> CS: ConstraintSystem<E>
{ {
let mut result_value = None; let mut result_value = None;
@ -221,12 +220,11 @@ impl<Var: Copy> AllocatedBit<Var> {
// Constrain (1 - a) * (1 - b) = (c), ensuring c is 1 iff // Constrain (1 - a) * (1 - b) = (c), ensuring c is 1 iff
// a and b are both false, and otherwise c is 0. // a and b are both false, and otherwise c is 0.
let one = cs.one();
cs.enforce( cs.enforce(
|| "nor constraint", || "nor constraint",
LinearCombination::zero() + one - a.variable, |lc| lc + CS::one() - a.variable,
LinearCombination::zero() + one - b.variable, |lc| lc + CS::one() - b.variable,
LinearCombination::zero() + result_var |lc| lc + result_var
); );
Ok(AllocatedBit { Ok(AllocatedBit {
@ -239,23 +237,23 @@ impl<Var: Copy> AllocatedBit<Var> {
/// This is a boolean value which may be either a constant or /// This is a boolean value which may be either a constant or
/// an interpretation of an `AllocatedBit`. /// an interpretation of an `AllocatedBit`.
#[derive(Clone)] #[derive(Clone)]
pub enum Boolean<Var> { pub enum Boolean {
/// Existential view of the boolean variable /// Existential view of the boolean variable
Is(AllocatedBit<Var>), Is(AllocatedBit),
/// Negated view of the boolean variable /// Negated view of the boolean variable
Not(AllocatedBit<Var>), Not(AllocatedBit),
/// Constant (not an allocated variable) /// Constant (not an allocated variable)
Constant(bool) Constant(bool)
} }
impl<Var: Copy> Boolean<Var> { impl Boolean {
pub fn enforce_equal<E, CS>( pub fn enforce_equal<E, CS>(
mut cs: CS, mut cs: CS,
a: &Self, a: &Self,
b: &Self b: &Self
) -> Result<(), SynthesisError> ) -> Result<(), SynthesisError>
where E: Engine, where E: Engine,
CS: ConstraintSystem<E, Variable=Var> CS: ConstraintSystem<E>
{ {
let c = Self::xor(&mut cs, a, b)?; let c = Self::xor(&mut cs, a, b)?;
@ -270,21 +268,25 @@ impl<Var: Copy> Boolean<Var> {
} }
} }
pub fn lc<E: Engine>(&self, one: Var, coeff: E::Fr) -> LinearCombination<Var, E> pub fn lc<E: Engine>(
&self,
one: Variable,
coeff: E::Fr
) -> LinearCombination<E>
{ {
match self { match self {
&Boolean::Constant(c) => { &Boolean::Constant(c) => {
if c { if c {
LinearCombination::<Var, E>::zero() + (coeff, one) LinearCombination::<E>::zero() + (coeff, one)
} else { } else {
LinearCombination::<Var, E>::zero() LinearCombination::<E>::zero()
} }
}, },
&Boolean::Is(ref v) => { &Boolean::Is(ref v) => {
LinearCombination::<Var, E>::zero() + (coeff, v.get_variable()) LinearCombination::<E>::zero() + (coeff, v.get_variable())
}, },
&Boolean::Not(ref v) => { &Boolean::Not(ref v) => {
LinearCombination::<Var, E>::zero() + (coeff, one) - (coeff, v.get_variable()) LinearCombination::<E>::zero() + (coeff, one) - (coeff, v.get_variable())
} }
} }
} }
@ -310,7 +312,7 @@ impl<Var: Copy> Boolean<Var> {
b: &'a Self b: &'a Self
) -> Result<Self, SynthesisError> ) -> Result<Self, SynthesisError>
where E: Engine, where E: Engine,
CS: ConstraintSystem<E, Variable=Var> CS: ConstraintSystem<E>
{ {
match (a, b) { match (a, b) {
(&Boolean::Constant(false), x) | (x, &Boolean::Constant(false)) => Ok(x.clone()), (&Boolean::Constant(false), x) | (x, &Boolean::Constant(false)) => Ok(x.clone()),
@ -337,7 +339,7 @@ impl<Var: Copy> Boolean<Var> {
b: &'a Self b: &'a Self
) -> Result<Self, SynthesisError> ) -> Result<Self, SynthesisError>
where E: Engine, where E: Engine,
CS: ConstraintSystem<E, Variable=Var> CS: ConstraintSystem<E>
{ {
match (a, b) { match (a, b) {
// false AND x is always false // false AND x is always false
@ -364,7 +366,7 @@ impl<Var: Copy> Boolean<Var> {
bits: &[Self] bits: &[Self]
) -> Result<Self, SynthesisError> ) -> Result<Self, SynthesisError>
where E: Engine, where E: Engine,
CS: ConstraintSystem<E, Variable=Var> CS: ConstraintSystem<E>
{ {
assert!(bits.len() > 0); assert!(bits.len() > 0);
let mut bits = bits.iter(); let mut bits = bits.iter();
@ -387,7 +389,7 @@ impl<Var: Copy> Boolean<Var> {
bits: &[Self] bits: &[Self]
) -> Result<(), SynthesisError> ) -> Result<(), SynthesisError>
where E: Engine, where E: Engine,
CS: ConstraintSystem<E, Variable=Var> CS: ConstraintSystem<E>
{ {
let res = Self::kary_and(&mut cs, bits)?; let res = Self::kary_and(&mut cs, bits)?;
@ -396,25 +398,24 @@ impl<Var: Copy> Boolean<Var> {
Ok(()) Ok(())
}, },
Boolean::Constant(true) => { Boolean::Constant(true) => {
Err(SynthesisError::AssignmentMissing) Err(SynthesisError::Unsatisfiable)
}, },
Boolean::Is(ref res) => { Boolean::Is(ref res) => {
cs.enforce( cs.enforce(
|| "enforce nand", || "enforce nand",
LinearCombination::zero(), |lc| lc,
LinearCombination::zero(), |lc| lc,
LinearCombination::zero() + res.get_variable() |lc| lc + res.get_variable()
); );
Ok(()) Ok(())
}, },
Boolean::Not(ref res) => { Boolean::Not(ref res) => {
let one = cs.one();
cs.enforce( cs.enforce(
|| "enforce nand", || "enforce nand",
LinearCombination::zero(), |lc| lc,
LinearCombination::zero(), |lc| lc,
LinearCombination::zero() + one - res.get_variable() |lc| lc + CS::one() - res.get_variable()
); );
Ok(()) Ok(())
@ -429,7 +430,7 @@ impl<Var: Copy> Boolean<Var> {
bits: &[Self] bits: &[Self]
) -> Result<(), SynthesisError> ) -> Result<(), SynthesisError>
where E: Engine, where E: Engine,
CS: ConstraintSystem<E, Variable=Var> CS: ConstraintSystem<E>
{ {
assert_eq!(bits.len(), F::NUM_BITS as usize); assert_eq!(bits.len(), F::NUM_BITS as usize);
@ -440,7 +441,7 @@ impl<Var: Copy> Boolean<Var> {
b.sub_noborrow(&1.into()); b.sub_noborrow(&1.into());
// Runs of ones in r // Runs of ones in r
let mut last_run = Boolean::<Var>::constant(true); let mut last_run = Boolean::constant(true);
let mut current_run = vec![]; let mut current_run = vec![];
let mut found_one = false; let mut found_one = false;
@ -495,8 +496,8 @@ impl<Var: Copy> Boolean<Var> {
} }
} }
impl<Var> From<AllocatedBit<Var>> for Boolean<Var> { impl From<AllocatedBit> for Boolean {
fn from(b: AllocatedBit<Var>) -> Boolean<Var> { fn from(b: AllocatedBit) -> Boolean {
Boolean::Is(b) Boolean::Is(b)
} }
} }

View File

@ -3,8 +3,7 @@ use super::*;
use super::num::AllocatedNum; use super::num::AllocatedNum;
use super::boolean::Boolean; use super::boolean::Boolean;
use bellman::{ use bellman::{
ConstraintSystem, ConstraintSystem
LinearCombination
}; };
// Synthesize the constants for each base pattern. // Synthesize the constants for each base pattern.
@ -32,12 +31,12 @@ fn synth<'a, E: Engine, I>(
/// Performs a 3-bit window table lookup. `bits` is in /// Performs a 3-bit window table lookup. `bits` is in
/// little-endian order. /// little-endian order.
pub fn lookup3_xy<E: Engine, CS, Var: Copy>( pub fn lookup3_xy<E: Engine, CS>(
mut cs: CS, mut cs: CS,
bits: &[Boolean<Var>], bits: &[Boolean],
coords: &[(E::Fr, E::Fr)] coords: &[(E::Fr, E::Fr)]
) -> Result<(AllocatedNum<E, Var>, AllocatedNum<E, Var>), SynthesisError> ) -> Result<(AllocatedNum<E>, AllocatedNum<E>), SynthesisError>
where CS: ConstraintSystem<E, Variable=Var> where CS: ConstraintSystem<E>
{ {
assert_eq!(bits.len(), 3); assert_eq!(bits.len(), 3);
assert_eq!(coords.len(), 8); assert_eq!(coords.len(), 8);
@ -85,16 +84,16 @@ pub fn lookup3_xy<E: Engine, CS, Var: Copy>(
let precomp = Boolean::and(cs.namespace(|| "precomp"), &bits[1], &bits[2])?; let precomp = Boolean::and(cs.namespace(|| "precomp"), &bits[1], &bits[2])?;
let one = cs.one(); let one = CS::one();
cs.enforce( cs.enforce(
|| "x-coordinate lookup", || "x-coordinate lookup",
LinearCombination::<Var, E>::zero() + (x_coeffs[0b001], one) |lc| lc + (x_coeffs[0b001], one)
+ &bits[1].lc::<E>(one, x_coeffs[0b011]) + &bits[1].lc::<E>(one, x_coeffs[0b011])
+ &bits[2].lc::<E>(one, x_coeffs[0b101]) + &bits[2].lc::<E>(one, x_coeffs[0b101])
+ &precomp.lc::<E>(one, x_coeffs[0b111]), + &precomp.lc::<E>(one, x_coeffs[0b111]),
LinearCombination::<Var, E>::zero() + &bits[0].lc::<E>(one, E::Fr::one()), |lc| lc + &bits[0].lc::<E>(one, E::Fr::one()),
LinearCombination::<Var, E>::zero() + res_x.get_variable() |lc| lc + res_x.get_variable()
- (x_coeffs[0b000], one) - (x_coeffs[0b000], one)
- &bits[1].lc::<E>(one, x_coeffs[0b010]) - &bits[1].lc::<E>(one, x_coeffs[0b010])
- &bits[2].lc::<E>(one, x_coeffs[0b100]) - &bits[2].lc::<E>(one, x_coeffs[0b100])
@ -103,12 +102,12 @@ pub fn lookup3_xy<E: Engine, CS, Var: Copy>(
cs.enforce( cs.enforce(
|| "y-coordinate lookup", || "y-coordinate lookup",
LinearCombination::<Var, E>::zero() + (y_coeffs[0b001], one) |lc| lc + (y_coeffs[0b001], one)
+ &bits[1].lc::<E>(one, y_coeffs[0b011]) + &bits[1].lc::<E>(one, y_coeffs[0b011])
+ &bits[2].lc::<E>(one, y_coeffs[0b101]) + &bits[2].lc::<E>(one, y_coeffs[0b101])
+ &precomp.lc::<E>(one, y_coeffs[0b111]), + &precomp.lc::<E>(one, y_coeffs[0b111]),
LinearCombination::<Var, E>::zero() + &bits[0].lc::<E>(one, E::Fr::one()), |lc| lc + &bits[0].lc::<E>(one, E::Fr::one()),
LinearCombination::<Var, E>::zero() + res_y.get_variable() |lc| lc + res_y.get_variable()
- (y_coeffs[0b000], one) - (y_coeffs[0b000], one)
- &bits[1].lc::<E>(one, y_coeffs[0b010]) - &bits[1].lc::<E>(one, y_coeffs[0b010])
- &bits[2].lc::<E>(one, y_coeffs[0b100]) - &bits[2].lc::<E>(one, y_coeffs[0b100])
@ -120,12 +119,12 @@ pub fn lookup3_xy<E: Engine, CS, Var: Copy>(
/// Performs a 3-bit window table lookup, where /// Performs a 3-bit window table lookup, where
/// one of the bits is a sign bit. /// one of the bits is a sign bit.
pub fn lookup3_xy_with_conditional_negation<E: Engine, CS, Var: Copy>( pub fn lookup3_xy_with_conditional_negation<E: Engine, CS>(
mut cs: CS, mut cs: CS,
bits: &[Boolean<Var>], bits: &[Boolean],
coords: &[(E::Fr, E::Fr)] coords: &[(E::Fr, E::Fr)]
) -> Result<(AllocatedNum<E, Var>, AllocatedNum<E, Var>), SynthesisError> ) -> Result<(AllocatedNum<E>, AllocatedNum<E>), SynthesisError>
where CS: ConstraintSystem<E, Variable=Var> where CS: ConstraintSystem<E>
{ {
assert_eq!(bits.len(), 3); assert_eq!(bits.len(), 3);
assert_eq!(coords.len(), 4); assert_eq!(coords.len(), 4);
@ -162,7 +161,7 @@ pub fn lookup3_xy_with_conditional_negation<E: Engine, CS, Var: Copy>(
} }
)?; )?;
let one = cs.one(); let one = CS::one();
// Compute the coefficients for the lookup constraints // Compute the coefficients for the lookup constraints
let mut x_coeffs = [E::Fr::zero(); 4]; let mut x_coeffs = [E::Fr::zero(); 4];
@ -172,20 +171,20 @@ pub fn lookup3_xy_with_conditional_negation<E: Engine, CS, Var: Copy>(
cs.enforce( cs.enforce(
|| "x-coordinate lookup", || "x-coordinate lookup",
LinearCombination::<Var, E>::zero() + (x_coeffs[0b01], one) |lc| lc + (x_coeffs[0b01], one)
+ &bits[1].lc::<E>(one, x_coeffs[0b11]), + &bits[1].lc::<E>(one, x_coeffs[0b11]),
LinearCombination::<Var, E>::zero() + &bits[0].lc::<E>(one, E::Fr::one()), |lc| lc + &bits[0].lc::<E>(one, E::Fr::one()),
LinearCombination::<Var, E>::zero() + res_x.get_variable() |lc| lc + res_x.get_variable()
- (x_coeffs[0b00], one) - (x_coeffs[0b00], one)
- &bits[1].lc::<E>(one, x_coeffs[0b10]) - &bits[1].lc::<E>(one, x_coeffs[0b10])
); );
cs.enforce( cs.enforce(
|| "y-coordinate lookup", || "y-coordinate lookup",
LinearCombination::<Var, E>::zero() + (y_coeffs[0b01], one) |lc| lc + (y_coeffs[0b01], one)
+ &bits[1].lc::<E>(one, y_coeffs[0b11]), + &bits[1].lc::<E>(one, y_coeffs[0b11]),
LinearCombination::<Var, E>::zero() + &bits[0].lc::<E>(one, E::Fr::one()), |lc| lc + &bits[0].lc::<E>(one, E::Fr::one()),
LinearCombination::<Var, E>::zero() + res_y.get_variable() |lc| lc + res_y.get_variable()
- (y_coeffs[0b00], one) - (y_coeffs[0b00], one)
- &bits[1].lc::<E>(one, y_coeffs[0b10]) - &bits[1].lc::<E>(one, y_coeffs[0b10])
); );
@ -290,7 +289,7 @@ mod test {
let window_size = 4; let window_size = 4;
let mut assignment = vec![Fr::zero(); (1 << window_size)]; let mut assignment = vec![Fr::zero(); 1 << window_size];
let constants: Vec<_> = (0..(1 << window_size)).map(|_| Fr::rand(&mut rng)).collect(); let constants: Vec<_> = (0..(1 << window_size)).map(|_| Fr::rand(&mut rng)).collect();
synth::<Bls12, _>(window_size, &constants, &mut assignment); synth::<Bls12, _>(window_size, &constants, &mut assignment);

View File

@ -5,8 +5,8 @@ pub mod boolean;
pub mod uint32; pub mod uint32;
pub mod blake2s; pub mod blake2s;
pub mod num; pub mod num;
pub mod mont;
pub mod lookup; pub mod lookup;
pub mod mont;
pub mod pedersen_hash; pub mod pedersen_hash;
use bellman::SynthesisError; use bellman::SynthesisError;

View File

@ -5,8 +5,7 @@ use pairing::{
use bellman::{ use bellman::{
SynthesisError, SynthesisError,
ConstraintSystem, ConstraintSystem
LinearCombination
}; };
use super::{ use super::{
@ -27,12 +26,12 @@ use super::lookup::{
use super::boolean::Boolean; use super::boolean::Boolean;
pub struct EdwardsPoint<E: Engine, Var> { pub struct EdwardsPoint<E: Engine> {
pub x: AllocatedNum<E, Var>, pub x: AllocatedNum<E>,
pub y: AllocatedNum<E, Var> pub y: AllocatedNum<E>
} }
impl<E: Engine, Var: Copy> Clone for EdwardsPoint<E, Var> { impl<E: Engine> Clone for EdwardsPoint<E> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
EdwardsPoint { EdwardsPoint {
x: self.x.clone(), x: self.x.clone(),
@ -44,15 +43,14 @@ impl<E: Engine, Var: Copy> Clone for EdwardsPoint<E, Var> {
/// Perform a fixed-base scalar multiplication with /// Perform a fixed-base scalar multiplication with
/// `by` being in little-endian bit order. `by` must /// `by` being in little-endian bit order. `by` must
/// be a multiple of 3. /// be a multiple of 3.
pub fn fixed_base_multiplication<E, Var, CS>( pub fn fixed_base_multiplication<E, CS>(
mut cs: CS, mut cs: CS,
base: FixedGenerators, base: FixedGenerators,
by: &[Boolean<Var>], by: &[Boolean],
params: &E::Params params: &E::Params
) -> Result<EdwardsPoint<E, Var>, SynthesisError> ) -> Result<EdwardsPoint<E>, SynthesisError>
where CS: ConstraintSystem<E, Variable=Var>, where CS: ConstraintSystem<E>,
E: JubjubEngine, E: JubjubEngine
Var: Copy
{ {
// We're going to chunk the scalar into 3-bit windows, // We're going to chunk the scalar into 3-bit windows,
// so let's force the caller to supply the right number // so let's force the caller to supply the right number
@ -91,10 +89,10 @@ pub fn fixed_base_multiplication<E, Var, CS>(
Ok(result.get()?.clone()) Ok(result.get()?.clone())
} }
impl<E: JubjubEngine, Var: Copy> EdwardsPoint<E, Var> { impl<E: JubjubEngine> EdwardsPoint<E> {
/// This extracts the x-coordinate, which is an injective /// This extracts the x-coordinate, which is an injective
/// encoding for elements of the prime order subgroup. /// encoding for elements of the prime order subgroup.
pub fn into_num(&self) -> AllocatedNum<E, Var> { pub fn into_num(&self) -> AllocatedNum<E> {
self.x.clone() self.x.clone()
} }
@ -103,9 +101,9 @@ impl<E: JubjubEngine, Var: Copy> EdwardsPoint<E, Var> {
pub fn conditionally_select<CS>( pub fn conditionally_select<CS>(
&self, &self,
mut cs: CS, mut cs: CS,
condition: &Boolean<Var> condition: &Boolean
) -> Result<Self, SynthesisError> ) -> Result<Self, SynthesisError>
where CS: ConstraintSystem<E, Variable=Var> where CS: ConstraintSystem<E>
{ {
// Compute x' = self.x if condition, and 0 otherwise // Compute x' = self.x if condition, and 0 otherwise
let x_prime = AllocatedNum::alloc(cs.namespace(|| "x'"), || { let x_prime = AllocatedNum::alloc(cs.namespace(|| "x'"), || {
@ -119,12 +117,12 @@ impl<E: JubjubEngine, Var: Copy> EdwardsPoint<E, Var> {
// condition * x = x' // condition * x = x'
// if condition is 0, x' must be 0 // if condition is 0, x' must be 0
// if condition is 1, x' must be x // if condition is 1, x' must be x
let one = cs.one(); let one = CS::one();
cs.enforce( cs.enforce(
|| "x' computation", || "x' computation",
LinearCombination::<Var, E>::zero() + self.x.get_variable(), |lc| lc + self.x.get_variable(),
condition.lc(one, E::Fr::one()), |_| condition.lc(one, E::Fr::one()),
LinearCombination::<Var, E>::zero() + x_prime.get_variable() |lc| lc + x_prime.get_variable()
); );
// Compute y' = self.y if condition, and 1 otherwise // Compute y' = self.y if condition, and 1 otherwise
@ -141,9 +139,9 @@ impl<E: JubjubEngine, Var: Copy> EdwardsPoint<E, Var> {
// if condition is 1, y' must be y // if condition is 1, y' must be y
cs.enforce( cs.enforce(
|| "y' computation", || "y' computation",
LinearCombination::<Var, E>::zero() + self.y.get_variable(), |lc| lc + self.y.get_variable(),
condition.lc(one, E::Fr::one()), |_| condition.lc(one, E::Fr::one()),
LinearCombination::<Var, E>::zero() + y_prime.get_variable() |lc| lc + y_prime.get_variable()
- &condition.not().lc(one, E::Fr::one()) - &condition.not().lc(one, E::Fr::one())
); );
@ -159,10 +157,10 @@ impl<E: JubjubEngine, Var: Copy> EdwardsPoint<E, Var> {
pub fn mul<CS>( pub fn mul<CS>(
&self, &self,
mut cs: CS, mut cs: CS,
by: &[Boolean<Var>], by: &[Boolean],
params: &E::Params params: &E::Params
) -> Result<Self, SynthesisError> ) -> Result<Self, SynthesisError>
where CS: ConstraintSystem<E, Variable=Var> where CS: ConstraintSystem<E>
{ {
// Represents the current "magnitude" of the base // Represents the current "magnitude" of the base
// that we're operating over. Starts at self, // that we're operating over. Starts at self,
@ -210,11 +208,11 @@ impl<E: JubjubEngine, Var: Copy> EdwardsPoint<E, Var> {
pub fn interpret<CS>( pub fn interpret<CS>(
mut cs: CS, mut cs: CS,
x: &AllocatedNum<E, Var>, x: &AllocatedNum<E>,
y: &AllocatedNum<E, Var>, y: &AllocatedNum<E>,
params: &E::Params params: &E::Params
) -> Result<Self, SynthesisError> ) -> Result<Self, SynthesisError>
where CS: ConstraintSystem<E, Variable=Var> where CS: ConstraintSystem<E>
{ {
// -x^2 + y^2 = 1 + dx^2y^2 // -x^2 + y^2 = 1 + dx^2y^2
@ -222,13 +220,13 @@ impl<E: JubjubEngine, Var: Copy> EdwardsPoint<E, Var> {
let y2 = y.square(cs.namespace(|| "y^2"))?; let y2 = y.square(cs.namespace(|| "y^2"))?;
let x2y2 = x2.mul(cs.namespace(|| "x^2 y^2"), &y2)?; let x2y2 = x2.mul(cs.namespace(|| "x^2 y^2"), &y2)?;
let one = cs.one(); let one = CS::one();
cs.enforce( cs.enforce(
|| "on curve check", || "on curve check",
LinearCombination::zero() - x2.get_variable() |lc| lc - x2.get_variable()
+ y2.get_variable(), + y2.get_variable(),
LinearCombination::zero() + one, |lc| lc + one,
LinearCombination::zero() + one |lc| lc + one
+ (*params.edwards_d(), x2y2.get_variable()) + (*params.edwards_d(), x2y2.get_variable())
); );
@ -243,7 +241,7 @@ impl<E: JubjubEngine, Var: Copy> EdwardsPoint<E, Var> {
cs: CS, cs: CS,
params: &E::Params params: &E::Params
) -> Result<Self, SynthesisError> ) -> Result<Self, SynthesisError>
where CS: ConstraintSystem<E, Variable=Var> where CS: ConstraintSystem<E>
{ {
self.add(cs, self, params) self.add(cs, self, params)
} }
@ -255,7 +253,7 @@ impl<E: JubjubEngine, Var: Copy> EdwardsPoint<E, Var> {
other: &Self, other: &Self,
params: &E::Params params: &E::Params
) -> Result<Self, SynthesisError> ) -> Result<Self, SynthesisError>
where CS: ConstraintSystem<E, Variable=Var> where CS: ConstraintSystem<E>
{ {
// Compute U = (x1 + y1) * (x2 + y2) // Compute U = (x1 + y1) * (x2 + y2)
let u = AllocatedNum::alloc(cs.namespace(|| "U"), || { let u = AllocatedNum::alloc(cs.namespace(|| "U"), || {
@ -272,11 +270,11 @@ impl<E: JubjubEngine, Var: Copy> EdwardsPoint<E, Var> {
cs.enforce( cs.enforce(
|| "U computation", || "U computation",
LinearCombination::<Var, E>::zero() + self.x.get_variable() |lc| lc + self.x.get_variable()
+ self.y.get_variable(), + self.y.get_variable(),
LinearCombination::<Var, E>::zero() + other.x.get_variable() |lc| lc + other.x.get_variable()
+ other.y.get_variable(), + other.y.get_variable(),
LinearCombination::<Var, E>::zero() + u.get_variable() |lc| lc + u.get_variable()
); );
// Compute A = y2 * x1 // Compute A = y2 * x1
@ -296,9 +294,9 @@ impl<E: JubjubEngine, Var: Copy> EdwardsPoint<E, Var> {
cs.enforce( cs.enforce(
|| "C computation", || "C computation",
LinearCombination::<Var, E>::zero() + (*params.edwards_d(), a.get_variable()), |lc| lc + (*params.edwards_d(), a.get_variable()),
LinearCombination::<Var, E>::zero() + b.get_variable(), |lc| lc + b.get_variable(),
LinearCombination::<Var, E>::zero() + c.get_variable() |lc| lc + c.get_variable()
); );
// Compute x3 = (A + B) / (1 + C) // Compute x3 = (A + B) / (1 + C)
@ -316,17 +314,17 @@ impl<E: JubjubEngine, Var: Copy> EdwardsPoint<E, Var> {
Ok(t0) Ok(t0)
}, },
None => { None => {
Err(SynthesisError::AssignmentMissing) Err(SynthesisError::DivisionByZero)
} }
} }
})?; })?;
let one = cs.one(); let one = CS::one();
cs.enforce( cs.enforce(
|| "x3 computation", || "x3 computation",
LinearCombination::<Var, E>::zero() + one + c.get_variable(), |lc| lc + one + c.get_variable(),
LinearCombination::<Var, E>::zero() + x3.get_variable(), |lc| lc + x3.get_variable(),
LinearCombination::<Var, E>::zero() + a.get_variable() |lc| lc + a.get_variable()
+ b.get_variable() + b.get_variable()
); );
@ -346,16 +344,16 @@ impl<E: JubjubEngine, Var: Copy> EdwardsPoint<E, Var> {
Ok(t0) Ok(t0)
}, },
None => { None => {
Err(SynthesisError::AssignmentMissing) Err(SynthesisError::DivisionByZero)
} }
} }
})?; })?;
cs.enforce( cs.enforce(
|| "y3 computation", || "y3 computation",
LinearCombination::<Var, E>::zero() + one - c.get_variable(), |lc| lc + one - c.get_variable(),
LinearCombination::<Var, E>::zero() + y3.get_variable(), |lc| lc + y3.get_variable(),
LinearCombination::<Var, E>::zero() + u.get_variable() |lc| lc + u.get_variable()
- a.get_variable() - a.get_variable()
- b.get_variable() - b.get_variable()
); );
@ -367,12 +365,12 @@ impl<E: JubjubEngine, Var: Copy> EdwardsPoint<E, Var> {
} }
} }
pub struct MontgomeryPoint<E: Engine, Var> { pub struct MontgomeryPoint<E: Engine> {
x: AllocatedNum<E, Var>, x: AllocatedNum<E>,
y: AllocatedNum<E, Var> y: AllocatedNum<E>
} }
impl<E: JubjubEngine, Var: Copy> MontgomeryPoint<E, Var> { impl<E: JubjubEngine> MontgomeryPoint<E> {
/// Converts an element in the prime order subgroup into /// Converts an element in the prime order subgroup into
/// a point in the birationally equivalent twisted /// a point in the birationally equivalent twisted
/// Edwards curve. /// Edwards curve.
@ -380,8 +378,8 @@ impl<E: JubjubEngine, Var: Copy> MontgomeryPoint<E, Var> {
&self, &self,
mut cs: CS, mut cs: CS,
params: &E::Params params: &E::Params
) -> Result<EdwardsPoint<E, Var>, SynthesisError> ) -> Result<EdwardsPoint<E>, SynthesisError>
where CS: ConstraintSystem<E, Variable=Var> where CS: ConstraintSystem<E>
{ {
// Compute u = (scale*x) / y // Compute u = (scale*x) / y
let u = AllocatedNum::alloc(cs.namespace(|| "u"), || { let u = AllocatedNum::alloc(cs.namespace(|| "u"), || {
@ -395,16 +393,16 @@ impl<E: JubjubEngine, Var: Copy> MontgomeryPoint<E, Var> {
Ok(t0) Ok(t0)
}, },
None => { None => {
Err(SynthesisError::AssignmentMissing) Err(SynthesisError::DivisionByZero)
} }
} }
})?; })?;
cs.enforce( cs.enforce(
|| "u computation", || "u computation",
LinearCombination::<Var, E>::zero() + self.y.get_variable(), |lc| lc + self.y.get_variable(),
LinearCombination::<Var, E>::zero() + u.get_variable(), |lc| lc + u.get_variable(),
LinearCombination::<Var, E>::zero() + (*params.scale(), self.x.get_variable()) |lc| lc + (*params.scale(), self.x.get_variable())
); );
// Compute v = (x - 1) / (x + 1) // Compute v = (x - 1) / (x + 1)
@ -421,18 +419,18 @@ impl<E: JubjubEngine, Var: Copy> MontgomeryPoint<E, Var> {
Ok(t0) Ok(t0)
}, },
None => { None => {
Err(SynthesisError::AssignmentMissing) Err(SynthesisError::DivisionByZero)
} }
} }
})?; })?;
let one = cs.one(); let one = CS::one();
cs.enforce( cs.enforce(
|| "v computation", || "v computation",
LinearCombination::<Var, E>::zero() + self.x.get_variable() |lc| lc + self.x.get_variable()
+ one, + one,
LinearCombination::<Var, E>::zero() + v.get_variable(), |lc| lc + v.get_variable(),
LinearCombination::<Var, E>::zero() + self.x.get_variable() |lc| lc + self.x.get_variable()
- one, - one,
); );
@ -447,8 +445,8 @@ impl<E: JubjubEngine, Var: Copy> MontgomeryPoint<E, Var> {
/// on the curve. Useful for constants and /// on the curve. Useful for constants and
/// window table lookups. /// window table lookups.
pub fn interpret_unchecked( pub fn interpret_unchecked(
x: AllocatedNum<E, Var>, x: AllocatedNum<E>,
y: AllocatedNum<E, Var> y: AllocatedNum<E>
) -> Self ) -> Self
{ {
MontgomeryPoint { MontgomeryPoint {
@ -465,7 +463,7 @@ impl<E: JubjubEngine, Var: Copy> MontgomeryPoint<E, Var> {
other: &Self, other: &Self,
params: &E::Params params: &E::Params
) -> Result<Self, SynthesisError> ) -> Result<Self, SynthesisError>
where CS: ConstraintSystem<E, Variable=Var> where CS: ConstraintSystem<E>
{ {
// Compute lambda = (y' - y) / (x' - x) // Compute lambda = (y' - y) / (x' - x)
let lambda = AllocatedNum::alloc(cs.namespace(|| "lambda"), || { let lambda = AllocatedNum::alloc(cs.namespace(|| "lambda"), || {
@ -481,19 +479,19 @@ impl<E: JubjubEngine, Var: Copy> MontgomeryPoint<E, Var> {
Ok(n) Ok(n)
}, },
None => { None => {
Err(SynthesisError::AssignmentMissing) Err(SynthesisError::DivisionByZero)
} }
} }
})?; })?;
cs.enforce( cs.enforce(
|| "evaluate lambda", || "evaluate lambda",
LinearCombination::<Var, E>::zero() + other.x.get_variable() |lc| lc + other.x.get_variable()
- self.x.get_variable(), - self.x.get_variable(),
LinearCombination::zero() + lambda.get_variable(), |lc| lc + lambda.get_variable(),
LinearCombination::<Var, E>::zero() + other.y.get_variable() |lc| lc + other.y.get_variable()
- self.y.get_variable() - self.y.get_variable()
); );
@ -509,12 +507,12 @@ impl<E: JubjubEngine, Var: Copy> MontgomeryPoint<E, Var> {
})?; })?;
// (lambda) * (lambda) = (A + x + x' + x'') // (lambda) * (lambda) = (A + x + x' + x'')
let one = cs.one(); let one = CS::one();
cs.enforce( cs.enforce(
|| "evaluate xprime", || "evaluate xprime",
LinearCombination::zero() + lambda.get_variable(), |lc| lc + lambda.get_variable(),
LinearCombination::zero() + lambda.get_variable(), |lc| lc + lambda.get_variable(),
LinearCombination::<Var, E>::zero() + (*params.montgomery_a(), one) |lc| lc + (*params.montgomery_a(), one)
+ self.x.get_variable() + self.x.get_variable()
+ other.x.get_variable() + other.x.get_variable()
+ xprime.get_variable() + xprime.get_variable()
@ -534,12 +532,12 @@ impl<E: JubjubEngine, Var: Copy> MontgomeryPoint<E, Var> {
// y' + y = lambda(x - x') // y' + y = lambda(x - x')
cs.enforce( cs.enforce(
|| "evaluate yprime", || "evaluate yprime",
LinearCombination::zero() + self.x.get_variable() |lc| lc + self.x.get_variable()
- xprime.get_variable(), - xprime.get_variable(),
LinearCombination::zero() + lambda.get_variable(), |lc| lc + lambda.get_variable(),
LinearCombination::<Var, E>::zero() + yprime.get_variable() |lc| lc + yprime.get_variable()
+ self.y.get_variable() + self.y.get_variable()
); );
@ -556,7 +554,7 @@ impl<E: JubjubEngine, Var: Copy> MontgomeryPoint<E, Var> {
mut cs: CS, mut cs: CS,
params: &E::Params params: &E::Params
) -> Result<Self, SynthesisError> ) -> Result<Self, SynthesisError>
where CS: ConstraintSystem<E, Variable=Var> where CS: ConstraintSystem<E>
{ {
// Square x // Square x
let xx = self.x.square(&mut cs)?; let xx = self.x.square(&mut cs)?;
@ -580,21 +578,21 @@ impl<E: JubjubEngine, Var: Copy> MontgomeryPoint<E, Var> {
Ok(t0) Ok(t0)
}, },
None => { None => {
Err(SynthesisError::AssignmentMissing) Err(SynthesisError::DivisionByZero)
} }
} }
})?; })?;
// (2.y) * (lambda) = (3.xx + 2.A.x + 1) // (2.y) * (lambda) = (3.xx + 2.A.x + 1)
let one = cs.one(); let one = CS::one();
cs.enforce( cs.enforce(
|| "evaluate lambda", || "evaluate lambda",
LinearCombination::<Var, E>::zero() + self.y.get_variable() |lc| lc + self.y.get_variable()
+ self.y.get_variable(), + self.y.get_variable(),
LinearCombination::zero() + lambda.get_variable(), |lc| lc + lambda.get_variable(),
LinearCombination::<Var, E>::zero() + xx.get_variable() |lc| lc + xx.get_variable()
+ xx.get_variable() + xx.get_variable()
+ xx.get_variable() + xx.get_variable()
+ (*params.montgomery_2a(), self.x.get_variable()) + (*params.montgomery_2a(), self.x.get_variable())
@ -615,9 +613,9 @@ impl<E: JubjubEngine, Var: Copy> MontgomeryPoint<E, Var> {
// (lambda) * (lambda) = (A + 2.x + x') // (lambda) * (lambda) = (A + 2.x + x')
cs.enforce( cs.enforce(
|| "evaluate xprime", || "evaluate xprime",
LinearCombination::zero() + lambda.get_variable(), |lc| lc + lambda.get_variable(),
LinearCombination::zero() + lambda.get_variable(), |lc| lc + lambda.get_variable(),
LinearCombination::<Var, E>::zero() + (*params.montgomery_a(), one) |lc| lc + (*params.montgomery_a(), one)
+ self.x.get_variable() + self.x.get_variable()
+ self.x.get_variable() + self.x.get_variable()
+ xprime.get_variable() + xprime.get_variable()
@ -637,12 +635,12 @@ impl<E: JubjubEngine, Var: Copy> MontgomeryPoint<E, Var> {
// y' + y = lambda(x - x') // y' + y = lambda(x - x')
cs.enforce( cs.enforce(
|| "evaluate yprime", || "evaluate yprime",
LinearCombination::zero() + self.x.get_variable() |lc| lc + self.x.get_variable()
- xprime.get_variable(), - xprime.get_variable(),
LinearCombination::zero() + lambda.get_variable(), |lc| lc + lambda.get_variable(),
LinearCombination::<Var, E>::zero() + yprime.get_variable() |lc| lc + yprime.get_variable()
+ self.y.get_variable() + self.y.get_variable()
); );

View File

@ -8,7 +8,8 @@ use pairing::{
use bellman::{ use bellman::{
SynthesisError, SynthesisError,
ConstraintSystem, ConstraintSystem,
LinearCombination LinearCombination,
Variable
}; };
use super::{ use super::{
@ -20,12 +21,12 @@ use super::boolean::{
AllocatedBit AllocatedBit
}; };
pub struct AllocatedNum<E: Engine, Var> { pub struct AllocatedNum<E: Engine> {
value: Option<E::Fr>, value: Option<E::Fr>,
variable: Var variable: Variable
} }
impl<Var: Copy, E: Engine> Clone for AllocatedNum<E, Var> { impl<E: Engine> Clone for AllocatedNum<E> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
AllocatedNum { AllocatedNum {
value: self.value, value: self.value,
@ -34,12 +35,12 @@ impl<Var: Copy, E: Engine> Clone for AllocatedNum<E, Var> {
} }
} }
impl<E: Engine, Var: Copy> AllocatedNum<E, Var> { impl<E: Engine> AllocatedNum<E> {
pub fn alloc<CS, F>( pub fn alloc<CS, F>(
mut cs: CS, mut cs: CS,
value: F, value: F,
) -> Result<Self, SynthesisError> ) -> Result<Self, SynthesisError>
where CS: ConstraintSystem<E, Variable=Var>, where CS: ConstraintSystem<E>,
F: FnOnce() -> Result<E::Fr, SynthesisError> F: FnOnce() -> Result<E::Fr, SynthesisError>
{ {
let mut new_value = None; let mut new_value = None;
@ -60,8 +61,8 @@ impl<E: Engine, Var: Copy> AllocatedNum<E, Var> {
pub fn into_bits_strict<CS>( pub fn into_bits_strict<CS>(
&self, &self,
mut cs: CS mut cs: CS
) -> Result<Vec<Boolean<Var>>, SynthesisError> ) -> Result<Vec<Boolean>, SynthesisError>
where CS: ConstraintSystem<E, Variable=Var> where CS: ConstraintSystem<E>
{ {
let bits = self.into_bits(&mut cs)?; let bits = self.into_bits(&mut cs)?;
Boolean::enforce_in_field::<_, _, E::Fr>(&mut cs, &bits)?; Boolean::enforce_in_field::<_, _, E::Fr>(&mut cs, &bits)?;
@ -72,8 +73,8 @@ impl<E: Engine, Var: Copy> AllocatedNum<E, Var> {
pub fn into_bits<CS>( pub fn into_bits<CS>(
&self, &self,
mut cs: CS mut cs: CS
) -> Result<Vec<Boolean<Var>>, SynthesisError> ) -> Result<Vec<Boolean>, SynthesisError>
where CS: ConstraintSystem<E, Variable=Var> where CS: ConstraintSystem<E>
{ {
let bit_values = match self.value { let bit_values = match self.value {
Some(value) => { Some(value) => {
@ -122,9 +123,9 @@ impl<E: Engine, Var: Copy> AllocatedNum<E, Var> {
cs.enforce( cs.enforce(
|| "unpacking constraint", || "unpacking constraint",
LinearCombination::zero(), |lc| lc,
LinearCombination::zero(), |lc| lc,
lc |_| lc
); );
Ok(bits.into_iter().map(|b| Boolean::from(b)).collect()) Ok(bits.into_iter().map(|b| Boolean::from(b)).collect())
@ -132,16 +133,16 @@ impl<E: Engine, Var: Copy> AllocatedNum<E, Var> {
pub fn from_bits_strict<CS>( pub fn from_bits_strict<CS>(
mut cs: CS, mut cs: CS,
bits: &[Boolean<Var>] bits: &[Boolean]
) -> Result<Self, SynthesisError> ) -> Result<Self, SynthesisError>
where CS: ConstraintSystem<E, Variable=Var> where CS: ConstraintSystem<E>
{ {
assert_eq!(bits.len(), E::Fr::NUM_BITS as usize); assert_eq!(bits.len(), E::Fr::NUM_BITS as usize);
Boolean::enforce_in_field::<_, _, E::Fr>(&mut cs, bits)?; Boolean::enforce_in_field::<_, _, E::Fr>(&mut cs, bits)?;
let one = cs.one(); let one = CS::one();
let mut lc = LinearCombination::<Var, E>::zero(); let mut lc = LinearCombination::<E>::zero();
let mut coeff = E::Fr::one(); let mut coeff = E::Fr::one();
let mut value = Some(E::Fr::zero()); let mut value = Some(E::Fr::zero());
for bit in bits.iter().rev() { for bit in bits.iter().rev() {
@ -191,9 +192,9 @@ impl<E: Engine, Var: Copy> AllocatedNum<E, Var> {
cs.enforce( cs.enforce(
|| "packing constraint", || "packing constraint",
LinearCombination::zero(), |lc| lc,
LinearCombination::zero(), |lc| lc,
lc |_| lc
); );
Ok(num) Ok(num)
@ -204,7 +205,7 @@ impl<E: Engine, Var: Copy> AllocatedNum<E, Var> {
mut cs: CS, mut cs: CS,
other: &Self other: &Self
) -> Result<Self, SynthesisError> ) -> Result<Self, SynthesisError>
where CS: ConstraintSystem<E, Variable=Var> where CS: ConstraintSystem<E>
{ {
let mut value = None; let mut value = None;
@ -220,9 +221,9 @@ impl<E: Engine, Var: Copy> AllocatedNum<E, Var> {
// Constrain: a * b = ab // Constrain: a * b = ab
cs.enforce( cs.enforce(
|| "multiplication constraint", || "multiplication constraint",
LinearCombination::zero() + self.variable, |lc| lc + self.variable,
LinearCombination::zero() + other.variable, |lc| lc + other.variable,
LinearCombination::zero() + var |lc| lc + var
); );
Ok(AllocatedNum { Ok(AllocatedNum {
@ -235,7 +236,7 @@ impl<E: Engine, Var: Copy> AllocatedNum<E, Var> {
&self, &self,
mut cs: CS mut cs: CS
) -> Result<Self, SynthesisError> ) -> Result<Self, SynthesisError>
where CS: ConstraintSystem<E, Variable=Var> where CS: ConstraintSystem<E>
{ {
let mut value = None; let mut value = None;
@ -251,9 +252,9 @@ impl<E: Engine, Var: Copy> AllocatedNum<E, Var> {
// Constrain: a * a = aa // Constrain: a * a = aa
cs.enforce( cs.enforce(
|| "squaring constraint", || "squaring constraint",
LinearCombination::zero() + self.variable, |lc| lc + self.variable,
LinearCombination::zero() + self.variable, |lc| lc + self.variable,
LinearCombination::zero() + var |lc| lc + var
); );
Ok(AllocatedNum { Ok(AllocatedNum {
@ -266,13 +267,13 @@ impl<E: Engine, Var: Copy> AllocatedNum<E, Var> {
&self, &self,
mut cs: CS mut cs: CS
) -> Result<(), SynthesisError> ) -> Result<(), SynthesisError>
where CS: ConstraintSystem<E, Variable=Var> where CS: ConstraintSystem<E>
{ {
let inv = cs.alloc(|| "ephemeral inverse", || { let inv = cs.alloc(|| "ephemeral inverse", || {
let tmp = *self.value.get()?; let tmp = *self.value.get()?;
if tmp.is_zero() { if tmp.is_zero() {
Err(SynthesisError::AssignmentMissing) Err(SynthesisError::DivisionByZero)
} else { } else {
Ok(tmp.inverse().unwrap()) Ok(tmp.inverse().unwrap())
} }
@ -281,12 +282,11 @@ impl<E: Engine, Var: Copy> AllocatedNum<E, Var> {
// Constrain a * inv = 1, which is only valid // Constrain a * inv = 1, which is only valid
// iff a has a multiplicative inverse, untrue // iff a has a multiplicative inverse, untrue
// for zero. // for zero.
let one = cs.one();
cs.enforce( cs.enforce(
|| "nonzero assertion constraint", || "nonzero assertion constraint",
LinearCombination::zero() + self.variable, |lc| lc + self.variable,
LinearCombination::zero() + inv, |lc| lc + inv,
LinearCombination::zero() + one |lc| lc + CS::one()
); );
Ok(()) Ok(())
@ -299,9 +299,9 @@ impl<E: Engine, Var: Copy> AllocatedNum<E, Var> {
mut cs: CS, mut cs: CS,
a: &Self, a: &Self,
b: &Self, b: &Self,
condition: &Boolean<Var> condition: &Boolean
) -> Result<(Self, Self), SynthesisError> ) -> Result<(Self, Self), SynthesisError>
where CS: ConstraintSystem<E, Variable=Var> where CS: ConstraintSystem<E>
{ {
let c = Self::alloc( let c = Self::alloc(
cs.namespace(|| "conditional reversal result 1"), cs.namespace(|| "conditional reversal result 1"),
@ -314,12 +314,11 @@ impl<E: Engine, Var: Copy> AllocatedNum<E, Var> {
} }
)?; )?;
let one = cs.one();
cs.enforce( cs.enforce(
|| "first conditional reversal", || "first conditional reversal",
LinearCombination::zero() + a.variable - b.variable, |lc| lc + a.variable - b.variable,
condition.lc(one, E::Fr::one()), |_| condition.lc(CS::one(), E::Fr::one()),
LinearCombination::zero() + a.variable - c.variable |lc| lc + a.variable - c.variable
); );
let d = Self::alloc( let d = Self::alloc(
@ -335,9 +334,9 @@ impl<E: Engine, Var: Copy> AllocatedNum<E, Var> {
cs.enforce( cs.enforce(
|| "second conditional reversal", || "second conditional reversal",
LinearCombination::zero() + b.variable - a.variable, |lc| lc + b.variable - a.variable,
condition.lc(one, E::Fr::one()), |_| condition.lc(CS::one(), E::Fr::one()),
LinearCombination::zero() + b.variable - d.variable |lc| lc + b.variable - d.variable
); );
Ok((c, d)) Ok((c, d))
@ -346,9 +345,9 @@ impl<E: Engine, Var: Copy> AllocatedNum<E, Var> {
pub fn conditionally_negate<CS>( pub fn conditionally_negate<CS>(
&self, &self,
mut cs: CS, mut cs: CS,
condition: &Boolean<Var> condition: &Boolean
) -> Result<Self, SynthesisError> ) -> Result<Self, SynthesisError>
where CS: ConstraintSystem<E, Variable=Var> where CS: ConstraintSystem<E>
{ {
let r = Self::alloc( let r = Self::alloc(
cs.namespace(|| "conditional negation result"), cs.namespace(|| "conditional negation result"),
@ -365,12 +364,11 @@ impl<E: Engine, Var: Copy> AllocatedNum<E, Var> {
// x - 2cx = r // x - 2cx = r
// (2x) * (c) = x - r // (2x) * (c) = x - r
let one = cs.one();
cs.enforce( cs.enforce(
|| "conditional negation", || "conditional negation",
LinearCombination::zero() + self.variable + self.variable, |lc| lc + self.variable + self.variable,
condition.lc(one, E::Fr::one()), |_| condition.lc(CS::one(), E::Fr::one()),
LinearCombination::zero() + self.variable - r.variable |lc| lc + self.variable - r.variable
); );
Ok(r) Ok(r)
@ -380,7 +378,7 @@ impl<E: Engine, Var: Copy> AllocatedNum<E, Var> {
self.value self.value
} }
pub fn get_variable(&self) -> Var { pub fn get_variable(&self) -> Variable {
self.variable self.variable
} }
} }

View File

@ -10,12 +10,12 @@ use bellman::{
}; };
use super::lookup::*; use super::lookup::*;
pub fn pedersen_hash<E: JubjubEngine, CS, Var: Copy>( pub fn pedersen_hash<E: JubjubEngine, CS>(
mut cs: CS, mut cs: CS,
bits: &[Boolean<Var>], bits: &[Boolean],
params: &E::Params params: &E::Params
) -> Result<EdwardsPoint<E, Var>, SynthesisError> ) -> Result<EdwardsPoint<E>, SynthesisError>
where CS: ConstraintSystem<E, Variable=Var> where CS: ConstraintSystem<E>
{ {
// Unnecessary if forced personalization is introduced // Unnecessary if forced personalization is introduced
assert!(bits.len() > 0); assert!(bits.len() > 0);
@ -116,7 +116,7 @@ mod test {
let input: Vec<bool> = (0..(Fr::NUM_BITS * 2)).map(|_| rng.gen()).collect(); let input: Vec<bool> = (0..(Fr::NUM_BITS * 2)).map(|_| rng.gen()).collect();
let input_bools: Vec<Boolean<_>> = input.iter().enumerate().map(|(i, b)| { let input_bools: Vec<Boolean> = input.iter().enumerate().map(|(i, b)| {
Boolean::from( Boolean::from(
AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)).unwrap() AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)).unwrap()
) )
@ -143,7 +143,7 @@ mod test {
let mut cs = TestConstraintSystem::<Bls12>::new(); let mut cs = TestConstraintSystem::<Bls12>::new();
let input_bools: Vec<Boolean<_>> = input.iter().enumerate().map(|(i, b)| { let input_bools: Vec<Boolean> = input.iter().enumerate().map(|(i, b)| {
Boolean::from( Boolean::from(
AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)).unwrap() AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)).unwrap()
) )

View File

@ -6,17 +6,13 @@ use pairing::{
use bellman::{ use bellman::{
LinearCombination, LinearCombination,
SynthesisError, SynthesisError,
ConstraintSystem ConstraintSystem,
Variable,
Index
}; };
use std::collections::HashMap; use std::collections::HashMap;
#[derive(Debug, Copy, Clone)]
pub enum Variable {
Input(usize),
Aux(usize)
}
#[derive(Debug)] #[derive(Debug)]
enum NamedObject { enum NamedObject {
Constraint(usize), Constraint(usize),
@ -28,7 +24,12 @@ enum NamedObject {
pub struct TestConstraintSystem<E: Engine> { pub struct TestConstraintSystem<E: Engine> {
named_objects: HashMap<String, NamedObject>, named_objects: HashMap<String, NamedObject>,
current_namespace: Vec<String>, current_namespace: Vec<String>,
constraints: Vec<(LinearCombination<Variable, E>, LinearCombination<Variable, E>, LinearCombination<Variable, E>, String)>, constraints: Vec<(
LinearCombination<E>,
LinearCombination<E>,
LinearCombination<E>,
String
)>,
inputs: Vec<(E::Fr, String)>, inputs: Vec<(E::Fr, String)>,
aux: Vec<(E::Fr, String)> aux: Vec<(E::Fr, String)>
} }
@ -42,9 +43,9 @@ fn eval_lc<E: Engine>(
let mut acc = E::Fr::zero(); let mut acc = E::Fr::zero();
for &(var, ref coeff) in terms { for &(var, ref coeff) in terms {
let mut tmp = match var { let mut tmp = match var.get_unchecked() {
Variable::Input(index) => inputs[index].0, Index::Input(index) => inputs[index].0,
Variable::Aux(index) => aux[index].0 Index::Aux(index) => aux[index].0
}; };
tmp.mul_assign(&coeff); tmp.mul_assign(&coeff);
@ -57,7 +58,7 @@ fn eval_lc<E: Engine>(
impl<E: Engine> TestConstraintSystem<E> { impl<E: Engine> TestConstraintSystem<E> {
pub fn new() -> TestConstraintSystem<E> { pub fn new() -> TestConstraintSystem<E> {
let mut map = HashMap::new(); let mut map = HashMap::new();
map.insert("ONE".into(), NamedObject::Var(Variable::Input(0))); map.insert("ONE".into(), NamedObject::Var(TestConstraintSystem::<E>::one()));
TestConstraintSystem { TestConstraintSystem {
named_objects: map, named_objects: map,
@ -97,8 +98,12 @@ impl<E: Engine> TestConstraintSystem<E> {
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) { match self.named_objects.get(path) {
Some(&NamedObject::Var(Variable::Input(index))) => self.inputs[index].0 = to, Some(&NamedObject::Var(ref v)) => {
Some(&NamedObject::Var(Variable::Aux(index))) => self.aux[index].0 = to, 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), Some(e) => panic!("tried to set path `{}` to value, but `{:?}` already exists there.", path, e),
_ => panic!("no variable exists at path: {}", path) _ => panic!("no variable exists at path: {}", path)
} }
@ -107,8 +112,12 @@ impl<E: Engine> TestConstraintSystem<E> {
pub fn get(&mut self, path: &str) -> E::Fr pub fn get(&mut self, path: &str) -> E::Fr
{ {
match self.named_objects.get(path) { match self.named_objects.get(path) {
Some(&NamedObject::Var(Variable::Input(index))) => self.inputs[index].0, Some(&NamedObject::Var(ref v)) => {
Some(&NamedObject::Var(Variable::Aux(index))) => self.aux[index].0, 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), Some(e) => panic!("tried to get value of path `{}`, but `{:?}` exists there (not a variable)", path, e),
_ => panic!("no variable exists at path: {}", path) _ => panic!("no variable exists at path: {}", path)
} }
@ -145,42 +154,60 @@ fn compute_path(ns: &[String], this: String) -> String {
} }
impl<E: Engine> ConstraintSystem<E> for TestConstraintSystem<E> { impl<E: Engine> ConstraintSystem<E> for TestConstraintSystem<E> {
type Variable = Variable;
type Root = Self; type Root = Self;
fn one(&self) -> Self::Variable {
Variable::Input(0)
}
fn alloc<F, A, AR>( fn alloc<F, A, AR>(
&mut self, &mut self,
annotation: A, annotation: A,
f: F f: F
) -> Result<Self::Variable, SynthesisError> ) -> Result<Variable, SynthesisError>
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String> where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
{ {
let index = self.aux.len(); let index = self.aux.len();
let path = compute_path(&self.current_namespace, annotation().into()); let path = compute_path(&self.current_namespace, annotation().into());
self.aux.push((f()?, path.clone())); self.aux.push((f()?, path.clone()));
let var = Variable::Aux(index); let var = Variable::new_unchecked(Index::Aux(index));
self.set_named_obj(path, NamedObject::Var(var)); self.set_named_obj(path, NamedObject::Var(var));
Ok(var) Ok(var)
} }
fn enforce<A, AR>( fn alloc_input<F, A, AR>(
&mut self, &mut self,
annotation: A, annotation: A,
a: LinearCombination<Self::Variable, E>, f: F
b: LinearCombination<Self::Variable, E>, ) -> Result<Variable, SynthesisError>
c: LinearCombination<Self::Variable, E> 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());
self.inputs.push((f()?, path.clone()));
let var = Variable::new_unchecked(Index::Input(index));
self.set_named_obj(path, NamedObject::Var(var));
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> 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 path = compute_path(&self.current_namespace, annotation().into());
let index = self.constraints.len(); let index = self.constraints.len();
self.set_named_obj(path.clone(), NamedObject::Constraint(index)); self.set_named_obj(path.clone(), NamedObject::Constraint(index));
let a = a(LinearCombination::zero());
let b = b(LinearCombination::zero());
let c = c(LinearCombination::zero());
self.constraints.push((a, b, c, path)); self.constraints.push((a, b, c, path));
} }
@ -218,21 +245,21 @@ fn test_cs() {
cs.enforce( cs.enforce(
|| "mult", || "mult",
LinearCombination::zero() + a, |lc| lc + a,
LinearCombination::zero() + b, |lc| lc + b,
LinearCombination::zero() + c |lc| lc + c
); );
assert!(cs.is_satisfied()); assert!(cs.is_satisfied());
assert_eq!(cs.num_constraints(), 1); assert_eq!(cs.num_constraints(), 1);
cs.set("a/var", Fr::from_str("4").unwrap()); cs.set("a/var", Fr::from_str("4").unwrap());
let one = cs.one(); let one = TestConstraintSystem::<Bls12>::one();
cs.enforce( cs.enforce(
|| "eq", || "eq",
LinearCombination::zero() + a, |lc| lc + a,
LinearCombination::zero() + one, |lc| lc + one,
LinearCombination::zero() + b |lc| lc + b
); );
assert!(!cs.is_satisfied()); assert!(!cs.is_satisfied());

View File

@ -18,13 +18,13 @@ use super::boolean::{
/// Represents an interpretation of 32 `Boolean` objects as an /// Represents an interpretation of 32 `Boolean` objects as an
/// unsigned integer. /// unsigned integer.
#[derive(Clone)] #[derive(Clone)]
pub struct UInt32<Var> { pub struct UInt32 {
// Least significant bit first // Least significant bit first
bits: Vec<Boolean<Var>>, bits: Vec<Boolean>,
value: Option<u32> value: Option<u32>
} }
impl<Var: Copy> UInt32<Var> { impl UInt32 {
/// Construct a constant `UInt32` from a `u32` /// Construct a constant `UInt32` from a `u32`
pub fn constant(value: u32) -> Self pub fn constant(value: u32) -> Self
{ {
@ -53,7 +53,7 @@ impl<Var: Copy> UInt32<Var> {
value: Option<u32> value: Option<u32>
) -> Result<Self, SynthesisError> ) -> Result<Self, SynthesisError>
where E: Engine, where E: Engine,
CS: ConstraintSystem<E, Variable=Var> CS: ConstraintSystem<E>
{ {
let values = match value { let values = match value {
Some(mut val) => { Some(mut val) => {
@ -72,7 +72,10 @@ impl<Var: Copy> UInt32<Var> {
let bits = values.into_iter() let bits = values.into_iter()
.enumerate() .enumerate()
.map(|(i, v)| { .map(|(i, v)| {
Ok(Boolean::from(AllocatedBit::alloc(cs.namespace(|| format!("allocated bit {}", i)), v)?)) Ok(Boolean::from(AllocatedBit::alloc(
cs.namespace(|| format!("allocated bit {}", i)),
v
)?))
}) })
.collect::<Result<Vec<_>, SynthesisError>>()?; .collect::<Result<Vec<_>, SynthesisError>>()?;
@ -83,7 +86,7 @@ impl<Var: Copy> UInt32<Var> {
} }
/// Turns this `UInt32` into its little-endian byte order representation. /// Turns this `UInt32` into its little-endian byte order representation.
pub fn into_bits(&self) -> Vec<Boolean<Var>> { pub fn into_bits(&self) -> Vec<Boolean> {
self.bits.chunks(8) self.bits.chunks(8)
.flat_map(|v| v.iter().rev()) .flat_map(|v| v.iter().rev())
.cloned() .cloned()
@ -92,7 +95,7 @@ impl<Var: Copy> UInt32<Var> {
/// Converts a little-endian byte order representation of bits into a /// Converts a little-endian byte order representation of bits into a
/// `UInt32`. /// `UInt32`.
pub fn from_bits(bits: &[Boolean<Var>]) -> Self pub fn from_bits(bits: &[Boolean]) -> Self
{ {
assert_eq!(bits.len(), 32); assert_eq!(bits.len(), 32);
@ -157,7 +160,7 @@ impl<Var: Copy> UInt32<Var> {
other: &Self other: &Self
) -> Result<Self, SynthesisError> ) -> Result<Self, SynthesisError>
where E: Engine, where E: Engine,
CS: ConstraintSystem<E, Variable=Var> CS: ConstraintSystem<E>
{ {
let new_value = match (self.value, other.value) { let new_value = match (self.value, other.value) {
(Some(a), Some(b)) => { (Some(a), Some(b)) => {
@ -170,7 +173,11 @@ impl<Var: Copy> UInt32<Var> {
.zip(other.bits.iter()) .zip(other.bits.iter())
.enumerate() .enumerate()
.map(|(i, (a, b))| { .map(|(i, (a, b))| {
Boolean::xor(cs.namespace(|| format!("xor of bit {}", i)), a, b) Boolean::xor(
cs.namespace(|| format!("xor of bit {}", i)),
a,
b
)
}) })
.collect::<Result<_, _>>()?; .collect::<Result<_, _>>()?;
@ -186,7 +193,7 @@ impl<Var: Copy> UInt32<Var> {
operands: &[Self] operands: &[Self]
) -> Result<Self, SynthesisError> ) -> Result<Self, SynthesisError>
where E: Engine, where E: Engine,
CS: ConstraintSystem<E, Variable=Var> CS: ConstraintSystem<E>
{ {
// Make some arbitrary bounds for ourselves to avoid overflows // Make some arbitrary bounds for ourselves to avoid overflows
// in the scalar field // in the scalar field
@ -235,11 +242,11 @@ impl<Var: Copy> UInt32<Var> {
all_constants = false; 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());
}, },
&Boolean::Constant(bit) => { &Boolean::Constant(bit) => {
if bit { if bit {
lc = lc + (coeff, cs.one()); lc = lc + (coeff, CS::one());
} }
} }
} }
@ -266,7 +273,10 @@ impl<Var: Copy> UInt32<Var> {
let mut i = 0; let mut i = 0;
while max_value != 0 { while max_value != 0 {
// Allocate the bit // Allocate the bit
let b = AllocatedBit::alloc(cs.namespace(|| format!("result bit {}", i)), result_value.map(|v| (v >> i) & 1 == 1))?; let b = AllocatedBit::alloc(
cs.namespace(|| format!("result bit {}", i)),
result_value.map(|v| (v >> i) & 1 == 1)
)?;
// Subtract this bit from the linear combination to ensure the sums balance out // Subtract this bit from the linear combination to ensure the sums balance out
lc = lc - (coeff, b.get_variable()); lc = lc - (coeff, b.get_variable());
@ -281,9 +291,9 @@ impl<Var: Copy> UInt32<Var> {
// Enforce that the linear combination equals zero // Enforce that the linear combination equals zero
cs.enforce( cs.enforce(
|| "modular addition", || "modular addition",
LinearCombination::zero(), |lc| lc,
LinearCombination::zero(), |lc| lc,
lc |_| lc
); );
// Discard carry bits that we don't care about // Discard carry bits that we don't care about
@ -311,7 +321,7 @@ mod test {
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0653]); let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0653]);
for _ in 0..1000 { for _ in 0..1000 {
let mut v = (0..32).map(|_| Boolean::<()>::constant(rng.gen())).collect::<Vec<_>>(); let mut v = (0..32).map(|_| Boolean::constant(rng.gen())).collect::<Vec<_>>();
let b = UInt32::from_bits(&v); let b = UInt32::from_bits(&v);
@ -473,7 +483,7 @@ mod test {
let mut num = rng.gen(); let mut num = rng.gen();
let a = UInt32::<()>::constant(num); let a = UInt32::constant(num);
for i in 0..32 { for i in 0..32 {
let b = a.rotr(i); let b = a.rotr(i);