From cd30430f70f683a0e87f6108f6ceb7bf63877efe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Gir=C3=A1ldez?= Date: Wed, 10 Jan 2024 18:19:45 -0500 Subject: [PATCH 01/10] feat: (incomplete) support (de)flattening arrays/vectors for foreign calls --- acvm-repo/brillig/src/black_box.rs | 2 +- acvm-repo/brillig/src/lib.rs | 3 +- acvm-repo/brillig/src/opcodes.rs | 22 +++- acvm-repo/brillig_vm/src/lib.rs | 105 ++++++++++++------ .../brillig/brillig_gen/brillig_black_box.rs | 45 ++++---- .../src/brillig/brillig_gen/brillig_block.rs | 7 +- .../noirc_evaluator/src/brillig/brillig_ir.rs | 2 +- .../brillig/brillig_ir/brillig_variable.rs | 51 +++++++-- .../src/brillig/brillig_ir/debug_show.rs | 2 +- 9 files changed, 167 insertions(+), 72 deletions(-) diff --git a/acvm-repo/brillig/src/black_box.rs b/acvm-repo/brillig/src/black_box.rs index 41e54ab2705..7e3c0975692 100644 --- a/acvm-repo/brillig/src/black_box.rs +++ b/acvm-repo/brillig/src/black_box.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; /// These opcodes provide an equivalent of ACIR blackbox functions. /// They are implemented as native functions in the VM. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum BlackBoxOp { /// Calculates the SHA256 hash of the inputs. Sha256 { message: HeapVector, output: HeapArray }, diff --git a/acvm-repo/brillig/src/lib.rs b/acvm-repo/brillig/src/lib.rs index 5e033e3c792..8d32b8d6ce7 100644 --- a/acvm-repo/brillig/src/lib.rs +++ b/acvm-repo/brillig/src/lib.rs @@ -18,7 +18,8 @@ mod value; pub use black_box::BlackBoxOp; pub use foreign_call::{ForeignCallParam, ForeignCallResult}; pub use opcodes::{ - BinaryFieldOp, BinaryIntOp, HeapArray, HeapVector, RegisterIndex, RegisterOrMemory, + BinaryFieldOp, BinaryIntOp, HeapArray, HeapValueType, HeapVector, RegisterIndex, + RegisterOrMemory, }; pub use opcodes::{BrilligOpcode as Opcode, Label}; pub use value::Typ; diff --git a/acvm-repo/brillig/src/opcodes.rs b/acvm-repo/brillig/src/opcodes.rs index 79295cc6e5d..cb2b6364c4b 100644 --- a/acvm-repo/brillig/src/opcodes.rs +++ b/acvm-repo/brillig/src/opcodes.rs @@ -19,18 +19,34 @@ impl From for RegisterIndex { } } +/// Describes the memory layout for an array/vector element +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub enum HeapValueType { + Simple, + Array { value_types: Vec, size: usize }, + Vector { value_types: Vec }, +} + +impl HeapValueType { + pub fn all_simple(types: &Vec) -> bool { + types.iter().all(|typ| matches!(typ, HeapValueType::Simple)) + } +} + /// A fixed-sized array starting from a Brillig register memory location. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct HeapArray { pub pointer: RegisterIndex, pub size: usize, + pub value_types: Vec, } /// A register-sized vector passed starting from a Brillig register memory location and with a register-held size -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct HeapVector { pub pointer: RegisterIndex, pub size: RegisterIndex, + pub value_types: Vec, } /// Lays out various ways an external foreign call's input and output data may be interpreted inside Brillig. @@ -39,7 +55,7 @@ pub struct HeapVector { /// While we are usually agnostic to how memory is passed within Brillig, /// this needs to be encoded somehow when dealing with an external system. /// For simplicity, the extra type information is given right in the ForeignCall instructions. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum RegisterOrMemory { /// A single register value passed to or from an external call /// It is an 'immediate' value - used without dereferencing memory. diff --git a/acvm-repo/brillig_vm/src/lib.rs b/acvm-repo/brillig_vm/src/lib.rs index 482b9b36d77..11b6408cf43 100644 --- a/acvm-repo/brillig_vm/src/lib.rs +++ b/acvm-repo/brillig_vm/src/lib.rs @@ -12,8 +12,8 @@ //! [acvm]: https://crates.io/crates/acvm use acir::brillig::{ - BinaryFieldOp, BinaryIntOp, ForeignCallParam, ForeignCallResult, HeapArray, HeapVector, Opcode, - RegisterIndex, RegisterOrMemory, Value, + BinaryFieldOp, BinaryIntOp, ForeignCallParam, ForeignCallResult, HeapArray, HeapValueType, + HeapVector, Opcode, RegisterIndex, RegisterOrMemory, Value, }; use acir::FieldElement; // Re-export `brillig`. @@ -227,7 +227,7 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { // but has the necessary results to proceed with execution. let resolved_inputs = inputs .iter() - .map(|input| self.get_register_value_or_memory_values(*input)) + .map(|input| self.get_register_value_or_memory_values(input.clone())) .collect::>(); return self.wait_for_foreign_call(function.clone(), resolved_inputs); } @@ -245,36 +245,51 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { "Function result size does not match brillig bytecode (expected 1 result)" ), }, - RegisterOrMemory::HeapArray(HeapArray { pointer: pointer_index, size }) => { - match output { - ForeignCallParam::Array(values) => { - if values.len() != *size { - invalid_foreign_call_result = true; - break; + RegisterOrMemory::HeapArray(HeapArray { + pointer: pointer_index, + size, + value_types, + }) => { + if HeapValueType::all_simple(value_types) { + match output { + ForeignCallParam::Array(values) => { + if values.len() != *size { + invalid_foreign_call_result = true; + break; + } + // Convert the destination pointer to a usize + let destination = self.registers.get(*pointer_index).to_usize(); + // Write to our destination memory + self.memory.write_slice(destination, values); + } + _ => { + unreachable!("Function result size does not match brillig bytecode size") } - // Convert the destination pointer to a usize - let destination = self.registers.get(*pointer_index).to_usize(); - // Write to our destination memory - self.memory.write_slice(destination, values); - } - _ => { - unreachable!("Function result size does not match brillig bytecode size") } + } else { + unimplemented!("unflattening heap arrays"); } } - RegisterOrMemory::HeapVector(HeapVector { pointer: pointer_index, size: size_index }) => { - match output { - ForeignCallParam::Array(values) => { - // Set our size in the size register - self.registers.set(*size_index, Value::from(values.len())); - // Convert the destination pointer to a usize - let destination = self.registers.get(*pointer_index).to_usize(); - // Write to our destination memory - self.memory.write_slice(destination, values); - } - _ => { - unreachable!("Function result size does not match brillig bytecode size") + RegisterOrMemory::HeapVector(HeapVector { pointer: pointer_index, + size: size_index, + value_types, + }) => { + if HeapValueType::all_simple(value_types) { + match output { + ForeignCallParam::Array(values) => { + // Set our size in the size register + self.registers.set(*size_index, Value::from(values.len())); + // Convert the destination pointer to a usize + let destination = self.registers.get(*pointer_index).to_usize(); + // Write to our destination memory + self.memory.write_slice(destination, values); + } + _ => { + unreachable!("Function result size does not match brillig bytecode size") + } } + } else { + unimplemented!("unflattening heap vectors"); } } } @@ -361,17 +376,30 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { fn get_register_value_or_memory_values(&self, input: RegisterOrMemory) -> ForeignCallParam { match input { RegisterOrMemory::RegisterIndex(value_index) => self.registers.get(value_index).into(), - RegisterOrMemory::HeapArray(HeapArray { pointer: pointer_index, size }) => { - let start = self.registers.get(pointer_index); - self.memory.read_slice(start.to_usize(), size).to_vec().into() + RegisterOrMemory::HeapArray(HeapArray { + pointer: pointer_index, + size, + value_types, + }) => { + if HeapValueType::all_simple(&value_types) { + let start = self.registers.get(pointer_index); + self.memory.read_slice(start.to_usize(), size).to_vec().into() + } else { + unimplemented!("flattening heap arrays"); + } } RegisterOrMemory::HeapVector(HeapVector { pointer: pointer_index, size: size_index, + value_types, }) => { - let start = self.registers.get(pointer_index); - let size = self.registers.get(size_index); - self.memory.read_slice(start.to_usize(), size.to_usize()).to_vec().into() + if HeapValueType::all_simple(&value_types) { + let start = self.registers.get(pointer_index); + let size = self.registers.get(size_index); + self.memory.read_slice(start.to_usize(), size.to_usize()).to_vec().into() + } else { + unimplemented!("flattening heap vectors"); + } } } } @@ -999,10 +1027,12 @@ mod tests { destinations: vec![RegisterOrMemory::HeapArray(HeapArray { pointer: r_output, size: initial_matrix.len(), + value_types: vec![HeapValueType::Simple], })], inputs: vec![RegisterOrMemory::HeapArray(HeapArray { pointer: r_input, size: initial_matrix.len(), + value_types: vec![HeapValueType::Simple], })], }, ]; @@ -1072,10 +1102,12 @@ mod tests { destinations: vec![RegisterOrMemory::HeapVector(HeapVector { pointer: r_output_pointer, size: r_output_size, + value_types: vec![HeapValueType::Simple], })], inputs: vec![RegisterOrMemory::HeapVector(HeapVector { pointer: r_input_pointer, size: r_input_size, + value_types: vec![HeapValueType::Simple], })], }, ]; @@ -1134,10 +1166,12 @@ mod tests { destinations: vec![RegisterOrMemory::HeapArray(HeapArray { pointer: r_output, size: initial_matrix.len(), + value_types: vec![HeapValueType::Simple], })], inputs: vec![RegisterOrMemory::HeapArray(HeapArray { pointer: r_input, size: initial_matrix.len(), + value_types: vec![HeapValueType::Simple], })], }, ]; @@ -1212,15 +1246,18 @@ mod tests { destinations: vec![RegisterOrMemory::HeapArray(HeapArray { pointer: r_output, size: matrix_a.len(), + value_types: vec![HeapValueType::Simple], })], inputs: vec![ RegisterOrMemory::HeapArray(HeapArray { pointer: r_input_a, size: matrix_a.len(), + value_types: vec![HeapValueType::Simple], }), RegisterOrMemory::HeapArray(HeapArray { pointer: r_input_b, size: matrix_b.len(), + value_types: vec![HeapValueType::Simple], }), ], }, diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs index a6d3220fa85..354d37e2c5d 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs @@ -1,4 +1,7 @@ -use acvm::acir::{brillig::BlackBoxOp, BlackBoxFunc}; +use acvm::{ + acir::{brillig::BlackBoxOp, BlackBoxFunc}, + brillig_vm::brillig::HeapValueType, +}; use crate::brillig::brillig_ir::{ brillig_variable::{BrilligVariable, BrilligVector}, @@ -21,8 +24,8 @@ pub(crate) fn convert_black_box_call( { let message_vector = convert_array_or_vector(brillig_context, message, bb_func); brillig_context.black_box_op_instruction(BlackBoxOp::Sha256 { - message: message_vector.to_heap_vector(), - output: result_array.to_heap_array(), + message: message_vector.to_heap_vector(vec![HeapValueType::Simple]), + output: result_array.to_heap_array(vec![HeapValueType::Simple]), }); } else { unreachable!("ICE: SHA256 expects one array argument and one array result") @@ -34,8 +37,8 @@ pub(crate) fn convert_black_box_call( { let message_vector = convert_array_or_vector(brillig_context, message, bb_func); brillig_context.black_box_op_instruction(BlackBoxOp::Blake2s { - message: message_vector.to_heap_vector(), - output: result_array.to_heap_array(), + message: message_vector.to_heap_vector(vec![HeapValueType::Simple]), + output: result_array.to_heap_array(vec![HeapValueType::Simple]), }); } else { unreachable!("ICE: Blake2s expects one array argument and one array result") @@ -51,8 +54,8 @@ pub(crate) fn convert_black_box_call( message_vector.size = *array_size; brillig_context.black_box_op_instruction(BlackBoxOp::Keccak256 { - message: message_vector.to_heap_vector(), - output: result_array.to_heap_array(), + message: message_vector.to_heap_vector(vec![HeapValueType::Simple]), + output: result_array.to_heap_array(vec![HeapValueType::Simple]), }); } else { unreachable!("ICE: Keccak256 expects message, message size and result array") @@ -67,10 +70,10 @@ pub(crate) fn convert_black_box_call( let message_hash_vector = convert_array_or_vector(brillig_context, message, bb_func); brillig_context.black_box_op_instruction(BlackBoxOp::EcdsaSecp256k1 { - hashed_msg: message_hash_vector.to_heap_vector(), - public_key_x: public_key_x.to_heap_array(), - public_key_y: public_key_y.to_heap_array(), - signature: signature.to_heap_array(), + hashed_msg: message_hash_vector.to_heap_vector(vec![HeapValueType::Simple]), + public_key_x: public_key_x.to_heap_array(vec![HeapValueType::Simple]), + public_key_y: public_key_y.to_heap_array(vec![HeapValueType::Simple]), + signature: signature.to_heap_array(vec![HeapValueType::Simple]), result: *result_register, }); } else { @@ -88,10 +91,10 @@ pub(crate) fn convert_black_box_call( let message_hash_vector = convert_array_or_vector(brillig_context, message, bb_func); brillig_context.black_box_op_instruction(BlackBoxOp::EcdsaSecp256r1 { - hashed_msg: message_hash_vector.to_heap_vector(), - public_key_x: public_key_x.to_heap_array(), - public_key_y: public_key_y.to_heap_array(), - signature: signature.to_heap_array(), + hashed_msg: message_hash_vector.to_heap_vector(vec![HeapValueType::Simple]), + public_key_x: public_key_x.to_heap_array(vec![HeapValueType::Simple]), + public_key_y: public_key_y.to_heap_array(vec![HeapValueType::Simple]), + signature: signature.to_heap_array(vec![HeapValueType::Simple]), result: *result_register, }); } else { @@ -109,9 +112,9 @@ pub(crate) fn convert_black_box_call( { let message_vector = convert_array_or_vector(brillig_context, message, bb_func); brillig_context.black_box_op_instruction(BlackBoxOp::PedersenCommitment { - inputs: message_vector.to_heap_vector(), + inputs: message_vector.to_heap_vector(vec![HeapValueType::Simple]), domain_separator: *domain_separator, - output: result_array.to_heap_array(), + output: result_array.to_heap_array(vec![HeapValueType::Simple]), }); } else { unreachable!("ICE: Pedersen expects one array argument, a register for the domain separator, and one array result") @@ -125,7 +128,7 @@ pub(crate) fn convert_black_box_call( { let message_vector = convert_array_or_vector(brillig_context, message, bb_func); brillig_context.black_box_op_instruction(BlackBoxOp::PedersenHash { - inputs: message_vector.to_heap_vector(), + inputs: message_vector.to_heap_vector(vec![HeapValueType::Simple]), domain_separator: *domain_separator, output: *result, }); @@ -144,8 +147,8 @@ pub(crate) fn convert_black_box_call( brillig_context.black_box_op_instruction(BlackBoxOp::SchnorrVerify { public_key_x: *public_key_x, public_key_y: *public_key_y, - message: message_hash.to_heap_vector(), - signature: signature.to_heap_vector(), + message: message_hash.to_heap_vector(vec![HeapValueType::Simple]), + signature: signature.to_heap_vector(vec![HeapValueType::Simple]), result: *result_register, }); } else { @@ -161,7 +164,7 @@ pub(crate) fn convert_black_box_call( brillig_context.black_box_op_instruction(BlackBoxOp::FixedBaseScalarMul { low: *low, high: *high, - result: result_array.to_heap_array(), + result: result_array.to_heap_array(vec![HeapValueType::Simple]), }); } else { unreachable!( diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index db005d9d438..dc14ad23900 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -330,10 +330,13 @@ impl<'block> BrilligBlock<'block> { let result_ids = dfg.instruction_results(instruction_id); let input_registers = vecmap(arguments, |value_id| { - self.convert_ssa_value(*value_id, dfg).to_register_or_memory() + let value_type = dfg.type_of_value(*value_id); + self.convert_ssa_value(*value_id, dfg).to_register_or_memory(&value_type) }); let output_registers = vecmap(result_ids, |value_id| { - self.allocate_external_call_result(*value_id, dfg).to_register_or_memory() + let value_type = dfg.type_of_value(*value_id); + self.allocate_external_call_result(*value_id, dfg) + .to_register_or_memory(&value_type) }); self.brillig_context.foreign_call_instruction( func_name.to_owned(), diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index 3c4e77b09ec..976a344b800 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -930,7 +930,7 @@ impl BrilligContext { /// Issues a blackbox operation. pub(crate) fn black_box_op_instruction(&mut self, op: BlackBoxOp) { - self.debug_show.black_box_op_instruction(op); + self.debug_show.black_box_op_instruction(&op); self.push_opcode(BrilligOpcode::BlackBox(op)); } diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs index 46c54d55ecb..8dbe69aff80 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs @@ -1,6 +1,10 @@ -use acvm::brillig_vm::brillig::{HeapArray, HeapVector, RegisterIndex, RegisterOrMemory}; +use acvm::brillig_vm::brillig::{ + HeapArray, HeapValueType, HeapVector, RegisterIndex, RegisterOrMemory, +}; use serde::{Deserialize, Serialize}; +use crate::ssa::ir::types::Type; + /// The representation of a noir array in the Brillig IR #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] pub(crate) struct BrilligArray { @@ -10,8 +14,8 @@ pub(crate) struct BrilligArray { } impl BrilligArray { - pub(crate) fn to_heap_array(self) -> HeapArray { - HeapArray { pointer: self.pointer, size: self.size } + pub(crate) fn to_heap_array(self, value_types: Vec) -> HeapArray { + HeapArray { pointer: self.pointer, size: self.size, value_types } } pub(crate) fn registers_count() -> usize { @@ -32,8 +36,8 @@ pub(crate) struct BrilligVector { } impl BrilligVector { - pub(crate) fn to_heap_vector(self) -> HeapVector { - HeapVector { pointer: self.pointer, size: self.size } + pub(crate) fn to_heap_vector(self, value_types: Vec) -> HeapVector { + HeapVector { pointer: self.pointer, size: self.size, value_types } } pub(crate) fn registers_count() -> usize { @@ -83,17 +87,48 @@ impl BrilligVariable { } } - pub(crate) fn to_register_or_memory(self) -> RegisterOrMemory { + pub(crate) fn to_register_or_memory(self, typ: &Type) -> RegisterOrMemory { match self { BrilligVariable::Simple(register_index) => { RegisterOrMemory::RegisterIndex(register_index) } BrilligVariable::BrilligArray(array) => { - RegisterOrMemory::HeapArray(array.to_heap_array()) + let value_types = heap_value_types_of_array(typ); + RegisterOrMemory::HeapArray(array.to_heap_array(value_types)) } BrilligVariable::BrilligVector(vector) => { - RegisterOrMemory::HeapVector(vector.to_heap_vector()) + let value_types = heap_value_types_of_slice(typ); + RegisterOrMemory::HeapVector(vector.to_heap_vector(value_types)) } } } } + +fn type_to_heap_value_type(typ: &Type) -> HeapValueType { + match typ { + Type::Numeric(_) | Type::Reference(_) | Type::Function => HeapValueType::Simple, + Type::Array(elem_type, size) => HeapValueType::Array { + value_types: elem_type.as_ref().iter().map(type_to_heap_value_type).collect(), + size: *size, + }, + Type::Slice(elem_type) => HeapValueType::Vector { + value_types: elem_type.as_ref().iter().map(type_to_heap_value_type).collect(), + }, + } +} + +fn heap_value_types_of_array(typ: &Type) -> Vec { + if let Type::Array(elem_type, _) = typ { + elem_type.as_ref().iter().map(type_to_heap_value_type).collect() + } else { + unreachable!("value is not of type Array"); + } +} + +fn heap_value_types_of_slice(typ: &Type) -> Vec { + if let Type::Slice(elem_type) = typ { + elem_type.as_ref().iter().map(type_to_heap_value_type).collect() + } else { + unreachable!("value is not of type Slice"); + } +} diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs index 74b24b280cd..92120666e3e 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs @@ -342,7 +342,7 @@ impl DebugShow { } /// Debug function for black_box_op - pub(crate) fn black_box_op_instruction(&self, op: BlackBoxOp) { + pub(crate) fn black_box_op_instruction(&self, op: &BlackBoxOp) { match op { BlackBoxOp::Sha256 { message, output } => { debug_println!(self.enable_debug_trace, " SHA256 {} -> {}", message, output); From ad59a27295d194baee2c5265c59d1024a0024b17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Gir=C3=A1ldez?= Date: Thu, 11 Jan 2024 17:00:09 -0500 Subject: [PATCH 02/10] feat: Flatten arrays and vectors when calling foreign functions --- acvm-repo/brillig/src/opcodes.rs | 9 ++- acvm-repo/brillig_vm/src/black_box.rs | 14 +++- acvm-repo/brillig_vm/src/lib.rs | 64 ++++++++++++++----- .../brillig/brillig_ir/brillig_variable.rs | 2 +- 4 files changed, 69 insertions(+), 20 deletions(-) diff --git a/acvm-repo/brillig/src/opcodes.rs b/acvm-repo/brillig/src/opcodes.rs index cb2b6364c4b..6b126691166 100644 --- a/acvm-repo/brillig/src/opcodes.rs +++ b/acvm-repo/brillig/src/opcodes.rs @@ -22,13 +22,20 @@ impl From for RegisterIndex { /// Describes the memory layout for an array/vector element #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub enum HeapValueType { + // A single field element is enough to represent the value Simple, + // The value read should be interpreted as a pointer to a heap array, which + // consists of a pointer to a slice of memory of size elements, and a + // reference count Array { value_types: Vec, size: usize }, + // The value read should be interpreted as a pointer to a heap vector, which + // consists of a pointer to a slice of memory, a number of elements in that + // slice, and a reference count Vector { value_types: Vec }, } impl HeapValueType { - pub fn all_simple(types: &Vec) -> bool { + pub fn all_simple(types: &[HeapValueType]) -> bool { types.iter().all(|typ| matches!(typ, HeapValueType::Simple)) } } diff --git a/acvm-repo/brillig_vm/src/black_box.rs b/acvm-repo/brillig_vm/src/black_box.rs index 94feb23e1a6..fcf31496b78 100644 --- a/acvm-repo/brillig_vm/src/black_box.rs +++ b/acvm-repo/brillig_vm/src/black_box.rs @@ -183,7 +183,7 @@ fn black_box_function_from_op(op: &BlackBoxOp) -> BlackBoxFunc { #[cfg(test)] mod test { - use acir::brillig::BlackBoxOp; + use acir::brillig::{BlackBoxOp, HeapValueType}; use crate::{ black_box::{evaluate_black_box, to_u8_vec, to_value_vec}, @@ -209,8 +209,16 @@ mod test { }; let op = BlackBoxOp::Sha256 { - message: HeapVector { pointer: 0.into(), size: 1.into() }, - output: HeapArray { pointer: 2.into(), size: 32 }, + message: HeapVector { + pointer: 0.into(), + size: 1.into(), + value_types: vec![HeapValueType::Simple], + }, + output: HeapArray { + pointer: 2.into(), + size: 32, + value_types: vec![HeapValueType::Simple], + }, }; evaluate_black_box(&op, &DummyBlackBoxSolver, &mut registers, &mut memory).unwrap(); diff --git a/acvm-repo/brillig_vm/src/lib.rs b/acvm-repo/brillig_vm/src/lib.rs index 11b6408cf43..78d5da97fb9 100644 --- a/acvm-repo/brillig_vm/src/lib.rs +++ b/acvm-repo/brillig_vm/src/lib.rs @@ -267,7 +267,7 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { } } } else { - unimplemented!("unflattening heap arrays"); + unimplemented!("deflattening heap arrays from foreign calls"); } } RegisterOrMemory::HeapVector(HeapVector { pointer: pointer_index, @@ -289,7 +289,7 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { } } } else { - unimplemented!("unflattening heap vectors"); + unimplemented!("deflattening heap vectors from foreign calls"); } } } @@ -381,29 +381,63 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { size, value_types, }) => { - if HeapValueType::all_simple(&value_types) { - let start = self.registers.get(pointer_index); - self.memory.read_slice(start.to_usize(), size).to_vec().into() - } else { - unimplemented!("flattening heap arrays"); - } + let ptr = self.registers.get(pointer_index).to_usize(); + self.read_slice_of_values_from_memory(ptr, size, &value_types).into() } RegisterOrMemory::HeapVector(HeapVector { pointer: pointer_index, size: size_index, value_types, }) => { - if HeapValueType::all_simple(&value_types) { - let start = self.registers.get(pointer_index); - let size = self.registers.get(size_index); - self.memory.read_slice(start.to_usize(), size.to_usize()).to_vec().into() - } else { - unimplemented!("flattening heap vectors"); - } + let ptr = self.registers.get(pointer_index).to_usize(); + let size = self.registers.get(size_index).to_usize(); + self.read_slice_of_values_from_memory(ptr, size, &value_types).into() } } } + /// Reads an array/vector from memory but recursively reads pointers to + /// nested arrays/vectors according to the sequence of value types. + fn read_slice_of_values_from_memory( + &self, + ptr: usize, + size: usize, + value_types: &[HeapValueType], + ) -> Vec { + if HeapValueType::all_simple(value_types) { + self.memory.read_slice(ptr, size).to_vec() + } else { + // Check that the sequence of value types fit an integer number of + // times inside the given size. + assert!( + 0 == size % value_types.len(), + "array/vector does not contain a whole number of elements" + ); + (0..size) + .zip(value_types.iter().cycle()) + .flat_map(|(i, value_type)| { + let value = self.memory.read(ptr + i); + match value_type { + HeapValueType::Simple => vec![value], + HeapValueType::Array { value_types, size } => { + let inner_ptr = self.memory.read(value.to_usize()).to_usize(); + self.read_slice_of_values_from_memory(inner_ptr, *size, value_types) + } + HeapValueType::Vector { value_types } => { + let inner_ptr = self.memory.read(value.to_usize()).to_usize(); + let inner_size = self.memory.read(value.to_usize() + 1).to_usize(); + self.read_slice_of_values_from_memory( + inner_ptr, + inner_size, + value_types, + ) + } + } + }) + .collect::>() + } + } + /// Process a binary operation. /// This method will not modify the program counter. fn process_binary_field_op( diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs index 8dbe69aff80..f545a07fba2 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs @@ -109,7 +109,7 @@ fn type_to_heap_value_type(typ: &Type) -> HeapValueType { Type::Numeric(_) | Type::Reference(_) | Type::Function => HeapValueType::Simple, Type::Array(elem_type, size) => HeapValueType::Array { value_types: elem_type.as_ref().iter().map(type_to_heap_value_type).collect(), - size: *size, + size: typ.element_size() * size, }, Type::Slice(elem_type) => HeapValueType::Vector { value_types: elem_type.as_ref().iter().map(type_to_heap_value_type).collect(), From 3b050eb8af395f568faeffdde2d95681d1669076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Gir=C3=A1ldez?= Date: Fri, 12 Jan 2024 18:19:29 -0500 Subject: [PATCH 03/10] feat: test for passing nested arrays/vectors into foreign calls --- acvm-repo/brillig_vm/src/lib.rs | 109 ++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/acvm-repo/brillig_vm/src/lib.rs b/acvm-repo/brillig_vm/src/lib.rs index 78d5da97fb9..acbc419d204 100644 --- a/acvm-repo/brillig_vm/src/lib.rs +++ b/acvm-repo/brillig_vm/src/lib.rs @@ -1325,4 +1325,113 @@ mod tests { // Ensure the foreign call counter has been incremented assert_eq!(vm.foreign_call_counter, 1); } + + #[test] + fn foreign_call_opcode_nested_arrays_and_slices_input() { + // [(1, <2,3>, [4]), (5, <6,7,8>, [9])] + + let v2 = vec![Value::from(2u128), Value::from(3u128)]; + let a4 = vec![Value::from(4u128)]; + let v6 = vec![Value::from(6u128), Value::from(7u128), Value::from(8u128)]; + let a9 = vec![Value::from(9u128)]; + + // construct memory by declaring all inner arrays/vectors first + let v2_ptr = 0u128; + let mut memory = v2.clone(); + let v2_start = memory.len(); + memory.extend(vec![Value::from(v2_ptr), Value::from(v2.len()), Value::from(1u128)]); + let a4_ptr = memory.len(); + memory.extend(a4.clone()); + let a4_start = memory.len(); + memory.extend(vec![Value::from(a4_ptr), Value::from(1u128)]); + let v6_ptr = memory.len(); + memory.extend(v6.clone()); + let v6_start = memory.len(); + memory.extend(vec![Value::from(v6_ptr), Value::from(v6.len()), Value::from(1u128)]); + let a9_ptr = memory.len(); + memory.extend(a9.clone()); + let a9_start = memory.len(); + memory.extend(vec![Value::from(a9_ptr), Value::from(1u128)]); + // finally we add the contents of the outer array + let outer_ptr = memory.len(); + let outer_array = vec![ + Value::from(1u128), + Value::from(v2.len()), + Value::from(v2_start), + Value::from(a4_start), + Value::from(5u128), + Value::from(v6.len()), + Value::from(v6_start), + Value::from(a9_start), + ]; + memory.extend(outer_array.clone()); + + let input_array_value_types = vec![ + HeapValueType::Simple, + HeapValueType::Simple, // size of following vector + HeapValueType::Vector { value_types: vec![HeapValueType::Simple] }, + HeapValueType::Array { value_types: vec![HeapValueType::Simple], size: 1 }, + ]; + + let r_input = RegisterIndex::from(0); + let r_output = RegisterIndex::from(1); + + let program = vec![ + // input = 0 + Opcode::Const { destination: r_input, value: Value::from(outer_ptr) }, + // some_function(input) + Opcode::ForeignCall { + function: "flat_sum".into(), + destinations: vec![RegisterOrMemory::RegisterIndex(r_output)], + inputs: vec![ + RegisterOrMemory::HeapArray(HeapArray { + pointer: r_input, + size: outer_array.len(), + value_types: input_array_value_types, + }), + ], + }, + ]; + + let mut vm = brillig_execute_and_get_vm(memory, &program); + + // Check that VM is waiting + assert_eq!( + vm.status, + VMStatus::ForeignCallWait { + function: "flat_sum".into(), + inputs: vec![ + ForeignCallParam::Array(vec![ + Value::from(1u128), + Value::from(2u128), // size of following vector + Value::from(2u128), + Value::from(3u128), + Value::from(4u128), + Value::from(5u128), + Value::from(3u128), // size of following vector + Value::from(6u128), + Value::from(7u128), + Value::from(8u128), + Value::from(9u128), + ]) + ], + } + ); + + // Push result we're waiting for + vm.resolve_foreign_call(Value::from(45u128).into()); + + // Resume VM + brillig_execute(&mut vm); + + // Check that VM finished once resumed + assert_eq!(vm.status, VMStatus::Finished); + + // Check result + let result_value = vm.registers.get(r_output); + assert_eq!(result_value, Value::from(45u128)); + + // Ensure the foreign call counter has been incremented + assert_eq!(vm.foreign_call_counter, 1); + } } From 11d244127dedf8a6ddee711c334db28abf5b916f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Gir=C3=A1ldez?= Date: Tue, 16 Jan 2024 10:19:04 -0500 Subject: [PATCH 04/10] chore: cargo fmt --- acvm-repo/brillig_vm/src/lib.rs | 40 +++++++++++++++------------------ 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/acvm-repo/brillig_vm/src/lib.rs b/acvm-repo/brillig_vm/src/lib.rs index acbc419d204..d488a968d07 100644 --- a/acvm-repo/brillig_vm/src/lib.rs +++ b/acvm-repo/brillig_vm/src/lib.rs @@ -1383,13 +1383,11 @@ mod tests { Opcode::ForeignCall { function: "flat_sum".into(), destinations: vec![RegisterOrMemory::RegisterIndex(r_output)], - inputs: vec![ - RegisterOrMemory::HeapArray(HeapArray { - pointer: r_input, - size: outer_array.len(), - value_types: input_array_value_types, - }), - ], + inputs: vec![RegisterOrMemory::HeapArray(HeapArray { + pointer: r_input, + size: outer_array.len(), + value_types: input_array_value_types, + })], }, ]; @@ -1400,21 +1398,19 @@ mod tests { vm.status, VMStatus::ForeignCallWait { function: "flat_sum".into(), - inputs: vec![ - ForeignCallParam::Array(vec![ - Value::from(1u128), - Value::from(2u128), // size of following vector - Value::from(2u128), - Value::from(3u128), - Value::from(4u128), - Value::from(5u128), - Value::from(3u128), // size of following vector - Value::from(6u128), - Value::from(7u128), - Value::from(8u128), - Value::from(9u128), - ]) - ], + inputs: vec![ForeignCallParam::Array(vec![ + Value::from(1u128), + Value::from(2u128), // size of following vector + Value::from(2u128), + Value::from(3u128), + Value::from(4u128), + Value::from(5u128), + Value::from(3u128), // size of following vector + Value::from(6u128), + Value::from(7u128), + Value::from(8u128), + Value::from(9u128), + ])], } ); From 08d61b8af0ee91d61400af9061ae83c84208b1e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Gir=C3=A1ldez?= Date: Tue, 16 Jan 2024 11:01:10 -0500 Subject: [PATCH 05/10] feat: update serialization or ACIR circuits --- acvm-repo/acir/codegen/acir.cpp | 198 ++++++++++++++++++ acvm-repo/acir/src/lib.rs | 4 +- .../acir/tests/test_program_serialization.rs | 28 ++- .../test/shared/complex_foreign_call.ts | 12 +- 4 files changed, 226 insertions(+), 16 deletions(-) diff --git a/acvm-repo/acir/codegen/acir.cpp b/acvm-repo/acir/codegen/acir.cpp index 2b217c7e93d..5ea491c31f5 100644 --- a/acvm-repo/acir/codegen/acir.cpp +++ b/acvm-repo/acir/codegen/acir.cpp @@ -360,6 +360,40 @@ namespace Circuit { static BinaryIntOp bincodeDeserialize(std::vector); }; + struct HeapValueType; + + struct HeapValueType { + + struct Simple { + friend bool operator==(const Simple&, const Simple&); + std::vector bincodeSerialize() const; + static Simple bincodeDeserialize(std::vector); + }; + + struct Array { + std::vector value_types; + uint64_t size; + + friend bool operator==(const Array&, const Array&); + std::vector bincodeSerialize() const; + static Array bincodeDeserialize(std::vector); + }; + + struct Vector { + std::vector value_types; + + friend bool operator==(const Vector&, const Vector&); + std::vector bincodeSerialize() const; + static Vector bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const HeapValueType&, const HeapValueType&); + std::vector bincodeSerialize() const; + static HeapValueType bincodeDeserialize(std::vector); + }; + struct RegisterIndex { uint64_t value; @@ -371,6 +405,7 @@ namespace Circuit { struct HeapArray { Circuit::RegisterIndex pointer; uint64_t size; + std::vector value_types; friend bool operator==(const HeapArray&, const HeapArray&); std::vector bincodeSerialize() const; @@ -380,6 +415,7 @@ namespace Circuit { struct HeapVector { Circuit::RegisterIndex pointer; Circuit::RegisterIndex size; + std::vector value_types; friend bool operator==(const HeapVector&, const HeapVector&); std::vector bincodeSerialize() const; @@ -4083,6 +4119,7 @@ namespace Circuit { inline bool operator==(const HeapArray &lhs, const HeapArray &rhs) { if (!(lhs.pointer == rhs.pointer)) { return false; } if (!(lhs.size == rhs.size)) { return false; } + if (!(lhs.value_types == rhs.value_types)) { return false; } return true; } @@ -4109,6 +4146,7 @@ void serde::Serializable::serialize(const Circuit::HeapArray serializer.increase_container_depth(); serde::Serializable::serialize(obj.pointer, serializer); serde::Serializable::serialize(obj.size, serializer); + serde::Serializable::serialize(obj.value_types, serializer); serializer.decrease_container_depth(); } @@ -4119,15 +4157,173 @@ Circuit::HeapArray serde::Deserializable::deserialize(Deseri Circuit::HeapArray obj; obj.pointer = serde::Deserializable::deserialize(deserializer); obj.size = serde::Deserializable::deserialize(deserializer); + obj.value_types = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } +namespace Circuit { + + inline bool operator==(const HeapValueType &lhs, const HeapValueType &rhs) { + if (!(lhs.value == rhs.value)) { return false; } + return true; + } + + inline std::vector HeapValueType::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline HeapValueType HeapValueType::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::HeapValueType &obj, Serializer &serializer) { + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); +} + +template <> +template +Circuit::HeapValueType serde::Deserializable::deserialize(Deserializer &deserializer) { + deserializer.increase_container_depth(); + Circuit::HeapValueType obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); + return obj; +} + +namespace Circuit { + + inline bool operator==(const HeapValueType::Simple &lhs, const HeapValueType::Simple &rhs) { + return true; + } + + inline std::vector HeapValueType::Simple::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline HeapValueType::Simple HeapValueType::Simple::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::HeapValueType::Simple &obj, Serializer &serializer) { +} + +template <> +template +Circuit::HeapValueType::Simple serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::HeapValueType::Simple obj; + return obj; +} + +namespace Circuit { + + inline bool operator==(const HeapValueType::Array &lhs, const HeapValueType::Array &rhs) { + if (!(lhs.value_types == rhs.value_types)) { return false; } + if (!(lhs.size == rhs.size)) { return false; } + return true; + } + + inline std::vector HeapValueType::Array::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline HeapValueType::Array HeapValueType::Array::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::HeapValueType::Array &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.value_types, serializer); + serde::Serializable::serialize(obj.size, serializer); +} + +template <> +template +Circuit::HeapValueType::Array serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::HeapValueType::Array obj; + obj.value_types = serde::Deserializable::deserialize(deserializer); + obj.size = serde::Deserializable::deserialize(deserializer); + return obj; +} + +namespace Circuit { + + inline bool operator==(const HeapValueType::Vector &lhs, const HeapValueType::Vector &rhs) { + if (!(lhs.value_types == rhs.value_types)) { return false; } + return true; + } + + inline std::vector HeapValueType::Vector::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline HeapValueType::Vector HeapValueType::Vector::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::HeapValueType::Vector &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.value_types, serializer); +} + +template <> +template +Circuit::HeapValueType::Vector serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::HeapValueType::Vector obj; + obj.value_types = serde::Deserializable::deserialize(deserializer); + return obj; +} + namespace Circuit { inline bool operator==(const HeapVector &lhs, const HeapVector &rhs) { if (!(lhs.pointer == rhs.pointer)) { return false; } if (!(lhs.size == rhs.size)) { return false; } + if (!(lhs.value_types == rhs.value_types)) { return false; } return true; } @@ -4154,6 +4350,7 @@ void serde::Serializable::serialize(const Circuit::HeapVect serializer.increase_container_depth(); serde::Serializable::serialize(obj.pointer, serializer); serde::Serializable::serialize(obj.size, serializer); + serde::Serializable::serialize(obj.value_types, serializer); serializer.decrease_container_depth(); } @@ -4164,6 +4361,7 @@ Circuit::HeapVector serde::Deserializable::deserialize(Dese Circuit::HeapVector obj; obj.pointer = serde::Deserializable::deserialize(deserializer); obj.size = serde::Deserializable::deserialize(deserializer); + obj.value_types = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } diff --git a/acvm-repo/acir/src/lib.rs b/acvm-repo/acir/src/lib.rs index b7bcaa0c5c0..50de09c5ad9 100644 --- a/acvm-repo/acir/src/lib.rs +++ b/acvm-repo/acir/src/lib.rs @@ -32,7 +32,8 @@ mod reflection { }; use brillig::{ - BinaryFieldOp, BinaryIntOp, BlackBoxOp, Opcode as BrilligOpcode, RegisterOrMemory, + BinaryFieldOp, BinaryIntOp, BlackBoxOp, HeapValueType, Opcode as BrilligOpcode, + RegisterOrMemory, }; use serde_reflection::{Tracer, TracerConfig}; @@ -70,6 +71,7 @@ mod reflection { tracer.trace_simple_type::().unwrap(); tracer.trace_simple_type::().unwrap(); tracer.trace_simple_type::().unwrap(); + tracer.trace_simple_type::().unwrap(); let registry = tracer.registry().unwrap(); diff --git a/acvm-repo/acir/tests/test_program_serialization.rs b/acvm-repo/acir/tests/test_program_serialization.rs index 7d3b7b32d35..8df4f992fb2 100644 --- a/acvm-repo/acir/tests/test_program_serialization.rs +++ b/acvm-repo/acir/tests/test_program_serialization.rs @@ -20,7 +20,7 @@ use acir::{ native_types::{Expression, Witness}, }; use acir_field::FieldElement; -use brillig::{HeapArray, RegisterIndex, RegisterOrMemory}; +use brillig::{HeapArray, HeapValueType, RegisterIndex, RegisterOrMemory}; #[test] fn addition_circuit() { @@ -245,11 +245,19 @@ fn complex_brillig_foreign_call() { brillig::Opcode::ForeignCall { function: "complex".into(), inputs: vec![ - RegisterOrMemory::HeapArray(HeapArray { pointer: 0.into(), size: 3 }), + RegisterOrMemory::HeapArray(HeapArray { + pointer: 0.into(), + size: 3, + value_types: vec![HeapValueType::Simple], + }), RegisterOrMemory::RegisterIndex(RegisterIndex::from(1)), ], destinations: vec![ - RegisterOrMemory::HeapArray(HeapArray { pointer: 0.into(), size: 3 }), + RegisterOrMemory::HeapArray(HeapArray { + pointer: 0.into(), + size: 3, + value_types: vec![HeapValueType::Simple], + }), RegisterOrMemory::RegisterIndex(RegisterIndex::from(1)), RegisterOrMemory::RegisterIndex(RegisterIndex::from(2)), ], @@ -269,13 +277,13 @@ fn complex_brillig_foreign_call() { let bytes = Circuit::serialize_circuit(&circuit); let expected_serialization: Vec = 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, 84, 219, 10, 128, 48, 8, 117, 174, 203, 62, 103, + 253, 65, 255, 18, 189, 21, 245, 216, 231, 55, 200, 193, 193, 122, 137, 28, 180, 3, 226, 20, + 39, 135, 29, 103, 32, 34, 71, 23, 124, 50, 150, 179, 147, 24, 145, 235, 70, 241, 241, 27, + 6, 103, 215, 43, 150, 226, 200, 21, 112, 244, 5, 56, 230, 121, 248, 169, 222, 150, 186, + 152, 190, 159, 127, 248, 63, 77, 178, 54, 89, 39, 113, 47, 62, 192, 44, 4, 200, 79, 219, + 186, 47, 243, 129, 173, 180, 36, 152, 211, 49, 43, 255, 234, 62, 22, 48, 221, 119, 0, 226, + 4, 104, 45, 56, 241, 60, 4, 0, 0, ]; assert_eq!(bytes, expected_serialization) diff --git a/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts b/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts index 1b6f5e4319a..d685ba33cac 100644 --- a/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts +++ b/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts @@ -2,11 +2,13 @@ import { WitnessMap } from '@noir-lang/acvm_js'; // See `complex_brillig_foreign_call` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 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, 84, 219, 10, 128, 48, 8, 117, 174, 203, 62, 103, + 253, 65, 255, 18, 189, 21, 245, 216, 231, 55, 200, 193, 193, 122, 137, 28, 180, 3, 226, 20, + 39, 135, 29, 103, 32, 34, 71, 23, 124, 50, 150, 179, 147, 24, 145, 235, 70, 241, 241, 27, + 6, 103, 215, 43, 150, 226, 200, 21, 112, 244, 5, 56, 230, 121, 248, 169, 222, 150, 186, + 152, 190, 159, 127, 248, 63, 77, 178, 54, 89, 39, 113, 47, 62, 192, 44, 4, 200, 79, 219, + 186, 47, 243, 129, 173, 180, 36, 152, 211, 49, 43, 255, 234, 62, 22, 48, 221, 119, 0, 226, + 4, 104, 45, 56, 241, 60, 4, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000001'], From 182d5f82e04cd563e929821e0614bd8a592eabdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Gir=C3=A1ldez?= Date: Tue, 16 Jan 2024 11:30:29 -0500 Subject: [PATCH 06/10] chore: run prettier --- .../acvm_js/test/shared/complex_foreign_call.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts b/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts index d685ba33cac..ff444879eea 100644 --- a/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts +++ b/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts @@ -2,13 +2,11 @@ import { WitnessMap } from '@noir-lang/acvm_js'; // See `complex_brillig_foreign_call` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 219, 10, 128, 48, 8, 117, 174, 203, 62, 103, - 253, 65, 255, 18, 189, 21, 245, 216, 231, 55, 200, 193, 193, 122, 137, 28, 180, 3, 226, 20, - 39, 135, 29, 103, 32, 34, 71, 23, 124, 50, 150, 179, 147, 24, 145, 235, 70, 241, 241, 27, - 6, 103, 215, 43, 150, 226, 200, 21, 112, 244, 5, 56, 230, 121, 248, 169, 222, 150, 186, - 152, 190, 159, 127, 248, 63, 77, 178, 54, 89, 39, 113, 47, 62, 192, 44, 4, 200, 79, 219, - 186, 47, 243, 129, 173, 180, 36, 152, 211, 49, 43, 255, 234, 62, 22, 48, 221, 119, 0, 226, - 4, 104, 45, 56, 241, 60, 4, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 219, 10, 128, 48, 8, 117, 174, 203, 62, 103, 253, 65, 255, 18, 189, 21, + 245, 216, 231, 55, 200, 193, 193, 122, 137, 28, 180, 3, 226, 20, 39, 135, 29, 103, 32, 34, 71, 23, 124, 50, 150, 179, + 147, 24, 145, 235, 70, 241, 241, 27, 6, 103, 215, 43, 150, 226, 200, 21, 112, 244, 5, 56, 230, 121, 248, 169, 222, + 150, 186, 152, 190, 159, 127, 248, 63, 77, 178, 54, 89, 39, 113, 47, 62, 192, 44, 4, 200, 79, 219, 186, 47, 243, 129, + 173, 180, 36, 152, 211, 49, 43, 255, 234, 62, 22, 48, 221, 119, 0, 226, 4, 104, 45, 56, 241, 60, 4, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000001'], From f7666e414846c3dc6a6330c67ec59331fd58d407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Gir=C3=A1ldez?= Date: Tue, 16 Jan 2024 12:19:12 -0500 Subject: [PATCH 07/10] fix: test compilation in noirc_evaluator --- compiler/noirc_evaluator/src/brillig/brillig_ir.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index 976a344b800..5001523ce54 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -1045,6 +1045,7 @@ pub(crate) mod tests { BinaryIntOp, ForeignCallParam, ForeignCallResult, HeapVector, RegisterIndex, RegisterOrMemory, Value, }; + use acvm::brillig_vm::brillig::HeapValueType; use acvm::brillig_vm::{Registers, VMStatus, VM}; use acvm::{BlackBoxFunctionSolver, BlackBoxResolutionError, FieldElement}; @@ -1151,7 +1152,11 @@ pub(crate) mod tests { context.foreign_call_instruction( "make_number_sequence".into(), &[RegisterOrMemory::RegisterIndex(r_input_size)], - &[RegisterOrMemory::HeapVector(HeapVector { pointer: r_stack, size: r_output_size })], + &[RegisterOrMemory::HeapVector(HeapVector { + pointer: r_stack, + size: r_output_size, + value_types: vec![HeapValueType::Simple], + })], ); // push stack frame by r_returned_size context.memory_op(r_stack, r_output_size, r_stack, BinaryIntOp::Add); From 60e4c9eb3607b8be7edc328ad61c4d44f6c68876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Gir=C3=A1ldez?= Date: Tue, 23 Jan 2024 19:53:12 -0500 Subject: [PATCH 08/10] feat: Move heap value types into the ForeignCall opcode And remove it from the HeapArray/HeapVector types which are used for other situations where the runtime type information is not needed (eg. blackbox calls which are statically typed). --- acvm-repo/acir/codegen/acir.cpp | 564 +++++++++--------- .../acir/tests/test_program_serialization.rs | 46 +- acvm-repo/acvm/tests/solver.rs | 13 + .../test/shared/complex_foreign_call.ts | 11 +- acvm-repo/acvm_js/test/shared/foreign_call.ts | 8 +- acvm-repo/brillig/src/opcodes.rs | 7 +- acvm-repo/brillig_vm/src/black_box.rs | 14 +- acvm-repo/brillig_vm/src/lib.rs | 144 +++-- .../brillig/brillig_gen/brillig_black_box.rs | 45 +- .../src/brillig/brillig_gen/brillig_block.rs | 17 +- .../noirc_evaluator/src/brillig/brillig_ir.rs | 15 +- .../brillig/brillig_ir/brillig_variable.rs | 34 +- tooling/debugger/src/context.rs | 4 +- 13 files changed, 497 insertions(+), 425 deletions(-) diff --git a/acvm-repo/acir/codegen/acir.cpp b/acvm-repo/acir/codegen/acir.cpp index 5ea491c31f5..69e926bd57b 100644 --- a/acvm-repo/acir/codegen/acir.cpp +++ b/acvm-repo/acir/codegen/acir.cpp @@ -5,235 +5,6 @@ namespace Circuit { - struct Witness { - uint32_t value; - - friend bool operator==(const Witness&, const Witness&); - std::vector bincodeSerialize() const; - static Witness bincodeDeserialize(std::vector); - }; - - struct FunctionInput { - Circuit::Witness witness; - uint32_t num_bits; - - friend bool operator==(const FunctionInput&, const FunctionInput&); - std::vector bincodeSerialize() const; - static FunctionInput bincodeDeserialize(std::vector); - }; - - struct BlackBoxFuncCall { - - struct AND { - Circuit::FunctionInput lhs; - Circuit::FunctionInput rhs; - Circuit::Witness output; - - friend bool operator==(const AND&, const AND&); - std::vector bincodeSerialize() const; - static AND bincodeDeserialize(std::vector); - }; - - struct XOR { - Circuit::FunctionInput lhs; - Circuit::FunctionInput rhs; - Circuit::Witness output; - - friend bool operator==(const XOR&, const XOR&); - std::vector bincodeSerialize() const; - static XOR bincodeDeserialize(std::vector); - }; - - struct RANGE { - Circuit::FunctionInput input; - - friend bool operator==(const RANGE&, const RANGE&); - std::vector bincodeSerialize() const; - static RANGE bincodeDeserialize(std::vector); - }; - - struct SHA256 { - std::vector inputs; - std::vector outputs; - - friend bool operator==(const SHA256&, const SHA256&); - std::vector bincodeSerialize() const; - static SHA256 bincodeDeserialize(std::vector); - }; - - struct Blake2s { - std::vector inputs; - std::vector outputs; - - friend bool operator==(const Blake2s&, const Blake2s&); - std::vector bincodeSerialize() const; - static Blake2s bincodeDeserialize(std::vector); - }; - - struct Blake3 { - std::vector inputs; - std::vector outputs; - - friend bool operator==(const Blake3&, const Blake3&); - std::vector bincodeSerialize() const; - static Blake3 bincodeDeserialize(std::vector); - }; - - struct SchnorrVerify { - Circuit::FunctionInput public_key_x; - Circuit::FunctionInput public_key_y; - std::vector signature; - std::vector message; - Circuit::Witness output; - - friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); - std::vector bincodeSerialize() const; - static SchnorrVerify bincodeDeserialize(std::vector); - }; - - struct PedersenCommitment { - std::vector inputs; - uint32_t domain_separator; - std::array outputs; - - friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); - std::vector bincodeSerialize() const; - static PedersenCommitment bincodeDeserialize(std::vector); - }; - - struct PedersenHash { - std::vector inputs; - uint32_t domain_separator; - Circuit::Witness output; - - friend bool operator==(const PedersenHash&, const PedersenHash&); - std::vector bincodeSerialize() const; - static PedersenHash bincodeDeserialize(std::vector); - }; - - struct EcdsaSecp256k1 { - std::vector public_key_x; - std::vector public_key_y; - std::vector signature; - std::vector hashed_message; - Circuit::Witness output; - - friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); - std::vector bincodeSerialize() const; - static EcdsaSecp256k1 bincodeDeserialize(std::vector); - }; - - struct EcdsaSecp256r1 { - std::vector public_key_x; - std::vector public_key_y; - std::vector signature; - std::vector hashed_message; - Circuit::Witness output; - - friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); - std::vector bincodeSerialize() const; - static EcdsaSecp256r1 bincodeDeserialize(std::vector); - }; - - struct FixedBaseScalarMul { - Circuit::FunctionInput low; - Circuit::FunctionInput high; - std::array outputs; - - friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); - std::vector bincodeSerialize() const; - static FixedBaseScalarMul bincodeDeserialize(std::vector); - }; - - struct Keccak256 { - std::vector inputs; - std::vector outputs; - - friend bool operator==(const Keccak256&, const Keccak256&); - std::vector bincodeSerialize() const; - static Keccak256 bincodeDeserialize(std::vector); - }; - - struct Keccak256VariableLength { - std::vector inputs; - Circuit::FunctionInput var_message_size; - std::vector outputs; - - friend bool operator==(const Keccak256VariableLength&, const Keccak256VariableLength&); - std::vector bincodeSerialize() const; - static Keccak256VariableLength bincodeDeserialize(std::vector); - }; - - struct Keccakf1600 { - std::vector inputs; - std::vector outputs; - - friend bool operator==(const Keccakf1600&, const Keccakf1600&); - std::vector bincodeSerialize() const; - static Keccakf1600 bincodeDeserialize(std::vector); - }; - - struct RecursiveAggregation { - std::vector verification_key; - std::vector proof; - std::vector public_inputs; - Circuit::FunctionInput key_hash; - - friend bool operator==(const RecursiveAggregation&, const RecursiveAggregation&); - std::vector bincodeSerialize() const; - static RecursiveAggregation bincodeDeserialize(std::vector); - }; - - std::variant value; - - friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); - std::vector bincodeSerialize() const; - static BlackBoxFuncCall bincodeDeserialize(std::vector); - }; - - struct BlockId { - uint32_t value; - - friend bool operator==(const BlockId&, const BlockId&); - std::vector bincodeSerialize() const; - static BlockId bincodeDeserialize(std::vector); - }; - - struct Expression { - std::vector> mul_terms; - std::vector> linear_combinations; - std::string q_c; - - friend bool operator==(const Expression&, const Expression&); - std::vector bincodeSerialize() const; - static Expression bincodeDeserialize(std::vector); - }; - - struct BrilligInputs { - - struct Single { - Circuit::Expression value; - - friend bool operator==(const Single&, const Single&); - std::vector bincodeSerialize() const; - static Single bincodeDeserialize(std::vector); - }; - - struct Array { - std::vector value; - - friend bool operator==(const Array&, const Array&); - std::vector bincodeSerialize() const; - static Array bincodeDeserialize(std::vector); - }; - - std::variant value; - - friend bool operator==(const BrilligInputs&, const BrilligInputs&); - std::vector bincodeSerialize() const; - static BrilligInputs bincodeDeserialize(std::vector); - }; - struct BinaryFieldOp { struct Add { @@ -360,40 +131,6 @@ namespace Circuit { static BinaryIntOp bincodeDeserialize(std::vector); }; - struct HeapValueType; - - struct HeapValueType { - - struct Simple { - friend bool operator==(const Simple&, const Simple&); - std::vector bincodeSerialize() const; - static Simple bincodeDeserialize(std::vector); - }; - - struct Array { - std::vector value_types; - uint64_t size; - - friend bool operator==(const Array&, const Array&); - std::vector bincodeSerialize() const; - static Array bincodeDeserialize(std::vector); - }; - - struct Vector { - std::vector value_types; - - friend bool operator==(const Vector&, const Vector&); - std::vector bincodeSerialize() const; - static Vector bincodeDeserialize(std::vector); - }; - - std::variant value; - - friend bool operator==(const HeapValueType&, const HeapValueType&); - std::vector bincodeSerialize() const; - static HeapValueType bincodeDeserialize(std::vector); - }; - struct RegisterIndex { uint64_t value; @@ -405,7 +142,6 @@ namespace Circuit { struct HeapArray { Circuit::RegisterIndex pointer; uint64_t size; - std::vector value_types; friend bool operator==(const HeapArray&, const HeapArray&); std::vector bincodeSerialize() const; @@ -415,7 +151,6 @@ namespace Circuit { struct HeapVector { Circuit::RegisterIndex pointer; Circuit::RegisterIndex size; - std::vector value_types; friend bool operator==(const HeapVector&, const HeapVector&); std::vector bincodeSerialize() const; @@ -502,26 +237,60 @@ namespace Circuit { Circuit::RegisterIndex domain_separator; Circuit::RegisterIndex output; - friend bool operator==(const PedersenHash&, const PedersenHash&); + friend bool operator==(const PedersenHash&, const PedersenHash&); + std::vector bincodeSerialize() const; + static PedersenHash bincodeDeserialize(std::vector); + }; + + struct FixedBaseScalarMul { + Circuit::RegisterIndex low; + Circuit::RegisterIndex high; + Circuit::HeapArray result; + + friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); + std::vector bincodeSerialize() const; + static FixedBaseScalarMul bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const BlackBoxOp&, const BlackBoxOp&); + std::vector bincodeSerialize() const; + static BlackBoxOp bincodeDeserialize(std::vector); + }; + + struct HeapValueType; + + struct HeapValueType { + + struct Simple { + friend bool operator==(const Simple&, const Simple&); + std::vector bincodeSerialize() const; + static Simple bincodeDeserialize(std::vector); + }; + + struct Array { + std::vector value_types; + uint64_t size; + + friend bool operator==(const Array&, const Array&); std::vector bincodeSerialize() const; - static PedersenHash bincodeDeserialize(std::vector); + static Array bincodeDeserialize(std::vector); }; - struct FixedBaseScalarMul { - Circuit::RegisterIndex low; - Circuit::RegisterIndex high; - Circuit::HeapArray result; + struct Vector { + std::vector value_types; - friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); + friend bool operator==(const Vector&, const Vector&); std::vector bincodeSerialize() const; - static FixedBaseScalarMul bincodeDeserialize(std::vector); + static Vector bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; - friend bool operator==(const BlackBoxOp&, const BlackBoxOp&); + friend bool operator==(const HeapValueType&, const HeapValueType&); std::vector bincodeSerialize() const; - static BlackBoxOp bincodeDeserialize(std::vector); + static HeapValueType bincodeDeserialize(std::vector); }; struct RegisterOrMemory { @@ -642,7 +411,9 @@ namespace Circuit { struct ForeignCall { std::string function; std::vector destinations; + std::vector destination_value_types; std::vector inputs; + std::vector input_value_types; friend bool operator==(const ForeignCall&, const ForeignCall&); std::vector bincodeSerialize() const; @@ -703,6 +474,235 @@ namespace Circuit { static BrilligOpcode bincodeDeserialize(std::vector); }; + struct Witness { + uint32_t value; + + friend bool operator==(const Witness&, const Witness&); + std::vector bincodeSerialize() const; + static Witness bincodeDeserialize(std::vector); + }; + + struct FunctionInput { + Circuit::Witness witness; + uint32_t num_bits; + + friend bool operator==(const FunctionInput&, const FunctionInput&); + std::vector bincodeSerialize() const; + static FunctionInput bincodeDeserialize(std::vector); + }; + + struct BlackBoxFuncCall { + + struct AND { + Circuit::FunctionInput lhs; + Circuit::FunctionInput rhs; + Circuit::Witness output; + + friend bool operator==(const AND&, const AND&); + std::vector bincodeSerialize() const; + static AND bincodeDeserialize(std::vector); + }; + + struct XOR { + Circuit::FunctionInput lhs; + Circuit::FunctionInput rhs; + Circuit::Witness output; + + friend bool operator==(const XOR&, const XOR&); + std::vector bincodeSerialize() const; + static XOR bincodeDeserialize(std::vector); + }; + + struct RANGE { + Circuit::FunctionInput input; + + friend bool operator==(const RANGE&, const RANGE&); + std::vector bincodeSerialize() const; + static RANGE bincodeDeserialize(std::vector); + }; + + struct SHA256 { + std::vector inputs; + std::vector outputs; + + friend bool operator==(const SHA256&, const SHA256&); + std::vector bincodeSerialize() const; + static SHA256 bincodeDeserialize(std::vector); + }; + + struct Blake2s { + std::vector inputs; + std::vector outputs; + + friend bool operator==(const Blake2s&, const Blake2s&); + std::vector bincodeSerialize() const; + static Blake2s bincodeDeserialize(std::vector); + }; + + struct Blake3 { + std::vector inputs; + std::vector outputs; + + friend bool operator==(const Blake3&, const Blake3&); + std::vector bincodeSerialize() const; + static Blake3 bincodeDeserialize(std::vector); + }; + + struct SchnorrVerify { + Circuit::FunctionInput public_key_x; + Circuit::FunctionInput public_key_y; + std::vector signature; + std::vector message; + Circuit::Witness output; + + friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); + std::vector bincodeSerialize() const; + static SchnorrVerify bincodeDeserialize(std::vector); + }; + + struct PedersenCommitment { + std::vector inputs; + uint32_t domain_separator; + std::array outputs; + + friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); + std::vector bincodeSerialize() const; + static PedersenCommitment bincodeDeserialize(std::vector); + }; + + struct PedersenHash { + std::vector inputs; + uint32_t domain_separator; + Circuit::Witness output; + + friend bool operator==(const PedersenHash&, const PedersenHash&); + std::vector bincodeSerialize() const; + static PedersenHash bincodeDeserialize(std::vector); + }; + + struct EcdsaSecp256k1 { + std::vector public_key_x; + std::vector public_key_y; + std::vector signature; + std::vector hashed_message; + Circuit::Witness output; + + friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); + std::vector bincodeSerialize() const; + static EcdsaSecp256k1 bincodeDeserialize(std::vector); + }; + + struct EcdsaSecp256r1 { + std::vector public_key_x; + std::vector public_key_y; + std::vector signature; + std::vector hashed_message; + Circuit::Witness output; + + friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); + std::vector bincodeSerialize() const; + static EcdsaSecp256r1 bincodeDeserialize(std::vector); + }; + + struct FixedBaseScalarMul { + Circuit::FunctionInput low; + Circuit::FunctionInput high; + std::array outputs; + + friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); + std::vector bincodeSerialize() const; + static FixedBaseScalarMul bincodeDeserialize(std::vector); + }; + + struct Keccak256 { + std::vector inputs; + std::vector outputs; + + friend bool operator==(const Keccak256&, const Keccak256&); + std::vector bincodeSerialize() const; + static Keccak256 bincodeDeserialize(std::vector); + }; + + struct Keccak256VariableLength { + std::vector inputs; + Circuit::FunctionInput var_message_size; + std::vector outputs; + + friend bool operator==(const Keccak256VariableLength&, const Keccak256VariableLength&); + std::vector bincodeSerialize() const; + static Keccak256VariableLength bincodeDeserialize(std::vector); + }; + + struct Keccakf1600 { + std::vector inputs; + std::vector outputs; + + friend bool operator==(const Keccakf1600&, const Keccakf1600&); + std::vector bincodeSerialize() const; + static Keccakf1600 bincodeDeserialize(std::vector); + }; + + struct RecursiveAggregation { + std::vector verification_key; + std::vector proof; + std::vector public_inputs; + Circuit::FunctionInput key_hash; + + friend bool operator==(const RecursiveAggregation&, const RecursiveAggregation&); + std::vector bincodeSerialize() const; + static RecursiveAggregation bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); + std::vector bincodeSerialize() const; + static BlackBoxFuncCall bincodeDeserialize(std::vector); + }; + + struct BlockId { + uint32_t value; + + friend bool operator==(const BlockId&, const BlockId&); + std::vector bincodeSerialize() const; + static BlockId bincodeDeserialize(std::vector); + }; + + struct Expression { + std::vector> mul_terms; + std::vector> linear_combinations; + std::string q_c; + + friend bool operator==(const Expression&, const Expression&); + std::vector bincodeSerialize() const; + static Expression bincodeDeserialize(std::vector); + }; + + struct BrilligInputs { + + struct Single { + Circuit::Expression value; + + friend bool operator==(const Single&, const Single&); + std::vector bincodeSerialize() const; + static Single bincodeDeserialize(std::vector); + }; + + struct Array { + std::vector value; + + friend bool operator==(const Array&, const Array&); + std::vector bincodeSerialize() const; + static Array bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const BrilligInputs&, const BrilligInputs&); + std::vector bincodeSerialize() const; + static BrilligInputs bincodeDeserialize(std::vector); + }; + struct BrilligOutputs { struct Simple { @@ -3405,7 +3405,9 @@ namespace Circuit { inline bool operator==(const BrilligOpcode::ForeignCall &lhs, const BrilligOpcode::ForeignCall &rhs) { if (!(lhs.function == rhs.function)) { return false; } if (!(lhs.destinations == rhs.destinations)) { return false; } + if (!(lhs.destination_value_types == rhs.destination_value_types)) { return false; } if (!(lhs.inputs == rhs.inputs)) { return false; } + if (!(lhs.input_value_types == rhs.input_value_types)) { return false; } return true; } @@ -3431,7 +3433,9 @@ template void serde::Serializable::serialize(const Circuit::BrilligOpcode::ForeignCall &obj, Serializer &serializer) { serde::Serializable::serialize(obj.function, serializer); serde::Serializable::serialize(obj.destinations, serializer); + serde::Serializable::serialize(obj.destination_value_types, serializer); serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.input_value_types, serializer); } template <> @@ -3440,7 +3444,9 @@ Circuit::BrilligOpcode::ForeignCall serde::Deserializable::deserialize(deserializer); obj.destinations = serde::Deserializable::deserialize(deserializer); + obj.destination_value_types = serde::Deserializable::deserialize(deserializer); obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.input_value_types = serde::Deserializable::deserialize(deserializer); return obj; } @@ -4119,7 +4125,6 @@ namespace Circuit { inline bool operator==(const HeapArray &lhs, const HeapArray &rhs) { if (!(lhs.pointer == rhs.pointer)) { return false; } if (!(lhs.size == rhs.size)) { return false; } - if (!(lhs.value_types == rhs.value_types)) { return false; } return true; } @@ -4146,7 +4151,6 @@ void serde::Serializable::serialize(const Circuit::HeapArray serializer.increase_container_depth(); serde::Serializable::serialize(obj.pointer, serializer); serde::Serializable::serialize(obj.size, serializer); - serde::Serializable::serialize(obj.value_types, serializer); serializer.decrease_container_depth(); } @@ -4157,7 +4161,6 @@ Circuit::HeapArray serde::Deserializable::deserialize(Deseri Circuit::HeapArray obj; obj.pointer = serde::Deserializable::deserialize(deserializer); obj.size = serde::Deserializable::deserialize(deserializer); - obj.value_types = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } @@ -4323,7 +4326,6 @@ namespace Circuit { inline bool operator==(const HeapVector &lhs, const HeapVector &rhs) { if (!(lhs.pointer == rhs.pointer)) { return false; } if (!(lhs.size == rhs.size)) { return false; } - if (!(lhs.value_types == rhs.value_types)) { return false; } return true; } @@ -4350,7 +4352,6 @@ void serde::Serializable::serialize(const Circuit::HeapVect serializer.increase_container_depth(); serde::Serializable::serialize(obj.pointer, serializer); serde::Serializable::serialize(obj.size, serializer); - serde::Serializable::serialize(obj.value_types, serializer); serializer.decrease_container_depth(); } @@ -4361,7 +4362,6 @@ Circuit::HeapVector serde::Deserializable::deserialize(Dese Circuit::HeapVector obj; obj.pointer = serde::Deserializable::deserialize(deserializer); obj.size = serde::Deserializable::deserialize(deserializer); - obj.value_types = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } diff --git a/acvm-repo/acir/tests/test_program_serialization.rs b/acvm-repo/acir/tests/test_program_serialization.rs index 8df4f992fb2..6dc1bd1dc43 100644 --- a/acvm-repo/acir/tests/test_program_serialization.rs +++ b/acvm-repo/acir/tests/test_program_serialization.rs @@ -180,7 +180,9 @@ fn simple_brillig_foreign_call() { bytecode: vec![brillig::Opcode::ForeignCall { function: "invert".into(), destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], + input_value_types: vec![HeapValueType::Simple], }], predicate: None, }; @@ -196,10 +198,11 @@ fn simple_brillig_foreign_call() { let bytes = Circuit::serialize_circuit(&circuit); let expected_serialization: Vec = 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, 49, 10, 0, 33, 12, 4, 215, 28, 28, 62, 199, + 251, 193, 125, 198, 194, 198, 66, 196, 247, 43, 168, 176, 136, 218, 232, 64, 200, 50, 69, + 216, 104, 0, 10, 149, 135, 50, 211, 221, 223, 182, 57, 227, 83, 247, 110, 25, 238, 43, 212, + 85, 151, 121, 91, 118, 62, 217, 16, 119, 159, 141, 121, 234, 132, 164, 96, 77, 6, 148, 102, + 152, 53, 83, 1, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -245,22 +248,23 @@ fn complex_brillig_foreign_call() { brillig::Opcode::ForeignCall { function: "complex".into(), inputs: vec![ - RegisterOrMemory::HeapArray(HeapArray { - pointer: 0.into(), - size: 3, - value_types: vec![HeapValueType::Simple], - }), + RegisterOrMemory::HeapArray(HeapArray { pointer: 0.into(), size: 3 }), RegisterOrMemory::RegisterIndex(RegisterIndex::from(1)), ], + input_value_types: vec![ + HeapValueType::Array { size: 3, value_types: vec![HeapValueType::Simple] }, + HeapValueType::Simple, + ], destinations: vec![ - RegisterOrMemory::HeapArray(HeapArray { - pointer: 0.into(), - size: 3, - value_types: vec![HeapValueType::Simple], - }), + RegisterOrMemory::HeapArray(HeapArray { pointer: 0.into(), size: 3 }), RegisterOrMemory::RegisterIndex(RegisterIndex::from(1)), RegisterOrMemory::RegisterIndex(RegisterIndex::from(2)), ], + destination_value_types: vec![ + HeapValueType::Array { size: 3, value_types: vec![HeapValueType::Simple] }, + HeapValueType::Simple, + HeapValueType::Simple, + ], }, ], predicate: None, @@ -277,13 +281,13 @@ fn complex_brillig_foreign_call() { let bytes = Circuit::serialize_circuit(&circuit); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 219, 10, 128, 48, 8, 117, 174, 203, 62, 103, - 253, 65, 255, 18, 189, 21, 245, 216, 231, 55, 200, 193, 193, 122, 137, 28, 180, 3, 226, 20, - 39, 135, 29, 103, 32, 34, 71, 23, 124, 50, 150, 179, 147, 24, 145, 235, 70, 241, 241, 27, - 6, 103, 215, 43, 150, 226, 200, 21, 112, 244, 5, 56, 230, 121, 248, 169, 222, 150, 186, - 152, 190, 159, 127, 248, 63, 77, 178, 54, 89, 39, 113, 47, 62, 192, 44, 4, 200, 79, 219, - 186, 47, 243, 129, 173, 180, 36, 152, 211, 49, 43, 255, 234, 62, 22, 48, 221, 119, 0, 226, - 4, 104, 45, 56, 241, 60, 4, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 83, 109, 10, 128, 48, 8, 85, 215, 199, 142, 179, + 110, 208, 93, 162, 127, 69, 253, 236, 248, 13, 114, 240, 88, 81, 65, 27, 180, 7, 226, 116, + 238, 41, 83, 45, 17, 49, 29, 48, 94, 68, 207, 172, 54, 34, 196, 245, 170, 221, 55, 116, + 156, 142, 203, 229, 170, 81, 10, 168, 209, 100, 168, 49, 204, 195, 79, 251, 157, 178, 47, + 73, 255, 207, 92, 236, 79, 229, 165, 246, 210, 168, 221, 170, 182, 48, 11, 22, 252, 195, + 50, 175, 211, 184, 33, 85, 220, 146, 216, 47, 209, 61, 223, 188, 195, 248, 39, 110, 121, + 195, 135, 73, 133, 206, 201, 16, 59, 245, 249, 221, 124, 112, 4, 0, 0, ]; assert_eq!(bytes, expected_serialization) diff --git a/acvm-repo/acvm/tests/solver.rs b/acvm-repo/acvm/tests/solver.rs index 4a4b75df146..5f5c78453e2 100644 --- a/acvm-repo/acvm/tests/solver.rs +++ b/acvm-repo/acvm/tests/solver.rs @@ -13,6 +13,7 @@ use acir::{ use acvm::pwg::{ACVMStatus, ErrorLocation, ForeignCallWaitInfo, OpcodeResolutionError, ACVM}; use acvm_blackbox_solver::StubbedBlackBoxSolver; +use brillig_vm::brillig::HeapValueType; // Reenable these test cases once we move the brillig implementation of inversion down into the acvm stdlib. @@ -65,7 +66,9 @@ fn inversion_brillig_oracle_equivalence() { BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(1))], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], + input_value_types: vec![HeapValueType::Simple], }, ], predicate: None, @@ -187,12 +190,16 @@ fn double_inversion_brillig_oracle() { BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(1))], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], + input_value_types: vec![HeapValueType::Simple], }, BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(3))], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(2))], + input_value_types: vec![HeapValueType::Simple], }, ], predicate: None, @@ -312,12 +319,16 @@ fn oracle_dependent_execution() { BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(1))], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], + input_value_types: vec![HeapValueType::Simple], }, BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(3))], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(2))], + input_value_types: vec![HeapValueType::Simple], }, ], predicate: None, @@ -432,7 +443,9 @@ fn brillig_oracle_predicate() { BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(1))], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], + input_value_types: vec![HeapValueType::Simple], }, ], predicate: Some(Expression::default()), diff --git a/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts b/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts index ff444879eea..7e12ec1e13a 100644 --- a/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts +++ b/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts @@ -2,11 +2,12 @@ import { WitnessMap } from '@noir-lang/acvm_js'; // See `complex_brillig_foreign_call` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 219, 10, 128, 48, 8, 117, 174, 203, 62, 103, 253, 65, 255, 18, 189, 21, - 245, 216, 231, 55, 200, 193, 193, 122, 137, 28, 180, 3, 226, 20, 39, 135, 29, 103, 32, 34, 71, 23, 124, 50, 150, 179, - 147, 24, 145, 235, 70, 241, 241, 27, 6, 103, 215, 43, 150, 226, 200, 21, 112, 244, 5, 56, 230, 121, 248, 169, 222, - 150, 186, 152, 190, 159, 127, 248, 63, 77, 178, 54, 89, 39, 113, 47, 62, 192, 44, 4, 200, 79, 219, 186, 47, 243, 129, - 173, 180, 36, 152, 211, 49, 43, 255, 234, 62, 22, 48, 221, 119, 0, 226, 4, 104, 45, 56, 241, 60, 4, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 83, 109, 10, 128, 48, 8, 85, 215, 199, 142, 179, 110, 208, 93, 162, 127, 69, + 253, 236, 248, 13, 114, 240, 88, 81, 65, 27, 180, 7, 226, 116, 238, 41, 83, 45, 17, 49, 29, 48, 94, 68, 207, 172, 54, + 34, 196, 245, 170, 221, 55, 116, 156, 142, 203, 229, 170, 81, 10, 168, 209, 100, 168, 49, 204, 195, 79, 251, 157, 178, + 47, 73, 255, 207, 92, 236, 79, 229, 165, 246, 210, 168, 221, 170, 182, 48, 11, 22, 252, 195, 50, 175, 211, 184, 33, + 85, 220, 146, 216, 47, 209, 61, 223, 188, 195, 248, 39, 110, 121, 195, 135, 73, 133, 206, 201, 16, 59, 245, 249, 221, + 124, 112, 4, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000001'], diff --git a/acvm-repo/acvm_js/test/shared/foreign_call.ts b/acvm-repo/acvm_js/test/shared/foreign_call.ts index 178ec3a09d1..d9184b79b5d 100644 --- a/acvm-repo/acvm_js/test/shared/foreign_call.ts +++ b/acvm-repo/acvm_js/test/shared/foreign_call.ts @@ -2,10 +2,10 @@ import { WitnessMap } from '@noir-lang/acvm_js'; // See `simple_brillig_foreign_call` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 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, 49, 10, 0, 33, 12, 4, 215, 28, 28, 62, 199, 251, 193, 125, 198, 194, 198, + 66, 196, 247, 43, 168, 176, 136, 218, 232, 64, 200, 50, 69, 216, 104, 0, 10, 149, 135, 50, 211, 221, 223, 182, 57, + 227, 83, 247, 110, 25, 238, 43, 212, 85, 151, 121, 91, 118, 62, 217, 16, 119, 159, 141, 121, 234, 132, 164, 96, 77, 6, + 148, 102, 152, 53, 83, 1, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000005'], diff --git a/acvm-repo/brillig/src/opcodes.rs b/acvm-repo/brillig/src/opcodes.rs index 6b126691166..f6c7b8003a7 100644 --- a/acvm-repo/brillig/src/opcodes.rs +++ b/acvm-repo/brillig/src/opcodes.rs @@ -45,7 +45,6 @@ impl HeapValueType { pub struct HeapArray { pub pointer: RegisterIndex, pub size: usize, - pub value_types: Vec, } /// A register-sized vector passed starting from a Brillig register memory location and with a register-held size @@ -53,7 +52,6 @@ pub struct HeapArray { pub struct HeapVector { pub pointer: RegisterIndex, pub size: RegisterIndex, - pub value_types: Vec, } /// Lays out various ways an external foreign call's input and output data may be interpreted inside Brillig. @@ -134,8 +132,13 @@ pub enum BrilligOpcode { function: String, /// Destination registers (may be single values or memory pointers). destinations: Vec, + /// Destination value types + destination_value_types: Vec, /// Input registers (may be single values or memory pointers). inputs: Vec, + /// Input value types (for heap allocated structures indicates how to + /// retrieve the elements) + input_value_types: Vec, }, Mov { destination: RegisterIndex, diff --git a/acvm-repo/brillig_vm/src/black_box.rs b/acvm-repo/brillig_vm/src/black_box.rs index fcf31496b78..94feb23e1a6 100644 --- a/acvm-repo/brillig_vm/src/black_box.rs +++ b/acvm-repo/brillig_vm/src/black_box.rs @@ -183,7 +183,7 @@ fn black_box_function_from_op(op: &BlackBoxOp) -> BlackBoxFunc { #[cfg(test)] mod test { - use acir::brillig::{BlackBoxOp, HeapValueType}; + use acir::brillig::BlackBoxOp; use crate::{ black_box::{evaluate_black_box, to_u8_vec, to_value_vec}, @@ -209,16 +209,8 @@ mod test { }; let op = BlackBoxOp::Sha256 { - message: HeapVector { - pointer: 0.into(), - size: 1.into(), - value_types: vec![HeapValueType::Simple], - }, - output: HeapArray { - pointer: 2.into(), - size: 32, - value_types: vec![HeapValueType::Simple], - }, + message: HeapVector { pointer: 0.into(), size: 1.into() }, + output: HeapArray { pointer: 2.into(), size: 32 }, }; evaluate_black_box(&op, &DummyBlackBoxSolver, &mut registers, &mut memory).unwrap(); diff --git a/acvm-repo/brillig_vm/src/lib.rs b/acvm-repo/brillig_vm/src/lib.rs index d488a968d07..9042fa5d882 100644 --- a/acvm-repo/brillig_vm/src/lib.rs +++ b/acvm-repo/brillig_vm/src/lib.rs @@ -216,7 +216,16 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { self.fail("return opcode hit, but callstack already empty".to_string()) } } - Opcode::ForeignCall { function, destinations, inputs } => { + Opcode::ForeignCall { + function, + destinations, + destination_value_types, + inputs, + input_value_types, + } => { + assert!(inputs.len() == input_value_types.len()); + assert!(destinations.len() == destination_value_types.len()); + if self.foreign_call_counter >= self.foreign_call_results.len() { // When this opcode is called, it is possible that the results of a foreign call are // not yet known (not enough entries in `foreign_call_results`). @@ -227,7 +236,10 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { // but has the necessary results to proceed with execution. let resolved_inputs = inputs .iter() - .map(|input| self.get_register_value_or_memory_values(input.clone())) + .zip(input_value_types) + .map(|(input, input_type)| { + self.get_register_value_or_memory_values(input.clone(), input_type) + }) .collect::>(); return self.wait_for_foreign_call(function.clone(), resolved_inputs); } @@ -235,21 +247,26 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { let values = &self.foreign_call_results[self.foreign_call_counter].values; let mut invalid_foreign_call_result = false; - for (destination, output) in destinations.iter().zip(values) { + for ((destination, value_type), output) in + destinations.iter().zip(destination_value_types).zip(values) + { match destination { - RegisterOrMemory::RegisterIndex(value_index) => match output { - ForeignCallParam::Single(value) => { - self.registers.set(*value_index, *value); + RegisterOrMemory::RegisterIndex(value_index) => { + assert!(*value_type == HeapValueType::Simple); + match output { + ForeignCallParam::Single(value) => { + self.registers.set(*value_index, *value); + } + _ => unreachable!( + "Function result size does not match brillig bytecode (expected 1 result)" + ), } - _ => unreachable!( - "Function result size does not match brillig bytecode (expected 1 result)" - ), - }, - RegisterOrMemory::HeapArray(HeapArray { - pointer: pointer_index, - size, - value_types, - }) => { + } + RegisterOrMemory::HeapArray(HeapArray { pointer: pointer_index, size }) => { + let HeapValueType::Array { value_types, size: type_size } = value_type else { + unreachable!("Expected array heap type"); + }; + assert!(size == type_size); if HeapValueType::all_simple(value_types) { match output { ForeignCallParam::Array(values) => { @@ -258,7 +275,8 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { break; } // Convert the destination pointer to a usize - let destination = self.registers.get(*pointer_index).to_usize(); + let destination = + self.registers.get(*pointer_index).to_usize(); // Write to our destination memory self.memory.write_slice(destination, values); } @@ -270,17 +288,21 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { unimplemented!("deflattening heap arrays from foreign calls"); } } - RegisterOrMemory::HeapVector(HeapVector { pointer: pointer_index, - size: size_index, - value_types, + RegisterOrMemory::HeapVector(HeapVector { + pointer: pointer_index, + size: size_index, }) => { + let HeapValueType::Vector { value_types } = value_type else { + unreachable!("Expected vector heap type"); + }; if HeapValueType::all_simple(value_types) { match output { ForeignCallParam::Array(values) => { // Set our size in the size register self.registers.set(*size_index, Value::from(values.len())); // Convert the destination pointer to a usize - let destination = self.registers.get(*pointer_index).to_usize(); + let destination = + self.registers.get(*pointer_index).to_usize(); // Write to our destination memory self.memory.write_slice(destination, values); } @@ -373,25 +395,34 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { self.status.clone() } - fn get_register_value_or_memory_values(&self, input: RegisterOrMemory) -> ForeignCallParam { + fn get_register_value_or_memory_values( + &self, + input: RegisterOrMemory, + value_type: &HeapValueType, + ) -> ForeignCallParam { match input { - RegisterOrMemory::RegisterIndex(value_index) => self.registers.get(value_index).into(), - RegisterOrMemory::HeapArray(HeapArray { - pointer: pointer_index, - size, - value_types, - }) => { + RegisterOrMemory::RegisterIndex(value_index) => { + assert!(*value_type == HeapValueType::Simple); + self.registers.get(value_index).into() + } + RegisterOrMemory::HeapArray(HeapArray { pointer: pointer_index, size }) => { + let HeapValueType::Array { value_types, size: type_size } = value_type else { + unreachable!("expected array heap value type"); + }; + assert!(*type_size == size); let ptr = self.registers.get(pointer_index).to_usize(); - self.read_slice_of_values_from_memory(ptr, size, &value_types).into() + self.read_slice_of_values_from_memory(ptr, size, value_types).into() } RegisterOrMemory::HeapVector(HeapVector { pointer: pointer_index, size: size_index, - value_types, }) => { + let HeapValueType::Vector { value_types } = value_type else { + unreachable!("expected vector heap value type"); + }; let ptr = self.registers.get(pointer_index).to_usize(); let size = self.registers.get(size_index).to_usize(); - self.read_slice_of_values_from_memory(ptr, size, &value_types).into() + self.read_slice_of_values_from_memory(ptr, size, value_types).into() } } } @@ -1004,7 +1035,9 @@ mod tests { Opcode::ForeignCall { function: "double".into(), destinations: vec![RegisterOrMemory::RegisterIndex(r_result)], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![RegisterOrMemory::RegisterIndex(r_input)], + input_value_types: vec![HeapValueType::Simple], }, ]; @@ -1061,13 +1094,19 @@ mod tests { destinations: vec![RegisterOrMemory::HeapArray(HeapArray { pointer: r_output, size: initial_matrix.len(), - value_types: vec![HeapValueType::Simple], })], + destination_value_types: vec![HeapValueType::Array { + size: initial_matrix.len(), + value_types: vec![HeapValueType::Simple], + }], inputs: vec![RegisterOrMemory::HeapArray(HeapArray { pointer: r_input, size: initial_matrix.len(), - value_types: vec![HeapValueType::Simple], })], + input_value_types: vec![HeapValueType::Array { + value_types: vec![HeapValueType::Simple], + size: initial_matrix.len(), + }], }, ]; @@ -1136,13 +1175,17 @@ mod tests { destinations: vec![RegisterOrMemory::HeapVector(HeapVector { pointer: r_output_pointer, size: r_output_size, - value_types: vec![HeapValueType::Simple], })], + destination_value_types: vec![HeapValueType::Vector { + value_types: vec![HeapValueType::Simple], + }], inputs: vec![RegisterOrMemory::HeapVector(HeapVector { pointer: r_input_pointer, size: r_input_size, - value_types: vec![HeapValueType::Simple], })], + input_value_types: vec![HeapValueType::Vector { + value_types: vec![HeapValueType::Simple], + }], }, ]; @@ -1200,13 +1243,19 @@ mod tests { destinations: vec![RegisterOrMemory::HeapArray(HeapArray { pointer: r_output, size: initial_matrix.len(), - value_types: vec![HeapValueType::Simple], })], + destination_value_types: vec![HeapValueType::Array { + size: initial_matrix.len(), + value_types: vec![HeapValueType::Simple], + }], inputs: vec![RegisterOrMemory::HeapArray(HeapArray { pointer: r_input, size: initial_matrix.len(), - value_types: vec![HeapValueType::Simple], })], + input_value_types: vec![HeapValueType::Array { + size: initial_matrix.len(), + value_types: vec![HeapValueType::Simple], + }], }, ]; @@ -1280,20 +1329,31 @@ mod tests { destinations: vec![RegisterOrMemory::HeapArray(HeapArray { pointer: r_output, size: matrix_a.len(), - value_types: vec![HeapValueType::Simple], })], + destination_value_types: vec![HeapValueType::Array { + size: matrix_a.len(), + value_types: vec![HeapValueType::Simple], + }], inputs: vec![ RegisterOrMemory::HeapArray(HeapArray { pointer: r_input_a, size: matrix_a.len(), - value_types: vec![HeapValueType::Simple], }), RegisterOrMemory::HeapArray(HeapArray { pointer: r_input_b, size: matrix_b.len(), - value_types: vec![HeapValueType::Simple], }), ], + input_value_types: vec![ + HeapValueType::Array { + size: matrix_a.len(), + value_types: vec![HeapValueType::Simple], + }, + HeapValueType::Array { + size: matrix_b.len(), + value_types: vec![HeapValueType::Simple], + }, + ], }, ]; let mut initial_memory = matrix_a.clone(); @@ -1383,11 +1443,15 @@ mod tests { Opcode::ForeignCall { function: "flat_sum".into(), destinations: vec![RegisterOrMemory::RegisterIndex(r_output)], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![RegisterOrMemory::HeapArray(HeapArray { pointer: r_input, size: outer_array.len(), - value_types: input_array_value_types, })], + input_value_types: vec![HeapValueType::Array { + value_types: input_array_value_types, + size: outer_array.len(), + }], }, ]; diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs index 354d37e2c5d..a6d3220fa85 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs @@ -1,7 +1,4 @@ -use acvm::{ - acir::{brillig::BlackBoxOp, BlackBoxFunc}, - brillig_vm::brillig::HeapValueType, -}; +use acvm::acir::{brillig::BlackBoxOp, BlackBoxFunc}; use crate::brillig::brillig_ir::{ brillig_variable::{BrilligVariable, BrilligVector}, @@ -24,8 +21,8 @@ pub(crate) fn convert_black_box_call( { let message_vector = convert_array_or_vector(brillig_context, message, bb_func); brillig_context.black_box_op_instruction(BlackBoxOp::Sha256 { - message: message_vector.to_heap_vector(vec![HeapValueType::Simple]), - output: result_array.to_heap_array(vec![HeapValueType::Simple]), + message: message_vector.to_heap_vector(), + output: result_array.to_heap_array(), }); } else { unreachable!("ICE: SHA256 expects one array argument and one array result") @@ -37,8 +34,8 @@ pub(crate) fn convert_black_box_call( { let message_vector = convert_array_or_vector(brillig_context, message, bb_func); brillig_context.black_box_op_instruction(BlackBoxOp::Blake2s { - message: message_vector.to_heap_vector(vec![HeapValueType::Simple]), - output: result_array.to_heap_array(vec![HeapValueType::Simple]), + message: message_vector.to_heap_vector(), + output: result_array.to_heap_array(), }); } else { unreachable!("ICE: Blake2s expects one array argument and one array result") @@ -54,8 +51,8 @@ pub(crate) fn convert_black_box_call( message_vector.size = *array_size; brillig_context.black_box_op_instruction(BlackBoxOp::Keccak256 { - message: message_vector.to_heap_vector(vec![HeapValueType::Simple]), - output: result_array.to_heap_array(vec![HeapValueType::Simple]), + message: message_vector.to_heap_vector(), + output: result_array.to_heap_array(), }); } else { unreachable!("ICE: Keccak256 expects message, message size and result array") @@ -70,10 +67,10 @@ pub(crate) fn convert_black_box_call( let message_hash_vector = convert_array_or_vector(brillig_context, message, bb_func); brillig_context.black_box_op_instruction(BlackBoxOp::EcdsaSecp256k1 { - hashed_msg: message_hash_vector.to_heap_vector(vec![HeapValueType::Simple]), - public_key_x: public_key_x.to_heap_array(vec![HeapValueType::Simple]), - public_key_y: public_key_y.to_heap_array(vec![HeapValueType::Simple]), - signature: signature.to_heap_array(vec![HeapValueType::Simple]), + hashed_msg: message_hash_vector.to_heap_vector(), + public_key_x: public_key_x.to_heap_array(), + public_key_y: public_key_y.to_heap_array(), + signature: signature.to_heap_array(), result: *result_register, }); } else { @@ -91,10 +88,10 @@ pub(crate) fn convert_black_box_call( let message_hash_vector = convert_array_or_vector(brillig_context, message, bb_func); brillig_context.black_box_op_instruction(BlackBoxOp::EcdsaSecp256r1 { - hashed_msg: message_hash_vector.to_heap_vector(vec![HeapValueType::Simple]), - public_key_x: public_key_x.to_heap_array(vec![HeapValueType::Simple]), - public_key_y: public_key_y.to_heap_array(vec![HeapValueType::Simple]), - signature: signature.to_heap_array(vec![HeapValueType::Simple]), + hashed_msg: message_hash_vector.to_heap_vector(), + public_key_x: public_key_x.to_heap_array(), + public_key_y: public_key_y.to_heap_array(), + signature: signature.to_heap_array(), result: *result_register, }); } else { @@ -112,9 +109,9 @@ pub(crate) fn convert_black_box_call( { let message_vector = convert_array_or_vector(brillig_context, message, bb_func); brillig_context.black_box_op_instruction(BlackBoxOp::PedersenCommitment { - inputs: message_vector.to_heap_vector(vec![HeapValueType::Simple]), + inputs: message_vector.to_heap_vector(), domain_separator: *domain_separator, - output: result_array.to_heap_array(vec![HeapValueType::Simple]), + output: result_array.to_heap_array(), }); } else { unreachable!("ICE: Pedersen expects one array argument, a register for the domain separator, and one array result") @@ -128,7 +125,7 @@ pub(crate) fn convert_black_box_call( { let message_vector = convert_array_or_vector(brillig_context, message, bb_func); brillig_context.black_box_op_instruction(BlackBoxOp::PedersenHash { - inputs: message_vector.to_heap_vector(vec![HeapValueType::Simple]), + inputs: message_vector.to_heap_vector(), domain_separator: *domain_separator, output: *result, }); @@ -147,8 +144,8 @@ pub(crate) fn convert_black_box_call( brillig_context.black_box_op_instruction(BlackBoxOp::SchnorrVerify { public_key_x: *public_key_x, public_key_y: *public_key_y, - message: message_hash.to_heap_vector(vec![HeapValueType::Simple]), - signature: signature.to_heap_vector(vec![HeapValueType::Simple]), + message: message_hash.to_heap_vector(), + signature: signature.to_heap_vector(), result: *result_register, }); } else { @@ -164,7 +161,7 @@ pub(crate) fn convert_black_box_call( brillig_context.black_box_op_instruction(BlackBoxOp::FixedBaseScalarMul { low: *low, high: *high, - result: result_array.to_heap_array(vec![HeapValueType::Simple]), + result: result_array.to_heap_array(), }); } else { unreachable!( diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index dc14ad23900..638ae44314c 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -1,4 +1,6 @@ -use crate::brillig::brillig_ir::brillig_variable::{BrilligArray, BrilligVariable, BrilligVector}; +use crate::brillig::brillig_ir::brillig_variable::{ + type_to_heap_value_type, BrilligArray, BrilligVariable, BrilligVector, +}; use crate::brillig::brillig_ir::{ BrilligBinaryOp, BrilligContext, BRILLIG_INTEGER_ARITHMETIC_BIT_SIZE, }; @@ -330,18 +332,25 @@ impl<'block> BrilligBlock<'block> { let result_ids = dfg.instruction_results(instruction_id); let input_registers = vecmap(arguments, |value_id| { + self.convert_ssa_value(*value_id, dfg).to_register_or_memory() + }); + let input_value_types = vecmap(arguments, |value_id| { let value_type = dfg.type_of_value(*value_id); - self.convert_ssa_value(*value_id, dfg).to_register_or_memory(&value_type) + type_to_heap_value_type(&value_type) }); let output_registers = vecmap(result_ids, |value_id| { + self.allocate_external_call_result(*value_id, dfg).to_register_or_memory() + }); + let output_value_types = vecmap(result_ids, |value_id| { let value_type = dfg.type_of_value(*value_id); - self.allocate_external_call_result(*value_id, dfg) - .to_register_or_memory(&value_type) + type_to_heap_value_type(&value_type) }); self.brillig_context.foreign_call_instruction( func_name.to_owned(), &input_registers, + &input_value_types, &output_registers, + &output_value_types, ); for (i, output_register) in output_registers.iter().enumerate() { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index 5001523ce54..4c53ee61043 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -23,6 +23,7 @@ use acvm::{ BinaryFieldOp, BinaryIntOp, BlackBoxOp, Opcode as BrilligOpcode, RegisterIndex, RegisterOrMemory, Value, }, + brillig_vm::brillig::HeapValueType, FieldElement, }; use debug_show::DebugShow; @@ -566,13 +567,19 @@ impl BrilligContext { &mut self, func_name: String, inputs: &[RegisterOrMemory], + input_value_types: &[HeapValueType], outputs: &[RegisterOrMemory], + output_value_types: &[HeapValueType], ) { + assert!(inputs.len() == input_value_types.len()); + assert!(outputs.len() == output_value_types.len()); self.debug_show.foreign_call_instruction(func_name.clone(), inputs, outputs); let opcode = BrilligOpcode::ForeignCall { function: func_name, destinations: outputs.to_vec(), + destination_value_types: output_value_types.to_vec(), inputs: inputs.to_vec(), + input_value_types: input_value_types.to_vec(), }; self.push_opcode(opcode); } @@ -1152,11 +1159,9 @@ pub(crate) mod tests { context.foreign_call_instruction( "make_number_sequence".into(), &[RegisterOrMemory::RegisterIndex(r_input_size)], - &[RegisterOrMemory::HeapVector(HeapVector { - pointer: r_stack, - size: r_output_size, - value_types: vec![HeapValueType::Simple], - })], + &[HeapValueType::Simple], + &[RegisterOrMemory::HeapVector(HeapVector { pointer: r_stack, size: r_output_size })], + &[HeapValueType::Vector { value_types: vec![HeapValueType::Simple] }], ); // push stack frame by r_returned_size context.memory_op(r_stack, r_output_size, r_stack, BinaryIntOp::Add); diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs index f545a07fba2..5014b275748 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs @@ -14,8 +14,8 @@ pub(crate) struct BrilligArray { } impl BrilligArray { - pub(crate) fn to_heap_array(self, value_types: Vec) -> HeapArray { - HeapArray { pointer: self.pointer, size: self.size, value_types } + pub(crate) fn to_heap_array(self) -> HeapArray { + HeapArray { pointer: self.pointer, size: self.size } } pub(crate) fn registers_count() -> usize { @@ -36,8 +36,8 @@ pub(crate) struct BrilligVector { } impl BrilligVector { - pub(crate) fn to_heap_vector(self, value_types: Vec) -> HeapVector { - HeapVector { pointer: self.pointer, size: self.size, value_types } + pub(crate) fn to_heap_vector(self) -> HeapVector { + HeapVector { pointer: self.pointer, size: self.size } } pub(crate) fn registers_count() -> usize { @@ -87,24 +87,22 @@ impl BrilligVariable { } } - pub(crate) fn to_register_or_memory(self, typ: &Type) -> RegisterOrMemory { + pub(crate) fn to_register_or_memory(self) -> RegisterOrMemory { match self { BrilligVariable::Simple(register_index) => { RegisterOrMemory::RegisterIndex(register_index) } BrilligVariable::BrilligArray(array) => { - let value_types = heap_value_types_of_array(typ); - RegisterOrMemory::HeapArray(array.to_heap_array(value_types)) + RegisterOrMemory::HeapArray(array.to_heap_array()) } BrilligVariable::BrilligVector(vector) => { - let value_types = heap_value_types_of_slice(typ); - RegisterOrMemory::HeapVector(vector.to_heap_vector(value_types)) + RegisterOrMemory::HeapVector(vector.to_heap_vector()) } } } } -fn type_to_heap_value_type(typ: &Type) -> HeapValueType { +pub(crate) fn type_to_heap_value_type(typ: &Type) -> HeapValueType { match typ { Type::Numeric(_) | Type::Reference(_) | Type::Function => HeapValueType::Simple, Type::Array(elem_type, size) => HeapValueType::Array { @@ -116,19 +114,3 @@ fn type_to_heap_value_type(typ: &Type) -> HeapValueType { }, } } - -fn heap_value_types_of_array(typ: &Type) -> Vec { - if let Type::Array(elem_type, _) = typ { - elem_type.as_ref().iter().map(type_to_heap_value_type).collect() - } else { - unreachable!("value is not of type Array"); - } -} - -fn heap_value_types_of_slice(typ: &Type) -> Vec { - if let Type::Slice(elem_type) = typ { - elem_type.as_ref().iter().map(type_to_heap_value_type).collect() - } else { - unreachable!("value is not of type Slice"); - } -} diff --git a/tooling/debugger/src/context.rs b/tooling/debugger/src/context.rs index 12b55708b15..90caae87688 100644 --- a/tooling/debugger/src/context.rs +++ b/tooling/debugger/src/context.rs @@ -442,7 +442,7 @@ mod tests { }, blackbox_solver::StubbedBlackBoxSolver, brillig_vm::brillig::{ - BinaryFieldOp, Opcode as BrilligOpcode, RegisterIndex, RegisterOrMemory, + BinaryFieldOp, HeapValueType, Opcode as BrilligOpcode, RegisterIndex, RegisterOrMemory, }, }; use nargo::{artifacts::debug::DebugArtifact, ops::DefaultForeignCallExecutor}; @@ -468,7 +468,9 @@ mod tests { BrilligOpcode::ForeignCall { function: "clear_mock".into(), destinations: vec![], + destination_value_types: vec![], inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], + input_value_types: vec![HeapValueType::Simple], }, BrilligOpcode::Stop, ], From a90e23038c0a05b6230c05f16e748d41e3cbc83a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Gir=C3=A1ldez?= Date: Tue, 23 Jan 2024 20:15:41 -0500 Subject: [PATCH 09/10] feat: Revert removing the Copy trait from Brillig types --- acvm-repo/brillig/src/black_box.rs | 2 +- acvm-repo/brillig/src/opcodes.rs | 6 +++--- acvm-repo/brillig_vm/src/lib.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/acvm-repo/brillig/src/black_box.rs b/acvm-repo/brillig/src/black_box.rs index 7e3c0975692..41e54ab2705 100644 --- a/acvm-repo/brillig/src/black_box.rs +++ b/acvm-repo/brillig/src/black_box.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; /// These opcodes provide an equivalent of ACIR blackbox functions. /// They are implemented as native functions in the VM. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum BlackBoxOp { /// Calculates the SHA256 hash of the inputs. Sha256 { message: HeapVector, output: HeapArray }, diff --git a/acvm-repo/brillig/src/opcodes.rs b/acvm-repo/brillig/src/opcodes.rs index f6c7b8003a7..780b58aa8b4 100644 --- a/acvm-repo/brillig/src/opcodes.rs +++ b/acvm-repo/brillig/src/opcodes.rs @@ -41,14 +41,14 @@ impl HeapValueType { } /// A fixed-sized array starting from a Brillig register memory location. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] pub struct HeapArray { pub pointer: RegisterIndex, pub size: usize, } /// A register-sized vector passed starting from a Brillig register memory location and with a register-held size -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] pub struct HeapVector { pub pointer: RegisterIndex, pub size: RegisterIndex, @@ -60,7 +60,7 @@ pub struct HeapVector { /// While we are usually agnostic to how memory is passed within Brillig, /// this needs to be encoded somehow when dealing with an external system. /// For simplicity, the extra type information is given right in the ForeignCall instructions. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] pub enum RegisterOrMemory { /// A single register value passed to or from an external call /// It is an 'immediate' value - used without dereferencing memory. diff --git a/acvm-repo/brillig_vm/src/lib.rs b/acvm-repo/brillig_vm/src/lib.rs index 9042fa5d882..7a72a6dd60e 100644 --- a/acvm-repo/brillig_vm/src/lib.rs +++ b/acvm-repo/brillig_vm/src/lib.rs @@ -238,7 +238,7 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { .iter() .zip(input_value_types) .map(|(input, input_type)| { - self.get_register_value_or_memory_values(input.clone(), input_type) + self.get_register_value_or_memory_values(*input, input_type) }) .collect::>(); return self.wait_for_foreign_call(function.clone(), resolved_inputs); From 5bc8cca2aa852ad845f8963b967d3cccfac14089 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Gir=C3=A1ldez?= Date: Fri, 2 Feb 2024 13:16:18 -0500 Subject: [PATCH 10/10] chore: Add case to debug_logs to show nested arrays passing to foreign functions --- test_programs/execution_success/debug_logs/src/main.nr | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test_programs/execution_success/debug_logs/src/main.nr b/test_programs/execution_success/debug_logs/src/main.nr index b640e4f5f0c..49e0041594a 100644 --- a/test_programs/execution_success/debug_logs/src/main.nr +++ b/test_programs/execution_success/debug_logs/src/main.nr @@ -57,6 +57,12 @@ fn main(x: Field, y: pub Field) { regression_2906(); + let first_array = [1, 2, 3]; + let second_array = [4, 5, 6]; + let arrays_nested = [first_array, second_array]; + std::println(f"first_array: {first_array}, second_array: {second_array}"); + std::println(f"arrays_nested: {arrays_nested}"); + let free_lambda = |x| x + 1; let sentinel: u32 = 8888; std::println(f"free_lambda: {free_lambda}, sentinel: {sentinel}");