Skip to content

Commit

Permalink
feat: pull Language and Opcode support from backend (#2563)
Browse files Browse the repository at this point in the history
  • Loading branch information
TomAFrench authored Sep 7, 2023
1 parent fa016ae commit 2d0a5e4
Show file tree
Hide file tree
Showing 11 changed files with 163 additions and 39 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions crates/acvm_backend_barretenberg/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ license = "MIT OR Apache-2.0"
acvm.workspace = true
dirs.workspace = true
thiserror.workspace = true
serde.workspace = true
serde_json.workspace = true

tempfile = "3.6.0"

Expand Down
6 changes: 5 additions & 1 deletion crates/acvm_backend_barretenberg/src/bb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ const TAG: &str = formatcp!("barretenberg-v{}", VERSION);
const API_URL: &str =
formatcp!("https://github.com/{}/{}/releases/download/{}", USERNAME, REPO, TAG);

pub(crate) fn get_bb_download_url() -> String {
pub(super) fn get_bb_download_url() -> String {
if let Ok(path) = std::env::var("BB_BINARY_URL") {
return path;
}

let target_os = env!("TARGET_OS");
let target_arch = env!("TARGET_ARCH");

Expand Down
94 changes: 94 additions & 0 deletions crates/acvm_backend_barretenberg/src/cli/info.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
use acvm::acir::circuit::opcodes::Opcode;
use acvm::Language;
use serde::Deserialize;
use std::collections::HashSet;
use std::path::{Path, PathBuf};

use crate::BackendError;

pub(crate) struct InfoCommand {
pub(crate) crs_path: PathBuf,
}

#[derive(Deserialize)]
struct InfoResponse {
language: LanguageResponse,
opcodes_supported: Vec<String>,
black_box_functions_supported: Vec<String>,
}

#[derive(Deserialize)]
struct LanguageResponse {
name: String,
width: Option<usize>,
}

impl InfoCommand {
pub(crate) fn run(
self,
binary_path: &Path,
) -> Result<(Language, Box<impl Fn(&Opcode) -> bool>), BackendError> {
let mut command = std::process::Command::new(binary_path);

command.arg("info").arg("-c").arg(self.crs_path).arg("-o").arg("-");

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<String> = backend_info.opcodes_supported.into_iter().collect();
let black_box_functions_set: HashSet<String> =
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())
}
}
};

Ok((language, Box::new(is_opcode_supported)))
}
}

#[test]
#[serial_test::serial]
fn info_command() {
use acvm::acir::circuit::black_box_functions::BlackBoxFunc;
use acvm::acir::circuit::opcodes::{BlackBoxFuncCall, Opcode};

use acvm::acir::native_types::Expression;

let backend = crate::get_mock_backend();
let crs_path = backend.backend_directory();

let (language, is_opcode_supported) =
InfoCommand { crs_path }.run(&backend.binary_path()).unwrap();

assert!(matches!(language, Language::PLONKCSat { width: 3 }));
assert!(is_opcode_supported(&Opcode::Arithmetic(Expression::default())));

assert!(!is_opcode_supported(&Opcode::BlackBoxFuncCall(
#[allow(deprecated)]
BlackBoxFuncCall::dummy(BlackBoxFunc::Keccak256)
)));
}
2 changes: 2 additions & 0 deletions crates/acvm_backend_barretenberg/src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
36 changes: 7 additions & 29 deletions crates/acvm_backend_barretenberg/src/proof_system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,15 @@ use std::io::{Read, Write};
use std::path::Path;

