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

chore: move nargo I/O into separate module #896

Merged
merged 3 commits into from
Feb 22, 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
3 changes: 2 additions & 1 deletion crates/nargo/src/cli/check_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use std::{
path::{Path, PathBuf},
};

use super::{add_std_lib, write_to_file, NargoConfig};
use super::fs::write_to_file;
use super::{add_std_lib, NargoConfig};
use crate::constants::{PROVER_INPUT_FILE, VERIFIER_INPUT_FILE};

/// Checks the constraint system for errors
Expand Down
49 changes: 4 additions & 45 deletions crates/nargo/src/cli/compile_cmd.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
use acvm::acir::circuit::Circuit;
use acvm::ProofSystemCompiler;
use acvm::{acir::circuit::Circuit, hash_constraint_system};
use std::path::{Path, PathBuf};

use clap::Args;

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

use super::{add_std_lib, create_named_dir, write_to_file, NargoConfig};
use super::fs::{acir::save_acir_to_dir, keys::save_key_to_dir};
use super::{add_std_lib, NargoConfig};

/// Compile the program and its secret execution trace into ACIR format
#[derive(Debug, Clone, Args)]
Expand Down Expand Up @@ -81,41 +78,3 @@ fn preprocess_with_path<P: AsRef<Path>>(

Ok((pk_path, vk_path))
}

fn save_acir_to_dir<P: AsRef<Path>>(
circuit: &Circuit,
circuit_name: &str,
circuit_dir: P,
) -> PathBuf {
let mut circuit_path = create_named_dir(circuit_dir.as_ref(), "target");
circuit_path.push(circuit_name);

let mut serialized = Vec::new();
circuit.write(&mut serialized).expect("could not serialize circuit");

circuit_path.set_extension(ACIR_EXT);
write_to_file(serialized.as_slice(), &circuit_path);

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

circuit_path
}

fn save_key_to_dir<P: AsRef<Path>>(
key: Vec<u8>,
key_name: &str,
key_dir: P,
is_proving_key: bool,
) -> Result<PathBuf, CliError> {
let mut key_path = create_named_dir(key_dir.as_ref(), key_name);
key_path.push(key_name);
let extension = if is_proving_key { PK_EXT } else { VK_EXT };
key_path.set_extension(extension);

write_to_file(hex::encode(key).as_bytes(), &key_path);

Ok(key_path)
}
3 changes: 2 additions & 1 deletion crates/nargo/src/cli/contract_cmd.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::{create_named_dir, write_to_file, NargoConfig};
use super::fs::{create_named_dir, write_to_file};
use super::NargoConfig;
use crate::{cli::compile_cmd::compile_circuit, constants::CONTRACT_DIR, errors::CliError};
use acvm::SmartContract;
use clap::Args;
Expand Down
23 changes: 3 additions & 20 deletions crates/nargo/src/cli/execute_cmd.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
use std::path::{Path, PathBuf};
use std::path::Path;

use acvm::acir::native_types::Witness;
use acvm::PartialWitnessGenerator;
use clap::Args;
use noirc_abi::input_parser::{Format, InputValue};
use noirc_abi::{InputMap, WitnessMap};
use noirc_driver::CompiledProgram;

use super::fs::{inputs::read_inputs_from_file, witness::save_witness_to_dir};
use super::NargoConfig;
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},
constants::{PROVER_INPUT_FILE, TARGET_DIR},
errors::CliError,
};

Expand Down Expand Up @@ -83,19 +82,3 @@ pub(crate) fn execute_program(

Ok(solved_witness)
}

pub(crate) fn save_witness_to_dir<P: AsRef<Path>>(
witness: WitnessMap,
witness_name: &str,
witness_dir: P,
) -> Result<PathBuf, CliError> {
let mut witness_path = create_named_dir(witness_dir.as_ref(), "witness");
witness_path.push(witness_name);
witness_path.set_extension(WITNESS_EXT);

let buf = Witness::to_bytes(&witness);

write_to_file(buf.as_slice(), &witness_path);

Ok(witness_path)
}
29 changes: 29 additions & 0 deletions crates/nargo/src/cli/fs/acir.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use std::path::{Path, PathBuf};

