mirror of
https://github.com/arnaucube/ark-r1cs-std.git
synced 2026-01-11 00:11:29 +01:00
Refactor NIZK/MT verification to return a bit
This commit is contained in:
@@ -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> {
|
) -> Result<Boolean<ConstraintF>, 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> {
|
|
||||||
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
|
let cs = leaf_hash.cs().or(root.cs()).unwrap();
|
||||||
.cs()
|
|
||||||
.or(root.cs())
|
|
||||||
.or(should_enforce.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(
|
let mut result =
|
||||||
&leaf_is_left,
|
leaf_hash.is_eq(&leaf_is_left.select(&self.path[0].0, &self.path[0].1)?)?;
|
||||||
&self.path[0].0,
|
|
||||||
&self.path[0].1,
|
|
||||||
should_enforce,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// 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(
|
let equality_cmp = previous_is_left.select(left_hash, right_hash)?;
|
||||||
&previous_is_left,
|
result = result.and(&previous_hash.is_eq(&equality_cmp)?)?;
|
||||||
left_hash,
|
|
||||||
right_hash,
|
|
||||||
should_enforce,
|
|
||||||
)?;
|
|
||||||
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;
|
||||||
|
|||||||
@@ -39,21 +39,11 @@ pub trait NIZKVerifierGadget<N: NIZK, ConstraintF: Field> {
|
|||||||
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> {
|
) -> Result<Boolean<ConstraintF>, SynthesisError>;
|
||||||
Self::conditional_verify(verification_key, input, proof, &Boolean::constant(true))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn conditional_verify<'a, T: 'a + ToBitsGadget<ConstraintF> + ?Sized>(
|
fn verify_prepared<'a, T: 'a + ToBitsGadget<ConstraintF> + ?Sized>(
|
||||||
verification_key: &Self::VerificationKeyVar,
|
|
||||||
input: impl IntoIterator<Item = &'a T>,
|
|
||||||
proof: &Self::ProofVar,
|
|
||||||
condition: &Boolean<ConstraintF>,
|
|
||||||
) -> Result<(), SynthesisError>;
|
|
||||||
|
|
||||||
fn conditional_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<Boolean<ConstraintF>, SynthesisError>;
|
||||||
) -> Result<(), SynthesisError>;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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<Boolean<E::Fq>, SynthesisError> {
|
||||||
) -> Result<(), SynthesisError> {
|
|
||||||
let pvk = vk.prepare()?;
|
let pvk = vk.prepare()?;
|
||||||
<Self as NIZKVerifierGadget<Gm17<E, C, V>, E::Fq>>::conditional_verify_prepared(
|
<Self as NIZKVerifierGadget<Gm17<E, C, V>, E::Fq>>::verify_prepared(&pvk, input, proof)
|
||||||
&pvk, input, proof, condition,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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<Boolean<E::Fq>, SynthesisError> {
|
||||||
) -> Result<(), 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)?;
|
test1.is_eq(&one)?.and(&test2.is_eq(&one)?)
|
||||||
test2.conditional_enforce_equal(&one, condition)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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!("=========================================================");
|
||||||
|
|||||||
@@ -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<Boolean<E::Fq>, SynthesisError> {
|
||||||
) -> Result<(), SynthesisError> {
|
|
||||||
let pvk = vk.prepare()?;
|
let pvk = vk.prepare()?;
|
||||||
<Self as NIZKVerifierGadget<Groth16<E, C, V>, E::Fq>>::conditional_verify_prepared(
|
<Self as NIZKVerifierGadget<Groth16<E, C, V>, E::Fq>>::verify_prepared(&pvk, input, proof)
|
||||||
&pvk, input, proof, condition,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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<Boolean<E::Fq>, SynthesisError> {
|
||||||
) -> Result<(), 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();
|
let test = P::final_exponentiation(&test_exp)?;
|
||||||
|
test.is_eq(&pvk.alpha_g1_beta_g2)
|
||||||
test.conditional_enforce_equal(&pvk.alpha_g1_beta_g2, condition)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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!("=========================================================");
|
||||||
|
|||||||
@@ -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<F: Field> CondSelectGadget<F> for AllocatedBit<F> {
|
|||||||
/// 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<F: Field> R1CSVar<F> for Boolean<F> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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!(),
|
||||||
|
|||||||
@@ -87,45 +87,3 @@ impl<T: EqGadget<F> + R1CSVar<F>, F: Field> EqGadget<F> 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user