use acvm::acir::circuit::Opcode;
use acvm::acir::{circuit::Circuit, native_types::WitnessMap, BlackBoxFunc};
use acvm::acir::{circuit::Circuit, native_types::WitnessMap};
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 {
pub fn np_language(&self) -> Language {
Language::PLONKCSat { width: 3 }
}

pub fn get_exact_circuit_size(&self, circuit: &Circuit) -> Result<u32, BackendError> {
let temp_directory = tempdir().expect("could not create a temporary directory");
let temp_directory = temp_directory.path().to_path_buf();
Expand All @@ -30,29 +26,11 @@ impl Backend {
.run(&binary_path)
}

pub fn supports_opcode(&self, opcode: &Opcode) -> bool {
match opcode {
Opcode::Arithmetic(_) => true,
Opcode::Directive(_) => true,
Opcode::Brillig(_) => true,
Opcode::MemoryInit { .. } => true,
Opcode::MemoryOp { .. } => true,
Opcode::BlackBoxFuncCall(func) => match func.get_black_box_func() {
BlackBoxFunc::AND
| BlackBoxFunc::XOR
| BlackBoxFunc::RANGE
| BlackBoxFunc::SHA256
| BlackBoxFunc::Blake2s
| BlackBoxFunc::Keccak256
| BlackBoxFunc::SchnorrVerify
| BlackBoxFunc::Pedersen
| BlackBoxFunc::HashToField128Security
| BlackBoxFunc::EcdsaSecp256k1
| BlackBoxFunc::EcdsaSecp256r1
| BlackBoxFunc::FixedBaseScalarMul
| BlackBoxFunc::RecursiveAggregation => true,
},
}
pub fn get_backend_info(
&self,
) -> Result<(Language, Box<impl Fn(&Opcode) -> bool>), BackendError> {
let binary_path = assert_binary_exists(self);
InfoCommand { crs_path: self.crs_directory() }.run(&binary_path)
}

pub fn prove(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use clap::Args;
use std::io::Write;
use std::path::PathBuf;

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",
"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 {
#[clap(short = 'c')]
pub(crate) crs_path: Option<PathBuf>,

#[clap(short = 'o')]
pub(crate) info_path: Option<PathBuf>,
}

pub(crate) fn run(_args: InfoCommand) {
std::io::stdout().write_all(INFO_RESPONSE.as_bytes()).unwrap();
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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),
Expand All @@ -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),
Expand Down
6 changes: 3 additions & 3 deletions crates/nargo_cli/src/cli/backend_cmd/uninstall_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,14 @@ pub(crate) fn run(args: UninstallCommand) -> Result<(), CliError> {
};

if let Some(backend) = new_active_backend {
set_active_backend(backend)
set_active_backend(backend);
} else {
// We've deleted the last backend. Clear the active backend file to be recreated once we install a new one.
clear_active_backend()
clear_active_backend();
}
}

std::fs::remove_dir_all(&backends_directory().join(args.backend))
std::fs::remove_dir_all(backends_directory().join(args.backend))
.expect("backend directory should be deleted");

Ok(())
Expand Down
7 changes: 3 additions & 4 deletions crates/nargo_cli/src/cli/compile_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,9 @@ pub(super) fn optimize_circuit(
backend: &Backend,
circuit: Circuit,
) -> Result<(Circuit, AcirTransformationMap), CliError> {
let result = acvm::compiler::compile(circuit, backend.np_language(), |opcode| {
backend.supports_opcode(opcode)
})
.map_err(|_| NargoError::CompilationError)?;
let (np_language, is_opcode_supported) = backend.get_backend_info()?;
let result = acvm::compiler::compile(circuit, np_language, is_opcode_supported)
.map_err(|_| NargoError::CompilationError)?;

Ok(result)
}
Expand Down
6 changes: 4 additions & 2 deletions crates/nargo_cli/src/cli/info_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,11 @@ fn count_opcodes_and_gates_in_program(
compile_options: &CompileOptions,
) -> Result<ProgramInfo, CliError> {
let (_, compiled_program) = compile_package(backend, package, compile_options)?;
let (language, _) = backend.get_backend_info()?;

Ok(ProgramInfo {
name: package.name.to_string(),
language: backend.np_language(),
language,
acir_opcodes: compiled_program.circuit.opcodes.len(),
circuit_size: backend.get_exact_circuit_size(&compiled_program.circuit)?,
})
Expand All @@ -173,6 +174,7 @@ fn count_opcodes_and_gates_in_contracts(
compile_options: &CompileOptions,
) -> Result<Vec<ContractInfo>, CliError> {
let (_, contracts) = compile_contracts(backend, package, compile_options)?;
let (language, _) = backend.get_backend_info()?;

try_vecmap(contracts, |contract| {
let functions = try_vecmap(contract.functions, |function| -> Result<_, BackendError> {
Expand All @@ -183,6 +185,6 @@ fn count_opcodes_and_gates_in_contracts(
})
})?;

Ok(ContractInfo { name: contract.name, language: backend.np_language(), functions })
Ok(ContractInfo { name: contract.name, language, functions })
})
}

0 comments on commit 2d0a5e4

Please sign in to comment.