use acvm::{acir::circuit::Circuit, hash_constraint_system};

use crate::constants::ACIR_EXT;

use super::{create_named_dir, write_to_file};

pub(crate) fn save_acir_to_dir<P: AsRef<Path>>(
circuit: &Circuit,
circuit_name: &str,
circuit_dir: P,
) -> PathBuf {
let mut circuit_path = create_named_dir(circuit_dir.as_ref(), "target");
circuit_path.push(circuit_name);

let mut serialized = Vec::new();
circuit.write(&mut serialized).expect("could not serialize circuit");

circuit_path.set_extension(ACIR_EXT);
write_to_file(serialized.as_slice(), &circuit_path);

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

circuit_path
}
75 changes: 75 additions & 0 deletions crates/nargo/src/cli/fs/inputs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use noirc_abi::{
input_parser::{Format, InputValue},
Abi, InputMap, MAIN_RETURN_NAME,
};
use std::{collections::BTreeMap, path::Path};

use crate::errors::CliError;

use super::write_to_file;

/// Returns the circuit's parameters and its return value, if one exists.
/// # Examples
///
/// ```ignore
/// let (input_map, return_value): (InputMap, Option<InputValue>) =
/// read_inputs_from_file(path, "Verifier", Format::Toml, &abi)?;
/// ```
pub fn read_inputs_from_file<P: AsRef<Path>>(
path: P,
file_name: &str,
format: Format,
abi: &Abi,
) -> Result<(InputMap, Option<InputValue>), CliError> {
if abi.is_empty() {
return Ok((BTreeMap::new(), None));
}

let file_path = {
let mut dir_path = path.as_ref().to_path_buf();
dir_path.push(file_name);
dir_path.set_extension(format.ext());
dir_path
};
if !file_path.exists() {
return Err(CliError::MissingTomlFile(file_name.to_owned(), file_path));
}

let input_string = std::fs::read_to_string(file_path).unwrap();
let mut input_map = format.parse(&input_string, abi)?;
let return_value = input_map.remove(MAIN_RETURN_NAME);

Ok((input_map, return_value))
}

pub fn write_inputs_to_file<P: AsRef<Path>>(
input_map: &InputMap,
return_value: &Option<InputValue>,
path: P,
file_name: &str,
format: Format,
) -> Result<(), CliError> {
let file_path = {
let mut dir_path = path.as_ref().to_path_buf();
dir_path.push(file_name);
dir_path.set_extension(format.ext());
dir_path
};

// We must insert the return value into the `InputMap` in order for it to be written to file.
let serialized_output = match return_value {
// Parameters and return values are kept separate except for when they're being written to file.
// As a result, we don't want to modify the original map and must clone it before insertion.
Some(return_value) => {
let mut input_map = input_map.clone();
input_map.insert(MAIN_RETURN_NAME.to_owned(), return_value.clone());
format.serialize(&input_map)?
}
// If no return value exists, then we can serialize the original map directly.
None => format.serialize(input_map)?,
};

write_to_file(serialized_output.as_bytes(), &file_path);

Ok(())
}
68 changes: 68 additions & 0 deletions crates/nargo/src/cli/fs/keys.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use std::path::{Path, PathBuf};

use acvm::{acir::circuit::Circuit, hash_constraint_system};

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

use super::{create_named_dir, load_hex_data, write_to_file};

pub(crate) fn save_key_to_dir<P: AsRef<Path>>(
key: Vec<u8>,
key_name: &str,
key_dir: P,
is_proving_key: bool,
) -> Result<PathBuf, CliError> {
let mut key_path = create_named_dir(key_dir.as_ref(), key_name);
key_path.push(key_name);
let extension = if is_proving_key { PK_EXT } else { VK_EXT };
key_path.set_extension(extension);

write_to_file(hex::encode(key).as_bytes(), &key_path);

Ok(key_path)
}

