Browse Source

Refactor NIZK/MT verification to return a bit

master
Pratyush Mishra 4 years ago
parent
commit
d2d1b61d08
6 changed files with 46 additions and 111 deletions
  1. +9
    -29
      crypto-primitives/src/merkle_tree/constraints.rs
  2. +3
    -13
      crypto-primitives/src/nizk/constraints.rs
  3. +13
    -13
      crypto-primitives/src/nizk/gm17/constraints.rs
  4. +13
    -14
      crypto-primitives/src/nizk/groth16/constraints.rs
  5. +8
    -0
      r1cs-std/src/bits/boolean.rs
  6. +0
    -42
      r1cs-std/src/eq.rs

+ 9
- 29
crypto-primitives/src/merkle_tree/constraints.rs

@ -30,39 +30,21 @@ where
parameters: &CRHGadget::ParametersVar, parameters: &CRHGadget::ParametersVar,
root: &CRHGadget::OutputVar, root: &CRHGadget::OutputVar,
leaf: impl ToBytesGadget<ConstraintF>, leaf: impl ToBytesGadget<ConstraintF>,
) -> Result<(), SynthesisError> {
self.conditionally_check_membership(parameters, root, leaf, &Boolean::Constant(true))
}
pub fn conditionally_check_membership(
&self,
parameters: &CRHGadget::ParametersVar,
root: &CRHGadget::OutputVar,
leaf: impl ToBytesGadget<ConstraintF>,
should_enforce: &Boolean<ConstraintF>,
) -> Result<(), SynthesisError> {
) -> Result<Boolean<ConstraintF>, SynthesisError> {
assert_eq!(self.path.len(), P::HEIGHT - 1); assert_eq!(self.path.len(), P::HEIGHT - 1);
// Check that the hash of the given leaf matches the leaf hash in the membership // Check that the hash of the given leaf matches the leaf hash in the membership
// proof. // proof.
let leaf_bits = leaf.to_bytes()?; let leaf_bits = leaf.to_bytes()?;
let leaf_hash = CRHGadget::evaluate(parameters, &leaf_bits)?; let leaf_hash = CRHGadget::evaluate(parameters, &leaf_bits)?;
let cs = leaf_hash
.cs()
.or(root.cs())
.or(should_enforce.cs())
.unwrap();
let cs = leaf_hash.cs().or(root.cs()).unwrap();
// Check if leaf is one of the bottom-most siblings. // Check if leaf is one of the bottom-most siblings.
let leaf_is_left = Boolean::new_witness(cs.ns("leaf_is_left"), || { let leaf_is_left = Boolean::new_witness(cs.ns("leaf_is_left"), || {
Ok(leaf_hash.value()?.eq(&self.path[0].0.value()?)) Ok(leaf_hash.value()?.eq(&self.path[0].0.value()?))
})?; })?;
leaf_hash.conditional_enforce_equal_or(
&leaf_is_left,
&self.path[0].0,
&self.path[0].1,
should_enforce,
)?;
let mut result =
leaf_hash.is_eq(&leaf_is_left.select(&self.path[0].0, &self.path[0].1)?)?;
// Check levels between leaf level and root. // Check levels between leaf level and root.
let mut previous_hash = leaf_hash; let mut previous_hash = leaf_hash;
@ -77,12 +59,8 @@ where
"enforcing that inner hash is correct at i-th level{}", "enforcing that inner hash is correct at i-th level{}",
i i
)); ));
previous_hash.conditional_enforce_equal_or(
&previous_is_left,
left_hash,
right_hash,
should_enforce,
)?;
let equality_cmp = previous_is_left.select(left_hash, right_hash)?;
result = result.and(&previous_hash.is_eq(&equality_cmp)?)?;
drop(ns); drop(ns);
previous_hash = previous_hash =
@ -90,7 +68,7 @@ where
i += 1; i += 1;
} }
root.conditional_enforce_equal(&previous_hash, should_enforce)
result.and(&root.is_eq(&previous_hash)?)
} }
} }
@ -235,6 +213,8 @@ mod test {
println!("constraints from path: {}", constraints_from_path); println!("constraints from path: {}", constraints_from_path);
let leaf_g: &[_] = leaf_g.as_slice(); let leaf_g: &[_] = leaf_g.as_slice();
cw.check_membership(&crh_parameters, &root, &leaf_g) cw.check_membership(&crh_parameters, &root, &leaf_g)
.unwrap()
.enforce_equal(&Boolean::TRUE)
.unwrap(); .unwrap();
if !cs.is_satisfied().unwrap() { if !cs.is_satisfied().unwrap() {
satisfied = false; satisfied = false;

+ 3
- 13
crypto-primitives/src/nizk/constraints.rs

@ -39,21 +39,11 @@ pub trait NIZKVerifierGadget {
verification_key: &Self::VerificationKeyVar, verification_key: &Self::VerificationKeyVar,
input: impl IntoIterator<Item = &'a T>, input: impl IntoIterator<Item = &'a T>,
proof: &Self::ProofVar, proof: &Self::ProofVar,
) -> Result<(), SynthesisError> {
Self::conditional_verify(verification_key, input, proof, &Boolean::constant(true))
}
fn conditional_verify<'a, T: 'a + ToBitsGadget<ConstraintF> + ?Sized>(
verification_key: &Self::VerificationKeyVar,
input: impl IntoIterator<Item = &'a T>,
proof: &Self::ProofVar,
condition: &Boolean<ConstraintF>,
) -> Result<(), SynthesisError>;
) -> Result<Boolean<ConstraintF>, SynthesisError>;
fn conditional_verify_prepared<'a, T: 'a + ToBitsGadget<ConstraintF> + ?Sized>(
fn verify_prepared<'a, T: 'a + ToBitsGadget<ConstraintF> + ?Sized>(
prepared_verification_key: &Self::PreparedVerificationKeyVar, prepared_verification_key: &Self::PreparedVerificationKeyVar,
input: impl IntoIterator<Item = &'a T>, input: impl IntoIterator<Item = &'a T>,
proof: &Self::ProofVar, proof: &Self::ProofVar,
condition: &Boolean<ConstraintF>,
) -> Result<(), SynthesisError>;
) -> Result<Boolean<ConstraintF>, SynthesisError>;
} }

