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

feat: Memory only brillig #4215

Merged
merged 24 commits into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
ef1521d
feat: First version of memory only brillig
sirasistant Jan 25, 2024
c898e38
fix: brillig vm tests
sirasistant Jan 25, 2024
21050ad
test: restore more tests
sirasistant Jan 25, 2024
e355798
test: restore entry point tests
sirasistant Jan 25, 2024
1ea76d7
test: fix brillig slice ops tests
sirasistant Jan 25, 2024
b1c33ea
fix: properly build return data
sirasistant Jan 25, 2024
fdf3c08
feat: added return data size, try to fix return arrays
sirasistant Jan 29, 2024
1d4f469
fix: fix returning arrays of plain structs
sirasistant Jan 29, 2024
c262135
test: increase test timeout
sirasistant Jan 29, 2024
ed4f3c8
tests: fix some noir tests
sirasistant Jan 29, 2024
26127fa
test: increased timeouts
sirasistant Jan 29, 2024
3685ca3
feat: try to use a more reasonable stack size
sirasistant Jan 29, 2024
498fed8
feat: optimize return data
sirasistant Jan 29, 2024
318a15b
fix: try to force rebuild of protocol circuits
sirasistant Jan 30, 2024
4b3f61c
feat: optimizations
sirasistant Jan 30, 2024
cb54b24
Merge branch 'master' into arv/memory_only_brillig
sirasistant Jan 30, 2024
be58b49
tests: fix serialization tests
sirasistant Jan 30, 2024
bbb58c1
tests: fix serialization tests
sirasistant Jan 30, 2024
1f83e96
Merge branch 'master' into arv/memory_only_brillig
sirasistant Jan 30, 2024
4a04d53
refactor: extract common patterns in entry point
sirasistant Jan 30, 2024
3dcc94b
Merge branch 'arv/memory_only_brillig' of github.com:AztecProtocol/az…
sirasistant Jan 30, 2024
05bcd68
chore: remove commented out code
sirasistant Jan 30, 2024
eab8934
chore: updated comments phrasing about registers in vm
sirasistant Jan 30, 2024
9bc223e
Merge branch 'master' into arv/memory_only_brillig
sirasistant Jan 30, 2024
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
411 changes: 246 additions & 165 deletions barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp

Large diffs are not rendered by default.

371 changes: 217 additions & 154 deletions noir/acvm-repo/acir/codegen/acir.cpp

Large diffs are not rendered by default.

6 changes: 2 additions & 4 deletions noir/acvm-repo/acir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,7 @@ mod reflection {
path::{Path, PathBuf},
};

use brillig::{
BinaryFieldOp, BinaryIntOp, BlackBoxOp, Opcode as BrilligOpcode, RegisterOrMemory,
};
use brillig::{BinaryFieldOp, BinaryIntOp, BlackBoxOp, Opcode as BrilligOpcode, ValueOrArray};
use serde_reflection::{Tracer, TracerConfig};

use crate::{
Expand Down Expand Up @@ -69,7 +67,7 @@ mod reflection {
tracer.trace_simple_type::<BinaryIntOp>().unwrap();
tracer.trace_simple_type::<BlackBoxOp>().unwrap();
tracer.trace_simple_type::<Directive>().unwrap();
tracer.trace_simple_type::<RegisterOrMemory>().unwrap();
tracer.trace_simple_type::<ValueOrArray>().unwrap();

let registry = tracer.registry().unwrap();

Expand Down
83 changes: 54 additions & 29 deletions noir/acvm-repo/acir/tests/test_program_serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use acir::{
native_types::{Expression, Witness},
};
use acir_field::FieldElement;
use brillig::{HeapArray, RegisterIndex, RegisterOrMemory};
use brillig::{HeapArray, MemoryAddress, ValueOrArray};

#[test]
fn addition_circuit() {
Expand Down Expand Up @@ -173,15 +173,23 @@ fn simple_brillig_foreign_call() {
inputs: vec![
BrilligInputs::Single(w_input.into()), // Input Register 0,
],
// This tells the BrilligSolver which witnesses its output registers correspond to
// This tells the BrilligSolver which witnesses its output values correspond to
outputs: vec![
BrilligOutputs::Simple(w_inverted), // Output Register 1
],
bytecode: vec![brillig::Opcode::ForeignCall {
function: "invert".into(),
destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))],
inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))],
}],
bytecode: vec![
brillig::Opcode::CalldataCopy {
destination_address: MemoryAddress(0),
size: 1,
offset: 0,
},
brillig::Opcode::ForeignCall {
function: "invert".into(),
destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))],
inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))],
},
brillig::Opcode::Stop { return_data_offset: 0, return_data_size: 1 },
],
predicate: None,
};

