From cecc2f1b624504ce7a3324b97403c5eee9ce1eb6 Mon Sep 17 00:00:00 2001 From: Srinath Setty Date: Thu, 12 May 2022 13:46:05 +0530 Subject: [PATCH] Transcript (#46) * add items to transcript * add additional items to transcript * fix benches * cargo fmt --- Cargo.toml | 2 +- README.md | 3 ++- benches/snark.rs | 13 +++++++++++-- examples/cubic.rs | 1 + profiler/snark.rs | 10 +++++++++- src/lib.rs | 22 +++++++++++++++++++++- src/nizk/mod.rs | 6 ++++++ src/r1csinstance.rs | 24 +++++++++++++++++++++++- src/r1csproof.rs | 4 ++++ src/sparse_mlpoly.rs | 18 ++++++++++++++++-- src/transcript.rs | 2 +- 11 files changed, 95 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index df38f6c..487dbc6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spartan" -version = "0.5.0" +version = "0.6.0" authors = ["Srinath Setty "] edition = "2018" description = "High-speed zkSNARKs without trusted setup" diff --git a/README.md b/README.md index ebc1008..e86921e 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ Some of our public APIs' style is inspired by the underlying crates we use. // produce a proof of satisfiability let mut prover_transcript = Transcript::new(b"snark_example"); - let proof = SNARK::prove(&inst, &decomm, vars, &inputs, &gens, &mut prover_transcript); + let proof = SNARK::prove(&inst, &comm, &decomm, vars, &inputs, &gens, &mut prover_transcript); // verify the proof of satisfiability let mut verifier_transcript = Transcript::new(b"snark_example"); @@ -132,6 +132,7 @@ Finally, we provide an example that specifies a custom R1CS instance instead of let mut prover_transcript = Transcript::new(b"snark_example"); let proof = SNARK::prove( &inst, + &comm, &decomm, assignment_vars, &assignment_inputs, diff --git a/benches/snark.rs b/benches/snark.rs index 110d642..7747f9c 100644 --- a/benches/snark.rs +++ b/benches/snark.rs @@ -47,7 +47,7 @@ fn snark_prove_benchmark(c: &mut Criterion) { let gens = SNARKGens::new(num_cons, num_vars, num_inputs, num_cons); // produce a commitment to R1CS instance - let (_comm, decomm) = SNARK::encode(&inst, &gens); + let (comm, decomm) = SNARK::encode(&inst, &gens); // produce a proof let name = format!("SNARK_prove_{}", num_cons); @@ -56,6 +56,7 @@ fn snark_prove_benchmark(c: &mut Criterion) { let mut prover_transcript = Transcript::new(b"example"); SNARK::prove( black_box(&inst), + black_box(&comm), black_box(&decomm), black_box(vars.clone()), black_box(&inputs), @@ -87,7 +88,15 @@ fn snark_verify_benchmark(c: &mut Criterion) { // produce a proof of satisfiability let mut prover_transcript = Transcript::new(b"example"); - let proof = SNARK::prove(&inst, &decomm, vars, &inputs, &gens, &mut prover_transcript); + let proof = SNARK::prove( + &inst, + &comm, + &decomm, + vars, + &inputs, + &gens, + &mut prover_transcript, + ); // verify the proof let name = format!("SNARK_verify_{}", num_cons); diff --git a/examples/cubic.rs b/examples/cubic.rs index 9f5eade..dcfa7b4 100644 --- a/examples/cubic.rs +++ b/examples/cubic.rs @@ -128,6 +128,7 @@ fn main() { let mut prover_transcript = Transcript::new(b"snark_example"); let proof = SNARK::prove( &inst, + &comm, &decomm, assignment_vars, &assignment_inputs, diff --git a/profiler/snark.rs b/profiler/snark.rs index cc4862a..5308a79 100644 --- a/profiler/snark.rs +++ b/profiler/snark.rs @@ -33,7 +33,15 @@ pub fn main() { // produce a proof of satisfiability let mut prover_transcript = Transcript::new(b"snark_example"); - let proof = SNARK::prove(&inst, &decomm, vars, &inputs, &gens, &mut prover_transcript); + let proof = SNARK::prove( + &inst, + &comm, + &decomm, + vars, + &inputs, + &gens, + &mut prover_transcript, + ); let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default()); bincode::serialize_into(&mut encoder, &proof).unwrap(); diff --git a/src/lib.rs b/src/lib.rs index fc90919..e48eecf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -336,6 +336,7 @@ impl SNARK { /// A method to produce a SNARK proof of the satisfiability of an R1CS instance pub fn prove( inst: &Instance, + comm: &ComputationCommitment, decomm: &ComputationDecommitment, vars: VarsAssignment, inputs: &InputsAssignment, @@ -347,7 +348,10 @@ impl SNARK { // we create a Transcript object seeded with a random Scalar // to aid the prover produce its randomness let mut random_tape = RandomTape::new(b"proof"); + transcript.append_protocol_name(SNARK::protocol_name()); + comm.comm.append_to_transcript(b"comm", transcript); + let (r1cs_sat_proof, rx, ry) = { let (proof, rx, ry) = { // we might need to pad variables @@ -424,6 +428,9 @@ impl SNARK { let timer_verify = Timer::new("SNARK::verify"); transcript.append_protocol_name(SNARK::protocol_name()); + // append a commitment to the computation to the transcript + comm.comm.append_to_transcript(b"comm", transcript); + let timer_sat_proof = Timer::new("verify_sat_proof"); assert_eq!(input.assignment.len(), comm.comm.get_num_inputs()); let (rx, ry) = self.r1cs_sat_proof.verify( @@ -500,7 +507,10 @@ impl NIZK { // we create a Transcript object seeded with a random Scalar // to aid the prover produce its randomness let mut random_tape = RandomTape::new(b"proof"); + transcript.append_protocol_name(NIZK::protocol_name()); + inst.inst.append_to_transcript(b"inst", transcript); + let (r1cs_sat_proof, rx, ry) = { // we might need to pad variables let padded_vars = { @@ -544,6 +554,7 @@ impl NIZK { let timer_verify = Timer::new("NIZK::verify"); transcript.append_protocol_name(NIZK::protocol_name()); + inst.inst.append_to_transcript(b"inst", transcript); // We send evaluations of A, B, C at r = (rx, ry) as claims // to enable the verifier complete the first sum-check @@ -594,7 +605,15 @@ mod tests { // produce a proof let mut prover_transcript = Transcript::new(b"example"); - let proof = SNARK::prove(&inst, &decomm, vars, &inputs, &gens, &mut prover_transcript); + let proof = SNARK::prove( + &inst, + &comm, + &decomm, + vars, + &inputs, + &gens, + &mut prover_transcript, + ); // verify the proof let mut verifier_transcript = Transcript::new(b"example"); @@ -696,6 +715,7 @@ mod tests { let mut prover_transcript = Transcript::new(b"snark_example"); let proof = SNARK::prove( &inst, + &comm, &decomm, assignment_vars.clone(), &assignment_inputs, diff --git a/src/nizk/mod.rs b/src/nizk/mod.rs index 35e75eb..e80f2b1 100644 --- a/src/nizk/mod.rs +++ b/src/nizk/mod.rs @@ -336,6 +336,8 @@ impl DotProductProof { let Cy = y.commit(blind_y, gens_1).compress(); Cy.append_to_transcript(b"Cy", transcript); + a_vec.append_to_transcript(b"a", transcript); + let delta = d_vec.commit(&r_delta, gens_n).compress(); delta.append_to_transcript(b"delta", transcript); @@ -381,6 +383,7 @@ impl DotProductProof { transcript.append_protocol_name(DotProductProof::protocol_name()); Cx.append_to_transcript(b"Cx", transcript); Cy.append_to_transcript(b"Cy", transcript); + a.append_to_transcript(b"a", transcript); self.delta.append_to_transcript(b"delta", transcript); self.beta.append_to_transcript(b"beta", transcript); @@ -466,6 +469,8 @@ impl DotProductProofLog { let Cy = y.commit(blind_y, &gens.gens_1).compress(); Cy.append_to_transcript(b"Cy", transcript); + a_vec.append_to_transcript(b"a", transcript); + let blind_Gamma = blind_x + blind_y; let (bullet_reduction_proof, _Gamma_hat, x_hat, a_hat, g_hat, rhat_Gamma) = BulletReductionProof::prove( @@ -526,6 +531,7 @@ impl DotProductProofLog { transcript.append_protocol_name(DotProductProofLog::protocol_name()); Cx.append_to_transcript(b"Cx", transcript); Cy.append_to_transcript(b"Cy", transcript); + a.append_to_transcript(b"a", transcript); let Gamma = Cx.unpack()? + Cy.unpack()?; diff --git a/src/r1csinstance.rs b/src/r1csinstance.rs index 8e3abea..6a3885a 100644 --- a/src/r1csinstance.rs +++ b/src/r1csinstance.rs @@ -1,3 +1,5 @@ +use crate::transcript::AppendToTranscript; + use super::dense_mlpoly::DensePolynomial; use super::errors::ProofVerifyError; use super::math::Math; @@ -8,11 +10,12 @@ use super::sparse_mlpoly::{ SparseMatPolyCommitmentGens, SparseMatPolyEvalProof, SparseMatPolynomial, }; use super::timer::Timer; +use flate2::{write::ZlibEncoder, Compression}; use merlin::Transcript; use rand::rngs::OsRng; use serde::{Deserialize, Serialize}; -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize)] pub struct R1CSInstance { num_cons: usize, num_vars: usize, @@ -22,6 +25,15 @@ pub struct R1CSInstance { C: SparseMatPolynomial, } +impl AppendToTranscript for R1CSInstance { + fn append_to_transcript(&self, _label: &'static [u8], transcript: &mut Transcript) { + let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default()); + bincode::serialize_into(&mut encoder, &self).unwrap(); + let bytes = encoder.finish().unwrap(); + transcript.append_message(b"R1CSInstance", &bytes); + } +} + pub struct R1CSCommitmentGens { gens: SparseMatPolyCommitmentGens, } @@ -43,6 +55,7 @@ impl R1CSCommitmentGens { } } +#[derive(Debug, Serialize, Deserialize)] pub struct R1CSCommitment { num_cons: usize, num_vars: usize, @@ -50,6 +63,15 @@ pub struct R1CSCommitment { comm: SparseMatPolyCommitment, } +impl AppendToTranscript for R1CSCommitment { + fn append_to_transcript(&self, _label: &'static [u8], transcript: &mut Transcript) { + transcript.append_u64(b"num_cons", self.num_cons as u64); + transcript.append_u64(b"num_vars", self.num_vars as u64); + transcript.append_u64(b"num_inputs", self.num_inputs as u64); + self.comm.append_to_transcript(b"comm", transcript); + } +} + pub struct R1CSDecommitment { dense: MultiSparseMatPolynomialAsDense, } diff --git a/src/r1csproof.rs b/src/r1csproof.rs index d57735f..60c6366 100644 --- a/src/r1csproof.rs +++ b/src/r1csproof.rs @@ -152,6 +152,8 @@ impl R1CSProof { // we currently require the number of |inputs| + 1 to be at most number of vars assert!(input.len() < vars.len()); + input.append_to_transcript(b"input", transcript); + let timer_commit = Timer::new("polycommit"); let (poly_vars, comm_vars, blinds_vars) = { // create a multilinear polynomial using the supplied assignment for variables @@ -355,6 +357,8 @@ impl R1CSProof { ) -> Result<(Vec, Vec), ProofVerifyError> { transcript.append_protocol_name(R1CSProof::protocol_name()); + input.append_to_transcript(b"input", transcript); + let n = num_vars; // add the commitment to the verifier's transcript self diff --git a/src/sparse_mlpoly.rs b/src/sparse_mlpoly.rs index df9e240..00a86ae 100644 --- a/src/sparse_mlpoly.rs +++ b/src/sparse_mlpoly.rs @@ -16,7 +16,7 @@ use core::cmp::Ordering; use merlin::Transcript; use serde::{Deserialize, Serialize}; -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize)] pub struct SparseMatEntry { row: usize, col: usize, @@ -29,7 +29,7 @@ impl SparseMatEntry { } } -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize)] pub struct SparseMatPolynomial { num_vars_x: usize, num_vars_y: usize, @@ -330,6 +330,20 @@ pub struct SparseMatPolyCommitment { comm_comb_mem: PolyCommitment, } +impl AppendToTranscript for SparseMatPolyCommitment { + fn append_to_transcript(&self, _label: &'static [u8], transcript: &mut Transcript) { + transcript.append_u64(b"batch_size", self.batch_size as u64); + transcript.append_u64(b"num_ops", self.num_ops as u64); + transcript.append_u64(b"num_mem_cells", self.num_mem_cells as u64); + self + .comm_comb_ops + .append_to_transcript(b"comm_comb_ops", transcript); + self + .comm_comb_mem + .append_to_transcript(b"comm_comb_mem", transcript); + } +} + impl SparseMatPolynomial { pub fn new(num_vars_x: usize, num_vars_y: usize, M: Vec) -> Self { SparseMatPolynomial { diff --git a/src/transcript.rs b/src/transcript.rs index 00572b1..a57f150 100644 --- a/src/transcript.rs +++ b/src/transcript.rs @@ -46,7 +46,7 @@ impl AppendToTranscript for Scalar { } } -impl AppendToTranscript for Vec { +impl AppendToTranscript for [Scalar] { fn append_to_transcript(&self, label: &'static [u8], transcript: &mut Transcript) { transcript.append_message(label, b"begin_append_vector"); for item in self {