// For randomness (during paramgen and proof generation) use rand::thread_rng; // For benchmarking use std::time::{Duration, Instant}; // Bring in some tools for using finite fiels use ff::Field; // We're going to use the BLS12-381 pairing-friendly elliptic curve. use bls12_381::{Bls12, Scalar}; // We're going to use the Groth16 proving system. use groth16::{ batch, create_random_proof, generate_random_parameters, prepare_verifying_key, verify_proof, Proof, }; mod common; use common::*; #[test] fn test_mimc() { // This may not be cryptographically safe, use // `OsRng` (for example) in production software. let mut rng = thread_rng(); // Generate the MiMC round constants let constants = (0..MIMC_ROUNDS) .map(|_| Scalar::random(&mut rng)) .collect::>(); println!("Creating parameters..."); // Create parameters for our circuit let params = { let c = MiMCDemo { xl: None, xr: None, constants: &constants, }; generate_random_parameters::(c, &mut rng).unwrap() }; // Prepare the verification key (for proof verification) let pvk = prepare_verifying_key(¶ms.vk); println!("Creating proofs..."); // Let's benchmark stuff! const SAMPLES: u32 = 50; let mut total_proving = Duration::new(0, 0); let mut total_verifying = Duration::new(0, 0); // Just a place to put the proof data, so we can // benchmark deserialization. let mut proof_vec = vec![]; for _ in 0..SAMPLES { // Generate a random preimage and compute the image let xl = Scalar::random(&mut rng); let xr = Scalar::random(&mut rng); let image = mimc(xl, xr, &constants); proof_vec.truncate(0); let start = Instant::now(); { // Create an instance of our circuit (with the // witness) let c = MiMCDemo { xl: Some(xl), xr: Some(xr), constants: &constants, }; // Create a groth16 proof with our parameters. let proof = create_random_proof(c, ¶ms, &mut rng).unwrap(); proof.write(&mut proof_vec).unwrap(); } total_proving += start.elapsed(); let start = Instant::now(); let proof = Proof::read(&proof_vec[..]).unwrap(); // Check the proof assert!(verify_proof(&pvk, &proof, &[image]).is_ok()); total_verifying += start.elapsed(); } let proving_avg = total_proving / SAMPLES; let proving_avg = proving_avg.subsec_nanos() as f64 / 1_000_000_000f64 + (proving_avg.as_secs() as f64); let verifying_avg = total_verifying / SAMPLES; let verifying_avg = verifying_avg.subsec_nanos() as f64 / 1_000_000_000f64 + (verifying_avg.as_secs() as f64); println!("Average proving time: {:?} seconds", proving_avg); println!("Average verifying time: {:?} seconds", verifying_avg); } #[test] fn batch_verify() { let mut rng = thread_rng(); let mut batch = batch::Verifier::new(); // Generate the MiMC round constants let constants = (0..MIMC_ROUNDS) .map(|_| Scalar::random(&mut rng)) .collect::>(); println!("Creating parameters..."); // Create parameters for our circuit let params = { let c = MiMCDemo { xl: None, xr: None, constants: &constants, }; generate_random_parameters::(c, &mut rng).unwrap() }; // Prepare the verification key (for proof verification) let pvk = prepare_verifying_key(¶ms.vk); println!("Creating proofs..."); // Let's benchmark stuff! const SAMPLES: u32 = 50; let mut total_proving = Duration::new(0, 0); let mut total_verifying = Duration::new(0, 0); // Just a place to put the proof data, so we can // benchmark deserialization. let mut proof_vec = vec![]; for _ in 0..SAMPLES { // Generate a random preimage and compute the image let xl = Scalar::random(&mut rng); let xr = Scalar::random(&mut rng); let image = mimc(xl, xr, &constants); proof_vec.truncate(0); let start = Instant::now(); { // Create an instance of our circuit (with the // witness) let c = MiMCDemo { xl: Some(xl), xr: Some(xr), constants: &constants, }; // Create a groth16 proof with our parameters. let proof = create_random_proof(c, ¶ms, &mut rng).unwrap(); proof.write(&mut proof_vec).unwrap(); } total_proving += start.elapsed(); let start = Instant::now(); let proof = Proof::read(&proof_vec[..]).unwrap(); // Check the proof assert!(verify_proof(&pvk, &proof, &[image]).is_ok()); total_verifying += start.elapsed(); // Queue the proof and inputs for batch verification. batch.queue((proof, [image].into())); } let mut batch_verifying = Duration::new(0, 0); let batch_start = Instant::now(); // Verify this batch for this specific verifying key assert!(batch.verify(rng, ¶ms.vk).is_ok()); batch_verifying += batch_start.elapsed(); let proving_avg = total_proving / SAMPLES; let proving_avg = proving_avg.subsec_nanos() as f64 / 1_000_000_000f64 + (proving_avg.as_secs() as f64); let verifying_avg = total_verifying / SAMPLES; let verifying_avg = verifying_avg.subsec_nanos() as f64 / 1_000_000_000f64 + (verifying_avg.as_secs() as f64); let batch_amortized = batch_verifying / SAMPLES; let batch_amortized = batch_amortized.subsec_nanos() as f64 / 1_000_000_000f64 + (batch_amortized.as_secs() as f64); println!("Average proving time: {:?} seconds", proving_avg); println!("Average verifying time: {:?} seconds", verifying_avg); println!( "Amortized batch verifying time: {:?} seconds", batch_amortized ); }