use std::{collections::HashMap, env::current_dir, time::Instant}; use nova_scotia::{ circom::reader::load_r1cs, create_public_params, create_recursive_circuit, FileLocation, F, S, }; use nova_snark::{ provider, traits::{circuit::StepCircuit, Group}, CompressedSNARK, PublicParams, }; use pasta_curves::group::ff::Field; use serde_json::json; fn run_test(circuit_filepath: String, witness_gen_filepath: String) { type G1 = provider::bn256_grumpkin::bn256::Point; type G2 = provider::bn256_grumpkin::grumpkin::Point; println!( "Running test with witness generator: {} and group: {}", witness_gen_filepath, std::any::type_name::() ); let iteration_count = 5; let root = current_dir().unwrap(); let circuit_file = root.join(circuit_filepath); let r1cs = load_r1cs::(&FileLocation::PathBuf(circuit_file)); let witness_generator_file = root.join(witness_gen_filepath); let mut private_inputs = Vec::new(); for i in 0..iteration_count { let mut private_input = HashMap::new(); private_input.insert("adder".to_string(), json!(i)); private_inputs.push(private_input); } let start_public_input = [F::::from(10), F::::from(10)]; let pp: PublicParams = create_public_params(r1cs.clone()); println!( "Number of constraints per step (primary circuit): {}", pp.num_constraints().0 ); println!( "Number of constraints per step (secondary circuit): {}", pp.num_constraints().1 ); println!( "Number of variables per step (primary circuit): {}", pp.num_variables().0 ); println!( "Number of variables per step (secondary circuit): {}", pp.num_variables().1 ); println!("Creating a RecursiveSNARK..."); let start = Instant::now(); let recursive_snark = create_recursive_circuit( FileLocation::PathBuf(witness_generator_file), r1cs, private_inputs, start_public_input.to_vec(), &pp, ) .unwrap(); println!("RecursiveSNARK creation took {:?}", start.elapsed()); // TODO: empty? let z0_secondary = [F::::from(0)]; // verify the recursive SNARK println!("Verifying a RecursiveSNARK..."); let start = Instant::now(); let res = recursive_snark.verify(&pp, iteration_count, &start_public_input, &z0_secondary); println!( "RecursiveSNARK::verify: {:?}, took {:?}", res, start.elapsed() ); assert!(res.is_ok()); // produce a compressed SNARK println!("Generating a CompressedSNARK using Spartan with IPA-PC..."); let start = Instant::now(); let (pk, vk) = CompressedSNARK::<_, _, _, _, S, S>::setup(&pp).unwrap(); let res = CompressedSNARK::<_, _, _, _, S, S>::prove(&pp, &pk, &recursive_snark); println!( "CompressedSNARK::prove: {:?}, took {:?}", res.is_ok(), start.elapsed() ); assert!(res.is_ok()); let compressed_snark = res.unwrap(); // verify the compressed SNARK println!("Verifying a CompressedSNARK..."); let start = Instant::now(); let res = compressed_snark.verify( &vk, iteration_count, start_public_input.to_vec(), z0_secondary.to_vec(), ); println!( "CompressedSNARK::verify: {:?}, took {:?}", res.is_ok(), start.elapsed() ); assert!(res.is_ok()); } fn main() { let group_name = "bn254"; let circuit_filepath = format!("examples/toy/{}/toy.r1cs", group_name); for witness_gen_filepath in [ format!("examples/toy/{}/toy_cpp/toy", group_name), format!("examples/toy/{}/toy_js/toy.wasm", group_name), ] { run_test(circuit_filepath.clone(), witness_gen_filepath); } }