Expand All @@ -196,10 +204,11 @@ fn simple_brillig_foreign_call() {
let bytes = Circuit::serialize_circuit(&circuit);

let expected_serialization: Vec<u8> = vec![
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 49, 10, 64, 33, 12, 67, 99, 63, 124, 60, 142,
222, 192, 203, 56, 184, 56, 136, 120, 126, 5, 21, 226, 160, 139, 62, 40, 13, 45, 132, 68,
3, 80, 232, 124, 164, 153, 121, 115, 99, 155, 59, 172, 122, 231, 101, 56, 175, 80, 86, 221,
230, 31, 58, 196, 226, 83, 62, 53, 91, 16, 122, 10, 246, 84, 99, 243, 0, 30, 59, 1, 0, 0,
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 177, 10, 192, 32, 12, 68, 207, 148, 150, 118,
234, 175, 216, 63, 232, 207, 116, 232, 210, 161, 136, 223, 175, 98, 132, 27, 212, 69, 31,
132, 28, 23, 8, 119, 59, 0, 131, 204, 66, 154, 41, 222, 173, 219, 142, 113, 153, 121, 191,
44, 231, 21, 237, 144, 88, 43, 249, 11, 71, 156, 77, 245, 251, 249, 231, 119, 189, 214,
204, 89, 187, 11, 25, 130, 54, 1, 36, 1, 124, 242, 107, 1, 0, 0,
];

assert_eq!(bytes, expected_serialization)
Expand All @@ -221,39 +230,54 @@ fn complex_brillig_foreign_call() {

let brillig_data = Brillig {
inputs: vec![
// Input Register 0
// Input 0,1,2
BrilligInputs::Array(vec![
Expression::from(a),
Expression::from(b),
Expression::from(c),
]),
// Input Register 1
// Input 3
BrilligInputs::Single(Expression {
mul_terms: vec![],
linear_combinations: vec![(fe_1, a), (fe_1, b), (fe_1, c)],
q_c: fe_0,
}),
],
// This tells the BrilligSolver which witnesses its output registers correspond to
// This tells the BrilligSolver which witnesses its output values correspond to
outputs: vec![
BrilligOutputs::Array(vec![a_times_2, b_times_3, c_times_4]), // Output Register 0
BrilligOutputs::Simple(a_plus_b_plus_c), // Output Register 1
BrilligOutputs::Simple(a_plus_b_plus_c_times_2), // Output Register 2
BrilligOutputs::Array(vec![a_times_2, b_times_3, c_times_4]), // Output 0,1,2
BrilligOutputs::Simple(a_plus_b_plus_c), // Output 3
BrilligOutputs::Simple(a_plus_b_plus_c_times_2), // Output 4
],
bytecode: vec![
brillig::Opcode::CalldataCopy {
destination_address: MemoryAddress(32),
size: 3,
offset: 0,
},
brillig::Opcode::Const {
destination: MemoryAddress(0),
value: brillig::Value::from(32_usize),
},
brillig::Opcode::CalldataCopy {
destination_address: MemoryAddress(1),
size: 1,
offset: 3,
},
// Oracles are named 'foreign calls' in brillig
brillig::Opcode::ForeignCall {
function: "complex".into(),
inputs: vec![
RegisterOrMemory::HeapArray(HeapArray { pointer: 0.into(), size: 3 }),
RegisterOrMemory::RegisterIndex(RegisterIndex::from(1)),
ValueOrArray::HeapArray(HeapArray { pointer: 0.into(), size: 3 }),
ValueOrArray::MemoryAddress(MemoryAddress::from(1)),
],
destinations: vec![
RegisterOrMemory::HeapArray(HeapArray { pointer: 0.into(), size: 3 }),
RegisterOrMemory::RegisterIndex(RegisterIndex::from(1)),
RegisterOrMemory::RegisterIndex(RegisterIndex::from(2)),
ValueOrArray::HeapArray(HeapArray { pointer: 0.into(), size: 3 }),
ValueOrArray::MemoryAddress(MemoryAddress::from(35)),
ValueOrArray::MemoryAddress(MemoryAddress::from(36)),
],
},
brillig::Opcode::Stop { return_data_offset: 32, return_data_size: 5 },
],
predicate: None,
};
Expand All @@ -269,13 +293,14 @@ fn complex_brillig_foreign_call() {
let bytes = Circuit::serialize_circuit(&circuit);

let expected_serialization: Vec<u8> = vec![
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 83, 219, 10, 128, 48, 8, 117, 174, 139, 159, 179,
254, 160, 127, 137, 222, 138, 122, 236, 243, 19, 114, 32, 22, 244, 144, 131, 118, 64, 156,
178, 29, 14, 59, 74, 0, 16, 224, 66, 228, 64, 57, 7, 169, 53, 242, 189, 81, 114, 250, 134,
33, 248, 113, 165, 82, 26, 177, 2, 141, 177, 128, 198, 60, 15, 63, 245, 219, 211, 23, 215,
255, 139, 15, 251, 211, 112, 180, 28, 157, 212, 189, 100, 82, 179, 64, 170, 63, 109, 235,
190, 204, 135, 166, 178, 150, 216, 62, 154, 252, 250, 70, 147, 35, 220, 119, 93, 227, 4,
182, 131, 81, 25, 36, 4, 0, 0,
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 83, 65, 10, 132, 48, 12, 76, 218, 237, 174, 123,
242, 11, 130, 62, 160, 250, 2, 255, 34, 222, 20, 61, 250, 124, 11, 78, 49, 4, 193, 131, 21,
52, 16, 210, 132, 105, 50, 77, 210, 140, 136, 152, 54, 177, 65, 13, 206, 12, 95, 74, 196,
181, 176, 254, 154, 212, 156, 46, 151, 191, 139, 163, 121, 1, 71, 123, 3, 199, 184, 15, 15,
157, 119, 202, 185, 36, 237, 159, 61, 248, 63, 159, 160, 46, 232, 23, 254, 15, 54, 67, 156,
96, 11, 213, 119, 82, 248, 116, 179, 104, 188, 163, 125, 15, 89, 213, 253, 139, 154, 221,
52, 206, 67, 191, 88, 5, 213, 52, 75, 113, 174, 96, 205, 201, 157, 24, 207, 197, 211, 157,
6, 50, 18, 233, 158, 72, 89, 1, 53, 215, 75, 175, 196, 4, 0, 0,
];

assert_eq!(bytes, expected_serialization)
Expand Down
56 changes: 25 additions & 31 deletions noir/acvm-repo/acvm/src/pwg/brillig.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use acir::{
brillig::{ForeignCallParam, ForeignCallResult, RegisterIndex, Value},
brillig::{ForeignCallParam, ForeignCallResult, Value},
circuit::{
brillig::{Brillig, BrilligInputs, BrilligOutputs},
OpcodeLocation,
Expand All @@ -8,7 +8,7 @@ use acir::{
FieldElement,
};
use acvm_blackbox_solver::BlackBoxFunctionSolver;
use brillig_vm::{Registers, VMStatus, VM};
use brillig_vm::{VMStatus, VM};

use crate::{pwg::OpcodeNotSolvable, OpcodeResolutionError};

Expand Down Expand Up @@ -69,16 +69,15 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> {
acir_index: usize,
) -> Result<Self, OpcodeResolutionError> {
// Set input values
let mut input_register_values: Vec<Value> = Vec::new();
let mut input_memory: Vec<Value> = Vec::new();
let mut calldata: Vec<Value> = Vec::new();
// Each input represents an expression or array of expressions to evaluate.
// Iterate over each input and evaluate the expression(s) associated with it.
// Push the results into registers and/or memory.
// Push the results into memory.
// If a certain expression is not solvable, we stall the ACVM and do not proceed with Brillig VM execution.
for input in &brillig.inputs {
match input {
BrilligInputs::Single(expr) => match get_value(expr, initial_witness) {
Ok(value) => input_register_values.push(value.into()),
Ok(value) => calldata.push(value.into()),
Err(_) => {
return Err(OpcodeResolutionError::OpcodeNotSolvable(
OpcodeNotSolvable::ExpressionHasTooManyUnknowns(expr.clone()),
Expand All @@ -87,39 +86,26 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> {
},
BrilligInputs::Array(expr_arr) => {
// Attempt to fetch all array input values
let memory_pointer = input_memory.len();
for expr in expr_arr.iter() {
match get_value(expr, initial_witness) {
Ok(value) => input_memory.push(value.into()),
Ok(value) => calldata.push(value.into()),
Err(_) => {
return Err(OpcodeResolutionError::OpcodeNotSolvable(
OpcodeNotSolvable::ExpressionHasTooManyUnknowns(expr.clone()),
))
}
}
}

// Push value of the array pointer as a register
input_register_values.push(Value::from(memory_pointer));
}
}
}

// Instantiate a Brillig VM given the solved input registers and memory
// Instantiate a Brillig VM given the solved calldata
// along with the Brillig bytecode.
let input_registers = Registers::load(input_register_values);
let vm = VM::new(input_registers, input_memory, &brillig.bytecode, vec![], bb_solver);
let vm = VM::new(calldata, &brillig.bytecode, vec![], bb_solver);
Ok(Self { vm, acir_index })
}

pub fn get_registers(&self) -> &Registers {
self.vm.get_registers()
}

pub fn set_register(&mut self, register_index: usize, value: Value) {
self.vm.set_register(RegisterIndex(register_index), value);
}

pub fn get_memory(&self) -> &[Value] {
self.vm.get_memory()
}
Expand Down Expand Up @@ -151,7 +137,7 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> {
// Return the "resolution" to the caller who may choose to make subsequent calls
// (when it gets foreign call results for example).
match vm_status {
VMStatus::Finished => Ok(BrilligSolverStatus::Finished),
VMStatus::Finished { .. } => Ok(BrilligSolverStatus::Finished),
VMStatus::InProgress => Ok(BrilligSolverStatus::InProgress),
VMStatus::Failure { message, call_stack } => {
Err(OpcodeResolutionError::BrilligFunctionFailed {
Expand Down Expand Up @@ -179,8 +165,8 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> {
// Finish the Brillig execution by writing the outputs to the witness map
let vm_status = self.vm.get_status();
match vm_status {
VMStatus::Finished => {
self.write_brillig_outputs(witness, brillig)?;
VMStatus::Finished { return_data_offset, return_data_size } => {
self.write_brillig_outputs(witness, return_data_offset, return_data_size, brillig)?;
Ok(())
}
_ => panic!("Brillig VM has not completed execution"),
Expand All @@ -190,24 +176,32 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> {
fn write_brillig_outputs(
&self,
witness_map: &mut WitnessMap,
return_data_offset: usize,
return_data_size: usize,
brillig: &Brillig,
) -> Result<(), OpcodeResolutionError> {
// Write VM execution results into the witness map
for (i, output) in brillig.outputs.iter().enumerate() {
let register_value = self.vm.get_registers().get(RegisterIndex::from(i));
let memory = self.vm.get_memory();
let mut current_ret_data_idx = return_data_offset;
for output in brillig.outputs.iter() {
match output {
BrilligOutputs::Simple(witness) => {
insert_value(witness, register_value.to_field(), witness_map)?;
insert_value(witness, memory[current_ret_data_idx].to_field(), witness_map)?;
current_ret_data_idx += 1;
}
BrilligOutputs::Array(witness_arr) => {
// Treat the register value as a pointer to memory
for (i, witness) in witness_arr.iter().enumerate() {
let value = &self.vm.get_memory()[register_value.to_usize() + i];
for witness in witness_arr.iter() {
let value = memory[current_ret_data_idx];
insert_value(witness, value.to_field(), witness_map)?;
current_ret_data_idx += 1;
}
}
}
}
assert!(
current_ret_data_idx == return_data_offset + return_data_size,
"Brillig VM did not write the expected number of return values"
);
Ok(())
}

Expand Down
Loading
Loading