Skip to content

Commit

Permalink
feat(abi)!: add an explicit mapping from ABI params to witness indices (
Browse files Browse the repository at this point in the history
#851)

* feat: track all parameter witnesses in evaluator

* chore: use explicit witness map for encoding/decoding witness map

* chore: move `param_witnesses` to be stored within ABI

* feat: create separate methods for encoding to a witness vs verifier inputs

* chore: move encode_value and decode_value back inside Abi's impl

* chore: remove clone from `encode_to_witness`

* chore: use try_btree_map instead of unwrapping

* feat: check for unexpected inputs when encoding a witness

* chore: use InputMap and WitnessMap types in ABI

* chore: update stale comment

* chore: apply input validation checks on new encoding method

* chore: clippy

* chore: remove unnecessary clone

* feat: add smoke test for abi encoding and decoding

* chore: remove todo

* chore: return abi from compile_circuit

* chore: simplify returning `CompiledProgram`

* chore: clippy

* feat: return AbiError if witness value can't be found

* chore: add documentation for Abi fields

* fix: re-add `public_inputs` field to `Evaluator`

* chore: remove stale code from BTreeSet experiment

* chore: fix merge issues

* fix: re-add deleted `num_witnesses_abi_len` init
  • Loading branch information
TomAFrench authored Feb 16, 2023
1 parent 479da0e commit 5bd4bd5
Show file tree
Hide file tree
Showing 12 changed files with 222 additions and 137 deletions.
53 changes: 7 additions & 46 deletions crates/nargo/src/cli/execute_cmd.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
use clap::ArgMatches;
use std::path::{Path, PathBuf};

use acvm::acir::native_types::Witness;
use acvm::{FieldElement, PartialWitnessGenerator};
use acvm::PartialWitnessGenerator;
use clap::ArgMatches;
use noirc_abi::errors::AbiError;
use noirc_abi::input_parser::{Format, InputValue};
use noirc_abi::{Abi, MAIN_RETURN_NAME};
use noirc_abi::{InputMap, WitnessMap, MAIN_RETURN_NAME};
use noirc_driver::CompiledProgram;

use super::{create_named_dir, read_inputs_from_file, write_to_file, InputMap, WitnessMap};
use super::{create_named_dir, read_inputs_from_file, write_to_file};
use crate::{
cli::compile_cmd::compile_circuit,
constants::{PROVER_INPUT_FILE, TARGET_DIR, WITNESS_EXT},
Expand Down Expand Up @@ -40,10 +40,6 @@ pub(crate) fn run(args: ArgMatches) -> Result<(), CliError> {
Ok(())
}

/// In Barretenberg, the proof system adds a zero witness in the first index,
/// So when we add witness values, their index start from 1.
const WITNESS_OFFSET: u32 = 1;

fn execute_with_path<P: AsRef<Path>>(
program_dir: P,
show_ssa: bool,
Expand All @@ -69,36 +65,19 @@ pub(crate) fn execute_program(
// Solve the remaining witnesses
let solved_witness = solve_witness(compiled_program, inputs_map)?;

let public_inputs = extract_public_inputs(compiled_program, &solved_witness)?;
let public_abi = compiled_program.abi.clone().public_abi();
let public_inputs = public_abi.decode_from_witness(&solved_witness)?;
let return_value = public_inputs.get(MAIN_RETURN_NAME).cloned();

Ok((return_value, solved_witness))
}

pub(crate) fn extract_public_inputs(
compiled_program: &CompiledProgram,
solved_witness: &WitnessMap,
) -> Result<InputMap, AbiError> {
let encoded_public_inputs: Vec<FieldElement> = compiled_program
.circuit
.public_inputs
.0
.iter()
.map(|index| solved_witness[index])
.collect();

let public_abi = compiled_program.abi.clone().public_abi();

public_abi.decode(&encoded_public_inputs)
}

pub(crate) fn solve_witness(
compiled_program: &CompiledProgram,
input_map: &InputMap,
) -> Result<WitnessMap, CliError> {
let abi = compiled_program.abi.clone();
let mut solved_witness =
input_map_to_witness_map(abi, input_map).map_err(|error| match error {
compiled_program.abi.encode_to_witness(input_map).map_err(|error| match error {
AbiError::UndefinedInput(_) => {
CliError::Generic(format!("{error} in the {PROVER_INPUT_FILE}.toml file."))
}
Expand All @@ -111,24 +90,6 @@ pub(crate) fn solve_witness(
Ok(solved_witness)
}

/// Given an InputMap and an Abi, produce a WitnessMap
///
/// In particular, this method shows one how to associate values in a Toml/JSON
/// file with witness indices
fn input_map_to_witness_map(abi: Abi, input_map: &InputMap) -> Result<WitnessMap, AbiError> {
// The ABI map is first encoded as a vector of field elements
let encoded_inputs = abi.encode(input_map, true)?;

Ok(encoded_inputs
.into_iter()
.enumerate()
.map(|(index, witness_value)| {
let witness = Witness::new(WITNESS_OFFSET + (index as u32));
(witness, witness_value)
})
.collect())
}

pub(crate) fn save_witness_to_dir<P: AsRef<Path>>(
witness: WitnessMap,
witness_name: &str,
Expand Down
18 changes: 3 additions & 15 deletions crates/nargo/src/cli/mod.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
use acvm::{
acir::{
circuit::{Circuit, PublicInputs},
native_types::Witness,
},
acir::circuit::{Circuit, PublicInputs},
hash_constraint_system, FieldElement, ProofSystemCompiler,
};
pub use check_cmd::check_from_path;
use clap::{App, AppSettings, Arg};
use const_format::formatcp;
use noirc_abi::{
input_parser::{Format, InputValue},
Abi,
};
use noirc_abi::{input_parser::Format, Abi, InputMap};
use noirc_driver::Driver;
use noirc_frontend::graph::{CrateName, CrateType};
use std::{
collections::{BTreeMap, HashMap, HashSet},
collections::{HashMap, HashSet},
fs::File,
io::Write,
path::{Path, PathBuf},
Expand Down Expand Up @@ -45,12 +39,6 @@ const CARGO_PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
static VERSION_STRING: &str =
formatcp!("{} (git version hash: {}, is dirty: {})", CARGO_PKG_VERSION, GIT_HASH, IS_DIRTY);

/// A map from the fields in an TOML/JSON file which correspond to some ABI to their values
pub type InputMap = BTreeMap<String, InputValue>;

/// A map from the witnesses in a constraint system to the field element values
pub type WitnessMap = BTreeMap<Witness, FieldElement>;

pub fn start_cli() {
let allow_warnings = Arg::with_name("allow-warnings")
.long("allow-warnings")
Expand Down
8 changes: 3 additions & 5 deletions crates/nargo/src/cli/prove_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ use super::{
write_inputs_to_file, write_to_file,
};
use crate::{
cli::{
execute_cmd::{execute_program, extract_public_inputs},
verify_cmd::verify_proof,
},
cli::{execute_cmd::execute_program, verify_cmd::verify_proof},
constants::{PROOFS_DIR, PROOF_EXT, PROVER_INPUT_FILE, TARGET_DIR, VERIFIER_INPUT_FILE},
errors::CliError,
};
Expand Down Expand Up @@ -82,7 +79,8 @@ pub fn prove_with_path<P: AsRef<Path>>(
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)?;
let public_abi = compiled_program.abi.clone().public_abi();
let public_inputs = public_abi.decode_from_witness(&solved_witness)?;
write_inputs_to_file(&public_inputs, &program_dir, VERIFIER_INPUT_FILE, Format::Toml)?;

// Since the public outputs are added onto the public inputs list, there can be duplicates.
Expand Down
2 changes: 1 addition & 1 deletion crates/nargo/src/cli/verify_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ pub(crate) fn verify_proof(
) -> Result<bool, CliError> {
let public_abi = compiled_program.abi.public_abi();
let public_inputs =
public_abi.encode(&public_inputs_map, false).map_err(|error| match error {
public_abi.encode_to_array(&public_inputs_map).map_err(|error| match error {
AbiError::UndefinedInput(_) => {
CliError::Generic(format!("{error} in the {VERIFIER_INPUT_FILE}.toml file."))
}
Expand Down
5 changes: 5 additions & 0 deletions crates/noirc_abi/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::{input_parser::InputValue, AbiParameter, AbiType};
use acvm::acir::native_types::Witness;
use thiserror::Error;

#[derive(Debug, Error)]
Expand Down Expand Up @@ -41,4 +42,8 @@ pub enum AbiError {
UndefinedInput(String),
#[error("ABI specifies an input of length {expected} but received input of length {actual}")]
UnexpectedInputLength { expected: u32, actual: u32 },
#[error(
"Could not read witness value at index {witness_index:?} (required for parameter \"{name}\")"
)]
MissingParamWitnessValue { name: String, witness_index: Witness },
}
1 change: 1 addition & 0 deletions crates/noirc_abi/src/input_parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::{Abi, AbiType};
/// This is what all formats eventually transform into
/// For example, a toml file will parse into TomlTypes
/// and those TomlTypes will be mapped to Value
#[cfg_attr(test, derive(PartialEq))]
#[derive(Debug, Clone, Serialize)]
pub enum InputValue {
Field(FieldElement),
Expand Down
Loading

0 comments on commit 5bd4bd5

Please sign in to comment.