Prepare Zexe for recursion (#241)

Co-authored-by: Pratyush Mishra <pratyushmishra@berkeley.edu>
This commit is contained in:
Weikeng Chen
2020-07-20 15:42:25 -07:00
committed by GitHub
parent 36305e7247
commit 61c70ed644
20 changed files with 1071 additions and 15 deletions

View File

@@ -5,9 +5,9 @@ use r1cs_std::prelude::*;
use crate::nizk::NIZK;
pub trait NIZKVerifierGadget<N: NIZK, ConstraintF: Field> {
type PreparedVerificationKeyGadget;
type VerificationKeyGadget: AllocGadget<N::VerificationParameters, ConstraintF>
+ ToBytesGadget<ConstraintF>;
type ProofGadget: AllocGadget<N::Proof, ConstraintF>;
fn check_verify<'a, CS, I, T>(
@@ -32,4 +32,16 @@ pub trait NIZKVerifierGadget<N: NIZK, ConstraintF: Field> {
CS: ConstraintSystem<ConstraintF>,
I: Iterator<Item = &'a T>,
T: 'a + ToBitsGadget<ConstraintF> + ?Sized;
fn conditional_check_verify_prepared<'a, CS, I, T>(
cs: CS,
prepared_verification_key: &Self::PreparedVerificationKeyGadget,
input: I,
proof: &Self::ProofGadget,
condition: &Boolean,
) -> Result<(), SynthesisError>
where
CS: ConstraintSystem<ConstraintF>,
I: Iterator<Item = &'a T>,
T: 'a + ToBitsGadget<ConstraintF> + ?Sized;
}

View File

@@ -7,7 +7,7 @@ use r1cs_core::{ConstraintSynthesizer, ConstraintSystem, SynthesisError};
use r1cs_std::prelude::*;
use core::{borrow::Borrow, marker::PhantomData};
use gm17::{Proof, VerifyingKey};
use gm17::{PreparedVerifyingKey, Proof, VerifyingKey};
#[derive(Derivative)]
#[derivative(Clone(bound = "P::G1Gadget: Clone, P::G2Gadget: Clone"))]
@@ -105,6 +105,7 @@ where
V: ToConstraintField<PairingE::Fr>,
P: PairingGadget<PairingE, ConstraintF>,
{
type PreparedVerificationKeyGadget = PreparedVerifyingKeyGadget<PairingE, ConstraintF, P>;
type VerificationKeyGadget = VerifyingKeyGadget<PairingE, ConstraintF, P>;
type ProofGadget = ProofGadget<PairingE, ConstraintF, P>;
@@ -131,7 +132,7 @@ where
fn conditional_check_verify<'a, CS, I, T>(
mut cs: CS,
vk: &Self::VerificationKeyGadget,
mut public_inputs: I,
public_inputs: I,
proof: &Self::ProofGadget,
condition: &Boolean,
) -> Result<(), SynthesisError>
@@ -141,9 +142,24 @@ where
T: 'a + ToBitsGadget<ConstraintF> + ?Sized,
{
let pvk = vk.prepare(&mut cs.ns(|| "Prepare vk"))?;
<Self as NIZKVerifierGadget<Gm17<PairingE, C, V>, ConstraintF>>::conditional_check_verify_prepared(cs, &pvk, public_inputs, proof, condition)
}
fn conditional_check_verify_prepared<'a, CS, I, T>(
mut cs: CS,
pvk: &Self::PreparedVerificationKeyGadget,
mut public_inputs: I,
proof: &Self::ProofGadget,
condition: &Boolean,
) -> Result<(), SynthesisError>
where
CS: ConstraintSystem<ConstraintF>,
I: Iterator<Item = &'a T>,
T: 'a + ToBitsGadget<ConstraintF> + ?Sized,
{
let pvk = pvk.clone();
// 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]
let g_psi = {
let mut cs = cs.ns(|| "Process input");
let mut g_psi = pvk.query[0].clone();
@@ -216,6 +232,148 @@ where
}
}
impl<PairingE, ConstraintF, P> AllocGadget<PreparedVerifyingKey<PairingE>, ConstraintF>
for PreparedVerifyingKeyGadget<PairingE, ConstraintF, P>
where
PairingE: PairingEngine,
ConstraintF: Field,
P: PairingGadget<PairingE, ConstraintF>,
P::G1PreparedGadget: AllocGadget<PairingE::G1Prepared, ConstraintF>,
P::G2PreparedGadget: AllocGadget<PairingE::G2Prepared, ConstraintF>,
{
#[inline]
fn alloc_constant<T, CS: ConstraintSystem<ConstraintF>>(
mut cs: CS,
val: T,
) -> Result<Self, SynthesisError>
where
T: Borrow<PreparedVerifyingKey<PairingE>>,
{
let pvk = val.borrow().clone();
let g_alpha =
P::G1Gadget::alloc_constant(cs.ns(|| "g_alpha"), pvk.g_alpha.into_projective())?;
let h_beta = P::G2Gadget::alloc_constant(cs.ns(|| "h_beta"), pvk.h_beta.into_projective())?;
let g_alpha_pc =
P::G1PreparedGadget::alloc_constant(cs.ns(|| "g_alpha_pc"), pvk.g_alpha.into())?;
let h_beta_pc =
P::G2PreparedGadget::alloc_constant(cs.ns(|| "h_beta_pc"), pvk.h_beta.into())?;
let g_gamma_pc =
P::G1PreparedGadget::alloc_constant(cs.ns(|| "g_gamma_pc"), pvk.g_gamma_pc)?;
let h_gamma_pc =
P::G2PreparedGadget::alloc_constant(cs.ns(|| "h_gamma_pc"), pvk.h_gamma_pc)?;
let h_pc = P::G2PreparedGadget::alloc_constant(cs.ns(|| "h_pc"), pvk.h_pc)?;
let mut query = Vec::<P::G1Gadget>::new();
for (i, item) in pvk.query.iter().enumerate() {
query.push(P::G1Gadget::alloc_constant(
&mut cs.ns(|| format!("query_{}", i)),
item.borrow().into_projective(),
)?);
}
Ok(Self {
g_alpha,
h_beta,
g_alpha_pc,
h_beta_pc,
g_gamma_pc,
h_gamma_pc,
h_pc,
query,
})
}
#[inline]
fn alloc<FN, T, CS: ConstraintSystem<ConstraintF>>(
mut cs: CS,
value_gen: FN,
) -> Result<Self, SynthesisError>
where
FN: FnOnce() -> Result<T, SynthesisError>,
T: Borrow<PreparedVerifyingKey<PairingE>>,
{
let pvk = value_gen()?.borrow().clone();
let g_alpha =
P::G1Gadget::alloc(cs.ns(|| "g_alpha"), || Ok(pvk.g_alpha.into_projective()))?;
let h_beta = P::G2Gadget::alloc(cs.ns(|| "h_beta"), || Ok(pvk.h_beta.into_projective()))?;
let g_alpha_pc =
P::G1PreparedGadget::alloc(cs.ns(|| "g_alpha_pc"), || Ok(pvk.g_alpha.into()))?;
let h_beta_pc =
P::G2PreparedGadget::alloc(cs.ns(|| "h_beta_pc"), || Ok(pvk.h_beta.into()))?;
let g_gamma_pc =
P::G1PreparedGadget::alloc(cs.ns(|| "g_gamma_pc"), || Ok(&pvk.g_gamma_pc))?;
let h_gamma_pc =
P::G2PreparedGadget::alloc(cs.ns(|| "h_gamma_pc"), || Ok(&pvk.h_gamma_pc))?;
let h_pc = P::G2PreparedGadget::alloc(cs.ns(|| "h_pc"), || Ok(&pvk.h_pc))?;
let mut query = Vec::<P::G1Gadget>::new();
for (i, item) in pvk.query.iter().enumerate() {
query.push(P::G1Gadget::alloc(
cs.ns(|| format!("query_{}", i)),
|| Ok(item.borrow().into_projective()),
)?);
}
Ok(Self {
g_alpha,
h_beta,
g_alpha_pc,
h_beta_pc,
g_gamma_pc,
h_gamma_pc,
h_pc,
query,
})
}
#[inline]
fn alloc_input<FN, T, CS: ConstraintSystem<ConstraintF>>(
mut cs: CS,
value_gen: FN,
) -> Result<Self, SynthesisError>
where
FN: FnOnce() -> Result<T, SynthesisError>,
T: Borrow<PreparedVerifyingKey<PairingE>>,
{
let pvk = value_gen()?.borrow().clone();
let g_alpha =
P::G1Gadget::alloc_input(cs.ns(|| "g_alpha"), || Ok(pvk.g_alpha.into_projective()))?;
let h_beta =
P::G2Gadget::alloc_input(cs.ns(|| "h_beta"), || Ok(pvk.h_beta.into_projective()))?;
let g_alpha_pc =
P::G1PreparedGadget::alloc_input(cs.ns(|| "g_alpha_pc"), || Ok(pvk.g_alpha.into()))?;
let h_beta_pc =
P::G2PreparedGadget::alloc_input(cs.ns(|| "h_beta_pc"), || Ok(pvk.h_beta.into()))?;
let g_gamma_pc =
P::G1PreparedGadget::alloc_input(cs.ns(|| "g_gamma_pc"), || Ok(&pvk.g_gamma_pc))?;
let h_gamma_pc =
P::G2PreparedGadget::alloc_input(cs.ns(|| "h_gamma_pc"), || Ok(&pvk.h_gamma_pc))?;
let h_pc = P::G2PreparedGadget::alloc_input(cs.ns(|| "h_pc"), || Ok(&pvk.h_pc))?;
let mut query = Vec::<P::G1Gadget>::new();
for (i, item) in pvk.query.iter().enumerate() {
query.push(P::G1Gadget::alloc_input(
&mut cs.ns(|| format!("query_{}", i)),
|| Ok(item.borrow().into_projective()),
)?);
}
Ok(Self {
g_alpha,
h_beta,
g_alpha_pc,
h_beta_pc,
g_gamma_pc,
h_gamma_pc,
h_pc,
query,
})
}
}
impl<PairingE, ConstraintF, P> AllocGadget<VerifyingKey<PairingE>, ConstraintF>
for VerifyingKeyGadget<PairingE, ConstraintF, P>
where

