diff --git a/Cargo.lock b/Cargo.lock index 7a631368870..78698b9ebc0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,21 +4,20 @@ version = 3 [[package]] name = "acir" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "510b65efd4d20bf266185ce0a5dc7d29bcdd196a6a1835c20908fd88040de76c" +version = "0.11.0" +source = "git+https://github.com/noir-lang/acvm?rev=c395c55b7acc84b10dbe6896398ca4df32b2a48a#c395c55b7acc84b10dbe6896398ca4df32b2a48a" dependencies = [ "acir_field", "flate2", "rmp-serde", "serde", + "thiserror", ] [[package]] name = "acir_field" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f032e710c67fd146caedc8fe1dea6e95f01ab59453e42d59b604a51fef3dfe" +version = "0.11.0" +source = "git+https://github.com/noir-lang/acvm?rev=c395c55b7acc84b10dbe6896398ca4df32b2a48a#c395c55b7acc84b10dbe6896398ca4df32b2a48a" dependencies = [ "ark-bn254", "ark-ff", @@ -30,9 +29,8 @@ dependencies = [ [[package]] name = "acvm" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2611266039740ffd1978f23258bd6ce3166c22cf15b8227685c2f3bb20ae2ee0" +version = "0.11.0" +source = "git+https://github.com/noir-lang/acvm?rev=c395c55b7acc84b10dbe6896398ca4df32b2a48a#c395c55b7acc84b10dbe6896398ca4df32b2a48a" dependencies = [ "acir", "acvm_stdlib", @@ -42,18 +40,18 @@ dependencies = [ "k256", "num-bigint", "num-traits", - "sha2 0.9.9", + "sha2 0.10.6", + "sha3", "thiserror", ] [[package]] name = "acvm-backend-barretenberg" -version = "0.0.0" -source = "git+https://github.com/noir-lang/aztec_backend?rev=677f10e07011849f8aa0d75fe80390bb3081b1e5#677f10e07011849f8aa0d75fe80390bb3081b1e5" +version = "0.1.2" +source = "git+https://github.com/noir-lang/acvm-backend-barretenberg?rev=030a7e7b9ba842f3d307dbab178962b63d0dedcf#030a7e7b9ba842f3d307dbab178962b63d0dedcf" dependencies = [ "acvm", "barretenberg-sys", - "blake2", "dirs 3.0.2", "futures-util", "getrandom", @@ -61,16 +59,15 @@ dependencies = [ "pkg-config", "reqwest", "rust-embed", - "sha3", + "thiserror", "tokio", "wasmer", ] [[package]] name = "acvm_stdlib" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5ec51160c66eba75dc15a028a2391675386fd395b3897478d89a386c64a48dd" +version = "0.11.0" +source = "git+https://github.com/noir-lang/acvm?rev=c395c55b7acc84b10dbe6896398ca4df32b2a48a#c395c55b7acc84b10dbe6896398ca4df32b2a48a" dependencies = [ "acir", ] @@ -372,13 +369,11 @@ dependencies = [ [[package]] name = "blake2" -version = "0.9.2" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a4e37d16930f5459780f5621038b6382b9bb37c19016f39fb6b5808d831f174" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" dependencies = [ - "crypto-mac 0.8.0", - "digest 0.9.0", - "opaque-debug", + "digest 0.10.6", ] [[package]] @@ -387,7 +382,6 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "block-padding", "generic-array", ] @@ -400,12 +394,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "block-padding" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" - [[package]] name = "bstr" version = "1.4.0" @@ -822,16 +810,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "crypto-mac" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "crypto-mac" version = "0.10.1" @@ -963,6 +941,7 @@ checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" dependencies = [ "block-buffer 0.10.4", "crypto-common", + "subtle", ] [[package]] @@ -1446,7 +1425,7 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" dependencies = [ - "crypto-mac 0.10.1", + "crypto-mac", "digest 0.9.0", ] @@ -2840,14 +2819,12 @@ dependencies = [ [[package]] name = "sha3" -version = "0.9.1" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ - "block-buffer 0.9.0", - "digest 0.9.0", + "digest 0.10.6", "keccak", - "opaque-debug", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index badaab032ce..67dfa24a797 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ edition = "2021" rust-version = "1.66" [workspace.dependencies] -acvm = "0.10.3" +acvm = "0.11.0" arena = { path = "crates/arena" } fm = { path = "crates/fm" } iter-extended = { path = "crates/iter-extended" } @@ -50,3 +50,7 @@ toml = "0.7.2" url = "2.2.0" wasm-bindgen = { version = "0.2.83", features = ["serde-serialize"] } wasm-bindgen-test = "0.3.33" + +[patch.crates-io] +acvm = { package = "acvm", git = "https://github.com/noir-lang/acvm", rev = "c395c55b7acc84b10dbe6896398ca4df32b2a48a" } +acvm-backend-barretenberg = { git = "https://github.com/noir-lang/acvm-backend-barretenberg", rev = "030a7e7b9ba842f3d307dbab178962b63d0dedcf" } diff --git a/crates/nargo/src/ops/codegen_verifier.rs b/crates/nargo/src/ops/codegen_verifier.rs index ead125699b4..2a0b54df865 100644 --- a/crates/nargo/src/ops/codegen_verifier.rs +++ b/crates/nargo/src/ops/codegen_verifier.rs @@ -1,10 +1,8 @@ use acvm::SmartContract; -use crate::NargoError; - -pub fn codegen_verifier( - backend: &impl SmartContract, +pub fn codegen_verifier( + backend: &B, verification_key: &[u8], -) -> Result { - Ok(backend.eth_contract_from_vk(verification_key)) +) -> Result { + backend.eth_contract_from_vk(verification_key) } diff --git a/crates/nargo/src/ops/execute.rs b/crates/nargo/src/ops/execute.rs index e4c8a5afbb5..98d525525da 100644 --- a/crates/nargo/src/ops/execute.rs +++ b/crates/nargo/src/ops/execute.rs @@ -1,6 +1,7 @@ +use acvm::acir::native_types::WitnessMap; +use acvm::pwg::{solve, PartialWitnessGeneratorStatus}; +use acvm::PartialWitnessGenerator; use acvm::{acir::circuit::Circuit, pwg::block::Blocks}; -use acvm::{PartialWitnessGenerator, PartialWitnessGeneratorStatus}; -use noirc_abi::WitnessMap; use crate::NargoError; @@ -10,7 +11,7 @@ pub fn execute_circuit( mut initial_witness: WitnessMap, ) -> Result { let mut blocks = Blocks::default(); - let solver_status = backend.solve(&mut initial_witness, &mut blocks, circuit.opcodes)?; + let solver_status = solve(backend, &mut initial_witness, &mut blocks, circuit.opcodes)?; if matches!(solver_status, PartialWitnessGeneratorStatus::RequiresOracleData { .. }) { todo!("Add oracle support to nargo execute") } diff --git a/crates/nargo/src/ops/preprocess.rs b/crates/nargo/src/ops/preprocess.rs index f8d4eb5a825..3be8151f9c9 100644 --- a/crates/nargo/src/ops/preprocess.rs +++ b/crates/nargo/src/ops/preprocess.rs @@ -1,26 +1,23 @@ use acvm::ProofSystemCompiler; -use iter_extended::vecmap; +use iter_extended::try_vecmap; use noirc_driver::{CompiledContract, CompiledProgram}; -use crate::{ - artifacts::{ - contract::{PreprocessedContract, PreprocessedContractFunction}, - program::PreprocessedProgram, - }, - NargoError, +use crate::artifacts::{ + contract::{PreprocessedContract, PreprocessedContractFunction}, + program::PreprocessedProgram, }; // TODO: pull this from backend. const BACKEND_IDENTIFIER: &str = "acvm-backend-barretenberg"; -pub fn preprocess_program( - backend: &impl ProofSystemCompiler, +pub fn preprocess_program( + backend: &B, compiled_program: CompiledProgram, -) -> Result { +) -> Result { // TODO: currently `compiled_program`'s bytecode is already optimized for the backend. // In future we'll need to apply those optimizations here. let optimized_bytecode = compiled_program.circuit; - let (proving_key, verification_key) = backend.preprocess(&optimized_bytecode); + let (proving_key, verification_key) = backend.preprocess(&optimized_bytecode)?; Ok(PreprocessedProgram { backend: String::from(BACKEND_IDENTIFIER), @@ -31,17 +28,17 @@ pub fn preprocess_program( }) } -pub fn preprocess_contract( - backend: &impl ProofSystemCompiler, +pub fn preprocess_contract( + backend: &B, compiled_contract: CompiledContract, -) -> Result { - let preprocessed_contract_functions = vecmap(compiled_contract.functions, |func| { +) -> Result { + let preprocessed_contract_functions = try_vecmap(compiled_contract.functions, |func| { // TODO: currently `func`'s bytecode is already optimized for the backend. // In future we'll need to apply those optimizations here. let optimized_bytecode = func.bytecode; - let (proving_key, verification_key) = backend.preprocess(&optimized_bytecode); + let (proving_key, verification_key) = backend.preprocess(&optimized_bytecode)?; - PreprocessedContractFunction { + Ok(PreprocessedContractFunction { name: func.name, function_type: func.function_type, abi: func.abi, @@ -49,8 +46,8 @@ pub fn preprocess_contract( bytecode: optimized_bytecode, proving_key, verification_key, - } - }); + }) + })?; Ok(PreprocessedContract { name: compiled_contract.name, diff --git a/crates/nargo/src/ops/prove.rs b/crates/nargo/src/ops/prove.rs index 376220a8a74..523b2ed5ed4 100644 --- a/crates/nargo/src/ops/prove.rs +++ b/crates/nargo/src/ops/prove.rs @@ -1,16 +1,11 @@ -use acvm::acir::circuit::Circuit; +use acvm::acir::{circuit::Circuit, native_types::WitnessMap}; use acvm::ProofSystemCompiler; -use noirc_abi::WitnessMap; -use crate::NargoError; - -pub fn prove_execution( - backend: &impl ProofSystemCompiler, +pub fn prove_execution( + backend: &B, circuit: &Circuit, solved_witness: WitnessMap, proving_key: &[u8], -) -> Result, NargoError> { - let proof = backend.prove_with_pk(circuit, solved_witness, proving_key); - - Ok(proof) +) -> Result, B::Error> { + backend.prove_with_pk(circuit, solved_witness, proving_key) } diff --git a/crates/nargo/src/ops/verify.rs b/crates/nargo/src/ops/verify.rs index 5109d2291db..f2145e3cf87 100644 --- a/crates/nargo/src/ops/verify.rs +++ b/crates/nargo/src/ops/verify.rs @@ -1,17 +1,12 @@ -use acvm::acir::circuit::Circuit; +use acvm::acir::{circuit::Circuit, native_types::WitnessMap}; use acvm::ProofSystemCompiler; -use noirc_abi::WitnessMap; -use crate::NargoError; - -pub fn verify_proof( - backend: &impl ProofSystemCompiler, +pub fn verify_proof( + backend: &B, circuit: &Circuit, proof: &[u8], public_inputs: WitnessMap, verification_key: &[u8], -) -> Result { - let valid_proof = backend.verify_with_vk(proof, public_inputs, circuit, verification_key); - - Ok(valid_proof) +) -> Result { + backend.verify_with_vk(proof, public_inputs, circuit, verification_key) } diff --git a/crates/nargo_cli/Cargo.toml b/crates/nargo_cli/Cargo.toml index 6e8801301b1..74db54c8ef7 100644 --- a/crates/nargo_cli/Cargo.toml +++ b/crates/nargo_cli/Cargo.toml @@ -37,7 +37,7 @@ termcolor = "1.1.2" color-eyre = "0.6.2" # Backends -acvm-backend-barretenberg = { git = "https://github.com/noir-lang/aztec_backend", rev = "677f10e07011849f8aa0d75fe80390bb3081b1e5", default-features = false } +acvm-backend-barretenberg = { version = "0.1.2", default-features = false } [dev-dependencies] tempdir = "0.3.7" diff --git a/crates/nargo_cli/src/cli/check_cmd.rs b/crates/nargo_cli/src/cli/check_cmd.rs index 3049c830def..9664930466b 100644 --- a/crates/nargo_cli/src/cli/check_cmd.rs +++ b/crates/nargo_cli/src/cli/check_cmd.rs @@ -1,5 +1,5 @@ use crate::{errors::CliError, resolver::Resolver}; -use acvm::ProofSystemCompiler; +use acvm::Backend; use clap::Args; use iter_extended::btree_map; use noirc_abi::{AbiParameter, AbiType, MAIN_RETURN_NAME}; @@ -17,15 +17,21 @@ pub(crate) struct CheckCommand { compile_options: CompileOptions, } -pub(crate) fn run(args: CheckCommand, config: NargoConfig) -> Result<(), CliError> { - check_from_path(config.program_dir, &args.compile_options)?; +pub(crate) fn run( + backend: &B, + args: CheckCommand, + config: NargoConfig, +) -> Result<(), CliError> { + check_from_path(backend, config.program_dir, &args.compile_options)?; println!("Constraint system successfully built!"); Ok(()) } -fn check_from_path>(p: P, compile_options: &CompileOptions) -> Result<(), CliError> { - let backend = crate::backends::ConcreteBackend::default(); - +fn check_from_path>( + backend: &B, + p: P, + compile_options: &CompileOptions, +) -> Result<(), CliError> { let mut driver = Resolver::resolve_root_manifest(p.as_ref(), backend.np_language())?; driver.check_crate(compile_options).map_err(|_| CliError::CompilationError)?; @@ -148,12 +154,13 @@ d2 = ["", "", ""] let pass_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(format!("{TEST_DATA_DIR}/pass")); + let backend = crate::backends::ConcreteBackend::default(); let config = CompileOptions::default(); let paths = std::fs::read_dir(pass_dir).unwrap(); for path in paths.flatten() { let path = path.path(); assert!( - super::check_from_path(path.clone(), &config).is_ok(), + super::check_from_path(&backend, path.clone(), &config).is_ok(), "path: {}", path.display() ); @@ -166,12 +173,13 @@ d2 = ["", "", ""] let fail_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(format!("{TEST_DATA_DIR}/fail")); + let backend = crate::backends::ConcreteBackend::default(); let config = CompileOptions::default(); let paths = std::fs::read_dir(fail_dir).unwrap(); for path in paths.flatten() { let path = path.path(); assert!( - super::check_from_path(path.clone(), &config).is_err(), + super::check_from_path(&backend, path.clone(), &config).is_err(), "path: {}", path.display() ); @@ -183,13 +191,14 @@ d2 = ["", "", ""] let pass_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")) .join(format!("{TEST_DATA_DIR}/pass_dev_mode")); + let backend = crate::backends::ConcreteBackend::default(); let config = CompileOptions { allow_warnings: true, ..Default::default() }; let paths = std::fs::read_dir(pass_dir).unwrap(); for path in paths.flatten() { let path = path.path(); assert!( - super::check_from_path(path.clone(), &config).is_ok(), + super::check_from_path(&backend, path.clone(), &config).is_ok(), "path: {}", path.display() ); diff --git a/crates/nargo_cli/src/cli/codegen_verifier_cmd.rs b/crates/nargo_cli/src/cli/codegen_verifier_cmd.rs index f23502a15b5..d38433e2d1c 100644 --- a/crates/nargo_cli/src/cli/codegen_verifier_cmd.rs +++ b/crates/nargo_cli/src/cli/codegen_verifier_cmd.rs @@ -4,6 +4,7 @@ use crate::{ cli::compile_cmd::compile_circuit, constants::CONTRACT_DIR, constants::TARGET_DIR, errors::CliError, }; +use acvm::Backend; use clap::Args; use nargo::ops::{codegen_verifier, preprocess_program}; use noirc_driver::CompileOptions; @@ -18,9 +19,11 @@ pub(crate) struct CodegenVerifierCommand { compile_options: CompileOptions, } -pub(crate) fn run(args: CodegenVerifierCommand, config: NargoConfig) -> Result<(), CliError> { - let backend = crate::backends::ConcreteBackend::default(); - +pub(crate) fn run( + backend: &B, + args: CodegenVerifierCommand, + config: NargoConfig, +) -> Result<(), CliError> { // TODO(#1201): Should this be a utility function? let circuit_build_path = args .circuit_name @@ -30,12 +33,14 @@ pub(crate) fn run(args: CodegenVerifierCommand, config: NargoConfig) -> Result<( Some(circuit_build_path) => read_program_from_file(circuit_build_path)?, None => { let compiled_program = - compile_circuit(&backend, config.program_dir.as_ref(), &args.compile_options)?; - preprocess_program(&backend, compiled_program)? + compile_circuit(backend, config.program_dir.as_ref(), &args.compile_options)?; + preprocess_program(backend, compiled_program) + .map_err(CliError::ProofSystemCompilerError)? } }; - let smart_contract_string = codegen_verifier(&backend, &preprocessed_program.verification_key)?; + let smart_contract_string = codegen_verifier(backend, &preprocessed_program.verification_key) + .map_err(CliError::SmartContractError)?; let contract_dir = config.program_dir.join(CONTRACT_DIR); create_named_dir(&contract_dir, "contract"); diff --git a/crates/nargo_cli/src/cli/compile_cmd.rs b/crates/nargo_cli/src/cli/compile_cmd.rs index 78b52003166..531560b87db 100644 --- a/crates/nargo_cli/src/cli/compile_cmd.rs +++ b/crates/nargo_cli/src/cli/compile_cmd.rs @@ -1,4 +1,4 @@ -use acvm::ProofSystemCompiler; +use acvm::Backend; use iter_extended::try_vecmap; use noirc_driver::{CompileOptions, CompiledProgram, Driver}; use std::path::Path; @@ -27,19 +27,22 @@ pub(crate) struct CompileCommand { compile_options: CompileOptions, } -pub(crate) fn run(args: CompileCommand, config: NargoConfig) -> Result<(), CliError> { +pub(crate) fn run( + backend: &B, + args: CompileCommand, + config: NargoConfig, +) -> Result<(), CliError> { let circuit_dir = config.program_dir.join(TARGET_DIR); - let backend = crate::backends::ConcreteBackend::default(); - // If contracts is set we're compiling every function in a 'contract' rather than just 'main'. if args.contracts { - let mut driver = setup_driver(&backend, &config.program_dir)?; + let mut driver = setup_driver(backend, &config.program_dir)?; let compiled_contracts = driver .compile_contracts(&args.compile_options) .map_err(|_| CliError::CompilationError)?; - let preprocessed_contracts = - try_vecmap(compiled_contracts, |contract| preprocess_contract(&backend, contract))?; + let preprocessed_contracts = try_vecmap(compiled_contracts, |contract| { + preprocess_contract(backend, contract).map_err(CliError::ProofSystemCompilerError) + })?; for contract in preprocessed_contracts { save_contract_to_file( &contract, @@ -48,25 +51,26 @@ pub(crate) fn run(args: CompileCommand, config: NargoConfig) -> Result<(), CliEr ); } } else { - let program = compile_circuit(&backend, &config.program_dir, &args.compile_options)?; - let preprocessed_program = preprocess_program(&backend, program)?; + let program = compile_circuit(backend, &config.program_dir, &args.compile_options)?; + let preprocessed_program = + preprocess_program(backend, program).map_err(CliError::ProofSystemCompilerError)?; save_program_to_file(&preprocessed_program, &args.circuit_name, circuit_dir); } Ok(()) } -fn setup_driver( - backend: &impl ProofSystemCompiler, +fn setup_driver( + backend: &B, program_dir: &Path, ) -> Result { Resolver::resolve_root_manifest(program_dir, backend.np_language()) } -pub(crate) fn compile_circuit( - backend: &impl ProofSystemCompiler, +pub(crate) fn compile_circuit( + backend: &B, program_dir: &Path, compile_options: &CompileOptions, -) -> Result { +) -> Result> { let mut driver = setup_driver(backend, program_dir)?; driver.compile_main(compile_options).map_err(|_| CliError::CompilationError) } diff --git a/crates/nargo_cli/src/cli/execute_cmd.rs b/crates/nargo_cli/src/cli/execute_cmd.rs index b9b2be3febf..b597dfb17c8 100644 --- a/crates/nargo_cli/src/cli/execute_cmd.rs +++ b/crates/nargo_cli/src/cli/execute_cmd.rs @@ -1,10 +1,11 @@ use std::path::Path; use acvm::acir::circuit::Circuit; -use acvm::PartialWitnessGenerator; +use acvm::acir::native_types::WitnessMap; +use acvm::Backend; use clap::Args; use noirc_abi::input_parser::{Format, InputValue}; -use noirc_abi::{Abi, InputMap, WitnessMap}; +use noirc_abi::{Abi, InputMap}; use noirc_driver::{CompileOptions, CompiledProgram}; use super::fs::{inputs::read_inputs_from_file, witness::save_witness_to_dir}; @@ -25,9 +26,13 @@ pub(crate) struct ExecuteCommand { compile_options: CompileOptions, } -pub(crate) fn run(args: ExecuteCommand, config: NargoConfig) -> Result<(), CliError> { +pub(crate) fn run( + backend: &B, + args: ExecuteCommand, + config: NargoConfig, +) -> Result<(), CliError> { let (return_value, solved_witness) = - execute_with_path(&config.program_dir, &args.compile_options)?; + execute_with_path(backend, &config.program_dir, &args.compile_options)?; println!("Circuit witness successfully solved"); if let Some(return_value) = return_value { @@ -43,19 +48,18 @@ pub(crate) fn run(args: ExecuteCommand, config: NargoConfig) -> Result<(), CliEr Ok(()) } -fn execute_with_path( +fn execute_with_path( + backend: &B, program_dir: &Path, compile_options: &CompileOptions, -) -> Result<(Option, WitnessMap), CliError> { - let backend = crate::backends::ConcreteBackend::default(); - - let CompiledProgram { abi, circuit } = compile_circuit(&backend, program_dir, compile_options)?; +) -> Result<(Option, WitnessMap), CliError> { + let CompiledProgram { abi, circuit } = compile_circuit(backend, program_dir, compile_options)?; // Parse the initial witness values from Prover.toml let (inputs_map, _) = read_inputs_from_file(program_dir, PROVER_INPUT_FILE, Format::Toml, &abi)?; - let solved_witness = execute_program(&backend, circuit, &abi, &inputs_map)?; + let solved_witness = execute_program(backend, circuit, &abi, &inputs_map)?; let public_abi = abi.public_abi(); let (_, return_value) = public_abi.decode(&solved_witness)?; @@ -63,12 +67,12 @@ fn execute_with_path( Ok((return_value, solved_witness)) } -pub(crate) fn execute_program( - backend: &impl PartialWitnessGenerator, +pub(crate) fn execute_program( + backend: &B, circuit: Circuit, abi: &Abi, inputs_map: &InputMap, -) -> Result { +) -> Result> { let initial_witness = abi.encode(inputs_map, None)?; let solved_witness = nargo::ops::execute_circuit(backend, circuit, initial_witness)?; diff --git a/crates/nargo_cli/src/cli/fs/inputs.rs b/crates/nargo_cli/src/cli/fs/inputs.rs index dd9ce199720..eaf94cc22fd 100644 --- a/crates/nargo_cli/src/cli/fs/inputs.rs +++ b/crates/nargo_cli/src/cli/fs/inputs.rs @@ -4,7 +4,7 @@ use noirc_abi::{ }; use std::{collections::BTreeMap, path::Path}; -use crate::errors::CliError; +use crate::errors::FilesystemError; use super::write_to_file; @@ -20,14 +20,14 @@ pub(crate) fn read_inputs_from_file>( file_name: &str, format: Format, abi: &Abi, -) -> Result<(InputMap, Option), CliError> { +) -> Result<(InputMap, Option), FilesystemError> { if abi.is_empty() { return Ok((BTreeMap::new(), None)); } let file_path = path.as_ref().join(file_name).with_extension(format.ext()); if !file_path.exists() { - return Err(CliError::MissingTomlFile(file_name.to_owned(), file_path)); + return Err(FilesystemError::MissingTomlFile(file_name.to_owned(), file_path)); } let input_string = std::fs::read_to_string(file_path).unwrap(); @@ -43,7 +43,7 @@ pub(crate) fn write_inputs_to_file>( path: P, file_name: &str, format: Format, -) -> Result<(), CliError> { +) -> Result<(), FilesystemError> { let file_path = path.as_ref().join(file_name).with_extension(format.ext()); // We must insert the return value into the `InputMap` in order for it to be written to file. diff --git a/crates/nargo_cli/src/cli/fs/mod.rs b/crates/nargo_cli/src/cli/fs/mod.rs index d860f722fd1..4ebce3b3325 100644 --- a/crates/nargo_cli/src/cli/fs/mod.rs +++ b/crates/nargo_cli/src/cli/fs/mod.rs @@ -4,7 +4,7 @@ use std::{ path::{Path, PathBuf}, }; -use crate::errors::CliError; +use crate::errors::FilesystemError; pub(super) mod inputs; pub(super) mod program; @@ -32,11 +32,11 @@ pub(super) fn write_to_file(bytes: &[u8], path: &Path) -> String { } } -pub(super) fn load_hex_data>(path: P) -> Result, CliError> { - let hex_data: Vec<_> = - std::fs::read(&path).map_err(|_| CliError::PathNotValid(path.as_ref().to_path_buf()))?; +pub(super) fn load_hex_data>(path: P) -> Result, FilesystemError> { + let hex_data: Vec<_> = std::fs::read(&path) + .map_err(|_| FilesystemError::PathNotValid(path.as_ref().to_path_buf()))?; - let raw_bytes = hex::decode(hex_data).map_err(CliError::HexArtifactNotValid)?; + let raw_bytes = hex::decode(hex_data).map_err(FilesystemError::HexArtifactNotValid)?; Ok(raw_bytes) } diff --git a/crates/nargo_cli/src/cli/fs/program.rs b/crates/nargo_cli/src/cli/fs/program.rs index a3b5f4026bd..871a6023837 100644 --- a/crates/nargo_cli/src/cli/fs/program.rs +++ b/crates/nargo_cli/src/cli/fs/program.rs @@ -2,7 +2,7 @@ use std::path::{Path, PathBuf}; use nargo::artifacts::{contract::PreprocessedContract, program::PreprocessedProgram}; -use crate::errors::CliError; +use crate::errors::FilesystemError; use super::{create_named_dir, write_to_file}; @@ -35,10 +35,11 @@ fn save_build_artifact_to_file, T: ?Sized + serde::Serialize>( pub(crate) fn read_program_from_file>( circuit_path: P, -) -> Result { +) -> Result { 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 input_string = + std::fs::read(&file_path).map_err(|_| FilesystemError::PathNotValid(file_path))?; let program = serde_json::from_slice(&input_string).expect("could not deserialize program"); diff --git a/crates/nargo_cli/src/cli/fs/proof.rs b/crates/nargo_cli/src/cli/fs/proof.rs index 4a77595a54b..3a54aa908f8 100644 --- a/crates/nargo_cli/src/cli/fs/proof.rs +++ b/crates/nargo_cli/src/cli/fs/proof.rs @@ -1,6 +1,6 @@ use std::path::{Path, PathBuf}; -use crate::{constants::PROOF_EXT, errors::CliError}; +use crate::{constants::PROOF_EXT, errors::FilesystemError}; use super::{create_named_dir, write_to_file}; @@ -8,7 +8,7 @@ pub(crate) fn save_proof_to_dir>( proof: &[u8], proof_name: &str, proof_dir: P, -) -> Result { +) -> Result { create_named_dir(proof_dir.as_ref(), "proof"); let proof_path = proof_dir.as_ref().join(proof_name).with_extension(PROOF_EXT); diff --git a/crates/nargo_cli/src/cli/fs/witness.rs b/crates/nargo_cli/src/cli/fs/witness.rs index f3a5d3ea469..3b2ca2aab9f 100644 --- a/crates/nargo_cli/src/cli/fs/witness.rs +++ b/crates/nargo_cli/src/cli/fs/witness.rs @@ -1,20 +1,19 @@ use std::path::{Path, PathBuf}; -use acvm::acir::native_types::Witness; -use noirc_abi::WitnessMap; +use acvm::acir::native_types::WitnessMap; use super::{create_named_dir, write_to_file}; -use crate::{constants::WITNESS_EXT, errors::CliError}; +use crate::{constants::WITNESS_EXT, errors::FilesystemError}; pub(crate) fn save_witness_to_dir>( witness: WitnessMap, witness_name: &str, witness_dir: P, -) -> Result { +) -> Result { create_named_dir(witness_dir.as_ref(), "witness"); let witness_path = witness_dir.as_ref().join(witness_name).with_extension(WITNESS_EXT); - let buf = Witness::to_bytes(&witness); + let buf: Vec = witness.try_into()?; write_to_file(buf.as_slice(), &witness_path); diff --git a/crates/nargo_cli/src/cli/gates_cmd.rs b/crates/nargo_cli/src/cli/gates_cmd.rs index 9fe9f5c7a53..88e11c683eb 100644 --- a/crates/nargo_cli/src/cli/gates_cmd.rs +++ b/crates/nargo_cli/src/cli/gates_cmd.rs @@ -1,4 +1,4 @@ -use acvm::ProofSystemCompiler; +use acvm::Backend; use clap::Args; use noirc_driver::CompileOptions; use std::path::Path; @@ -15,17 +15,20 @@ pub(crate) struct GatesCommand { compile_options: CompileOptions, } -pub(crate) fn run(args: GatesCommand, config: NargoConfig) -> Result<(), CliError> { - count_gates_with_path(config.program_dir, &args.compile_options) +pub(crate) fn run( + backend: &B, + args: GatesCommand, + config: NargoConfig, +) -> Result<(), CliError> { + count_gates_with_path(backend, config.program_dir, &args.compile_options) } -fn count_gates_with_path>( +fn count_gates_with_path>( + backend: &B, program_dir: P, compile_options: &CompileOptions, -) -> Result<(), CliError> { - let backend = crate::backends::ConcreteBackend::default(); - - let compiled_program = compile_circuit(&backend, program_dir.as_ref(), compile_options)?; +) -> Result<(), CliError> { + let compiled_program = compile_circuit(backend, program_dir.as_ref(), compile_options)?; let num_opcodes = compiled_program.circuit.opcodes.len(); println!( @@ -34,7 +37,9 @@ fn count_gates_with_path>( num_opcodes ); - let exact_circuit_size = backend.get_exact_circuit_size(&compiled_program.circuit); + let exact_circuit_size = backend + .get_exact_circuit_size(&compiled_program.circuit) + .map_err(CliError::ProofSystemCompilerError)?; println!("Backend circuit size: {exact_circuit_size}"); Ok(()) diff --git a/crates/nargo_cli/src/cli/mod.rs b/crates/nargo_cli/src/cli/mod.rs index 5450bb39660..d41dc1a815a 100644 --- a/crates/nargo_cli/src/cli/mod.rs +++ b/crates/nargo_cli/src/cli/mod.rs @@ -67,17 +67,19 @@ pub fn start_cli() -> eyre::Result<()> { config.program_dir = find_package_root(&config.program_dir)?; } + let backend = crate::backends::ConcreteBackend::default(); + match command { - NargoCommand::New(args) => new_cmd::run(args, config), - NargoCommand::Check(args) => check_cmd::run(args, config), - NargoCommand::Compile(args) => compile_cmd::run(args, config), - NargoCommand::Execute(args) => execute_cmd::run(args, config), - NargoCommand::Prove(args) => prove_cmd::run(args, config), - NargoCommand::Verify(args) => verify_cmd::run(args, config), - NargoCommand::Test(args) => test_cmd::run(args, config), - NargoCommand::Gates(args) => gates_cmd::run(args, config), - NargoCommand::CodegenVerifier(args) => codegen_verifier_cmd::run(args, config), - NargoCommand::PrintAcir(args) => print_acir_cmd::run(args, config), + NargoCommand::New(args) => new_cmd::run(&backend, args, config), + NargoCommand::Check(args) => check_cmd::run(&backend, args, config), + NargoCommand::Compile(args) => compile_cmd::run(&backend, args, config), + NargoCommand::Execute(args) => execute_cmd::run(&backend, args, config), + NargoCommand::Prove(args) => prove_cmd::run(&backend, args, config), + NargoCommand::Verify(args) => verify_cmd::run(&backend, args, config), + NargoCommand::Test(args) => test_cmd::run(&backend, args, config), + NargoCommand::Gates(args) => gates_cmd::run(&backend, args, config), + NargoCommand::CodegenVerifier(args) => codegen_verifier_cmd::run(&backend, args, config), + NargoCommand::PrintAcir(args) => print_acir_cmd::run(&backend, args, config), }?; Ok(()) @@ -85,6 +87,8 @@ pub fn start_cli() -> eyre::Result<()> { // helper function which tests noir programs by trying to generate a proof and verify it pub fn prove_and_verify(proof_name: &str, program_dir: &Path, show_ssa: bool) -> bool { + let backend = crate::backends::ConcreteBackend::default(); + let compile_options = CompileOptions { show_ssa, allow_warnings: false, @@ -94,6 +98,7 @@ pub fn prove_and_verify(proof_name: &str, program_dir: &Path, show_ssa: bool) -> let proof_dir = program_dir.join(PROOFS_DIR); match prove_cmd::prove_with_path( + &backend, Some(proof_name.to_owned()), program_dir, &proof_dir, diff --git a/crates/nargo_cli/src/cli/new_cmd.rs b/crates/nargo_cli/src/cli/new_cmd.rs index 36146028454..5868c1e820e 100644 --- a/crates/nargo_cli/src/cli/new_cmd.rs +++ b/crates/nargo_cli/src/cli/new_cmd.rs @@ -5,6 +5,7 @@ use crate::{ use super::fs::{create_named_dir, write_to_file}; use super::{NargoConfig, CARGO_PKG_VERSION}; +use acvm::Backend; use clap::Args; use const_format::formatcp; use std::path::{Path, PathBuf}; @@ -33,13 +34,18 @@ const EXAMPLE: &str = r#"fn main(x : Field, y : pub Field) { #[test] fn test_main() { main(1, 2); - + // Uncomment to make test fail // main(1, 1); } "#; -pub(crate) fn run(args: NewCommand, config: NargoConfig) -> Result<(), CliError> { +pub(crate) fn run( + // Backend is currently unused, but we might want to use it to inform the "new" template in the future + _backend: &B, + args: NewCommand, + config: NargoConfig, +) -> Result<(), CliError> { let package_dir = config.program_dir.join(args.package_name); if package_dir.exists() { diff --git a/crates/nargo_cli/src/cli/print_acir_cmd.rs b/crates/nargo_cli/src/cli/print_acir_cmd.rs index 38b841121bc..420c57c6a08 100644 --- a/crates/nargo_cli/src/cli/print_acir_cmd.rs +++ b/crates/nargo_cli/src/cli/print_acir_cmd.rs @@ -1,3 +1,4 @@ +use acvm::Backend; use clap::Args; use noirc_driver::CompileOptions; use std::path::Path; @@ -14,17 +15,20 @@ pub(crate) struct PrintAcirCommand { compile_options: CompileOptions, } -pub(crate) fn run(args: PrintAcirCommand, config: NargoConfig) -> Result<(), CliError> { - print_acir_with_path(config.program_dir, &args.compile_options) +pub(crate) fn run( + backend: &B, + args: PrintAcirCommand, + config: NargoConfig, +) -> Result<(), CliError> { + print_acir_with_path(backend, config.program_dir, &args.compile_options) } -fn print_acir_with_path>( +fn print_acir_with_path>( + backend: &B, program_dir: P, compile_options: &CompileOptions, -) -> Result<(), CliError> { - let backend = crate::backends::ConcreteBackend::default(); - - let compiled_program = compile_circuit(&backend, program_dir.as_ref(), compile_options)?; +) -> Result<(), CliError> { + let compiled_program = compile_circuit(backend, program_dir.as_ref(), compile_options)?; println!("{}", compiled_program.circuit); Ok(()) diff --git a/crates/nargo_cli/src/cli/prove_cmd.rs b/crates/nargo_cli/src/cli/prove_cmd.rs index 2b9ed4b067a..d2adc8d4af1 100644 --- a/crates/nargo_cli/src/cli/prove_cmd.rs +++ b/crates/nargo_cli/src/cli/prove_cmd.rs @@ -1,5 +1,6 @@ use std::path::{Path, PathBuf}; +use acvm::Backend; use clap::Args; use nargo::artifacts::program::PreprocessedProgram; use nargo::ops::{preprocess_program, prove_execution, verify_proof}; @@ -38,7 +39,11 @@ pub(crate) struct ProveCommand { compile_options: CompileOptions, } -pub(crate) fn run(args: ProveCommand, config: NargoConfig) -> Result<(), CliError> { +pub(crate) fn run( + backend: &B, + args: ProveCommand, + config: NargoConfig, +) -> Result<(), CliError> { let proof_dir = config.program_dir.join(PROOFS_DIR); let circuit_build_path = args @@ -46,6 +51,7 @@ pub(crate) fn run(args: ProveCommand, config: NargoConfig) -> Result<(), CliErro .map(|circuit_name| config.program_dir.join(TARGET_DIR).join(circuit_name)); prove_with_path( + backend, args.proof_name, config.program_dir, proof_dir, @@ -57,22 +63,21 @@ pub(crate) fn run(args: ProveCommand, config: NargoConfig) -> Result<(), CliErro Ok(()) } -pub(crate) fn prove_with_path>( +pub(crate) fn prove_with_path>( + backend: &B, proof_name: Option, program_dir: P, proof_dir: P, circuit_build_path: Option, check_proof: bool, compile_options: &CompileOptions, -) -> Result, CliError> { - let backend = crate::backends::ConcreteBackend::default(); - +) -> Result, CliError> { let preprocessed_program = match circuit_build_path { Some(circuit_build_path) => read_program_from_file(circuit_build_path)?, None => { - let compiled_program = - compile_circuit(&backend, program_dir.as_ref(), compile_options)?; - preprocess_program(&backend, compiled_program)? + let compiled_program = compile_circuit(backend, program_dir.as_ref(), compile_options)?; + preprocess_program(backend, compiled_program) + .map_err(CliError::ProofSystemCompilerError)? } }; @@ -83,7 +88,7 @@ pub(crate) fn prove_with_path>( let (inputs_map, _) = read_inputs_from_file(&program_dir, PROVER_INPUT_FILE, Format::Toml, &abi)?; - let solved_witness = execute_program(&backend, bytecode.clone(), &abi, &inputs_map)?; + let solved_witness = execute_program(backend, bytecode.clone(), &abi, &inputs_map)?; // Write public inputs into Verifier.toml let public_abi = abi.public_abi(); @@ -97,12 +102,14 @@ pub(crate) fn prove_with_path>( Format::Toml, )?; - let proof = prove_execution(&backend, &bytecode, solved_witness, &proving_key)?; + let proof = prove_execution(backend, &bytecode, solved_witness, &proving_key) + .map_err(CliError::ProofSystemCompilerError)?; if check_proof { let public_inputs = public_abi.encode(&public_inputs, return_value)?; let valid_proof = - verify_proof(&backend, &bytecode, &proof, public_inputs, &verification_key)?; + verify_proof(backend, &bytecode, &proof, public_inputs, &verification_key) + .map_err(CliError::ProofSystemCompilerError)?; if !valid_proof { return Err(CliError::InvalidProof("".into())); diff --git a/crates/nargo_cli/src/cli/test_cmd.rs b/crates/nargo_cli/src/cli/test_cmd.rs index 65f8265a862..16857f4b3a1 100644 --- a/crates/nargo_cli/src/cli/test_cmd.rs +++ b/crates/nargo_cli/src/cli/test_cmd.rs @@ -1,6 +1,6 @@ -use std::{collections::BTreeMap, io::Write, path::Path}; +use std::{io::Write, path::Path}; -use acvm::ProofSystemCompiler; +use acvm::{acir::native_types::WitnessMap, Backend}; use clap::Args; use nargo::ops::execute_circuit; use noirc_driver::{CompileOptions, Driver}; @@ -21,19 +21,22 @@ pub(crate) struct TestCommand { compile_options: CompileOptions, } -pub(crate) fn run(args: TestCommand, config: NargoConfig) -> Result<(), CliError> { +pub(crate) fn run( + backend: &B, + args: TestCommand, + config: NargoConfig, +) -> Result<(), CliError> { let test_name: String = args.test_name.unwrap_or_else(|| "".to_owned()); - run_tests(&config.program_dir, &test_name, &args.compile_options) + run_tests(backend, &config.program_dir, &test_name, &args.compile_options) } -fn run_tests( +fn run_tests( + backend: &B, program_dir: &Path, test_name: &str, compile_options: &CompileOptions, -) -> Result<(), CliError> { - let backend = crate::backends::ConcreteBackend::default(); - +) -> Result<(), CliError> { let mut driver = Resolver::resolve_root_manifest(program_dir, backend.np_language())?; driver.check_crate(compile_options).map_err(|_| CliError::CompilationError)?; @@ -50,7 +53,7 @@ fn run_tests( writeln!(writer, "Testing {test_name}...").expect("Failed to write to stdout"); writer.flush().ok(); - match run_test(test_name, test_function, &driver, compile_options) { + match run_test(backend, test_name, test_function, &driver, compile_options) { Ok(_) => { writer.set_color(ColorSpec::new().set_fg(Some(Color::Green))).ok(); writeln!(writer, "ok").ok(); @@ -73,21 +76,20 @@ fn run_tests( Ok(()) } -fn run_test( +fn run_test( + backend: &B, test_name: &str, main: FuncId, driver: &Driver, config: &CompileOptions, -) -> Result<(), CliError> { - let backend = crate::backends::ConcreteBackend::default(); - +) -> Result<(), CliError> { let program = driver .compile_no_check(config, main) .map_err(|_| CliError::Generic(format!("Test '{test_name}' failed to compile")))?; // Run the backend to ensure the PWG evaluates functions like std::hash::pedersen, // otherwise constraints involving these expressions will not error. - match execute_circuit(&backend, program.circuit, BTreeMap::new()) { + match execute_circuit(backend, program.circuit, WitnessMap::new()) { Ok(_) => Ok(()), Err(error) => { let writer = StandardStream::stderr(ColorChoice::Always); diff --git a/crates/nargo_cli/src/cli/verify_cmd.rs b/crates/nargo_cli/src/cli/verify_cmd.rs index 84a6416d44e..07ba12d3899 100644 --- a/crates/nargo_cli/src/cli/verify_cmd.rs +++ b/crates/nargo_cli/src/cli/verify_cmd.rs @@ -6,6 +6,7 @@ use crate::{ errors::CliError, }; +use acvm::Backend; use clap::Args; use nargo::artifacts::program::PreprocessedProgram; use nargo::ops::preprocess_program; @@ -26,7 +27,11 @@ pub(crate) struct VerifyCommand { compile_options: CompileOptions, } -pub(crate) fn run(args: VerifyCommand, config: NargoConfig) -> Result<(), CliError> { +pub(crate) fn run( + backend: &B, + args: VerifyCommand, + config: NargoConfig, +) -> Result<(), CliError> { let proof_path = config.program_dir.join(PROOFS_DIR).join(&args.proof).with_extension(PROOF_EXT); @@ -35,6 +40,7 @@ pub(crate) fn run(args: VerifyCommand, config: NargoConfig) -> Result<(), CliErr .map(|circuit_name| config.program_dir.join(TARGET_DIR).join(circuit_name)); verify_with_path( + backend, &config.program_dir, proof_path, circuit_build_path.as_ref(), @@ -42,20 +48,20 @@ pub(crate) fn run(args: VerifyCommand, config: NargoConfig) -> Result<(), CliErr ) } -fn verify_with_path>( +fn verify_with_path>( + backend: &B, program_dir: P, proof_path: PathBuf, circuit_build_path: Option

