From e981c7ca0ab23073339869a7d45c04ae10fe1adf Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Tue, 14 Feb 2023 13:05:57 +0000 Subject: [PATCH] feat(nargo): add flag to verify created proofs (#737) * feat(nargo): add flag to verify created proofs * chore: rename variable * chore(nargo): cleanup imports * chore: rename `checked` arg to `verify` * chore: make verify arg named rather than positional * chore: remove scope around `prover_circuit` --- crates/nargo/src/cli/compile_cmd.rs | 23 +++++++----- crates/nargo/src/cli/execute_cmd.rs | 33 +++++++++------- crates/nargo/src/cli/mod.rs | 12 +++--- crates/nargo/src/cli/prove_cmd.rs | 58 +++++++++++++++++++++-------- crates/nargo/src/cli/verify_cmd.rs | 8 ++-- crates/noirc_driver/src/lib.rs | 2 +- 6 files changed, 87 insertions(+), 49 deletions(-) diff --git a/crates/nargo/src/cli/compile_cmd.rs b/crates/nargo/src/cli/compile_cmd.rs index ff0f922e70a..603f26d82a0 100644 --- a/crates/nargo/src/cli/compile_cmd.rs +++ b/crates/nargo/src/cli/compile_cmd.rs @@ -1,20 +1,17 @@ -use std::path::PathBuf; - -use acvm::ProofSystemCompiler; - use clap::ArgMatches; +use std::path::{Path, PathBuf}; -use std::path::Path; +use acvm::ProofSystemCompiler; +use noirc_abi::input_parser::Format; +use super::{add_std_lib, create_named_dir, read_inputs_from_file, write_to_file}; use crate::{ cli::execute_cmd::save_witness_to_dir, - constants::{ACIR_EXT, TARGET_DIR}, + constants::{ACIR_EXT, PROVER_INPUT_FILE, TARGET_DIR}, errors::CliError, resolver::Resolver, }; -use super::{add_std_lib, create_named_dir, write_to_file}; - pub(crate) fn run(args: ArgMatches) -> Result<(), CliError> { let args = args.subcommand_matches("compile").unwrap(); let circuit_name = args.value_of("circuit_name").unwrap(); @@ -54,8 +51,16 @@ pub fn generate_circuit_and_witness_to_disk>( println!("Generated ACIR code into {path}"); if generate_witness { + // Parse the initial witness values from Prover.toml + let inputs_map = read_inputs_from_file( + program_dir, + PROVER_INPUT_FILE, + Format::Toml, + compiled_program.abi.as_ref().unwrap().clone(), + )?; + let (_, solved_witness) = - super::execute_cmd::execute_program(program_dir, &compiled_program)?; + super::execute_cmd::execute_program(&compiled_program, &inputs_map)?; circuit_path.pop(); save_witness_to_dir(solved_witness, circuit_name, &circuit_path)?; diff --git a/crates/nargo/src/cli/execute_cmd.rs b/crates/nargo/src/cli/execute_cmd.rs index 537907efd5f..a89a0fcaa21 100644 --- a/crates/nargo/src/cli/execute_cmd.rs +++ b/crates/nargo/src/cli/execute_cmd.rs @@ -1,16 +1,14 @@ +use clap::ArgMatches; use std::path::{Path, PathBuf}; use acvm::acir::native_types::Witness; -use acvm::FieldElement; -use acvm::PartialWitnessGenerator; -use clap::ArgMatches; +use acvm::{FieldElement, PartialWitnessGenerator}; use noirc_abi::errors::AbiError; use noirc_abi::input_parser::{Format, InputValue}; use noirc_abi::{Abi, MAIN_RETURN_NAME}; use noirc_driver::CompiledProgram; -use super::{create_named_dir, read_inputs_from_file, write_to_file}; -use super::{InputMap, WitnessMap}; +use super::{create_named_dir, read_inputs_from_file, write_to_file, InputMap, WitnessMap}; use crate::{ cli::compile_cmd::compile_circuit, constants::{PROVER_INPUT_FILE, TARGET_DIR, WITNESS_EXT}, @@ -25,8 +23,7 @@ pub(crate) fn run(args: ArgMatches) -> Result<(), CliError> { let program_dir = args.value_of("path").map_or_else(|| std::env::current_dir().unwrap(), PathBuf::from); - let compiled_program = compile_circuit(&program_dir, show_ssa, allow_warnings)?; - let (return_value, solved_witness) = execute_program(&program_dir, &compiled_program)?; + let (return_value, solved_witness) = execute_with_path(&program_dir, show_ssa, allow_warnings)?; println!("Circuit witness successfully solved"); if let Some(return_value) = return_value { @@ -47,20 +44,30 @@ pub(crate) fn run(args: ArgMatches) -> Result<(), CliError> { /// So when we add witness values, their index start from 1. const WITNESS_OFFSET: u32 = 1; -pub(crate) fn execute_program>( - inputs_dir: P, - compiled_program: &CompiledProgram, +fn execute_with_path>( + program_dir: P, + show_ssa: bool, + allow_warnings: bool, ) -> Result<(Option, WitnessMap), CliError> { + let compiled_program = compile_circuit(&program_dir, show_ssa, allow_warnings)?; + // Parse the initial witness values from Prover.toml - let witness_map = read_inputs_from_file( - inputs_dir, + let inputs_map = read_inputs_from_file( + &program_dir, PROVER_INPUT_FILE, Format::Toml, compiled_program.abi.as_ref().unwrap().clone(), )?; + execute_program(&compiled_program, &inputs_map) +} + +pub(crate) fn execute_program( + compiled_program: &CompiledProgram, + inputs_map: &InputMap, +) -> Result<(Option, WitnessMap), CliError> { // Solve the remaining witnesses - let solved_witness = solve_witness(compiled_program, &witness_map)?; + let solved_witness = solve_witness(compiled_program, inputs_map)?; let public_inputs = extract_public_inputs(compiled_program, &solved_witness)?; let return_value = public_inputs.get(MAIN_RETURN_NAME).cloned(); diff --git a/crates/nargo/src/cli/mod.rs b/crates/nargo/src/cli/mod.rs index db07f84496c..92cc68b41d9 100644 --- a/crates/nargo/src/cli/mod.rs +++ b/crates/nargo/src/cli/mod.rs @@ -82,6 +82,7 @@ pub fn start_cli() { App::new("prove") .about("Create proof for this program") .arg(Arg::with_name("proof_name").help("The name of the proof")) + .arg(Arg::with_name("verify").long("verify").help("Verify proof after proving")) .arg(show_ssa.clone()) .arg(allow_warnings.clone()), ) @@ -213,21 +214,20 @@ fn write_inputs_to_file>( // helper function which tests noir programs by trying to generate a proof and verify it pub fn prove_and_verify(proof_name: &str, prg_dir: &Path, show_ssa: bool) -> bool { let tmp_dir = TempDir::new("p_and_v_tests").unwrap(); - let proof_path = match prove_cmd::prove_with_path( + match prove_cmd::prove_with_path( Some(proof_name), prg_dir, &tmp_dir.into_path(), + true, show_ssa, false, ) { - Ok(p) => p, + Ok(_) => true, Err(error) => { println!("{error}"); - return false; + false } - }; - - verify_cmd::verify_with_path(prg_dir, &proof_path.unwrap(), show_ssa, false).unwrap() + } } fn add_std_lib(driver: &mut Driver) { diff --git a/crates/nargo/src/cli/prove_cmd.rs b/crates/nargo/src/cli/prove_cmd.rs index 7d821b0f7d0..d67cdceffb9 100644 --- a/crates/nargo/src/cli/prove_cmd.rs +++ b/crates/nargo/src/cli/prove_cmd.rs @@ -4,17 +4,23 @@ use acvm::ProofSystemCompiler; use clap::ArgMatches; use noirc_abi::input_parser::Format; -use super::execute_cmd::{execute_program, extract_public_inputs}; -use super::{create_named_dir, write_inputs_to_file, write_to_file}; -use crate::cli::dedup_public_input_indices; +use super::{ + create_named_dir, dedup_public_input_indices, read_inputs_from_file, write_inputs_to_file, + write_to_file, +}; use crate::{ - constants::{PROOFS_DIR, PROOF_EXT, VERIFIER_INPUT_FILE}, + cli::{ + execute_cmd::{execute_program, extract_public_inputs}, + verify_cmd::verify_proof, + }, + constants::{PROOFS_DIR, PROOF_EXT, PROVER_INPUT_FILE, VERIFIER_INPUT_FILE}, errors::CliError, }; pub(crate) fn run(args: ArgMatches) -> Result<(), CliError> { let args = args.subcommand_matches("prove").unwrap(); let proof_name = args.value_of("proof_name"); + let check_proof = args.is_present("verify"); let show_ssa = args.is_present("show-ssa"); let allow_warnings = args.is_present("allow-warnings"); @@ -24,7 +30,7 @@ pub(crate) fn run(args: ArgMatches) -> Result<(), CliError> { let mut proof_dir = program_dir.clone(); proof_dir.push(PROOFS_DIR); - prove_with_path(proof_name, program_dir, proof_dir, show_ssa, allow_warnings)?; + prove_with_path(proof_name, program_dir, proof_dir, check_proof, show_ssa, allow_warnings)?; Ok(()) } @@ -33,12 +39,22 @@ pub fn prove_with_path>( proof_name: Option<&str>, program_dir: P, proof_dir: P, + check_proof: bool, show_ssa: bool, allow_warnings: bool, ) -> Result, CliError> { - let mut compiled_program = + let compiled_program = super::compile_cmd::compile_circuit(program_dir.as_ref(), show_ssa, allow_warnings)?; - let (_, solved_witness) = execute_program(&program_dir, &compiled_program)?; + + // Parse the initial witness values from Prover.toml + let inputs_map = read_inputs_from_file( + &program_dir, + PROVER_INPUT_FILE, + Format::Toml, + compiled_program.abi.as_ref().unwrap().clone(), + )?; + + let (_, solved_witness) = execute_program(&compiled_program, &inputs_map)?; // Write public inputs into Verifier.toml let public_inputs = extract_public_inputs(&compiled_program, &solved_witness)?; @@ -47,26 +63,36 @@ pub fn prove_with_path>( // Since the public outputs are added onto the public inputs list, there can be duplicates. // We keep the duplicates for when one is encoding the return values into the Verifier.toml, // however we must remove these duplicates when creating a proof. - compiled_program.circuit.public_inputs = - dedup_public_input_indices(compiled_program.circuit.public_inputs); + let mut prover_circuit = compiled_program.circuit.clone(); + prover_circuit.public_inputs = dedup_public_input_indices(prover_circuit.public_inputs); let backend = crate::backends::ConcreteBackend; - let proof = backend.prove_with_meta(compiled_program.circuit, solved_witness); + let proof = backend.prove_with_meta(prover_circuit, solved_witness); println!("Proof successfully created"); - if let Some(proof_name) = proof_name { - let proof_path = save_proof_to_dir(proof, proof_name, proof_dir)?; + if check_proof { + let valid_proof = verify_proof(compiled_program, public_inputs, &proof)?; + println!("Proof verified : {valid_proof}"); + if !valid_proof { + return Err(CliError::Generic("Could not verify generated proof".to_owned())); + } + } + + let proof_path = if let Some(proof_name) = proof_name { + let proof_path = save_proof_to_dir(&proof, proof_name, proof_dir)?; println!("Proof saved to {}", proof_path.display()); - Ok(Some(proof_path)) + Some(proof_path) } else { println!("{}", hex::encode(&proof)); - Ok(None) - } + None + }; + + Ok(proof_path) } fn save_proof_to_dir>( - proof: Vec, + proof: &[u8], proof_name: &str, proof_dir: P, ) -> Result { diff --git a/crates/nargo/src/cli/verify_cmd.rs b/crates/nargo/src/cli/verify_cmd.rs index 28a48cbba97..60efc882ec7 100644 --- a/crates/nargo/src/cli/verify_cmd.rs +++ b/crates/nargo/src/cli/verify_cmd.rs @@ -52,15 +52,15 @@ pub fn verify_with_path>( read_inputs_from_file(current_dir, VERIFIER_INPUT_FILE, Format::Toml, public_abi)?; } - let valid_proof = verify_proof(compiled_program, public_inputs_map, load_proof(proof_path)?)?; + let valid_proof = verify_proof(compiled_program, public_inputs_map, &load_proof(proof_path)?)?; Ok(valid_proof) } -fn verify_proof( +pub(crate) fn verify_proof( mut compiled_program: CompiledProgram, public_inputs_map: InputMap, - proof: Vec, + proof: &[u8], ) -> Result { let public_abi = compiled_program.abi.unwrap().public_abi(); let public_inputs = @@ -78,7 +78,7 @@ fn verify_proof( compiled_program.circuit.public_inputs = dedup_public_indices; let backend = crate::backends::ConcreteBackend; - let valid_proof = backend.verify_from_cs(&proof, dedup_public_values, compiled_program.circuit); + let valid_proof = backend.verify_from_cs(proof, dedup_public_values, compiled_program.circuit); Ok(valid_proof) } diff --git a/crates/noirc_driver/src/lib.rs b/crates/noirc_driver/src/lib.rs index 7f2de00b85a..69d19517585 100644 --- a/crates/noirc_driver/src/lib.rs +++ b/crates/noirc_driver/src/lib.rs @@ -18,7 +18,7 @@ pub struct Driver { context: Context, } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct CompiledProgram { pub circuit: Circuit, pub abi: Option,