Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce UIntGadget and ComparisonGadget #163

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 61 additions & 14 deletions r1cs/core/src/constraint_system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ pub trait ConstraintSystemAbstract<F: Field>: Sized {

/// Output the number of constraints in the system.
fn num_constraints(&self) -> usize;

/// Evaluate linear combination lc with the values assigned to variables of lc
/// in the constraint system `self`. Returns an error if one variable of lc is not found among
/// allocated variables in `self`. The result is None if variables have not been assigned to a
/// value yet
fn eval_lc(&self, lc: &LinearCombination<F>) -> Result<Option<F>, SynthesisError>;
}

/// Defines debugging functionalities for a constraint system, which allow to verify which
Expand Down Expand Up @@ -346,14 +352,48 @@ impl<F: Field> ConstraintSystemAbstract<F> for ConstraintSystem<F> {
fn num_constraints(&self) -> usize {
self.num_constraints
}

fn eval_lc(&self, lc: &LinearCombination<F>) -> Result<Option<F>, SynthesisError> {
let mut acc = F::zero();

if self.is_in_setup_mode() {
// in setup mode there are for sure no assignment to variables, so we can return None
return Ok(None)
}

for &(ref var, coeff) in lc.as_ref() {
let mut tmp = match var.0 {
Index::Input(index) => *self.input_assignment.get(index).ok_or(
SynthesisError::Other(
format!(
"no public input variable with index {} found in the constraint system"
, index)))?,
Index::Aux(index) => *self.aux_assignment.get(index).ok_or(
SynthesisError::Other(
format!(
"no private variable with index {} found in the constraint system"
, index)))?,
};

tmp.mul_assign(coeff);
acc.add_assign(tmp);
}

Ok(Some(acc))
}
}

