Skip to content

Commit

Permalink
Merge branch 'master' into update-clap
Browse files Browse the repository at this point in the history
* master:
  feat(nargo): add flag to verify created proofs (#737)
  chore: Add display for binaryop (#839)
  chore(ssa): per array memory map (#832)
  chore: remove unwanted print of Ok(<path>) in nargo compile (#843)
  • Loading branch information
TomAFrench committed Feb 14, 2023
2 parents d67fbef + e981c7c commit a9ad0a5
Show file tree
Hide file tree
Showing 16 changed files with 174 additions and 117 deletions.
20 changes: 13 additions & 7 deletions crates/nargo/src/cli/compile_cmd.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
use std::path::PathBuf;
use std::path::{Path, PathBuf};

use acvm::ProofSystemCompiler;
use noirc_abi::input_parser::Format;

use clap::Args;

use std::path::Path;

use crate::{
cli::execute_cmd::save_witness_to_dir,
constants::{ACIR_EXT, TARGET_DIR},
cli::{execute_cmd::save_witness_to_dir, read_inputs_from_file},
constants::{ACIR_EXT, PROVER_INPUT_FILE, TARGET_DIR},
errors::CliError,
resolver::Resolver,
};
Expand Down Expand Up @@ -60,11 +59,18 @@ pub fn generate_circuit_and_witness_to_disk<P: AsRef<Path>>(
circuit_path.set_extension(ACIR_EXT);
let path = write_to_file(serialized.as_slice(), &circuit_path);
println!("Generated ACIR code into {path}");
println!("{:?}", std::fs::canonicalize(&circuit_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
27 changes: 18 additions & 9 deletions crates/nargo/src/cli/execute_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,8 @@ pub(crate) struct ExecuteCommand {
}

pub(crate) fn run(args: ExecuteCommand, config: NargoConfig) -> Result<(), CliError> {
let compiled_program =
compile_circuit(&config.program_dir, args.show_ssa, args.allow_warnings)?;
let (return_value, solved_witness) = execute_program(&config.program_dir, &compiled_program)?;
let (return_value, solved_witness) =
execute_with_path(&config.program_dir, args.show_ssa, args.allow_warnings)?;

println!("Circuit witness successfully solved");
if let Some(return_value) = return_value {
Expand All @@ -57,20 +56,30 @@ pub(crate) fn run(args: ExecuteCommand, config: NargoConfig) -> Result<(), CliEr
/// 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
11 changes: 5 additions & 6 deletions crates/nargo/src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,21 +159,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.to_owned()),
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
60 changes: 45 additions & 15 deletions crates/nargo/src/cli/prove_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@ use acvm::ProofSystemCompiler;
use clap::Args;
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, NargoConfig};
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, NargoConfig,
};
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,
};

Expand All @@ -18,6 +23,10 @@ pub(crate) struct ProveCommand {
/// The name of the proof
proof_name: Option<String>,

/// Verify proof after proving
#[arg(short, long)]
verify: bool,

/// Issue a warning for each unused variable instead of an error
#[arg(short, long)]
allow_warnings: bool,
Expand All @@ -35,6 +44,7 @@ pub(crate) fn run(args: ProveCommand, config: NargoConfig) -> Result<(), CliErro
args.proof_name,
config.program_dir,
proof_dir,
args.verify,
args.show_ssa,
args.allow_warnings,
)?;
Expand All @@ -46,12 +56,22 @@ pub fn prove_with_path<P: AsRef<Path>>(
proof_name: Option<String>,
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 @@ -60,26 +80,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 @@ -53,15 +53,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 @@ -79,7 +79,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
18 changes: 9 additions & 9 deletions crates/noirc_evaluator/src/ssa/acir_gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ use internal_var_cache::InternalVarCache;
// Expose this to the crate as we need to apply range constraints when
// converting the ABI(main parameters) to Noir types
pub(crate) use constraints::range_constraint;
mod memory_map;
use memory_map::MemoryMap;
mod acir_mem;
use acir_mem::AcirMem;

#[derive(Default)]
pub struct Acir {
memory_map: MemoryMap,
memory: AcirMem,
var_cache: InternalVarCache,
}

Expand All @@ -39,12 +39,12 @@ impl Acir {
binary, condition, constrain, intrinsics, load, not, r#return, store, truncate,
};

let memory_map = &mut self.memory_map;
let acir_mem = &mut self.memory;
let var_cache = &mut self.var_cache;

let output = match &ins.operation {
Operation::Binary(binary) => {
binary::evaluate(binary, ins.res_type, var_cache, memory_map, evaluator, ctx)
binary::evaluate(binary, ins.res_type, var_cache, acir_mem, evaluator, ctx)
}
Operation::Constrain(value, ..) => {
constrain::evaluate(value, var_cache, evaluator, ctx)
Expand All @@ -57,19 +57,19 @@ impl Acir {
truncate::evaluate(value, *bit_size, *max_bit_size, var_cache, evaluator, ctx)
}
Operation::Intrinsic(opcode, args) => {
intrinsics::evaluate(args, ins, *opcode, var_cache, memory_map, ctx, evaluator)
intrinsics::evaluate(args, ins, *opcode, var_cache, acir_mem, ctx, evaluator)
}
Operation::Return(node_ids) => {
r#return::evaluate(node_ids, memory_map, var_cache, evaluator, ctx)?
r#return::evaluate(node_ids, acir_mem, var_cache, evaluator, ctx)?
}
Operation::Cond { condition, val_true: lhs, val_false: rhs } => {
condition::evaluate(*condition, *lhs, *rhs, var_cache, evaluator, ctx)
}
Operation::Load { array_id, index } => {
load::evaluate(*array_id, *index, memory_map, var_cache, evaluator, ctx)
load::evaluate(*array_id, *index, acir_mem, var_cache, evaluator, ctx)
}
Operation::Store { array_id, index, value } => {
store::evaluate(*array_id, *index, *value, memory_map, var_cache, evaluator, ctx)
store::evaluate(*array_id, *index, *value, acir_mem, var_cache, evaluator, ctx)
}
Operation::Nop => None,
i @ Operation::Jne(..)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,41 @@ use crate::ssa::{
};
use acvm::acir::native_types::Witness;
use iter_extended::vecmap;
use std::collections::HashMap;
use std::collections::BTreeMap;

// maps memory address to expression
#[derive(Default)]
pub struct MemoryMap {
inner: HashMap<u32, InternalVar>,
pub struct ArrayHeap {
// maps memory address to InternalVar
memory_map: BTreeMap<u32, InternalVar>,
}

impl MemoryMap {
/// Handle virtual memory access
#[derive(Default)]
pub struct AcirMem {
virtual_memory: BTreeMap<ArrayId, ArrayHeap>,
}

impl AcirMem {
// Returns the memory_map for the array
fn array_map_mut(&mut self, array_id: ArrayId) -> &mut BTreeMap<u32, InternalVar> {
&mut self.virtual_memory.entry(array_id).or_default().memory_map
}

// Write the value to the array's VM at the specified index
pub fn insert(&mut self, array_id: ArrayId, index: u32, value: InternalVar) {
self.array_map_mut(array_id).insert(index, value);
}

//Map the outputs into the array
pub(crate) fn map_array(&mut self, a: ArrayId, outputs: &[Witness], ctx: &SsaContext) {
let array = &ctx.mem[a];
let address = array.adr;
for i in 0..array.len {
let var = if i < outputs.len() as u32 {
InternalVar::from(outputs[i as usize])
} else {
InternalVar::zero_expr()
};
self.inner.insert(address + i, var);
self.array_map_mut(array.id).insert(i, var);
}
}

Expand Down Expand Up @@ -60,10 +75,8 @@ impl MemoryMap {
return None; // IndexOutOfBoundsError
}

let address_of_element = array.absolute_adr(offset);

// Check the memory_map to see if the element is there
if let Some(internal_var) = self.inner.get(&address_of_element) {
if let Some(internal_var) = self.array_map_mut(array.id).get(&offset) {
return Some(internal_var.clone());
};

Expand All @@ -78,8 +91,4 @@ impl MemoryMap {

Some(array_element)
}

pub(crate) fn insert(&mut self, key: u32, value: InternalVar) -> Option<InternalVar> {
self.inner.insert(key, value)
}
}
Loading

0 comments on commit a9ad0a5

Please sign in to comment.