, compile_options: CompileOptions, -) -> Result<(), CliError> { - let backend = crate::backends::ConcreteBackend::default(); - +) -> Result<(), CliError> { let preprocessed_program = match circuit_build_path { Some(circuit_build_path) => read_program_from_file(circuit_build_path)?, None => { let compiled_program = - compile_circuit(&backend, program_dir.as_ref(), &compile_options)?; - preprocess_program(&backend, compiled_program)? + compile_circuit(backend, program_dir.as_ref(), &compile_options)?; + preprocess_program(backend, compiled_program) + .map_err(CliError::ProofSystemCompilerError)? } }; @@ -70,7 +76,8 @@ fn verify_with_path>( let proof = load_hex_data(&proof_path)?; let valid_proof = - nargo::ops::verify_proof(&backend, &bytecode, &proof, public_inputs, &verification_key)?; + nargo::ops::verify_proof(backend, &bytecode, &proof, public_inputs, &verification_key) + .map_err(CliError::ProofSystemCompilerError)?; if valid_proof { Ok(()) diff --git a/crates/nargo_cli/src/errors.rs b/crates/nargo_cli/src/errors.rs index f6537b550ea..94772b578b4 100644 --- a/crates/nargo_cli/src/errors.rs +++ b/crates/nargo_cli/src/errors.rs @@ -1,3 +1,4 @@ +use acvm::{acir::native_types::WitnessMapError, Backend, ProofSystemCompiler, SmartContract}; use hex::FromHexError; use nargo::NargoError; use noirc_abi::errors::{AbiError, InputParserError}; @@ -7,11 +8,7 @@ use thiserror::Error; use crate::resolver::DependencyResolutionError; #[derive(Debug, Error)] -pub(crate) enum CliError { - #[error("{0}")] - Generic(String), - #[error("Error: destination {} already exists", .0.display())] - DestinationAlreadyExists(PathBuf), +pub(crate) enum FilesystemError { #[error("Error: {} is not a valid path\nRun either `nargo compile` to generate missing build artifacts or `nargo prove` to construct a proof", .0.display())] PathNotValid(PathBuf), #[error("Error: could not parse hex build artifact (proof, proving and/or verification keys, ACIR checksum) ({0})")] @@ -21,6 +18,22 @@ pub(crate) enum CliError { )] MissingTomlFile(String, PathBuf), + /// Input parsing error + #[error(transparent)] + InputParserError(#[from] InputParserError), + + /// WitnessMap serialization error + #[error(transparent)] + WitnessMapSerialization(#[from] WitnessMapError), +} + +#[derive(Debug, Error)] +pub(crate) enum CliError { + #[error("{0}")] + Generic(String), + #[error("Error: destination {} already exists", .0.display())] + DestinationAlreadyExists(PathBuf), + #[error("Failed to verify proof {}", .0.display())] InvalidProof(PathBuf), @@ -31,15 +44,23 @@ pub(crate) enum CliError { #[error("Failed to compile circuit")] CompilationError, - /// Input parsing error - #[error(transparent)] - InputParserError(#[from] InputParserError), - /// ABI encoding/decoding error #[error(transparent)] AbiError(#[from] AbiError), + /// Filesystem errors + #[error(transparent)] + FilesystemError(#[from] FilesystemError), + /// Error from Nargo #[error(transparent)] NargoError(#[from] NargoError), + + /// Backend error caused by a function on the SmartContract trait + #[error(transparent)] + SmartContractError(::Error), // Unfortunately, Rust won't let us `impl From` over an Associated Type on a generic + + /// Backend error caused by a function on the ProofSystemCompiler trait + #[error(transparent)] + ProofSystemCompilerError(::Error), // Unfortunately, Rust won't let us `impl From` over an Associated Type on a generic } diff --git a/crates/noirc_abi/src/lib.rs b/crates/noirc_abi/src/lib.rs index 191128b9407..56ed3728527 100644 --- a/crates/noirc_abi/src/lib.rs +++ b/crates/noirc_abi/src/lib.rs @@ -5,7 +5,10 @@ use std::{collections::BTreeMap, str}; -use acvm::{acir::native_types::Witness, FieldElement}; +use acvm::{ + acir::native_types::{Witness, WitnessMap}, + FieldElement, +}; use errors::AbiError; use input_parser::InputValue; use iter_extended::{try_btree_map, try_vecmap, vecmap}; @@ -22,9 +25,6 @@ mod serialization; /// A map from the fields in an TOML/JSON file which correspond to some ABI to their values pub type InputMap = BTreeMap; -/// A map from the witnesses in a constraint system to the field element values -pub type WitnessMap = BTreeMap; - /// A tuple of the arguments to a function along with its return value. pub type FunctionSignature = (Vec, Option); @@ -254,7 +254,7 @@ impl Abi { .collect::>()?; // Write input field elements into witness indices specified in `self.param_witnesses`. - let mut witness_map: WitnessMap = encoded_input_map + let mut witness_map: BTreeMap = encoded_input_map .iter() .flat_map(|(param_name, encoded_param_fields)| { let param_witness_indices = &self.param_witnesses[param_name]; @@ -297,7 +297,7 @@ impl Abi { (_, None) => {} } - Ok(witness_map) + Ok(witness_map.into()) } fn encode_value(value: InputValue) -> Result, AbiError> { diff --git a/crates/noirc_evaluator/src/lib.rs b/crates/noirc_evaluator/src/lib.rs index 533adce4325..4c70e15bcb4 100644 --- a/crates/noirc_evaluator/src/lib.rs +++ b/crates/noirc_evaluator/src/lib.rs @@ -13,7 +13,7 @@ pub mod ssa_refactor; use acvm::{ acir::circuit::{opcodes::Opcode as AcirOpcode, Circuit, PublicInputs}, acir::native_types::{Expression, Witness}, - compiler::transformers::IsOpcodeSupported, + compiler::{optimizers::simplify::CircuitSimplifier, transformers::IsOpcodeSupported}, Language, }; use errors::{RuntimeError, RuntimeErrorKind}; @@ -83,6 +83,7 @@ pub fn create_circuit( opcodes, .. } = evaluator; + let simplifier = CircuitSimplifier::new(current_witness_index); let optimized_circuit = acvm::compiler::compile( Circuit { current_witness_index, @@ -92,6 +93,7 @@ pub fn create_circuit( }, np_language, is_opcode_supported, + &simplifier, ) .map_err(|_| RuntimeErrorKind::Spanless(String::from("produced an acvm compile error")))?; diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/constraints.rs b/crates/noirc_evaluator/src/ssa/acir_gen/constraints.rs index 11371dc54a6..2d0378c3390 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/constraints.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/constraints.rs @@ -6,7 +6,7 @@ use crate::{ use acvm::{ acir::{ circuit::{ - directives::Directive, + directives::{Directive, QuotientDirective}, opcodes::{BlackBoxFuncCall, FunctionInput, Opcode as AcirOpcode}, }, native_types::{Expression, Witness}, @@ -265,13 +265,13 @@ pub(crate) fn range_constraint( let b_witness = evaluator.add_witness_to_cs(); let exp_big = BigUint::from(2_u128).pow(num_bits - 1); let exp = FieldElement::from_be_bytes_reduce(&exp_big.to_bytes_be()); - evaluator.push_opcode(AcirOpcode::Directive(Directive::Quotient { + evaluator.push_opcode(AcirOpcode::Directive(Directive::Quotient(QuotientDirective { a: Expression::from(witness), b: Expression::from_field(exp), q: b_witness, r: r_witness, predicate: None, - })); + }))); try_range_constraint(r_witness, num_bits - 1, evaluator); try_range_constraint(b_witness, 1, evaluator); @@ -283,10 +283,8 @@ pub(crate) fn range_constraint( let my_constraint = add(&res, -FieldElement::one(), &witness.into()); evaluator.push_opcode(AcirOpcode::Arithmetic(my_constraint)); } else { - let gate = AcirOpcode::BlackBoxFuncCall(BlackBoxFuncCall { - name: acvm::acir::BlackBoxFunc::RANGE, - inputs: vec![FunctionInput { witness, num_bits }], - outputs: vec![], + let gate = AcirOpcode::BlackBoxFuncCall(BlackBoxFuncCall::RANGE { + input: FunctionInput { witness, num_bits }, }); evaluator.push_opcode(gate); } @@ -311,13 +309,13 @@ pub(crate) fn bound_check( //2^s+a-b=q*2^s +r let expr = add(&r_witness.into(), two_s, &q_witness.into()); evaluator.push_opcode(AcirOpcode::Arithmetic(subtract(&sub, FieldElement::one(), &expr))); - evaluator.push_opcode(AcirOpcode::Directive(Directive::Quotient { + evaluator.push_opcode(AcirOpcode::Directive(Directive::Quotient(QuotientDirective { a: sub, b: Expression::from_field(two_s), q: q_witness, r: r_witness, predicate: None, - })); + }))); try_range_constraint(r_witness, max_bits, evaluator); evaluator.push_opcode(AcirOpcode::Arithmetic(boolean(q_witness))); q_witness @@ -504,13 +502,13 @@ pub(crate) fn evaluate_truncate( //1. Generate witnesses a,b,c let b_witness = evaluator.add_witness_to_cs(); let c_witness = evaluator.add_witness_to_cs(); - evaluator.push_opcode(AcirOpcode::Directive(Directive::Quotient { + evaluator.push_opcode(AcirOpcode::Directive(Directive::Quotient(QuotientDirective { a: lhs.clone(), b: Expression::from_field(exp), q: c_witness, r: b_witness, predicate: None, - })); + }))); try_range_constraint(b_witness, rhs, evaluator); //TODO propagate the error using ? try_range_constraint(c_witness, max_bits - rhs, evaluator); @@ -537,13 +535,13 @@ pub(crate) fn evaluate_udiv( let q_witness = evaluator.add_witness_to_cs(); let r_witness = evaluator.add_witness_to_cs(); let pa = mul_with_witness(evaluator, lhs, predicate); - evaluator.push_opcode(AcirOpcode::Directive(Directive::Quotient { + evaluator.push_opcode(AcirOpcode::Directive(Directive::Quotient(QuotientDirective { a: lhs.clone(), b: rhs.clone(), q: q_witness, r: r_witness, predicate: Some(predicate.clone()), - })); + }))); //r acvm::acir::BlackBoxFunc::AND, - BinaryOp::Xor => acvm::acir::BlackBoxFunc::XOR, + let gate = match opcode { + BinaryOp::And => AcirOpcode::BlackBoxFuncCall(BlackBoxFuncCall::AND { + lhs: FunctionInput { witness: a_witness, num_bits: bit_size }, + rhs: FunctionInput { witness: b_witness, num_bits: bit_size }, + output: result, + }), + BinaryOp::Xor => AcirOpcode::BlackBoxFuncCall(BlackBoxFuncCall::XOR { + lhs: FunctionInput { witness: a_witness, num_bits: bit_size }, + rhs: FunctionInput { witness: b_witness, num_bits: bit_size }, + output: result, + }), BinaryOp::Or => { a_witness = evaluator.create_intermediate_variable(constraints::subtract( &Expression::from_field(max), @@ -136,19 +144,15 @@ pub(super) fn evaluate_bitwise( &Expression::from(b_witness), )); // We do not have an OR gate yet, so we use the AND gate - acvm::acir::BlackBoxFunc::AND + AcirOpcode::BlackBoxFuncCall(BlackBoxFuncCall::AND { + lhs: FunctionInput { witness: a_witness, num_bits: bit_size }, + rhs: FunctionInput { witness: b_witness, num_bits: bit_size }, + output: result, + }) } _ => unreachable!("ICE: expected a bitwise operation"), }; - let gate = AcirOpcode::BlackBoxFuncCall(BlackBoxFuncCall { - name: bit_gate, - inputs: vec![ - FunctionInput { witness: a_witness, num_bits: bit_size }, - FunctionInput { witness: b_witness, num_bits: bit_size }, - ], - outputs: vec![result], - }); evaluator.opcodes.push(gate); if opcode == BinaryOp::Or { diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/operations/intrinsics.rs b/crates/noirc_evaluator/src/ssa/acir_gen/operations/intrinsics.rs index ea7d3d9c6c0..01d5fecc897 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/operations/intrinsics.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/operations/intrinsics.rs @@ -7,7 +7,7 @@ use crate::{ }, builtin, context::SsaContext, - mem::{ArrayId, Memory}, + mem::Memory, node::{self, Instruction, Node, NodeId, ObjectType}, }, Evaluator, @@ -19,6 +19,7 @@ use acvm::{ opcodes::{BlackBoxFuncCall, FunctionInput, Opcode as AcirOpcode}, }, native_types::{Expression, Witness}, + BlackBoxFunc, }, FieldElement, }; @@ -79,15 +80,70 @@ pub(crate) fn evaluate( } } Opcode::LowLevel(op) => { - let inputs = prepare_inputs(acir_gen, args, ctx, evaluator); - let output_count = op.definition().output_size.0 as u32; - outputs = - prepare_outputs(&mut acir_gen.memory, instruction_id, output_count, ctx, evaluator); - - let func_call = BlackBoxFuncCall { - name: op, - inputs, //witness + bit size - outputs: outputs.clone(), //witness + outputs = match op { + BlackBoxFunc::SHA256 | BlackBoxFunc::Blake2s => { + prepare_outputs(&mut acir_gen.memory, instruction_id, 32, ctx, evaluator) + } + BlackBoxFunc::Keccak256 => { + prepare_outputs(&mut acir_gen.memory, instruction_id, 32, ctx, evaluator) + } + BlackBoxFunc::Pedersen | BlackBoxFunc::FixedBaseScalarMul => { + prepare_outputs(&mut acir_gen.memory, instruction_id, 2, ctx, evaluator) + } + BlackBoxFunc::SchnorrVerify + | BlackBoxFunc::EcdsaSecp256k1 + | BlackBoxFunc::ComputeMerkleRoot + | BlackBoxFunc::HashToField128Security => { + prepare_outputs(&mut acir_gen.memory, instruction_id, 1, ctx, evaluator) + } + _ => panic!("Unsupported low level function {:?}", op), + }; + let func_call = match op { + BlackBoxFunc::SHA256 => BlackBoxFuncCall::SHA256 { + inputs: resolve_array(&args[0], acir_gen, ctx, evaluator), + outputs: outputs.to_vec(), + }, + BlackBoxFunc::Blake2s => BlackBoxFuncCall::Blake2s { + inputs: resolve_array(&args[0], acir_gen, ctx, evaluator), + outputs: outputs.to_vec(), + }, + BlackBoxFunc::Keccak256 => BlackBoxFuncCall::Keccak256 { + inputs: resolve_array(&args[0], acir_gen, ctx, evaluator), + outputs: outputs.to_vec(), + }, + BlackBoxFunc::Pedersen => BlackBoxFuncCall::Pedersen { + inputs: resolve_array(&args[0], acir_gen, ctx, evaluator), + outputs: outputs.to_vec(), + }, + BlackBoxFunc::FixedBaseScalarMul => BlackBoxFuncCall::FixedBaseScalarMul { + input: resolve_variable(&args[0], acir_gen, ctx, evaluator).unwrap(), + outputs: outputs.to_vec(), + }, + BlackBoxFunc::SchnorrVerify => BlackBoxFuncCall::SchnorrVerify { + public_key_x: resolve_variable(&args[0], acir_gen, ctx, evaluator).unwrap(), + public_key_y: resolve_variable(&args[1], acir_gen, ctx, evaluator).unwrap(), + signature: resolve_array(&args[2], acir_gen, ctx, evaluator), + message: resolve_array(&args[3], acir_gen, ctx, evaluator), + output: outputs[0], + }, + BlackBoxFunc::EcdsaSecp256k1 => BlackBoxFuncCall::EcdsaSecp256k1 { + public_key_x: resolve_array(&args[0], acir_gen, ctx, evaluator), + public_key_y: resolve_array(&args[1], acir_gen, ctx, evaluator), + signature: resolve_array(&args[2], acir_gen, ctx, evaluator), + hashed_message: resolve_array(&args[3], acir_gen, ctx, evaluator), + output: outputs[0], + }, + BlackBoxFunc::ComputeMerkleRoot => BlackBoxFuncCall::ComputeMerkleRoot { + leaf: resolve_variable(&args[0], acir_gen, ctx, evaluator).unwrap(), + index: resolve_variable(&args[1], acir_gen, ctx, evaluator).unwrap(), + hash_path: resolve_array(&args[2], acir_gen, ctx, evaluator), + output: outputs[0], + }, + BlackBoxFunc::HashToField128Security => BlackBoxFuncCall::HashToField128Security { + inputs: resolve_array(&args[0], acir_gen, ctx, evaluator), + output: outputs[0], + }, + _ => panic!("Unsupported low level function {:?}", op), }; evaluator.opcodes.push(AcirOpcode::BlackBoxFuncCall(func_call)); } @@ -139,64 +195,45 @@ pub(crate) fn evaluate( (outputs.len() == 1).then(|| InternalVar::from(outputs[0])) } -// Transform the arguments of intrinsic functions into witnesses -fn prepare_inputs( - acir_gen: &mut Acir, - arguments: &[NodeId], - cfg: &SsaContext, - evaluator: &mut Evaluator, -) -> Vec { - let mut inputs: Vec = Vec::new(); - - for argument in arguments { - inputs.extend(resolve_node_id(argument, acir_gen, cfg, evaluator)); - } - inputs -} - -fn resolve_node_id( +fn resolve_variable( node_id: &NodeId, acir_gen: &mut Acir, cfg: &SsaContext, evaluator: &mut Evaluator, -) -> Vec { +) -> Option { let node_object = cfg.try_get_node(*node_id).expect("could not find node for {node_id}"); match node_object { node::NodeObject::Variable(v) => { - let node_obj_type = node_object.get_type(); - match node_obj_type { - // If the `Variable` represents a Pointer - // Then we know that it is an `Array` - node::ObjectType::ArrayPointer(a) => resolve_array(a, acir_gen, cfg, evaluator), - // If it is not a pointer, we attempt to fetch the witness associated with it - _ => match v.witness { - Some(w) => { - vec![FunctionInput { witness: w, num_bits: v.size_in_bits() }] - } - None => todo!("generate a witness"), - }, - } + Some(FunctionInput { witness: v.witness?, num_bits: v.size_in_bits() }) } _ => { // Upon the case that the `NodeObject` is not a `Variable`, // we attempt to fetch an associated `InternalVar`. // Otherwise, this is a internal compiler error. let internal_var = acir_gen.var_cache.get(node_id).expect("invalid input").clone(); - let witness = acir_gen - .var_cache - .get_or_compute_witness(internal_var, evaluator) - .expect("unexpected constant expression"); - vec![FunctionInput { witness, num_bits: node_object.size_in_bits() }] + let witness = acir_gen.var_cache.get_or_compute_witness(internal_var, evaluator)?; + Some(FunctionInput { witness, num_bits: node_object.size_in_bits() }) } } } fn resolve_array( - array_id: ArrayId, + node_id: &NodeId, acir_gen: &mut Acir, cfg: &SsaContext, evaluator: &mut Evaluator, ) -> Vec { + let node_object = cfg.try_get_node(*node_id).expect("could not find node for {node_id}"); + let array_id = match node_object { + node::NodeObject::Variable(_) => { + let node_obj_type = node_object.get_type(); + match node_obj_type { + node::ObjectType::ArrayPointer(a) => a, + _ => unreachable!(), + } + } + _ => todo!("generate a witness"), + }; let mut inputs = Vec::new(); let array = &cfg.mem[array_id]; diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/operations/sort.rs b/crates/noirc_evaluator/src/ssa/acir_gen/operations/sort.rs index 9566252b2be..c131068f88c 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/operations/sort.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/operations/sort.rs @@ -113,13 +113,13 @@ fn permutation_layer( #[cfg(test)] mod test { - use std::collections::BTreeMap; - use acvm::{ - acir::{circuit::opcodes::BlackBoxFuncCall, native_types::Witness}, - pwg::block::Blocks, - FieldElement, OpcodeResolution, OpcodeResolutionError, PartialWitnessGenerator, - PartialWitnessGeneratorStatus, + acir::{ + circuit::opcodes::FunctionInput, + native_types::{Witness, WitnessMap}, + }, + pwg::{block::Blocks, solve, OpcodeResolution, PartialWitnessGeneratorStatus}, + FieldElement, OpcodeResolutionError, PartialWitnessGenerator, }; use crate::{ @@ -130,12 +130,118 @@ mod test { struct MockBackend {} impl PartialWitnessGenerator for MockBackend { - fn solve_black_box_function_call( + fn aes( + &self, + _initial_witness: &mut WitnessMap, + _inputs: &[FunctionInput], + _outputs: &[Witness], + ) -> Result { + panic!("Path not trodden by this test") + } + fn and( + &self, + _initial_witness: &mut WitnessMap, + _lhs: &FunctionInput, + _rhs: &FunctionInput, + _output: &Witness, + ) -> Result { + panic!("Path not trodden by this test") + } + fn xor( + &self, + _initial_witness: &mut WitnessMap, + _lhs: &FunctionInput, + _rhs: &FunctionInput, + _output: &Witness, + ) -> Result { + panic!("Path not trodden by this test") + } + fn range( + &self, + _initial_witness: &mut WitnessMap, + _input: &FunctionInput, + ) -> Result { + panic!("Path not trodden by this test") + } + fn sha256( + &self, + _initial_witness: &mut WitnessMap, + _inputs: &[FunctionInput], + _outputs: &[Witness], + ) -> Result { + panic!("Path not trodden by this test") + } + fn blake2s( + &self, + _initial_witness: &mut WitnessMap, + _inputs: &[FunctionInput], + _outputs: &[Witness], + ) -> Result { + panic!("Path not trodden by this test") + } + fn compute_merkle_root( + &self, + _initial_witness: &mut WitnessMap, + _leaf: &FunctionInput, + _index: &FunctionInput, + _hash_path: &[FunctionInput], + _output: &Witness, + ) -> Result { + panic!("Path not trodden by this test") + } + fn schnorr_verify( + &self, + _initial_witness: &mut WitnessMap, + _public_key_x: &FunctionInput, + _public_key_y: &FunctionInput, + _signature: &[FunctionInput], + _message: &[FunctionInput], + _output: &Witness, + ) -> Result { + panic!("Path not trodden by this test") + } + fn pedersen( + &self, + _initial_witness: &mut WitnessMap, + _inputs: &[FunctionInput], + _outputs: &[Witness], + ) -> Result { + panic!("Path not trodden by this test") + } + fn hash_to_field_128_security( + &self, + _initial_witness: &mut WitnessMap, + _inputs: &[FunctionInput], + _output: &Witness, + ) -> Result { + panic!("Path not trodden by this test") + } + fn ecdsa_secp256k1( + &self, + _initial_witness: &mut WitnessMap, + _public_key_x: &[FunctionInput], + _public_key_y: &[FunctionInput], + _signature: &[FunctionInput], + _message: &[FunctionInput], + _output: &Witness, + ) -> Result { + panic!("Path not trodden by this test") + } + fn fixed_base_scalar_mul( + &self, + _initial_witness: &mut WitnessMap, + _input: &FunctionInput, + _outputs: &[Witness], + ) -> Result { + panic!("Path not trodden by this test") + } + fn keccak256( &self, - _initial_witness: &mut BTreeMap, - _func_call: &BlackBoxFuncCall, + _initial_witness: &mut WitnessMap, + _inputs: &[FunctionInput], + _outputs: &[Witness], ) -> Result { - unreachable!(); + panic!("Path not trodden by this test") } } @@ -150,7 +256,7 @@ mod test { let mut input = Vec::new(); let mut a_val = Vec::new(); let mut b_wit = Vec::new(); - let mut solved_witness: BTreeMap = BTreeMap::new(); + let mut solved_witness = WitnessMap::new(); for i in 0..n { let w = eval.add_witness_to_cs(); input.push(w.into()); @@ -181,9 +287,9 @@ mod test { // compute the network output by solving the constraints let backend = MockBackend {}; let mut blocks = Blocks::default(); - let solver_status = backend - .solve(&mut solved_witness, &mut blocks, eval.opcodes.clone()) - .expect("Could not solve permutation constraints"); + let solver_status = + solve(&backend, &mut solved_witness, &mut blocks, eval.opcodes.clone()) + .expect("Could not solve permutation constraints"); assert_eq!(solver_status, PartialWitnessGeneratorStatus::Solved, "Incomplete solution"); let mut b_val = Vec::new(); for i in 0..output.len() { diff --git a/crates/noirc_frontend/src/node_interner.rs b/crates/noirc_frontend/src/node_interner.rs index d8ea11ae89c..f3cb00ae9ca 100644 --- a/crates/noirc_frontend/src/node_interner.rs +++ b/crates/noirc_frontend/src/node_interner.rs @@ -586,15 +586,11 @@ impl NodeInterner { #[allow(deprecated)] pub fn foreign(&self, opcode: &str) -> bool { let is_supported = acvm::default_is_opcode_supported(self.language.clone()); - let black_box_func = match acvm::acir::BlackBoxFunc::lookup(opcode) { - Some(black_box_func) => black_box_func, + let black_box_func_call = match acvm::acir::BlackBoxFunc::lookup(opcode) { + Some(black_box_func) => BlackBoxFuncCall::dummy(black_box_func), None => return false, }; - is_supported(&Opcode::BlackBoxFuncCall(BlackBoxFuncCall { - name: black_box_func, - inputs: Vec::new(), - outputs: Vec::new(), - })) + is_supported(&Opcode::BlackBoxFuncCall(black_box_func_call)) } pub fn push_delayed_type_check(&mut self, f: TypeCheckFn) {