From bbb7d75ec8d338e40f7e69f809fa8c5cba31afe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Fran=C3=A7a?= <43445067+brunoffranca@users.noreply.github.com> Date: Wed, 22 Apr 2020 21:30:33 +0100 Subject: [PATCH] Implement `conditional_check_verify` for `NIZK`s (#195) * Implement `ToBitsGadget` for `UInt8` and `Vec` * Add `kary_or` function to `Boolean`. --- crypto-primitives/src/nizk/constraints.rs | 12 +++++++++ .../src/nizk/gm17/constraints.rs | 25 +++++++++++++++++-- crypto-primitives/src/nizk/gm17/mod.rs | 2 +- .../src/nizk/groth16/constraints.rs | 23 ++++++++++++++++- crypto-primitives/src/nizk/groth16/mod.rs | 2 +- r1cs-std/src/bits/boolean.rs | 16 ++++++++++++ r1cs-std/src/bits/mod.rs | 22 ++++++++++++++++ 7 files changed, 97 insertions(+), 5 deletions(-) diff --git a/crypto-primitives/src/nizk/constraints.rs b/crypto-primitives/src/nizk/constraints.rs index da75548..61c4cb6 100644 --- a/crypto-primitives/src/nizk/constraints.rs +++ b/crypto-primitives/src/nizk/constraints.rs @@ -20,4 +20,16 @@ pub trait NIZKVerifierGadget { CS: ConstraintSystem, I: Iterator, T: 'a + ToBitsGadget + ?Sized; + + fn conditional_check_verify<'a, CS, I, T>( + cs: CS, + verification_key: &Self::VerificationKeyGadget, + input: I, + proof: &Self::ProofGadget, + condition: &Boolean, + ) -> Result<(), SynthesisError> + where + CS: ConstraintSystem, + I: Iterator, + T: 'a + ToBitsGadget + ?Sized; } diff --git a/crypto-primitives/src/nizk/gm17/constraints.rs b/crypto-primitives/src/nizk/gm17/constraints.rs index 6e9b523..6f09608 100644 --- a/crypto-primitives/src/nizk/gm17/constraints.rs +++ b/crypto-primitives/src/nizk/gm17/constraints.rs @@ -109,10 +109,31 @@ where type ProofGadget = ProofGadget; fn check_verify<'a, CS, I, T>( + cs: CS, + vk: &Self::VerificationKeyGadget, + public_inputs: I, + proof: &Self::ProofGadget, + ) -> Result<(), SynthesisError> + where + CS: ConstraintSystem, + I: Iterator, + T: 'a + ToBitsGadget + ?Sized, + { + , ConstraintF>>::conditional_check_verify( + cs, + vk, + public_inputs, + proof, + &Boolean::constant(true), + ) + } + + fn conditional_check_verify<'a, CS, I, T>( mut cs: CS, vk: &Self::VerificationKeyGadget, mut public_inputs: I, proof: &Self::ProofGadget, + condition: &Boolean, ) -> Result<(), SynthesisError> where CS: ConstraintSystem, @@ -189,8 +210,8 @@ where let test2 = P::final_exponentiation(cs.ns(|| "Final Exp 2"), &test2_exp)?; let one = P::GTGadget::one(cs.ns(|| "GT One"))?; - test1.enforce_equal(cs.ns(|| "Test 1"), &one)?; - test2.enforce_equal(cs.ns(|| "Test 2"), &one)?; + test1.conditional_enforce_equal(cs.ns(|| "Test 1"), &one, condition)?; + test2.conditional_enforce_equal(cs.ns(|| "Test 2"), &one, condition)?; Ok(()) } } diff --git a/crypto-primitives/src/nizk/gm17/mod.rs b/crypto-primitives/src/nizk/gm17/mod.rs index 82c312c..290add9 100644 --- a/crypto-primitives/src/nizk/gm17/mod.rs +++ b/crypto-primitives/src/nizk/gm17/mod.rs @@ -35,10 +35,10 @@ impl, V: ToConstraintField; type VerificationParameters = VerifyingKey; type PreparedVerificationParameters = PreparedVerifyingKey; - type VerifierInput = V; type Proof = Proof; fn setup( diff --git a/crypto-primitives/src/nizk/groth16/constraints.rs b/crypto-primitives/src/nizk/groth16/constraints.rs index 9b8144c..49e07d7 100644 --- a/crypto-primitives/src/nizk/groth16/constraints.rs +++ b/crypto-primitives/src/nizk/groth16/constraints.rs @@ -110,10 +110,31 @@ where type ProofGadget = ProofGadget; fn check_verify<'a, CS, I, T>( + cs: CS, + vk: &Self::VerificationKeyGadget, + public_inputs: I, + proof: &Self::ProofGadget, + ) -> Result<(), SynthesisError> + where + CS: ConstraintSystem, + I: Iterator, + T: 'a + ToBitsGadget + ?Sized, + { + , ConstraintF>>::conditional_check_verify( + cs, + vk, + public_inputs, + proof, + &Boolean::constant(true), + ) + } + + fn conditional_check_verify<'a, CS, I, T>( mut cs: CS, vk: &Self::VerificationKeyGadget, mut public_inputs: I, proof: &Self::ProofGadget, + condition: &Boolean, ) -> Result<(), SynthesisError> where CS: ConstraintSystem, @@ -161,7 +182,7 @@ where let test = P::final_exponentiation(cs.ns(|| "Final Exp"), &test_exp).unwrap(); - test.enforce_equal(cs.ns(|| "Test 1"), &pvk.alpha_g1_beta_g2)?; + test.conditional_enforce_equal(cs.ns(|| "Test 1"), &pvk.alpha_g1_beta_g2, condition)?; Ok(()) } } diff --git a/crypto-primitives/src/nizk/groth16/mod.rs b/crypto-primitives/src/nizk/groth16/mod.rs index 44faec9..c4d6f05 100644 --- a/crypto-primitives/src/nizk/groth16/mod.rs +++ b/crypto-primitives/src/nizk/groth16/mod.rs @@ -35,10 +35,10 @@ impl, V: ToConstraintField; type VerificationParameters = VerifyingKey; type PreparedVerificationParameters = PreparedVerifyingKey; - type VerifierInput = V; type Proof = Proof; fn setup( diff --git a/r1cs-std/src/bits/boolean.rs b/r1cs-std/src/bits/boolean.rs index 23a205f..70759d1 100644 --- a/r1cs-std/src/bits/boolean.rs +++ b/r1cs-std/src/bits/boolean.rs @@ -549,6 +549,22 @@ impl Boolean { Ok(cur) } + pub fn kary_or(mut cs: CS, bits: &[Self]) -> Result + where + ConstraintF: Field, + CS: ConstraintSystem, + { + assert!(!bits.is_empty()); + let mut bits = bits.iter(); + + let mut cur: Self = *bits.next().unwrap(); + for (i, next) in bits.enumerate() { + cur = Boolean::or(cs.ns(|| format!("OR {}", i)), &cur, next)?; + } + + Ok(cur) + } + /// Asserts that at least one operand is false. pub fn enforce_nand(mut cs: CS, bits: &[Self]) -> Result<(), SynthesisError> where diff --git a/r1cs-std/src/bits/mod.rs b/r1cs-std/src/bits/mod.rs index 3829d8b..6bb4747 100644 --- a/r1cs-std/src/bits/mod.rs +++ b/r1cs-std/src/bits/mod.rs @@ -58,6 +58,15 @@ impl ToBitsGadget for Vec { } } +impl ToBitsGadget for UInt8 { + fn to_bits>( + &self, + _cs: CS, + ) -> Result, SynthesisError> { + Ok(self.into_bits_le()) + } +} + impl ToBitsGadget for [UInt8] { fn to_bits>( &self, @@ -71,6 +80,19 @@ impl ToBitsGadget for [UInt8] { } } +impl ToBitsGadget for Vec { + fn to_bits>( + &self, + _cs: CS, + ) -> Result, SynthesisError> { + let mut result = Vec::with_capacity(&self.len() * 8); + for byte in self { + result.extend_from_slice(&byte.into_bits_le()); + } + Ok(result) + } +} + pub trait ToBytesGadget { /// Outputs a canonical byte-wise representation of `self`. ///