Skip to content
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
280 changes: 275 additions & 5 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions tooling/ssa_fuzzer/fuzzer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ strum = "0.24"
sha2.workspace = true
p256 = "0.13.2"
k256 = "0.13.4"
reqwest = { version = "0.12.23", features = ["json", "blocking"] }

[dependencies.noir_ssa_fuzzer]
path = "../"
Expand Down
89 changes: 89 additions & 0 deletions tooling/ssa_fuzzer/fuzzer/src/abstract_vm_integration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
//! Module for comparing Brillig output with Brillig-compatible Abstract VM output
use crate::fuzz_lib::fuzzer::FuzzerOutput;
use acvm::acir::circuit::Program;
use acvm::{AcirField, FieldElement};
use base64::Engine;
use std::time::Instant;

/// Function for transpiling Brillig bytecode to Abstract VM bytecode

Check warning on line 8 in tooling/ssa_fuzzer/fuzzer/src/abstract_vm_integration.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (transpiling)
/// The first argument is the Brillig bytecode
pub(crate) type TranspileBrilligBytecodeToAbstractVMBytecode =
Box<dyn Fn(String) -> Result<String, String>>;
/// Function for executing Abstract VM bytecode
/// The first argument is the Abstract VM bytecode
/// The second argument is the inputs as strings
pub(crate) type ExecuteAbstractVMBytecode =
Box<dyn Fn(String, Vec<String>) -> Result<Vec<String>, String>>;

#[derive(Debug)]
pub(crate) enum AbstractVMComparisonResult {
Match,
Mismatch { brillig_outputs: Vec<FieldElement>, abstract_vm_outputs: Vec<FieldElement> },
TranspilerError(String),
SimulatorError(String),
BrilligCompilationError(String),
}

pub(crate) fn compare_with_abstract_vm(
fuzzer_output: &FuzzerOutput,
transpiler: &TranspileBrilligBytecodeToAbstractVMBytecode,
simulator: &ExecuteAbstractVMBytecode,
) -> AbstractVMComparisonResult {
let step_start = Instant::now();
let brillig_outputs = fuzzer_output.get_return_witnesses();
let bytecode = if let Some(program) = &fuzzer_output.program {
let serialized = Program::serialize_program(&program.program);
base64::engine::general_purpose::STANDARD.encode(serialized)
} else {
return AbstractVMComparisonResult::BrilligCompilationError(
"No bytecode found in program".to_string(),
);
};
log::debug!("Bytecode serialization: {:?}", step_start.elapsed());

let step_start = Instant::now();
let abstract_vm_bytecode = match transpiler(bytecode) {
Ok(bc) => bc,
Err(e) => return AbstractVMComparisonResult::TranspilerError(e),
};
log::debug!("Transpiler call: {:?}", step_start.elapsed());

// TODO(sn): now simulator service perceives first input as a selector, which must fit in 32 bits
if fuzzer_output.get_input_witnesses()[0].num_bits() >= 32 {
return AbstractVMComparisonResult::Match;
}

let step_start = Instant::now();
let inputs = fuzzer_output
.get_input_witnesses()
.iter()
.map(FieldElement::to_string)
.collect::<Vec<String>>();
log::debug!("Input extraction: {:?}", step_start.elapsed());

let abstract_vm_outputs: Vec<FieldElement> = match simulator(abstract_vm_bytecode, inputs) {
Ok(outputs) => {
outputs.iter().map(|output| FieldElement::try_from_str(output).unwrap()).collect()
}
Err(e) => {
// brillig execution failed, so we assume the match
if brillig_outputs.is_empty() {
return AbstractVMComparisonResult::Match;
}
log::info!("Brillig outputs: {brillig_outputs:?}");
return AbstractVMComparisonResult::SimulatorError(e);
}
};

if brillig_outputs.len() != abstract_vm_outputs.len() {
return AbstractVMComparisonResult::Mismatch { brillig_outputs, abstract_vm_outputs };
}

for (brillig_out, abstract_vm_out) in brillig_outputs.iter().zip(abstract_vm_outputs.iter()) {
if *brillig_out != *abstract_vm_out {
return AbstractVMComparisonResult::Mismatch { brillig_outputs, abstract_vm_outputs };
}
}

AbstractVMComparisonResult::Match
}
4 changes: 2 additions & 2 deletions tooling/ssa_fuzzer/fuzzer/src/acir_vs_brillig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ libfuzzer_sys::fuzz_target!(|data: &[u8]| -> Corpus {
"FULL" => compile_options.show_ssa = true,
"FINAL" => {
compile_options.show_ssa_pass =
vec!["After Dead Instruction Elimination - ACIR".to_string()];
vec!["Dead Instruction Elimination (3)".to_string()];
}
"FIRST_AND_FINAL" => {
compile_options.show_ssa_pass = vec![
"After Removing Unreachable Functions (1)".to_string(),
"After Dead Instruction Elimination - ACIR".to_string(),
"Dead Instruction Elimination (3)".to_string(),
];
}
_ => (),
Expand Down
Loading
Loading