Browse Source

implement transcript methods for various types (#49)

* implement transcript methods for various types

* address clippy

* add shape to transcript
main
Srinath Setty 2 years ago
committed by GitHub
parent
commit
0d53db18e3
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 104 additions and 11 deletions
  1. +3
    -0
      Cargo.toml
  2. +1
    -5
      src/commitments.rs
  3. +19
    -4
      src/lib.rs
  4. +61
    -2
      src/r1cs.rs
  5. +20
    -0
      src/traits.rs

+ 3
- 0
Cargo.toml

@ -27,6 +27,9 @@ neptune = "6.1"
generic-array = "0.14.4" generic-array = "0.14.4"
bellperson-nonnative = { version = "0.2.1", default-features = false, features = ["wasm"] } bellperson-nonnative = { version = "0.2.1", default-features = false, features = ["wasm"] }
rug = { version = "1.10", default-features = false, features = ["integer", "serde", "rand"] } rug = { version = "1.10", default-features = false, features = ["integer", "serde", "rand"] }
serde = { version = "1.0", features = ["derive"] }
bincode = "1.2.1"
flate2 = "1.0"
[features] [features]
default = [ "bellperson/default", "bellperson-nonnative/default" ] default = [ "bellperson/default", "bellperson-nonnative/default" ]

+ 1
- 5
src/commitments.rs

@ -1,6 +1,6 @@
use super::{ use super::{
errors::NovaError, errors::NovaError,
traits::{CompressedGroup, Group},
traits::{AppendToTranscriptTrait, CompressedGroup, Group},
}; };
use core::{ use core::{
fmt::Debug, fmt::Debug,
@ -80,10 +80,6 @@ impl CommitTrait for [G::Scalar] {
} }
} }
pub trait AppendToTranscriptTrait {
fn append_to_transcript(&self, label: &'static [u8], transcript: &mut Transcript);
}
impl<G: Group> AppendToTranscriptTrait for Commitment<G> { impl<G: Group> AppendToTranscriptTrait for Commitment<G> {
fn append_to_transcript(&self, label: &'static [u8], transcript: &mut Transcript) { fn append_to_transcript(&self, label: &'static [u8], transcript: &mut Transcript) {
transcript.append_message(label, self.comm.compress().as_bytes()); transcript.append_message(label, self.comm.compress().as_bytes());

+ 19
- 4
src/lib.rs

@ -16,13 +16,13 @@ pub mod traits;
use std::marker::PhantomData; use std::marker::PhantomData;
use commitments::{AppendToTranscriptTrait, CompressedCommitment};
use commitments::CompressedCommitment;
use errors::NovaError; use errors::NovaError;
use merlin::Transcript; use merlin::Transcript;
use r1cs::{ use r1cs::{
R1CSGens, R1CSInstance, R1CSShape, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness, R1CSGens, R1CSInstance, R1CSShape, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness,
}; };
use traits::{ChallengeTrait, Group};
use traits::{AppendToTranscriptTrait, ChallengeTrait, Group};
/// A SNARK that holds the proof of a step of an incremental computation /// A SNARK that holds the proof of a step of an incremental computation
pub struct StepSNARK<G: Group> { pub struct StepSNARK<G: Group> {
@ -59,6 +59,13 @@ impl StepSNARK {
// append the protocol name to the transcript // append the protocol name to the transcript
transcript.append_message(b"protocol-name", StepSNARK::<G>::protocol_name()); transcript.append_message(b"protocol-name", StepSNARK::<G>::protocol_name());
// append S to the transcript
S.append_to_transcript(b"S", transcript);
// append U1 and U2 to transcript
U1.append_to_transcript(b"U1", transcript);
U2.append_to_transcript(b"U2", transcript);
// compute a commitment to the cross-term // compute a commitment to the cross-term
let (T, comm_T) = S.commit_T(gens, U1, W1, U2, W2)?; let (T, comm_T) = S.commit_T(gens, U1, W1, U2, W2)?;
@ -91,6 +98,7 @@ impl StepSNARK {
/// if and only if `U1` and `U2` are satisfiable. /// if and only if `U1` and `U2` are satisfiable.
pub fn verify( pub fn verify(
&self, &self,
S: &R1CSShape<G>,
U1: &RelaxedR1CSInstance<G>, U1: &RelaxedR1CSInstance<G>,
U2: &R1CSInstance<G>, U2: &R1CSInstance<G>,
transcript: &mut Transcript, transcript: &mut Transcript,
@ -98,6 +106,13 @@ impl StepSNARK {
// append the protocol name to the transcript // append the protocol name to the transcript
transcript.append_message(b"protocol-name", StepSNARK::<G>::protocol_name()); transcript.append_message(b"protocol-name", StepSNARK::<G>::protocol_name());
// append S to the transcript
S.append_to_transcript(b"S", transcript);
// append U1 and U2 to transcript
U1.append_to_transcript(b"U1", transcript);
U2.append_to_transcript(b"U2", transcript);
// append `comm_T` to the transcript and obtain a challenge // append `comm_T` to the transcript and obtain a challenge
self.comm_T.append_to_transcript(b"comm_T", transcript); self.comm_T.append_to_transcript(b"comm_T", transcript);
@ -232,7 +247,7 @@ mod tests {
// verify the step SNARK with U1 as the first incoming instance // verify the step SNARK with U1 as the first incoming instance
let mut verifier_transcript = Transcript::new(b"StepSNARKExample"); let mut verifier_transcript = Transcript::new(b"StepSNARKExample");
let res = step_snark.verify(&r_U, U1, &mut verifier_transcript);
let res = step_snark.verify(shape, &r_U, U1, &mut verifier_transcript);
assert!(res.is_ok()); assert!(res.is_ok());
let U = res.unwrap(); let U = res.unwrap();
@ -248,7 +263,7 @@ mod tests {
let (step_snark, (_U, W)) = res.unwrap(); let (step_snark, (_U, W)) = res.unwrap();
// verify the step SNARK with U1 as the first incoming instance // verify the step SNARK with U1 as the first incoming instance
let res = step_snark.verify(&r_U, U2, &mut verifier_transcript);
let res = step_snark.verify(shape, &r_U, U2, &mut verifier_transcript);
assert!(res.is_ok()); assert!(res.is_ok());
let U = res.unwrap(); let U = res.unwrap();

+ 61
- 2
src/r1cs.rs

@ -3,11 +3,14 @@
use super::{ use super::{
commitments::{CommitGens, CommitTrait, Commitment, CompressedCommitment}, commitments::{CommitGens, CommitTrait, Commitment, CompressedCommitment},
errors::NovaError, errors::NovaError,
traits::Group,
traits::{AppendToTranscriptTrait, Group},
}; };
use ff::Field;
use ff::{Field, PrimeField};
use flate2::{write::ZlibEncoder, Compression};
use itertools::concat; use itertools::concat;
use merlin::Transcript;
use rayon::prelude::*; use rayon::prelude::*;
use serde::{Deserialize, Serialize};
/// Public parameters for a given R1CS /// Public parameters for a given R1CS
pub struct R1CSGens<G: Group> { pub struct R1CSGens<G: Group> {
@ -292,6 +295,46 @@ impl R1CSShape {
} }
} }
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
struct R1CSShapeSerialized {
num_cons: usize,
num_vars: usize,
num_io: usize,
A: Vec<(usize, usize, Vec<u8>)>,
B: Vec<(usize, usize, Vec<u8>)>,
C: Vec<(usize, usize, Vec<u8>)>,
}
impl<G: Group> AppendToTranscriptTrait for R1CSShape<G> {
fn append_to_transcript(&self, _label: &'static [u8], transcript: &mut Transcript) {
let shape_serialized = R1CSShapeSerialized {
num_cons: self.num_cons,
num_vars: self.num_vars,
num_io: self.num_io,
A: self
.A
.iter()
.map(|(i, j, v)| (*i, *j, v.to_repr().as_ref().to_vec()))
.collect(),
B: self
.B
.iter()
.map(|(i, j, v)| (*i, *j, v.to_repr().as_ref().to_vec()))
.collect(),
C: self
.C
.iter()
.map(|(i, j, v)| (*i, *j, v.to_repr().as_ref().to_vec()))
.collect(),
};
let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
bincode::serialize_into(&mut encoder, &shape_serialized).unwrap();
let shape_bytes = encoder.finish().unwrap();
transcript.append_message(b"R1CSShape", &shape_bytes);
}
}
impl<G: Group> R1CSWitness<G> { impl<G: Group> R1CSWitness<G> {
/// A method to create a witness object using a vector of scalars /// A method to create a witness object using a vector of scalars
pub fn new(S: &R1CSShape<G>, W: &[G::Scalar]) -> Result<R1CSWitness<G>, NovaError> { pub fn new(S: &R1CSShape<G>, W: &[G::Scalar]) -> Result<R1CSWitness<G>, NovaError> {
@ -326,6 +369,13 @@ impl R1CSInstance {
} }
} }
impl<G: Group> AppendToTranscriptTrait for R1CSInstance<G> {
fn append_to_transcript(&self, _label: &'static [u8], transcript: &mut Transcript) {
self.comm_W.append_to_transcript(b"comm_W", transcript);
self.X.append_to_transcript(b"X", transcript);
}
}
impl<G: Group> RelaxedR1CSWitness<G> { impl<G: Group> RelaxedR1CSWitness<G> {
/// Produces a default RelaxedR1CSWitness given an R1CSShape /// Produces a default RelaxedR1CSWitness given an R1CSShape
pub fn default(S: &R1CSShape<G>) -> RelaxedR1CSWitness<G> { pub fn default(S: &R1CSShape<G>) -> RelaxedR1CSWitness<G> {
@ -427,3 +477,12 @@ impl RelaxedR1CSInstance {
}) })
} }
} }
impl<G: Group> AppendToTranscriptTrait for RelaxedR1CSInstance<G> {
fn append_to_transcript(&self, _label: &'static [u8], transcript: &mut Transcript) {
self.comm_W.append_to_transcript(b"comm_W", transcript);
self.comm_E.append_to_transcript(b"comm_E", transcript);
self.X.append_to_transcript(b"X", transcript);
self.u.append_to_transcript(b"u", transcript);
}
}

+ 20
- 0
src/traits.rs

@ -68,6 +68,12 @@ pub trait CompressedGroup: Clone + Copy + Debug + Eq + Sized + Send + Sync + 'st
fn as_bytes(&self) -> &[u8]; fn as_bytes(&self) -> &[u8];
} }
/// A helper trait to append different types to the transcript
pub trait AppendToTranscriptTrait {
/// appends the value to the transcript under the provided label
fn append_to_transcript(&self, label: &'static [u8], transcript: &mut Transcript);
}
/// A helper trait to generate challenges using a transcript object /// A helper trait to generate challenges using a transcript object
pub trait ChallengeTrait { pub trait ChallengeTrait {
/// Returns a Scalar representing the challenge using the transcript /// Returns a Scalar representing the challenge using the transcript
@ -133,3 +139,17 @@ pub trait StepCircuit {
z: AllocatedNum<F>, z: AllocatedNum<F>,
) -> Result<AllocatedNum<F>, SynthesisError>; ) -> Result<AllocatedNum<F>, SynthesisError>;
} }
impl<F: PrimeField> AppendToTranscriptTrait for F {
fn append_to_transcript(&self, label: &'static [u8], transcript: &mut Transcript) {
transcript.append_message(label, self.to_repr().as_ref());
}
}
impl<F: PrimeField> AppendToTranscriptTrait for [F] {
fn append_to_transcript(&self, label: &'static [u8], transcript: &mut Transcript) {
for s in self {
s.append_to_transcript(label, transcript);
}
}
}

Loading…
Cancel
Save