Skip to content

Commit

Permalink
feat: import core logic in cli from nargo crate (#1142)
Browse files Browse the repository at this point in the history
  • Loading branch information
TomAFrench authored Apr 12, 2023
1 parent 24adcc0 commit 753a272
Show file tree
Hide file tree
Showing 20 changed files with 167 additions and 71 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions crates/nargo/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ edition.workspace = true
rustc_version = "0.4.0"

[dependencies]
acvm.workspace = true
noirc_abi.workspace = true
toml.workspace = true
serde.workspace = true
thiserror.workspace = true
Expand Down
13 changes: 13 additions & 0 deletions crates/nargo/src/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use acvm::OpcodeResolutionError;
use thiserror::Error;

#[derive(Debug, Error)]
pub enum NargoError {
/// Error while compiling Noir into ACIR.
#[error("Failed to compile circuit")]
CompilationError,

/// ACIR circuit solving error
#[error(transparent)]
SolvingError(#[from] OpcodeResolutionError),
}
4 changes: 4 additions & 0 deletions crates/nargo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,8 @@
//! This name was used because it sounds like `cargo` and
//! Noir Package Manager abbreviated is npm, which is already taken.
mod errors;
pub mod manifest;
pub mod ops;

pub use self::errors::NargoError;
10 changes: 10 additions & 0 deletions crates/nargo/src/ops/codegen_verifier.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use acvm::SmartContract;

use crate::NargoError;

pub fn codegen_verifier(
backend: &impl SmartContract,
verification_key: &[u8],
) -> Result<String, NargoError> {
Ok(backend.eth_contract_from_vk(verification_key))
}
20 changes: 20 additions & 0 deletions crates/nargo/src/ops/execute.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use acvm::PartialWitnessGenerator;
use acvm::{acir::circuit::Circuit, pwg::block::Blocks};
use noirc_abi::WitnessMap;

use crate::NargoError;

pub fn execute_circuit(
backend: &impl PartialWitnessGenerator,
circuit: Circuit,
mut initial_witness: WitnessMap,
) -> Result<WitnessMap, NargoError> {
let mut blocks = Blocks::default();
let (unresolved_opcodes, oracles) =
backend.solve(&mut initial_witness, &mut blocks, circuit.opcodes)?;
if !unresolved_opcodes.is_empty() || !oracles.is_empty() {
todo!("Add oracle support to nargo execute")
}

Ok(initial_witness)
}
11 changes: 11 additions & 0 deletions crates/nargo/src/ops/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
pub use self::codegen_verifier::codegen_verifier;
pub use self::execute::execute_circuit;
pub use self::preprocess::{checksum_acir, preprocess_circuit, PreprocessedData};
pub use self::prove::prove;
pub use self::verify::verify_proof;

mod codegen_verifier;
mod execute;
mod preprocess;
mod prove;
mod verify;
31 changes: 31 additions & 0 deletions crates/nargo/src/ops/preprocess.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use acvm::acir::circuit::Circuit;
use acvm::{checksum_constraint_system, ProofSystemCompiler};

use crate::NargoError;

pub fn checksum_acir(circuit: &Circuit) -> [u8; 4] {
checksum_constraint_system(circuit).to_be_bytes()
}

/// The result of preprocessing the ACIR bytecode.
/// The proving, verification key and circuit are backend specific.
///
/// The circuit is backend specific because at the end of compilation
/// an optimization pass is applied which will transform the bytecode into
/// a format that the backend will accept; removing unsupported gates
/// is one example of this.
pub struct PreprocessedData {
pub proving_key: Vec<u8>,
pub verification_key: Vec<u8>,
pub program_checksum: [u8; 4],
}

pub fn preprocess_circuit(
backend: &impl ProofSystemCompiler,
circuit: &Circuit,
) -> Result<PreprocessedData, NargoError> {
let (proving_key, verification_key) = backend.preprocess(circuit);
let program_checksum = checksum_acir(circuit);

Ok(PreprocessedData { proving_key, verification_key, program_checksum })
}
16 changes: 16 additions & 0 deletions crates/nargo/src/ops/prove.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use acvm::acir::circuit::Circuit;
use acvm::ProofSystemCompiler;
use noirc_abi::WitnessMap;

use crate::NargoError;

pub fn prove(
backend: &impl ProofSystemCompiler,
circuit: &Circuit,
solved_witness: WitnessMap,
proving_key: &[u8],
) -> Result<Vec<u8>, NargoError> {
let proof = backend.prove_with_pk(circuit, solved_witness, proving_key);

Ok(proof)
}
17 changes: 17 additions & 0 deletions crates/nargo/src/ops/verify.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use acvm::acir::circuit::Circuit;
use acvm::ProofSystemCompiler;
use noirc_abi::WitnessMap;

use crate::NargoError;

pub fn verify_proof(
backend: &impl ProofSystemCompiler,
circuit: &Circuit,
proof: &[u8],
public_inputs: WitnessMap,
verification_key: &[u8],
) -> Result<bool, NargoError> {
let valid_proof = backend.verify_with_vk(proof, public_inputs, circuit, verification_key);

Ok(valid_proof)
}
1 change: 1 addition & 0 deletions crates/nargo_cli/src/cli/codegen_verifier_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub(crate) struct CodegenVerifierCommand {
pub(crate) fn run(args: CodegenVerifierCommand, config: NargoConfig) -> Result<(), CliError> {
let compiled_program = compile_circuit(&config.program_dir, &args.compile_options)?;

// TODO: replace with `nargo::ops::codegen_verifier`
let backend = crate::backends::ConcreteBackend;
#[allow(deprecated)]
let smart_contract_string = backend.eth_contract_from_cs(compiled_program.circuit);
Expand Down
9 changes: 6 additions & 3 deletions crates/nargo_cli/src/cli/compile_cmd.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use acvm::ProofSystemCompiler;
use nargo::ops::preprocess_circuit;
use noirc_driver::{CompileOptions, CompiledContract, CompiledProgram, Driver};
use std::path::Path;

Expand All @@ -8,7 +9,7 @@ use crate::resolver::DependencyResolutionError;
use crate::{constants::TARGET_DIR, errors::CliError, resolver::Resolver};

use super::fs::program::{save_contract_to_file, save_program_to_file};
use super::preprocess_cmd::{save_preprocess_data, PreprocessedData};
use super::preprocess_cmd::save_preprocess_data;
use super::NargoConfig;

/// Compile the program and its secret execution trace into ACIR format
Expand Down Expand Up @@ -54,7 +55,8 @@ fn save_and_preprocess_program(
) -> Result<(), CliError> {
save_program_to_file(compiled_program, circuit_name, circuit_dir);

let preprocessed_data = PreprocessedData::from(&compiled_program.circuit);
let backend = crate::backends::ConcreteBackend;
let preprocessed_data = preprocess_circuit(&backend, &compiled_program.circuit)?;
save_preprocess_data(&preprocessed_data, circuit_name, circuit_dir)?;
Ok(())
}
Expand All @@ -74,9 +76,10 @@ fn save_and_preprocess_contract(
// Preprocess all contract data
// We are patching the verification key in our contract functions
// so when we save it to disk, the ABI will have the verification key.
let backend = crate::backends::ConcreteBackend;
let mut contract_preprocess_data = Vec::new();
for contract_function in &mut compiled_contract.functions {
let preprocessed_data = PreprocessedData::from(&contract_function.bytecode);
let preprocessed_data = preprocess_circuit(&backend, &contract_function.bytecode)?;
contract_function.verification_key = Some(preprocessed_data.verification_key.clone());
contract_preprocess_data.push(preprocessed_data);
}
Expand Down
15 changes: 3 additions & 12 deletions crates/nargo_cli/src/cli/execute_cmd.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use std::path::Path;

use acvm::pwg::block::Blocks;
use acvm::PartialWitnessGenerator;
use clap::Args;
use noirc_abi::input_parser::{Format, InputValue};
use noirc_abi::{InputMap, WitnessMap};
Expand Down Expand Up @@ -65,18 +63,11 @@ pub(crate) fn execute_program(
compiled_program: &CompiledProgram,
inputs_map: &InputMap,
) -> Result<WitnessMap, CliError> {
let mut solved_witness = compiled_program.abi.encode(inputs_map, None)?;
let initial_witness = compiled_program.abi.encode(inputs_map, None)?;

let backend = crate::backends::ConcreteBackend;
let mut blocks = Blocks::default();
let (unresolved_opcodes, oracles) = backend.solve(
&mut solved_witness,
&mut blocks,
compiled_program.circuit.opcodes.clone(),
)?;
if !unresolved_opcodes.is_empty() || !oracles.is_empty() {
todo!("Add oracle support to nargo execute")
}
let solved_witness =
nargo::ops::execute_circuit(&backend, compiled_program.circuit.clone(), initial_witness)?;

Ok(solved_witness)
}
9 changes: 4 additions & 5 deletions crates/nargo_cli/src/cli/fs/keys.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use super::{create_named_dir, load_hex_data, program::checksum_acir, write_to_file};
use super::{create_named_dir, load_hex_data, write_to_file};
use crate::{
constants::{ACIR_CHECKSUM, PK_EXT, VK_EXT},
errors::CliError,
};
use acvm::acir::circuit::Circuit;
use nargo::ops::checksum_acir;
use std::path::{Path, PathBuf};

pub(crate) fn save_key_to_dir<P: AsRef<Path>>(
Expand Down Expand Up @@ -61,11 +62,9 @@ pub(crate) fn fetch_pk_and_vk<P: AsRef<Path>>(
#[cfg(test)]
mod tests {
use super::fetch_pk_and_vk;
use crate::cli::fs::{
keys::save_key_to_dir,
program::{checksum_acir, save_acir_checksum_to_dir},
};
use crate::cli::fs::{keys::save_key_to_dir, program::save_acir_checksum_to_dir};
use acvm::acir::circuit::Circuit;
use nargo::ops::checksum_acir;
use tempdir::TempDir;

#[test]
Expand Down
4 changes: 0 additions & 4 deletions crates/nargo_cli/src/cli/fs/program.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::path::{Path, PathBuf};

use acvm::{acir::circuit::Circuit, checksum_constraint_system};
use noirc_driver::{CompiledContract, CompiledProgram};

use crate::{constants::ACIR_CHECKSUM, errors::CliError};
Expand Down Expand Up @@ -34,9 +33,6 @@ fn save_build_artifact_to_file<P: AsRef<Path>, T: ?Sized + serde::Serialize>(
circuit_path
}

pub(crate) fn checksum_acir(circuit: &Circuit) -> [u8; 4] {
checksum_constraint_system(circuit).to_be_bytes()
}
pub(crate) fn save_acir_checksum_to_dir<P: AsRef<Path>>(
acir_checksum: [u8; 4],
hash_name: &str,
Expand Down
31 changes: 5 additions & 26 deletions crates/nargo_cli/src/cli/preprocess_cmd.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use acvm::acir::circuit::Circuit;
use acvm::ProofSystemCompiler;
use nargo::ops::{preprocess_circuit, PreprocessedData};
use std::path::{Path, PathBuf};

use clap::Args;
Expand All @@ -8,7 +7,7 @@ use crate::{constants::TARGET_DIR, errors::CliError};

use super::fs::{
keys::save_key_to_dir,
program::{checksum_acir, read_program_from_file, save_acir_checksum_to_dir},
program::{read_program_from_file, save_acir_checksum_to_dir},
};
use super::NargoConfig;

Expand All @@ -23,33 +22,13 @@ pub(crate) fn run(args: PreprocessCommand, config: NargoConfig) -> Result<(), Cl
let circuit_dir = config.program_dir.join(TARGET_DIR);

let program = read_program_from_file(circuit_dir.join(&args.artifact_name))?;
let preprocess_data = PreprocessedData::from(&program.circuit);

let backend = crate::backends::ConcreteBackend;
let preprocess_data = preprocess_circuit(&backend, &program.circuit)?;
save_preprocess_data(&preprocess_data, &args.artifact_name, circuit_dir)?;

Ok(())
}
/// The result of preprocessing the ACIR bytecode.
/// The proving, verification key and circuit are backend specific.
///
/// The circuit is backend specific because at the end of compilation
/// an optimization pass is applied which will transform the bytecode into
/// a format that the backend will accept; removing unsupported gates
/// is one example of this.
pub(crate) struct PreprocessedData {
pub(crate) proving_key: Vec<u8>,
pub(crate) verification_key: Vec<u8>,
pub(crate) program_checksum: [u8; 4],
}

impl From<&Circuit> for PreprocessedData {
fn from(circuit: &Circuit) -> Self {
let backend = crate::backends::ConcreteBackend;
let (proving_key, verification_key) = backend.preprocess(circuit);
let program_checksum = checksum_acir(circuit);

PreprocessedData { proving_key, verification_key, program_checksum }
}
}

pub(crate) fn save_preprocess_data<P: AsRef<Path>>(
data: &PreprocessedData,
Expand Down
8 changes: 5 additions & 3 deletions crates/nargo_cli/src/cli/prove_cmd.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::path::{Path, PathBuf};

use acvm::ProofSystemCompiler;
use clap::Args;
use nargo::ops::{preprocess_circuit, PreprocessedData};
use noirc_abi::input_parser::Format;
use noirc_driver::CompileOptions;

Expand Down Expand Up @@ -75,7 +75,8 @@ pub(crate) fn prove_with_path<P: AsRef<Path>>(
super::compile_cmd::compile_circuit(program_dir.as_ref(), compile_options)?;

let backend = crate::backends::ConcreteBackend;
let (proving_key, verification_key) = backend.preprocess(&compiled_program.circuit);
let PreprocessedData { proving_key, verification_key, .. } =
preprocess_circuit(&backend, &compiled_program.circuit)?;
(compiled_program, proving_key, verification_key)
}
};
Expand Down Expand Up @@ -103,7 +104,8 @@ pub(crate) fn prove_with_path<P: AsRef<Path>>(
)?;

let backend = crate::backends::ConcreteBackend;
let proof = backend.prove_with_pk(&compiled_program.circuit, solved_witness, &proving_key);
let proof =
nargo::ops::prove(&backend, &compiled_program.circuit, solved_witness, &proving_key)?;

if check_proof {
let no_proof_name = "".into();
Expand Down
15 changes: 4 additions & 11 deletions crates/nargo_cli/src/cli/test_cmd.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::{collections::BTreeMap, io::Write, path::Path};

use acvm::{pwg::block::Blocks, PartialWitnessGenerator, ProofSystemCompiler};
use acvm::ProofSystemCompiler;
use clap::Args;
use nargo::ops::execute_circuit;
use noirc_driver::{CompileOptions, Driver};
use noirc_frontend::node_interner::FuncId;
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
Expand Down Expand Up @@ -79,23 +80,15 @@ fn run_test(
config: &CompileOptions,
) -> Result<(), CliError> {
let backend = crate::backends::ConcreteBackend;
let mut blocks = Blocks::default();

let program = driver
.compile_no_check(config, main)
.map_err(|_| CliError::Generic(format!("Test '{test_name}' failed to compile")))?;

let mut solved_witness = BTreeMap::new();

// Run the backend to ensure the PWG evaluates functions like std::hash::pedersen,
// otherwise constraints involving these expressions will not error.
match backend.solve(&mut solved_witness, &mut blocks, program.circuit.opcodes) {
Ok((unresolved_opcodes, oracles)) => {
if !unresolved_opcodes.is_empty() || !oracles.is_empty() {
todo!("Add oracle support to nargo test")
}
Ok(())
}
match execute_circuit(&backend, program.circuit, BTreeMap::new()) {
Ok(_) => Ok(()),
Err(error) => {
let writer = StandardStream::stderr(ColorChoice::Always);
let mut writer = writer.lock();
Expand Down
Loading

0 comments on commit 753a272

Please sign in to comment.