From f98b6eaaf4c3de78ed0e19fe75cf3bd35e67c39a Mon Sep 17 00:00:00 2001 From: Alex Vlasov Date: Sun, 10 Feb 2019 19:20:06 +0300 Subject: [PATCH] introduce high-level verifier api --- src/domain.rs | 2 +- src/sonic/helped/adapted_verifier.rs | 102 ++++++++++++++++++++++++++ src/sonic/helped/generator.rs | 2 +- src/sonic/helped/mod.rs | 6 ++ src/sonic/helped/prover.rs | 4 +- src/sonic/helped/verifier.rs | 105 ++++++++++++++++++++++----- tests/mimc.rs | 99 +++++++++++++++++++++++-- 7 files changed, 292 insertions(+), 28 deletions(-) create mode 100644 src/sonic/helped/adapted_verifier.rs diff --git a/src/domain.rs b/src/domain.rs index 85c8a26..d9c87b2 100644 --- a/src/domain.rs +++ b/src/domain.rs @@ -28,7 +28,7 @@ use super::{ use super::multicore::Worker; pub use super::group::*; -#[feature(not(singlecore))] +#[cfg(not(feature = "singlecore"))] use super::parallel_fft::*; pub struct EvaluationDomain> { diff --git a/src/sonic/helped/adapted_verifier.rs b/src/sonic/helped/adapted_verifier.rs new file mode 100644 index 0000000..0c4b0c8 --- /dev/null +++ b/src/sonic/helped/adapted_verifier.rs @@ -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 + Clone, R: Rng>( + proofs: &[Proof], + inputs: &[Vec], + circuit: C, + rng: R, + params: &Parameters, +) -> Result +{ + let adapted_circuit = AdaptorCircuit(circuit); + + verify_proofs_on_srs_sonic_circuit::<_, _, Nonassigning, _>(proofs, inputs, adapted_circuit, rng, ¶ms.srs) +} + +/// Check multiple proofs with aggregation. Verifier's work is +/// not succint due to `S(X, Y)` evaluation +pub fn verify_aggregate + Clone, R: Rng>( + proofs: &[(Proof, SxyAdvice)], + aggregate: &Aggregate, + inputs: &[Vec], + circuit: C, + rng: R, + params: &Parameters, +) -> Result { + let adapted_circuit = AdaptorCircuit(circuit); + + verify_aggregate_on_srs_sonic_circuit::<_, _, Nonassigning, _>(proofs, aggregate, inputs, adapted_circuit, rng, ¶ms.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 Circuit for MyCircuit { +// fn synthesize>(&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::::new( +// 20, +// Fr::from_str("22222").unwrap(), +// Fr::from_str("33333333").unwrap(), +// ); +// let proof = create_proof_on_srs::(&MyCircuit, &srs).unwrap(); + +// use std::time::{Instant}; +// let start = Instant::now(); +// let mut batch = MultiVerifier::::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); +// } diff --git a/src/sonic/helped/generator.rs b/src/sonic/helped/generator.rs index ce7cea9..79e8b79 100644 --- a/src/sonic/helped/generator.rs +++ b/src/sonic/helped/generator.rs @@ -482,7 +482,7 @@ pub fn generate_srs( let mut x_powers_negative = vec![Scalar::(E::Fr::zero()); d]; { // Compute powers of tau - if verbose {eprintln!("computing powers of tau...")}; + if verbose {eprintln!("computing powers of x...")}; let start = std::time::Instant::now(); diff --git a/src/sonic/helped/mod.rs b/src/sonic/helped/mod.rs index 86ca823..05d2816 100644 --- a/src/sonic/helped/mod.rs +++ b/src/sonic/helped/mod.rs @@ -12,6 +12,7 @@ mod helper; mod parameters; mod generator; mod adapted_prover; +mod adapted_verifier; pub mod prover; @@ -35,4 +36,9 @@ pub use self::adapted_prover::{ create_advice_on_information_and_srs, create_proof, create_proof_on_srs, +}; + +pub use self::adapted_verifier::{ + verify_proofs, + verify_aggregate }; \ No newline at end of file diff --git a/src/sonic/helped/prover.rs b/src/sonic/helped/prover.rs index 613aa3a..ff78c2d 100644 --- a/src/sonic/helped/prover.rs +++ b/src/sonic/helped/prover.rs @@ -382,6 +382,7 @@ fn my_fun_circuit_test() { use pairing::bls12_381::{Bls12, Fr}; use super::*; use crate::sonic::cs::{Basic, ConstraintSystem, LinearCombination}; + use rand::{thread_rng}; struct MyCircuit; @@ -414,7 +415,8 @@ fn my_fun_circuit_test() { use std::time::{Instant}; let start = Instant::now(); - let mut batch = MultiVerifier::::new(MyCircuit, &srs).unwrap(); + let rng = thread_rng(); + let mut batch = MultiVerifier::::new(MyCircuit, &srs, rng).unwrap(); for _ in 0..1 { batch.add_proof(&proof, &[/*Fr::from_str("20").unwrap()*/], |_, _| None); diff --git a/src/sonic/helped/verifier.rs b/src/sonic/helped/verifier.rs index f6fada4..768500d 100644 --- a/src/sonic/helped/verifier.rs +++ b/src/sonic/helped/verifier.rs @@ -1,11 +1,13 @@ 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::helper::Aggregate; +use super::parameters::{Parameters}; use crate::SynthesisError; @@ -15,17 +17,19 @@ use crate::sonic::cs::{Backend, SynthesisDriver}; use crate::sonic::cs::{Circuit, Variable, Coeff}; use crate::sonic::srs::SRS; -pub struct MultiVerifier, S: SynthesisDriver> { +pub struct MultiVerifier, S: SynthesisDriver, R: Rng> { circuit: C, batch: Batch, k_map: Vec, n: usize, q: usize, + randomness_source: R, _marker: PhantomData<(E, S)> } -impl, S: SynthesisDriver> MultiVerifier { - pub fn new(circuit: C, srs: &SRS) -> Result { +impl, S: SynthesisDriver, R: Rng> MultiVerifier { + // This constructor consumes randomness source cause it's later used internally + pub fn new(circuit: C, srs: &SRS, rng: R) -> Result { struct Preprocess { k_map: Vec, n: usize, @@ -57,6 +61,7 @@ impl, S: SynthesisDriver> MultiVerifier { k_map: preprocess.k_map, n: preprocess.n, q: preprocess.q, + randomness_source: rng, _marker: PhantomData }) } @@ -93,10 +98,7 @@ impl, S: SynthesisDriver> MultiVerifier { }; { - // TODO: like everything else doing this, this isn't really random - let random: E::Fr; - let mut transcript = transcript.clone(); - random = transcript.get_challenge_scalar(); + let random: E::Fr = self.randomness_source.gen(); self.batch.add_opening(aggregate.opening, random, w); self.batch.add_commitment(aggregate.c, random); @@ -104,20 +106,14 @@ impl, S: SynthesisDriver> MultiVerifier { } for ((opening, value), &y) in aggregate.c_openings.iter().zip(y_values.iter()) { - let random: E::Fr; - let mut transcript = transcript.clone(); - random = transcript.get_challenge_scalar(); + let random: E::Fr = self.randomness_source.gen(); self.batch.add_opening(*opening, random, y); self.batch.add_commitment(aggregate.c, random); self.batch.add_opening_value(*value, random); } - let random: E::Fr; - { - let mut transcript = transcript.clone(); - random = transcript.get_challenge_scalar(); - } + let random: E::Fr = self.randomness_source.gen(); let mut expected_value = E::Fr::zero(); for ((_, advice), c_opening) in proofs.iter().zip(aggregate.c_openings.iter()) { @@ -139,6 +135,7 @@ impl, S: SynthesisDriver> MultiVerifier { 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( &mut self, proof: &Proof, @@ -160,7 +157,7 @@ impl, S: SynthesisDriver> MultiVerifier { transcript.commit_point(&advice.opening); transcript.commit_point(&advice.s); 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_commitment(advice.s, random); @@ -196,7 +193,7 @@ impl, S: SynthesisDriver> MultiVerifier { // 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. { - let random = transcript.get_challenge_scalar(); + let random: E::Fr = self.randomness_source.gen(); let mut zy = z; zy.mul_assign(&y); self.batch.add_opening(proof.zy_opening, random, zy); @@ -235,7 +232,7 @@ impl, S: SynthesisDriver> MultiVerifier { // We open these both at the same time by keeping their commitments // 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_value(tzy, random); @@ -263,4 +260,74 @@ impl, S: SynthesisDriver> MultiVerifier { pub fn check_all(self) -> bool { self.batch.check_all() } -} \ No newline at end of file +} + +/// Check multiple proofs without aggregation. Verifier's work is +/// not succint due to `S(X, Y)` evaluation +pub fn verify_proofs, S: SynthesisDriver, R: Rng>( + proofs: &[Proof], + inputs: &[Vec], + circuit: C, + rng: R, + params: &Parameters, +) -> Result { + verify_proofs_on_srs::(proofs, inputs, circuit, rng, ¶ms.srs) +} + +/// Check multiple proofs without aggregation. Verifier's work is +/// not succint due to `S(X, Y)` evaluation +pub fn verify_proofs_on_srs, S: SynthesisDriver, R: Rng>( + proofs: &[Proof], + inputs: &[Vec], + circuit: C, + rng: R, + srs: &SRS, +) -> Result { + let mut verifier = MultiVerifier::::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, S: SynthesisDriver,R: Rng>( + proofs: &[(Proof, SxyAdvice)], + aggregate: &Aggregate, + inputs: &[Vec], + circuit: C, + rng: R, + params: &Parameters, +) -> Result { + verify_aggregate_on_srs::(proofs, aggregate, inputs, circuit, rng, ¶ms.srs) +} + +/// Check multiple proofs with aggregation. Verifier's work is +/// not succint due to `S(X, Y)` evaluation +pub fn verify_aggregate_on_srs, S: SynthesisDriver, R: Rng>( + proofs: &[(Proof, SxyAdvice)], + aggregate: &Aggregate, + inputs: &[Vec], + circuit: C, + rng: R, + srs: &SRS, +) -> Result { + let mut verifier = MultiVerifier::::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()) +} + diff --git a/tests/mimc.rs b/tests/mimc.rs index 7a37a7f..fbaf382 100644 --- a/tests/mimc.rs +++ b/tests/mimc.rs @@ -499,7 +499,8 @@ fn test_sonic_mimc() { println!("done in {:?}", start.elapsed()); { - let mut verifier = MultiVerifier::::new(AdaptorCircuit(circuit.clone()), &srs).unwrap(); + let rng = thread_rng(); + let mut verifier = MultiVerifier::::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap(); println!("verifying 1 proof without advice"); let start = Instant::now(); { @@ -512,7 +513,8 @@ fn test_sonic_mimc() { } { - let mut verifier = MultiVerifier::::new(AdaptorCircuit(circuit.clone()), &srs).unwrap(); + let rng = thread_rng(); + let mut verifier = MultiVerifier::::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap(); println!("verifying {} proofs without advice", samples); let start = Instant::now(); { @@ -525,7 +527,8 @@ fn test_sonic_mimc() { } { - let mut verifier = MultiVerifier::::new(AdaptorCircuit(circuit.clone()), &srs).unwrap(); + let rng = thread_rng(); + let mut verifier = MultiVerifier::::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap(); println!("verifying 100 proofs with advice"); let start = Instant::now(); { @@ -602,7 +605,8 @@ fn test_inputs_into_sonic_mimc() { println!("done in {:?}", start.elapsed()); { - let mut verifier = MultiVerifier::::new(AdaptorCircuit(circuit.clone()), &srs).unwrap(); + let rng = thread_rng(); + let mut verifier = MultiVerifier::::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap(); println!("verifying 1 proof without advice"); let start = Instant::now(); { @@ -615,7 +619,8 @@ fn test_inputs_into_sonic_mimc() { } { - let mut verifier = MultiVerifier::::new(AdaptorCircuit(circuit.clone()), &srs).unwrap(); + let rng = thread_rng(); + let mut verifier = MultiVerifier::::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap(); println!("verifying {} proofs without advice", samples); let start = Instant::now(); { @@ -628,7 +633,8 @@ fn test_inputs_into_sonic_mimc() { } { - let mut verifier = MultiVerifier::::new(AdaptorCircuit(circuit.clone()), &srs).unwrap(); + let rng = thread_rng(); + let mut verifier = MultiVerifier::::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap(); println!("verifying 100 proofs with advice and aggregate"); let start = Instant::now(); { @@ -641,4 +647,85 @@ fn test_inputs_into_sonic_mimc() { println!("done in {:?}", start.elapsed()); } } +} + +#[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::>(); + let samples: usize = 100; + + let xl = rng.gen(); + let xr = rng.gen(); + let image = mimc::(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(), ¶ms).unwrap(); + println!("done in {:?}", start.elapsed()); + + println!("creating advice"); + let start = Instant::now(); + let advice = create_advice(circuit.clone(), &proof, ¶ms).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::(&AdaptorCircuit(circuit.clone()), &proofs, ¶ms.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, ¶ms).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, ¶ms).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, ¶ms).unwrap(), true); + println!("done in {:?}", start.elapsed()); + } + } } \ No newline at end of file