From 376e9bc827549e900811194e07e7bc3874eae2c5 Mon Sep 17 00:00:00 2001 From: Srinath Setty Date: Fri, 13 Oct 2023 15:08:56 -0700 Subject: [PATCH] remove duplicate shape object --- src/lib.rs | 62 +++++++----------------------------- src/r1cs.rs | 1 + src/spartan/ppsnark.rs | 71 ++++++++++++++++++++++++++++-------------- src/spartan/snark.rs | 60 ++++++++++++++++++++++++----------- src/traits/snark.rs | 23 ++++---------- 5 files changed, 107 insertions(+), 110 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 37e9641..5a60502 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,15 +23,9 @@ pub mod provider; pub mod spartan; pub mod traits; -use crate::bellpepper::{ - r1cs::{SpartanShape, SpartanWitness}, - shape_cs::ShapeCS, - solver::SatisfyingAssignment, -}; -use bellpepper_core::{Circuit, ConstraintSystem}; +use bellpepper_core::Circuit; use core::marker::PhantomData; use errors::SpartanError; -use r1cs::{R1CSShape, RelaxedR1CSInstance, RelaxedR1CSWitness}; use serde::{Deserialize, Serialize}; use traits::{ commitment::{CommitmentEngineTrait, CommitmentTrait}, @@ -47,8 +41,6 @@ where G: Group, S: RelaxedR1CSSNARKTrait, { - S: R1CSShape, - ck: CommitmentKey, pk: S::ProverKey, } @@ -75,61 +67,34 @@ where S: RelaxedR1CSSNARKTrait, C: Circuit, { - comm_W: Commitment, // commitment to the witness - io: Vec, // public IO - snark: S, // snark proving the witness is satisfying - _p: PhantomData, + snark: S, // snark proving the witness is satisfying + _p: PhantomData, + _p2: PhantomData, } impl, C: Circuit> SNARK { /// Produces prover and verifier keys for the direct SNARK pub fn setup(circuit: C) -> Result<(ProverKey, VerifierKey), SpartanError> { - let mut cs: ShapeCS = ShapeCS::new(); - let _ = circuit.synthesize(&mut cs); - let (shape, ck) = cs.r1cs_shape(); - - let (pk, vk) = S::setup(&ck, &shape)?; - let pk = ProverKey { S: shape, ck, pk }; - let vk = VerifierKey { vk }; - - Ok((pk, vk)) + let (pk, vk) = S::setup(circuit)?; + Ok((ProverKey { pk }, VerifierKey { vk })) } /// Produces a proof of satisfiability of the provided circuit pub fn prove(pk: &ProverKey, circuit: C) -> Result { - let mut cs: SatisfyingAssignment = SatisfyingAssignment::new(); - let _ = circuit.synthesize(&mut cs); - - let (u, w) = cs - .r1cs_instance_and_witness(&pk.S, &pk.ck) - .map_err(|_e| SpartanError::UnSat)?; - - // convert the instance and witness to relaxed form - let (u_relaxed, w_relaxed) = ( - RelaxedR1CSInstance::from_r1cs_instance_unchecked(&u.comm_W, &u.X), - RelaxedR1CSWitness::from_r1cs_witness(&pk.S, &w), - ); - // prove the instance using Spartan - let snark = S::prove(&pk.ck, &pk.pk, &u_relaxed, &w_relaxed)?; + let snark = S::prove(&pk.pk, circuit)?; Ok(SNARK { - comm_W: u.comm_W, - io: u.X, snark, _p: Default::default(), + _p2: Default::default(), }) } /// Verifies a proof of satisfiability - pub fn verify(&self, vk: &VerifierKey) -> Result, SpartanError> { - // construct an instance using the provided commitment to the witness and IO - let u_relaxed = RelaxedR1CSInstance::from_r1cs_instance_unchecked(&self.comm_W, &self.io); - + pub fn verify(&self, vk: &VerifierKey, io: &[G::Scalar]) -> Result<(), SpartanError> { // verify the snark using the constructed instance - self.snark.verify(&vk.vk, &u_relaxed)?; - - Ok(self.io.clone()) + self.snark.verify(&vk.vk, io) } } @@ -222,12 +187,7 @@ mod tests { let snark = res.unwrap(); // verify the SNARK - let res = snark.verify(&vk); + let res = snark.verify(&vk, &[::Scalar::from(15u64)]); assert!(res.is_ok()); - - let io = res.unwrap(); - - // sanity: check the claimed output with a direct computation of the same - assert_eq!(io, vec![::Scalar::from(15u64)]); } } diff --git a/src/r1cs.rs b/src/r1cs.rs index e9d1415..86c71ce 100644 --- a/src/r1cs.rs +++ b/src/r1cs.rs @@ -63,6 +63,7 @@ pub struct RelaxedR1CSInstance { impl R1CS { /// Samples public parameters for the specified number of constraints and variables in an R1CS pub fn commitment_key(S: &R1CSShape) -> CommitmentKey { + let S = S.pad(); // pad the shape before computing the commitment key let num_cons = S.num_cons; let num_vars = S.num_vars; let total_nz = S.A.len() + S.B.len() + S.C.len(); diff --git a/src/spartan/ppsnark.rs b/src/spartan/ppsnark.rs index 1064995..4eefd3c 100644 --- a/src/spartan/ppsnark.rs +++ b/src/spartan/ppsnark.rs @@ -3,6 +3,11 @@ //! The verifier in this preprocessing SNARK maintains a commitment to R1CS matrices. This is beneficial when using a //! polynomial commitment scheme in which the verifier's costs is succinct. use crate::{ + bellpepper::{ + r1cs::{SpartanShape, SpartanWitness}, + shape_cs::ShapeCS, + solver::SatisfyingAssignment, + }, digest::{DigestComputer, SimpleDigestible}, errors::SpartanError, r1cs::{R1CSShape, RelaxedR1CSInstance, RelaxedR1CSWitness}, @@ -25,10 +30,10 @@ use crate::{ }, Commitment, CommitmentKey, CompressedCommitment, }; +use bellpepper_core::{Circuit, ConstraintSystem}; use core::{cmp::max, marker::PhantomData}; use ff::{Field, PrimeField}; use once_cell::sync::OnceCell; - use rayon::prelude::*; use serde::{Deserialize, Serialize}; @@ -656,6 +661,7 @@ impl SumcheckEngine for InnerSumcheckInstance { #[derive(Clone, Serialize, Deserialize)] #[serde(bound = "")] pub struct ProverKey> { + ck: CommitmentKey, pk_ee: EE::ProverKey, S: R1CSShape, S_repr: R1CSShapeSparkRepr, @@ -683,6 +689,9 @@ impl> SimpleDigestible for VerifierKey> { + // commitment to witness + comm_W: CompressedCommitment, + // commitment to oracles comm_Az: CompressedCommitment, comm_Bz: CompressedCommitment, @@ -876,21 +885,22 @@ impl> RelaxedR1CSSNARKTrait for Relaxe type ProverKey = ProverKey; type VerifierKey = VerifierKey; - fn setup( - ck: &CommitmentKey, - S: &R1CSShape, + fn setup>( + circuit: C, ) -> Result<(Self::ProverKey, Self::VerifierKey), SpartanError> { - let (pk_ee, vk_ee) = EE::setup(ck); + let mut cs: ShapeCS = ShapeCS::new(); + let _ = circuit.synthesize(&mut cs); + let (S, ck) = cs.r1cs_shape(); - // pad the R1CS matrices - let S = S.pad(); + let (pk_ee, vk_ee) = EE::setup(&ck); let S_repr = R1CSShapeSparkRepr::new(&S); - let S_comm = S_repr.commit(ck); + let S_comm = S_repr.commit(&ck); let vk = VerifierKey::new(S.num_cons, S.num_vars, S_comm.clone(), vk_ee); let pk = ProverKey { + ck, pk_ee, S, S_repr, @@ -902,12 +912,20 @@ impl> RelaxedR1CSSNARKTrait for Relaxe } /// produces a succinct proof of satisfiability of a `RelaxedR1CS` instance - fn prove( - ck: &CommitmentKey, - pk: &Self::ProverKey, - U: &RelaxedR1CSInstance, - W: &RelaxedR1CSWitness, - ) -> Result { + fn prove>(pk: &Self::ProverKey, circuit: C) -> Result { + let mut cs: SatisfyingAssignment = SatisfyingAssignment::new(); + let _ = circuit.synthesize(&mut cs); + + let (u, w) = cs + .r1cs_instance_and_witness(&pk.S, &pk.ck) + .map_err(|_e| SpartanError::UnSat)?; + + // convert the instance and witness to relaxed form + let (U, W) = ( + RelaxedR1CSInstance::from_r1cs_instance_unchecked(&u.comm_W, &u.X), + RelaxedR1CSWitness::from_r1cs_witness(&pk.S, &w), + ); + let W = W.pad(&pk.S); // pad the witness let mut transcript = G::TE::new(b"RelaxedR1CSSNARK"); @@ -919,7 +937,7 @@ impl> RelaxedR1CSSNARKTrait for Relaxe // append the verifier key (which includes commitment to R1CS matrices) and the RelaxedR1CSInstance to the transcript transcript.absorb(b"vk", &pk.vk_digest); - transcript.absorb(b"U", U); + transcript.absorb(b"U", &U); // compute the full satisfying assignment by concatenating W.W, U.u, and U.X let z = [W.W.clone(), vec![U.u], U.X.clone()].concat(); @@ -929,8 +947,8 @@ impl> RelaxedR1CSSNARKTrait for Relaxe // commit to Az, Bz, Cz let (comm_Az, (comm_Bz, comm_Cz)) = rayon::join( - || G::CE::commit(ck, &Az), - || rayon::join(|| G::CE::commit(ck, &Bz), || G::CE::commit(ck, &Cz)), + || G::CE::commit(&pk.ck, &Az), + || rayon::join(|| G::CE::commit(&pk.ck, &Bz), || G::CE::commit(&pk.ck, &Cz)), ); transcript.absorb(b"c", &[comm_Az, comm_Bz, comm_Cz].as_slice()); @@ -969,8 +987,10 @@ impl> RelaxedR1CSSNARKTrait for Relaxe // E_row(i) = eq(tau, row(i)) for all i // E_col(i) = z(col(i)) for all i let (mem_row, mem_col, E_row, E_col) = pk.S_repr.evaluation_oracles(&pk.S, &tau, &z); - let (comm_E_row, comm_E_col) = - rayon::join(|| G::CE::commit(ck, &E_row), || G::CE::commit(ck, &E_col)); + let (comm_E_row, comm_E_col) = rayon::join( + || G::CE::commit(&pk.ck, &E_row), + || G::CE::commit(&pk.ck, &E_col), + ); // absorb the claimed evaluations into the transcript transcript.absorb( @@ -1090,7 +1110,7 @@ impl> RelaxedR1CSSNARKTrait for Relaxe .collect::>(); let mut mem_sc_inst = ProductSumcheckInstance::new( - ck, + &pk.ck, vec![ init_row, read_row, write_row, audit_row, init_col, read_col, write_col, audit_col, ], @@ -1450,7 +1470,7 @@ impl> RelaxedR1CSSNARKTrait for Relaxe .sum(); let eval_arg = EE::prove( - ck, + &pk.ck, &pk.pk_ee, &mut transcript, &comm_joint, @@ -1460,6 +1480,7 @@ impl> RelaxedR1CSSNARKTrait for Relaxe )?; Ok(RelaxedR1CSSNARK { + comm_W: U.comm_W.compress(), comm_Az: comm_Az.compress(), comm_Bz: comm_Bz.compress(), comm_Cz: comm_Cz.compress(), @@ -1512,13 +1533,17 @@ impl> RelaxedR1CSSNARKTrait for Relaxe } /// verifies a proof of satisfiability of a `RelaxedR1CS` instance - fn verify(&self, vk: &Self::VerifierKey, U: &RelaxedR1CSInstance) -> Result<(), SpartanError> { + fn verify(&self, vk: &Self::VerifierKey, io: &[G::Scalar]) -> Result<(), SpartanError> { + // construct an instance using the provided commitment to the witness and IO + let comm_W = Commitment::::decompress(&self.comm_W)?; + let U = RelaxedR1CSInstance::from_r1cs_instance_unchecked(&comm_W, io); + let mut transcript = G::TE::new(b"RelaxedR1CSSNARK"); let mut u_vec: Vec> = Vec::new(); // append the verifier key (including commitment to R1CS matrices) and the RelaxedR1CSInstance to the transcript transcript.absorb(b"vk", &vk.digest()); - transcript.absorb(b"U", U); + transcript.absorb(b"U", &U); let comm_Az = Commitment::::decompress(&self.comm_Az)?; let comm_Bz = Commitment::::decompress(&self.comm_Bz)?; diff --git a/src/spartan/snark.rs b/src/spartan/snark.rs index cbf3fb1..a1ad696 100644 --- a/src/spartan/snark.rs +++ b/src/spartan/snark.rs @@ -5,6 +5,11 @@ //! an IPA-based polynomial commitment scheme. use crate::{ + bellpepper::{ + r1cs::{SpartanShape, SpartanWitness}, + shape_cs::ShapeCS, + solver::SatisfyingAssignment, + }, digest::{DigestComputer, SimpleDigestible}, errors::SpartanError, r1cs::{R1CSShape, RelaxedR1CSInstance, RelaxedR1CSWitness}, @@ -15,13 +20,14 @@ use crate::{ PolyEvalInstance, PolyEvalWitness, }, traits::{ - evaluation::EvaluationEngineTrait, snark::RelaxedR1CSSNARKTrait, Group, TranscriptEngineTrait, + commitment::CommitmentTrait, evaluation::EvaluationEngineTrait, snark::RelaxedR1CSSNARKTrait, + Group, TranscriptEngineTrait, }, - Commitment, CommitmentKey, + Commitment, CommitmentKey, CompressedCommitment, }; +use bellpepper_core::{Circuit, ConstraintSystem}; use ff::Field; use once_cell::sync::OnceCell; - use rayon::prelude::*; use serde::{Deserialize, Serialize}; @@ -29,6 +35,7 @@ use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize)] #[serde(bound = "")] pub struct ProverKey> { + ck: CommitmentKey, pk_ee: EE::ProverKey, S: R1CSShape, vk_digest: G::Scalar, // digest of the verifier's key @@ -74,6 +81,7 @@ impl> VerifierKey { #[derive(Serialize, Deserialize)] #[serde(bound = "")] pub struct RelaxedR1CSSNARK> { + comm_W: CompressedCommitment, sc_proof_outer: SumcheckProof, claims_outer: (G::Scalar, G::Scalar, G::Scalar), eval_E: G::Scalar, @@ -88,17 +96,18 @@ impl> RelaxedR1CSSNARKTrait for Relaxe type ProverKey = ProverKey; type VerifierKey = VerifierKey; - fn setup( - ck: &CommitmentKey, - S: &R1CSShape, + fn setup>( + circuit: C, ) -> Result<(Self::ProverKey, Self::VerifierKey), SpartanError> { - let (pk_ee, vk_ee) = EE::setup(ck); + let mut cs: ShapeCS = ShapeCS::new(); + let _ = circuit.synthesize(&mut cs); + let (S, ck) = cs.r1cs_shape(); - let S = S.pad(); + let (pk_ee, vk_ee) = EE::setup(&ck); let vk: VerifierKey = VerifierKey::new(S.clone(), vk_ee); - let pk = ProverKey { + ck, pk_ee, S, vk_digest: vk.digest(), @@ -108,12 +117,20 @@ impl> RelaxedR1CSSNARKTrait for Relaxe } /// produces a succinct proof of satisfiability of a `RelaxedR1CS` instance - fn prove( - ck: &CommitmentKey, - pk: &Self::ProverKey, - U: &RelaxedR1CSInstance, - W: &RelaxedR1CSWitness, - ) -> Result { + fn prove>(pk: &Self::ProverKey, circuit: C) -> Result { + let mut cs: SatisfyingAssignment = SatisfyingAssignment::new(); + let _ = circuit.synthesize(&mut cs); + + let (u, w) = cs + .r1cs_instance_and_witness(&pk.S, &pk.ck) + .map_err(|_e| SpartanError::UnSat)?; + + // convert the instance and witness to relaxed form + let (U, W) = ( + RelaxedR1CSInstance::from_r1cs_instance_unchecked(&u.comm_W, &u.X), + RelaxedR1CSWitness::from_r1cs_witness(&pk.S, &w), + ); + let W = W.pad(&pk.S); // pad the witness let mut transcript = G::TE::new(b"RelaxedR1CSSNARK"); @@ -122,7 +139,7 @@ impl> RelaxedR1CSSNARKTrait for Relaxe // append the digest of vk (which includes R1CS matrices) and the RelaxedR1CSInstance to the transcript transcript.absorb(b"vk", &pk.vk_digest); - transcript.absorb(b"U", U); + transcript.absorb(b"U", &U); // compute the full satisfying assignment by concatenating W.W, U.u, and U.X let mut z = [W.W.clone(), vec![U.u], U.X.clone()].concat(); @@ -336,7 +353,7 @@ impl> RelaxedR1CSSNARKTrait for Relaxe .sum(); let eval_arg = EE::prove( - ck, + &pk.ck, &pk.pk_ee, &mut transcript, &comm_joint, @@ -346,6 +363,7 @@ impl> RelaxedR1CSSNARKTrait for Relaxe )?; Ok(RelaxedR1CSSNARK { + comm_W: U.comm_W.compress(), sc_proof_outer, claims_outer: (claim_Az, claim_Bz, claim_Cz), eval_E, @@ -358,12 +376,16 @@ impl> RelaxedR1CSSNARKTrait for Relaxe } /// verifies a proof of satisfiability of a `RelaxedR1CS` instance - fn verify(&self, vk: &Self::VerifierKey, U: &RelaxedR1CSInstance) -> Result<(), SpartanError> { + fn verify(&self, vk: &Self::VerifierKey, io: &[G::Scalar]) -> Result<(), SpartanError> { + // construct an instance using the provided commitment to the witness and IO + let comm_W = Commitment::::decompress(&self.comm_W)?; + let U = RelaxedR1CSInstance::from_r1cs_instance_unchecked(&comm_W, io); + let mut transcript = G::TE::new(b"RelaxedR1CSSNARK"); // append the digest of R1CS matrices and the RelaxedR1CSInstance to the transcript transcript.absorb(b"vk", &vk.digest()); - transcript.absorb(b"U", U); + transcript.absorb(b"U", &U); let (num_rounds_x, num_rounds_y) = ( usize::try_from(vk.S.num_cons.ilog2()).unwrap(), diff --git a/src/traits/snark.rs b/src/traits/snark.rs index 8b136b5..d79996a 100644 --- a/src/traits/snark.rs +++ b/src/traits/snark.rs @@ -1,11 +1,6 @@ //! This module defines a collection of traits that define the behavior of a zkSNARK for RelaxedR1CS -use crate::{ - errors::SpartanError, - r1cs::{R1CSShape, RelaxedR1CSInstance, RelaxedR1CSWitness}, - traits::Group, - CommitmentKey, -}; - +use crate::{errors::SpartanError, traits::Group}; +use bellpepper_core::Circuit; use serde::{Deserialize, Serialize}; /// A trait that defines the behavior of a zkSNARK @@ -19,19 +14,13 @@ pub trait RelaxedR1CSSNARKTrait: type VerifierKey: Send + Sync + Serialize + for<'de> Deserialize<'de>; /// Produces the keys for the prover and the verifier - fn setup( - ck: &CommitmentKey, - S: &R1CSShape, + fn setup>( + circuit: C, ) -> Result<(Self::ProverKey, Self::VerifierKey), SpartanError>; /// Produces a new SNARK for a relaxed R1CS - fn prove( - ck: &CommitmentKey, - pk: &Self::ProverKey, - U: &RelaxedR1CSInstance, - W: &RelaxedR1CSWitness, - ) -> Result; + fn prove>(pk: &Self::ProverKey, circuit: C) -> Result; /// Verifies a SNARK for a relaxed R1CS - fn verify(&self, vk: &Self::VerifierKey, U: &RelaxedR1CSInstance) -> Result<(), SpartanError>; + fn verify(&self, vk: &Self::VerifierKey, io: &[G::Scalar]) -> Result<(), SpartanError>; }