pub(crate) fn fetch_pk_and_vk<P: AsRef<Path>>(
circuit: &Circuit,
circuit_build_path: P,
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 expected_acir_hash = load_hex_data(acir_hash_path.clone())?;

let new_acir_hash = hash_constraint_system(circuit);

if new_acir_hash[..] != expected_acir_hash {
return Err(CliError::MismatchedAcir(acir_hash_path));
}

// This flag exists to avoid an unnecessary read of the proving key during verification
// as this method is used by both `nargo prove` and `nargo verify`
let proving_key = if prove_circuit {
let mut proving_key_path = PathBuf::new();
proving_key_path.push(circuit_build_path.as_ref());
proving_key_path.set_extension(PK_EXT);
load_hex_data(proving_key_path)?
} else {
// We can return an empty Vec here as `prove_circuit` should only be false when running `nargo verify`
vec![]
};

let verification_key = if check_proof {
let mut verification_key_path = PathBuf::new();
verification_key_path.push(circuit_build_path);
verification_key_path.set_extension(VK_EXT);
load_hex_data(verification_key_path)?
} else {
// We can return an empty Vec here as the verification key is used only is `check_proof` is true
vec![]
};

Ok((proving_key, verification_key))
}
47 changes: 47 additions & 0 deletions crates/nargo/src/cli/fs/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use std::{
fs::File,
io::Write,
path::{Path, PathBuf},
};

use crate::errors::CliError;

pub mod acir;
pub mod inputs;
pub mod keys;
pub mod proof;
pub mod witness;

fn create_dir<P: AsRef<Path>>(dir_path: P) -> Result<PathBuf, std::io::Error> {
let mut dir = std::path::PathBuf::new();
dir.push(dir_path);
std::fs::create_dir_all(&dir)?;
Ok(dir)
}

pub(crate) fn create_named_dir(named_dir: &Path, name: &str) -> PathBuf {
create_dir(named_dir).unwrap_or_else(|_| panic!("could not create the `{name}` directory"))
}

pub(crate) fn write_to_file(bytes: &[u8], path: &Path) -> String {
let display = path.display();

let mut file = match File::create(path) {
Err(why) => panic!("couldn't create {display}: {why}"),
Ok(file) => file,
};

match file.write_all(bytes) {
Err(why) => panic!("couldn't write to {display}: {why}"),
Ok(_) => display.to_string(),
}
}

pub fn load_hex_data<P: AsRef<Path>>(path: P) -> Result<Vec<u8>, CliError> {
let hex_data: Vec<_> =
std::fs::read(&path).map_err(|_| CliError::PathNotValid(path.as_ref().to_path_buf()))?;

let raw_bytes = hex::decode(hex_data).map_err(CliError::HexArtifactNotValid)?;

Ok(raw_bytes)
}
19 changes: 19 additions & 0 deletions crates/nargo/src/cli/fs/proof.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use std::path::{Path, PathBuf};

use crate::{constants::PROOF_EXT, errors::CliError};

use super::{create_named_dir, write_to_file};

pub(crate) fn save_proof_to_dir<P: AsRef<Path>>(
proof: &[u8],
proof_name: &str,
proof_dir: P,
) -> Result<PathBuf, CliError> {
let mut proof_path = create_named_dir(proof_dir.as_ref(), "proof");
proof_path.push(proof_name);
proof_path.set_extension(PROOF_EXT);

write_to_file(hex::encode(proof).as_bytes(), &proof_path);

Ok(proof_path)
}
23 changes: 23 additions & 0 deletions crates/nargo/src/cli/fs/witness.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use std::path::{Path, PathBuf};

use acvm::acir::native_types::Witness;
use noirc_abi::WitnessMap;

use super::{create_named_dir, write_to_file};
use crate::{constants::WITNESS_EXT, errors::CliError};

pub(crate) fn save_witness_to_dir<P: AsRef<Path>>(
witness: WitnessMap,
witness_name: &str,
witness_dir: P,
) -> Result<PathBuf, CliError> {
let mut witness_path = create_named_dir(witness_dir.as_ref(), "witness");
witness_path.push(witness_name);
witness_path.set_extension(WITNESS_EXT);

let buf = Witness::to_bytes(&witness);

write_to_file(buf.as_slice(), &witness_path);

Ok(witness_path)
}
Loading