Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: import core logic in cli from nargo crate #1142

Merged
merged 1 commit into from
Apr 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -6,4 +6,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