Skip to content

Commit

Permalink
feat(nargo)!: save program ABI alongside ACIR (#922)
Browse files Browse the repository at this point in the history
* feat!(nargo): save program ABI alongside ACIR

* chore: clippy fix

* fix: update extension for reading program hash

* chore: add some error handling to `read_program_from_file`

* chore: replace `.sha256` extension with `.checksum`
  • Loading branch information
TomAFrench authored Feb 27, 2023
1 parent c730329 commit ddaf305
Show file tree
Hide file tree
Showing 12 changed files with 110 additions and 58 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions crates/nargo/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ thiserror.workspace = true
clap = { version = "4.1.4", features = ["derive"]}
const_format = "0.2.30"
hex = "0.4.2"
serde_json = "1.0"
termcolor = "1.1.2"
tempdir = "0.3.7"

Expand Down
4 changes: 2 additions & 2 deletions crates/nargo/src/cli/compile_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use clap::Args;

use crate::{constants::TARGET_DIR, errors::CliError, resolver::Resolver};

use super::fs::{acir::save_acir_to_dir, keys::save_key_to_dir};
use super::fs::{keys::save_key_to_dir, program::save_program_to_file};
use super::{add_std_lib, NargoConfig};

/// Compile the program and its secret execution trace into ACIR format
Expand Down Expand Up @@ -43,7 +43,7 @@ fn compile_and_preprocess_circuit<P: AsRef<Path>>(
allow_warnings: bool,
) -> Result<PathBuf, CliError> {
let compiled_program = compile_circuit(program_dir, false, allow_warnings)?;
let circuit_path = save_acir_to_dir(&compiled_program.circuit, circuit_name, &circuit_dir);
let circuit_path = save_program_to_file(&compiled_program, circuit_name, &circuit_dir);

preprocess_with_path(circuit_name, circuit_dir, &compiled_program.circuit)?;

Expand Down
29 changes: 0 additions & 29 deletions crates/nargo/src/cli/fs/acir.rs

This file was deleted.

8 changes: 4 additions & 4 deletions crates/nargo/src/cli/fs/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::path::{Path, PathBuf};
use acvm::{acir::circuit::Circuit, hash_constraint_system};

use crate::{
constants::{ACIR_EXT, PK_EXT, VK_EXT},
constants::{PK_EXT, VK_EXT},
errors::CliError,
};

Expand Down Expand Up @@ -31,9 +31,9 @@ pub(crate) fn fetch_pk_and_vk<P: AsRef<Path>>(
prove_circuit: bool,
check_proof: bool,
) -> Result<(Vec<u8>, Vec<u8>), CliError> {
let mut acir_hash_path = PathBuf::new();
acir_hash_path.push(circuit_build_path.as_ref());
acir_hash_path.set_extension(ACIR_EXT.to_owned() + ".sha256");
let mut acir_hash_path = PathBuf::from(circuit_build_path.as_ref());
acir_hash_path.set_extension("json.checksum");

let expected_acir_hash = load_hex_data(acir_hash_path.clone())?;

let new_acir_hash = hash_constraint_system(circuit);
Expand Down
2 changes: 1 addition & 1 deletion crates/nargo/src/cli/fs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ use std::{

use crate::errors::CliError;

pub(super) mod acir;
pub(super) mod inputs;
pub(super) mod keys;
pub(super) mod program;
pub(super) mod proof;
pub(super) mod witness;

Expand Down
39 changes: 39 additions & 0 deletions crates/nargo/src/cli/fs/program.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use std::path::{Path, PathBuf};

use acvm::hash_constraint_system;
use noirc_driver::CompiledProgram;

use crate::errors::CliError;

use super::{create_named_dir, write_to_file};

pub(crate) fn save_program_to_file<P: AsRef<Path>>(
compiled_program: &CompiledProgram,
circuit_name: &str,
circuit_dir: P,
) -> PathBuf {
let mut circuit_path = create_named_dir(circuit_dir.as_ref(), "target");
circuit_path.push(circuit_name);
circuit_path.set_extension("json");

write_to_file(&serde_json::to_vec(compiled_program).unwrap(), &circuit_path);

// Save a checksum of the circuit to compare against during proving and verification
let acir_hash = hash_constraint_system(&compiled_program.circuit);
circuit_path.set_extension("json.checksum");
write_to_file(hex::encode(acir_hash).as_bytes(), &circuit_path);

circuit_path
}

pub(crate) fn read_program_from_file<P: AsRef<Path>>(
circuit_path: P,
) -> Result<CompiledProgram, CliError> {
let file_path = circuit_path.as_ref().with_extension("json");

let input_string = std::fs::read(&file_path).map_err(|_| CliError::PathNotValid(file_path))?;

let program = serde_json::from_slice(&input_string).expect("could not deserialize program");

Ok(program)
}
22 changes: 16 additions & 6 deletions crates/nargo/src/cli/prove_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use noirc_abi::input_parser::Format;
use super::fs::{
inputs::{read_inputs_from_file, write_inputs_to_file},
keys::fetch_pk_and_vk,
program::read_program_from_file,
proof::save_proof_to_dir,
};
use super::NargoConfig;
Expand Down Expand Up @@ -68,20 +69,29 @@ pub(crate) fn prove_with_path<P: AsRef<Path>>(
proof_name: Option<String>,
program_dir: P,
proof_dir: P,
circuit_build_path: Option<P>,
circuit_build_path: Option<PathBuf>,
check_proof: bool,
show_ssa: bool,
allow_warnings: bool,
) -> Result<Option<PathBuf>, CliError> {
let compiled_program =
super::compile_cmd::compile_circuit(program_dir.as_ref(), show_ssa, allow_warnings)?;
let (proving_key, verification_key) = match circuit_build_path {
let (compiled_program, proving_key, verification_key) = match circuit_build_path {
Some(circuit_build_path) => {
fetch_pk_and_vk(&compiled_program.circuit, circuit_build_path, true, true)?
let compiled_program = read_program_from_file(&circuit_build_path)?;

let (proving_key, verification_key) =
fetch_pk_and_vk(&compiled_program.circuit, circuit_build_path, true, true)?;
(compiled_program, proving_key, verification_key)
}
None => {
let compiled_program = super::compile_cmd::compile_circuit(
program_dir.as_ref(),
show_ssa,
allow_warnings,
)?;

let backend = crate::backends::ConcreteBackend;
backend.preprocess(&compiled_program.circuit)
let (proving_key, verification_key) = backend.preprocess(&compiled_program.circuit);
(compiled_program, proving_key, verification_key)
}
};

Expand Down
19 changes: 14 additions & 5 deletions crates/nargo/src/cli/verify_cmd.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use super::fs::{inputs::read_inputs_from_file, keys::fetch_pk_and_vk, load_hex_data};
use super::fs::{
inputs::read_inputs_from_file, keys::fetch_pk_and_vk, load_hex_data,
program::read_program_from_file,
};
use super::{compile_cmd::compile_circuit, InputMap, NargoConfig};
use crate::{
constants::{PROOFS_DIR, PROOF_EXT, TARGET_DIR, VERIFIER_INPUT_FILE},
Expand Down Expand Up @@ -47,14 +50,20 @@ fn verify_with_path<P: AsRef<Path>>(
show_ssa: bool,
allow_warnings: bool,
) -> Result<(), CliError> {
let compiled_program = compile_circuit(program_dir.as_ref(), show_ssa, allow_warnings)?;
let (_, verification_key) = match circuit_build_path {
let (compiled_program, verification_key) = match circuit_build_path {
Some(circuit_build_path) => {
fetch_pk_and_vk(&compiled_program.circuit, circuit_build_path, false, true)?
let compiled_program = read_program_from_file(&circuit_build_path)?;

let (_, verification_key) =
fetch_pk_and_vk(&compiled_program.circuit, circuit_build_path, false, true)?;
(compiled_program, verification_key)
}
None => {
let compiled_program = compile_circuit(program_dir.as_ref(), show_ssa, allow_warnings)?;

let backend = crate::backends::ConcreteBackend;
backend.preprocess(&compiled_program.circuit)
let (_, verification_key) = backend.preprocess(&compiled_program.circuit);
(compiled_program, verification_key)
}
};

Expand Down
2 changes: 0 additions & 2 deletions crates/nargo/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ pub(crate) const PKG_FILE: &str = "Nargo.toml";
// Extensions
/// The extension for files containing circuit proofs.
pub(crate) const PROOF_EXT: &str = "proof";
/// The extension for files containing circuit ACIR representations.
pub(crate) const ACIR_EXT: &str = "acir";
/// The extension for files containing proof witnesses.
pub(crate) const WITNESS_EXT: &str = "tr";
/// The extension for proving keys.
Expand Down
12 changes: 3 additions & 9 deletions crates/noirc_driver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
#![warn(unused_crate_dependencies, unused_extern_crates)]
#![warn(unreachable_pub)]

use acvm::acir::circuit::Circuit;

use acvm::Language;
use fm::FileType;
use noirc_abi::Abi;
Expand All @@ -14,20 +12,16 @@ use noirc_frontend::hir::def_map::CrateDefMap;
use noirc_frontend::hir::Context;
use noirc_frontend::monomorphization::monomorphize;
use noirc_frontend::node_interner::FuncId;
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};

mod program;
pub use program::CompiledProgram;

pub struct Driver {
context: Context,
language: Language,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CompiledProgram {
pub circuit: Circuit,
pub abi: noirc_abi::Abi,
}

impl Driver {
pub fn new(np_language: &Language) -> Self {
let mut driver = Driver { context: Context::default(), language: np_language.clone() };
Expand Down
29 changes: 29 additions & 0 deletions crates/noirc_driver/src/program.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use acvm::acir::circuit::Circuit;

use serde::{Deserialize, Deserializer, Serialize, Serializer};

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CompiledProgram {
#[serde(serialize_with = "serialize_circuit", deserialize_with = "deserialize_circuit")]
pub circuit: Circuit,
pub abi: noirc_abi::Abi,
}

fn serialize_circuit<S>(circuit: &Circuit, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut circuit_bytes: Vec<u8> = Vec::new();
circuit.write(&mut circuit_bytes).unwrap();

circuit_bytes.serialize(s)
}

fn deserialize_circuit<'de, D>(deserializer: D) -> Result<Circuit, D::Error>
where
D: Deserializer<'de>,
{
let circuit_bytes = Vec::<u8>::deserialize(deserializer)?;
let circuit = Circuit::read(&*circuit_bytes).unwrap();
Ok(circuit)
}

0 comments on commit ddaf305

Please sign in to comment.