Skip to content

Commit

Permalink
feat(nargo): add flag to verify created proofs (#737)
Browse files Browse the repository at this point in the history
* 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`
  • Loading branch information
TomAFrench authored Feb 14, 2023
1 parent 766b57d commit e981c7c
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 49 deletions.
23 changes: 14 additions & 9 deletions crates/nargo/src/cli/compile_cmd.rs
Original file line number Diff line number Diff line change
@@ -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();
Expand Down Expand Up @@ -54,8 +51,16 @@ pub fn generate_circuit_and_witness_to_disk<P: AsRef<Path>>(
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)?;
Expand Down
33 changes: 20 additions & 13 deletions crates/nargo/src/cli/execute_cmd.rs
Original file line number Diff line number Diff line change
@@ -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},
Expand All @@ -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 {
Expand All @@ -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<P: AsRef<Path>>(
inputs_dir: P,
compiled_program: &CompiledProgram,
fn execute_with_path<P: AsRef<Path>>(
program_dir: P,
show_ssa: bool,
allow_warnings: bool,
) -> Result<(Option<InputValue>, 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<InputValue>, 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();
Expand Down
12 changes: 6 additions & 6 deletions crates/nargo/src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()),
)
Expand Down Expand Up @@ -213,21 +214,20 @@ fn write_inputs_to_file<P: AsRef<Path>>(
// 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) {
Expand Down
58 changes: 42 additions & 16 deletions crates/nargo/src/cli/prove_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand All @@ -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(())
}
Expand All @@ -33,12 +39,22 @@ pub fn prove_with_path<P: AsRef<Path>>(
proof_name: Option<&str>,
program_dir: P,
proof_dir: P,
check_proof: bool,
show_ssa: bool,
allow_warnings: bool,
) -> Result<Option<PathBuf>, 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)?;
Expand All @@ -47,26 +63,36 @@ pub fn prove_with_path<P: AsRef<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<P: AsRef<Path>>(
proof: Vec<u8>,
proof: &[u8],
proof_name: &str,
proof_dir: P,
) -> Result<PathBuf, CliError> {
Expand Down
8 changes: 4 additions & 4 deletions crates/nargo/src/cli/verify_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,15 @@ pub fn verify_with_path<P: AsRef<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<u8>,
proof: &[u8],
) -> Result<bool, CliError> {
let public_abi = compiled_program.abi.unwrap().public_abi();
let public_inputs =
Expand All @@ -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)
}
Expand Down
2 changes: 1 addition & 1 deletion crates/noirc_driver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<noirc_abi::Abi>,
Expand Down

0 comments on commit e981c7c

Please sign in to comment.