From ea50fd6b15a799a7b3308c0fb8aeeeb5517b3bd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bene=C5=A1?= Date: Sat, 3 Feb 2024 13:49:54 +0100 Subject: [PATCH] refactor: implementing `deserialize()` in Noir structs (#4384) Implementing deserialize in a few structs --- yarn-project/aztec-nr/aztec/src/context.nr | 67 ++----------------- yarn-project/aztec-nr/aztec/src/utils.nr | 2 + .../src/crates/types/src/abis/call_context.nr | 21 +++++- .../crates/types/src/abis/function_data.nr | 40 +++++++++-- .../src/abis/private_circuit_public_inputs.nr | 53 +++++++++++++-- .../src/abis/public_circuit_public_inputs.nr | 56 ++++++++++++---- .../types/src/contrakt/deployment_data.nr | 39 ++++++++--- .../crates/types/src/contrakt/storage_read.nr | 37 ++++++++-- .../src/contrakt/storage_update_request.nr | 17 ++++- .../src/crates/types/src/grumpkin_point.nr | 9 +++ .../src/crates/types/src/utils.nr | 1 + .../src/crates/types/src/utils/reader.nr | 41 ++++++++++++ 12 files changed, 279 insertions(+), 104 deletions(-) create mode 100644 yarn-project/noir-protocol-circuits/src/crates/types/src/utils/reader.nr diff --git a/yarn-project/aztec-nr/aztec/src/context.nr b/yarn-project/aztec-nr/aztec/src/context.nr index c1e8bd5404c6..3eda05bb01e4 100644 --- a/yarn-project/aztec-nr/aztec/src/context.nr +++ b/yarn-project/aztec-nr/aztec/src/context.nr @@ -311,51 +311,8 @@ impl PrivateContext { let item = PrivateCallStackItem { contract_address: AztecAddress::from_field(reader.read()), - function_data: FunctionData { - selector: FunctionSelector::from_field(reader.read()), - is_internal: reader.read() as bool, - is_private: reader.read() as bool, - is_constructor: reader.read() as bool, - }, - public_inputs: PrivateCircuitPublicInputs { - call_context: CallContext { - msg_sender : AztecAddress::from_field(reader.read()), - storage_contract_address : AztecAddress::from_field(reader.read()), - portal_contract_address : EthAddress::from_field(reader.read()), - function_selector: FunctionSelector::from_field(reader.read()), // practically same as fields[1] - is_delegate_call : reader.read() as bool, - is_static_call : reader.read() as bool, - is_contract_deployment: reader.read() as bool, - start_side_effect_counter: reader.read() as u32, - }, - args_hash: reader.read(), - return_values: reader.read_array([0; RETURN_VALUES_LENGTH]), // +1 - read_requests: reader.read_struct_array(SideEffect::deserialize, [SideEffect::empty(); MAX_READ_REQUESTS_PER_CALL]), - nullifier_key_validation_requests: reader.read_struct_array(NullifierKeyValidationRequest::deserialize, [NullifierKeyValidationRequest::empty(); MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL]), - new_commitments: reader.read_struct_array(SideEffect::deserialize, [SideEffect::empty(); MAX_NEW_COMMITMENTS_PER_CALL]), - new_nullifiers: reader.read_struct_array(SideEffectLinkedToNoteHash::deserialize, [SideEffectLinkedToNoteHash::empty(); MAX_NEW_NULLIFIERS_PER_CALL]), - private_call_stack_hashes: reader.read_array([0; MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL]), - public_call_stack_hashes: reader.read_array([0; MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL]), - new_l2_to_l1_msgs: reader.read_array([0; MAX_NEW_L2_TO_L1_MSGS_PER_CALL]), - end_side_effect_counter: reader.read() as u32, - encrypted_logs_hash: reader.read_array([0; NUM_FIELDS_PER_SHA256]), - unencrypted_logs_hash: reader.read_array([0; NUM_FIELDS_PER_SHA256]), - encrypted_log_preimages_length: reader.read(), - unencrypted_log_preimages_length: reader.read(), - historical_header: reader.read_struct(Header::deserialize), - contract_deployment_data: ContractDeploymentData { - public_key: GrumpkinPoint { - x: reader.read(), - y: reader.read() - }, - initialization_hash : reader.read(), - contract_class_id : ContractClassId::from_field(reader.read()), - contract_address_salt : reader.read(), - portal_contract_address : EthAddress::from_field(reader.read()), - }, - chain_id: reader.read(), - version: reader.read(), - }, + function_data: reader.read_struct(FunctionData::deserialize), + public_inputs: reader.read_struct(PrivateCircuitPublicInputs::deserialize), is_execution_request: reader.read() as bool, }; @@ -420,25 +377,13 @@ impl PrivateContext { let mut reader = Reader::new(fields); + // Note: Not using PublicCirclePublicInputs::deserialize here, because everything below args_hash is 0 and + // there is no more data in fields because there is only ENQUEUE_PUBLIC_FUNCTION_CALL_RETURN_SIZE fields! let item = PublicCallStackItem { contract_address: AztecAddress::from_field(reader.read()), - function_data: FunctionData { - selector: FunctionSelector::from_field(reader.read()), - is_internal: reader.read() as bool, - is_private: reader.read() as bool, - is_constructor: reader.read() as bool, - }, + function_data: reader.read_struct(FunctionData::deserialize), public_inputs: PublicCircuitPublicInputs { - call_context: CallContext { - msg_sender : AztecAddress::from_field(reader.read()), - storage_contract_address : AztecAddress::from_field(reader.read()), - portal_contract_address : EthAddress::from_field(reader.read()), - function_selector: FunctionSelector::from_field(reader.read()), // practically same as fields[1] - is_delegate_call : reader.read() as bool, - is_static_call : reader.read() as bool, - is_contract_deployment: reader.read() as bool, - start_side_effect_counter: reader.read() as u32, - }, + call_context: reader.read_struct(CallContext::deserialize), args_hash: reader.read(), return_values: [0; RETURN_VALUES_LENGTH], contract_storage_update_requests: [StorageUpdateRequest::empty(); MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL], diff --git a/yarn-project/aztec-nr/aztec/src/utils.nr b/yarn-project/aztec-nr/aztec/src/utils.nr index 58664c32c5c9..a0936a3015bb 100644 --- a/yarn-project/aztec-nr/aztec/src/utils.nr +++ b/yarn-project/aztec-nr/aztec/src/utils.nr @@ -17,6 +17,7 @@ pub fn full_field_greater_than(lhs: Field, rhs: Field) -> bool { rhs.lt(lhs) } +// TODO(benesjan): also in circuits. NUKE THIS! struct Reader { data: [Field; N], offset: Field, @@ -41,6 +42,7 @@ impl Reader { result } + // TODO(#4394) pub fn read_struct(&mut self, deserialise: fn([Field; K]) -> T) -> T { let result = deserialise(self.read_array([0; K])); result diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/call_context.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/call_context.nr index 4c1bacbe3e24..42e516226552 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/call_context.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/call_context.nr @@ -6,9 +6,13 @@ use crate::{ GENERATOR_INDEX__CALL_CONTEXT, }, hash::pedersen_hash, + traits::{ + Deserialize, + Hash, + Serialize, + }, }; use dep::std::cmp::Eq; -use crate::traits::{Hash, Serialize}; // docs:start:call-context struct CallContext { @@ -75,6 +79,21 @@ impl Serialize for CallContext { } } +impl Deserialize for CallContext { + fn deserialize(serialized: [Field; CALL_CONTEXT_LENGTH]) -> CallContext { + CallContext { + msg_sender: AztecAddress::from_field(serialized[0]), + storage_contract_address: AztecAddress::from_field(serialized[1]), + portal_contract_address: EthAddress::from_field(serialized[2]), + function_selector: FunctionSelector::from_field(serialized[3]), + is_delegate_call: serialized[4] as bool, + is_static_call: serialized[5] as bool, + is_contract_deployment: serialized[6] as bool, + start_side_effect_counter: serialized[7] as u32, + } + } +} + #[test] fn serialization_smoke() { let context: CallContext = dep::std::unsafe::zeroed(); diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/function_data.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/function_data.nr index a7f706297119..513c90e7d1f1 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/function_data.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/function_data.nr @@ -1,5 +1,16 @@ -use crate::abis::function_selector::FunctionSelector; -use crate::constants::GENERATOR_INDEX__FUNCTION_DATA; +use crate::{ + abis::function_selector::FunctionSelector, + constants::{ + GENERATOR_INDEX__FUNCTION_DATA, + FUNCTION_DATA_LENGTH, + }, + hash::pedersen_hash, + traits::{ + Serialize, + Hash, + Deserialize, + }, +}; struct FunctionData { // First four bytes of the abi encoding @@ -10,16 +21,33 @@ struct FunctionData { is_constructor : bool, } -impl FunctionData { +impl Hash for FunctionData { + fn hash(self) -> Field { + pedersen_hash(self.serialize(), GENERATOR_INDEX__FUNCTION_DATA) + } +} + +impl Serialize for FunctionData { // A field is ~256 bits // TODO(https://github.com/AztecProtocol/aztec-packages/issues/3057): Since, function data can fit into a Field, // This method will simply return a bit packed Field instead of hashing - fn hash(self) -> Field { - dep::std::hash::pedersen_hash_with_separator([ + fn serialize(self) -> [Field; FUNCTION_DATA_LENGTH] { + [ self.selector.to_field(), self.is_internal as Field, self.is_private as Field, self.is_constructor as Field, - ], GENERATOR_INDEX__FUNCTION_DATA) + ] + } +} + +impl Deserialize for FunctionData { + fn deserialize(serialized: [Field; FUNCTION_DATA_LENGTH]) -> Self { + Self { + selector: FunctionSelector::from_field(serialized[0]), + is_internal: serialized[1] as bool, + is_private: serialized[2] as bool, + is_constructor: serialized[3] as bool, + } } } diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_circuit_public_inputs.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_circuit_public_inputs.nr index 353ba24b2d99..9995bee6a05b 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_circuit_public_inputs.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_circuit_public_inputs.nr @@ -2,13 +2,12 @@ use crate::{ abis::{ call_context::CallContext, nullifier_key_validation_request::NullifierKeyValidationRequest, - side_effect::{SideEffect, SideEffectLinkedToNoteHash}, + side_effect::{ + SideEffect, + SideEffectLinkedToNoteHash, + }, }, - contrakt::deployment_data::ContractDeploymentData, - hash::pedersen_hash, - header::Header, -}; -use crate::constants::{ + constants::{ MAX_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_NEW_COMMITMENTS_PER_CALL, @@ -20,8 +19,17 @@ use crate::constants::{ RETURN_VALUES_LENGTH, PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH, GENERATOR_INDEX__PRIVATE_CIRCUIT_PUBLIC_INPUTS, + }, + contrakt::deployment_data::ContractDeploymentData, + header::Header, + hash::pedersen_hash, + traits::{ + Deserialize, + Hash, + Serialize, + }, + utils::reader::Reader, }; -use crate::traits::{Hash, Serialize}; struct PrivateCircuitPublicInputs { call_context: CallContext, @@ -97,6 +105,37 @@ impl Serialize for PrivateCircuitPublicInp } } +impl Deserialize for PrivateCircuitPublicInputs { + fn deserialize(serialized: [Field; PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH]) -> Self { + // TODO(#4390): This should accept a reader ^ to avoid copying data. + let mut reader = Reader::new(serialized); + let inputs = Self { + call_context: reader.read_struct(CallContext::deserialize), + args_hash: reader.read(), + return_values: reader.read_array([0; RETURN_VALUES_LENGTH]), + read_requests: reader.read_struct_array(SideEffect::deserialize, [SideEffect::empty(); MAX_READ_REQUESTS_PER_CALL]), + nullifier_key_validation_requests: reader.read_struct_array(NullifierKeyValidationRequest::deserialize, [NullifierKeyValidationRequest::empty(); MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL]), + new_commitments: reader.read_struct_array(SideEffect::deserialize, [SideEffect::empty(); MAX_NEW_COMMITMENTS_PER_CALL]), + new_nullifiers: reader.read_struct_array(SideEffectLinkedToNoteHash::deserialize, [SideEffectLinkedToNoteHash::empty(); MAX_NEW_NULLIFIERS_PER_CALL]), + private_call_stack_hashes: reader.read_array([0; MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL]), + public_call_stack_hashes: reader.read_array([0; MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL]), + new_l2_to_l1_msgs: reader.read_array([0; MAX_NEW_L2_TO_L1_MSGS_PER_CALL]), + end_side_effect_counter: reader.read() as u32, + encrypted_logs_hash: reader.read_array([0; NUM_FIELDS_PER_SHA256]), + unencrypted_logs_hash: reader.read_array([0; NUM_FIELDS_PER_SHA256]), + encrypted_log_preimages_length: reader.read(), + unencrypted_log_preimages_length: reader.read(), + historical_header: reader.read_struct(Header::deserialize), + contract_deployment_data: reader.read_struct(ContractDeploymentData::deserialize), + chain_id: reader.read(), + version: reader.read(), + }; + + reader.finish(); + inputs + } +} + impl Hash for PrivateCircuitPublicInputs { fn hash(self) -> Field { pedersen_hash(self.serialize(), GENERATOR_INDEX__PRIVATE_CIRCUIT_PUBLIC_INPUTS) diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_circuit_public_inputs.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_circuit_public_inputs.nr index 138a9d0e17d3..8d981d4ca12e 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_circuit_public_inputs.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_circuit_public_inputs.nr @@ -1,29 +1,34 @@ -use crate::constants::{ - MAX_NEW_L2_TO_L1_MSGS_PER_CALL, - MAX_NEW_NULLIFIERS_PER_CALL, - MAX_NEW_COMMITMENTS_PER_CALL, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, - MAX_PUBLIC_DATA_READS_PER_CALL, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, - NUM_FIELDS_PER_SHA256, - RETURN_VALUES_LENGTH, - GENERATOR_INDEX__PUBLIC_CIRCUIT_PUBLIC_INPUTS, - PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH, -}; use crate::{ abis::{ call_context::CallContext, side_effect::{SideEffect, SideEffectLinkedToNoteHash}, }, address::AztecAddress, + constants::{ + MAX_NEW_L2_TO_L1_MSGS_PER_CALL, + MAX_NEW_NULLIFIERS_PER_CALL, + MAX_NEW_COMMITMENTS_PER_CALL, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, + MAX_PUBLIC_DATA_READS_PER_CALL, + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, + NUM_FIELDS_PER_SHA256, + RETURN_VALUES_LENGTH, + GENERATOR_INDEX__PUBLIC_CIRCUIT_PUBLIC_INPUTS, + PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH, + }, contrakt::{ storage_read::StorageRead, storage_update_request::StorageUpdateRequest, }, hash::pedersen_hash, header::Header, + traits::{ + Hash, + Serialize, + Deserialize, + }, + utils::reader::Reader, }; -use crate::traits::{Hash, Serialize, Deserialize}; struct PublicCircuitPublicInputs{ call_context: CallContext, @@ -82,6 +87,31 @@ impl Serialize for PublicCircuitPublicInput } } +impl Deserialize for PublicCircuitPublicInputs { + fn deserialize(serialized: [Field; PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH]) -> Self { + // TODO(#4390): This should accept a reader ^ to avoid copying data. + let mut reader = Reader::new(serialized); + let inputs = PublicCircuitPublicInputs { + call_context: reader.read_struct(CallContext::deserialize), + args_hash: reader.read(), + return_values: reader.read_array([0; RETURN_VALUES_LENGTH]), + contract_storage_update_requests: reader.read_struct_array(StorageUpdateRequest::deserialize, [StorageUpdateRequest::empty(); MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL]), + contract_storage_reads: reader.read_struct_array(StorageRead::deserialize, [StorageRead::empty(); MAX_PUBLIC_DATA_READS_PER_CALL]), + public_call_stack_hashes: reader.read_array([0; MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL]), + new_commitments: reader.read_struct_array(SideEffect::deserialize, [SideEffect::empty(); MAX_NEW_COMMITMENTS_PER_CALL]), + new_nullifiers: reader.read_struct_array(SideEffectLinkedToNoteHash::deserialize, [SideEffectLinkedToNoteHash::empty(); MAX_NEW_NULLIFIERS_PER_CALL]), + new_l2_to_l1_msgs: reader.read_array([0; MAX_NEW_L2_TO_L1_MSGS_PER_CALL]), + unencrypted_logs_hash: reader.read_array([0; NUM_FIELDS_PER_SHA256]), + unencrypted_log_preimages_length: reader.read(), + historical_header: reader.read_struct(Header::deserialize), + prover_address: reader.read_struct(AztecAddress::deserialize), + }; + + reader.finish(); + inputs + } +} + impl Hash for PublicCircuitPublicInputs { fn hash(self) -> Field { pedersen_hash(self.serialize(), GENERATOR_INDEX__PUBLIC_CIRCUIT_PUBLIC_INPUTS) diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/contrakt/deployment_data.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/contrakt/deployment_data.nr index dbe5a65990ca..c7637c795bbb 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/contrakt/deployment_data.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/contrakt/deployment_data.nr @@ -1,12 +1,18 @@ -use crate::address::EthAddress; -use crate::contract_class::ContractClassId; -use crate::constants::{ - CONTRACT_DEPLOYMENT_DATA_LENGTH, - GENERATOR_INDEX__CONTRACT_DEPLOYMENT_DATA, +use crate::{ + address::EthAddress, + contract_class::ContractClassId, + constants::{ + CONTRACT_DEPLOYMENT_DATA_LENGTH, + GENERATOR_INDEX__CONTRACT_DEPLOYMENT_DATA, + }, + grumpkin_point::GrumpkinPoint, + hash::pedersen_hash, + traits::{ + Deserialize, + Hash, + Serialize, + }, }; -use crate::hash::pedersen_hash; -use crate::grumpkin_point::GrumpkinPoint; -use crate::traits::{Hash, Serialize}; // docs:start:contract-deployment-data struct ContractDeploymentData { @@ -37,8 +43,22 @@ impl Serialize for ContractDeploymentData { } } +impl Deserialize for ContractDeploymentData { + fn deserialize(serialized: [Field; CONTRACT_DEPLOYMENT_DATA_LENGTH]) -> Self { + Self { + public_key: GrumpkinPoint { + x: serialized[0], + y: serialized[1], + }, + initialization_hash: serialized[2], + contract_class_id: ContractClassId::from_field(serialized[3]), + contract_address_salt: serialized[4], + portal_contract_address: EthAddress::from_field(serialized[5]), + } + } +} + impl ContractDeploymentData { - fn assert_is_zero(self) { self.public_key.assert_is_zero(); assert(self.initialization_hash == 0); @@ -46,5 +66,4 @@ impl ContractDeploymentData { assert(self.contract_address_salt == 0); self.portal_contract_address.assert_is_zero(); } - } diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/contrakt/storage_read.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/contrakt/storage_read.nr index 3c358168fb6a..f2149c67b1d7 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/contrakt/storage_read.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/contrakt/storage_read.nr @@ -4,14 +4,25 @@ use crate::{ GENERATOR_INDEX__PUBLIC_DATA_READ, }, hash::pedersen_hash, + traits::{ + Deserialize, + Hash, + Empty, + Serialize, + }, }; -use crate::traits::Empty; struct StorageRead { storage_slot: Field, current_value: Field, } +impl Eq for StorageRead { + fn eq(self, other: Self) -> bool { + (self.storage_slot == other.storage_slot) & (self.current_value == other.current_value) + } +} + impl Empty for StorageRead { fn empty() -> Self { Self { @@ -25,12 +36,28 @@ impl Empty for StorageRead { } } -impl StorageRead { - pub fn serialize(self) -> [Field; CONTRACT_STORAGE_READ_LENGTH] { +impl Hash for StorageRead { + fn hash(self) -> Field { + pedersen_hash(self.serialize(), GENERATOR_INDEX__PUBLIC_DATA_READ) + } +} +impl Serialize for StorageRead { + fn serialize(self) -> [Field; CONTRACT_STORAGE_READ_LENGTH] { [self.storage_slot, self.current_value] } +} - pub fn hash(self) -> Field { - pedersen_hash(self.serialize(), GENERATOR_INDEX__PUBLIC_DATA_READ) +impl Deserialize for StorageRead { + fn deserialize(serialized: [Field; CONTRACT_STORAGE_READ_LENGTH]) -> Self { + Self { + storage_slot: serialized[0], + current_value: serialized[1], + } + } +} + +impl StorageRead { + pub fn is_empty(self) -> bool { + self.storage_slot == 0 } } diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/contrakt/storage_update_request.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/contrakt/storage_update_request.nr index 42f3689e599d..c84e6da4213c 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/contrakt/storage_update_request.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/contrakt/storage_update_request.nr @@ -4,9 +4,14 @@ use crate::{ GENERATOR_INDEX__PUBLIC_DATA_UPDATE_REQUEST, }, hash::pedersen_hash, + traits::{ + Deserialize, + Hash, + Empty, + Serialize, + }, }; use dep::std::cmp::Eq; -use crate::traits::{Hash, Empty, Serialize}; struct StorageUpdateRequest{ storage_slot : Field, @@ -48,3 +53,13 @@ impl Serialize for StorageUpdateRequest [self.storage_slot, self.old_value, self.new_value] } } + +impl Deserialize for StorageUpdateRequest { + fn deserialize(serialized: [Field; CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH]) -> Self { + StorageUpdateRequest { + storage_slot: serialized[0], + old_value: serialized[1], + new_value: serialized[2], + } + } +} diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/grumpkin_point.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/grumpkin_point.nr index 71322d0afa50..59b3db2ec5fc 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/grumpkin_point.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/grumpkin_point.nr @@ -14,6 +14,15 @@ impl Serialize for GrumpkinPoint { } } +impl Deserialize for GrumpkinPoint { + fn deserialize(serialized: [Field; GRUMPKIN_POINT_SERIALIZED_LEN]) -> Self { + Self { + x: serialized[0], + y: serialized[1], + } + } +} + impl Eq for GrumpkinPoint { fn eq(self, point: GrumpkinPoint) -> bool { (point.x == self.x) & (point.y == self.y) diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/utils.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/utils.nr index f4c2b212cc2b..b39707c73ae7 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/utils.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/utils.nr @@ -4,6 +4,7 @@ mod arrays; mod field; +mod reader; mod uint256; // if predicate == true then return lhs, else return rhs diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/utils/reader.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/utils/reader.nr new file mode 100644 index 000000000000..10bfc050fb8f --- /dev/null +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/utils/reader.nr @@ -0,0 +1,41 @@ +struct Reader { + data: [Field; N], + offset: Field, +} + +impl Reader { + pub fn new(data: [Field; N]) -> Self { + Self { data, offset: 0 } + } + + pub fn read(&mut self) -> Field { + let result = self.data[self.offset]; + self.offset += 1; + result + } + + pub fn read_array(&mut self, mut result: [Field; K]) -> [Field; K] { + for i in 0..K { + result[i] = self.data[self.offset + i]; + } + self.offset += K; + result + } + + // TODO(#4394) + pub fn read_struct(&mut self, deserialise: fn([Field; K]) -> T) -> T { + let result = deserialise(self.read_array([0; K])); + result + } + + pub fn read_struct_array(&mut self, deserialise: fn([Field; K]) -> T, mut result: [T; C]) -> [T; C] { + for i in 0..C { + result[i] = self.read_struct(deserialise); + } + result + } + + pub fn finish(self) { + assert(self.offset == self.data.len(), "Reader did not read all data"); + } +}