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: Sync from aztec-packages #4254

Closed
wants to merge 1 commit into from
Closed
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
375 changes: 221 additions & 154 deletions acvm-repo/acir/codegen/acir.cpp

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions acvm-repo/acir/src/circuit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ pub struct Circuit {
// TODO: We should move towards having all the checks being evaluated in the same manner
// TODO: as runtime assert messages specified by the user. This will also be a breaking change as the `Circuit` structure will change.
pub assert_messages: Vec<(OpcodeLocation, String)>,

/// States whether the backend should use a SNARK recursion friendly prover.
/// If implemented by a backend, this means that proofs generated with this circuit
/// will be friendly for recursively verifying inside of another SNARK.
pub recursive: bool,
}

impl Circuit {
Expand Down Expand Up @@ -322,6 +327,7 @@ mod tests {
public_parameters: PublicInputs(BTreeSet::from_iter(vec![Witness(2), Witness(12)])),
return_values: PublicInputs(BTreeSet::from_iter(vec![Witness(4), Witness(12)])),
assert_messages: Default::default(),
recursive: false,
};

fn read_write(circuit: Circuit) -> (Circuit, Circuit) {
Expand Down Expand Up @@ -352,6 +358,7 @@ mod tests {
public_parameters: PublicInputs(BTreeSet::from_iter(vec![Witness(2)])),
return_values: PublicInputs(BTreeSet::from_iter(vec![Witness(2)])),
assert_messages: Default::default(),
recursive: false,
};

let json = serde_json::to_string_pretty(&circuit).unwrap();
Expand Down
6 changes: 2 additions & 4 deletions acvm-repo/acir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
mod reflection {
//! Getting test failures? You've probably changed the ACIR serialization format.
//!
//! These tests generate C++ deserializers for [`ACIR bytecode`][super::circuit::Circuit]

Check warning on line 20 in acvm-repo/acir/src/lib.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (deserializers)
//! and the [`WitnessMap`] structs. These get checked against the C++ files committed to the `codegen` folder
//! to see if changes have been to the serialization format. These are almost always a breaking change!
//!
Expand All @@ -31,9 +31,7 @@
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 @@
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 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 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