diff --git a/l1-contracts/slither_output.md b/l1-contracts/slither_output.md index 6128c8b37f5..bb1d199cf78 100644 --- a/l1-contracts/slither_output.md +++ b/l1-contracts/slither_output.md @@ -353,9 +353,9 @@ src/core/messagebridge/Inbox.sol#L148-L153 Impact: Informational Confidence: Medium - [ ] ID-41 -Variable [Constants.L1_TO_L2_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L80) is too similar to [Constants.L2_TO_L1_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L81) +Variable [Constants.L1_TO_L2_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L96) is too similar to [Constants.L2_TO_L1_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L97) -src/core/libraries/ConstantsGen.sol#L80 +src/core/libraries/ConstantsGen.sol#L96 - [ ] ID-42 diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index df8a7fd5213..a5682884a4a 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -77,26 +77,34 @@ library Constants { 0xe7af816635466f128568edb04c9fa024f6c87fb9010fdbffa68b3d99; uint256 internal constant DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE = 0x85864497636cf755ae7bde03f267ce01a520981c21c3682aaf82a631; - uint256 internal constant L1_TO_L2_MESSAGE_LENGTH = 8; - uint256 internal constant L2_TO_L1_MESSAGE_LENGTH = 2; uint256 internal constant L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH = 25; uint256 internal constant MAX_NOTE_FIELDS_LENGTH = 20; uint256 internal constant GET_NOTE_ORACLE_RETURN_LENGTH = 23; uint256 internal constant MAX_NOTES_PER_PAGE = 10; uint256 internal constant VIEW_NOTE_ORACLE_RETURN_LENGTH = 212; + uint256 internal constant AZTEC_ADDRESS_LENGTH = 1; uint256 internal constant CALL_CONTEXT_LENGTH = 8; - uint256 internal constant GLOBAL_VARIABLES_LENGTH = 6; - uint256 internal constant PARTIAL_STATE_REFERENCE_LENGTH = 8; - uint256 internal constant STATE_REFERENCE_LENGTH = 10; uint256 internal constant CONTENT_COMMITMENT_LENGTH = 7; - uint256 internal constant HEADER_LENGTH = 25; - uint256 internal constant FUNCTION_DATA_LENGTH = 4; uint256 internal constant CONTRACT_DEPLOYMENT_DATA_LENGTH = 6; - uint256 internal constant PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 214; + uint256 internal constant CONTRACT_STORAGE_READ_LENGTH = 2; + uint256 internal constant CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH = 2; + uint256 internal constant ETH_ADDRESS_LENGTH = 1; + uint256 internal constant FUNCTION_DATA_LENGTH = 4; + uint256 internal constant FUNCTION_LEAF_PREIMAGE_LENGTH = 5; + uint256 internal constant GLOBAL_VARIABLES_LENGTH = 6; + uint256 internal constant HEADER_LENGTH = 25; + uint256 internal constant L1_TO_L2_MESSAGE_LENGTH = 8; + uint256 internal constant L2_TO_L1_MESSAGE_LENGTH = 2; + uint256 internal constant NEW_CONTRACT_DATA_LENGTH = 3; + uint256 internal constant NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH = 4; + uint256 internal constant NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_LENGTH = 5; + uint256 internal constant PARTIAL_STATE_REFERENCE_LENGTH = 8; uint256 internal constant PRIVATE_CALL_STACK_ITEM_LENGTH = 219; + uint256 internal constant PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 214; uint256 internal constant PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = 194; - uint256 internal constant CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH = 2; - uint256 internal constant CONTRACT_STORAGE_READ_LENGTH = 2; + uint256 internal constant STATE_REFERENCE_LENGTH = 10; + uint256 internal constant TX_CONTEXT_DATA_LENGTH = 11; + uint256 internal constant TX_REQUEST_LENGTH = 17; uint256 internal constant GET_NOTES_ORACLE_RETURN_LENGTH = 674; uint256 internal constant COMMITMENTS_NUM_BYTES_PER_BASE_ROLLUP = 2048; uint256 internal constant NULLIFIERS_NUM_BYTES_PER_BASE_ROLLUP = 2048; diff --git a/noir-projects/aztec-nr/aztec/src/context/inputs/private_context_inputs.nr b/noir-projects/aztec-nr/aztec/src/context/inputs/private_context_inputs.nr index c2ed873541a..48339688ea9 100644 --- a/noir-projects/aztec-nr/aztec/src/context/inputs/private_context_inputs.nr +++ b/noir-projects/aztec-nr/aztec/src/context/inputs/private_context_inputs.nr @@ -1,4 +1,7 @@ -use dep::protocol_types::{abis::call_context::CallContext, contrakt::deployment_data::ContractDeploymentData, header::Header}; +use dep::protocol_types::{ + abis::call_context::CallContext, contrakt::contract_deployment_data::ContractDeploymentData, + header::Header +}; use crate::context::globals::private_global_variables::PrivateGlobalVariables; // PrivateContextInputs are expected to be provided to each private function diff --git a/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr b/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr index 64bab5a6e72..c617053ae6a 100644 --- a/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr @@ -66,14 +66,7 @@ contract Lending { let last_updated_ts = context.timestamp() as u120; let loan_to_value = loan_to_value as u120; - asset_loc.write( - Asset { - interest_accumulator: 1000000000, - last_updated_ts, - loan_to_value, - oracle - } - ); + asset_loc.write(Asset { interest_accumulator: 1000000000, last_updated_ts, loan_to_value, oracle }); storage.collateral_asset.write(collateral_asset); storage.stable_coin.write(stable_coin); diff --git a/noir-projects/noir-contracts/package.json b/noir-projects/noir-contracts/package.json index c62f077623b..a0d93fa1c74 100644 --- a/noir-projects/noir-contracts/package.json +++ b/noir-projects/noir-contracts/package.json @@ -2,6 +2,7 @@ "name": "@aztec/noir-contracts", "version": "0.1.0", "type": "module", + "license": "MIT", "exports": { "./target/*": "./target/*.json" }, diff --git a/noir-projects/noir-protocol-circuits/package.json b/noir-projects/noir-protocol-circuits/package.json index 61be3ed3407..d957434c438 100644 --- a/noir-projects/noir-protocol-circuits/package.json +++ b/noir-projects/noir-protocol-circuits/package.json @@ -2,6 +2,7 @@ "name": "@aztec/noir-protocol-circuits", "version": "0.1.0", "type": "module", + "license": "MIT", "exports": { ".": "./dest/index.js", "./types": "./dest/types/index.js" diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/common.nr b/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/common.nr index 7c2514a3502..6e95786f39e 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/common.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/common.nr @@ -11,7 +11,7 @@ use dep::types::{ side_effect::{SideEffect, SideEffectLinkedToNoteHash} }, address::{AztecAddress, EthAddress, PartialAddress, compute_initialization_hash}, - contract_class::ContractClassId, contrakt::deployment_data::ContractDeploymentData, + contract_class::ContractClassId, contrakt::contract_deployment_data::ContractDeploymentData, constants::{ MAX_NEW_NULLIFIERS_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_COMMITMENTS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_READ_REQUESTS_PER_CALL, diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_init.nr b/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_init.nr index 276989a661a..363be67a85f 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_init.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_init.nr @@ -10,7 +10,7 @@ use dep::types::{ side_effect::{SideEffect, SideEffectLinkedToNoteHash} }, address::{AztecAddress, PublicKeysHash, compute_initialization_hash}, - mocked::{Proof, verify_previous_kernel_state}, transaction::request::TxRequest, + mocked::{Proof, verify_previous_kernel_state}, transaction::tx_request::TxRequest, traits::is_empty_array }; @@ -133,7 +133,7 @@ mod tests { grumpkin_private_key::GrumpkinPrivateKey, hash::{compute_constructor_hash, compute_logs_hash, stdlib_recursion_verification_key_compress_native_vk}, messaging::l2_to_l1_message::L2ToL1Message, - tests::private_call_data_builder::PrivateCallDataBuilder, transaction::request::TxRequest, + tests::private_call_data_builder::PrivateCallDataBuilder, transaction::tx_request::TxRequest, utils::arrays::array_length }; diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis.nr index dd30f3f4c92..b1c37eb647e 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis.nr @@ -1,5 +1,7 @@ mod append_only_tree_snapshot; +mod contract_class_function_leaf_preimage; + mod function_selector; mod function_data; mod function_leaf_preimage; diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/combined_constant_data.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/combined_constant_data.nr index 2ccf9e7e51b..1ae4ba6ce50 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/combined_constant_data.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/combined_constant_data.nr @@ -1,4 +1,4 @@ -use crate::transaction::context::TxContext; +use crate::transaction::tx_context::TxContext; use crate::header::Header; struct CombinedConstantData { diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/contract_class_function_leaf_preimage.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/contract_class_function_leaf_preimage.nr new file mode 100644 index 00000000000..3a94d6cd241 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/contract_class_function_leaf_preimage.nr @@ -0,0 +1,17 @@ +use crate::abis::function_selector::FunctionSelector; +use crate::constants::GENERATOR_INDEX__FUNCTION_LEAF; +use crate::traits::Hash; + +struct ContractClassFunctionLeafPreimage { + selector : FunctionSelector, + vk_hash : Field, +} + +impl Hash for ContractClassFunctionLeafPreimage { + fn hash(self) -> Field { + dep::std::hash::pedersen_hash_with_separator([ + self.selector.to_field(), + self.vk_hash, + ], GENERATOR_INDEX__FUNCTION_LEAF) + } +} diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/function_data.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/function_data.nr index ac042d74b31..d185979b20a 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/function_data.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/function_data.nr @@ -61,6 +61,7 @@ fn serialization_of_empty() { assert(data.eq(deserialized)); } +// TODO(#4619): Hash non-empty #[test] fn empty_hash() { let data: FunctionData = dep::std::unsafe::zeroed(); diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/function_leaf_preimage.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/function_leaf_preimage.nr index 20252e40fd3..ded25c0740e 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/function_leaf_preimage.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/function_leaf_preimage.nr @@ -1,6 +1,8 @@ -use crate::abis::function_selector::FunctionSelector; -use crate::constants::GENERATOR_INDEX__FUNCTION_LEAF; -use crate::traits::Hash; +use crate::{ + abis::function_selector::FunctionSelector, + constants::{GENERATOR_INDEX__FUNCTION_LEAF, FUNCTION_LEAF_PREIMAGE_LENGTH}, hash::pedersen_hash, + traits::{Serialize, Hash, Deserialize} +}; struct FunctionLeafPreimage { selector : FunctionSelector, @@ -10,28 +12,66 @@ struct FunctionLeafPreimage { acir_hash : Field } -impl Hash for FunctionLeafPreimage { - fn hash(self) -> Field { - dep::std::hash::pedersen_hash_with_separator([ +impl Eq for FunctionLeafPreimage { + fn eq(self, other: Self) -> bool { + self.selector.eq(other.selector) & + (self.is_internal == other.is_internal) & + (self.is_private == other.is_private) & + (self.vk_hash == other.vk_hash) & + (self.acir_hash == other.acir_hash) + } +} + +impl Serialize for FunctionLeafPreimage { + fn serialize(self) -> [Field; FUNCTION_LEAF_PREIMAGE_LENGTH] { + [ self.selector.to_field(), self.is_internal as Field, self.is_private as Field, self.vk_hash, - self.acir_hash - ], GENERATOR_INDEX__FUNCTION_LEAF) + self.acir_hash, + ] } } -struct ContractClassFunctionLeafPreimage { - selector : FunctionSelector, - vk_hash : Field, +impl Deserialize for FunctionLeafPreimage { + fn deserialize(serialized: [Field; FUNCTION_LEAF_PREIMAGE_LENGTH]) -> Self { + Self { + selector: FunctionSelector::from_field(serialized[0]), + is_internal: serialized[1] as bool, + is_private: serialized[2] as bool, + vk_hash: serialized[3], + acir_hash: serialized[4], + } + } } -impl Hash for ContractClassFunctionLeafPreimage { +impl Hash for FunctionLeafPreimage { fn hash(self) -> Field { - dep::std::hash::pedersen_hash_with_separator([ - self.selector.to_field(), - self.vk_hash, - ], GENERATOR_INDEX__FUNCTION_LEAF) + pedersen_hash(self.serialize(), GENERATOR_INDEX__FUNCTION_LEAF) } } + +#[test] +fn serialization_of_empty() { + let data: FunctionLeafPreimage = dep::std::unsafe::zeroed(); + let serialized = data.serialize(); + let deserialized = FunctionLeafPreimage::deserialize(serialized); + assert(data.eq(deserialized)); +} + +#[test] +fn empty_hash() { + let data: FunctionLeafPreimage = dep::std::unsafe::zeroed(); + let hash = data.hash(); + + // Value from function_leaf_preimage.test.ts "computes a function leaf" test + assert_eq(hash, 0x1f2e3193c7187347a099ee7cb5d6ac077da6b18706fe5508e658a3d0a05494f7); +} + +#[test] +fn compute_function_leaf() { + let leaf = FunctionLeafPreimage { selector: FunctionSelector::from_u32(27), is_internal: false, is_private: true, vk_hash: 1, acir_hash: 2 }; + + assert_eq(leaf.hash(), 0x1ad8ece7f40e63d011ae47c6ce6cdaf31d632a23f5cf35bbeaaf69c8302afdbc); +} diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/new_contract_data.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/new_contract_data.nr index 598c00e103a..2f129dbdff8 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/new_contract_data.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/new_contract_data.nr @@ -1,8 +1,9 @@ use crate::address::{AztecAddress, EthAddress}; use crate::contract_class::ContractClassId; -use crate::constants::GENERATOR_INDEX__CONTRACT_LEAF; +use crate::constants::{GENERATOR_INDEX__CONTRACT_LEAF, NEW_CONTRACT_DATA_LENGTH}; use dep::std::cmp::Eq; -use crate::traits::{Empty, Hash}; +use crate::traits::{Empty, Serialize, Hash, Deserialize}; +use crate::hash::pedersen_hash; struct NewContractData { contract_address: AztecAddress, @@ -18,6 +19,26 @@ impl Eq for NewContractData { } } +impl Serialize for NewContractData { + fn serialize(self) -> [Field; NEW_CONTRACT_DATA_LENGTH] { + [ + self.contract_address.to_field(), + self.portal_contract_address.to_field(), + self.contract_class_id.to_field(), + ] + } +} + +impl Deserialize for NewContractData { + fn deserialize(serialized: [Field; NEW_CONTRACT_DATA_LENGTH]) -> Self { + Self { + contract_address: AztecAddress::from_field(serialized[0]), + portal_contract_address: EthAddress::from_field(serialized[1]), + contract_class_id: ContractClassId::from_field(serialized[2]), + } + } +} + impl Empty for NewContractData { fn empty() -> Self { Self { @@ -33,11 +54,7 @@ impl Hash for NewContractData { if self.is_empty() { 0 // We want to return 0 here since the contract_address is zero } else { - dep::std::hash::pedersen_hash_with_separator([ - self.contract_address.to_field(), - self.portal_contract_address.to_field(), - self.contract_class_id.to_field(), - ], GENERATOR_INDEX__CONTRACT_LEAF) + pedersen_hash(self.serialize(), GENERATOR_INDEX__CONTRACT_LEAF) } } } diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/nullifier_key_validation_request.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/nullifier_key_validation_request.nr index e1e7769bb10..a522dace348 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/nullifier_key_validation_request.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/nullifier_key_validation_request.nr @@ -1,12 +1,11 @@ use dep::std::cmp::Eq; use crate::{ - address::AztecAddress, traits::{Empty, Serialize, Deserialize}, grumpkin_point::GrumpkinPoint, + address::AztecAddress, + constants::{NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_LENGTH, NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH}, + traits::{Empty, Serialize, Deserialize}, grumpkin_point::GrumpkinPoint, grumpkin_private_key::GrumpkinPrivateKey }; -global NULLIFIER_KEY_VALIDATION_REQUEST_SERIALIZED_LEN = 4; -global NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_SERIALIZED_LEN = 5; - struct NullifierKeyValidationRequest { public_key: GrumpkinPoint, secret_key: GrumpkinPrivateKey, @@ -28,8 +27,8 @@ impl Empty for NullifierKeyValidationRequest { } } -impl Serialize for NullifierKeyValidationRequest { - fn serialize(self) -> [Field; NULLIFIER_KEY_VALIDATION_REQUEST_SERIALIZED_LEN] { +impl Serialize for NullifierKeyValidationRequest { + fn serialize(self) -> [Field; NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH] { [ self.public_key.x, self.public_key.y, @@ -39,8 +38,8 @@ impl Serialize for NullifierKey } } -impl Deserialize for NullifierKeyValidationRequest { - fn deserialize(fields: [Field; NULLIFIER_KEY_VALIDATION_REQUEST_SERIALIZED_LEN]) -> Self { +impl Deserialize for NullifierKeyValidationRequest { + fn deserialize(fields: [Field; NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH]) -> Self { Self { public_key: GrumpkinPoint::new(fields[0], fields[1]), secret_key: GrumpkinPrivateKey::new(fields[2], fields[3]), @@ -78,8 +77,8 @@ impl Empty for NullifierKeyValidationRequestContext { } } -impl Serialize for NullifierKeyValidationRequestContext { - fn serialize(self) -> [Field; NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_SERIALIZED_LEN] { +impl Serialize for NullifierKeyValidationRequestContext { + fn serialize(self) -> [Field; NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_LENGTH] { [ self.public_key.x, self.public_key.y, @@ -90,8 +89,8 @@ impl Serialize for Null } } -impl Deserialize for NullifierKeyValidationRequestContext { - fn deserialize(fields: [Field; NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_SERIALIZED_LEN]) -> Self { +impl Deserialize for NullifierKeyValidationRequestContext { + fn deserialize(fields: [Field; NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_LENGTH]) -> Self { Self { public_key: GrumpkinPoint::new(fields[0], fields[1]), secret_key: GrumpkinPrivateKey::new(fields[2], fields[3]), diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/private_call_stack_item.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/private_call_stack_item.nr index 9b8fc45d0c9..2fe2f373b44 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/private_call_stack_item.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/private_call_stack_item.nr @@ -68,6 +68,7 @@ fn serialization_of_empty() { assert(item.eq(deserialized)); } +// TODO(#4619): Hash non-empty #[test] fn empty_hash() { let mut item: PrivateCallStackItem = dep::std::unsafe::zeroed(); @@ -75,5 +76,5 @@ fn empty_hash() { let hash = item.hash(); // Value from private_call_stack_item.test.ts "computes empty item hash" test - assert_eq(hash, 0x1c3b67cab2bc3dc2106cfeddd8ea68b8d445849f20ed3b9286ad684542aae25d); + assert_eq(hash, 0x07151bc7440eb0b1c4c61a0bcfacca82cf2aed402c20d3742557179f7fedb635); } diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/private_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/private_circuit_public_inputs.nr index dbfa07e4dd9..53d6216ba69 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/private_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/private_circuit_public_inputs.nr @@ -10,7 +10,7 @@ use crate::{ RETURN_VALUES_LENGTH, PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH, GENERATOR_INDEX__PRIVATE_CIRCUIT_PUBLIC_INPUTS }, - contrakt::deployment_data::ContractDeploymentData, header::Header, hash::pedersen_hash, + contrakt::contract_deployment_data::ContractDeploymentData, header::Header, hash::pedersen_hash, messaging::l2_to_l1_message::L2ToL1Message, traits::{Deserialize, Hash, Serialize}, utils::reader::Reader }; @@ -165,11 +165,12 @@ fn serialization_of_empty() { assert(pcpi.eq(deserialized)); } +// TODO(#4619): Hash non-empty #[test] fn empty_hash() { let inputs: PrivateCircuitPublicInputs = dep::std::unsafe::zeroed(); let hash = inputs.hash(); // Value from private_circuit_public_inputs.test.ts "computes empty item hash" test - assert_eq(hash, 0x2745ec62624afeb19b86af3d440db1f8c3432e1d17a074c75cb8f44999fd3fae); + assert_eq(hash, 0x1d45bdd12fe635c85eedd27300524378c35be3aafb3501632a408bbe9db2e1d9); } diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/public_call_stack_item.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/public_call_stack_item.nr index d113c95b0ab..1fe1f24f3b6 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/public_call_stack_item.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/public_call_stack_item.nr @@ -44,3 +44,48 @@ impl PublicCallStackItem { call_stack_item } } + +mod tests { + use crate::{ + abis::{ + function_data::FunctionData, function_selector::FunctionSelector, + public_circuit_public_inputs::PublicCircuitPublicInputs, + public_call_stack_item::PublicCallStackItem, side_effect::SideEffect + }, + address::AztecAddress, constants::GENERATOR_INDEX__CALL_STACK_ITEM, traits::Hash + }; + + #[test] + fn compute_call_stack_item_request_hash() { + let contract_address = AztecAddress::from_field(1); + let function_data = FunctionData { selector: FunctionSelector::from_u32(2), is_internal: false, is_private: false, is_constructor: false }; + + let mut public_inputs: PublicCircuitPublicInputs = dep::std::unsafe::zeroed(); + public_inputs.new_commitments[0] = SideEffect{ + value: 1, + counter: 0, + }; + + let call_stack_item = PublicCallStackItem { contract_address, public_inputs, is_execution_request: true, function_data }; + + // Value from public_call_stack_item.test.ts "Computes a callstack item request hash" test + assert_eq(call_stack_item.hash(), 0x2812dfeffdb7553fbbdd27c03fbdf61e3aa9bab3209db39f78838508ad892803); + } + + #[test] + fn compute_call_stack_item_hash() { + let contract_address = AztecAddress::from_field(1); + let function_data = FunctionData { selector: FunctionSelector::from_u32(2), is_internal: false, is_private: false, is_constructor: false }; + + let mut public_inputs: PublicCircuitPublicInputs = dep::std::unsafe::zeroed(); + public_inputs.new_commitments[0] = SideEffect{ + value: 1, + counter: 0, + }; + + let call_stack_item = PublicCallStackItem { contract_address, public_inputs, is_execution_request: false, function_data }; + + // Value from public_call_stack_item.test.ts "Computes a callstack item hash" test + assert_eq(call_stack_item.hash(), 0x1f71c0d6bd03e409df694549b6aa83d706cfe55427152e6ec443ec64fa62d3a0); + } +} diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/address.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/address.nr index ab4b31e0ce2..20594437e86 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/address.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/address.nr @@ -1,297 +1,16 @@ -use crate::{ - constants::{GENERATOR_INDEX__CONTRACT_ADDRESS, GENERATOR_INDEX__PARTIAL_ADDRESS, GENERATOR_INDEX__CONSTRUCTOR}, - hash::pedersen_hash, contract_class::ContractClassId, utils, grumpkin_point::GrumpkinPoint -}; -use dep::std::cmp::Eq; -use crate::traits::{Empty, ToField, Serialize, Deserialize}; -use crate::type_serialization::{ETH_ADDRESS_SERIALIZED_LEN, AZTEC_ADDRESS_SERIALIZED_LEN}; - -// Aztec address -struct AztecAddress { - inner : Field -} - -impl Eq for AztecAddress { - fn eq(self, other : Self) -> bool { - self.to_field() == other.to_field() - } -} - -impl Empty for AztecAddress { - fn empty() -> Self { - Self { - inner : 0 - } - } -} - -impl ToField for AztecAddress { - fn to_field(self) -> Field { - self.inner - } -} - -impl Serialize for AztecAddress { - fn serialize(self: Self) -> [Field; AZTEC_ADDRESS_SERIALIZED_LEN] { - [self.to_field()] - } -} - -impl Deserialize for AztecAddress { - fn deserialize(fields: [Field; AZTEC_ADDRESS_SERIALIZED_LEN]) -> Self { - AztecAddress::from_field(fields[0]) - } -} - -impl AztecAddress { - pub fn zero() -> Self { - Self { inner: 0 } - } - - pub fn from_field(field: Field) -> Self { - Self { inner: field } - } - - pub fn compute_from_public_key( - pub_key: GrumpkinPoint, - contract_class_id: ContractClassId, - salt: Field, - initialization_hash: Field, - portal_contract_address: EthAddress - ) -> AztecAddress { - AztecAddress::compute( - PublicKeysHash::compute(pub_key), - PartialAddress::compute( - contract_class_id, - salt, - initialization_hash, - portal_contract_address - ) - ) - } - - pub fn compute(pub_keys_hash: PublicKeysHash, partial_address: PartialAddress) -> AztecAddress { - AztecAddress::from_field( - pedersen_hash( - [pub_keys_hash.to_field(), partial_address.to_field()], - GENERATOR_INDEX__CONTRACT_ADDRESS - ) - ) - } - - pub fn is_zero(self) -> bool { - self.inner == 0 - } - - pub fn assert_is_zero(self) { - assert(self.to_field() == 0); - } - - pub fn conditional_assign(predicate: bool, lhs: Self, rhs: Self) -> Self { - let result = utils::conditional_assign(predicate, rhs.to_field(), lhs.to_field()); - Self { inner: result } - } -} - -struct EthAddress{ - inner : Field -} - -impl Eq for EthAddress { - fn eq(self, other : Self) -> bool { - self.to_field() == other.to_field() - } -} - -impl Empty for EthAddress { - fn empty() -> Self { - Self { - inner : 0 - } - } -} - -impl ToField for EthAddress { - fn to_field(self) -> Field { - self.inner - } -} - -impl Serialize for EthAddress { - fn serialize(self: Self) -> [Field; ETH_ADDRESS_SERIALIZED_LEN] { - [self.inner] - } -} - -impl Deserialize for EthAddress { - fn deserialize(fields: [Field; ETH_ADDRESS_SERIALIZED_LEN]) -> Self { - Self { - inner: fields[0] - } - } -} - -impl EthAddress { - pub fn zero() -> Self { - Self { inner: 0 } - } - - pub fn from_field(field: Field) -> Self { - Self { inner: field } - } - - pub fn is_zero(self) -> bool { - self.inner == 0 - } - - pub fn assert_is_zero(self) { - assert(self.to_field() == 0); - } - - pub fn conditional_assign(predicate: bool, lhs: Self, rhs: Self) -> Self { - let result = utils::conditional_assign(predicate, rhs.to_field(), lhs.to_field()); - Self { inner: result } - } -} - -// Partial address -struct PartialAddress { - inner : Field -} - -impl ToField for PartialAddress { - fn to_field(self) -> Field { - self.inner - } -} - -impl PartialAddress { - pub fn from_field(field: Field) -> Self { - Self { inner: field } - } - - pub fn compute( - contract_class_id: ContractClassId, - salt: Field, - initialization_hash: Field, - portal_contract_address: EthAddress - ) -> Self { - PartialAddress::compute_from_salted_initialization_hash( - contract_class_id, - SaltedInitializationHash::compute(salt, initialization_hash, portal_contract_address) - ) - } - - pub fn compute_from_salted_initialization_hash( - contract_class_id: ContractClassId, - salted_initialization_hash: SaltedInitializationHash - ) -> Self { - PartialAddress::from_field( - pedersen_hash( - [ - contract_class_id.to_field(), - salted_initialization_hash.to_field() - ], - GENERATOR_INDEX__PARTIAL_ADDRESS - ) - ) - } - - pub fn to_field(self) -> Field { - self.inner - } - - pub fn assert_is_zero(self) { - assert(self.to_field() == 0); - } -} - -// Salted initialization hash. Used in the computation of a partial address. -struct SaltedInitializationHash { - inner: Field -} - -impl ToField for SaltedInitializationHash { - fn to_field(self) -> Field { - self.inner - } -} - -impl SaltedInitializationHash { - pub fn from_field(field: Field) -> Self { - Self { inner: field } - } - - pub fn compute(salt: Field, initialization_hash: Field, portal_contract_address: EthAddress) -> Self { - SaltedInitializationHash::from_field( - pedersen_hash( - [ - salt, - initialization_hash, - portal_contract_address.to_field() - ], - GENERATOR_INDEX__PARTIAL_ADDRESS - ) - ) - } - - pub fn to_field(self) -> Field { - self.inner - } - - pub fn assert_is_zero(self) { - assert(self.to_field() == 0); - } -} - -// Public keys hash. Used in the computation of an address. -struct PublicKeysHash { - inner: Field -} - -impl ToField for PublicKeysHash { - fn to_field(self) -> Field { - self.inner - } -} - -impl Serialize<1> for PublicKeysHash { - fn serialize(self: Self) -> [Field; 1] { - [self.to_field()] - } -} - -impl Deserialize<1> for PublicKeysHash { - fn deserialize(fields: [Field; 1]) -> Self { - PublicKeysHash::from_field(fields[0]) - } -} - -impl PublicKeysHash { - pub fn from_field(field: Field) -> Self { - Self { inner: field } - } - - pub fn compute(public_key: GrumpkinPoint) -> Self { - PublicKeysHash::from_field( - pedersen_hash( - [ - public_key.x, - public_key.y - ], - GENERATOR_INDEX__PARTIAL_ADDRESS - ) - ) - } - - pub fn to_field(self) -> Field { - self.inner - } - - pub fn assert_is_zero(self) { - assert(self.to_field() == 0); - } -} +mod aztec_address; +mod eth_address; +mod partial_address; +mod public_keys_hash; +mod salted_initialization_hash; + +use crate::address::aztec_address::AztecAddress; +use crate::address::eth_address::EthAddress; +use crate::address::partial_address::PartialAddress; +use crate::address::public_keys_hash::PublicKeysHash; +use crate::address::salted_initialization_hash::SaltedInitializationHash; + +use crate::{constants::GENERATOR_INDEX__CONSTRUCTOR, hash::pedersen_hash}; pub fn compute_initialization_hash(selector: Field, args_hash: Field) -> Field { pedersen_hash( diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/address/aztec_address.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/address/aztec_address.nr new file mode 100644 index 00000000000..e407dbebb2b --- /dev/null +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/address/aztec_address.nr @@ -0,0 +1,121 @@ +use crate::{ + crate::address::{eth_address::EthAddress, partial_address::PartialAddress, public_keys_hash::PublicKeysHash}, + constants::{AZTEC_ADDRESS_LENGTH, GENERATOR_INDEX__CONTRACT_ADDRESS}, + contract_class::ContractClassId, hash::pedersen_hash, grumpkin_point::GrumpkinPoint, + traits::{Empty, ToField, Serialize, Deserialize}, utils +}; + +// Aztec address +struct AztecAddress { + inner : Field +} + +impl Eq for AztecAddress { + fn eq(self, other : Self) -> bool { + self.to_field() == other.to_field() + } +} + +impl Empty for AztecAddress { + fn empty() -> Self { + Self { + inner : 0 + } + } +} + +impl ToField for AztecAddress { + fn to_field(self) -> Field { + self.inner + } +} + +impl Serialize for AztecAddress { + fn serialize(self: Self) -> [Field; AZTEC_ADDRESS_LENGTH] { + [self.to_field()] + } +} + +impl Deserialize for AztecAddress { + fn deserialize(fields: [Field; AZTEC_ADDRESS_LENGTH]) -> Self { + AztecAddress::from_field(fields[0]) + } +} + +impl AztecAddress { + pub fn zero() -> Self { + Self { inner: 0 } + } + + pub fn from_field(field: Field) -> Self { + Self { inner: field } + } + + pub fn compute_from_public_key( + pub_key: GrumpkinPoint, + contract_class_id: ContractClassId, + salt: Field, + initialization_hash: Field, + portal_contract_address: EthAddress + ) -> AztecAddress { + AztecAddress::compute( + PublicKeysHash::compute(pub_key), + PartialAddress::compute( + contract_class_id, + salt, + initialization_hash, + portal_contract_address + ) + ) + } + + pub fn compute(pub_keys_hash: PublicKeysHash, partial_address: PartialAddress) -> AztecAddress { + AztecAddress::from_field( + pedersen_hash( + [pub_keys_hash.to_field(), partial_address.to_field()], + GENERATOR_INDEX__CONTRACT_ADDRESS + ) + ) + } + + pub fn is_zero(self) -> bool { + self.inner == 0 + } + + pub fn assert_is_zero(self) { + assert(self.to_field() == 0); + } + + pub fn conditional_assign(predicate: bool, lhs: Self, rhs: Self) -> Self { + let result = utils::conditional_assign(predicate, rhs.to_field(), lhs.to_field()); + Self { inner: result } + } +} + +#[test] +fn compute_address() { + let point = GrumpkinPoint { x: 1, y: 2 }; + let contract_address_salt = 3; + let contract_class_id = ContractClassId::from_field(4); + let initialization_hash = 5; + let portal_contract_address = EthAddress::from_field(6); + + let address = AztecAddress::compute_from_public_key( + point, + contract_class_id, + contract_address_salt, + initialization_hash, + portal_contract_address + ); + + assert(address.to_field() == 0x2fd71a4f0742364f194dd16d0ae32d2f47845ddc7f5d328f37d4148b565c4123); +} + +#[test] +fn compute_address_from_partial_and_pubkey() { + let point = GrumpkinPoint { x: 1, y: 2 }; + let partial_address = PartialAddress::from_field(3); + + let address = AztecAddress::compute(PublicKeysHash::compute(point), partial_address); + assert(address.to_field() == 0x0447f893197175723deb223696e2e96dbba1e707ee8507766373558877e74197); +} diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/address/eth_address.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/address/eth_address.nr new file mode 100644 index 00000000000..4edb40f6b6e --- /dev/null +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/address/eth_address.nr @@ -0,0 +1,65 @@ +use crate::{ + constants::ETH_ADDRESS_LENGTH, hash::pedersen_hash, + traits::{Empty, ToField, Serialize, Deserialize}, utils +}; + +struct EthAddress{ + inner : Field +} + +impl Eq for EthAddress { + fn eq(self, other : Self) -> bool { + self.to_field() == other.to_field() + } +} + +impl Empty for EthAddress { + fn empty() -> Self { + Self { + inner : 0 + } + } +} + +impl ToField for EthAddress { + fn to_field(self) -> Field { + self.inner + } +} + +impl Serialize for EthAddress { + fn serialize(self: Self) -> [Field; ETH_ADDRESS_LENGTH] { + [self.inner] + } +} + +impl Deserialize for EthAddress { + fn deserialize(fields: [Field; ETH_ADDRESS_LENGTH]) -> Self { + Self { + inner: fields[0] + } + } +} + +impl EthAddress { + pub fn zero() -> Self { + Self { inner: 0 } + } + + pub fn from_field(field: Field) -> Self { + Self { inner: field } + } + + pub fn is_zero(self) -> bool { + self.inner == 0 + } + + pub fn assert_is_zero(self) { + assert(self.to_field() == 0); + } + + pub fn conditional_assign(predicate: bool, lhs: Self, rhs: Self) -> Self { + let result = utils::conditional_assign(predicate, rhs.to_field(), lhs.to_field()); + Self { inner: result } + } +} diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/address/partial_address.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/address/partial_address.nr new file mode 100644 index 00000000000..7e3f49ed8f6 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/address/partial_address.nr @@ -0,0 +1,57 @@ +use crate::{ + address::{eth_address::EthAddress, salted_initialization_hash::SaltedInitializationHash}, + constants::GENERATOR_INDEX__PARTIAL_ADDRESS, contract_class::ContractClassId, hash::pedersen_hash, + traits::ToField +}; + +// Partial address +struct PartialAddress { + inner : Field +} + +impl ToField for PartialAddress { + fn to_field(self) -> Field { + self.inner + } +} + +impl PartialAddress { + pub fn from_field(field: Field) -> Self { + Self { inner: field } + } + + pub fn compute( + contract_class_id: ContractClassId, + salt: Field, + initialization_hash: Field, + portal_contract_address: EthAddress + ) -> Self { + PartialAddress::compute_from_salted_initialization_hash( + contract_class_id, + SaltedInitializationHash::compute(salt, initialization_hash, portal_contract_address) + ) + } + + pub fn compute_from_salted_initialization_hash( + contract_class_id: ContractClassId, + salted_initialization_hash: SaltedInitializationHash + ) -> Self { + PartialAddress::from_field( + pedersen_hash( + [ + contract_class_id.to_field(), + salted_initialization_hash.to_field() + ], + GENERATOR_INDEX__PARTIAL_ADDRESS + ) + ) + } + + pub fn to_field(self) -> Field { + self.inner + } + + pub fn assert_is_zero(self) { + assert(self.to_field() == 0); + } +} diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/address/public_keys_hash.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/address/public_keys_hash.nr new file mode 100644 index 00000000000..34c085ef999 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/address/public_keys_hash.nr @@ -0,0 +1,60 @@ +use crate::{ + constants::GENERATOR_INDEX__PARTIAL_ADDRESS, hash::pedersen_hash, grumpkin_point::GrumpkinPoint, + traits::{ToField, Serialize, Deserialize} +}; + +// Public keys hash. Used in the computation of an address. +struct PublicKeysHash { + inner: Field +} + +impl ToField for PublicKeysHash { + fn to_field(self) -> Field { + self.inner + } +} + +impl Serialize<1> for PublicKeysHash { + fn serialize(self: Self) -> [Field; 1] { + [self.to_field()] + } +} + +impl Deserialize<1> for PublicKeysHash { + fn deserialize(fields: [Field; 1]) -> Self { + PublicKeysHash::from_field(fields[0]) + } +} + +impl PublicKeysHash { + pub fn from_field(field: Field) -> Self { + Self { inner: field } + } + + pub fn compute(public_key: GrumpkinPoint) -> Self { + PublicKeysHash::from_field( + pedersen_hash( + [ + public_key.x, + public_key.y + ], + GENERATOR_INDEX__PARTIAL_ADDRESS + ) + ) + } + + pub fn to_field(self) -> Field { + self.inner + } + + pub fn assert_is_zero(self) { + assert(self.to_field() == 0); + } +} + +#[test] +fn compute_public_keys_hash() { + let point = GrumpkinPoint { x: 1, y: 2 }; + let actual = PublicKeysHash::compute(point); + assert(actual.to_field() == 0x1923a6246e305720b6aaf751fde0342613e93c82e455c3831e28375c16dd40d8); +} diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/address/salted_initialization_hash.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/address/salted_initialization_hash.nr new file mode 100644 index 00000000000..ed0b2b831b7 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/address/salted_initialization_hash.nr @@ -0,0 +1,42 @@ +use crate::{ + address::eth_address::EthAddress, constants::GENERATOR_INDEX__PARTIAL_ADDRESS, hash::pedersen_hash, + traits::ToField +}; + +// Salted initialization hash. Used in the computation of a partial address. +struct SaltedInitializationHash { + inner: Field +} + +impl ToField for SaltedInitializationHash { + fn to_field(self) -> Field { + self.inner + } +} + +impl SaltedInitializationHash { + pub fn from_field(field: Field) -> Self { + Self { inner: field } + } + + pub fn compute(salt: Field, initialization_hash: Field, portal_contract_address: EthAddress) -> Self { + SaltedInitializationHash::from_field( + pedersen_hash( + [ + salt, + initialization_hash, + portal_contract_address.to_field() + ], + GENERATOR_INDEX__PARTIAL_ADDRESS + ) + ) + } + + pub fn to_field(self) -> Field { + self.inner + } + + pub fn assert_is_zero(self) { + assert(self.to_field() == 0); + } +} diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/constants.nr index 4484bea09b5..6d81837f76d 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/constants.nr @@ -115,8 +115,6 @@ global DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE = 0x85864497636cf755ae7bd // Some are defined here because Noir doesn't yet support globals referencing other globals yet. // Move these constants to a noir file once the issue below is resolved: // https://github.com/noir-lang/noir/issues/1734 -global L1_TO_L2_MESSAGE_LENGTH: Field = 8; -global L2_TO_L1_MESSAGE_LENGTH: Field = 2; global L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH: Field = 25; global MAX_NOTE_FIELDS_LENGTH: Field = 20; // GET_NOTE_ORACLE_RETURN_LENGT = MAX_NOTE_FIELDS_LENGTH + 1 + 2 @@ -126,23 +124,36 @@ global GET_NOTE_ORACLE_RETURN_LENGTH: Field = 23; global MAX_NOTES_PER_PAGE: Field = 10; // VIEW_NOTE_ORACLE_RETURN_LENGTH = MAX_NOTES_PER_PAGE * (MAX_NOTE_FIELDS_LENGTH + 1) + 2; global VIEW_NOTE_ORACLE_RETURN_LENGTH: Field = 212; + +// LENGTH OF STRUCTS SERIALIZED TO FIELDS +global AZTEC_ADDRESS_LENGTH = 1; global CALL_CONTEXT_LENGTH: Field = 8; -global GLOBAL_VARIABLES_LENGTH: Field = 6; -global PARTIAL_STATE_REFERENCE_LENGTH: Field = 8; -global STATE_REFERENCE_LENGTH: Field = 10; // 2 for snap + 8 for partial global CONTENT_COMMITMENT_LENGTH: Field = 7; -global HEADER_LENGTH: Field = 25; // 2 for last_archive, 7 for content commitment, 10 for state reference, 6 for global vars -global FUNCTION_DATA_LENGTH: Field = 4; global CONTRACT_DEPLOYMENT_DATA_LENGTH: Field = 6; +global CONTRACT_STORAGE_READ_LENGTH: Field = 2; +global CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH: Field = 2; +global ETH_ADDRESS_LENGTH = 1; +global FUNCTION_DATA_LENGTH: Field = 4; +global FUNCTION_LEAF_PREIMAGE_LENGTH: Field = 5; +global GLOBAL_VARIABLES_LENGTH: Field = 6; +global HEADER_LENGTH: Field = 25; // 2 for last_archive, 7 for content commitment, 10 for state reference, 6 for global vars +global L1_TO_L2_MESSAGE_LENGTH: Field = 8; +global L2_TO_L1_MESSAGE_LENGTH: Field = 2; +global NEW_CONTRACT_DATA_LENGTH: Field = 3; +global NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH = 4; +global NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_LENGTH = 5; +global PARTIAL_STATE_REFERENCE_LENGTH: Field = 8; +global PRIVATE_CALL_STACK_ITEM_LENGTH: Field = 219; // Change this ONLY if you have changed the PrivateCircuitPublicInputs structure. // In other words, if the structure/size of the public inputs of a function call changes then we should change this // constant as well PRIVATE_CALL_STACK_ITEM_LENGTH global PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH: Field = 214; -global PRIVATE_CALL_STACK_ITEM_LENGTH: Field = 219; // Change this ONLY if you have changed the PublicCircuitPublicInputs structure. global PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH: Field = 194; -global CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH: Field = 2; -global CONTRACT_STORAGE_READ_LENGTH: Field = 2; +global STATE_REFERENCE_LENGTH: Field = 10; // 2 for snap + 8 for partial +global TX_CONTEXT_DATA_LENGTH: Field = 11; +global TX_REQUEST_LENGTH: Field = 17; + global GET_NOTES_ORACLE_RETURN_LENGTH: Field = 674; global COMMITMENTS_NUM_BYTES_PER_BASE_ROLLUP: Field = 2048; global NULLIFIERS_NUM_BYTES_PER_BASE_ROLLUP: Field = 2048; diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/contrakt.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/contrakt.nr index ee2acdd3993..75c7324eb40 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/contrakt.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/contrakt.nr @@ -1,3 +1,3 @@ -mod deployment_data; +mod contract_deployment_data; mod storage_read; mod storage_update_request; diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/contrakt/deployment_data.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/contrakt/contract_deployment_data.nr similarity index 89% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/contrakt/deployment_data.nr rename to noir-projects/noir-protocol-circuits/src/crates/types/src/contrakt/contract_deployment_data.nr index e1f13954e36..9e97e634e41 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/contrakt/deployment_data.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/contrakt/contract_deployment_data.nr @@ -75,3 +75,13 @@ fn serialization_of_empty() { let deserialized = ContractDeploymentData::deserialize(serialized); assert(data.eq(deserialized)); } + +// TODO(#4619): Hash non-empty +#[test] +fn empty_hash() { + let data: ContractDeploymentData = dep::std::unsafe::zeroed(); + let hash = data.hash(); + + // Value from contract_deployment_data.test.ts "computes empty item hash" test + assert_eq(hash, 0x0e7babf59de8dfc7f5992cd34fb0066105d07ce67f68fc33d4a0a6a933a30405); +} diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/hash.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/hash.nr index d82313271de..b2804c6b6c1 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/hash.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/hash.nr @@ -1,7 +1,8 @@ use crate::address::{AztecAddress, EthAddress}; use crate::mocked::VerificationKey; use crate::abis::function_selector::FunctionSelector; -use crate::abis::function_leaf_preimage::{ContractClassFunctionLeafPreimage, FunctionLeafPreimage}; +use crate::abis::function_leaf_preimage::FunctionLeafPreimage; +use crate::abis::contract_class_function_leaf_preimage::ContractClassFunctionLeafPreimage; use crate::contract_class::ContractClassId; use crate::abis::new_contract_data::NewContractData as ContractLeafPreimage; use crate::abis::function_data::FunctionData; @@ -323,3 +324,41 @@ pub fn compute_unique_siloed_commitments( pub fn pedersen_hash(inputs: [Field; N], hash_index: u32) -> Field { dep::std::hash::pedersen_hash_with_separator(inputs, hash_index) } + +#[test] +fn smoke_sha256_to_field() { + let full_buffer = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159 + ]; + let result = sha256_to_field(full_buffer); + assert(result == 0x142a6d57007171f6eaa33d55976d9dbe739c889c8e920f115f7808dea184c718); +} + +#[test] +fn compute_var_args_hash() { + let mut input = [0; 800]; + for i in 0..800 { + input[i] = i as Field; + } + let hash = hash_args(input); + assert(hash == 0x371960dd84ed3445ab099ac4c1af5ba90e0c713b593e0ca52ee532087c7f097); +} + +#[test] +fn compute_l2_l1_hash() { + // All zeroes + let hash_result = compute_l2_to_l1_hash(AztecAddress::from_field(0), 0, 0, L2ToL1Message::empty()); + assert(hash_result == 0x2266ac2f9f0c19c015239ef5ea85862fc6fac00db73779b220a4d49c4856c2e1); + + // Non-zero case + let message = L2ToL1Message { recipient: EthAddress::from_field(3), content: 5 }; + let hash_result = compute_l2_to_l1_hash(AztecAddress::from_field(1), 2, 4, message); + assert(hash_result == 0x0f24729168d4450a5681beafa5e3a899ac28bd17bf5a4877dab37bcd834e1634); +} diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/interop_testing.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/interop_testing.nr deleted file mode 100644 index b8595b67b97..00000000000 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/interop_testing.nr +++ /dev/null @@ -1,152 +0,0 @@ -use crate::grumpkin_point::GrumpkinPoint; -use crate::transaction::request::TxRequest; -use crate::address::{AztecAddress, EthAddress, PartialAddress, PublicKeysHash}; -use crate::transaction::context::TxContext; -use crate::abis::function_data::FunctionData; -use crate::abis::function_leaf_preimage::FunctionLeafPreimage; -use crate::contrakt::deployment_data::ContractDeploymentData; -use crate::abis::function_selector::FunctionSelector; -use crate::hash::{compute_l2_to_l1_hash, sha256_to_field, hash_args}; -use crate::abis::public_call_stack_item::PublicCallStackItem; -use crate::abis::public_circuit_public_inputs::PublicCircuitPublicInputs; -use crate::abis::side_effect::SideEffect; -use crate::contract_class::ContractClassId; -use crate::messaging::l2_to_l1_message::L2ToL1Message; - -#[test] -fn compute_address() { - let point = GrumpkinPoint { x: 1, y: 2 }; - let contract_address_salt = 3; - let contract_class_id = ContractClassId::from_field(4); - let initialization_hash = 5; - let portal_contract_address = EthAddress::from_field(6); - - let address = AztecAddress::compute_from_public_key( - point, - contract_class_id, - contract_address_salt, - initialization_hash, - portal_contract_address - ); - - assert(address.to_field() == 0x2fd71a4f0742364f194dd16d0ae32d2f47845ddc7f5d328f37d4148b565c4123); -} - -#[test] -fn compute_public_keys_hash() { - let point = GrumpkinPoint { x: 1, y: 2 }; - let actual = PublicKeysHash::compute(point); - assert(actual.to_field() == 0x1923a6246e305720b6aaf751fde0342613e93c82e455c3831e28375c16dd40d8); -} - -#[test] -fn compute_address_from_partial_and_pubkey() { - let point = GrumpkinPoint { x: 1, y: 2 }; - let partial_address = PartialAddress::from_field(3); - - let address = AztecAddress::compute(PublicKeysHash::compute(point), partial_address); - assert(address.to_field() == 0x0447f893197175723deb223696e2e96dbba1e707ee8507766373558877e74197); -} - -#[test] -fn compute_var_args_hash() { - let mut input = [0; 800]; - for i in 0..800 { - input[i] = i as Field; - } - let hash = hash_args(input); - assert(hash == 1557627899280963684159398665725097926236612957540256425197580046184563077271); -} - -#[test] -fn compute_tx_request_hash() { - let tx_request = TxRequest { - origin: AztecAddress::from_field(1), - args_hash: 3, - tx_context: TxContext { - is_fee_payment_tx: false, - is_rebate_payment_tx: false, - is_contract_deployment_tx: true, - contract_deployment_data: ContractDeploymentData { - public_key: GrumpkinPoint { x: 1, y: 2 }, - initialization_hash: 1, - contract_class_id: ContractClassId::from_field(2), - contract_address_salt: 3, - portal_contract_address: EthAddress::from_field(1) - }, - chain_id: 0, - version: 0 - }, - function_data: FunctionData { selector: FunctionSelector::from_u32(2), is_internal: false, is_private: true, is_constructor: true } - }; - assert(tx_request.hash() == 0x0b487ff2900ae1178e131bfe333fdbc351beef658f7c0d62db2801429b1aab75); -} - -#[test] -fn compute_l2_l1_hash() { - // All zeroes - let hash_result = compute_l2_to_l1_hash(AztecAddress::from_field(0), 0, 0, L2ToL1Message::empty()); - assert(hash_result == 0x2266ac2f9f0c19c015239ef5ea85862fc6fac00db73779b220a4d49c4856c2e1); - - // Non-zero case - let message = L2ToL1Message { recipient: EthAddress::from_field(3), content: 5 }; - let hash_result = compute_l2_to_l1_hash(AztecAddress::from_field(1), 2, 4, message); - assert(hash_result == 0x0f24729168d4450a5681beafa5e3a899ac28bd17bf5a4877dab37bcd834e1634); -} - -#[test] -fn smoke_sha256_to_field() { - let full_buffer = [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159 - ]; - let result = sha256_to_field(full_buffer); - assert(result == 0x142a6d57007171f6eaa33d55976d9dbe739c889c8e920f115f7808dea184c718); -} - -#[test] -fn compute_function_leaf() { - let leaf = FunctionLeafPreimage { selector: FunctionSelector::from_u32(27), is_internal: false, is_private: true, vk_hash: 1, acir_hash: 2 }; - - assert_eq(leaf.hash(), 0x1ad8ece7f40e63d011ae47c6ce6cdaf31d632a23f5cf35bbeaaf69c8302afdbc); -} - -#[test] -fn compute_call_stack_item_request_hash() { - let contract_address = AztecAddress::from_field(1); - let function_data = FunctionData { selector: FunctionSelector::from_u32(2), is_internal: false, is_private: false, is_constructor: false }; - - let mut public_inputs: PublicCircuitPublicInputs = dep::std::unsafe::zeroed(); - public_inputs.new_commitments[0] = SideEffect{ - value: 1, - counter: 0, - }; - - let call_stack_item = PublicCallStackItem { contract_address, public_inputs, is_execution_request: true, function_data }; - - // Value from abis.test.ts "Computes a callstack item request hash" test - assert_eq(call_stack_item.hash(), 0x02550e7f875c3b6b7383292518af5aa7d04bfb40d21523780c73715456cc6d69); -} - -#[test] -fn compute_call_stack_item_hash() { - let contract_address = AztecAddress::from_field(1); - let function_data = FunctionData { selector: FunctionSelector::from_u32(2), is_internal: false, is_private: false, is_constructor: false }; - - let mut public_inputs: PublicCircuitPublicInputs = dep::std::unsafe::zeroed(); - public_inputs.new_commitments[0] = SideEffect{ - value: 1, - counter: 0, - }; - - let call_stack_item = PublicCallStackItem { contract_address, public_inputs, is_execution_request: false, function_data }; - - // Value from abis.test.ts "Computes a callstack item hash" test - assert_eq(call_stack_item.hash(), 0x2ba20f300313892a4349ee58faa9ede9154d45a162ad4da51490aea278a83fe4); -} diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/lib.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/lib.nr index f4a23fa20ba..ea426fd768e 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/lib.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/lib.nr @@ -20,8 +20,6 @@ mod type_serialization; mod content_commitment; mod header; -mod interop_testing; - mod tests; mod state_reference; diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/kernel_data_builder.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/kernel_data_builder.nr index 7e8398a0e06..d99c83ba9d4 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/kernel_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/kernel_data_builder.nr @@ -13,7 +13,7 @@ use crate::{ }, address::{AztecAddress, EthAddress}, header::Header, mocked::{AggregationObject, Proof, VerificationKey}, - tests::{fixtures, testing_harness::build_tx_context}, transaction::context::TxContext + tests::{fixtures, testing_harness::build_tx_context}, transaction::tx_context::TxContext }; use crate::constants::{ MAX_NEW_COMMITMENTS_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_PUBLIC_DATA_READS_PER_TX, diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/private_call_data_builder.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/private_call_data_builder.nr index 6af5745507a..31bf4bab027 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/private_call_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/private_call_data_builder.nr @@ -12,7 +12,7 @@ use crate::{ fixtures, private_circuit_public_inputs_builder::PrivateCircuitPublicInputsBuilder, testing_harness::build_tx_context }, - transaction::{request::TxRequest} + transaction::{tx_request::TxRequest} }; use crate::constants::{ MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/private_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/private_circuit_public_inputs_builder.nr index ee2d57de8fe..ef6bc0fb58a 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/private_circuit_public_inputs_builder.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/private_circuit_public_inputs_builder.nr @@ -5,8 +5,9 @@ use crate::{ side_effect::{SideEffect, SideEffectLinkedToNoteHash} }, address::{AztecAddress, compute_initialization_hash}, - contrakt::deployment_data::ContractDeploymentData, hash::{compute_constructor_hash, hash_args}, - header::Header, messaging::l2_to_l1_message::L2ToL1Message, + contrakt::contract_deployment_data::ContractDeploymentData, + hash::{compute_constructor_hash, hash_args}, header::Header, + messaging::l2_to_l1_message::L2ToL1Message, tests::{fixtures, testing_harness::build_contract_deployment_data} }; use crate::constants::{ diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/testing_harness.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/testing_harness.nr index 84d6e5b8c43..08afb981fba 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/testing_harness.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/testing_harness.nr @@ -1,6 +1,6 @@ use crate::{ - contrakt::deployment_data::ContractDeploymentData, tests::fixtures, transaction::context::TxContext, - address::compute_initialization_hash + contrakt::contract_deployment_data::ContractDeploymentData, tests::fixtures, + transaction::tx_context::TxContext, address::compute_initialization_hash }; pub fn build_contract_deployment_data(is_constructor: bool, args_hash: Field) -> ContractDeploymentData { diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/transaction.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/transaction.nr index 4b7dfb73695..023f66746a8 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/transaction.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/transaction.nr @@ -1,2 +1,2 @@ -mod request; -mod context; +mod tx_request; +mod tx_context; diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/transaction/context.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/transaction/context.nr deleted file mode 100644 index d34fe3e885b..00000000000 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/transaction/context.nr +++ /dev/null @@ -1,27 +0,0 @@ -use crate::constants::GENERATOR_INDEX__TX_CONTEXT; -use crate::contrakt::deployment_data::ContractDeploymentData; -use crate::traits::Hash; - -struct TxContext { - is_fee_payment_tx : bool, - is_rebate_payment_tx : bool, - is_contract_deployment_tx : bool, - - contract_deployment_data : ContractDeploymentData, - - chain_id : Field, - version : Field, -} - -impl Hash for TxContext { - fn hash(self) -> Field { - dep::std::hash::pedersen_hash_with_separator([ - self.is_fee_payment_tx as Field, - self.is_rebate_payment_tx as Field, - self.is_contract_deployment_tx as Field, - self.contract_deployment_data.hash(), - self.chain_id, - self.version, - ], GENERATOR_INDEX__TX_CONTEXT) - } -} diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/transaction/request.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/transaction/request.nr deleted file mode 100644 index 88d1a820143..00000000000 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/transaction/request.nr +++ /dev/null @@ -1,23 +0,0 @@ -use crate::constants::GENERATOR_INDEX__TX_REQUEST; -use crate::address::AztecAddress; -use crate::transaction::context::TxContext; -use crate::abis::function_data::FunctionData; -use crate::traits::Hash; - -struct TxRequest { - origin : AztecAddress, - args_hash : Field, - tx_context : TxContext, - function_data : FunctionData -} - -impl Hash for TxRequest { - fn hash(self) -> Field { - dep::std::hash::pedersen_hash_with_separator([ - self.origin.to_field(), - self.function_data.hash(), - self.args_hash, - self.tx_context.hash(), - ], GENERATOR_INDEX__TX_REQUEST) - } -} diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/transaction/tx_context.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/transaction/tx_context.nr new file mode 100644 index 00000000000..7ab20bc125b --- /dev/null +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/transaction/tx_context.nr @@ -0,0 +1,87 @@ +use crate::{ + constants::{GENERATOR_INDEX__TX_CONTEXT, TX_CONTEXT_DATA_LENGTH}, + contrakt::contract_deployment_data::ContractDeploymentData, hash::pedersen_hash, + traits::{Deserialize, Hash, Serialize}, utils::reader::Reader +}; + +struct TxContext { + is_fee_payment_tx : bool, + is_rebate_payment_tx : bool, + is_contract_deployment_tx : bool, + + contract_deployment_data : ContractDeploymentData, + + chain_id : Field, + version : Field, +} + +impl Eq for TxContext { + fn eq(self, other: Self) -> bool { + (self.is_fee_payment_tx == other.is_fee_payment_tx) & + (self.is_rebate_payment_tx == other.is_rebate_payment_tx) & + (self.is_contract_deployment_tx == other.is_contract_deployment_tx) & + self.contract_deployment_data.eq(other.contract_deployment_data) & + (self.chain_id == other.chain_id) & + (self.version == other.version) + } +} + +impl Serialize for TxContext { + fn serialize(self) -> [Field; TX_CONTEXT_DATA_LENGTH] { + let mut fields: BoundedVec = BoundedVec::new(0); + + fields.push(self.is_fee_payment_tx as Field); + fields.push(self.is_rebate_payment_tx as Field); + fields.push(self.is_contract_deployment_tx as Field); + fields.extend_from_array(self.contract_deployment_data.serialize()); + fields.push(self.chain_id); + fields.push(self.version); + + assert_eq(fields.len(), TX_CONTEXT_DATA_LENGTH); + + fields.storage + } +} + +impl Deserialize for TxContext { + fn deserialize(serialized: [Field; TX_CONTEXT_DATA_LENGTH]) -> Self { + // TODO(#4390): This should accept a reader ^ to avoid copying data. + let mut reader = Reader::new(serialized); + + let context = Self { + is_fee_payment_tx: reader.read() as bool, + is_rebate_payment_tx: reader.read() as bool, + is_contract_deployment_tx: reader.read() as bool, + contract_deployment_data: reader.read_struct(ContractDeploymentData::deserialize), + chain_id: reader.read(), + version: reader.read(), + }; + + reader.finish(); + context + } +} + +impl Hash for TxContext { + fn hash(self) -> Field { + pedersen_hash(self.serialize(), GENERATOR_INDEX__TX_CONTEXT) + } +} + +#[test] +fn serialization_of_empty() { + let context: TxContext = dep::std::unsafe::zeroed(); + let serialized = context.serialize(); + let deserialized = TxContext::deserialize(serialized); + assert(context.eq(deserialized)); +} + +// TODO(#4619): Hash non-empty +#[test] +fn empty_hash() { + let inputs: TxContext = dep::std::unsafe::zeroed(); + let hash = inputs.hash(); + + // Value from contract_deployment_data.test.ts "computes empty item hash" test + assert_eq(hash, 0x2e7ff14389eef3dc51597529149e01b49cb33829f7089438c8c145c8f352c17b); +} diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/transaction/tx_request.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/transaction/tx_request.nr new file mode 100644 index 00000000000..25b1913cdee --- /dev/null +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/transaction/tx_request.nr @@ -0,0 +1,102 @@ +use crate::{ + address::AztecAddress, abis::function_data::FunctionData, + constants::{GENERATOR_INDEX__TX_REQUEST, TX_REQUEST_LENGTH}, hash::pedersen_hash, + traits::{Hash, Serialize, Deserialize}, transaction::tx_context::TxContext, utils::reader::Reader +}; + +struct TxRequest { + origin: AztecAddress, + args_hash: Field, + tx_context: TxContext, + function_data: FunctionData, +} + +impl Eq for TxRequest { + fn eq(self, other: Self) -> bool { + (self.origin == other.origin) & + (self.args_hash == other.args_hash) & + (self.tx_context == other.tx_context) & + (self.function_data == other.function_data) + } +} + +impl Hash for TxRequest { + fn hash(self) -> Field { + pedersen_hash(self.serialize(), GENERATOR_INDEX__TX_REQUEST) + } +} + +impl Serialize for TxRequest { + fn serialize(self) -> [Field; TX_REQUEST_LENGTH] { + // TODO(#4390): This should accept a reader ^ to avoid copying data. + let mut fields: BoundedVec = BoundedVec::new(0); + + fields.push(self.origin.to_field()); + fields.extend_from_array(self.function_data.serialize()); + fields.push(self.args_hash); + fields.extend_from_array(self.tx_context.serialize()); + + assert_eq(fields.len(), TX_REQUEST_LENGTH); + + fields.storage + } +} + +impl Deserialize for TxRequest { + fn deserialize(serialized: [Field; TX_REQUEST_LENGTH]) -> Self { + let mut reader = Reader::new(serialized); + + let request = Self { + origin: reader.read_struct(AztecAddress::deserialize), + args_hash: reader.read(), + tx_context: reader.read_struct(TxContext::deserialize), + function_data: reader.read_struct(FunctionData::deserialize), + }; + + reader.finish(); + request + } +} + +mod tests { + use crate::{ + abis::{function_selector::FunctionSelector, function_data::FunctionData}, + address::{AztecAddress, EthAddress}, contract_class::ContractClassId, + contrakt::contract_deployment_data::ContractDeploymentData, grumpkin_point::GrumpkinPoint, + transaction::{tx_request::TxRequest, tx_context::TxContext} + }; + + #[test] + fn serialization_of_empty() { + // Assuming a zeroed initialization for simplicity + let request: TxRequest = dep::std::unsafe::zeroed(); + let serialized = request.serialize(); + let deserialized = TxRequest::deserialize(serialized); + assert(request.eq(deserialized)); + } + + #[test] + fn compute_hash() { + let tx_request = TxRequest { + origin: AztecAddress::from_field(1), + args_hash: 3, + tx_context: TxContext { + is_fee_payment_tx: false, + is_rebate_payment_tx: false, + is_contract_deployment_tx: true, + contract_deployment_data: ContractDeploymentData { + public_key: GrumpkinPoint { x: 1, y: 2 }, + initialization_hash: 1, + contract_class_id: ContractClassId::from_field(2), + contract_address_salt: 3, + portal_contract_address: EthAddress::from_field(1) + }, + chain_id: 0, + version: 0 + }, + function_data: FunctionData { selector: FunctionSelector::from_u32(2), is_internal: false, is_private: true, is_constructor: true } + }; + // Value from tx_request.test.ts "compute hash" test + assert(tx_request.hash() == 0x05e3f67a5e787faf63c85c28169a9d616b594c9799d9785b4f167d9cd7a71e9e); + } +} diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/type_serialization.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/type_serialization.nr index 7bc12f02d27..e817c228c7e 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/type_serialization.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/type_serialization.nr @@ -4,8 +4,6 @@ global BOOL_SERIALIZED_LEN: Field = 1; global U32_SERIALIZED_LEN: Field = 1; global U8_SERIALIZED_LEN: Field = 1; global FIELD_SERIALIZED_LEN: Field = 1; -global AZTEC_ADDRESS_SERIALIZED_LEN = 1; -global ETH_ADDRESS_SERIALIZED_LEN = 1; impl Serialize for u32 { fn serialize(self) -> [Field; U32_SERIALIZED_LEN] { diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index 8e42de8e586..6ab4ac34535 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -36,7 +36,7 @@ import { PUBLIC_DATA_TREE_HEIGHT, PublicDataTreeLeafPreimage, } from '@aztec/circuits.js'; -import { computePublicDataTreeLeafSlot } from '@aztec/circuits.js/abis'; +import { computePublicDataTreeLeafSlot } from '@aztec/circuits.js/hash'; import { L1ContractAddresses, createEthereumChain } from '@aztec/ethereum'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { createDebugLogger } from '@aztec/foundation/log'; diff --git a/yarn-project/aztec.js/src/index.ts b/yarn-project/aztec.js/src/index.ts index 855e5f96802..c4b950f624d 100644 --- a/yarn-project/aztec.js/src/index.ts +++ b/yarn-project/aztec.js/src/index.ts @@ -37,7 +37,6 @@ export { generatePublicKey, FieldLike, EthAddressLike, - computeMessageSecretHash, CheatCodes, AztecAddressLike, FunctionSelectorLike, @@ -72,6 +71,8 @@ export { getContractClassFromArtifact, } from '@aztec/circuits.js'; +export { computeMessageSecretHash } from '@aztec/circuits.js/hash'; + export { Grumpkin, Schnorr } from '@aztec/circuits.js/barretenberg'; export { diff --git a/yarn-project/aztec.js/src/utils/index.ts b/yarn-project/aztec.js/src/utils/index.ts index 5be623ef38d..9c612306fda 100644 --- a/yarn-project/aztec.js/src/utils/index.ts +++ b/yarn-project/aztec.js/src/utils/index.ts @@ -1,4 +1,3 @@ -export * from './secrets.js'; export * from './pub_key.js'; export * from './l1_contracts.js'; export * from './l2_contracts.js'; diff --git a/yarn-project/aztec.js/src/utils/secrets.ts b/yarn-project/aztec.js/src/utils/secrets.ts deleted file mode 100644 index ac642c15916..00000000000 --- a/yarn-project/aztec.js/src/utils/secrets.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Fr } from '@aztec/circuits.js'; -import { computeSecretMessageHash } from '@aztec/circuits.js/abis'; - -/** - * Given a secret, it computes its pedersen hash - used to send l1 to l2 messages - * @param secret - the secret to hash - secret could be generated however you want e.g. `Fr.random()` - * @returns the hash - */ -export function computeMessageSecretHash(secret: Fr) { - return computeSecretMessageHash(secret); -} diff --git a/yarn-project/circuit-types/src/packed_arguments.ts b/yarn-project/circuit-types/src/packed_arguments.ts index aa327d2d516..d5589a77ad1 100644 --- a/yarn-project/circuit-types/src/packed_arguments.ts +++ b/yarn-project/circuit-types/src/packed_arguments.ts @@ -1,5 +1,5 @@ import { Fr, Vector } from '@aztec/circuits.js'; -import { computeVarArgsHash } from '@aztec/circuits.js/abis'; +import { computeVarArgsHash } from '@aztec/circuits.js/hash'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { FieldsOf } from '@aztec/foundation/types'; diff --git a/yarn-project/circuit-types/src/sibling_path/index.ts b/yarn-project/circuit-types/src/sibling_path/index.ts index f691de90659..006b943d750 100644 --- a/yarn-project/circuit-types/src/sibling_path/index.ts +++ b/yarn-project/circuit-types/src/sibling_path/index.ts @@ -1 +1 @@ -export * from './sibling-path.js'; +export * from './sibling_path.js'; diff --git a/yarn-project/circuit-types/src/sibling_path/sibling-path.ts b/yarn-project/circuit-types/src/sibling_path/sibling_path.ts similarity index 100% rename from yarn-project/circuit-types/src/sibling_path/sibling-path.ts rename to yarn-project/circuit-types/src/sibling_path/sibling_path.ts diff --git a/yarn-project/circuits.js/package.json b/yarn-project/circuits.js/package.json index 458fc20b0ff..715e844ad06 100644 --- a/yarn-project/circuits.js/package.json +++ b/yarn-project/circuits.js/package.json @@ -4,7 +4,7 @@ "type": "module", "exports": { ".": "./dest/index.js", - "./abis": "./dest/abis/index.js", + "./hash": "./dest/hash/index.js", "./barretenberg": "./dest/barretenberg/index.js", "./factories": "./dest/tests/factories.js", "./utils": "./dest/utils/index.js", diff --git a/yarn-project/circuits.js/src/abis/index.ts b/yarn-project/circuits.js/src/abis/index.ts deleted file mode 100644 index 9c432c09e53..00000000000 --- a/yarn-project/circuits.js/src/abis/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './abis.js'; diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index ed820e0fdfd..efcc47de6c1 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -63,26 +63,34 @@ export const REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE = 0xe7af816635466f128568edb04c9fa024f6c87fb9010fdbffa68b3d99n; export const DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE = 0x85864497636cf755ae7bde03f267ce01a520981c21c3682aaf82a631n; -export const L1_TO_L2_MESSAGE_LENGTH = 8; -export const L2_TO_L1_MESSAGE_LENGTH = 2; export const L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH = 25; export const MAX_NOTE_FIELDS_LENGTH = 20; export const GET_NOTE_ORACLE_RETURN_LENGTH = 23; export const MAX_NOTES_PER_PAGE = 10; export const VIEW_NOTE_ORACLE_RETURN_LENGTH = 212; +export const AZTEC_ADDRESS_LENGTH = 1; export const CALL_CONTEXT_LENGTH = 8; -export const GLOBAL_VARIABLES_LENGTH = 6; -export const PARTIAL_STATE_REFERENCE_LENGTH = 8; -export const STATE_REFERENCE_LENGTH = 10; export const CONTENT_COMMITMENT_LENGTH = 7; -export const HEADER_LENGTH = 25; -export const FUNCTION_DATA_LENGTH = 4; export const CONTRACT_DEPLOYMENT_DATA_LENGTH = 6; -export const PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 214; +export const CONTRACT_STORAGE_READ_LENGTH = 2; +export const CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH = 2; +export const ETH_ADDRESS_LENGTH = 1; +export const FUNCTION_DATA_LENGTH = 4; +export const FUNCTION_LEAF_PREIMAGE_LENGTH = 5; +export const GLOBAL_VARIABLES_LENGTH = 6; +export const HEADER_LENGTH = 25; +export const L1_TO_L2_MESSAGE_LENGTH = 8; +export const L2_TO_L1_MESSAGE_LENGTH = 2; +export const NEW_CONTRACT_DATA_LENGTH = 3; +export const NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH = 4; +export const NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_LENGTH = 5; +export const PARTIAL_STATE_REFERENCE_LENGTH = 8; export const PRIVATE_CALL_STACK_ITEM_LENGTH = 219; +export const PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 214; export const PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = 194; -export const CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH = 2; -export const CONTRACT_STORAGE_READ_LENGTH = 2; +export const STATE_REFERENCE_LENGTH = 10; +export const TX_CONTEXT_DATA_LENGTH = 11; +export const TX_REQUEST_LENGTH = 17; export const GET_NOTES_ORACLE_RETURN_LENGTH = 674; export const COMMITMENTS_NUM_BYTES_PER_BASE_ROLLUP = 2048; export const NULLIFIERS_NUM_BYTES_PER_BASE_ROLLUP = 2048; diff --git a/yarn-project/circuits.js/src/contract/__snapshots__/contract_address.test.ts.snap b/yarn-project/circuits.js/src/contract/__snapshots__/contract_address.test.ts.snap index 122042ba049..4b5fae56077 100644 --- a/yarn-project/circuits.js/src/contract/__snapshots__/contract_address.test.ts.snap +++ b/yarn-project/circuits.js/src/contract/__snapshots__/contract_address.test.ts.snap @@ -1,90 +1,10 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`ContractAddress computeContractAddressFromInstance 1`] = ` -AztecAddress { - "asBigInt": 3883883889294466972222695990544651254433869677543312058555575694285817356088n, - "asBuffer": { - "data": [ - 8, - 150, - 51, - 76, - 27, - 117, - 237, - 233, - 137, - 38, - 191, - 74, - 188, - 215, - 31, - 48, - 171, - 201, - 98, - 17, - 7, - 12, - 250, - 148, - 232, - 140, - 94, - 129, - 3, - 105, - 159, - 56, - ], - "type": "Buffer", - }, -} -`; +exports[`ContractAddress Address from partial matches Noir 1`] = `"0x0447f893197175723deb223696e2e96dbba1e707ee8507766373558877e74197"`; -exports[`ContractAddress computeContractAddressFromPartial 1`] = ` -AztecAddress { - "asBigInt": 21497883470428896497848272622467250633298383505675808099366629400564707993275n, - "asBuffer": { - "data": [ - 47, - 135, - 94, - 239, - 243, - 232, - 72, - 120, - 213, - 116, - 228, - 154, - 136, - 109, - 14, - 128, - 44, - 244, - 1, - 8, - 118, - 28, - 224, - 83, - 57, - 99, - 133, - 163, - 33, - 177, - 166, - 187, - ], - "type": "Buffer", - }, -} -`; +exports[`ContractAddress Public key hash matches Noir 1`] = `"0x1923a6246e305720b6aaf751fde0342613e93c82e455c3831e28375c16dd40d8"`; + +exports[`ContractAddress computeContractAddressFromInstance 1`] = `"0x2fd71a4f0742364f194dd16d0ae32d2f47845ddc7f5d328f37d4148b565c4123"`; exports[`ContractAddress computeInitializationHash 1`] = ` Fr { @@ -172,49 +92,6 @@ Fr { } `; -exports[`ContractAddress computePublicKeysHash 1`] = ` -Fr { - "asBigInt": 11370807533904788559065519582196668367978392224620203970943957018221100220632n, - "asBuffer": { - "data": [ - 25, - 35, - 166, - 36, - 110, - 48, - 87, - 32, - 182, - 170, - 247, - 81, - 253, - 224, - 52, - 38, - 19, - 233, - 60, - 130, - 228, - 85, - 195, - 131, - 30, - 40, - 55, - 92, - 22, - 221, - 64, - 216, - ], - "type": "Buffer", - }, -} -`; - exports[`ContractAddress computeSaltedInitializationHash 1`] = ` Fr { "asBigInt": 11725758444245911667025964940014811412794639055001970719147766917493953867026n, diff --git a/yarn-project/circuits.js/src/contract/contract_address.test.ts b/yarn-project/circuits.js/src/contract/contract_address.test.ts index 02f3a488d7c..c32dab63f59 100644 --- a/yarn-project/circuits.js/src/contract/contract_address.test.ts +++ b/yarn-project/circuits.js/src/contract/contract_address.test.ts @@ -1,8 +1,7 @@ import { ABIParameterVisibility, FunctionAbi, FunctionType } from '@aztec/foundation/abi'; import { Fr, Point } from '@aztec/foundation/fields'; -import { ContractInstance } from '@aztec/types/contracts'; -import { EthAddress, PublicKey } from '../index.js'; +import { EthAddress } from '../index.js'; import { computeContractAddressFromInstance, computeContractAddressFromPartial, @@ -13,19 +12,6 @@ import { } from './contract_address.js'; describe('ContractAddress', () => { - it('computeContractAddressFromInstance', () => { - const mockInstance: ContractInstance = { - version: 1, - contractClassId: new Fr(1), - initializationHash: new Fr(2), - portalContractAddress: EthAddress.fromField(new Fr(3)), - publicKeysHash: new Fr(4), - salt: new Fr(5), - }; - const result = computeContractAddressFromInstance(mockInstance); - expect(result).toMatchSnapshot(); - }); - it('computePartialAddress', () => { const mockInstance = { contractClassId: new Fr(1), @@ -45,21 +31,6 @@ describe('ContractAddress', () => { expect(result).toMatchSnapshot(); }); - it('computeContractAddressFromPartial', () => { - const mockArgs = { - publicKeyHash: new Fr(1), - partialAddress: new Fr(2), - }; - const result = computeContractAddressFromPartial(mockArgs); - expect(result).toMatchSnapshot(); - }); - - it('computePublicKeysHash', () => { - const mockPublicKey: PublicKey = new Point(new Fr(1), new Fr(2)); - const result = computePublicKeysHash(mockPublicKey); - expect(result).toMatchSnapshot(); - }); - it('computeInitializationHash', () => { const mockInitFn: FunctionAbi = { functionType: FunctionType.SECRET, @@ -72,4 +43,45 @@ describe('ContractAddress', () => { const result = computeInitializationHash(mockInitFn, mockArgs); expect(result).toMatchSnapshot(); }); + + it('computeContractAddressFromInstance', () => { + const publicKey = new Point(new Fr(1n), new Fr(2n)); + const salt = new Fr(3n); + const contractClassId = new Fr(4n); + const initializationHash = new Fr(5n); + const portalContractAddress = EthAddress.fromField(new Fr(6n)); + + const address = computeContractAddressFromInstance({ + publicKeysHash: computePublicKeysHash(publicKey), + salt, + contractClassId, + initializationHash, + portalContractAddress, + version: 1, + }).toString(); + + expect(address).toMatchSnapshot(); + + // Value used in "compute_address" test in aztec_address.nr + // console.log("address", address); + }); + + it('Public key hash matches Noir', () => { + const publicKey = new Point(new Fr(1n), new Fr(2n)); + const hash = computePublicKeysHash(publicKey).toString(); + expect(hash).toMatchSnapshot(); + + // Value used in "compute_public_keys_hash" test in public_keys_hash.nr + // console.log("hash", hash); + }); + + it('Address from partial matches Noir', () => { + const publicKey = new Point(new Fr(1n), new Fr(2n)); + const partialAddress = new Fr(3n); + const address = computeContractAddressFromPartial({ publicKey, partialAddress }).toString(); + expect(address).toMatchSnapshot(); + + // Value used in "compute_address_from_partial_and_pubkey" test in aztec_address.nr + // console.log("address", address); + }); }); diff --git a/yarn-project/circuits.js/src/contract/contract_address.ts b/yarn-project/circuits.js/src/contract/contract_address.ts index b567aafc5c8..e9636e6de39 100644 --- a/yarn-project/circuits.js/src/contract/contract_address.ts +++ b/yarn-project/circuits.js/src/contract/contract_address.ts @@ -4,8 +4,8 @@ import { pedersenHash } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; import { ContractInstance } from '@aztec/types/contracts'; -import { computeVarArgsHash } from '../abis/abis.js'; import { GeneratorIndex } from '../constants.gen.js'; +import { computeVarArgsHash } from '../hash/hash.js'; import { PublicKey } from '../types/public_key.js'; // TODO(@spalladino): Review all generator indices in this file diff --git a/yarn-project/circuits.js/src/contract/contract_tree/contract_tree.ts b/yarn-project/circuits.js/src/contract/contract_tree/contract_tree.ts index 2f9c9a7a8b4..a35782a6fd9 100644 --- a/yarn-project/circuits.js/src/contract/contract_tree/contract_tree.ts +++ b/yarn-project/circuits.js/src/contract/contract_tree/contract_tree.ts @@ -1,7 +1,8 @@ import { ContractFunctionDao, Fr, FunctionData, FunctionLeafPreimage } from '@aztec/circuits.js'; -import { computeFunctionLeaf, hashVK } from '@aztec/circuits.js/abis'; import { FunctionSelector, FunctionType } from '@aztec/foundation/abi'; +import { hashVK } from '../../hash/hash.js'; + /** * Computes the hash of a hex-encoded string representation of a verification key (vk). * The input 'vk' should be a hexadecimal string, and the resulting hash is computed using 'hashVK' function. @@ -86,7 +87,7 @@ export function generateFunctionLeaves(functions: ContractFunctionDao[]) { Fr.fromBuffer(vkHash), Fr.fromBuffer(acirHash), ); - const fnLeaf = computeFunctionLeaf(fnLeafPreimage); + const fnLeaf = fnLeafPreimage.hash(); result.push(fnLeaf); } return result; diff --git a/yarn-project/circuits.js/src/abis/__snapshots__/abis.test.ts.snap b/yarn-project/circuits.js/src/hash/__snapshots__/hash.test.ts.snap similarity index 62% rename from yarn-project/circuits.js/src/abis/__snapshots__/abis.test.ts.snap rename to yarn-project/circuits.js/src/hash/__snapshots__/hash.test.ts.snap index 6b9fd662217..d30610199d3 100644 --- a/yarn-project/circuits.js/src/abis/__snapshots__/abis.test.ts.snap +++ b/yarn-project/circuits.js/src/hash/__snapshots__/hash.test.ts.snap @@ -1,57 +1,53 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`abis Computes a callstack item hash 1`] = `"0x1f71c0d6bd03e409df694549b6aa83d706cfe55427152e6ec443ec64fa62d3a0"`; +exports[`hash Computes an empty nullifier hash 1`] = `"0x066e6cdc4a6ba5e4781deda650b0be6c12f975f064fc38df72c1060716759b17"`; -exports[`abis Computes a callstack item request hash 1`] = `"0x2812dfeffdb7553fbbdd27c03fbdf61e3aa9bab3209db39f78838508ad892803"`; +exports[`hash Computes an empty sideeffect hash 1`] = `"0x27b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed"`; -exports[`abis Computes an empty nullifier hash 1`] = `"0x066e6cdc4a6ba5e4781deda650b0be6c12f975f064fc38df72c1060716759b17"`; - -exports[`abis Computes an empty sideeffect hash 1`] = `"0x27b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed"`; - -exports[`abis compute public call stack item hash 1`] = ` +exports[`hash Var args hash matches noir 1`] = ` Fr { - "asBigInt": 3788195771499507733306466132608199294191940083079612913177087023829747913637n, + "asBigInt": 1557627899280963684159398665725097926236612957540256425197580046184563077271n, "asBuffer": { "data": [ - 8, - 96, - 10, - 246, - 142, - 121, + 3, 113, - 30, - 158, - 45, - 35, - 114, - 228, - 214, - 105, - 72, - 47, - 39, + 150, + 13, + 216, + 78, + 211, + 68, + 90, + 176, + 153, + 172, 76, - 24, - 152, - 148, - 96, - 11, - 252, - 50, - 99, - 23, - 59, - 226, + 26, + 245, + 186, + 144, + 224, + 199, + 19, + 181, + 147, + 224, + 202, + 82, + 238, 83, - 165, + 32, + 135, + 199, + 240, + 151, ], "type": "Buffer", }, } `; -exports[`abis compute secret message hash 1`] = ` +exports[`hash compute secret message hash 1`] = ` Fr { "asBigInt": 6220068662483113241527007349428551778669520744131373768997518428761948042030n, "asBuffer": { @@ -94,105 +90,7 @@ Fr { } `; -exports[`abis compute tx hash 1`] = ` -Fr { - "asBigInt": 11028384086470399424960241201065432836500251313078792361310973684322431200173n, - "asBuffer": { - "data": [ - 24, - 97, - 216, - 28, - 219, - 86, - 198, - 156, - 231, - 143, - 46, - 78, - 221, - 7, - 18, - 240, - 152, - 126, - 198, - 240, - 27, - 12, - 209, - 163, - 188, - 112, - 63, - 126, - 44, - 152, - 235, - 173, - ], - "type": "Buffer", - }, -} -`; - -exports[`abis computes a function leaf 1`] = ` -Fr { - "asBigInt": 8957681167943973616438847631514238173699549883609341685749385526208761312950n, - "asBuffer": { - "data": [ - 19, - 205, - 222, - 44, - 215, - 32, - 246, - 85, - 182, - 194, - 113, - 211, - 193, - 23, - 61, - 121, - 173, - 10, - 133, - 48, - 24, - 129, - 231, - 172, - 246, - 68, - 18, - 40, - 227, - 134, - 54, - 182, - ], - "type": "Buffer", - }, -} -`; - -exports[`abis computes a function selector 1`] = ` -{ - "data": [ - 169, - 5, - 156, - 187, - ], - "type": "Buffer", -} -`; - -exports[`abis computes commitment nonce 1`] = ` +exports[`hash computes commitment nonce 1`] = ` Fr { "asBigInt": 7653394882992289714855533169019502055399179742531912347686813547951736946253n, "asBuffer": { @@ -235,50 +133,7 @@ Fr { } `; -exports[`abis computes contract leaf 1`] = ` -Fr { - "asBigInt": 16936439505140127403707082829495438425474294111732402569080458144683824428771n, - "asBuffer": { - "data": [ - 37, - 113, - 175, - 95, - 213, - 5, - 72, - 186, - 142, - 170, - 107, - 231, - 135, - 49, - 45, - 131, - 55, - 162, - 222, - 230, - 65, - 158, - 24, - 95, - 238, - 19, - 196, - 149, - 177, - 246, - 182, - 227, - ], - "type": "Buffer", - }, -} -`; - -exports[`abis computes function tree root 1`] = ` +exports[`hash computes function tree root 1`] = ` Fr { "asBigInt": 18902231782334398705464257251364974449663398212058621439366133672872128659209n, "asBuffer": { @@ -321,7 +176,7 @@ Fr { } `; -exports[`abis computes public data tree leaf slot 1`] = ` +exports[`hash computes public data tree leaf slot 1`] = ` Fr { "asBigInt": 9076808949980998475110411569159266589807853958487763065147292518713994520820n, "asBuffer": { @@ -364,7 +219,7 @@ Fr { } `; -exports[`abis computes public data tree value 1`] = ` +exports[`hash computes public data tree value 1`] = ` Fr { "asBigInt": 3n, "asBuffer": { @@ -407,7 +262,7 @@ Fr { } `; -exports[`abis computes siloed commitment 1`] = ` +exports[`hash computes siloed commitment 1`] = ` Fr { "asBigInt": 7262347077404413274044670947879391583109741657896097604752287127491776887739n, "asBuffer": { @@ -450,7 +305,7 @@ Fr { } `; -exports[`abis computes siloed nullifier 1`] = ` +exports[`hash computes siloed nullifier 1`] = ` Fr { "asBigInt": 10521714890263159342521589827909786073566333899903358017581007142888032736115n, "asBuffer": { @@ -493,7 +348,7 @@ Fr { } `; -exports[`abis computes unique commitment 1`] = ` +exports[`hash computes unique commitment 1`] = ` Fr { "asBigInt": 13000121189816960667906065043973697710794195579570622293955220571859166513128n, "asBuffer": { @@ -536,50 +391,7 @@ Fr { } `; -exports[`abis computes zero contract leaf 1`] = ` -Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, -} -`; - -exports[`abis hashes VK 1`] = ` +exports[`hash hashes VK 1`] = ` { "data": [ 4, @@ -619,47 +431,7 @@ exports[`abis hashes VK 1`] = ` } `; -exports[`abis hashes a tx request 1`] = ` -{ - "data": [ - 24, - 97, - 216, - 28, - 219, - 86, - 198, - 156, - 231, - 143, - 46, - 78, - 221, - 7, - 18, - 240, - 152, - 126, - 198, - 240, - 27, - 12, - 209, - 163, - 188, - 112, - 63, - 126, - 44, - 152, - 235, - 173, - ], - "type": "Buffer", -} -`; - -exports[`abis hashes constructor info 1`] = ` +exports[`hash hashes constructor info 1`] = ` Fr { "asBigInt": 8554563246648466207128694080427818093826588702256491720155365584899927973422n, "asBuffer": { @@ -702,7 +474,7 @@ Fr { } `; -exports[`abis hashes empty function args 1`] = ` +exports[`hash hashes empty function args 1`] = ` Fr { "asBigInt": 0n, "asBuffer": { @@ -745,7 +517,7 @@ Fr { } `; -exports[`abis hashes function args 1`] = ` +exports[`hash hashes function args 1`] = ` Fr { "asBigInt": 13773950327711008256617416059663646210697922258755635023101062905870427579114n, "asBuffer": { @@ -788,7 +560,7 @@ Fr { } `; -exports[`abis hashes many function args 1`] = ` +exports[`hash hashes many function args 1`] = ` Fr { "asBigInt": 5019561503322397537490243039227402098195702132635946562396386724242519444026n, "asBuffer": { diff --git a/yarn-project/circuits.js/src/abis/abis.test.ts b/yarn-project/circuits.js/src/hash/hash.test.ts similarity index 52% rename from yarn-project/circuits.js/src/abis/abis.test.ts rename to yarn-project/circuits.js/src/hash/hash.test.ts index 00c3d95aa57..fd85f263473 100644 --- a/yarn-project/circuits.js/src/abis/abis.test.ts +++ b/yarn-project/circuits.js/src/hash/hash.test.ts @@ -1,71 +1,30 @@ import { times } from '@aztec/foundation/collection'; -import { - AztecAddress, - EthAddress, - Fr, - FunctionData, - FunctionLeafPreimage, - FunctionSelector, - NewContractData, - PublicCallStackItem, - SideEffect, - SideEffectLinkedToNoteHash, -} from '../index.js'; -import { - makeAztecAddress, - makeEthAddress, - makePublicCallStackItem, - makeTxRequest, - makeVerificationKey, -} from '../tests/factories.js'; +import { AztecAddress, Fr, FunctionData, FunctionSelector, SideEffect, SideEffectLinkedToNoteHash } from '../index.js'; +import { makeAztecAddress, makeVerificationKey } from '../tests/factories.js'; import { computeCommitmentNonce, computeCommitmentsHash, - computeContractLeaf, - computeFunctionLeaf, - computeFunctionSelector, computeFunctionTreeRoot, + computeMessageSecretHash, computeNullifierHash, - computePublicCallStackItemHash, computePublicDataTreeLeafSlot, computePublicDataTreeValue, - computeSecretMessageHash, - computeTxHash, computeUniqueCommitment, computeVarArgsHash, hashConstructor, - hashTxRequest, hashVK, siloCommitment, siloNullifier, -} from './abis.js'; - -describe('abis', () => { - it('hashes a tx request', () => { - const txRequest = makeTxRequest(); - const hash = hashTxRequest(txRequest); - expect(hash).toMatchSnapshot(); - }); - - it('computes a function selector', () => { - const funcSig = 'transfer(address,uint256)'; - const res = computeFunctionSelector(funcSig); - expect(res).toMatchSnapshot(); - }); +} from './hash.js'; +describe('hash', () => { it('hashes VK', () => { const vk = makeVerificationKey(); const res = hashVK(vk.toBuffer()); expect(res).toMatchSnapshot(); }); - it('computes a function leaf', () => { - const leaf = new FunctionLeafPreimage(new FunctionSelector(7837), false, true, Fr.ZERO, Fr.ZERO); - const res = computeFunctionLeaf(leaf); - expect(res).toMatchSnapshot(); - }); - it('computes function tree root', () => { const res = computeFunctionTreeRoot([new Fr(0n), new Fr(0n), new Fr(0n), new Fr(0n)]); expect(res).toMatchSnapshot(); @@ -137,33 +96,9 @@ describe('abis', () => { expect(res).toMatchSnapshot(); }); - it('computes contract leaf', () => { - const cd = new NewContractData(makeAztecAddress(), makeEthAddress(), new Fr(3n)); - const res = computeContractLeaf(cd); - expect(res).toMatchSnapshot(); - }); - - it('computes zero contract leaf', () => { - const cd = new NewContractData(AztecAddress.ZERO, EthAddress.ZERO, new Fr(0n)); - const res = computeContractLeaf(cd); - expect(res).toMatchSnapshot(); - }); - - it('compute tx hash', () => { - const txRequest = makeTxRequest(); - const hash = computeTxHash(txRequest); - expect(hash).toMatchSnapshot(); - }); - - it('compute public call stack item hash', () => { - const item = makePublicCallStackItem(); - const hash = computePublicCallStackItemHash(item); - expect(hash).toMatchSnapshot(); - }); - it('compute secret message hash', () => { const value = new Fr(8n); - const hash = computeSecretMessageHash(value); + const hash = computeMessageSecretHash(value); expect(hash).toMatchSnapshot(); }); @@ -180,32 +115,12 @@ describe('abis', () => { expect(emptyHash).toMatchSnapshot(); }); - it('Computes a callstack item request hash', () => { - const callStack = PublicCallStackItem.empty(); - - callStack.contractAddress = AztecAddress.fromField(new Fr(1)); - callStack.functionData = new FunctionData(new FunctionSelector(2), false, false, false); - callStack.isExecutionRequest = true; - callStack.publicInputs.newCommitments[0] = new SideEffect(new Fr(1), new Fr(0)); - - const hash = callStack.hash(); - expect(hash.toString()).toMatchSnapshot(); - - // Value used in compute_call_stack_item_hash test in noir circuits - // console.log("hash", hash.toString()); - }); - - it('Computes a callstack item hash', () => { - const callStack = PublicCallStackItem.empty(); - - callStack.contractAddress = AztecAddress.fromField(new Fr(1)); - callStack.functionData = new FunctionData(new FunctionSelector(2), false, false, false); - callStack.publicInputs.newCommitments[0] = new SideEffect(new Fr(1), new Fr(0)); - - const hash = callStack.hash(); - expect(hash.toString()).toMatchSnapshot(); + it('Var args hash matches noir', () => { + const args = times(800, i => new Fr(i)); + const res = computeVarArgsHash(args); + expect(res).toMatchSnapshot(); - // Value used in compute_call_stack_item_request_hash test in noir circuits - // console.log("hash", hash.toString()); + // Value used in "compute_var_args_hash" test in hash.nr + // console.log("hash", hash); }); }); diff --git a/yarn-project/circuits.js/src/abis/abis.ts b/yarn-project/circuits.js/src/hash/hash.ts similarity index 64% rename from yarn-project/circuits.js/src/abis/abis.ts rename to yarn-project/circuits.js/src/hash/hash.ts index 38106b6927a..f3f8964c3c8 100644 --- a/yarn-project/circuits.js/src/abis/abis.ts +++ b/yarn-project/circuits.js/src/hash/hash.ts @@ -1,8 +1,8 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; import { padArrayEnd } from '@aztec/foundation/collection'; -import { keccak, pedersenHash, pedersenHashBuffer } from '@aztec/foundation/crypto'; +import { pedersenHash, pedersenHashBuffer } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; -import { boolToBuffer, numToUInt8, numToUInt16BE, numToUInt32BE } from '@aztec/foundation/serialize'; +import { numToUInt8, numToUInt16BE, numToUInt32BE } from '@aztec/foundation/serialize'; import { Buffer } from 'buffer'; import chunk from 'lodash.chunk'; @@ -10,43 +10,13 @@ import chunk from 'lodash.chunk'; import { ARGS_HASH_CHUNK_COUNT, ARGS_HASH_CHUNK_LENGTH, - FUNCTION_SELECTOR_NUM_BYTES, FUNCTION_TREE_HEIGHT, GeneratorIndex, } from '../constants.gen.js'; import { MerkleTreeCalculator } from '../merkle/merkle_tree_calculator.js'; -import type { - ContractDeploymentData, - FunctionData, - FunctionLeafPreimage, - NewContractData, - PublicCallStackItem, - SideEffect, - SideEffectLinkedToNoteHash, - TxContext, - TxRequest, -} from '../structs/index.js'; -import { PublicCircuitPublicInputs } from '../structs/public_circuit_public_inputs.js'; +import type { FunctionData, SideEffect, SideEffectLinkedToNoteHash } from '../structs/index.js'; import { VerificationKey } from '../structs/verification_key.js'; -/** - * Computes a hash of a transaction request. - * @param txRequest - The transaction request. - * @returns The hash of the transaction request. - */ -export function hashTxRequest(txRequest: TxRequest): Buffer { - return computeTxHash(txRequest).toBuffer(); -} - -/** - * Computes a function selector from a given function signature. - * @param funcSig - The function signature. - * @returns The function selector. - */ -export function computeFunctionSelector(funcSig: string): Buffer { - return keccak(Buffer.from(funcSig)).subarray(0, FUNCTION_SELECTOR_NUM_BYTES); -} - /** * Computes a hash of a given verification key. * @param vkBuf - The verification key. @@ -89,26 +59,6 @@ export function hashVK(vkBuf: Buffer) { // return crypto::pedersen_hash::hash_buffer(preimage_data, hash_index); } -/** - * Computes a function leaf from a given preimage. - * @param fnLeaf - The function leaf preimage. - * @returns The function leaf. - */ -export function computeFunctionLeaf(fnLeaf: FunctionLeafPreimage): Fr { - return Fr.fromBuffer( - pedersenHash( - [ - numToUInt32BE(fnLeaf.functionSelector.value, 32), - boolToBuffer(fnLeaf.isInternal, 32), - boolToBuffer(fnLeaf.isPrivate, 32), - fnLeaf.vkHash.toBuffer(), - fnLeaf.acirHash.toBuffer(), - ], - GeneratorIndex.FUNCTION_LEAF, - ), - ); -} - let functionTreeRootCalculator: MerkleTreeCalculator | undefined; /** * The "zero leaf" of the function tree is the hash of 5 zero fields. @@ -263,74 +213,6 @@ export function computeVarArgsHash(args: Fr[]) { ); } -/** - * Computes a contract leaf of the given contract. - * @param cd - The contract data of the deployed contract. - * @returns The contract leaf. - */ -export function computeContractLeaf(cd: NewContractData): Fr { - if (cd.contractAddress.isZero() && cd.portalContractAddress.isZero() && cd.contractClassId.isZero()) { - return new Fr(0); - } - return Fr.fromBuffer( - pedersenHash( - [cd.contractAddress.toBuffer(), cd.portalContractAddress.toBuffer(), cd.contractClassId.toBuffer()], - GeneratorIndex.CONTRACT_LEAF, - ), - ); -} - -/** - * Computes tx hash of a given transaction request. - * @param txRequest - The signed transaction request. - * @returns The transaction hash. - */ -export function computeTxHash(txRequest: TxRequest): Fr { - return Fr.fromBuffer( - pedersenHash( - [ - txRequest.origin.toBuffer(), - txRequest.functionData.hash().toBuffer(), - txRequest.argsHash.toBuffer(), - computeTxContextHash(txRequest.txContext).toBuffer(), - ], - GeneratorIndex.TX_REQUEST, - ), - ); -} - -function computeTxContextHash(txContext: TxContext): Fr { - return Fr.fromBuffer( - pedersenHash( - [ - new Fr(txContext.isFeePaymentTx).toBuffer(), - new Fr(txContext.isRebatePaymentTx).toBuffer(), - new Fr(txContext.isContractDeploymentTx).toBuffer(), - computeContractDeploymentDataHash(txContext.contractDeploymentData).toBuffer(), - txContext.chainId.toBuffer(), - txContext.version.toBuffer(), - ], - GeneratorIndex.TX_CONTEXT, - ), - ); -} - -function computeContractDeploymentDataHash(data: ContractDeploymentData): Fr { - return Fr.fromBuffer( - pedersenHash( - [ - data.publicKey.x.toBuffer(), - data.publicKey.y.toBuffer(), - data.initializationHash.toBuffer(), - data.contractClassId.toBuffer(), - data.contractAddressSalt.toBuffer(), - data.portalContractAddress.toBuffer(), - ], - GeneratorIndex.CONTRACT_DEPLOYMENT_DATA, - ), - ); -} - export function computeCommitmentsHash(input: SideEffect) { return pedersenHash([input.value.toBuffer(), input.counter.toBuffer()], GeneratorIndex.SIDE_EFFECT); } @@ -343,36 +225,10 @@ export function computeNullifierHash(input: SideEffectLinkedToNoteHash) { } /** - * Computes a call stack item hash. - * @param callStackItem - The call stack item. - * @returns The call stack item hash. - */ -export function computePublicCallStackItemHash({ - contractAddress, - functionData, - publicInputs, - isExecutionRequest, -}: PublicCallStackItem): Fr { - if (isExecutionRequest) { - const { callContext, argsHash } = publicInputs; - publicInputs = PublicCircuitPublicInputs.empty(); - publicInputs.callContext = callContext; - publicInputs.argsHash = argsHash; - } - - return Fr.fromBuffer( - pedersenHash( - [contractAddress, functionData.hash(), publicInputs.hash()].map(f => f.toBuffer()), - GeneratorIndex.CALL_STACK_ITEM, - ), - ); -} - -/** - * Computes a secret message hash for sending secret l1 to l2 messages. - * @param secretMessage - The secret message. - * @returns + * Given a secret, it computes its pedersen hash - used to send l1 to l2 messages + * @param secret - the secret to hash - secret could be generated however you want e.g. `Fr.random()` + * @returns the hash */ -export function computeSecretMessageHash(secretMessage: Fr) { +export function computeMessageSecretHash(secretMessage: Fr) { return Fr.fromBuffer(pedersenHash([secretMessage.toBuffer()], GeneratorIndex.L1_TO_L2_MESSAGE_SECRET)); } diff --git a/yarn-project/circuits.js/src/hash/index.ts b/yarn-project/circuits.js/src/hash/index.ts new file mode 100644 index 00000000000..c3e9a375b11 --- /dev/null +++ b/yarn-project/circuits.js/src/hash/index.ts @@ -0,0 +1 @@ +export * from './hash.js'; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/contract_deployment_data.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/contract_deployment_data.test.ts.snap new file mode 100644 index 00000000000..11a6dffff27 --- /dev/null +++ b/yarn-project/circuits.js/src/structs/__snapshots__/contract_deployment_data.test.ts.snap @@ -0,0 +1,44 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ContractDeploymentData computes empty hash 1`] = ` +Fr { + "asBigInt": 6550888889575534006716962010714219565950255479539883359305705974567832585221n, + "asBuffer": { + "data": [ + 14, + 123, + 171, + 245, + 157, + 232, + 223, + 199, + 245, + 153, + 44, + 211, + 79, + 176, + 6, + 97, + 5, + 208, + 124, + 230, + 127, + 104, + 252, + 51, + 212, + 160, + 166, + 169, + 51, + 163, + 4, + 5, + ], + "type": "Buffer", + }, +} +`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/function_leaf_preimage.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/function_leaf_preimage.test.ts.snap new file mode 100644 index 00000000000..d20affc7cbc --- /dev/null +++ b/yarn-project/circuits.js/src/structs/__snapshots__/function_leaf_preimage.test.ts.snap @@ -0,0 +1,44 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`FunctionLeafPreimage computes a function leaf 1`] = ` +Fr { + "asBigInt": 14103315440711420844377567457355366382339442623996583897989070814921979368695n, + "asBuffer": { + "data": [ + 31, + 46, + 49, + 147, + 199, + 24, + 115, + 71, + 160, + 153, + 238, + 124, + 181, + 214, + 172, + 7, + 125, + 166, + 177, + 135, + 6, + 254, + 85, + 8, + 230, + 88, + 163, + 208, + 160, + 84, + 148, + 247, + ], + "type": "Buffer", + }, +} +`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap index 1b018bee01c..00287829d25 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap @@ -1,5 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`PublicCallStackItem Computes a callstack item hash 1`] = `"0x1f71c0d6bd03e409df694549b6aa83d706cfe55427152e6ec443ec64fa62d3a0"`; + +exports[`PublicCallStackItem Computes a callstack item request hash 1`] = `"0x2812dfeffdb7553fbbdd27c03fbdf61e3aa9bab3209db39f78838508ad892803"`; + exports[`PublicCallStackItem computes hash 1`] = ` Fr { "asBigInt": 4979549560117705258967782015110547148437372289877391678586990786489996140757n, diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/tx_context.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/tx_context.test.ts.snap new file mode 100644 index 00000000000..40d9eb511f0 --- /dev/null +++ b/yarn-project/circuits.js/src/structs/__snapshots__/tx_context.test.ts.snap @@ -0,0 +1,44 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`TxContext computes empty hash 1`] = ` +Fr { + "asBigInt": 21032445753769195248650393789370064301738468736130164917667517476782805795195n, + "asBuffer": { + "data": [ + 46, + 127, + 241, + 67, + 137, + 238, + 243, + 220, + 81, + 89, + 117, + 41, + 20, + 158, + 1, + 180, + 156, + 179, + 56, + 41, + 247, + 8, + 148, + 56, + 200, + 193, + 69, + 200, + 243, + 82, + 193, + 123, + ], + "type": "Buffer", + }, +} +`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/tx_request.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/tx_request.test.ts.snap new file mode 100644 index 00000000000..fd6001beca6 --- /dev/null +++ b/yarn-project/circuits.js/src/structs/__snapshots__/tx_request.test.ts.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`TxRequest compute hash 1`] = `"0x05e3f67a5e787faf63c85c28169a9d616b594c9799d9785b4f167d9cd7a71e9e"`; diff --git a/yarn-project/circuits.js/src/structs/call_context.ts b/yarn-project/circuits.js/src/structs/call_context.ts index b271d282096..0e79e08f399 100644 --- a/yarn-project/circuits.js/src/structs/call_context.ts +++ b/yarn-project/circuits.js/src/structs/call_context.ts @@ -5,6 +5,8 @@ import { Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; import { FieldsOf } from '@aztec/foundation/types'; +import { CALL_CONTEXT_LENGTH } from '../constants.gen.js'; + /** * Call context. */ @@ -99,7 +101,13 @@ export class CallContext { } toFields(): Fr[] { - return serializeToFields(...CallContext.getFields(this)); + const fields = serializeToFields(...CallContext.getFields(this)); + if (fields.length !== CALL_CONTEXT_LENGTH) { + throw new Error( + `Invalid number of fields for CallContext. Expected ${CALL_CONTEXT_LENGTH}, got ${fields.length}`, + ); + } + return fields; } /** diff --git a/yarn-project/circuits.js/src/structs/contract_deployment_data.test.ts b/yarn-project/circuits.js/src/structs/contract_deployment_data.test.ts index d1988a62553..9bddc3a47cf 100644 --- a/yarn-project/circuits.js/src/structs/contract_deployment_data.test.ts +++ b/yarn-project/circuits.js/src/structs/contract_deployment_data.test.ts @@ -11,14 +11,20 @@ describe('ContractDeploymentData', () => { expect(res.isEmpty()).toBe(false); }); - it(`initializes an empty ContractDeploymentData`, () => { - const target = ContractDeploymentData.empty(); - expect(target.isEmpty()).toBe(true); - }); - it('number of fields matches constant', () => { const target = makeContractDeploymentData(327); const fields = target.toFields(); expect(fields.length).toBe(CONTRACT_DEPLOYMENT_DATA_LENGTH); }); + + it('computes empty hash', () => { + const cd = ContractDeploymentData.empty(); + expect(cd.isEmpty()).toBe(true); + + const hash = cd.hash(); + expect(hash).toMatchSnapshot(); + + // Value used in empty_hash test in contract_deployment_data.nr + // console.log("hash", hash.toString()); + }); }); diff --git a/yarn-project/circuits.js/src/structs/contract_deployment_data.ts b/yarn-project/circuits.js/src/structs/contract_deployment_data.ts index 4f154ace1ae..55f13f19ecd 100644 --- a/yarn-project/circuits.js/src/structs/contract_deployment_data.ts +++ b/yarn-project/circuits.js/src/structs/contract_deployment_data.ts @@ -1,7 +1,10 @@ +import { pedersenHash } from '@aztec/foundation/crypto'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr, Point } from '@aztec/foundation/fields'; -import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { BufferReader, FieldReader, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; +import { FieldsOf } from '@aztec/foundation/types'; +import { CONTRACT_DEPLOYMENT_DATA_LENGTH, GeneratorIndex } from '../constants.gen.js'; import { PublicKey } from '../types/public_key.js'; /** @@ -22,24 +25,28 @@ export class ContractDeploymentData { public portalContractAddress: EthAddress, ) {} + static getFields(fields: FieldsOf) { + return [ + fields.publicKey, + fields.initializationHash, + fields.contractClassId, + fields.contractAddressSalt, + fields.portalContractAddress, + ] as const; + } + toBuffer() { - return serializeToBuffer( - this.publicKey, - this.initializationHash, - this.contractClassId, - this.contractAddressSalt, - this.portalContractAddress, - ); + return serializeToBuffer(...ContractDeploymentData.getFields(this)); } toFields(): Fr[] { - return [ - ...this.publicKey.toFields(), - this.initializationHash, - this.contractClassId, - this.contractAddressSalt, - this.portalContractAddress.toField(), - ]; + const fields = serializeToFields(...ContractDeploymentData.getFields(this)); + if (fields.length !== CONTRACT_DEPLOYMENT_DATA_LENGTH) { + throw new Error( + `Invalid number of fields for ContractDeploymentData. Expected ${CONTRACT_DEPLOYMENT_DATA_LENGTH}, got ${fields.length}`, + ); + } + return fields; } /** @@ -51,13 +58,7 @@ export class ContractDeploymentData { } isEmpty() { - return ( - this.publicKey.isZero() && - this.initializationHash.isZero() && - this.contractClassId.isZero() && - this.contractAddressSalt.isZero() && - this.portalContractAddress.isZero() - ); + return ContractDeploymentData.getFields(this).every(f => f.isZero()); } /** @@ -78,19 +79,21 @@ export class ContractDeploymentData { static fromFields(fields: Fr[] | FieldReader): ContractDeploymentData { const reader = FieldReader.asReader(fields); - - const publicKey = reader.readObject(Point); - const initializationHash = reader.readField(); - const contractClassId = reader.readField(); - const contractAddressSalt = reader.readField(); - const portalContractAddress = reader.readObject(EthAddress); - return new ContractDeploymentData( - publicKey, - initializationHash, - contractClassId, - contractAddressSalt, - portalContractAddress, + reader.readObject(Point), + reader.readField(), + reader.readField(), + reader.readField(), + reader.readObject(EthAddress), + ); + } + + hash(): Fr { + return Fr.fromBuffer( + pedersenHash( + this.toFields().map(f => f.toBuffer()), + GeneratorIndex.CONTRACT_DEPLOYMENT_DATA, + ), ); } } diff --git a/yarn-project/circuits.js/src/structs/contract_storage_read.ts b/yarn-project/circuits.js/src/structs/contract_storage_read.ts index 907470b132d..2c376a1d3f5 100644 --- a/yarn-project/circuits.js/src/structs/contract_storage_read.ts +++ b/yarn-project/circuits.js/src/structs/contract_storage_read.ts @@ -1,6 +1,8 @@ import { Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { CONTRACT_STORAGE_READ_LENGTH } from '../constants.gen.js'; + /** * Contract storage read operation on a specific contract. * @@ -63,7 +65,13 @@ export class ContractStorageRead { } toFields(): Fr[] { - return [this.storageSlot, this.currentValue]; + const fields = [this.storageSlot, this.currentValue]; + if (fields.length !== CONTRACT_STORAGE_READ_LENGTH) { + throw new Error( + `Invalid number of fields for ContractStorageRead. Expected ${CONTRACT_STORAGE_READ_LENGTH}, got ${fields.length}`, + ); + } + return fields; } static fromFields(fields: Fr[] | FieldReader): ContractStorageRead { diff --git a/yarn-project/circuits.js/src/structs/contract_storage_update_request.ts b/yarn-project/circuits.js/src/structs/contract_storage_update_request.ts index 925ce63d1bb..37f9a678717 100644 --- a/yarn-project/circuits.js/src/structs/contract_storage_update_request.ts +++ b/yarn-project/circuits.js/src/structs/contract_storage_update_request.ts @@ -2,6 +2,8 @@ import { Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { FieldsOf } from '@aztec/foundation/types'; +import { CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH } from '../constants.gen.js'; + /** * Contract storage update request for a slot on a specific contract. * @@ -64,7 +66,13 @@ export class ContractStorageUpdateRequest { } toFields(): Fr[] { - return [this.storageSlot, this.newValue]; + const fields = [this.storageSlot, this.newValue]; + if (fields.length !== CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH) { + throw new Error( + `Invalid number of fields for ContractStorageUpdateRequest. Expected ${CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH}, got ${fields.length}`, + ); + } + return fields; } static fromFields(fields: Fr[] | FieldReader): ContractStorageUpdateRequest { diff --git a/yarn-project/circuits.js/src/structs/function_data.ts b/yarn-project/circuits.js/src/structs/function_data.ts index 378baab9f94..3cf82fc5784 100644 --- a/yarn-project/circuits.js/src/structs/function_data.ts +++ b/yarn-project/circuits.js/src/structs/function_data.ts @@ -3,12 +3,11 @@ import { pedersenHash } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; -import { GeneratorIndex } from '../constants.gen.js'; +import { FUNCTION_DATA_LENGTH, GeneratorIndex } from '../constants.gen.js'; import { ContractFunctionDao } from '../types/contract_function_dao.js'; /** * Function description for circuit. - * @see abis/function_data.hpp */ export class FunctionData { constructor( @@ -48,7 +47,18 @@ export class FunctionData { } toFields(): Fr[] { - return [this.selector.toField(), new Fr(this.isInternal), new Fr(this.isPrivate), new Fr(this.isConstructor)]; + const fields = [ + this.selector.toField(), + new Fr(this.isInternal), + new Fr(this.isPrivate), + new Fr(this.isConstructor), + ]; + if (fields.length !== FUNCTION_DATA_LENGTH) { + throw new Error( + `Invalid number of fields for FunctionData. Expected ${FUNCTION_DATA_LENGTH}, got ${fields.length}`, + ); + } + return fields; } /** diff --git a/yarn-project/circuits.js/src/structs/function_leaf_preimage.test.ts b/yarn-project/circuits.js/src/structs/function_leaf_preimage.test.ts index 71d28180452..9b23593f85f 100644 --- a/yarn-project/circuits.js/src/structs/function_leaf_preimage.test.ts +++ b/yarn-project/circuits.js/src/structs/function_leaf_preimage.test.ts @@ -1,13 +1,33 @@ import { FunctionSelector } from '@aztec/foundation/abi'; import { Fr } from '@aztec/foundation/fields'; +import { FUNCTION_LEAF_PREIMAGE_LENGTH } from '../constants.gen.js'; import { FunctionLeafPreimage } from './function_leaf_preimage.js'; describe('FunctionLeafPreimage', () => { + let leaf: FunctionLeafPreimage; + + beforeAll(() => { + leaf = new FunctionLeafPreimage(new FunctionSelector(8972), false, true, Fr.ZERO, Fr.ZERO); + }); + it(`serializes to buffer and deserializes it back`, () => { - const expected = new FunctionLeafPreimage(new FunctionSelector(8972), false, true, Fr.ZERO, Fr.ZERO); - const buffer = expected.toBuffer(); + const buffer = leaf.toBuffer(); const res = FunctionLeafPreimage.fromBuffer(buffer); - expect(res).toEqual(expected); + expect(res).toEqual(leaf); + }); + + it('number of fields matches constant', () => { + const fields = leaf.toFields(); + expect(fields.length).toBe(FUNCTION_LEAF_PREIMAGE_LENGTH); + }); + + it('computes a function leaf', () => { + const emptyLeaf = new FunctionLeafPreimage(new FunctionSelector(0), false, false, Fr.ZERO, Fr.ZERO); + const hash = emptyLeaf.hash(); + expect(hash).toMatchSnapshot(); + + // Value used in empty_hash test in function_leaf_preimage.nr + // console.log("hash", hash.toString()); }); }); diff --git a/yarn-project/circuits.js/src/structs/function_leaf_preimage.ts b/yarn-project/circuits.js/src/structs/function_leaf_preimage.ts index 5bf3c7a1195..53f2b1e71ca 100644 --- a/yarn-project/circuits.js/src/structs/function_leaf_preimage.ts +++ b/yarn-project/circuits.js/src/structs/function_leaf_preimage.ts @@ -1,10 +1,13 @@ import { FunctionSelector } from '@aztec/foundation/abi'; +import { pedersenHash } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; -import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { BufferReader, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; +import { FieldsOf } from '@aztec/foundation/types'; + +import { FUNCTION_LEAF_PREIMAGE_LENGTH, GeneratorIndex } from '../constants.gen.js'; /** * A class representing the "preimage" of a function tree leaf. - * @see abis/function_leaf_preimage.hpp */ export class FunctionLeafPreimage { constructor( @@ -30,12 +33,26 @@ export class FunctionLeafPreimage { public acirHash: Fr, ) {} + static getFields(fields: FieldsOf) { + return [fields.functionSelector, fields.isInternal, fields.isPrivate, fields.vkHash, fields.acirHash] as const; + } + /** * Serialize this as a buffer. * @returns The buffer. */ toBuffer(): Buffer { - return serializeToBuffer(this.functionSelector, this.isInternal, this.isPrivate, this.vkHash, this.acirHash); + return serializeToBuffer(...FunctionLeafPreimage.getFields(this)); + } + + toFields(): Fr[] { + const fields = serializeToFields(...FunctionLeafPreimage.getFields(this)); + if (fields.length !== FUNCTION_LEAF_PREIMAGE_LENGTH) { + throw new Error( + `Invalid number of fields for FunctionLeafPreimage. Expected ${FUNCTION_LEAF_PREIMAGE_LENGTH}, got ${fields.length}`, + ); + } + return fields; } /** @@ -53,4 +70,13 @@ export class FunctionLeafPreimage { Fr.fromBuffer(reader), ); } + + hash(): Fr { + return Fr.fromBuffer( + pedersenHash( + this.toFields().map(field => field.toBuffer()), + GeneratorIndex.FUNCTION_LEAF, + ), + ); + } } diff --git a/yarn-project/circuits.js/src/structs/global_variables.ts b/yarn-project/circuits.js/src/structs/global_variables.ts index 49ecf601b46..3b117686064 100644 --- a/yarn-project/circuits.js/src/structs/global_variables.ts +++ b/yarn-project/circuits.js/src/structs/global_variables.ts @@ -2,6 +2,7 @@ import { Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; import { FieldsOf } from '@aztec/foundation/types'; +import { GLOBAL_VARIABLES_LENGTH } from '../constants.gen.js'; import { AztecAddress, EthAddress } from './index.js'; /** @@ -84,7 +85,13 @@ export class GlobalVariables { } toFields() { - return serializeToFields(...GlobalVariables.getFields(this)); + const fields = serializeToFields(...GlobalVariables.getFields(this)); + if (fields.length !== GLOBAL_VARIABLES_LENGTH) { + throw new Error( + `Invalid number of fields for GlobalVariables. Expected ${GLOBAL_VARIABLES_LENGTH}, got ${fields.length}`, + ); + } + return fields; } toJSON() { diff --git a/yarn-project/circuits.js/src/structs/header.ts b/yarn-project/circuits.js/src/structs/header.ts index 69f2c2a724a..1e28525a99a 100644 --- a/yarn-project/circuits.js/src/structs/header.ts +++ b/yarn-project/circuits.js/src/structs/header.ts @@ -28,16 +28,16 @@ export class Header { toFields(): Fr[] { // Note: The order here must match the order in header.nr - const serialized = [ + const fields = [ ...this.lastArchive.toFields(), ...this.contentCommitment.toFields(), ...this.state.toFields(), ...this.globalVariables.toFields(), ]; - if (serialized.length !== HEADER_LENGTH) { - throw new Error(`Expected header to have ${HEADER_LENGTH} fields, but it has ${serialized.length} fields`); + if (fields.length !== HEADER_LENGTH) { + throw new Error(`Invalid number of fields for Header. Expected ${HEADER_LENGTH}, got ${fields.length}`); } - return serialized; + return fields; } static fromBuffer(buffer: Buffer | BufferReader): Header { diff --git a/yarn-project/circuits.js/src/structs/index.ts b/yarn-project/circuits.js/src/structs/index.ts index 939a709c3af..454fdf6ba67 100644 --- a/yarn-project/circuits.js/src/structs/index.ts +++ b/yarn-project/circuits.js/src/structs/index.ts @@ -13,6 +13,7 @@ export * from './content_commitment.js'; export * from './header.js'; export * from './kernel/combined_accumulated_data.js'; export * from './kernel/combined_constant_data.js'; +export * from './kernel/new_contract_data.js'; export * from './kernel/private_call_data.js'; export * from './kernel/private_kernel_init_circuit_private_inputs.js'; export * from './kernel/private_kernel_inner_circuit_private_inputs.js'; diff --git a/yarn-project/circuits.js/src/structs/kernel/__snapshots__/new_contract_data.test.ts.snap b/yarn-project/circuits.js/src/structs/kernel/__snapshots__/new_contract_data.test.ts.snap new file mode 100644 index 00000000000..3b575df1b03 --- /dev/null +++ b/yarn-project/circuits.js/src/structs/kernel/__snapshots__/new_contract_data.test.ts.snap @@ -0,0 +1,44 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`NewContractData computes contract leaf 1`] = ` +Fr { + "asBigInt": 5986263944919688269259252379860004722838901933221811337668199393213435390630n, + "asBuffer": { + "data": [ + 13, + 60, + 26, + 246, + 112, + 251, + 244, + 209, + 174, + 13, + 247, + 16, + 244, + 142, + 50, + 157, + 199, + 41, + 183, + 98, + 240, + 188, + 131, + 153, + 186, + 217, + 255, + 3, + 166, + 0, + 170, + 166, + ], + "type": "Buffer", + }, +} +`; diff --git a/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts b/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts index c2a382ae701..dd7f9015a13 100644 --- a/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts @@ -1,6 +1,4 @@ import { makeTuple } from '@aztec/foundation/array'; -import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; @@ -24,46 +22,7 @@ import { import { CallRequest } from '../call_request.js'; import { NullifierKeyValidationRequestContext } from '../nullifier_key_validation_request.js'; import { SideEffect, SideEffectLinkedToNoteHash } from '../side_effects.js'; - -/** - * The information assembled after the contract deployment was processed by the private kernel circuit. - * - * Note: Not to be confused with `ContractDeploymentData`. - */ -export class NewContractData { - constructor( - /** - * Aztec address of the contract. - */ - public contractAddress: AztecAddress, - /** - * Ethereum address of the portal contract on L1. - */ - public portalContractAddress: EthAddress, - /** - * Contract class id. - */ - public contractClassId: Fr, - ) {} - - toBuffer() { - return serializeToBuffer(this.contractAddress, this.portalContractAddress, this.contractClassId); - } - - /** - * Deserializes from a buffer or reader, corresponding to a write in cpp. - * @param buffer - Buffer or reader to read from. - * @returns The deserialized `NewContractData`. - */ - static fromBuffer(buffer: Buffer | BufferReader): NewContractData { - const reader = BufferReader.asReader(buffer); - return new NewContractData(reader.readObject(AztecAddress), reader.readObject(EthAddress), Fr.fromBuffer(reader)); - } - - static empty() { - return new NewContractData(AztecAddress.ZERO, EthAddress.ZERO, Fr.ZERO); - } -} +import { NewContractData } from './new_contract_data.js'; /** * Read operations from the public state tree. diff --git a/yarn-project/circuits.js/src/structs/kernel/new_contract_data.test.ts b/yarn-project/circuits.js/src/structs/kernel/new_contract_data.test.ts new file mode 100644 index 00000000000..df66eee7041 --- /dev/null +++ b/yarn-project/circuits.js/src/structs/kernel/new_contract_data.test.ts @@ -0,0 +1,29 @@ +import { NEW_CONTRACT_DATA_LENGTH } from '../../constants.gen.js'; +import { makeNewContractData } from '../../tests/factories.js'; +import { NewContractData } from './new_contract_data.js'; + +describe('NewContractData', () => { + let data: NewContractData; + + beforeAll(() => { + const randomInt = Math.floor(Math.random() * 1000); + data = makeNewContractData(randomInt); + }); + + it('serializes to buffer and deserializes it back', () => { + const buffer = data.toBuffer(); + const res = NewContractData.fromBuffer(buffer); + expect(res).toEqual(data); + }); + + it('number of fields matches constant', () => { + const fields = data.toFields(); + expect(fields.length).toBe(NEW_CONTRACT_DATA_LENGTH); + }); + + it('computes contract leaf', () => { + const cd = makeNewContractData(12); + const res = cd.computeLeaf(); + expect(res).toMatchSnapshot(); + }); +}); diff --git a/yarn-project/circuits.js/src/structs/kernel/new_contract_data.ts b/yarn-project/circuits.js/src/structs/kernel/new_contract_data.ts new file mode 100644 index 00000000000..33332732ccb --- /dev/null +++ b/yarn-project/circuits.js/src/structs/kernel/new_contract_data.ts @@ -0,0 +1,87 @@ +import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { pedersenHash } from '@aztec/foundation/crypto'; +import { EthAddress } from '@aztec/foundation/eth-address'; +import { Fr } from '@aztec/foundation/fields'; +import { BufferReader, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; +import { FieldsOf } from '@aztec/foundation/types'; + +import { GeneratorIndex, NEW_CONTRACT_DATA_LENGTH } from '../../constants.gen.js'; + +/** + * The information assembled after the contract deployment was processed by the private kernel circuit. + * + * Note: Not to be confused with `ContractDeploymentData`. + */ +export class NewContractData { + constructor( + /** + * Aztec address of the contract. + */ + public contractAddress: AztecAddress, + /** + * Ethereum address of the portal contract on L1. + */ + public portalContractAddress: EthAddress, + /** + * Contract class id. + */ + public contractClassId: Fr, + ) {} + + static getFields(fields: FieldsOf) { + return [fields.contractAddress, fields.portalContractAddress, fields.contractClassId] as const; + } + + toBuffer() { + return serializeToBuffer(...NewContractData.getFields(this)); + } + + toFields() { + const fields = serializeToFields(...NewContractData.getFields(this)); + if (fields.length !== NEW_CONTRACT_DATA_LENGTH) { + throw new Error( + `Invalid number of fields for NewContractData. Expected ${NEW_CONTRACT_DATA_LENGTH}, got ${fields.length}`, + ); + } + return fields; + } + + /** + * Computes a contract leaf of the given contract. + * @param cd - The contract data of the deployed contract. + * @returns The contract leaf. + */ + computeLeaf(): Fr { + if (this.isEmpty()) { + return new Fr(0); + } + return Fr.fromBuffer( + pedersenHash( + NewContractData.getFields(this).map(f => f.toBuffer()), + GeneratorIndex.CONTRACT_LEAF, + ), + ); + } + + /** + * Deserializes from a buffer or reader, corresponding to a write in cpp. + * @param buffer - Buffer or reader to read from. + * @returns The deserialized `NewContractData`. + */ + static fromBuffer(buffer: Buffer | BufferReader): NewContractData { + const reader = BufferReader.asReader(buffer); + return new NewContractData(reader.readObject(AztecAddress), reader.readObject(EthAddress), Fr.fromBuffer(reader)); + } + + static empty() { + return new NewContractData(AztecAddress.ZERO, EthAddress.ZERO, Fr.ZERO); + } + + /** + * Checks if the data is empty. + * @returns True if the data operation is empty, false otherwise. + */ + isEmpty(): boolean { + return this.contractAddress.isZero() && this.portalContractAddress.isZero() && this.contractClassId.isZero(); + } +} diff --git a/yarn-project/circuits.js/src/structs/l2_to_l1_message.ts b/yarn-project/circuits.js/src/structs/l2_to_l1_message.ts index ab4d91384d7..ef4bb082386 100644 --- a/yarn-project/circuits.js/src/structs/l2_to_l1_message.ts +++ b/yarn-project/circuits.js/src/structs/l2_to_l1_message.ts @@ -2,6 +2,8 @@ import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { L2_TO_L1_MESSAGE_LENGTH } from '../constants.gen.js'; + export class L2ToL1Message { constructor(public recipient: EthAddress, public content: Fr) {} @@ -35,7 +37,13 @@ export class L2ToL1Message { * @returns An array of fields representing the serialized message. */ toFields(): Fr[] { - return [this.recipient.toField(), this.content]; + const fields = [this.recipient.toField(), this.content]; + if (fields.length !== L2_TO_L1_MESSAGE_LENGTH) { + throw new Error( + `Invalid number of fields for L2ToL1Message. Expected ${L2_TO_L1_MESSAGE_LENGTH}, got ${fields.length}`, + ); + } + return fields; } /** diff --git a/yarn-project/circuits.js/src/structs/nullifier_key_validation_request.ts b/yarn-project/circuits.js/src/structs/nullifier_key_validation_request.ts index 5e93ead5855..37f2a6ad9ea 100644 --- a/yarn-project/circuits.js/src/structs/nullifier_key_validation_request.ts +++ b/yarn-project/circuits.js/src/structs/nullifier_key_validation_request.ts @@ -2,6 +2,10 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr, GrumpkinScalar, Point } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { + NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_LENGTH, + NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH, +} from '../constants.gen.js'; import { GrumpkinPrivateKey } from '../types/grumpkin_private_key.js'; /** @@ -29,7 +33,13 @@ export class NullifierKeyValidationRequest { } toFields(): Fr[] { - return [this.publicKey.toFields(), this.secretKey.high, this.secretKey.low].flat(); + const fields = [this.publicKey.toFields(), this.secretKey.high, this.secretKey.low].flat(); + if (fields.length !== NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH) { + throw new Error( + `Invalid number of fields for NullifierKeyValidationRequest. Expected ${NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH}, got ${fields.length}`, + ); + } + return fields; } static fromFields(fields: Fr[] | FieldReader): NullifierKeyValidationRequest { @@ -79,7 +89,13 @@ export class NullifierKeyValidationRequestContext { } toFields(): Fr[] { - return [this.publicKey.toFields(), this.secretKey.high, this.secretKey.low, this.contractAddress].flat(); + const fields = [this.publicKey.toFields(), this.secretKey.high, this.secretKey.low, this.contractAddress].flat(); + if (fields.length !== NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_LENGTH) { + throw new Error( + `Invalid number of fields for NullifierKeyValidationRequestContext. Expected ${NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_LENGTH}, got ${fields.length}`, + ); + } + return fields; } static fromFields(fields: Fr[] | FieldReader): NullifierKeyValidationRequestContext { diff --git a/yarn-project/circuits.js/src/structs/partial_state_reference.ts b/yarn-project/circuits.js/src/structs/partial_state_reference.ts index 369b0732c41..28dbd86654e 100644 --- a/yarn-project/circuits.js/src/structs/partial_state_reference.ts +++ b/yarn-project/circuits.js/src/structs/partial_state_reference.ts @@ -1,6 +1,7 @@ import { Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { PARTIAL_STATE_REFERENCE_LENGTH } from '../constants.gen.js'; import { AppendOnlyTreeSnapshot } from './rollup/append_only_tree_snapshot.js'; /** @@ -53,12 +54,18 @@ export class PartialStateReference { } toFields() { - return [ + const fields = [ ...this.noteHashTree.toFields(), ...this.nullifierTree.toFields(), ...this.contractTree.toFields(), ...this.publicDataTree.toFields(), ]; + if (fields.length !== PARTIAL_STATE_REFERENCE_LENGTH) { + throw new Error( + `Invalid number of fields for PartialStateReference. Expected ${PARTIAL_STATE_REFERENCE_LENGTH}, got ${fields.length}`, + ); + } + return fields; } isEmpty(): boolean { diff --git a/yarn-project/circuits.js/src/structs/private_call_stack_item.ts b/yarn-project/circuits.js/src/structs/private_call_stack_item.ts index fb4ceee298b..09650a0027c 100644 --- a/yarn-project/circuits.js/src/structs/private_call_stack_item.ts +++ b/yarn-project/circuits.js/src/structs/private_call_stack_item.ts @@ -4,7 +4,7 @@ import { Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; import { FieldsOf } from '@aztec/foundation/types'; -import { GeneratorIndex } from '../constants.gen.js'; +import { GeneratorIndex, PRIVATE_CALL_STACK_ITEM_LENGTH } from '../constants.gen.js'; import { CallRequest, CallerContext } from './call_request.js'; import { FunctionData } from './function_data.js'; import { PrivateCircuitPublicInputs } from './private_circuit_public_inputs.js'; @@ -37,7 +37,13 @@ export class PrivateCallStackItem { } toFields(): Fr[] { - return serializeToFields(...PrivateCallStackItem.getFields(this)); + const fields = serializeToFields(...PrivateCallStackItem.getFields(this)); + if (fields.length !== PRIVATE_CALL_STACK_ITEM_LENGTH) { + throw new Error( + `Invalid number of fields for PrivateCallStackItem. Expected ${PRIVATE_CALL_STACK_ITEM_LENGTH}, got ${fields.length}`, + ); + } + return fields; } /** diff --git a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts index ca491f09b7b..5415cab76fa 100644 --- a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts @@ -15,6 +15,7 @@ import { MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_READ_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256, + PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH, RETURN_VALUES_LENGTH, } from '../constants.gen.js'; import { ContractDeploymentData } from '../structs/contract_deployment_data.js'; @@ -288,7 +289,13 @@ export class PrivateCircuitPublicInputs { * Serialize this as a field array. */ toFields(): Fr[] { - return serializeToFields(...PrivateCircuitPublicInputs.getFields(this)); + const fields = serializeToFields(...PrivateCircuitPublicInputs.getFields(this)); + if (fields.length !== PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH) { + throw new Error( + `Invalid number of fields for PrivateCircuitPublicInputs. Expected ${PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH}, got ${fields.length}`, + ); + } + return fields; } hash(): Fr { diff --git a/yarn-project/circuits.js/src/structs/public_call_request.ts b/yarn-project/circuits.js/src/structs/public_call_request.ts index 8516081362a..0ffab8d62ac 100644 --- a/yarn-project/circuits.js/src/structs/public_call_request.ts +++ b/yarn-project/circuits.js/src/structs/public_call_request.ts @@ -3,7 +3,7 @@ import { Fr } from '@aztec/foundation/fields'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { FieldsOf } from '@aztec/foundation/types'; -import { computeVarArgsHash } from '../abis/abis.js'; +import { computeVarArgsHash } from '../hash/hash.js'; import { CallContext } from './call_context.js'; import { CallRequest, CallerContext } from './call_request.js'; import { FunctionData } from './function_data.js'; diff --git a/yarn-project/circuits.js/src/structs/public_call_stack_item.test.ts b/yarn-project/circuits.js/src/structs/public_call_stack_item.test.ts index 028d3980fda..dace12f6fe7 100644 --- a/yarn-project/circuits.js/src/structs/public_call_stack_item.test.ts +++ b/yarn-project/circuits.js/src/structs/public_call_stack_item.test.ts @@ -1,4 +1,5 @@ import { makePublicCallStackItem } from '../tests/factories.js'; +import { AztecAddress, Fr, FunctionData, FunctionSelector, SideEffect } from './index.js'; import { PublicCallStackItem } from './public_call_stack_item.js'; describe('PublicCallStackItem', () => { @@ -10,19 +11,39 @@ describe('PublicCallStackItem', () => { expect(res).toEqual(expected); }); - it('serializes to field array and deserializes it back', () => { - const randomInt = Math.floor(Math.random() * 1000); - const expected = makePublicCallStackItem(randomInt); - - const fieldArray = expected.toFields(); - const res = PublicCallStackItem.fromFields(fieldArray); - expect(res).toEqual(expected); - }); - it('computes hash', () => { const seed = 9870243; const item = makePublicCallStackItem(seed); const hash = item.hash(); expect(hash).toMatchSnapshot(); }); + + it('Computes a callstack item request hash', () => { + const callStack = PublicCallStackItem.empty(); + + callStack.contractAddress = AztecAddress.fromField(new Fr(1)); + callStack.functionData = new FunctionData(new FunctionSelector(2), false, false, false); + callStack.isExecutionRequest = true; + callStack.publicInputs.newCommitments[0] = new SideEffect(new Fr(1), new Fr(0)); + + const hash = callStack.hash(); + expect(hash.toString()).toMatchSnapshot(); + + // Value used in compute_call_stack_item_hash test in public_call_stack_item.test.ts + // console.log("hash", hash.toString()); + }); + + it('Computes a callstack item hash', () => { + const callStack = PublicCallStackItem.empty(); + + callStack.contractAddress = AztecAddress.fromField(new Fr(1)); + callStack.functionData = new FunctionData(new FunctionSelector(2), false, false, false); + callStack.publicInputs.newCommitments[0] = new SideEffect(new Fr(1), new Fr(0)); + + const hash = callStack.hash(); + expect(hash.toString()).toMatchSnapshot(); + + // Value used in compute_call_stack_item_request_hash test in public_call_stack_item.test.ts + // console.log("hash", hash.toString()); + }); }); diff --git a/yarn-project/circuits.js/src/structs/public_call_stack_item.ts b/yarn-project/circuits.js/src/structs/public_call_stack_item.ts index 9a4337f3e46..eef2a15eda8 100644 --- a/yarn-project/circuits.js/src/structs/public_call_stack_item.ts +++ b/yarn-project/circuits.js/src/structs/public_call_stack_item.ts @@ -1,9 +1,10 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { pedersenHash } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; -import { BufferReader, FieldReader, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; +import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { FieldsOf } from '@aztec/foundation/types'; -import { computePublicCallStackItemHash } from '../abis/abis.js'; +import { GeneratorIndex } from '../constants.gen.js'; import { CallRequest, CallerContext } from './call_request.js'; import { FunctionData } from './function_data.js'; import { PublicCircuitPublicInputs } from './public_circuit_public_inputs.js'; @@ -39,10 +40,6 @@ export class PublicCallStackItem { return serializeToBuffer(...PublicCallStackItem.getFields(this)); } - toFields(): Fr[] { - return serializeToFields(...PublicCallStackItem.getFields(this)); - } - /** * Deserializes from a buffer or reader. * @param buffer - Buffer or reader to read from. @@ -91,7 +88,19 @@ export class PublicCallStackItem { * @returns Hash. */ public hash() { - return computePublicCallStackItemHash(this); + if (this.isExecutionRequest) { + const { callContext, argsHash } = this.publicInputs; + this.publicInputs = PublicCircuitPublicInputs.empty(); + this.publicInputs.callContext = callContext; + this.publicInputs.argsHash = argsHash; + } + + return Fr.fromBuffer( + pedersenHash( + [this.contractAddress, this.functionData.hash(), this.publicInputs.hash()].map(f => f.toBuffer()), + GeneratorIndex.CALL_STACK_ITEM, + ), + ); } /** diff --git a/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.ts index 94771b61ac6..2b0e111f9df 100644 --- a/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.ts @@ -15,6 +15,7 @@ import { MAX_PUBLIC_DATA_READS_PER_CALL, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256, + PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH, RETURN_VALUES_LENGTH, } from '../constants.gen.js'; import { CallContext } from './call_context.js'; @@ -173,7 +174,13 @@ export class PublicCircuitPublicInputs { } toFields(): Fr[] { - return serializeToFields(...PublicCircuitPublicInputs.getFields(this)); + const fields = serializeToFields(...PublicCircuitPublicInputs.getFields(this)); + if (fields.length !== PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH) { + throw new Error( + `Invalid number of fields for PublicCircuitPublicInputs. Expected ${PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH}, got ${fields.length}`, + ); + } + return fields; } /** diff --git a/yarn-project/circuits.js/src/structs/state_reference.ts b/yarn-project/circuits.js/src/structs/state_reference.ts index 4beaab76e0a..8d05ec2b974 100644 --- a/yarn-project/circuits.js/src/structs/state_reference.ts +++ b/yarn-project/circuits.js/src/structs/state_reference.ts @@ -1,6 +1,7 @@ import { Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { STATE_REFERENCE_LENGTH } from '../constants.gen.js'; import { PartialStateReference } from './partial_state_reference.js'; import { AppendOnlyTreeSnapshot } from './rollup/append_only_tree_snapshot.js'; @@ -21,7 +22,13 @@ export class StateReference { } toFields(): Fr[] { - return [...this.l1ToL2MessageTree.toFields(), ...this.partial.toFields()]; + const fields = [...this.l1ToL2MessageTree.toFields(), ...this.partial.toFields()]; + if (fields.length !== STATE_REFERENCE_LENGTH) { + throw new Error( + `Invalid number of fields for StateReference. Expected ${STATE_REFERENCE_LENGTH}, got ${fields.length}`, + ); + } + return fields; } static fromBuffer(buffer: Buffer | BufferReader): StateReference { diff --git a/yarn-project/circuits.js/src/structs/tx_context.test.ts b/yarn-project/circuits.js/src/structs/tx_context.test.ts index 3fde72052f2..d090be9f0ed 100644 --- a/yarn-project/circuits.js/src/structs/tx_context.test.ts +++ b/yarn-project/circuits.js/src/structs/tx_context.test.ts @@ -1,17 +1,35 @@ +import { TX_CONTEXT_DATA_LENGTH } from '../constants.gen.js'; import { makeTxContext } from '../tests/factories.js'; import { TxContext } from './tx_context.js'; describe('TxContext', () => { + let context: TxContext; + + beforeAll(() => { + const randomInt = Math.floor(Math.random() * 1000); + context = makeTxContext(randomInt); + }); + it(`serializes to buffer and deserializes it back`, () => { - const expected = makeTxContext(1); - const buffer = expected.toBuffer(); + const buffer = context.toBuffer(); const res = TxContext.fromBuffer(buffer); - expect(res).toEqual(expected); + expect(res).toEqual(context); expect(res.isEmpty()).toBe(false); }); - it(`initializes an empty TxContext`, () => { - const target = TxContext.empty(); - expect(target.isEmpty()).toBe(true); + it('number of fields matches constant', () => { + const fields = context.toFields(); + expect(fields.length).toBe(TX_CONTEXT_DATA_LENGTH); + }); + + it('computes empty hash', () => { + const tc = TxContext.empty(); + expect(tc.isEmpty()).toBe(true); + + const hash = tc.hash(); + expect(hash).toMatchSnapshot(); + + // Value used in empty_hash test in contract_deployment_data.nr + // console.log("hash", hash.toString()); }); }); diff --git a/yarn-project/circuits.js/src/structs/tx_context.ts b/yarn-project/circuits.js/src/structs/tx_context.ts index 77b35cfd367..dd5107105b4 100644 --- a/yarn-project/circuits.js/src/structs/tx_context.ts +++ b/yarn-project/circuits.js/src/structs/tx_context.ts @@ -1,7 +1,9 @@ +import { pedersenHash } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; -import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { BufferReader, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; import { FieldsOf } from '@aztec/foundation/types'; +import { GeneratorIndex, TX_CONTEXT_DATA_LENGTH } from '../constants.gen.js'; import { ContractDeploymentData } from '../structs/contract_deployment_data.js'; /** @@ -47,14 +49,17 @@ export class TxContext { * @returns The buffer. */ toBuffer() { - return serializeToBuffer( - this.isFeePaymentTx, - this.isRebatePaymentTx, - this.isContractDeploymentTx, - this.contractDeploymentData, - this.chainId, - this.version, - ); + return serializeToBuffer(...TxContext.getFields(this)); + } + + toFields(): Fr[] { + const fields = serializeToFields(...TxContext.getFields(this)); + if (fields.length !== TX_CONTEXT_DATA_LENGTH) { + throw new Error( + `Invalid number of fields for TxContext. Expected ${TX_CONTEXT_DATA_LENGTH}, got ${fields.length}`, + ); + } + return fields; } /** @@ -113,4 +118,13 @@ export class TxContext { fields.version, ] as const; } + + hash(): Fr { + return Fr.fromBuffer( + pedersenHash( + this.toFields().map(f => f.toBuffer()), + GeneratorIndex.TX_CONTEXT, + ), + ); + } } diff --git a/yarn-project/circuits.js/src/structs/tx_request.test.ts b/yarn-project/circuits.js/src/structs/tx_request.test.ts new file mode 100644 index 00000000000..82ef6ff0361 --- /dev/null +++ b/yarn-project/circuits.js/src/structs/tx_request.test.ts @@ -0,0 +1,55 @@ +import { FunctionSelector } from '@aztec/foundation/abi'; +import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { Fr, Point } from '@aztec/foundation/fields'; + +import { TX_REQUEST_LENGTH } from '../constants.gen.js'; +import { makeTxRequest } from '../tests/factories.js'; +import { ContractDeploymentData } from './contract_deployment_data.js'; +import { FunctionData } from './function_data.js'; +import { EthAddress } from './index.js'; +import { TxContext } from './tx_context.js'; +import { TxRequest } from './tx_request.js'; + +describe('TxRequest', () => { + let request: TxRequest; + + beforeAll(() => { + const randomInt = Math.floor(Math.random() * 1000); + request = makeTxRequest(randomInt); + }); + + it(`serializes to buffer and deserializes it back`, () => { + const buffer = request.toBuffer(); + const res = TxRequest.fromBuffer(buffer); + expect(res).toEqual(request); + expect(res.isEmpty()).toBe(false); + }); + + it('number of fields matches constant', () => { + const fields = request.toFields(); + expect(fields.length).toBe(TX_REQUEST_LENGTH); + }); + + it('compute hash', () => { + const deploymentData = new ContractDeploymentData( + new Point(new Fr(1), new Fr(2)), + new Fr(1), + new Fr(2), + new Fr(3), + EthAddress.fromField(new Fr(1)), + ); + const txRequest = TxRequest.from({ + origin: AztecAddress.fromBigInt(1n), + functionData: new FunctionData(FunctionSelector.fromField(new Fr(2n)), false, true, true), + argsHash: new Fr(3), + txContext: new TxContext(false, false, true, deploymentData, Fr.ZERO, Fr.ZERO), + }); + + const hash = txRequest.hash().toString(); + + expect(hash).toMatchSnapshot(); + + // Value used in hash test in tx_request.nr + // console.log("hash", hash); + }); +}); diff --git a/yarn-project/circuits.js/src/structs/tx_request.ts b/yarn-project/circuits.js/src/structs/tx_request.ts index 5db6010997e..855da757002 100644 --- a/yarn-project/circuits.js/src/structs/tx_request.ts +++ b/yarn-project/circuits.js/src/structs/tx_request.ts @@ -1,14 +1,15 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { pedersenHash } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; -import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { BufferReader, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; import { FieldsOf } from '@aztec/foundation/types'; +import { GeneratorIndex, TX_REQUEST_LENGTH } from '../constants.gen.js'; import { FunctionData } from './function_data.js'; import { TxContext } from './tx_context.js'; /** * Transaction request. - * @see cpp/src/aztec3/circuits/abis/tx_request.hpp. */ export class TxRequest { constructor( @@ -43,8 +44,15 @@ export class TxRequest { * @returns The buffer. */ toBuffer() { - const fields = TxRequest.getFields(this); - return serializeToBuffer([...fields]); + return serializeToBuffer([...TxRequest.getFields(this)]); + } + + toFields(): Fr[] { + const fields = serializeToFields(...TxRequest.getFields(this)); + if (fields.length !== TX_REQUEST_LENGTH) { + throw new Error(`Invalid number of fields for TxRequest. Expected ${TX_REQUEST_LENGTH}, got ${fields.length}`); + } + return fields; } /** @@ -61,4 +69,21 @@ export class TxRequest { reader.readObject(TxContext), ); } + + hash() { + return Fr.fromBuffer( + pedersenHash( + this.toFields().map(field => field.toBuffer()), + GeneratorIndex.TX_REQUEST, + ), + ); + } + + static empty() { + return new TxRequest(AztecAddress.ZERO, FunctionData.empty(), Fr.zero(), TxContext.empty()); + } + + isEmpty() { + return this.origin.isZero() && this.functionData.isEmpty() && this.argsHash.isZero() && this.txContext.isEmpty(); + } } diff --git a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts index f0413d1fcb6..50d77af15e9 100644 --- a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts @@ -28,7 +28,7 @@ import { registerContractClass, } from '@aztec/aztec.js/deployment'; import { ContractClassIdPreimage, Point, PublicKey } from '@aztec/circuits.js'; -import { siloNullifier } from '@aztec/circuits.js/abis'; +import { siloNullifier } from '@aztec/circuits.js/hash'; import { FunctionSelector, FunctionType } from '@aztec/foundation/abi'; import { ContractInstanceDeployerContract, StatefulTestContract } from '@aztec/noir-contracts.js'; import { TestContract, TestContractArtifact } from '@aztec/noir-contracts.js/Test'; diff --git a/yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts b/yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts index 53adc6a61ad..ec6eca28b5b 100644 --- a/yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts @@ -10,7 +10,6 @@ import { getContractInstanceFromDeployParams, } from '@aztec/aztec.js'; import { NewContractData } from '@aztec/circuits.js'; -import { computeContractLeaf } from '@aztec/circuits.js/abis'; import { InclusionProofsContract } from '@aztec/noir-contracts.js/InclusionProofs'; import { jest } from '@jest/globals'; @@ -294,7 +293,7 @@ describe('e2e_inclusion_proofs_contract', () => { // This should fail because we choose a block number before the contract was deployed const blockNumber = deploymentBlockNumber - 1; const contractData = new NewContractData(contract.address, portalContractAddress, contractClassId); - const leaf = computeContractLeaf(contractData); + const leaf = contractData.computeLeaf(); await expect( contract.methods diff --git a/yarn-project/end-to-end/src/e2e_non_contract_account.test.ts b/yarn-project/end-to-end/src/e2e_non_contract_account.test.ts index 964adc7d7af..40ea8166bf9 100644 --- a/yarn-project/end-to-end/src/e2e_non_contract_account.test.ts +++ b/yarn-project/end-to-end/src/e2e_non_contract_account.test.ts @@ -10,7 +10,7 @@ import { Wallet, toBigInt, } from '@aztec/aztec.js'; -import { siloNullifier } from '@aztec/circuits.js/abis'; +import { siloNullifier } from '@aztec/circuits.js/hash'; import { TestContract } from '@aztec/noir-contracts.js/Test'; import { setup } from './fixtures/utils.js'; diff --git a/yarn-project/foundation/src/abi/abi.ts b/yarn-project/foundation/src/abi/abi.ts index 406ff37aa99..cf32e19076a 100644 --- a/yarn-project/foundation/src/abi/abi.ts +++ b/yarn-project/foundation/src/abi/abi.ts @@ -1,6 +1,6 @@ import { inflate } from 'pako'; -import { type FunctionSelector } from './selector.js'; +import { type FunctionSelector } from './function_selector.js'; /** * A named type. diff --git a/yarn-project/foundation/src/abi/event_selector.ts b/yarn-project/foundation/src/abi/event_selector.ts new file mode 100644 index 00000000000..2f4c6a8b2d3 --- /dev/null +++ b/yarn-project/foundation/src/abi/event_selector.ts @@ -0,0 +1,73 @@ +import { fromHex, toBigIntBE } from '../bigint-buffer/index.js'; +import { keccak } from '../crypto/index.js'; +import { Fr } from '../fields/fields.js'; +import { BufferReader } from '../serialize/buffer_reader.js'; +import { Selector } from './selector.js'; + +/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */ + +/** Event selector branding */ +export interface EventSelector { + /** Brand. */ + _branding: 'EventSelector'; +} + +/** An event selector is the first 4 bytes of the hash of an event signature. */ +export class EventSelector extends Selector { + /** + * Deserializes from a buffer or reader, corresponding to a write in cpp. + * @param buffer - Buffer or BufferReader to read from. + * @returns The Selector. + */ + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + const value = Number(toBigIntBE(reader.readBytes(Selector.SIZE))); + return new EventSelector(value); + } + + /** + * Converts a field to selector. + * @param fr - The field to convert. + * @returns The selector. + */ + static fromField(fr: Fr) { + return new EventSelector(Number(fr.toBigInt())); + } + + /** + * Creates a selector from a signature. + * @param signature - Signature to generate the selector for (e.g. "transfer(field,field)"). + * @returns selector. + */ + static fromSignature(signature: string) { + // throw if signature contains whitespace + if (/\s/.test(signature)) { + throw new Error('Signature cannot contain whitespace'); + } + return EventSelector.fromBuffer(keccak(Buffer.from(signature)).subarray(0, Selector.SIZE)); + } + + /** + * Create a Selector instance from a hex-encoded string. + * The input 'address' should be prefixed with '0x' or not, and have exactly 64 hex characters. + * Throws an error if the input length is invalid or address value is out of range. + * + * @param selector - The hex-encoded string representing the Selector. + * @returns An Selector instance. + */ + static fromString(selector: string) { + const buf = fromHex(selector); + if (buf.length !== Selector.SIZE) { + throw new Error(`Invalid Selector length ${buf.length} (expected ${Selector.SIZE}).`); + } + return EventSelector.fromBuffer(buf); + } + + /** + * Creates an empty selector. + * @returns An empty selector. + */ + static empty() { + return new EventSelector(0); + } +} diff --git a/yarn-project/foundation/src/abi/function_selector.test.ts b/yarn-project/foundation/src/abi/function_selector.test.ts new file mode 100644 index 00000000000..0fae5417ef6 --- /dev/null +++ b/yarn-project/foundation/src/abi/function_selector.test.ts @@ -0,0 +1,27 @@ +import { FunctionSelector } from './function_selector.js'; + +describe('FunctionSelector', () => { + let selector: FunctionSelector; + + beforeAll(() => { + selector = FunctionSelector.random(); + }); + + it('serializes to buffer and deserializes it back', () => { + const buffer = selector.toBuffer(); + const res = FunctionSelector.fromBuffer(buffer); + expect(res).toEqual(selector); + expect(res.isEmpty()).toBe(false); + }); + + it('serializes to field and deserializes it back', () => { + const field = selector.toField(); + const res = FunctionSelector.fromField(field); + expect(res).toEqual(selector); + }); + + it('computes a function selector from signature', () => { + const res = FunctionSelector.fromSignature('transfer(address,uint256)'); + expect(res).toMatchSnapshot(); + }); +}); diff --git a/yarn-project/foundation/src/abi/function_selector.ts b/yarn-project/foundation/src/abi/function_selector.ts new file mode 100644 index 00000000000..fc0eaae752b --- /dev/null +++ b/yarn-project/foundation/src/abi/function_selector.ts @@ -0,0 +1,122 @@ +import { fromHex, toBigIntBE } from '../bigint-buffer/index.js'; +import { keccak, randomBytes } from '../crypto/index.js'; +import { Fr } from '../fields/fields.js'; +import { BufferReader } from '../serialize/buffer_reader.js'; +import { FieldReader } from '../serialize/field_reader.js'; +import { ABIParameter } from './abi.js'; +import { decodeFunctionSignature } from './decoder.js'; +import { Selector } from './selector.js'; + +/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */ + +/** Function selector branding */ +export interface FunctionSelector { + /** Brand. */ + _branding: 'FunctionSelector'; +} + +/** A function selector is the first 4 bytes of the hash of a function signature. */ +export class FunctionSelector extends Selector { + /** + * Checks if this function selector is equal to another. + * @returns True if the function selectors are equal. + */ + equals(otherName: string, otherParams: ABIParameter[]): boolean; + equals(other: FunctionSelector): boolean; + equals(other: FunctionSelector | string, otherParams?: ABIParameter[]): boolean { + if (typeof other === 'string') { + return this.equals(FunctionSelector.fromNameAndParameters(other, otherParams!)); + } + return this.value === other.value; + } + + /** + * Deserializes from a buffer or reader, corresponding to a write in cpp. + * @param buffer - Buffer or BufferReader to read from. + * @returns The Selector. + */ + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + const value = Number(toBigIntBE(reader.readBytes(Selector.SIZE))); + return new FunctionSelector(value); + } + + /** + * Converts a field to selector. + * @param fr - The field to convert. + * @returns The selector. + */ + static fromField(fr: Fr) { + return new FunctionSelector(Number(fr.toBigInt())); + } + + static fromFields(fields: Fr[] | FieldReader) { + const reader = FieldReader.asReader(fields); + return FunctionSelector.fromField(reader.readField()); + } + + /** + * Creates a selector from a signature. + * @param signature - Signature to generate the selector for (e.g. "transfer(field,field)"). + * @returns selector. + */ + static fromSignature(signature: string) { + // throw if signature contains whitespace + if (/\s/.test(signature)) { + throw new Error('Signature cannot contain whitespace'); + } + return FunctionSelector.fromBuffer(keccak(Buffer.from(signature)).subarray(0, Selector.SIZE)); + } + + /** + * Create a Selector instance from a hex-encoded string. + * The input 'address' should be prefixed with '0x' or not, and have exactly 64 hex characters. + * Throws an error if the input length is invalid or address value is out of range. + * + * @param selector - The hex-encoded string representing the Selector. + * @returns An Selector instance. + */ + static fromString(selector: string) { + const buf = fromHex(selector); + if (buf.length !== Selector.SIZE) { + throw new Error(`Invalid Selector length ${buf.length} (expected ${Selector.SIZE}).`); + } + return FunctionSelector.fromBuffer(buf); + } + + /** + * Creates an empty selector. + * @returns An empty selector. + */ + static empty() { + return new FunctionSelector(0); + } + + /** + * Creates a function selector for a given function name and parameters. + * @param name - The name of the function. + * @param parameters - An array of ABIParameter objects, each containing the type information of a function parameter. + * @returns A Buffer containing the 4-byte selector. + */ + static fromNameAndParameters(args: { name: string; parameters: ABIParameter[] }): FunctionSelector; + static fromNameAndParameters(name: string, parameters: ABIParameter[]): FunctionSelector; + static fromNameAndParameters( + nameOrArgs: string | { name: string; parameters: ABIParameter[] }, + maybeParameters?: ABIParameter[], + ): FunctionSelector { + const { name, parameters } = + typeof nameOrArgs === 'string' ? { name: nameOrArgs, parameters: maybeParameters! } : nameOrArgs; + const signature = decodeFunctionSignature(name, parameters); + const selector = this.fromSignature(signature); + // If using the debug logger here it kill the typing in the `server_world_state_synchronizer` and jest tests. + // console.log(`selector for ${signature} is ${selector}`); + return selector; + } + + /** + * Creates a random instance. + */ + static random() { + return FunctionSelector.fromBuffer(randomBytes(Selector.SIZE)); + } +} diff --git a/yarn-project/foundation/src/abi/index.ts b/yarn-project/foundation/src/abi/index.ts index 3fd28c16cc4..476d3da8850 100644 --- a/yarn-project/foundation/src/abi/index.ts +++ b/yarn-project/foundation/src/abi/index.ts @@ -1,6 +1,7 @@ export * from './abi.js'; export * from './buffer.js'; export * from './encoder.js'; +export * from './event_selector.js'; export * from './decoder.js'; -export * from './selector.js'; +export * from './function_selector.js'; export * from './utils.js'; diff --git a/yarn-project/foundation/src/abi/selector.ts b/yarn-project/foundation/src/abi/selector.ts index b4e8911b70a..1d92fa10f31 100644 --- a/yarn-project/foundation/src/abi/selector.ts +++ b/yarn-project/foundation/src/abi/selector.ts @@ -1,16 +1,8 @@ -import { randomBytes } from 'crypto'; - -import { fromHex, toBigIntBE, toBufferBE } from '../bigint-buffer/index.js'; -import { keccak } from '../crypto/keccak/index.js'; +import { toBufferBE } from '../bigint-buffer/index.js'; import { Fr } from '../fields/index.js'; -import { BufferReader, FieldReader } from '../serialize/index.js'; -import { type ABIParameter } from './abi.js'; -import { decodeFunctionSignature } from './decoder.js'; - -/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */ /** A selector is the first 4 bytes of the hash of a signature. */ -abstract class Selector { +export abstract class Selector { /** The size of the selector in bytes. */ public static SIZE = 4; @@ -63,181 +55,3 @@ abstract class Selector { return new Fr(BigInt(this.value)); } } - -/** Function selector branding */ -export interface FunctionSelector { - /** Brand. */ - _branding: 'FunctionSelector'; -} - -/** A function selector is the first 4 bytes of the hash of a function signature. */ -export class FunctionSelector extends Selector { - /** - * Checks if this function selector is equal to another. - * @returns True if the function selectors are equal. - */ - equals(otherName: string, otherParams: ABIParameter[]): boolean; - equals(other: FunctionSelector): boolean; - equals(other: FunctionSelector | string, otherParams?: ABIParameter[]): boolean { - if (typeof other === 'string') { - return this.equals(FunctionSelector.fromNameAndParameters(other, otherParams!)); - } - return this.value === other.value; - } - - /** - * Deserializes from a buffer or reader, corresponding to a write in cpp. - * @param buffer - Buffer or BufferReader to read from. - * @returns The Selector. - */ - static fromBuffer(buffer: Buffer | BufferReader) { - const reader = BufferReader.asReader(buffer); - const value = Number(toBigIntBE(reader.readBytes(Selector.SIZE))); - return new FunctionSelector(value); - } - - /** - * Converts a field to selector. - * @param fr - The field to convert. - * @returns The selector. - */ - static fromField(fr: Fr) { - return new FunctionSelector(Number(fr.toBigInt())); - } - - static fromFields(fields: Fr[] | FieldReader) { - const reader = FieldReader.asReader(fields); - return FunctionSelector.fromField(reader.readField()); - } - - /** - * Creates a selector from a signature. - * @param signature - Signature to generate the selector for (e.g. "transfer(field,field)"). - * @returns selector. - */ - static fromSignature(signature: string) { - // throw if signature contains whitespace - if (/\s/.test(signature)) { - throw new Error('Signature cannot contain whitespace'); - } - return FunctionSelector.fromBuffer(keccak(Buffer.from(signature)).subarray(0, Selector.SIZE)); - } - - /** - * Create a Selector instance from a hex-encoded string. - * The input 'address' should be prefixed with '0x' or not, and have exactly 64 hex characters. - * Throws an error if the input length is invalid or address value is out of range. - * - * @param selector - The hex-encoded string representing the Selector. - * @returns An Selector instance. - */ - static fromString(selector: string) { - const buf = fromHex(selector); - if (buf.length !== Selector.SIZE) { - throw new Error(`Invalid Selector length ${buf.length} (expected ${Selector.SIZE}).`); - } - return FunctionSelector.fromBuffer(buf); - } - - /** - * Creates an empty selector. - * @returns An empty selector. - */ - static empty() { - return new FunctionSelector(0); - } - - /** - * Creates a function selector for a given function name and parameters. - * @param name - The name of the function. - * @param parameters - An array of ABIParameter objects, each containing the type information of a function parameter. - * @returns A Buffer containing the 4-byte selector. - */ - static fromNameAndParameters(args: { name: string; parameters: ABIParameter[] }): FunctionSelector; - static fromNameAndParameters(name: string, parameters: ABIParameter[]): FunctionSelector; - static fromNameAndParameters( - nameOrArgs: string | { name: string; parameters: ABIParameter[] }, - maybeParameters?: ABIParameter[], - ): FunctionSelector { - const { name, parameters } = - typeof nameOrArgs === 'string' ? { name: nameOrArgs, parameters: maybeParameters! } : nameOrArgs; - const signature = decodeFunctionSignature(name, parameters); - const selector = this.fromSignature(signature); - // If using the debug logger here it kill the typing in the `server_world_state_synchronizer` and jest tests. - // console.log(`selector for ${signature} is ${selector}`); - return selector; - } - - /** - * Creates a random instance. - */ - static random() { - return FunctionSelector.fromBuffer(randomBytes(Selector.SIZE)); - } -} - -/** Event selector branding */ -export interface EventSelector { - /** Brand. */ - _branding: 'EventSelector'; -} - -/** An event selector is the first 4 bytes of the hash of an event signature. */ -export class EventSelector extends Selector { - /** - * Deserializes from a buffer or reader, corresponding to a write in cpp. - * @param buffer - Buffer or BufferReader to read from. - * @returns The Selector. - */ - static fromBuffer(buffer: Buffer | BufferReader) { - const reader = BufferReader.asReader(buffer); - const value = Number(toBigIntBE(reader.readBytes(Selector.SIZE))); - return new EventSelector(value); - } - - /** - * Converts a field to selector. - * @param fr - The field to convert. - * @returns The selector. - */ - static fromField(fr: Fr) { - return new EventSelector(Number(fr.toBigInt())); - } - - /** - * Creates a selector from a signature. - * @param signature - Signature to generate the selector for (e.g. "transfer(field,field)"). - * @returns selector. - */ - static fromSignature(signature: string) { - // throw if signature contains whitespace - if (/\s/.test(signature)) { - throw new Error('Signature cannot contain whitespace'); - } - return EventSelector.fromBuffer(keccak(Buffer.from(signature)).subarray(0, Selector.SIZE)); - } - - /** - * Create a Selector instance from a hex-encoded string. - * The input 'address' should be prefixed with '0x' or not, and have exactly 64 hex characters. - * Throws an error if the input length is invalid or address value is out of range. - * - * @param selector - The hex-encoded string representing the Selector. - * @returns An Selector instance. - */ - static fromString(selector: string) { - const buf = fromHex(selector); - if (buf.length !== Selector.SIZE) { - throw new Error(`Invalid Selector length ${buf.length} (expected ${Selector.SIZE}).`); - } - return EventSelector.fromBuffer(buf); - } - - /** - * Creates an empty selector. - * @returns An empty selector. - */ - static empty() { - return new EventSelector(0); - } -} diff --git a/yarn-project/foundation/src/abi/utils.ts b/yarn-project/foundation/src/abi/utils.ts index 91a61320daa..1959d5762b8 100644 --- a/yarn-project/foundation/src/abi/utils.ts +++ b/yarn-project/foundation/src/abi/utils.ts @@ -15,7 +15,7 @@ export function isAddressStruct(abiType: ABIType) { * @returns Boolean. */ export function isEthAddressStruct(abiType: ABIType) { - return abiType.kind === 'struct' && abiType.path.endsWith('types::address::EthAddress'); + return abiType.kind === 'struct' && abiType.path.endsWith('address::EthAddress'); } /** @@ -24,7 +24,7 @@ export function isEthAddressStruct(abiType: ABIType) { * @returns Boolean. */ export function isAztecAddressStruct(abiType: ABIType) { - return abiType.kind === 'struct' && abiType.path.endsWith('types::address::AztecAddress'); + return abiType.kind === 'struct' && abiType.path.endsWith('address::AztecAddress'); } /** diff --git a/yarn-project/noir-protocol-circuits-types/src/__snapshots__/index.test.ts.snap b/yarn-project/noir-protocol-circuits-types/src/__snapshots__/index.test.ts.snap index 99d3c7a1aaf..1453c66240c 100644 --- a/yarn-project/noir-protocol-circuits-types/src/__snapshots__/index.test.ts.snap +++ b/yarn-project/noir-protocol-circuits-types/src/__snapshots__/index.test.ts.snap @@ -1,62 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Noir compatibility tests (interop_testing.nr) Address from partial matches Noir 1`] = `"0x0447f893197175723deb223696e2e96dbba1e707ee8507766373558877e74197"`; - -exports[`Noir compatibility tests (interop_testing.nr) Address matches Noir 1`] = `"0x2fd71a4f0742364f194dd16d0ae32d2f47845ddc7f5d328f37d4148b565c4123"`; - -exports[`Noir compatibility tests (interop_testing.nr) ComputeContractAddressFromPartial matches Noir 1`] = `"0x0b487ff2900ae1178e131bfe333fdbc351beef658f7c0d62db2801429b1aab75"`; - -exports[`Noir compatibility tests (interop_testing.nr) Public call stack item matches noir 1`] = `"0x1f71c0d6bd03e409df694549b6aa83d706cfe55427152e6ec443ec64fa62d3a0"`; - -exports[`Noir compatibility tests (interop_testing.nr) Public call stack item request matches noir 1`] = `"0x2812dfeffdb7553fbbdd27c03fbdf61e3aa9bab3209db39f78838508ad892803"`; - -exports[`Noir compatibility tests (interop_testing.nr) Public key hash matches Noir 1`] = `"0x1923a6246e305720b6aaf751fde0342613e93c82e455c3831e28375c16dd40d8"`; - -exports[`Noir compatibility tests (interop_testing.nr) TxRequest Hash matches Noir 1`] = `"0x0b487ff2900ae1178e131bfe333fdbc351beef658f7c0d62db2801429b1aab75"`; - -exports[`Noir compatibility tests (interop_testing.nr) Var args hash matches noir 1`] = ` -Fr { - "asBigInt": 1557627899280963684159398665725097926236612957540256425197580046184563077271n, - "asBuffer": { - "data": [ - 3, - 113, - 150, - 13, - 216, - 78, - 211, - 68, - 90, - 176, - 153, - 172, - 76, - 26, - 245, - 186, - 144, - 224, - 199, - 19, - 181, - 147, - 224, - 202, - 82, - 238, - 83, - 32, - 135, - 199, - 240, - 151, - ], - "type": "Buffer", - }, -} -`; - exports[`Private kernel Executes private kernel inner for a nested call 1`] = ` PrivateKernelInnerCircuitPublicInputs { "aggregationObject": AggregationObject { diff --git a/yarn-project/noir-protocol-circuits-types/src/index.test.ts b/yarn-project/noir-protocol-circuits-types/src/index.test.ts index 45a625eda4b..30d4a9f0449 100644 --- a/yarn-project/noir-protocol-circuits-types/src/index.test.ts +++ b/yarn-project/noir-protocol-circuits-types/src/index.test.ts @@ -1,25 +1,8 @@ import { - AztecAddress, - ContractDeploymentData, - EthAddress, - FunctionData, - FunctionSelector, - Point, PrivateKernelInitCircuitPrivateInputs, PrivateKernelInnerCircuitPrivateInputs, PrivateKernelTailCircuitPrivateInputs, - PublicCallStackItem, - PublicCircuitPublicInputs, - SideEffect, - TxContext, - TxRequest, - computeContractAddressFromInstance, - computeContractAddressFromPartial, - computePublicKeysHash, } from '@aztec/circuits.js'; -import { computeTxHash, computeVarArgsHash } from '@aztec/circuits.js/abis'; -import { times } from '@aztec/foundation/collection'; -import { Fr } from '@aztec/foundation/fields'; import { DebugLogger, createDebugLogger } from '@aztec/foundation/log'; import { fileURLToPath } from '@aztec/foundation/url'; @@ -88,104 +71,3 @@ describe('Private kernel', () => { expect(kernelOutputs).toMatchSnapshot(); }); }); - -describe('Noir compatibility tests (interop_testing.nr)', () => { - // Tests in this file are to check that what we are computing in Noir - // is equivalent to what we were computing in circuits.js/the typescript implementation - // This is to ensure that we have not introduced any bugs in the transition from circuits.js to Noir - - it('Address matches Noir', () => { - const publicKey = new Point(new Fr(1n), new Fr(2n)); - const salt = new Fr(3n); - const contractClassId = new Fr(4n); - const initializationHash = new Fr(5n); - const portalContractAddress = EthAddress.fromField(new Fr(6n)); - - const address = computeContractAddressFromInstance({ - publicKeysHash: computePublicKeysHash(publicKey), - salt, - contractClassId, - initializationHash, - portalContractAddress, - version: 1, - }); - - expect(address.toString()).toMatchSnapshot(); - }); - - it('Public key hash matches Noir', () => { - const publicKey = new Point(new Fr(1n), new Fr(2n)); - expect(computePublicKeysHash(publicKey).toString()).toMatchSnapshot(); - }); - - it('Address from partial matches Noir', () => { - const publicKey = new Point(new Fr(1n), new Fr(2n)); - const partialAddress = new Fr(3n); - const address = computeContractAddressFromPartial({ publicKey, partialAddress }); - expect(address.toString()).toMatchSnapshot(); - }); - - it('TxRequest Hash matches Noir', () => { - const deploymentData = new ContractDeploymentData( - new Point(new Fr(1), new Fr(2)), - new Fr(1), - new Fr(2), - new Fr(3), - EthAddress.fromField(new Fr(1)), - ); - const txRequest = TxRequest.from({ - origin: AztecAddress.fromBigInt(1n), - functionData: new FunctionData(FunctionSelector.fromField(new Fr(2n)), false, true, true), - argsHash: new Fr(3), - txContext: new TxContext(false, false, true, deploymentData, Fr.ZERO, Fr.ZERO), - }); - const hash = computeTxHash(txRequest); - - expect(hash.toString()).toMatchSnapshot(); - }); - - it('ComputeContractAddressFromPartial matches Noir', () => { - const deploymentData = new ContractDeploymentData( - new Point(new Fr(1), new Fr(2)), - new Fr(1), - new Fr(2), - new Fr(3), - EthAddress.fromField(new Fr(1)), - ); - const txRequest = TxRequest.from({ - origin: AztecAddress.fromBigInt(1n), - functionData: new FunctionData(FunctionSelector.fromField(new Fr(2n)), false, true, true), - argsHash: new Fr(3), - txContext: new TxContext(false, false, true, deploymentData, Fr.ZERO, Fr.ZERO), - }); - const hash = computeTxHash(txRequest); - - expect(hash.toString()).toMatchSnapshot(); - }); - - it('Public call stack item matches noir', () => { - const contractAddress = AztecAddress.fromBigInt(1n); - const functionData = new FunctionData(new FunctionSelector(2), false, false, false); - const appPublicInputs = PublicCircuitPublicInputs.empty(); - appPublicInputs.newCommitments[0] = new SideEffect(new Fr(1), Fr.ZERO); - - const publicCallStackItem = new PublicCallStackItem(contractAddress, functionData, appPublicInputs, false); - expect(publicCallStackItem.hash().toString()).toMatchSnapshot(); - }); - - it('Public call stack item request matches noir', () => { - const contractAddress = AztecAddress.fromBigInt(1n); - const functionData = new FunctionData(new FunctionSelector(2), false, false, false); - const appPublicInputs = PublicCircuitPublicInputs.empty(); - appPublicInputs.newCommitments[0] = new SideEffect(new Fr(1), Fr.ZERO); - - const publicCallStackItem = new PublicCallStackItem(contractAddress, functionData, appPublicInputs, true); - expect(publicCallStackItem.hash().toString()).toMatchSnapshot(); - }); - - it('Var args hash matches noir', () => { - const args = times(800, i => new Fr(i)); - const res = computeVarArgsHash(args); - expect(res).toMatchSnapshot(); - }); -}); diff --git a/yarn-project/pxe/src/kernel_prover/proof_creator.ts b/yarn-project/pxe/src/kernel_prover/proof_creator.ts index 2f1e24c2de8..bd53ce0e56e 100644 --- a/yarn-project/pxe/src/kernel_prover/proof_creator.ts +++ b/yarn-project/pxe/src/kernel_prover/proof_creator.ts @@ -9,7 +9,7 @@ import { Proof, makeEmptyProof, } from '@aztec/circuits.js'; -import { siloCommitment } from '@aztec/circuits.js/abis'; +import { siloCommitment } from '@aztec/circuits.js/hash'; import { Fr } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; import { elapsed } from '@aztec/foundation/timer'; diff --git a/yarn-project/pxe/src/note_processor/produce_note_dao.ts b/yarn-project/pxe/src/note_processor/produce_note_dao.ts index a57f0ffb33e..23823c7d5fe 100644 --- a/yarn-project/pxe/src/note_processor/produce_note_dao.ts +++ b/yarn-project/pxe/src/note_processor/produce_note_dao.ts @@ -1,6 +1,6 @@ import { L1NotePayload, TxHash } from '@aztec/circuit-types'; import { Fr, PublicKey } from '@aztec/circuits.js'; -import { computeCommitmentNonce, siloNullifier } from '@aztec/circuits.js/abis'; +import { computeCommitmentNonce, siloNullifier } from '@aztec/circuits.js/hash'; import { AcirSimulator } from '@aztec/simulator'; import { NoteDao } from '../database/note_dao.js'; diff --git a/yarn-project/pxe/src/pxe_service/pxe_service.ts b/yarn-project/pxe/src/pxe_service/pxe_service.ts index f08954f0131..dd73dadef97 100644 --- a/yarn-project/pxe/src/pxe_service/pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/pxe_service.ts @@ -41,7 +41,7 @@ import { computeSaltedInitializationHash, getContractClassFromArtifact, } from '@aztec/circuits.js'; -import { computeCommitmentNonce, siloNullifier } from '@aztec/circuits.js/abis'; +import { computeCommitmentNonce, siloNullifier } from '@aztec/circuits.js/hash'; import { DecodedReturn, encodeArguments } from '@aztec/foundation/abi'; import { padArrayEnd } from '@aztec/foundation/collection'; import { Fr } from '@aztec/foundation/fields'; diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts index ff09a3ef432..b3743a99dc9 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts @@ -36,7 +36,6 @@ import { SideEffectLinkedToNoteHash, StateReference, } from '@aztec/circuits.js'; -import { computeContractLeaf } from '@aztec/circuits.js/abis'; import { fr, makeBaseOrMergeRollupPublicInputs, @@ -132,7 +131,7 @@ describe('sequencer/solo_block_builder', () => { // Updates the expectedDb trees based on the new commitments, contracts, and nullifiers from these txs const updateExpectedTreesFromTxs = async (txs: ProcessedTx[]) => { - const newContracts = txs.flatMap(tx => tx.data.end.newContracts.map(n => computeContractLeaf(n))); + const newContracts = txs.flatMap(tx => tx.data.end.newContracts.map(cd => cd.computeLeaf())); for (const [tree, leaves] of [ [MerkleTreeId.NOTE_HASH_TREE, txs.flatMap(tx => tx.data.end.newCommitments.map(l => l.value.toBuffer()))], [MerkleTreeId.CONTRACT_TREE, newContracts.map(x => x.toBuffer())], @@ -216,7 +215,7 @@ describe('sequencer/solo_block_builder', () => { const newNullifiers = txs.flatMap(tx => tx.data.end.newNullifiers); const newCommitments = txs.flatMap(tx => tx.data.end.newCommitments); - const newContracts = txs.flatMap(tx => tx.data.end.newContracts).map(cd => computeContractLeaf(cd)); + const newContracts = txs.flatMap(tx => tx.data.end.newContracts).map(cd => cd.computeLeaf()); const newContractData = txs .flatMap(tx => tx.data.end.newContracts) .map(n => new ContractData(n.contractAddress, n.portalContractAddress)); diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts index 8185459f872..d2e670e89d7 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -42,7 +42,6 @@ import { VK_TREE_HEIGHT, VerificationKey, } from '@aztec/circuits.js'; -import { computeContractLeaf } from '@aztec/circuits.js/abis'; import { makeTuple } from '@aztec/foundation/array'; import { toBigIntBE } from '@aztec/foundation/bigint-buffer'; import { padArrayEnd } from '@aztec/foundation/collection'; @@ -104,7 +103,7 @@ export class SoloBlockBuilder implements BlockBuilder { // Collect all new nullifiers, commitments, and contracts from all txs in this block const newNullifiers = txs.flatMap(tx => tx.data.end.newNullifiers); const newCommitments = txs.flatMap(tx => tx.data.end.newCommitments); - const newContracts = txs.flatMap(tx => tx.data.end.newContracts).map(cd => computeContractLeaf(cd)); + const newContracts = txs.flatMap(tx => tx.data.end.newContracts).map(cd => cd.computeLeaf()); const newContractData = txs .flatMap(tx => tx.data.end.newContracts) .map(n => new ContractData(n.contractAddress, n.portalContractAddress)); @@ -616,7 +615,7 @@ export class SoloBlockBuilder implements BlockBuilder { // Update the contract and note hash trees with the new items being inserted to get the new roots // that will be used by the next iteration of the base rollup circuit, skipping the empty ones - const newContracts = tx.data.end.newContracts.map(cd => computeContractLeaf(cd)); + const newContracts = tx.data.end.newContracts.map(cd => cd.computeLeaf()); const newCommitments = tx.data.end.newCommitments.map(x => x.value.toBuffer()); await this.db.appendLeaves( MerkleTreeId.CONTRACT_TREE, diff --git a/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts b/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts index 6b9890f57ad..4db7c574689 100644 --- a/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts +++ b/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts @@ -33,7 +33,7 @@ import { SideEffectLinkedToNoteHash, VK_TREE_HEIGHT, } from '@aztec/circuits.js'; -import { computeVarArgsHash } from '@aztec/circuits.js/abis'; +import { computeVarArgsHash } from '@aztec/circuits.js/hash'; import { arrayNonEmptyLength, padArrayEnd } from '@aztec/foundation/collection'; import { createDebugLogger } from '@aztec/foundation/log'; import { to2Fields } from '@aztec/foundation/serialize'; diff --git a/yarn-project/sequencer-client/src/simulator/public_executor.ts b/yarn-project/sequencer-client/src/simulator/public_executor.ts index 5d9ac0cd000..a707355b751 100644 --- a/yarn-project/sequencer-client/src/simulator/public_executor.ts +++ b/yarn-project/sequencer-client/src/simulator/public_executor.ts @@ -7,7 +7,7 @@ import { L1_TO_L2_MSG_TREE_HEIGHT, PublicDataTreeLeafPreimage, } from '@aztec/circuits.js'; -import { computePublicDataTreeLeafSlot } from '@aztec/circuits.js/abis'; +import { computePublicDataTreeLeafSlot } from '@aztec/circuits.js/hash'; import { CommitmentsDB, MessageLoadOracleInputs, PublicContractsDB, PublicStateDB } from '@aztec/simulator'; import { MerkleTreeOperations } from '@aztec/world-state'; diff --git a/yarn-project/sequencer-client/src/simulator/world_state_public_db.test.ts b/yarn-project/sequencer-client/src/simulator/world_state_public_db.test.ts index acfa1675c32..885abc0b192 100644 --- a/yarn-project/sequencer-client/src/simulator/world_state_public_db.test.ts +++ b/yarn-project/sequencer-client/src/simulator/world_state_public_db.test.ts @@ -1,6 +1,6 @@ import { MerkleTreeId } from '@aztec/circuit-types'; import { AztecAddress, Fr, PublicDataTreeLeafPreimage } from '@aztec/circuits.js'; -import { computePublicDataTreeLeafSlot } from '@aztec/circuits.js/abis'; +import { computePublicDataTreeLeafSlot } from '@aztec/circuits.js/hash'; import { IndexedTreeLeafPreimage } from '@aztec/foundation/trees'; import { MerkleTreeOperations } from '@aztec/world-state'; diff --git a/yarn-project/simulator/src/client/client_execution_context.ts b/yarn-project/simulator/src/client/client_execution_context.ts index 1f4f555ec28..b5c78c45532 100644 --- a/yarn-project/simulator/src/client/client_execution_context.ts +++ b/yarn-project/simulator/src/client/client_execution_context.ts @@ -18,8 +18,8 @@ import { SideEffect, TxContext, } from '@aztec/circuits.js'; -import { computePublicDataTreeLeafSlot, computeUniqueCommitment, siloCommitment } from '@aztec/circuits.js/abis'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; +import { computePublicDataTreeLeafSlot, computeUniqueCommitment, siloCommitment } from '@aztec/circuits.js/hash'; import { FunctionAbi, FunctionArtifact, countArgumentsSize } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr, Point } from '@aztec/foundation/fields'; diff --git a/yarn-project/simulator/src/client/execution_note_cache.ts b/yarn-project/simulator/src/client/execution_note_cache.ts index dab6e05fd97..ad4be3e8c34 100644 --- a/yarn-project/simulator/src/client/execution_note_cache.ts +++ b/yarn-project/simulator/src/client/execution_note_cache.ts @@ -1,4 +1,4 @@ -import { siloNullifier } from '@aztec/circuits.js/abis'; +import { siloNullifier } from '@aztec/circuits.js/hash'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; diff --git a/yarn-project/simulator/src/client/private_execution.test.ts b/yarn-project/simulator/src/client/private_execution.test.ts index 49ca7fcf196..d5738bb7394 100644 --- a/yarn-project/simulator/src/client/private_execution.test.ts +++ b/yarn-project/simulator/src/client/private_execution.test.ts @@ -19,13 +19,13 @@ import { nonEmptySideEffects, sideEffectArrayToValueArray, } from '@aztec/circuits.js'; +import { makeContractDeploymentData, makeHeader } from '@aztec/circuits.js/factories'; import { computeCommitmentNonce, - computeSecretMessageHash, + computeMessageSecretHash, computeVarArgsHash, siloCommitment, -} from '@aztec/circuits.js/abis'; -import { makeContractDeploymentData, makeHeader } from '@aztec/circuits.js/factories'; +} from '@aztec/circuits.js/hash'; import { FunctionArtifact, FunctionSelector, @@ -792,7 +792,7 @@ describe('Private Execution test suite', () => { const artifact = getFunctionArtifact(TokenContractArtifact, 'redeem_shield'); const secret = new Fr(1n); - const secretHash = computeSecretMessageHash(secret); + const secretHash = computeMessageSecretHash(secret); const note = new Note([new Fr(amount), secretHash]); const noteHash = hashFields(note.items); const storageSlot = new Fr(5); diff --git a/yarn-project/simulator/src/client/simulator.test.ts b/yarn-project/simulator/src/client/simulator.test.ts index 0449969d275..a3924578b59 100644 --- a/yarn-project/simulator/src/client/simulator.test.ts +++ b/yarn-project/simulator/src/client/simulator.test.ts @@ -1,6 +1,6 @@ import { AztecNode, Note } from '@aztec/circuit-types'; import { CompleteAddress } from '@aztec/circuits.js'; -import { computeUniqueCommitment, siloCommitment } from '@aztec/circuits.js/abis'; +import { computeUniqueCommitment, siloCommitment } from '@aztec/circuits.js/hash'; import { ABIParameterVisibility, FunctionArtifactWithDebugMetadata, getFunctionArtifact } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { pedersenHash } from '@aztec/foundation/crypto'; diff --git a/yarn-project/simulator/src/client/view_data_oracle.ts b/yarn-project/simulator/src/client/view_data_oracle.ts index 5edf08a504f..20622b30681 100644 --- a/yarn-project/simulator/src/client/view_data_oracle.ts +++ b/yarn-project/simulator/src/client/view_data_oracle.ts @@ -8,7 +8,7 @@ import { PublicDataWitness, } from '@aztec/circuit-types'; import { Header } from '@aztec/circuits.js'; -import { siloNullifier } from '@aztec/circuits.js/abis'; +import { siloNullifier } from '@aztec/circuits.js/hash'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; diff --git a/yarn-project/simulator/src/public/execution.ts b/yarn-project/simulator/src/public/execution.ts index 5fb8b43be59..abc04da1400 100644 --- a/yarn-project/simulator/src/public/execution.ts +++ b/yarn-project/simulator/src/public/execution.ts @@ -12,7 +12,7 @@ import { SideEffect, SideEffectLinkedToNoteHash, } from '@aztec/circuits.js'; -import { computePublicDataTreeLeafSlot, computePublicDataTreeValue } from '@aztec/circuits.js/abis'; +import { computePublicDataTreeLeafSlot, computePublicDataTreeValue } from '@aztec/circuits.js/hash'; /** * The public function execution result. diff --git a/yarn-project/simulator/src/test/utils.ts b/yarn-project/simulator/src/test/utils.ts index 916243400e4..e38b80aaec0 100644 --- a/yarn-project/simulator/src/test/utils.ts +++ b/yarn-project/simulator/src/test/utils.ts @@ -1,6 +1,6 @@ import { L1Actor, L1ToL2Message, L2Actor } from '@aztec/circuit-types'; import { AztecAddress, EthAddress, Fr } from '@aztec/circuits.js'; -import { computeSecretMessageHash } from '@aztec/circuits.js/abis'; +import { computeMessageSecretHash } from '@aztec/circuits.js/hash'; import { sha256 } from '@aztec/foundation/crypto'; /** @@ -23,7 +23,7 @@ export const buildL1ToL2Message = ( const contentBuf = Buffer.concat([selectorBuf, ...contentPreimage.map(field => field.toBuffer())]); const content = Fr.fromBufferReduce(sha256(contentBuf)); - const secretHash = computeSecretMessageHash(secret); + const secretHash = computeMessageSecretHash(secret); // Eventually the kernel will need to prove the kernel portal pair exists within the contract tree, // EthAddress.random() will need to be replaced when this happens