introduce high-level verifier api

This commit is contained in:
Alex Vlasov 2019-02-10 19:20:06 +03:00
parent 2327a4527b
commit f98b6eaaf4
7 changed files with 292 additions and 28 deletions

@ -28,7 +28,7 @@ use super::{
use super::multicore::Worker; use super::multicore::Worker;
pub use super::group::*; pub use super::group::*;
#[feature(not(singlecore))] #[cfg(not(feature = "singlecore"))]
use super::parallel_fft::*; use super::parallel_fft::*;
pub struct EvaluationDomain<E: Engine, G: Group<E>> { pub struct EvaluationDomain<E: Engine, G: Group<E>> {

@ -0,0 +1,102 @@
use ff::{Field};
use pairing::{Engine, CurveProjective};
use std::marker::PhantomData;
use rand::{Rand, Rng};
use super::{Proof, SxyAdvice};
use super::batch::Batch;
use super::poly::{SxEval, SyEval};
use super::parameters::{Parameters};
use super::helper::{Aggregate};
use crate::SynthesisError;
use crate::sonic::transcript::{Transcript, TranscriptProtocol};
use crate::sonic::util::*;
use crate::sonic::cs::{Backend, SynthesisDriver};
use crate::{Circuit};
use crate::sonic::sonic::AdaptorCircuit;
use crate::sonic::srs::SRS;
use crate::sonic::cs::Nonassigning;
use super::verifier::verify_aggregate_on_srs as verify_aggregate_on_srs_sonic_circuit;
use super::verifier::verify_proofs_on_srs as verify_proofs_on_srs_sonic_circuit;
pub fn verify_proofs<E: Engine, C: Circuit<E> + Clone, R: Rng>(
proofs: &[Proof<E>],
inputs: &[Vec<E::Fr>],
circuit: C,
rng: R,
params: &Parameters<E>,
) -> Result<bool, SynthesisError>
{
let adapted_circuit = AdaptorCircuit(circuit);
verify_proofs_on_srs_sonic_circuit::<_, _, Nonassigning, _>(proofs, inputs, adapted_circuit, rng, &params.srs)
}
/// Check multiple proofs with aggregation. Verifier's work is
/// not succint due to `S(X, Y)` evaluation
pub fn verify_aggregate<E: Engine, C: Circuit<E> + Clone, R: Rng>(
proofs: &[(Proof<E>, SxyAdvice<E>)],
aggregate: &Aggregate<E>,
inputs: &[Vec<E::Fr>],
circuit: C,
rng: R,
params: &Parameters<E>,
) -> Result<bool, SynthesisError> {
let adapted_circuit = AdaptorCircuit(circuit);
verify_aggregate_on_srs_sonic_circuit::<_, _, Nonassigning, _>(proofs, aggregate, inputs, adapted_circuit, rng, &params.srs)
}
// #[test]
// fn my_fun_circuit_test() {
// use ff::PrimeField;
// use pairing::bls12_381::{Bls12, Fr};
// use super::*;
// use crate::sonic::cs::{Basic, ConstraintSystem, LinearCombination};
// struct MyCircuit;
// impl<E: Engine> Circuit<E> for MyCircuit {
// fn synthesize<CS: ConstraintSystem<E>>(&self, cs: &mut CS) -> Result<(), SynthesisError> {
// let (a, b, _) = cs.multiply(|| {
// Ok((
// E::Fr::from_str("10").unwrap(),
// E::Fr::from_str("20").unwrap(),
// E::Fr::from_str("200").unwrap(),
// ))
// })?;
// cs.enforce_zero(LinearCombination::from(a) + a - b);
// //let multiplier = cs.alloc_input(|| Ok(E::Fr::from_str("20").unwrap()))?;
// //cs.enforce_zero(LinearCombination::from(b) - multiplier);
// Ok(())
// }
// }
// let srs = SRS::<Bls12>::new(
// 20,
// Fr::from_str("22222").unwrap(),
// Fr::from_str("33333333").unwrap(),
// );
// let proof = create_proof_on_srs::<Bls12, _, Basic>(&MyCircuit, &srs).unwrap();
// use std::time::{Instant};
// let start = Instant::now();
// let mut batch = MultiVerifier::<Bls12, _, Basic>::new(MyCircuit, &srs).unwrap();
// for _ in 0..1 {
// batch.add_proof(&proof, &[/*Fr::from_str("20").unwrap()*/], |_, _| None);
// }
// assert!(batch.check_all());
// let elapsed = start.elapsed();
// println!("time to verify: {:?}", elapsed);
// }

@ -482,7 +482,7 @@ pub fn generate_srs<E: Engine>(
let mut x_powers_negative = vec![Scalar::<E>(E::Fr::zero()); d]; let mut x_powers_negative = vec![Scalar::<E>(E::Fr::zero()); d];
{ {
// Compute powers of tau // Compute powers of tau
if verbose {eprintln!("computing powers of tau...")}; if verbose {eprintln!("computing powers of x...")};
let start = std::time::Instant::now(); let start = std::time::Instant::now();

@ -12,6 +12,7 @@ mod helper;
mod parameters; mod parameters;
mod generator; mod generator;
mod adapted_prover; mod adapted_prover;
mod adapted_verifier;
pub mod prover; pub mod prover;
@ -36,3 +37,8 @@ pub use self::adapted_prover::{
create_proof, create_proof,
create_proof_on_srs, create_proof_on_srs,
}; };
pub use self::adapted_verifier::{
verify_proofs,
verify_aggregate
};

@ -382,6 +382,7 @@ fn my_fun_circuit_test() {
use pairing::bls12_381::{Bls12, Fr}; use pairing::bls12_381::{Bls12, Fr};
use super::*; use super::*;
use crate::sonic::cs::{Basic, ConstraintSystem, LinearCombination}; use crate::sonic::cs::{Basic, ConstraintSystem, LinearCombination};
use rand::{thread_rng};
struct MyCircuit; struct MyCircuit;
@ -414,7 +415,8 @@ fn my_fun_circuit_test() {
use std::time::{Instant}; use std::time::{Instant};
let start = Instant::now(); let start = Instant::now();
let mut batch = MultiVerifier::<Bls12, _, Basic>::new(MyCircuit, &srs).unwrap(); let rng = thread_rng();
let mut batch = MultiVerifier::<Bls12, _, Basic, _>::new(MyCircuit, &srs, rng).unwrap();
for _ in 0..1 { for _ in 0..1 {
batch.add_proof(&proof, &[/*Fr::from_str("20").unwrap()*/], |_, _| None); batch.add_proof(&proof, &[/*Fr::from_str("20").unwrap()*/], |_, _| None);

@ -1,11 +1,13 @@
use ff::{Field}; use ff::{Field};
use pairing::{Engine, CurveProjective}; use pairing::{Engine, CurveProjective};
use std::marker::PhantomData; use std::marker::PhantomData;
use rand::{Rand, Rng};
use super::{Proof, SxyAdvice}; use super::{Proof, SxyAdvice};
use super::batch::Batch; use super::batch::Batch;
use super::poly::{SxEval, SyEval}; use super::poly::{SxEval, SyEval};
use super::helper::Aggregate; use super::helper::Aggregate;
use super::parameters::{Parameters};
use crate::SynthesisError; use crate::SynthesisError;
@ -15,17 +17,19 @@ use crate::sonic::cs::{Backend, SynthesisDriver};
use crate::sonic::cs::{Circuit, Variable, Coeff}; use crate::sonic::cs::{Circuit, Variable, Coeff};
use crate::sonic::srs::SRS; use crate::sonic::srs::SRS;
pub struct MultiVerifier<E: Engine, C: Circuit<E>, S: SynthesisDriver> { pub struct MultiVerifier<E: Engine, C: Circuit<E>, S: SynthesisDriver, R: Rng> {
circuit: C, circuit: C,
batch: Batch<E>, batch: Batch<E>,
k_map: Vec<usize>, k_map: Vec<usize>,
n: usize, n: usize,
q: usize, q: usize,
randomness_source: R,
_marker: PhantomData<(E, S)> _marker: PhantomData<(E, S)>
} }
impl<E: Engine, C: Circuit<E>, S: SynthesisDriver> MultiVerifier<E, C, S> { impl<E: Engine, C: Circuit<E>, S: SynthesisDriver, R: Rng> MultiVerifier<E, C, S, R> {
pub fn new(circuit: C, srs: &SRS<E>) -> Result<Self, SynthesisError> { // This constructor consumes randomness source cause it's later used internally
pub fn new(circuit: C, srs: &SRS<E>, rng: R) -> Result<Self, SynthesisError> {
struct Preprocess<E: Engine> { struct Preprocess<E: Engine> {
k_map: Vec<usize>, k_map: Vec<usize>,
n: usize, n: usize,
@ -57,6 +61,7 @@ impl<E: Engine, C: Circuit<E>, S: SynthesisDriver> MultiVerifier<E, C, S> {
k_map: preprocess.k_map, k_map: preprocess.k_map,
n: preprocess.n, n: preprocess.n,
q: preprocess.q, q: preprocess.q,
randomness_source: rng,
_marker: PhantomData _marker: PhantomData
}) })
} }
@ -93,10 +98,7 @@ impl<E: Engine, C: Circuit<E>, S: SynthesisDriver> MultiVerifier<E, C, S> {
}; };
{ {
// TODO: like everything else doing this, this isn't really random let random: E::Fr = self.randomness_source.gen();
let random: E::Fr;
let mut transcript = transcript.clone();
random = transcript.get_challenge_scalar();
self.batch.add_opening(aggregate.opening, random, w); self.batch.add_opening(aggregate.opening, random, w);
self.batch.add_commitment(aggregate.c, random); self.batch.add_commitment(aggregate.c, random);
@ -104,20 +106,14 @@ impl<E: Engine, C: Circuit<E>, S: SynthesisDriver> MultiVerifier<E, C, S> {
} }
for ((opening, value), &y) in aggregate.c_openings.iter().zip(y_values.iter()) { for ((opening, value), &y) in aggregate.c_openings.iter().zip(y_values.iter()) {
let random: E::Fr; let random: E::Fr = self.randomness_source.gen();
let mut transcript = transcript.clone();
random = transcript.get_challenge_scalar();
self.batch.add_opening(*opening, random, y); self.batch.add_opening(*opening, random, y);
self.batch.add_commitment(aggregate.c, random); self.batch.add_commitment(aggregate.c, random);
self.batch.add_opening_value(*value, random); self.batch.add_opening_value(*value, random);
} }
let random: E::Fr; let random: E::Fr = self.randomness_source.gen();
{
let mut transcript = transcript.clone();
random = transcript.get_challenge_scalar();
}
let mut expected_value = E::Fr::zero(); let mut expected_value = E::Fr::zero();
for ((_, advice), c_opening) in proofs.iter().zip(aggregate.c_openings.iter()) { for ((_, advice), c_opening) in proofs.iter().zip(aggregate.c_openings.iter()) {
@ -139,6 +135,7 @@ impl<E: Engine, C: Circuit<E>, S: SynthesisDriver> MultiVerifier<E, C, S> {
self.batch.add_opening(aggregate.s_opening, random, z); self.batch.add_opening(aggregate.s_opening, random, z);
} }
/// Caller must ensure to add aggregate after adding a proof
pub fn add_proof_with_advice( pub fn add_proof_with_advice(
&mut self, &mut self,
proof: &Proof<E>, proof: &Proof<E>,
@ -160,7 +157,7 @@ impl<E: Engine, C: Circuit<E>, S: SynthesisDriver> MultiVerifier<E, C, S> {
transcript.commit_point(&advice.opening); transcript.commit_point(&advice.opening);
transcript.commit_point(&advice.s); transcript.commit_point(&advice.s);
transcript.commit_scalar(&advice.szy); transcript.commit_scalar(&advice.szy);
let random: E::Fr = transcript.get_challenge_scalar(); let random: E::Fr = self.randomness_source.gen();
self.batch.add_opening(advice.opening, random, z); self.batch.add_opening(advice.opening, random, z);
self.batch.add_commitment(advice.s, random); self.batch.add_commitment(advice.s, random);
@ -196,7 +193,7 @@ impl<E: Engine, C: Circuit<E>, S: SynthesisDriver> MultiVerifier<E, C, S> {
// First, the easy one. Let's open up proof.r at zy, using proof.zy_opening // First, the easy one. Let's open up proof.r at zy, using proof.zy_opening
// as the evidence and proof.rzy as the opening. // as the evidence and proof.rzy as the opening.
{ {
let random = transcript.get_challenge_scalar(); let random: E::Fr = self.randomness_source.gen();
let mut zy = z; let mut zy = z;
zy.mul_assign(&y); zy.mul_assign(&y);
self.batch.add_opening(proof.zy_opening, random, zy); self.batch.add_opening(proof.zy_opening, random, zy);
@ -235,7 +232,7 @@ impl<E: Engine, C: Circuit<E>, S: SynthesisDriver> MultiVerifier<E, C, S> {
// We open these both at the same time by keeping their commitments // We open these both at the same time by keeping their commitments
// linearly independent (using r1). // linearly independent (using r1).
{ {
let mut random = transcript.get_challenge_scalar(); let mut random: E::Fr = self.randomness_source.gen();
self.batch.add_opening(proof.z_opening, random, z); self.batch.add_opening(proof.z_opening, random, z);
self.batch.add_opening_value(tzy, random); self.batch.add_opening_value(tzy, random);
@ -264,3 +261,73 @@ impl<E: Engine, C: Circuit<E>, S: SynthesisDriver> MultiVerifier<E, C, S> {
self.batch.check_all() self.batch.check_all()
} }
} }
/// Check multiple proofs without aggregation. Verifier's work is
/// not succint due to `S(X, Y)` evaluation
pub fn verify_proofs<E: Engine, C: Circuit<E>, S: SynthesisDriver, R: Rng>(
proofs: &[Proof<E>],
inputs: &[Vec<E::Fr>],
circuit: C,
rng: R,
params: &Parameters<E>,
) -> Result<bool, SynthesisError> {
verify_proofs_on_srs::<E, C, S, R>(proofs, inputs, circuit, rng, &params.srs)
}
/// Check multiple proofs without aggregation. Verifier's work is
/// not succint due to `S(X, Y)` evaluation
pub fn verify_proofs_on_srs<E: Engine, C: Circuit<E>, S: SynthesisDriver, R: Rng>(
proofs: &[Proof<E>],
inputs: &[Vec<E::Fr>],
circuit: C,
rng: R,
srs: &SRS<E>,
) -> Result<bool, SynthesisError> {
let mut verifier = MultiVerifier::<E, C, S, R>::new(circuit, srs, rng)?;
let expected_inputs_size = verifier.get_k_map().len() - 1;
for (proof, inputs) in proofs.iter().zip(inputs.iter()) {
if inputs.len() != expected_inputs_size {
return Err(SynthesisError::Unsatisfiable);
}
verifier.add_proof(proof, &inputs, |_, _| None);
}
Ok(verifier.check_all())
}
/// Check multiple proofs with aggregation. Verifier's work is
/// not succint due to `S(X, Y)` evaluation
pub fn verify_aggregate<E: Engine, C: Circuit<E>, S: SynthesisDriver,R: Rng>(
proofs: &[(Proof<E>, SxyAdvice<E>)],
aggregate: &Aggregate<E>,
inputs: &[Vec<E::Fr>],
circuit: C,
rng: R,
params: &Parameters<E>,
) -> Result<bool, SynthesisError> {
verify_aggregate_on_srs::<E, C, S, R>(proofs, aggregate, inputs, circuit, rng, &params.srs)
}
/// Check multiple proofs with aggregation. Verifier's work is
/// not succint due to `S(X, Y)` evaluation
pub fn verify_aggregate_on_srs<E: Engine, C: Circuit<E>, S: SynthesisDriver, R: Rng>(
proofs: &[(Proof<E>, SxyAdvice<E>)],
aggregate: &Aggregate<E>,
inputs: &[Vec<E::Fr>],
circuit: C,
rng: R,
srs: &SRS<E>,
) -> Result<bool, SynthesisError> {
let mut verifier = MultiVerifier::<E, C, S, R>::new(circuit, srs, rng)?;
let expected_inputs_size = verifier.get_k_map().len() - 1;
for ((proof, advice), inputs) in proofs.iter().zip(inputs.iter()) {
if inputs.len() != expected_inputs_size {
return Err(SynthesisError::Unsatisfiable);
}
verifier.add_proof_with_advice(proof, &inputs, &advice);
}
verifier.add_aggregate(proofs, aggregate);
Ok(verifier.check_all())
}

@ -499,7 +499,8 @@ fn test_sonic_mimc() {
println!("done in {:?}", start.elapsed()); println!("done in {:?}", start.elapsed());
{ {
let mut verifier = MultiVerifier::<Bls12, _, Basic>::new(AdaptorCircuit(circuit.clone()), &srs).unwrap(); let rng = thread_rng();
let mut verifier = MultiVerifier::<Bls12, _, Basic, _>::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap();
println!("verifying 1 proof without advice"); println!("verifying 1 proof without advice");
let start = Instant::now(); let start = Instant::now();
{ {
@ -512,7 +513,8 @@ fn test_sonic_mimc() {
} }
{ {
let mut verifier = MultiVerifier::<Bls12, _, Basic>::new(AdaptorCircuit(circuit.clone()), &srs).unwrap(); let rng = thread_rng();
let mut verifier = MultiVerifier::<Bls12, _, Basic, _>::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap();
println!("verifying {} proofs without advice", samples); println!("verifying {} proofs without advice", samples);
let start = Instant::now(); let start = Instant::now();
{ {
@ -525,7 +527,8 @@ fn test_sonic_mimc() {
} }
{ {
let mut verifier = MultiVerifier::<Bls12, _, Basic>::new(AdaptorCircuit(circuit.clone()), &srs).unwrap(); let rng = thread_rng();
let mut verifier = MultiVerifier::<Bls12, _, Basic, _>::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap();
println!("verifying 100 proofs with advice"); println!("verifying 100 proofs with advice");
let start = Instant::now(); let start = Instant::now();
{ {
@ -602,7 +605,8 @@ fn test_inputs_into_sonic_mimc() {
println!("done in {:?}", start.elapsed()); println!("done in {:?}", start.elapsed());
{ {
let mut verifier = MultiVerifier::<Bn256, _, Basic>::new(AdaptorCircuit(circuit.clone()), &srs).unwrap(); let rng = thread_rng();
let mut verifier = MultiVerifier::<Bn256, _, Basic, _>::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap();
println!("verifying 1 proof without advice"); println!("verifying 1 proof without advice");
let start = Instant::now(); let start = Instant::now();
{ {
@ -615,7 +619,8 @@ fn test_inputs_into_sonic_mimc() {
} }
{ {
let mut verifier = MultiVerifier::<Bn256, _, Basic>::new(AdaptorCircuit(circuit.clone()), &srs).unwrap(); let rng = thread_rng();
let mut verifier = MultiVerifier::<Bn256, _, Basic, _>::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap();
println!("verifying {} proofs without advice", samples); println!("verifying {} proofs without advice", samples);
let start = Instant::now(); let start = Instant::now();
{ {
@ -628,7 +633,8 @@ fn test_inputs_into_sonic_mimc() {
} }
{ {
let mut verifier = MultiVerifier::<Bn256, _, Basic>::new(AdaptorCircuit(circuit.clone()), &srs).unwrap(); let rng = thread_rng();
let mut verifier = MultiVerifier::<Bn256, _, Basic, _>::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap();
println!("verifying 100 proofs with advice and aggregate"); println!("verifying 100 proofs with advice and aggregate");
let start = Instant::now(); let start = Instant::now();
{ {
@ -642,3 +648,84 @@ fn test_inputs_into_sonic_mimc() {
} }
} }
} }
#[test]
fn test_high_level_sonic_api() {
use ff::{Field, PrimeField};
use pairing::{Engine, CurveAffine, CurveProjective};
use pairing::bn256::{Bn256, Fr};
use std::time::{Instant};
use bellman::sonic::helped::{generate_random_parameters,
verify_aggregate,
verify_proofs,
create_proof,
create_advice,
create_aggregate
};
use bellman::sonic::cs::Basic;
use bellman::sonic::sonic::AdaptorCircuit;
{
// This may not be cryptographically safe, use
// `OsRng` (for example) in production software.
let mut rng = &mut thread_rng();
// Generate the MiMC round constants
let constants = (0..MIMC_ROUNDS).map(|_| rng.gen()).collect::<Vec<_>>();
let samples: usize = 100;
let xl = rng.gen();
let xr = rng.gen();
let image = mimc::<Bn256>(xl, xr, &constants);
// Create an instance of our circuit (with the
// witness)
let circuit = MiMCDemo {
xl: Some(xl),
xr: Some(xr),
constants: &constants
};
let params = generate_random_parameters(circuit.clone(), &mut rng).unwrap();
println!("creating proof");
let start = Instant::now();
let proof = create_proof(circuit.clone(), &params).unwrap();
println!("done in {:?}", start.elapsed());
println!("creating advice");
let start = Instant::now();
let advice = create_advice(circuit.clone(), &proof, &params).unwrap();
println!("done in {:?}", start.elapsed());
println!("creating aggregate for {} proofs", samples);
let start = Instant::now();
let proofs: Vec<_> = (0..samples).map(|_| (proof.clone(), advice.clone())).collect();
let aggregate = create_aggregate::<Bn256, _, Basic>(&AdaptorCircuit(circuit.clone()), &proofs, &params.srs);
println!("done in {:?}", start.elapsed());
{
println!("verifying 1 proof without advice");
let rng = thread_rng();
let start = Instant::now();
assert_eq!(verify_proofs(&vec![proof.clone()], &vec![vec![image.clone()]], circuit.clone(), rng, &params).unwrap(), true);
println!("done in {:?}", start.elapsed());
}
{
println!("verifying {} proofs without advice", samples);
let rng = thread_rng();
let start = Instant::now();
assert_eq!(verify_proofs(&vec![proof.clone(); 100], &vec![vec![image.clone()]; 100], circuit.clone(), rng, &params).unwrap(), true);
println!("done in {:?}", start.elapsed());
}
{
println!("verifying 100 proofs with advice and aggregate");
let rng = thread_rng();
let start = Instant::now();
assert_eq!(verify_aggregate(&vec![(proof.clone(), advice.clone()); 100], &aggregate, &vec![vec![image.clone()]; 100], circuit.clone(), rng, &params).unwrap(), true);
println!("done in {:?}", start.elapsed());
}
}
}