View File

@@ -7,7 +7,7 @@ use r1cs_core::{ConstraintSynthesizer, ConstraintSystem, SynthesisError};
use r1cs_std::prelude::*;
use core::{borrow::Borrow, marker::PhantomData};
use groth16::{Proof, VerifyingKey};
use groth16::{PreparedVerifyingKey, Proof, VerifyingKey};
#[derive(Derivative)]
#[derivative(Clone(bound = "P::G1Gadget: Clone, P::G2Gadget: Clone"))]
@@ -106,6 +106,7 @@ where
V: ToConstraintField<PairingE::Fr>,
P: PairingGadget<PairingE, ConstraintF>,
{
type PreparedVerificationKeyGadget = PreparedVerifyingKeyGadget<PairingE, ConstraintF, P>;
type VerificationKeyGadget = VerifyingKeyGadget<PairingE, ConstraintF, P>;
type ProofGadget = ProofGadget<PairingE, ConstraintF, P>;
@@ -132,7 +133,7 @@ where
fn conditional_check_verify<'a, CS, I, T>(
mut cs: CS,
vk: &Self::VerificationKeyGadget,
mut public_inputs: I,
public_inputs: I,
proof: &Self::ProofGadget,
condition: &Boolean,
) -> Result<(), SynthesisError>
@@ -142,6 +143,22 @@ where
T: 'a + ToBitsGadget<ConstraintF> + ?Sized,
{
let pvk = vk.prepare(&mut cs.ns(|| "Prepare vk"))?;
<Self as NIZKVerifierGadget<Groth16<PairingE, C, V>, ConstraintF>>::conditional_check_verify_prepared(cs, &pvk, public_inputs, proof, condition)
}
fn conditional_check_verify_prepared<'a, CS, I, T>(
mut cs: CS,
pvk: &Self::PreparedVerificationKeyGadget,
mut public_inputs: I,
proof: &Self::ProofGadget,
condition: &Boolean,
) -> Result<(), SynthesisError>
where
CS: ConstraintSystem<ConstraintF>,
I: Iterator<Item = &'a T>,
T: 'a + ToBitsGadget<ConstraintF> + ?Sized,
{
let pvk = pvk.clone();
let g_ic = {
let mut cs = cs.ns(|| "Process input");
@@ -187,6 +204,123 @@ where
}
}
impl<PairingE, ConstraintF, P> AllocGadget<PreparedVerifyingKey<PairingE>, ConstraintF>
for PreparedVerifyingKeyGadget<PairingE, ConstraintF, P>
where
PairingE: PairingEngine,
ConstraintF: Field,
P: PairingGadget<PairingE, ConstraintF>,
P::G2PreparedGadget: AllocGadget<PairingE::G2Prepared, ConstraintF>,
{
fn alloc_constant<T, CS: ConstraintSystem<ConstraintF>>(
mut cs: CS,
val: T,
) -> Result<Self, SynthesisError>
where
T: Borrow<PreparedVerifyingKey<PairingE>>,
{
let pvk = val.borrow().clone();
let alpha_g1_beta_g2 =
P::GTGadget::alloc_constant(cs.ns(|| "alpha_g1_beta_g2"), pvk.alpha_g1_beta_g2)?;
let gamma_g2_neg_pc =
P::G2PreparedGadget::alloc_constant(cs.ns(|| "gamma_g2_neg_pc"), pvk.gamma_g2_neg_pc)?;
let delta_g2_neg_pc =
P::G2PreparedGadget::alloc_constant(cs.ns(|| "delta_g2_neg_pc"), pvk.delta_g2_neg_pc)?;
let mut gamma_abc_g1 = Vec::<P::G1Gadget>::new();
for (i, item) in pvk.gamma_abc_g1.iter().enumerate() {
gamma_abc_g1.push(P::G1Gadget::alloc_constant(
cs.ns(|| format!("query_{}", i)),
item.borrow().into_projective(),
)?);
}
Ok(Self {
alpha_g1_beta_g2,
gamma_g2_neg_pc,
delta_g2_neg_pc,
gamma_abc_g1,
})
}
fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>(
mut cs: CS,
f: F,
) -> Result<Self, SynthesisError>
where
F: FnOnce() -> Result<T, SynthesisError>,
T: Borrow<PreparedVerifyingKey<PairingE>>,
{
let pvk = f()?.borrow().clone();
let alpha_g1_beta_g2 =
P::GTGadget::alloc(cs.ns(|| "alpha_g1_beta_g2"), || Ok(pvk.alpha_g1_beta_g2))?;
let gamma_g2_neg_pc =
P::G2PreparedGadget::alloc(cs.ns(|| "gamma_g2_neg_pc"), || Ok(&pvk.gamma_g2_neg_pc))?;
let delta_g2_neg_pc =
P::G2PreparedGadget::alloc(cs.ns(|| "delta_g2_neg_pc"), || Ok(&pvk.delta_g2_neg_pc))?;
let mut gamma_abc_g1 = Vec::<P::G1Gadget>::new();
for (i, item) in pvk.gamma_abc_g1.iter().enumerate() {
gamma_abc_g1.push(P::G1Gadget::alloc(
cs.ns(|| format!("query_{}", i)),
|| Ok(item.borrow().into_projective()),
)?);
}
Ok(Self {
alpha_g1_beta_g2,
gamma_g2_neg_pc,
delta_g2_neg_pc,
gamma_abc_g1,
})
}
fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>(
mut cs: CS,
f: F,
) -> Result<Self, SynthesisError>
where
F: FnOnce() -> Result<T, SynthesisError>,
T: Borrow<PreparedVerifyingKey<PairingE>>,
{
let pvk = f()?.borrow().clone();
let alpha_g1_beta_g2 =
P::GTGadget::alloc_input(cs.ns(|| "alpha_g1_beta_g2"), || Ok(pvk.alpha_g1_beta_g2))?;
let gamma_g2_neg_pc =
P::G2PreparedGadget::alloc_input(cs.ns(|| "gamma_g2_neg_pc"), || {
Ok(&pvk.gamma_g2_neg_pc)
})?;
let delta_g2_neg_pc =
P::G2PreparedGadget::alloc_input(cs.ns(|| "delta_g2_neg_pc"), || {
Ok(&pvk.delta_g2_neg_pc)
})?;
let mut gamma_abc_g1 = Vec::<P::G1Gadget>::new();
for (i, item) in pvk.gamma_abc_g1.iter().enumerate() {
gamma_abc_g1.push(P::G1Gadget::alloc_input(
cs.ns(|| format!("query_{}", i)),
|| Ok(item.borrow().into_projective()),
)?);
}
Ok(Self {
alpha_g1_beta_g2,
gamma_g2_neg_pc,
delta_g2_neg_pc,
gamma_abc_g1,
})
}
}
impl<PairingE, ConstraintF, P> AllocGadget<VerifyingKey<PairingE>, ConstraintF>
for VerifyingKeyGadget<PairingE, ConstraintF, P>
where