impl<F: Field> ConstraintSystemDebugger<F> for ConstraintSystem<F> {
fn which_is_unsatisfied(&self) -> Option<&str> {
for i in 0..self.num_constraints {
let mut a = Self::eval_lc(&self.at[i], &self.input_assignment, &self.aux_assignment);
let b = Self::eval_lc(&self.bt[i], &self.input_assignment, &self.aux_assignment);
let c = Self::eval_lc(&self.ct[i], &self.input_assignment, &self.aux_assignment);
// Note that the following `eval_lc` calls cannot return an error, as `get_constraint`
// constructs a LinearCombination whose variables are necessarily in `self`.
// Furthermore, we assume that this function is never called in setup mode, therefore
// `eval_lc` should never return None.
// Thus, we can safely unwrap the return values of `eval_lc` invocations
let mut a = self.eval_lc(&Self::get_constraint(&self.at, i)).unwrap().unwrap();
let b = self.eval_lc(&Self::get_constraint(&self.bt, i)).unwrap().unwrap();
let c = self.eval_lc(&Self::get_constraint(&self.ct, i)).unwrap().unwrap();
a.mul_assign(&b);

if a != c {
Expand Down Expand Up @@ -455,20 +495,19 @@ impl<F: Field> ConstraintSystem<F> {
}
}
}
fn eval_lc(terms: &[(F, Index)], inputs: &[F], aux: &[F]) -> F {
let mut acc = F::zero();

for &(ref coeff, idx) in terms {
let mut tmp = match idx {
Index::Input(index) => inputs[index],
Index::Aux(index) => aux[index],
};

tmp.mul_assign(coeff);
acc.add_assign(tmp);
fn get_constraint(
constraints: &[Vec<(F, Index)>],
this_constraint: usize,
) -> LinearCombination<F> {
let constraint = &constraints[this_constraint];
// build a linear combination representing the constraint
let mut lc = LinearCombination::zero();
for (coeff, idx) in constraint {
lc += (*coeff, Variable(idx.clone()));
}

acc
lc
}
}

Expand Down Expand Up @@ -557,6 +596,10 @@ impl<F: Field, CS: ConstraintSystemAbstract<F>> ConstraintSystemAbstract<F>
fn num_constraints(&self) -> usize {
self.0.num_constraints()
}

fn eval_lc(&self, lc: &LinearCombination<F>) -> Result<Option<F>, SynthesisError> {
self.0.eval_lc(lc)
}
}

impl<F: Field, CS: ConstraintSystemAbstract<F> + ConstraintSystemDebugger<F>>
Expand Down Expand Up @@ -650,6 +693,10 @@ impl<F: Field, CS: ConstraintSystemAbstract<F>> ConstraintSystemAbstract<F> for
fn num_constraints(&self) -> usize {
(**self).num_constraints()
}

fn eval_lc(&self, lc: &LinearCombination<F>) -> Result<Option<F>, SynthesisError> {
(**self).eval_lc(lc)
}
}

impl<F: Field, CS: ConstraintSystemAbstract<F> + ConstraintSystemDebugger<F>>
Expand Down
4 changes: 2 additions & 2 deletions r1cs/gadgets/crypto/src/commitment/blake2s/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ impl<ConstraintF: PrimeField> CommitmentGadget<Blake2sCommitment, ConstraintF>
r: &Self::RandomnessGadget,
) -> Result<Self::OutputGadget, SynthesisError> {
let mut input_bits = Vec::with_capacity(512);
for byte in input.iter().chain(r.0.iter()) {
input_bits.extend_from_slice(&byte.into_bits_le());
for (i, byte) in input.iter().chain(r.0.iter()).enumerate() {
input_bits.extend_from_slice(&byte.to_bits_le(cs.ns(|| format!("convert byte {} to bits", i)))?);
}
let mut result = Vec::new();
for (i, int) in blake2s_gadget(cs.ns(|| "Blake2s Eval"), &input_bits)?
Expand Down
2 changes: 1 addition & 1 deletion r1cs/gadgets/crypto/src/commitment/injective_map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::commitment::{
pub use crate::crh::injective_map::InjectiveMapGadget;
use algebra::groups::Group;
use r1cs_core::{ConstraintSystemAbstract, SynthesisError};
use r1cs_std::{groups::GroupGadget, uint8::UInt8};
use r1cs_std::{groups::GroupGadget, UInt8};

use std::marker::PhantomData;

Expand Down
7 changes: 2 additions & 5 deletions r1cs/gadgets/crypto/src/commitment/pedersen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,7 @@ where
}

// Allocate new variable for commitment output.
let input_in_bits: Vec<_> = padded_input
.iter()
.flat_map(|byte| byte.into_bits_le())
.collect();
let input_in_bits: Vec<_> = padded_input.to_bits_le(cs.ns(|| "padded input to bits"))?;
let input_in_bits = input_in_bits.chunks(W::WINDOW_SIZE);
let mut result = GG::precomputed_base_multiscalar_mul(
cs.ns(|| "multiexp"),
Expand All @@ -91,7 +88,7 @@ where
)?;

// Compute h^r
let rand_bits: Vec<_> = r.0.iter().flat_map(|byte| byte.into_bits_le()).collect();
let rand_bits: Vec<_> = r.0.to_bits_le(cs.ns(|| "pedersen randomness to bits"))?;
result.precomputed_base_scalar_mul(
cs.ns(|| "Randomizer"),
rand_bits
Expand Down
8 changes: 4 additions & 4 deletions r1cs/gadgets/crypto/src/crh/bowe_hopwood/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use primitives::{
crh::pedersen::PedersenWindow,
};
use r1cs_core::{ConstraintSystemAbstract, SynthesisError};
use r1cs_std::{alloc::AllocGadget, groups::GroupGadget, uint8::UInt8};
use r1cs_std::{alloc::AllocGadget, groups::GroupGadget, ToBitsGadget, UInt8};

use r1cs_std::bits::boolean::Boolean;
use std::{borrow::Borrow, marker::PhantomData};
Expand Down Expand Up @@ -51,12 +51,12 @@ where
type ParametersGadget = BoweHopwoodPedersenCRHGadgetParameters<G, W, ConstraintF, GG>;

fn check_evaluation_gadget<CS: ConstraintSystemAbstract<ConstraintF>>(
cs: CS,
mut cs: CS,
parameters: &Self::ParametersGadget,
input: &[UInt8],
) -> Result<Self::OutputGadget, SynthesisError> {
// Pad the input if it is not the current length.
let mut input_in_bits: Vec<_> = input.iter().flat_map(|byte| byte.into_bits_le()).collect();
let mut input_in_bits: Vec<_> = input.to_bits_le(cs.ns(|| "input to bits"))?;
if (input_in_bits.len()) % CHUNK_SIZE != 0 {
let current_length = input_in_bits.len();
for _ in 0..(CHUNK_SIZE - current_length % CHUNK_SIZE) {
Expand Down Expand Up @@ -154,7 +154,7 @@ mod test {
use r1cs_core::{
ConstraintSystem, ConstraintSystemAbstract, ConstraintSystemDebugger, SynthesisMode,
};
use r1cs_std::{alloc::AllocGadget, instantiated::edwards_sw6::EdwardsSWGadget, uint8::UInt8};
use r1cs_std::{alloc::AllocGadget, instantiated::edwards_sw6::EdwardsSWGadget, UInt8};
use rand::{thread_rng, Rng};

type TestCRH = BoweHopwoodPedersenCRH<Edwards, Window>;
Expand Down
7 changes: 2 additions & 5 deletions r1cs/gadgets/crypto/src/crh/pedersen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ where
type ParametersGadget = PedersenCRHGadgetParameters<G, W, ConstraintF, GG>;

fn check_evaluation_gadget<CS: ConstraintSystemAbstract<ConstraintF>>(
cs: CS,
mut cs: CS,
parameters: &Self::ParametersGadget,
input: &[UInt8],
) -> Result<Self::OutputGadget, SynthesisError> {
Expand Down Expand Up @@ -70,10 +70,7 @@ where
}

// Allocate new variable for the result.
let input_in_bits: Vec<_> = padded_input
.iter()
.flat_map(|byte| byte.into_bits_le())
.collect();
let input_in_bits: Vec<_> = padded_input.to_bits_le(cs.ns(|| "padded input to bits"))?;
let input_in_bits = input_in_bits.chunks(W::WINDOW_SIZE);
let result =
GG::precomputed_base_multiscalar_mul(cs, &parameters.params.generators, input_in_bits)?;
Expand Down
22 changes: 11 additions & 11 deletions r1cs/gadgets/crypto/src/prf/blake2s/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,16 +92,16 @@ fn mixing_g<ConstraintF: PrimeField, CS: ConstraintSystemAbstract<ConstraintF>>(
cs.ns(|| "mixing step 1"),
&[v[a].clone(), v[b].clone(), x.clone()],
)?;
v[d] = v[d].xor(cs.ns(|| "mixing step 2"), &v[a])?.rotr(R1);
v[d] = v[d].xor(cs.ns(|| "mixing step 2"), &v[a])?.rotr(R1, &mut cs);
v[c] = UInt32::addmany(cs.ns(|| "mixing step 3"), &[v[c].clone(), v[d].clone()])?;
v[b] = v[b].xor(cs.ns(|| "mixing step 4"), &v[c])?.rotr(R2);
v[b] = v[b].xor(cs.ns(|| "mixing step 4"), &v[c])?.rotr(R2, &mut cs);
v[a] = UInt32::addmany(
cs.ns(|| "mixing step 5"),
&[v[a].clone(), v[b].clone(), y.clone()],
)?;
v[d] = v[d].xor(cs.ns(|| "mixing step 6"), &v[a])?.rotr(R3);
v[d] = v[d].xor(cs.ns(|| "mixing step 6"), &v[a])?.rotr(R3, &mut cs);
v[c] = UInt32::addmany(cs.ns(|| "mixing step 7"), &[v[c].clone(), v[d].clone()])?;
v[b] = v[b].xor(cs.ns(|| "mixing step 8"), &v[c])?.rotr(R4);
v[b] = v[b].xor(cs.ns(|| "mixing step 8"), &v[c])?.rotr(R4, &mut cs);

Ok(())
}
Expand Down Expand Up @@ -332,14 +332,14 @@ pub fn blake2s_gadget<ConstraintF: PrimeField, CS: ConstraintSystemAbstract<Cons

let mut blocks: Vec<Vec<UInt32>> = vec![];

for block in input.chunks(512) {
for (i, block) in input.chunks(512).enumerate() {
let mut this_block = Vec::with_capacity(16);
for word in block.chunks(32) {
for (j, word) in block.chunks(32).enumerate() {
let mut tmp = word.to_vec();
while tmp.len() < 32 {
tmp.push(Boolean::constant(false));
}
this_block.push(UInt32::from_bits_le(&tmp));
this_block.push(UInt32::from_bits_le(cs.ns(|| format!("convert {}-th chunk of {}-th block to uint32", j, i)), &tmp)?);
}
while this_block.len() < 16 {
this_block.push(UInt32::constant(0));
Expand Down Expand Up @@ -496,8 +496,8 @@ impl<ConstraintF: PrimeField> PRFGadget<Blake2s, ConstraintF> for Blake2sGadget
assert_eq!(seed.len(), 32);
// assert_eq!(input.len(), 32);
let mut gadget_input = Vec::with_capacity(512);
for byte in seed.iter().chain(input) {
gadget_input.extend_from_slice(&byte.into_bits_le());
for (i, byte) in seed.iter().chain(input).enumerate() {
gadget_input.extend_from_slice(&byte.to_bits_le(cs.ns(|| format!("covert byte {} to bits", i)))?);
}
let mut result = Vec::new();
for (i, int) in blake2s_gadget(cs.ns(|| "Blake2s Eval"), &gadget_input)?
Expand Down Expand Up @@ -652,8 +652,8 @@ mod test {
.iter()
.flat_map(|&byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8));

for chunk in r {
for b in chunk.to_bits_le() {
for (i, chunk) in r.iter().enumerate() {
for b in chunk.to_bits_le(cs.ns(|| format!("chunk {} to bits", i))).unwrap() {
match b {
Boolean::Is(b) => {
assert!(s.next().unwrap() == b.get_value().unwrap());
Expand Down
31 changes: 14 additions & 17 deletions r1cs/gadgets/crypto/src/prf/ripemd160.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ use algebra::PrimeField;
use r1cs_core::{ConstraintSystemAbstract, SynthesisError};
use r1cs_std::boolean::Boolean;
use r1cs_std::eq::MultiEq;
use r1cs_std::uint32::UInt32;
use r1cs_std::uint8::UInt8;
use r1cs_std::uint::UInt32;
use r1cs_std::UInt8;
use r1cs_std::{UIntGadget, ToBitsGadget, FromBitsGadget};

use crate::sha256::{sha256_ch_boolean, triop};

Expand Down Expand Up @@ -125,12 +126,7 @@ where
{
assert_eq!(input.len(), 512);

Ok(
ripemd160_compression_function(&mut cs, &input, &get_ripemd160_iv())?
.into_iter()
.flat_map(|e| e.to_bits_le())
.collect(),
)
ripemd160_compression_function(&mut cs, &input, &get_ripemd160_iv())?.to_bits_le(cs)
}

/// The full domain RIPEMD160 hash function.
Expand All @@ -149,7 +145,7 @@ where
let mut padded = input.to_vec();
let plen = padded.len() as u64;
// append bit "1", and alread seven 0 bits (recall that our input length is a mult. of 8)
padded.append(&mut UInt8::constant(1).into_bits_be());
padded.append(&mut UInt8::constant(1).to_bits(cs.ns(|| "append bit 1"))?);

// append remaining K '0' bits such that L + 7 + K is 64 bit shy of being a multiple of 512
while (padded.len() + 64) % 512 != 0 {
Expand All @@ -166,7 +162,7 @@ where
cur = ripemd160_compression_function(cs.ns(|| format!("block {}", i)), block, &cur)?;
}

Ok(cur.into_iter().flat_map(|e| e.to_bits_le()).collect())
cur.to_bits_le(cs)
}

fn get_ripemd160_iv() -> Vec<UInt32> {
Expand All @@ -175,7 +171,7 @@ fn get_ripemd160_iv() -> Vec<UInt32> {

/// The RIPEMD160 block compression function
fn ripemd160_compression_function<ConstraintF, CS>(
cs: CS,
mut cs: CS,
input: &[Boolean],
current_hash_value: &[UInt32],
) -> Result<Vec<UInt32>, SynthesisError>
Expand All @@ -199,8 +195,9 @@ where

let x = input
.chunks(32)
.map(|e| UInt32::from_bits_le(e))
.collect::<Vec<_>>();
.enumerate()
.map(|(i, e)| UInt32::from_bits_le(cs.ns(|| format!("pack input chunk {}", i)),e))
.collect::<Result<Vec<_>, SynthesisError>>()?;

let mut cs = MultiEq::new(cs);

Expand All @@ -221,7 +218,7 @@ where
cs.ns(|| format!("first rotl(a + f + x + k) {}", i)),
&[a, f, selected_input_word, get_round_constants(i).0],
)?
.rotl(S[i]);
.rotl(S[i], &mut *cs);
UInt32::addmany(
cs.ns(|| format!("compute first T {}", i)),
&[result, e.clone()],
Expand All @@ -230,7 +227,7 @@ where

a = e;
e = d;
d = c.rotl(10);
d = c.rotl(10, &mut *cs);
c = b;
b = t;

Expand All @@ -249,7 +246,7 @@ where
cs.ns(|| format!("second rotl(a + f + x + k) {}", i)),
&[a_prime, f, selected_input_word, get_round_constants(i).1],
)?
.rotl(S_PRIME[i]);
.rotl(S_PRIME[i], &mut *cs);
UInt32::addmany(
cs.ns(|| format!("compute second T {}", i)),
&[result, e_prime.clone()],
Expand All @@ -258,7 +255,7 @@ where

a_prime = e_prime;
e_prime = d_prime;
d_prime = c_prime.rotl(10);
d_prime = c_prime.rotl(10, &mut *cs);
c_prime = b_prime;
b_prime = t;
}
Expand Down
Loading