From bec3cb2eff62b8e0fd4073300561bda28fb7487c Mon Sep 17 00:00:00 2001 From: Tom French Date: Tue, 5 Sep 2023 17:49:51 +0100 Subject: [PATCH] feat: pull `Language` and `Opcode` support from backend --- Cargo.lock | 2 + crates/acvm_backend_barretenberg/Cargo.toml | 2 + .../acvm_backend_barretenberg/src/cli/info.rs | 82 +++++++++++++++++++ .../acvm_backend_barretenberg/src/cli/mod.rs | 2 + .../src/proof_system.rs | 9 +- .../mock_backend/src/info_cmd.rs | 32 ++++++++ .../test-binaries/mock_backend/src/main.rs | 3 + 7 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 crates/acvm_backend_barretenberg/src/cli/info.rs create mode 100644 crates/acvm_backend_barretenberg/test-binaries/mock_backend/src/info_cmd.rs diff --git a/Cargo.lock b/Cargo.lock index 212571ac497..04ff61786ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,6 +57,8 @@ dependencies = [ "dirs", "flate2", "reqwest", + "serde", + "serde_json", "serial_test", "tar", "tempfile", diff --git a/crates/acvm_backend_barretenberg/Cargo.toml b/crates/acvm_backend_barretenberg/Cargo.toml index b925627615f..28011d4e9eb 100644 --- a/crates/acvm_backend_barretenberg/Cargo.toml +++ b/crates/acvm_backend_barretenberg/Cargo.toml @@ -14,6 +14,8 @@ acvm.workspace = true dirs.workspace = true thiserror.workspace = true base64.workspace = true +serde.workspace = true +serde_json.workspace = true tempfile = "3.6.0" diff --git a/crates/acvm_backend_barretenberg/src/cli/info.rs b/crates/acvm_backend_barretenberg/src/cli/info.rs new file mode 100644 index 00000000000..c58f1436d97 --- /dev/null +++ b/crates/acvm_backend_barretenberg/src/cli/info.rs @@ -0,0 +1,82 @@ +use acvm::acir::circuit::opcodes::Opcode; +use acvm::Language; +use serde::Deserialize; +use std::collections::HashSet; +use std::path::Path; + +use crate::BackendError; + +pub(crate) struct InfoCommand; + +#[derive(Deserialize)] +struct InfoResponse { + language: LanguageResponse, + opcodes_supported: Vec, + black_box_functions_supported: Vec, +} + +#[derive(Deserialize)] +struct LanguageResponse { + name: String, + width: Option, +} + +impl InfoCommand { + pub(crate) fn run( + self, + binary_path: &Path, + ) -> Result<(Language, Box bool>), BackendError> { + let mut command = std::process::Command::new(binary_path); + + command.arg("info"); + + let output = command.output().expect("Failed to execute command"); + + if !output.status.success() { + return Err(BackendError(String::from_utf8(output.stderr).unwrap())); + } + + let backend_info: InfoResponse = + serde_json::from_slice(&output.stdout).expect("Backend should return valid json"); + let language: Language = match backend_info.language.name.as_str() { + "PLONK-CSAT" => { + let width = backend_info.language.width.unwrap(); + Language::PLONKCSat { width } + } + "R1CS" => Language::R1CS, + _ => panic!("Unknown langauge"), + }; + + let opcodes_set: HashSet = backend_info.opcodes_supported.into_iter().collect(); + let black_box_functions_set: HashSet = + backend_info.black_box_functions_supported.into_iter().collect(); + + let is_opcode_supported = move |opcode: &Opcode| -> bool { + match opcode { + Opcode::Arithmetic(_) => opcodes_set.contains("arithmetic"), + Opcode::Directive(_) => opcodes_set.contains("directive"), + Opcode::Brillig(_) => opcodes_set.contains("brillig"), + Opcode::MemoryInit { .. } => opcodes_set.contains("memory_init"), + Opcode::MemoryOp { .. } => opcodes_set.contains("memory_op"), + Opcode::BlackBoxFuncCall(func) => { + black_box_functions_set.contains(func.get_black_box_func().name()) + } + } + }; + + return Ok((language, Box::new(is_opcode_supported))); + } +} + +#[test] +#[serial_test::serial] +fn info_command() { + use acvm::acir::native_types::Expression; + + let backend = crate::get_mock_backend(); + + let (language, is_opcode_supported) = InfoCommand.run(&backend.binary_path()).unwrap(); + + assert!(matches!(language, Language::PLONKCSat { width: 3 })); + assert!(is_opcode_supported(&Opcode::Arithmetic(Expression::default()))); +} diff --git a/crates/acvm_backend_barretenberg/src/cli/mod.rs b/crates/acvm_backend_barretenberg/src/cli/mod.rs index daad2f9b639..f34738acb62 100644 --- a/crates/acvm_backend_barretenberg/src/cli/mod.rs +++ b/crates/acvm_backend_barretenberg/src/cli/mod.rs @@ -2,12 +2,14 @@ mod contract; mod gates; +mod info; mod prove; mod verify; mod write_vk; pub(crate) use contract::ContractCommand; pub(crate) use gates::GatesCommand; +pub(crate) use info::InfoCommand; pub(crate) use prove::ProveCommand; pub(crate) use verify::VerifyCommand; pub(crate) use write_vk::WriteVkCommand; diff --git a/crates/acvm_backend_barretenberg/src/proof_system.rs b/crates/acvm_backend_barretenberg/src/proof_system.rs index b3e4806e426..cbbcbe07328 100644 --- a/crates/acvm_backend_barretenberg/src/proof_system.rs +++ b/crates/acvm_backend_barretenberg/src/proof_system.rs @@ -8,7 +8,7 @@ use acvm::FieldElement; use acvm::Language; use tempfile::tempdir; -use crate::cli::{GatesCommand, ProveCommand, VerifyCommand, WriteVkCommand}; +use crate::cli::{GatesCommand, InfoCommand, ProveCommand, VerifyCommand, WriteVkCommand}; use crate::{assert_binary_exists, Backend, BackendError}; impl Backend { @@ -30,6 +30,13 @@ impl Backend { .run(&binary_path) } + pub fn get_backend_info( + &self, + ) -> Result<(Language, Box bool>), BackendError> { + let binary_path = assert_binary_exists(self); + InfoCommand.run(&binary_path) + } + pub fn supports_opcode(&self, opcode: &Opcode) -> bool { match opcode { Opcode::Arithmetic(_) => true, diff --git a/crates/acvm_backend_barretenberg/test-binaries/mock_backend/src/info_cmd.rs b/crates/acvm_backend_barretenberg/test-binaries/mock_backend/src/info_cmd.rs new file mode 100644 index 00000000000..c5ca2fba38e --- /dev/null +++ b/crates/acvm_backend_barretenberg/test-binaries/mock_backend/src/info_cmd.rs @@ -0,0 +1,32 @@ +use clap::Args; +use std::io::Write; + +const INFO_RESPONSE: &str = r#"{ + "language": { + "name": "PLONK-CSAT", + "width": 3 + }, + "opcodes_supported": ["arithmetic", "directive", "brillig", "memory_init", "memory_op"], + "black_box_functions_supported": [ + "and", + "xor", + "range", + "sha256", + "blake2s", + "keccak256", + "schnorr_verify", + "pedersen", + "hash_to_field_128_security", + "ecdsa_secp256k1", + "ecdsa_secp256r1", + "fixed_base_scalar_mul", + "recursive_aggregation" + ] +}"#; + +#[derive(Debug, Clone, Args)] +pub(crate) struct InfoCommand; + +pub(crate) fn run(_args: InfoCommand) { + std::io::stdout().write_all(INFO_RESPONSE.as_bytes()).unwrap(); +} diff --git a/crates/acvm_backend_barretenberg/test-binaries/mock_backend/src/main.rs b/crates/acvm_backend_barretenberg/test-binaries/mock_backend/src/main.rs index 74ea82d28f8..ef8819af94b 100644 --- a/crates/acvm_backend_barretenberg/test-binaries/mock_backend/src/main.rs +++ b/crates/acvm_backend_barretenberg/test-binaries/mock_backend/src/main.rs @@ -7,6 +7,7 @@ use clap::{Parser, Subcommand}; mod contract_cmd; mod gates_cmd; +mod info_cmd; mod prove_cmd; mod verify_cmd; mod write_vk_cmd; @@ -20,6 +21,7 @@ struct BackendCli { #[derive(Subcommand, Clone, Debug)] enum BackendCommand { + Info(info_cmd::InfoCommand), Contract(contract_cmd::ContractCommand), Gates(gates_cmd::GatesCommand), Prove(prove_cmd::ProveCommand), @@ -32,6 +34,7 @@ fn main() { let BackendCli { command } = BackendCli::parse(); match command { + BackendCommand::Info(args) => info_cmd::run(args), BackendCommand::Contract(args) => contract_cmd::run(args), BackendCommand::Gates(args) => gates_cmd::run(args), BackendCommand::Prove(args) => prove_cmd::run(args),