+ 13
- 13
crypto-primitives/src/nizk/gm17/constraints.rs

@ -176,24 +176,20 @@ where
}) })
} }
fn conditional_verify<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>(
fn verify<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>(
vk: &Self::VerificationKeyVar, vk: &Self::VerificationKeyVar,
input: impl IntoIterator<Item = &'a T>, input: impl IntoIterator<Item = &'a T>,
proof: &Self::ProofVar, proof: &Self::ProofVar,
condition: &Boolean<E::Fq>,
) -> Result<(), SynthesisError> {
) -> Result<Boolean<E::Fq>, SynthesisError> {
let pvk = vk.prepare()?; let pvk = vk.prepare()?;
<Self as NIZKVerifierGadget<Gm17<E, C, V>, E::Fq>>::conditional_verify_prepared(
&pvk, input, proof, condition,
)
<Self as NIZKVerifierGadget<Gm17<E, C, V>, E::Fq>>::verify_prepared(&pvk, input, proof)
} }
fn conditional_verify_prepared<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>(
fn verify_prepared<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>(
pvk: &Self::PreparedVerificationKeyVar, pvk: &Self::PreparedVerificationKeyVar,
input: impl IntoIterator<Item = &'a T>, input: impl IntoIterator<Item = &'a T>,
proof: &Self::ProofVar, proof: &Self::ProofVar,
condition: &Boolean<E::Fq>,
) -> Result<(), SynthesisError> {
) -> Result<Boolean<E::Fq>, SynthesisError> {
let pvk = pvk.clone(); let pvk = pvk.clone();
// e(A*G^{alpha}, B*H^{beta}) = e(G^{alpha}, H^{beta}) * e(G^{psi}, H^{gamma}) * // e(A*G^{alpha}, B*H^{beta}) = e(G^{alpha}, H^{beta}) * e(G^{psi}, H^{gamma}) *
// e(C, H) where psi = \sum_{i=0}^l input_i pvk.query[i] // e(C, H) where psi = \sum_{i=0}^l input_i pvk.query[i]
@ -256,9 +252,7 @@ where
let test2 = P::final_exponentiation(&test2_exp)?; let test2 = P::final_exponentiation(&test2_exp)?;
let one = P::GTVar::one(); let one = P::GTVar::one();
test1.conditional_enforce_equal(&one, condition)?;
test2.conditional_enforce_equal(&one, condition)?;
Ok(())
test1.is_eq(&one)?.and(&test2.is_eq(&one)?)
} }
} }
@ -506,7 +500,10 @@ mod test {
&input_gadgets, &input_gadgets,
&proof_gadget, &proof_gadget,
) )
.unwrap()
.enforce_equal(&Boolean::TRUE)
.unwrap(); .unwrap();
if !cs.is_satisfied().unwrap() { if !cs.is_satisfied().unwrap() {
println!("========================================================="); println!("=========================================================");
println!("Unsatisfied constraints:"); println!("Unsatisfied constraints:");
@ -648,7 +645,8 @@ mod test_recursive {
&vk_gadget, &vk_gadget,
&input_gadgets, &input_gadgets,
&proof_gadget, &proof_gadget,
)?;
)?
.enforce_equal(&Boolean::TRUE)?;
Ok(()) Ok(())
} }
} }
@ -752,6 +750,8 @@ mod test_recursive {
&input_gadgets, &input_gadgets,
&proof_gadget, &proof_gadget,
) )
.unwrap()
.enforce_equal(&Boolean::TRUE)
.unwrap(); .unwrap();
if !cs.is_satisfied().unwrap() { if !cs.is_satisfied().unwrap() {
println!("========================================================="); println!("=========================================================");

+ 13
- 14
crypto-primitives/src/nizk/groth16/constraints.rs

@ -164,24 +164,20 @@ where
}) })
} }
fn conditional_verify<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>(
fn verify<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>(
vk: &Self::VerificationKeyVar, vk: &Self::VerificationKeyVar,
input: impl IntoIterator<Item = &'a T>, input: impl IntoIterator<Item = &'a T>,
proof: &Self::ProofVar, proof: &Self::ProofVar,
condition: &Boolean<E::Fq>,
) -> Result<(), SynthesisError> {
) -> Result<Boolean<E::Fq>, SynthesisError> {
let pvk = vk.prepare()?; let pvk = vk.prepare()?;
<Self as NIZKVerifierGadget<Groth16<E, C, V>, E::Fq>>::conditional_verify_prepared(
&pvk, input, proof, condition,
)
<Self as NIZKVerifierGadget<Groth16<E, C, V>, E::Fq>>::verify_prepared(&pvk, input, proof)
} }
fn conditional_verify_prepared<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>(
fn verify_prepared<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>(
pvk: &Self::PreparedVerificationKeyVar, pvk: &Self::PreparedVerificationKeyVar,
public_inputs: impl IntoIterator<Item = &'a T>, public_inputs: impl IntoIterator<Item = &'a T>,
proof: &Self::ProofVar, proof: &Self::ProofVar,
condition: &Boolean<E::Fq>,
) -> Result<(), SynthesisError> {
) -> Result<Boolean<E::Fq>, SynthesisError> {
let pvk = pvk.clone(); let pvk = pvk.clone();
let g_ic = { let g_ic = {
@ -216,10 +212,8 @@ where
)? )?
}; };
let test = P::final_exponentiation(&test_exp).unwrap();
test.conditional_enforce_equal(&pvk.alpha_g1_beta_g2, condition)?;
Ok(())
let test = P::final_exponentiation(&test_exp)?;
test.is_eq(&pvk.alpha_g1_beta_g2)
} }
} }
@ -468,6 +462,8 @@ mod test {
&input_gadgets, &input_gadgets,
&proof_gadget, &proof_gadget,
) )
.unwrap()
.enforce_equal(&Boolean::TRUE)
.unwrap(); .unwrap();
if !cs.is_satisfied().unwrap() { if !cs.is_satisfied().unwrap() {
println!("========================================================="); println!("=========================================================");
@ -610,7 +606,8 @@ mod test_recursive {
&vk_gadget, &vk_gadget,
&input_gadgets, &input_gadgets,
&proof_gadget, &proof_gadget,
)?;
)?
.enforce_equal(&Boolean::TRUE)?;
Ok(()) Ok(())
} }
} }
@ -714,6 +711,8 @@ mod test_recursive {
&input_gadgets, &input_gadgets,
&proof_gadget, &proof_gadget,
) )
.unwrap()
.enforce_equal(&Boolean::TRUE)
.unwrap(); .unwrap();
if !cs.is_satisfied().unwrap() { if !cs.is_satisfied().unwrap() {
println!("========================================================="); println!("=========================================================");

+ 8
- 0
r1cs-std/src/bits/boolean.rs

@ -7,6 +7,7 @@ use r1cs_core::{lc, ConstraintSystemRef, LinearCombination, Namespace, Synthesis
/// 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, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
#[must_use]
pub struct AllocatedBit<F: Field> { pub struct AllocatedBit<F: Field> {
variable: Variable, variable: Variable,
cs: ConstraintSystemRef<F>, cs: ConstraintSystemRef<F>,
@ -216,6 +217,7 @@ impl CondSelectGadget for AllocatedBit {
/// 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, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
#[must_use]
pub enum Boolean<F: Field> { pub enum Boolean<F: Field> {
/// Existential view of the boolean variable /// Existential view of the boolean variable
Is(AllocatedBit<F>), Is(AllocatedBit<F>),
@ -245,6 +247,12 @@ impl R1CSVar for Boolean {
} }
impl<F: Field> Boolean<F> { impl<F: Field> Boolean<F> {
/// Returns the constrant `true`.
pub const TRUE: Self = Boolean::Constant(true);
/// Returns the constrant `false`.
pub const FALSE: Self = Boolean::Constant(false);
pub fn lc(&self) -> LinearCombination<F> { pub fn lc(&self) -> LinearCombination<F> {
match self { match self {
Boolean::Constant(false) => lc!(), Boolean::Constant(false) => lc!(),

+ 0
- 42
r1cs-std/src/eq.rs

@ -87,45 +87,3 @@ impl + R1CSVar, F: Field> EqGadget for [T] {
} }
} }
} }
pub trait OrEqualsGadget<ConstraintF: Field>
where
Self: Sized,
{
/// If `should_enforce == true`, enforce that `self` equals
/// (a) `first` (if `cond` is `true`)
/// (b) `second` (if `cond` is `false`)
fn conditional_enforce_equal_or(
&self,
cond: &Boolean<ConstraintF>,
first: &Self,
second: &Self,
should_enforce: &Boolean<ConstraintF>,
) -> Result<(), SynthesisError>;
fn enforce_equal_or(
&self,
cond: &Boolean<ConstraintF>,
first: &Self,
second: &Self,
) -> Result<(), SynthesisError> {
self.conditional_enforce_equal_or(cond, first, second, &Boolean::Constant(true))
}
}
impl<ConstraintF, T> OrEqualsGadget<ConstraintF> for T
where
ConstraintF: Field,
T: Sized + EqGadget<ConstraintF> + CondSelectGadget<ConstraintF>,
{
fn conditional_enforce_equal_or(
&self,
cond: &Boolean<ConstraintF>,
first: &Self,
second: &Self,
should_enforce: &Boolean<ConstraintF>,
) -> Result<(), SynthesisError> {
let match_opt = cond.select(first, second)?;
self.conditional_enforce_equal(&match_opt, should_enforce)
}
}

Loading…
Cancel
Save