Browse Source

introduce APIs for NIZK and SNARK proof systems (#11)

master
Srinath Setty 4 years ago
parent
commit
456970e710
6 changed files with 265 additions and 50 deletions
  1. +0
    -1
      benches/commitments.rs
  2. +0
    -1
      benches/dotproduct.rs
  3. +88
    -20
      benches/spartan.rs
  4. +51
    -10
      src/profiler.rs
  5. +4
    -0
      src/r1csinstance.rs
  6. +122
    -18
      src/spartan.rs

+ 0
- 1
benches/commitments.rs

@ -1,7 +1,6 @@
extern crate byteorder;
extern crate core;
extern crate criterion;
extern crate curve25519_dalek;
extern crate digest;
extern crate libspartan;
extern crate merlin;

+ 0
- 1
benches/dotproduct.rs

@ -1,7 +1,6 @@
extern crate byteorder;
extern crate core;
extern crate criterion;
extern crate curve25519_dalek;
extern crate digest;
extern crate libspartan;
extern crate merlin;

+ 88
- 20
benches/spartan.rs

@ -10,15 +10,15 @@ extern crate sha3;
use libspartan::math::Math;
use libspartan::r1csinstance::{R1CSCommitmentGens, R1CSInstance};
use libspartan::r1csproof::R1CSGens;
use libspartan::spartan::{SpartanGens, SpartanProof};
use libspartan::spartan::{NIZKGens, SNARKGens, NIZK, SNARK};
use merlin::Transcript;
use criterion::*;
fn encode_benchmark(c: &mut Criterion) {
fn snark_encode_benchmark(c: &mut Criterion) {
for &s in [10, 12, 16].iter() {
let plot_config = PlotConfiguration::default().summary_scale(AxisScale::Logarithmic);
let mut group = c.benchmark_group("spartan_encode_benchmark");
let mut group = c.benchmark_group("SNARK_encode_benchmark");
group.plot_config(plot_config);
let num_vars = s.pow2();
@ -27,25 +27,23 @@ fn encode_benchmark(c: &mut Criterion) {
let (inst, _vars, _input) =
R1CSInstance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs);
let n = inst.get_num_vars();
let m = n.square_root();
assert_eq!(n, m * m);
let r1cs_size = inst.size();
let gens_r1cs = R1CSCommitmentGens::new(&r1cs_size, b"gens_r1cs");
let name = format!("spartan_encode_{}", n);
let name = format!("SNARK_encode_{}", n);
group.bench_function(&name, move |b| {
b.iter(|| {
SpartanProof::encode(black_box(&inst), black_box(&gens_r1cs));
SNARK::encode(black_box(&inst), black_box(&gens_r1cs));
});
});
group.finish();
}
}
fn prove_benchmark(c: &mut Criterion) {
fn snark_prove_benchmark(c: &mut Criterion) {
for &s in [10, 12, 16].iter() {
let plot_config = PlotConfiguration::default().summary_scale(AxisScale::Logarithmic);
let mut group = c.benchmark_group("spartan_prove_benchmark");
let mut group = c.benchmark_group("SNARK_prove_benchmark");
group.plot_config(plot_config);
let num_vars = s.pow2();
@ -60,14 +58,14 @@ fn prove_benchmark(c: &mut Criterion) {
let gens_r1cs_sat = R1CSGens::new(num_cons, num_vars, b"gens_r1cs_sat");
// produce a proof of satisfiability
let (_comm, decomm) = SpartanProof::encode(&inst, &gens_r1cs_eval);
let gens = SpartanGens::new(gens_r1cs_sat, gens_r1cs_eval);
let (_comm, decomm) = SNARK::encode(&inst, &gens_r1cs_eval);
let gens = SNARKGens::new(gens_r1cs_sat, gens_r1cs_eval);
let name = format!("spartan_prove_{}", n);
let name = format!("SNARK_prove_{}", n);
group.bench_function(&name, move |b| {
b.iter(|| {
let mut prover_transcript = Transcript::new(b"example");
SpartanProof::prove(
SNARK::prove(
black_box(&inst),
black_box(&decomm),
black_box(vars.clone()),
@ -81,10 +79,10 @@ fn prove_benchmark(c: &mut Criterion) {
}
}
fn verify_benchmark(c: &mut Criterion) {
fn snark_verify_benchmark(c: &mut Criterion) {
for &s in [10, 12, 16].iter() {
let plot_config = PlotConfiguration::default().summary_scale(AxisScale::Logarithmic);
let mut group = c.benchmark_group("spartan_verify_benchmark");
let mut group = c.benchmark_group("SNARK_verify_benchmark");
group.plot_config(plot_config);
let num_vars = s.pow2();
@ -97,16 +95,16 @@ fn verify_benchmark(c: &mut Criterion) {
let gens_r1cs_eval = R1CSCommitmentGens::new(&r1cs_size, b"gens_r1cs_eval");
// create a commitment to R1CSInstance
let (comm, decomm) = SpartanProof::encode(&inst, &gens_r1cs_eval);
let (comm, decomm) = SNARK::encode(&inst, &gens_r1cs_eval);
let gens_r1cs_sat = R1CSGens::new(num_cons, num_vars, b"gens_r1cs_sat");
let gens = SpartanGens::new(gens_r1cs_sat, gens_r1cs_eval);
let gens = SNARKGens::new(gens_r1cs_sat, gens_r1cs_eval);
// produce a proof of satisfiability
let mut prover_transcript = Transcript::new(b"example");
let proof = SpartanProof::prove(&inst, &decomm, vars, &input, &gens, &mut prover_transcript);
let proof = SNARK::prove(&inst, &decomm, vars, &input, &gens, &mut prover_transcript);
let name = format!("spartan_verify_{}", n);
let name = format!("SNARK_verify_{}", n);
group.bench_function(&name, move |b| {
b.iter(|| {
let mut verifier_transcript = Transcript::new(b"example");
@ -124,6 +122,76 @@ fn verify_benchmark(c: &mut Criterion) {
}
}
fn nizk_prove_benchmark(c: &mut Criterion) {
for &s in [10, 12, 16].iter() {
let plot_config = PlotConfiguration::default().summary_scale(AxisScale::Logarithmic);
let mut group = c.benchmark_group("NIZK_prove_benchmark");
group.plot_config(plot_config);
let num_vars = s.pow2();
let num_cons = num_vars;
let num_inputs = 10;
let (inst, vars, input) = R1CSInstance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs);
let n = inst.get_num_vars();
let gens_r1cs_sat = R1CSGens::new(num_cons, num_vars, b"gens_r1cs_sat");
let gens = NIZKGens::new(gens_r1cs_sat);
let name = format!("NIZK_prove_{}", n);
group.bench_function(&name, move |b| {
b.iter(|| {
let mut prover_transcript = Transcript::new(b"example");
NIZK::prove(
black_box(&inst),
black_box(vars.clone()),
black_box(&input),
black_box(&gens),
black_box(&mut prover_transcript),
);
});
});
group.finish();
}
}
fn nizk_verify_benchmark(c: &mut Criterion) {
for &s in [10, 12, 16].iter() {
let plot_config = PlotConfiguration::default().summary_scale(AxisScale::Logarithmic);
let mut group = c.benchmark_group("NIZK_verify_benchmark");
group.plot_config(plot_config);
let num_vars = s.pow2();
let num_cons = num_vars;
let num_inputs = 10;
let (inst, vars, input) = R1CSInstance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs);
let n = inst.get_num_vars();
let gens_r1cs_sat = R1CSGens::new(num_cons, num_vars, b"gens_r1cs_sat");
let gens = NIZKGens::new(gens_r1cs_sat);
// produce a proof of satisfiability
let mut prover_transcript = Transcript::new(b"example");
let proof = NIZK::prove(&inst, vars, &input, &gens, &mut prover_transcript);
let name = format!("NIZK_verify_{}", n);
group.bench_function(&name, move |b| {
b.iter(|| {
let mut verifier_transcript = Transcript::new(b"example");
assert!(proof
.verify(
black_box(&inst),
black_box(&input),
black_box(&mut verifier_transcript),
black_box(&gens)
)
.is_ok());
});
});
group.finish();
}
}
fn set_duration() -> Criterion {
Criterion::default().sample_size(10)
// .measurement_time(Duration::new(0, 50000000))
@ -132,7 +200,7 @@ fn set_duration() -> Criterion {
criterion_group! {
name = benches_spartan;
config = set_duration();
targets = encode_benchmark, prove_benchmark, verify_benchmark
targets = snark_encode_benchmark, snark_prove_benchmark, snark_verify_benchmark
}
criterion_main!(benches_spartan);

+ 51
- 10
src/profiler.rs

@ -8,42 +8,48 @@ use flate2::{write::ZlibEncoder, Compression};
use libspartan::math::Math;
use libspartan::r1csinstance::{R1CSCommitmentGens, R1CSInstance};
use libspartan::r1csproof::R1CSGens;
use libspartan::spartan::{SpartanGens, SpartanProof};
use libspartan::spartan::{NIZKGens, SNARKGens, NIZK, SNARK};
use libspartan::timer::Timer;
use merlin::Transcript;
pub fn main() {
for &s in [12, 16, 20].iter() {
// the list of number of variables (and constraints) in an R1CS instance
let inst_sizes = vec![12, 16, 20];
println!("Profiler:: SNARK");
for &s in inst_sizes.iter() {
let num_vars = (s as usize).pow2();
let num_cons = num_vars;
let num_inputs = 10;
let (inst, vars, input) = R1CSInstance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs);
Timer::print(&format!("number_of_constraints {}", num_cons));
let r1cs_size = inst.size();
let gens_r1cs_eval = R1CSCommitmentGens::new(&r1cs_size, b"gens_r1cs_eval");
Timer::print(&format!("number_of_constraints {}", num_cons));
// create a commitment to R1CSInstance
let timer_encode = Timer::new("SpartanProof::encode");
let (comm, decomm) = SpartanProof::encode(&inst, &gens_r1cs_eval);
let timer_encode = Timer::new("SNARK::encode");
let (comm, decomm) = SNARK::encode(&inst, &gens_r1cs_eval);
timer_encode.stop();
let gens_r1cs_sat = R1CSGens::new(num_cons, num_vars, b"gens_r1cs_sat");
let gens = SpartanGens::new(gens_r1cs_sat, gens_r1cs_eval);
let gens = SNARKGens::new(gens_r1cs_sat, gens_r1cs_eval);
// produce a proof of satisfiability
let timer_prove = Timer::new("SpartanProof::prove");
let timer_prove = Timer::new("SNARK::prove");
let mut prover_transcript = Transcript::new(b"example");
let proof = SpartanProof::prove(&inst, &decomm, vars, &input, &gens, &mut prover_transcript);
let proof = SNARK::prove(&inst, &decomm, vars, &input, &gens, &mut prover_transcript);
timer_prove.stop();
let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
bincode::serialize_into(&mut encoder, &proof).unwrap();
let proof_encoded = encoder.finish().unwrap();
let msg_proof_len = format!("proof_compressed_len {:?}", proof_encoded.len());
let msg_proof_len = format!("SNARK::proof_compressed_len {:?}", proof_encoded.len());
Timer::print(&msg_proof_len);
let timer_verify = Timer::new("SpartanProof::verify");
// verify the proof of satisfiability
let timer_verify = Timer::new("SNARK::verify");
let mut verifier_transcript = Transcript::new(b"example");
assert!(proof
.verify(&comm, &input, &mut verifier_transcript, &gens)
@ -52,4 +58,39 @@ pub fn main() {
println!();
}
println!("Profiler:: NIZK");
for &s in inst_sizes.iter() {
let num_vars = (s as usize).pow2();
let num_cons = num_vars;
let num_inputs = 10;
let (inst, vars, input) = R1CSInstance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs);
Timer::print(&format!("number_of_constraints {}", num_cons));
let gens_r1cs_sat = R1CSGens::new(num_cons, num_vars, b"gens_r1cs_sat");
let gens = NIZKGens::new(gens_r1cs_sat);
// produce a proof of satisfiability
let timer_prove = Timer::new("NIZK::prove");
let mut prover_transcript = Transcript::new(b"example");
let proof = NIZK::prove(&inst, vars, &input, &gens, &mut prover_transcript);
timer_prove.stop();
let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
bincode::serialize_into(&mut encoder, &proof).unwrap();
let proof_encoded = encoder.finish().unwrap();
let msg_proof_len = format!("NIZK::proof_compressed_len {:?}", proof_encoded.len());
Timer::print(&msg_proof_len);
// verify the proof of satisfiability
let timer_verify = Timer::new("NIZK::verify");
let mut verifier_transcript = Transcript::new(b"example");
assert!(proof
.verify(&inst, &input, &mut verifier_transcript, &gens)
.is_ok());
timer_verify.stop();
println!();
}
}

+ 4
- 0
src/r1csinstance.rs

@ -117,6 +117,10 @@ impl R1CSInstance {
self.num_cons
}
pub fn get_num_inputs(&self) -> usize {
self.num_inputs
}
pub fn size(&self) -> R1CSInstanceSize {
R1CSInstanceSize {
size_A: self.A.size(),

+ 122
- 18
src/spartan.rs

@ -12,14 +12,14 @@ use merlin::Transcript;
use rand::rngs::OsRng;
use serde::{Deserialize, Serialize};
pub struct SpartanGens {
pub struct SNARKGens {
gens_r1cs_sat: R1CSGens,
gens_r1cs_eval: R1CSCommitmentGens,
}
impl SpartanGens {
pub fn new(gens_r1cs_sat: R1CSGens, gens_r1cs_eval: R1CSCommitmentGens) -> SpartanGens {
SpartanGens {
impl SNARKGens {
pub fn new(gens_r1cs_sat: R1CSGens, gens_r1cs_eval: R1CSCommitmentGens) -> Self {
SNARKGens {
gens_r1cs_sat,
gens_r1cs_eval,
}
@ -27,15 +27,15 @@ impl SpartanGens {
}
#[derive(Serialize, Deserialize, Debug)]
pub struct SpartanProof {
pub struct SNARK {
r1cs_sat_proof: R1CSProof,
inst_evals: R1CSInstanceEvals,
r1cs_eval_proof: R1CSEvalProof,
}
impl SpartanProof {
impl SNARK {
fn protocol_name() -> &'static [u8] {
b"Spartan proof"
b"Spartan SNARK proof"
}
/// A public computation to create a commitment to an R1CS instance
@ -52,19 +52,19 @@ impl SpartanProof {
decomm: &R1CSDecommitment,
vars: Vec<Scalar>,
input: &Vec<Scalar>,
gens: &SpartanGens,
gens: &SNARKGens,
transcript: &mut Transcript,
) -> SpartanProof {
) -> Self {
// we create a Transcript object seeded with a random Scalar
// to aid the prover produce its randomness
let mut random_tape = {
let mut csprng: OsRng = OsRng;
let mut tape = Transcript::new(b"SpartanProof");
let mut tape = Transcript::new(b"SpartanSNARKProof");
tape.append_scalar(b"init_randomness", &Scalar::random(&mut csprng));
tape
};
transcript.append_protocol_name(SpartanProof::protocol_name());
transcript.append_protocol_name(SNARK::protocol_name());
let (r1cs_sat_proof, rx, ry) = {
let (proof, rx, ry) = R1CSProof::prove(
inst,
@ -107,7 +107,7 @@ impl SpartanProof {
proof
};
SpartanProof {
SNARK {
r1cs_sat_proof,
inst_evals,
r1cs_eval_proof,
@ -120,9 +120,9 @@ impl SpartanProof {
comm: &R1CSCommitment,
input: &Vec<Scalar>,
transcript: &mut Transcript,
gens: &SpartanGens,
gens: &SNARKGens,
) -> Result<(), ProofVerifyError> {
transcript.append_protocol_name(SpartanProof::protocol_name());
transcript.append_protocol_name(SNARK::protocol_name());
let timer_sat_proof = Timer::new("verify_sat_proof");
assert_eq!(input.len(), comm.get_num_inputs());
@ -159,12 +159,116 @@ impl SpartanProof {
}
}
pub struct NIZKGens {
gens_r1cs_sat: R1CSGens,
}
impl NIZKGens {
pub fn new(gens_r1cs_sat: R1CSGens) -> Self {
NIZKGens { gens_r1cs_sat }
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct NIZK {
r1cs_sat_proof: R1CSProof,
r: (Vec<Scalar>, Vec<Scalar>),
}
impl NIZK {
fn protocol_name() -> &'static [u8] {
b"Spartan NIZK proof"
}
/// A method to produce a proof of the satisfiability of an R1CS instance
pub fn prove(
inst: &R1CSInstance,
vars: Vec<Scalar>,
input: &Vec<Scalar>,
gens: &NIZKGens,
transcript: &mut Transcript,
) -> Self {
// we create a Transcript object seeded with a random Scalar
// to aid the prover produce its randomness
let mut random_tape = {
let mut csprng: OsRng = OsRng;
let mut tape = Transcript::new(b"SpartanNIZKProof");
tape.append_scalar(b"init_randomness", &Scalar::random(&mut csprng));
tape
};
transcript.append_protocol_name(NIZK::protocol_name());
let (r1cs_sat_proof, rx, ry) = {
let (proof, rx, ry) = R1CSProof::prove(
inst,
vars,
input,
&gens.gens_r1cs_sat,
transcript,
&mut random_tape,
);
let proof_encoded: Vec<u8> = bincode::serialize(&proof).unwrap();
Timer::print(&format!("len_r1cs_sat_proof {:?}", proof_encoded.len()));
(proof, rx, ry)
};
NIZK {
r1cs_sat_proof,
r: (rx, ry),
}
}
/// A method to verify the proof of the satisfiability of an R1CS instance
pub fn verify(
&self,
inst: &R1CSInstance,
input: &Vec<Scalar>,
transcript: &mut Transcript,
gens: &NIZKGens,
) -> Result<(), ProofVerifyError> {
transcript.append_protocol_name(NIZK::protocol_name());
// We send evaluations of A, B, C at r = (rx, ry) as claims
// to enable the verifier complete the first sum-check
let timer_eval = Timer::new("eval_sparse_polys");
let (claimed_rx, claimed_ry) = &self.r;
let inst_evals = {
let eval_table_rx = EqPolynomial::new(claimed_rx.clone()).evals();
let eval_table_ry = EqPolynomial::new(claimed_ry.clone()).evals();
inst.evaluate_with_tables(&eval_table_rx, &eval_table_ry)
};
timer_eval.stop();
let timer_sat_proof = Timer::new("verify_sat_proof");
assert_eq!(input.len(), inst.get_num_inputs());
let (rx, ry) = self
.r1cs_sat_proof
.verify(
inst.get_num_vars(),
inst.get_num_cons(),
input,
&inst_evals,
transcript,
&gens.gens_r1cs_sat,
)
.unwrap();
// verify if claimed rx and ry are correct
assert_eq!(rx, *claimed_rx);
assert_eq!(ry, *claimed_ry);
timer_sat_proof.stop();
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
pub fn check_spartan_proof() {
pub fn check_snark() {
let num_vars = 256;
let num_cons = num_vars;
let num_inputs = 10;
@ -174,13 +278,13 @@ mod tests {
let gens_r1cs_eval = R1CSCommitmentGens::new(&r1cs_size, b"gens_r1cs_eval");
// create a commitment to R1CSInstance
let (comm, decomm) = SpartanProof::encode(&inst, &gens_r1cs_eval);
let (comm, decomm) = SNARK::encode(&inst, &gens_r1cs_eval);
let gens_r1cs_sat = R1CSGens::new(num_cons, num_vars, b"gens_r1cs_sat");
let gens = SpartanGens::new(gens_r1cs_sat, gens_r1cs_eval);
let gens = SNARKGens::new(gens_r1cs_sat, gens_r1cs_eval);
let mut prover_transcript = Transcript::new(b"example");
let proof = SpartanProof::prove(&inst, &decomm, vars, &input, &gens, &mut prover_transcript);
let proof = SNARK::prove(&inst, &decomm, vars, &input, &gens, &mut prover_transcript);
let mut verifier_transcript = Transcript::new(b"example");
assert!(proof

Loading…
Cancel
Save