diff --git a/LICENSE b/LICENSE index f49a4e16e68..8dada3edaf5 100644 --- a/LICENSE +++ b/LICENSE @@ -178,7 +178,7 @@ APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" + boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -198,4 +198,4 @@ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file + limitations under the License. diff --git a/barretenberg/.gitrepo b/barretenberg/.gitrepo index 2be7fa7603f..91492d1465b 100644 --- a/barretenberg/.gitrepo +++ b/barretenberg/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/barretenberg branch = master - commit = bef9e485a04357d998c6e043713180822ebae7c5 - parent = 49f80b30db59e2454347c4b742d536e317305f2e + commit = 5e751b81cd5e5f34d9286d5a19ea6d4853566480 + parent = 887c01103255ea4cbbb6cb33c8771d47123b3bff method = merge cmdver = 0.4.6 diff --git a/barretenberg/cpp/src/barretenberg/crypto/merkle_tree/indexed_tree/content_addressed_indexed_tree.hpp b/barretenberg/cpp/src/barretenberg/crypto/merkle_tree/indexed_tree/content_addressed_indexed_tree.hpp index e1a47ec5351..197f784d59f 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/merkle_tree/indexed_tree/content_addressed_indexed_tree.hpp +++ b/barretenberg/cpp/src/barretenberg/crypto/merkle_tree/indexed_tree/content_addressed_indexed_tree.hpp @@ -252,20 +252,18 @@ class ContentAddressedIndexedTree : public ContentAddressedAppendOnlyTree> new_leaf; + IndexedLeafValueType new_leaf; + index_t new_leaf_index; }; struct SequentialInsertionGenerationResponse { - std::vector updates_to_perform; + std::shared_ptr> updates_to_perform; index_t highest_index; }; using SequentialInsertionGenerationCallback = - std::function&)>; + std::function&)>; void generate_sequential_insertions(const std::vector& values, const SequentialInsertionGenerationCallback& completion); @@ -1424,14 +1422,6 @@ void ContentAddressedIndexedTree::add_or_update_values_seq const AddSequentiallyCompletionCallbackWithWitness& completion, bool capture_witness) { - - // This struct is used to collect some state from the asynchronous operations we are about to perform - struct IntermediateResults { - std::vector updates_to_perform; - size_t appended_leaves = 0; - }; - auto results = std::make_shared(); - auto on_error = [=](const std::string& message) { try { TypedResponse> response; @@ -1453,7 +1443,7 @@ void ContentAddressedIndexedTree::add_or_update_values_seq ReadTransactionPtr tx = store_->create_read_transaction(); store_->get_meta(meta, *tx, true); - index_t new_total_size = results->appended_leaves + meta.size; + index_t new_total_size = values.size() + meta.size; meta.size = new_total_size; meta.root = store_->get_current_root(*tx, true); @@ -1462,29 +1452,23 @@ void ContentAddressedIndexedTree::add_or_update_values_seq if (capture_witness) { // Split results->update_witnesses between low_leaf_witness_data and insertion_witness_data + // Currently we always insert an empty leaf, even if it's an update, so we can split based + // on the index of the witness data response.inner.insertion_witness_data = std::make_shared>>(); - response.inner.insertion_witness_data->reserve(results->updates_to_perform.size()); - + ; response.inner.low_leaf_witness_data = std::make_shared>>(); - response.inner.low_leaf_witness_data->reserve(results->updates_to_perform.size()); - - size_t current_witness_index = 0; - for (size_t i = 0; i < results->updates_to_perform.size(); ++i) { - LeafUpdateWitnessData low_leaf_witness = - updates_completion_response.inner.update_witnesses->at(current_witness_index++); - response.inner.low_leaf_witness_data->push_back(low_leaf_witness); - - // If this update has an insertion, append the real witness - if (results->updates_to_perform.at(i).new_leaf.has_value()) { - LeafUpdateWitnessData insertion_witness = - updates_completion_response.inner.update_witnesses->at(current_witness_index++); - response.inner.insertion_witness_data->push_back(insertion_witness); + ; + + for (size_t i = 0; i < updates_completion_response.inner.update_witnesses->size(); ++i) { + LeafUpdateWitnessData& witness_data = + updates_completion_response.inner.update_witnesses->at(i); + // If even, it's a low leaf, if odd, it's an insertion witness + if (i % 2 == 0) { + response.inner.low_leaf_witness_data->push_back(witness_data); } else { - // If it's an update, append an empty witness - response.inner.insertion_witness_data->push_back(LeafUpdateWitnessData{ - .leaf = IndexedLeafValueType::empty(), .index = 0, .path = std::vector(depth_) }); + response.inner.insertion_witness_data->push_back(witness_data); } } } @@ -1496,33 +1480,23 @@ void ContentAddressedIndexedTree::add_or_update_values_seq // This signals the completion of the insertion data generation // Here we'll perform all updates to the tree SequentialInsertionGenerationCallback insertion_generation_completed = - [=, this](TypedResponse& insertion_response) { + [=, this](const TypedResponse& insertion_response) { if (!insertion_response.success) { on_error(insertion_response.message); return; } std::shared_ptr> flat_updates = std::make_shared>(); - flat_updates->reserve(insertion_response.inner.updates_to_perform.size() * 2); - - for (size_t i = 0; i < insertion_response.inner.updates_to_perform.size(); ++i) { - InsertionUpdates& insertion_update = insertion_response.inner.updates_to_perform.at(i); + for (size_t i = 0; i < insertion_response.inner.updates_to_perform->size(); ++i) { + InsertionUpdates& insertion_update = insertion_response.inner.updates_to_perform->at(i); flat_updates->push_back(insertion_update.low_leaf_update); - if (insertion_update.new_leaf.has_value()) { - results->appended_leaves++; - IndexedLeafValueType new_leaf; - index_t new_leaf_index = 0; - std::tie(new_leaf, new_leaf_index) = insertion_update.new_leaf.value(); - flat_updates->push_back(LeafUpdate{ - .leaf_index = new_leaf_index, - .updated_leaf = new_leaf, - .original_leaf = IndexedLeafValueType::empty(), - }); - } + flat_updates->push_back(LeafUpdate{ + .leaf_index = insertion_update.new_leaf_index, + .updated_leaf = insertion_update.new_leaf, + .original_leaf = IndexedLeafValueType::empty(), + }); } - // We won't use anymore updates_to_perform - results->updates_to_perform = std::move(insertion_response.inner.updates_to_perform); - assert(insertion_response.inner.updates_to_perform.size() == 0); + if (capture_witness) { perform_updates(flat_updates->size(), flat_updates, final_completion); return; @@ -1540,12 +1514,27 @@ void ContentAddressedIndexedTree::generate_sequential_inse { execute_and_report( [=, this](TypedResponse& response) { + response.inner.highest_index = 0; + response.inner.updates_to_perform = std::make_shared>(); + TreeMeta meta; ReadTransactionPtr tx = store_->create_read_transaction(); store_->get_meta(meta, *tx, true); RequestContext requestContext; requestContext.includeUncommitted = true; + // Ensure that the tree is not going to be overfilled + index_t new_total_size = values.size() + meta.size; + if (new_total_size > max_size_) { + throw std::runtime_error(format("Unable to insert values into tree ", + meta.name, + " new size: ", + new_total_size, + " max size: ", + max_size_)); + } + // The highest index touched will be the last leaf index, since we append a zero for updates + response.inner.highest_index = new_total_size - 1; requestContext.root = store_->get_current_root(*tx, true); // Fetch the frontier (non empty nodes to the right) of the tree. This will ensure that perform_updates or // perform_updates_without_witness has all the cached nodes it needs to perform the insertions. See comment @@ -1554,15 +1543,12 @@ void ContentAddressedIndexedTree::generate_sequential_inse find_leaf_hash(meta.size - 1, requestContext, *tx, true); } - index_t current_size = meta.size; - for (size_t i = 0; i < values.size(); ++i) { const LeafValueType& new_payload = values[i]; - // TODO(Alvaro) - Rethink this. I think it's fine for us to interpret empty values as a regular update - // (it'd empty out the payload of the zero leaf) if (new_payload.is_empty()) { continue; } + index_t index_of_new_leaf = i + meta.size; fr value = new_payload.get_key(); // This gives us the leaf that need updating @@ -1609,17 +1595,17 @@ void ContentAddressedIndexedTree::generate_sequential_inse .updated_leaf = IndexedLeafValueType::empty(), .original_leaf = low_leaf, }, - .new_leaf = std::nullopt, + .new_leaf = IndexedLeafValueType::empty(), + .new_leaf_index = index_of_new_leaf, }; if (!is_already_present) { // Update the current leaf to point it to the new leaf IndexedLeafValueType new_leaf = IndexedLeafValueType(new_payload, low_leaf.nextIndex, low_leaf.nextValue); - index_t index_of_new_leaf = current_size; + low_leaf.nextIndex = index_of_new_leaf; low_leaf.nextValue = value; - current_size++; // Cache the new leaf store_->set_leaf_key_at_index(index_of_new_leaf, new_leaf); store_->put_cached_leaf_by_index(index_of_new_leaf, new_leaf); @@ -1627,7 +1613,7 @@ void ContentAddressedIndexedTree::generate_sequential_inse store_->put_cached_leaf_by_index(low_leaf_index, low_leaf); insertion_update.low_leaf_update.updated_leaf = low_leaf; - insertion_update.new_leaf = std::pair(new_leaf, index_of_new_leaf); + insertion_update.new_leaf = new_leaf; } else if (IndexedLeafValueType::is_updateable()) { // Update the current leaf's value, don't change it's link IndexedLeafValueType replacement_leaf = @@ -1645,20 +1631,8 @@ void ContentAddressedIndexedTree::generate_sequential_inse " is already present")); } - response.inner.updates_to_perform.push_back(insertion_update); - } - - // Ensure that the tree is not going to be overfilled - if (current_size > max_size_) { - throw std::runtime_error(format("Unable to insert values into tree ", - meta.name, - " new size: ", - current_size, - " max size: ", - max_size_)); + response.inner.updates_to_perform->push_back(insertion_update); } - // The highest index touched will be current_size - 1 - response.inner.highest_index = current_size - 1; }, completion); } diff --git a/barretenberg/cpp/src/barretenberg/crypto/merkle_tree/indexed_tree/indexed_leaf.hpp b/barretenberg/cpp/src/barretenberg/crypto/merkle_tree/indexed_tree/indexed_leaf.hpp index bc13a93e598..615f2ce4cf2 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/merkle_tree/indexed_tree/indexed_leaf.hpp +++ b/barretenberg/cpp/src/barretenberg/crypto/merkle_tree/indexed_tree/indexed_leaf.hpp @@ -107,7 +107,7 @@ struct PublicDataLeafValue { fr get_key() const { return slot; } - bool is_empty() const { return slot == fr::zero() && value == fr::zero(); } + bool is_empty() const { return slot == fr::zero(); } std::vector get_hash_inputs(fr nextValue, fr nextIndex) const { diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/trace/gadgets/merkle_tree.cpp b/barretenberg/cpp/src/barretenberg/vm/avm/trace/gadgets/merkle_tree.cpp index 32a1e7eec2b..00171489efa 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/trace/gadgets/merkle_tree.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/trace/gadgets/merkle_tree.cpp @@ -102,8 +102,12 @@ FF AvmMerkleTreeTraceBuilder::perform_storage_write([[maybe_unused]] uint32_t cl // We update the low value low_preimage.value = value; FF low_preimage_hash = unconstrained_hash_public_data_preimage(low_preimage); - // Update the low leaf - return unconstrained_update_leaf_index(low_preimage_hash, static_cast(low_index), low_path); + // Update the low leaf - this will be returned in future + [[maybe_unused]] FF root = + unconstrained_update_leaf_index(low_preimage_hash, static_cast(low_index), low_path); + // TEMPORARY UNTIL WE CHANGE HOW UPDATES WORK + // Insert a zero leaf at the insertion index + return unconstrained_update_leaf_index(FF::zero(), static_cast(insertion_index), insertion_path); } // The new leaf for an insertion is PublicDataTreeLeafPreimage new_preimage{ diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index 0e095c7335c..31ec0c2410a 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -28,8 +28,7 @@ library Constants { uint256 internal constant MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL = 16; uint256 internal constant MAX_L1_TO_L2_MSG_READ_REQUESTS_PER_CALL = 16; uint256 internal constant MAX_KEY_VALIDATION_REQUESTS_PER_CALL = 16; - uint256 internal constant MAX_NOTE_ENCRYPTED_LOGS_PER_CALL = 16; - uint256 internal constant MAX_ENCRYPTED_LOGS_PER_CALL = 4; + uint256 internal constant MAX_PRIVATE_LOGS_PER_CALL = 16; uint256 internal constant MAX_UNENCRYPTED_LOGS_PER_CALL = 4; uint256 internal constant MAX_CONTRACT_CLASS_LOGS_PER_CALL = 1; uint256 internal constant ARCHIVE_HEIGHT = 29; @@ -67,8 +66,7 @@ library Constants { uint256 internal constant MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX = 64; uint256 internal constant MAX_L1_TO_L2_MSG_READ_REQUESTS_PER_TX = 64; uint256 internal constant MAX_KEY_VALIDATION_REQUESTS_PER_TX = 64; - uint256 internal constant MAX_NOTE_ENCRYPTED_LOGS_PER_TX = 64; - uint256 internal constant MAX_ENCRYPTED_LOGS_PER_TX = 8; + uint256 internal constant MAX_PRIVATE_LOGS_PER_TX = 32; uint256 internal constant MAX_UNENCRYPTED_LOGS_PER_TX = 8; uint256 internal constant MAX_CONTRACT_CLASS_LOGS_PER_TX = 1; uint256 internal constant NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP = 16; @@ -92,7 +90,7 @@ library Constants { uint256 internal constant FUNCTION_SELECTOR_NUM_BYTES = 4; uint256 internal constant INITIALIZATION_SLOT_SEPARATOR = 1000000000; uint256 internal constant INITIAL_L2_BLOCK_NUM = 1; - uint256 internal constant PRIVATE_LOG_SIZE_IN_BYTES = 576; + uint256 internal constant PRIVATE_LOG_SIZE_IN_FIELDS = 18; uint256 internal constant BLOB_SIZE_IN_BYTES = 126976; uint256 internal constant AZTEC_MAX_EPOCH_DURATION = 32; uint256 internal constant GENESIS_ARCHIVE_ROOT = @@ -131,6 +129,7 @@ library Constants { uint256 internal constant L2_GAS_PER_NULLIFIER_READ_REQUEST = 2400; uint256 internal constant L2_GAS_PER_L1_TO_L2_MSG_READ_REQUEST = 1170; uint256 internal constant L2_GAS_PER_LOG_BYTE = 4; + uint256 internal constant L2_GAS_PER_PRIVATE_LOG = 0; uint256 internal constant L2_GAS_PER_L2_TO_L1_MSG = 200; uint256 internal constant MAX_PROTOCOL_CONTRACTS = 7; uint256 internal constant CANONICAL_AUTH_REGISTRY_ADDRESS = 1; @@ -179,11 +178,10 @@ library Constants { uint256 internal constant PARTIAL_STATE_REFERENCE_LENGTH = 6; uint256 internal constant READ_REQUEST_LENGTH = 2; uint256 internal constant TREE_LEAF_READ_REQUEST_LENGTH = 2; + uint256 internal constant PRIVATE_LOG_DATA_LENGTH = 20; + uint256 internal constant SCOPED_PRIVATE_LOG_DATA_LENGTH = 21; uint256 internal constant LOG_HASH_LENGTH = 3; uint256 internal constant SCOPED_LOG_HASH_LENGTH = 4; - uint256 internal constant ENCRYPTED_LOG_HASH_LENGTH = 4; - uint256 internal constant SCOPED_ENCRYPTED_LOG_HASH_LENGTH = 5; - uint256 internal constant NOTE_LOG_HASH_LENGTH = 4; uint256 internal constant NOTE_HASH_LENGTH = 2; uint256 internal constant SCOPED_NOTE_HASH_LENGTH = 3; uint256 internal constant NULLIFIER_LENGTH = 3; @@ -202,7 +200,7 @@ library Constants { uint256 internal constant TOTAL_FEES_LENGTH = 1; uint256 internal constant TOTAL_MANA_USED_LENGTH = 1; uint256 internal constant HEADER_LENGTH = 25; - uint256 internal constant PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 491; + uint256 internal constant PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 731; uint256 internal constant PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = 867; uint256 internal constant PRIVATE_CONTEXT_INPUTS_LENGTH = 38; uint256 internal constant FEE_RECIPIENT_LENGTH = 2; @@ -210,16 +208,16 @@ library Constants { uint256 internal constant SCOPED_READ_REQUEST_LEN = 3; uint256 internal constant PUBLIC_DATA_READ_LENGTH = 3; uint256 internal constant PRIVATE_VALIDATION_REQUESTS_LENGTH = 772; - uint256 internal constant COMBINED_ACCUMULATED_DATA_LENGTH = 550; + uint256 internal constant COMBINED_ACCUMULATED_DATA_LENGTH = 900; uint256 internal constant TX_CONSTANT_DATA_LENGTH = 35; uint256 internal constant COMBINED_CONSTANT_DATA_LENGTH = 44; - uint256 internal constant PRIVATE_ACCUMULATED_DATA_LENGTH = 1036; - uint256 internal constant PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1850; - uint256 internal constant PRIVATE_TO_PUBLIC_ACCUMULATED_DATA_LENGTH = 548; + uint256 internal constant PRIVATE_ACCUMULATED_DATA_LENGTH = 1412; + uint256 internal constant PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 2226; + uint256 internal constant PRIVATE_TO_PUBLIC_ACCUMULATED_DATA_LENGTH = 900; uint256 internal constant PRIVATE_TO_AVM_ACCUMULATED_DATA_LENGTH = 160; uint256 internal constant NUM_PRIVATE_TO_AVM_ACCUMULATED_DATA_ARRAYS = 3; - uint256 internal constant PRIVATE_TO_PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1141; - uint256 internal constant KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 606; + uint256 internal constant PRIVATE_TO_PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1845; + uint256 internal constant KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 956; uint256 internal constant CONSTANT_ROLLUP_DATA_LENGTH = 13; uint256 internal constant BASE_OR_MERGE_PUBLIC_INPUTS_LENGTH = 31; uint256 internal constant BLOCK_ROOT_OR_BLOCK_MERGE_PUBLIC_INPUTS_LENGTH = 90; @@ -228,6 +226,7 @@ library Constants { uint256 internal constant NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP = 2048; uint256 internal constant NULLIFIERS_NUM_BYTES_PER_BASE_ROLLUP = 2048; uint256 internal constant PUBLIC_DATA_WRITES_NUM_BYTES_PER_BASE_ROLLUP = 4096; + uint256 internal constant PRIVATE_LOGS_NUM_BYTES_PER_BASE_ROLLUP = 18432; uint256 internal constant CONTRACTS_NUM_BYTES_PER_BASE_ROLLUP = 32; uint256 internal constant CONTRACT_DATA_NUM_BYTES_PER_BASE_ROLLUP = 64; uint256 internal constant CONTRACT_DATA_NUM_BYTES_PER_BASE_ROLLUP_UNPADDED = 52; diff --git a/l1-contracts/src/core/libraries/TxsDecoder.sol b/l1-contracts/src/core/libraries/TxsDecoder.sol index 9bf8ef5329e..4a7da2a7720 100644 --- a/l1-contracts/src/core/libraries/TxsDecoder.sol +++ b/l1-contracts/src/core/libraries/TxsDecoder.sol @@ -30,12 +30,12 @@ import {Errors} from "@aztec/core/libraries/Errors.sol"; * | 0x25 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 | d * 0x20 | l2ToL1Msgs * | 0x25 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 | 0x1 | len(publicDataUpdateRequests) (denoted e) * | 0x25 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 | e * 0x40 | publicDataUpdateRequests - * | 0x25 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 | 0x04 | byteLen(noteEncryptedLogs) (denoted f) - * | 0x25 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 | f | noteEncryptedLogs - * | 0x25 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f | 0x04 | byteLen(encryptedLogs) (denoted g) - * | 0x25 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f + 0x4 | g | encryptedLogs - * | 0x25 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f + 0x4 + g | 0x04 | byteLen(unencryptedLogs) (denoted h) - * | 0x25 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f + 0x4 + g + 0x04| h | unencryptedLogs + * | 0x25 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 | 0x1 | len(privateLogs) (denoted f) + * | 0x25 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x01 | f * 0x240 | privateLogs + * | 0x25 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x01 + f * 0x240 | 0x04 | byteLen(unencryptedLogs) (denoted g) + * | 0x25 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x01 + f * 0x240 + g | g | unencryptedLogs + * | 0x25 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f + 0x4 + g | 0x04 | byteLen(contractClassLogs) (denoted h) + * | 0x25 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f + 0x4 + g + 0x04| h | contractClassLogs * | | | }, * | | | TxEffect 1 { * | | | ... @@ -53,8 +53,7 @@ library TxsDecoder { uint256 nullifier; uint256 l2ToL1Msgs; uint256 publicData; - uint256 noteEncryptedLogsLength; - uint256 encryptedLogsLength; + uint256 privateLogs; uint256 unencryptedLogsLength; uint256 contractClassLogsLength; } @@ -64,18 +63,15 @@ library TxsDecoder { uint256 nullifier; uint256 l2ToL1Msgs; uint256 publicData; + uint256 privateLogs; } // Note: Used in `computeConsumables` to get around stack too deep errors. struct ConsumablesVars { bytes32[] baseLeaves; bytes baseLeaf; - uint256 kernelNoteEncryptedLogsLength; - uint256 kernelEncryptedLogsLength; uint256 kernelUnencryptedLogsLength; uint256 kernelContractClassLogsLength; - bytes32 noteEncryptedLogsHash; - bytes32 encryptedLogsHash; bytes32 unencryptedLogsHash; bytes32 contractClassLogsHash; bytes32 txOutHash; @@ -110,11 +106,8 @@ library TxsDecoder { * nullifiersKernel, * txOutHash, |=> Computed below from l2tol1msgs * publicDataUpdateRequestsKernel, - * noteEncryptedLogsLength, - * encryptedLogsLength, + * privateLogsKernel, * unencryptedLogsLength, - * noteEncryptedLogsHash, | - * encryptedLogsHash, | * unencryptedLogsHash, ____|=> Computed below from logs' preimages. * ); * Note that we always read data, the l2Block (atm) must therefore include dummy or zero-notes for @@ -157,13 +150,12 @@ library TxsDecoder { offsets.publicData = offset; offset += count * 0x40; // each public data update request is 0x40 bytes long - // NOTE ENCRYPTED LOGS LENGTH - offsets.noteEncryptedLogsLength = offset; - offset += 0x20; - - // ENCRYPTED LOGS LENGTH - offsets.encryptedLogsLength = offset; - offset += 0x20; + // PRIVATE LOGS + count = read1(_body, offset); + offset += 0x1; + counts.privateLogs = count; + offsets.privateLogs = offset; + offset += count * 0x240; // each private log is 0x240 bytes long // UNENCRYPTED LOGS LENGTH offsets.unencryptedLogsLength = offset; @@ -174,15 +166,9 @@ library TxsDecoder { offset += 0x20; /** - * Compute note, encrypted, unencrypted, and contract class logs hashes corresponding to the current leaf. + * Compute unencrypted and contract class logs hashes corresponding to the current leaf. * Note: will advance offsets by the number of bytes processed. */ - // NOTE ENCRYPTED LOGS HASH - (vars.noteEncryptedLogsHash, offset, vars.kernelNoteEncryptedLogsLength) = - computeKernelNoteEncryptedLogsHash(offset, _body); - // ENCRYPTED LOGS HASH - (vars.encryptedLogsHash, offset, vars.kernelEncryptedLogsLength) = - computeKernelEncryptedLogsHash(offset, _body); // UNENCRYPTED LOGS HASH (vars.unencryptedLogsHash, offset, vars.kernelUnencryptedLogsLength) = computeKernelUnencryptedLogsHash(offset, _body, false); @@ -195,22 +181,6 @@ library TxsDecoder { // We throw to ensure that the byte len we charge for DA gas in the kernels matches the actual chargable log byte len // Without this check, the user may provide the kernels with a lower log len than reality - require( - uint256(bytes32(slice(_body, offsets.noteEncryptedLogsLength, 0x20))) - == vars.kernelNoteEncryptedLogsLength, - Errors.TxsDecoder__InvalidLogsLength( - uint256(bytes32(slice(_body, offsets.noteEncryptedLogsLength, 0x20))), - vars.kernelNoteEncryptedLogsLength - ) - ); - require( - uint256(bytes32(slice(_body, offsets.encryptedLogsLength, 0x20))) - == vars.kernelEncryptedLogsLength, - Errors.TxsDecoder__InvalidLogsLength( - uint256(bytes32(slice(_body, offsets.encryptedLogsLength, 0x20))), - vars.kernelEncryptedLogsLength - ) - ); require( uint256(bytes32(slice(_body, offsets.unencryptedLogsLength, 0x20))) == vars.kernelUnencryptedLogsLength, @@ -248,28 +218,27 @@ library TxsDecoder { counts.nullifier * 0x20, Constants.NULLIFIERS_NUM_BYTES_PER_BASE_ROLLUP ), - vars.txOutHash, + vars.txOutHash + ), + bytes.concat( sliceAndPadRight( _body, offsets.publicData, counts.publicData * 0x40, Constants.PUBLIC_DATA_WRITES_NUM_BYTES_PER_BASE_ROLLUP + ), + sliceAndPadRight( + _body, + offsets.privateLogs, + counts.privateLogs * 0x240, + Constants.PRIVATE_LOGS_NUM_BYTES_PER_BASE_ROLLUP ) ), - bytes.concat( - slice(_body, offsets.noteEncryptedLogsLength, 0x20), - slice(_body, offsets.encryptedLogsLength, 0x20) - ), bytes.concat( slice(_body, offsets.unencryptedLogsLength, 0x20), slice(_body, offsets.contractClassLogsLength, 0x20) ), - bytes.concat( - vars.noteEncryptedLogsHash, - vars.encryptedLogsHash, - vars.unencryptedLogsHash, - vars.contractClassLogsHash - ) + bytes.concat(vars.unencryptedLogsHash, vars.contractClassLogsHash) ); vars.baseLeaves[i] = Hash.sha256ToField(vars.baseLeaf); @@ -278,175 +247,13 @@ library TxsDecoder { // We pad base leaves with hashes of empty tx effect. for (uint256 i = numTxEffects; i < vars.baseLeaves.length; i++) { // Value taken from tx_effect.test.ts "hash of empty tx effect matches snapshot" test case - vars.baseLeaves[i] = hex"00c2dece9c9f14c67b8aafabdcb80793f1cffe95a801e15d648fd214a0522ee8"; + vars.baseLeaves[i] = hex"0038249b91f300ff56f2a8135be3bdb4fc493df5771061b67f2ab01b620b22b7"; } } return computeUnbalancedRoot(vars.baseLeaves); } - /** - * @notice Computes logs hash as is done in the kernel and app circuits. - * @param _offsetInBlock - The offset of kernel's logs in a block. - * @param _body - The L2 block calldata. - * @return The hash of the logs and offset in a block after processing the logs. - * @dev We have logs preimages on the input and we need to perform the same hashing process as is done in the app - * circuit (hashing the logs) and in the kernel circuit (accumulating the logs hashes). The tail kernel - * circuit flat hashes all the app log hashes. - * - * E.g. for resulting logs hash of a kernel with 3 iterations would be computed as: - * - * kernelPublicInputsLogsHash = sha256((sha256(I1_LOGS), sha256(I2_LOGS)), sha256(I3_LOGS)) - * - * where I1_LOGS, I2_LOGS and I3_LOGS are logs emitted in the first, second and third function call. - * - * Note that `sha256(I1_LOGS)`, `sha256(I2_LOGS)` and `sha256(I3_LOGS)` are computed in the app circuit and not - * in the kernel circuit. The kernel circuit only accumulates the hashes. - * - * @dev For the example above, the logs are encoded in the following way: - * - * || K_LOGS_LEN | I1_LOGS_LEN | I1_LOGS | I2_LOGS_LEN | I2_LOGS | I3_LOGS_LEN | I3_LOGS || - * 4 bytes 4 bytes i bytes 4 bytes j bytes 4 bytes k bytes - * - * K_LOGS_LEN is the total length of the logs in the kernel. - * I1_LOGS_LEN (i) is the length of the logs in the first iteration. - * I1_LOGS are all the logs emitted in the first iteration. - * I2_LOGS_LEN (j) ... - * @dev The circuit outputs a total logs len based on the byte length that the user pays DA gas for. - * In terms of the encoding above, this is the raw log length (i, j, or k) + 4 for each log. - * For the example above, kernelLogsLength = (i + 4) + (j + 4) + (k + 4). Since we already track - * the total remainingLogsLength, we just remove the bytes holding function logs length. - * - * @dev Link to a relevant discussion: - * https://discourse.aztec.network/t/proposal-forcing-the-sequencer-to-actually-submit-data-to-l1/426/9 - */ - function computeKernelNoteEncryptedLogsHash(uint256 _offsetInBlock, bytes calldata _body) - internal - pure - returns (bytes32, uint256, uint256) - { - uint256 offset = _offsetInBlock; - uint256 remainingLogsLength = read4(_body, offset); - uint256 kernelLogsLength = remainingLogsLength; - offset += 0x4; - - bytes memory flattenedLogHashes; // The hash input - - // Iterate until all the logs were processed - while (remainingLogsLength > 0) { - // The length of the logs emitted by Aztec.nr from the function call corresponding to this kernel iteration - uint256 privateCircuitPublicInputLogsLength = read4(_body, offset); - offset += 0x4; - - // Decrease remaining logs length by this privateCircuitPublicInputsLogs's length (len(I?_LOGS)) and 4 bytes for I?_LOGS_LEN - remainingLogsLength -= (privateCircuitPublicInputLogsLength + 0x4); - - kernelLogsLength -= 0x4; - - while (privateCircuitPublicInputLogsLength > 0) { - uint256 singleCallLogsLength = read4(_body, offset); - offset += 0x4; - - bytes32 singleLogHash = Hash.sha256ToField(slice(_body, offset, singleCallLogsLength)); - offset += singleCallLogsLength; - - flattenedLogHashes = bytes.concat(flattenedLogHashes, singleLogHash); - - privateCircuitPublicInputLogsLength -= (singleCallLogsLength + 0x4); - } - } - - // Not having a 0 value hash for empty logs causes issues with empty txs used for padding. - if (flattenedLogHashes.length == 0) { - return (0, offset, 0); - } - - // padded to MAX_LOGS * 32 bytes - flattenedLogHashes = bytes.concat( - flattenedLogHashes, - new bytes(Constants.MAX_NOTE_ENCRYPTED_LOGS_PER_TX * 32 - flattenedLogHashes.length) - ); - - bytes32 kernelPublicInputsLogsHash = Hash.sha256ToField(flattenedLogHashes); - - return (kernelPublicInputsLogsHash, offset, kernelLogsLength); - } - - /** - * @notice Computes encrypted logs hash as is done in the kernel circuits. - * @param _offsetInBlock - The offset of kernel's logs in a block. - * @param _body - The L2 block calldata. - * @return The hash of the logs and offset in a block after processing the logs. - * @dev See above for full details. Non-note encrypted logs hashes are siloed with - * their (hidden) contract address: - * singleLogsHash = sha256ToField(encryptedBuffer) - * siloedLogsHash = sha256ToField(maskedContractAddress, singleLogsHash) - * where maskedContractAddress = pedersen(contract_address, randomness) is provided as part - * of the block bytes, prepended to each encrypted log. - * We don't currently count the maskedContractAddress as part of the - * chargable DA length of the log. - */ - function computeKernelEncryptedLogsHash(uint256 _offsetInBlock, bytes calldata _body) - internal - pure - returns (bytes32, uint256, uint256) - { - uint256 offset = _offsetInBlock; - uint256 remainingLogsLength = read4(_body, offset); - uint256 kernelLogsLength = remainingLogsLength; - offset += 0x4; - - bytes memory flattenedLogHashes; // The hash input - - // Iterate until all the logs were processed - while (remainingLogsLength > 0) { - // The length of the logs emitted by Aztec.nr from the function call corresponding to this kernel iteration - uint256 privateCircuitPublicInputLogsLength = read4(_body, offset); - offset += 0x4; - - // Decrease remaining logs length by this privateCircuitPublicInputsLogs's length (len(I?_LOGS)) and 4 bytes for I?_LOGS_LEN - remainingLogsLength -= (privateCircuitPublicInputLogsLength + 0x4); - - kernelLogsLength -= 0x4; - - while (privateCircuitPublicInputLogsLength > 0) { - uint256 singleCallLogsLengthWithMaskedAddress = read4(_body, offset); - offset += 0x4; - // The first 32 bytes of the provided encrypted log are its masked address (see EncryptedL2Log.toBuffer()) - bytes32 maskedContractAddress = bytes32(slice(_body, offset, 0x20)); - offset += 0x20; - // We don't currently include the masked contract address as part of the DA length - kernelLogsLength -= 0x20; - uint256 singleCallLogsLength = singleCallLogsLengthWithMaskedAddress - 0x20; - - bytes32 singleLogHash = Hash.sha256ToField(slice(_body, offset, singleCallLogsLength)); - - bytes32 siloedLogHash = - Hash.sha256ToField(bytes.concat(maskedContractAddress, singleLogHash)); - offset += singleCallLogsLength; - - flattenedLogHashes = bytes.concat(flattenedLogHashes, siloedLogHash); - - privateCircuitPublicInputLogsLength -= (singleCallLogsLengthWithMaskedAddress + 0x4); - } - } - - // Not having a 0 value hash for empty logs causes issues with empty txs used for padding. - if (flattenedLogHashes.length == 0) { - return (0, offset, 0); - } - - // padded to MAX_LOGS * 32 bytes - flattenedLogHashes = bytes.concat( - flattenedLogHashes, - new bytes(Constants.MAX_ENCRYPTED_LOGS_PER_TX * 32 - flattenedLogHashes.length) - ); - - bytes32 kernelPublicInputsLogsHash = Hash.sha256ToField(flattenedLogHashes); - - return (kernelPublicInputsLogsHash, offset, kernelLogsLength); - } - /** * @notice Computes unencrypted or contract class logs hash as is done in the kernel circuits. * @param _offsetInBlock - The offset of kernel's logs in a block. diff --git a/l1-contracts/test/decoders/Decoders.t.sol b/l1-contracts/test/decoders/Decoders.t.sol index 22e091c028d..c3d47db7bb8 100644 --- a/l1-contracts/test/decoders/Decoders.t.sol +++ b/l1-contracts/test/decoders/Decoders.t.sol @@ -187,30 +187,31 @@ contract DecodersTest is DecoderBase { // I1_LOGS_LEN = 8 (hex"00000008") // I1_LOGS = 8 bytes (hex"0000000493e78a70") bytes memory firstFunctionCallLogs = hex"93e78a70"; - // First, prefix logs with a masked address to mimic siloing - bytes32 maskedAddress = hex"11"; + // First, prefix logs with the contract address + bytes32 contractAddress = hex"11"; // Prefix logs with length of kernel logs (12) and length of iteration 1 logs (8) // Note: 00000004 is the length of 1 log within function logs // Note: 00000024 is the length of 1 log plus its masked address bytes memory encodedLogs = - abi.encodePacked(hex"0000002c00000028", hex"00000024", maskedAddress, firstFunctionCallLogs); + abi.encodePacked(hex"0000002c00000028", hex"00000024", contractAddress, firstFunctionCallLogs); (bytes32 logsHash, uint256 bytesAdvanced, uint256 logsLength) = txsHelper.computeKernelLogsHash(encodedLogs); - bytes32 privateCircuitPublicInputsLogsHashFirstCall = Hash.sha256ToField(firstFunctionCallLogs); + bytes32 privateCircuitPublicInputsLogsHashFirstCall = + Hash.sha256ToField(bytes.concat(contractAddress, firstFunctionCallLogs)); bytes32 privateCircuitPublicInputsLogsHashFirstCallSiloed = - Hash.sha256ToField(bytes.concat(maskedAddress, privateCircuitPublicInputsLogsHashFirstCall)); + Hash.sha256ToField(bytes.concat(contractAddress, privateCircuitPublicInputsLogsHashFirstCall)); bytes32 referenceLogsHash = Hash.sha256ToField( abi.encodePacked( privateCircuitPublicInputsLogsHashFirstCallSiloed, - new bytes(Constants.MAX_ENCRYPTED_LOGS_PER_TX * 32 - 32) + new bytes(Constants.MAX_UNENCRYPTED_LOGS_PER_TX * 32 - 32) ) ); assertEq(bytesAdvanced, encodedLogs.length, "Advanced by an incorrect number of bytes"); - // We take 40 as the user does not pay for the gas of the overall len or masked address - assertEq(logsLength, encodedLogs.length - 40, "Incorrect logs length"); + // We take 8 as the user does not pay for the gas of the overall len. + assertEq(logsLength, encodedLogs.length - 8, "Incorrect logs length"); assertEq(logsHash, referenceLogsHash, "Incorrect logs hash"); } @@ -222,44 +223,45 @@ contract DecodersTest is DecoderBase { // I2_LOGS_LEN = 20 (hex"00000014") // I2_LOGS = 20 bytes (hex"0000001006a86173c86c6d3f108eefc36e7fb014") bytes memory firstFunctionCallLogs = hex"93e78a70"; - // First, prefix logs with a masked address to mimic siloing - bytes32 firstCallMaskedAddress = hex"11"; + // First, prefix logs with a contract address to mimic siloing + bytes32 firstCallContractAddress = hex"11"; bytes memory secondFunctionCallLogs = hex"06a86173c86c6d3f108eefc36e7fb014"; - bytes32 secondCallMaskedAddress = hex"12"; + bytes32 secondCallContractAddress = hex"12"; bytes memory encodedLogs = abi.encodePacked( hex"0000006400000028", hex"00000024", - firstCallMaskedAddress, + firstCallContractAddress, firstFunctionCallLogs, hex"00000034", hex"00000030", - secondCallMaskedAddress, + secondCallContractAddress, secondFunctionCallLogs ); (bytes32 logsHash, uint256 bytesAdvanced, uint256 logsLength) = txsHelper.computeKernelLogsHash(encodedLogs); - bytes32 referenceLogsHashFromIteration1 = Hash.sha256ToField(firstFunctionCallLogs); + bytes32 referenceLogsHashFromIteration1 = + Hash.sha256ToField(bytes.concat(firstCallContractAddress, firstFunctionCallLogs)); bytes32 referenceLogsHashFromIteration1Siloed = - Hash.sha256ToField(bytes.concat(firstCallMaskedAddress, referenceLogsHashFromIteration1)); + Hash.sha256ToField(bytes.concat(firstCallContractAddress, referenceLogsHashFromIteration1)); bytes32 privateCircuitPublicInputsLogsHashSecondCall = - Hash.sha256ToField(secondFunctionCallLogs); + Hash.sha256ToField(bytes.concat(secondCallContractAddress, secondFunctionCallLogs)); bytes32 privateCircuitPublicInputsLogsHashSecondCallSiloed = Hash.sha256ToField( - bytes.concat(secondCallMaskedAddress, privateCircuitPublicInputsLogsHashSecondCall) + bytes.concat(secondCallContractAddress, privateCircuitPublicInputsLogsHashSecondCall) ); bytes32 referenceLogsHashFromIteration2 = Hash.sha256ToField( abi.encodePacked( referenceLogsHashFromIteration1Siloed, privateCircuitPublicInputsLogsHashSecondCallSiloed, - new bytes(Constants.MAX_ENCRYPTED_LOGS_PER_TX * 32 - 64) + new bytes(Constants.MAX_UNENCRYPTED_LOGS_PER_TX * 32 - 64) ) ); assertEq(bytesAdvanced, encodedLogs.length, "Advanced by an incorrect number of bytes"); - // We take 76 as the user does not pay for the gas of the parent len bytes or masked addresses - assertEq(logsLength, encodedLogs.length - 76, "Incorrect logs length"); + // We take 12 as the user does not pay for the gas of the parent len bytes. + assertEq(logsLength, encodedLogs.length - 12, "Incorrect logs length"); assertEq(logsHash, referenceLogsHashFromIteration2, "Incorrect logs hash"); } @@ -273,49 +275,51 @@ contract DecodersTest is DecoderBase { // I3_LOGS_LEN = 20 (hex"00000014") // I3_LOGS = 20 random bytes (hex"0000001006a86173c86c6d3f108eefc36e7fb014") bytes memory firstFunctionCallLogs = hex"93e78a70"; - // First, prefix logs with a masked address to mimic siloing - bytes32 firstCallMaskedAddress = hex"11"; + // First, prefix logs with a contract address to mimic siloing + bytes32 firstCallContractAddress = hex"11"; bytes memory secondFunctionCallLogs = hex""; bytes memory thirdFunctionCallLogs = hex"06a86173c86c6d3f108eefc36e7fb014"; - bytes32 thirdCallMaskedAddress = hex"12"; + bytes32 thirdCallContractAddress = hex"12"; bytes memory encodedLogs = abi.encodePacked( hex"0000006800000028", hex"00000024", - firstCallMaskedAddress, + firstCallContractAddress, firstFunctionCallLogs, hex"00000000", secondFunctionCallLogs, hex"00000034", hex"00000030", - thirdCallMaskedAddress, + thirdCallContractAddress, thirdFunctionCallLogs ); (bytes32 logsHash, uint256 bytesAdvanced, uint256 logsLength) = txsHelper.computeKernelLogsHash(encodedLogs); - bytes32 referenceLogsHashFromIteration1 = Hash.sha256ToField(firstFunctionCallLogs); + bytes32 referenceLogsHashFromIteration1 = + Hash.sha256ToField(bytes.concat(firstCallContractAddress, firstFunctionCallLogs)); bytes32 referenceLogsHashFromIteration1Siloed = - Hash.sha256ToField(bytes.concat(firstCallMaskedAddress, referenceLogsHashFromIteration1)); + Hash.sha256ToField(bytes.concat(firstCallContractAddress, referenceLogsHashFromIteration1)); // Note: as of resolving #5017, we now hash logs inside the circuits // Following the YP, we skip any zero length logs, hence no use of secondFunctionCallLogs here - bytes32 privateCircuitPublicInputsLogsHashThirdCall = Hash.sha256ToField(thirdFunctionCallLogs); + bytes32 privateCircuitPublicInputsLogsHashThirdCall = + Hash.sha256ToField(bytes.concat(thirdCallContractAddress, thirdFunctionCallLogs)); bytes32 privateCircuitPublicInputsLogsHashThirdCallSiloed = Hash.sha256ToField( - bytes.concat(thirdCallMaskedAddress, privateCircuitPublicInputsLogsHashThirdCall) + bytes.concat(thirdCallContractAddress, privateCircuitPublicInputsLogsHashThirdCall) ); bytes32 referenceLogsHashFromIteration3 = Hash.sha256ToField( abi.encodePacked( referenceLogsHashFromIteration1Siloed, privateCircuitPublicInputsLogsHashThirdCallSiloed, - new bytes(Constants.MAX_ENCRYPTED_LOGS_PER_TX * 32 - 64) + new bytes(Constants.MAX_UNENCRYPTED_LOGS_PER_TX * 32 - 64) ) ); assertEq(bytesAdvanced, encodedLogs.length, "Advanced by an incorrect number of bytes"); - // We take 80 as the user does not pay for the gas of the parent len bytes or masked addresses - assertEq(logsLength, encodedLogs.length - 80, "Incorrect logs length"); + // We take 16 as the user does not pay for the gas of the parent len bytes or contract addresses + assertEq(logsLength, encodedLogs.length - 16, "Incorrect logs length"); assertEq(logsHash, referenceLogsHashFromIteration3, "Incorrect logs hash"); } diff --git a/l1-contracts/test/decoders/helpers/TxsDecoderHelper.sol b/l1-contracts/test/decoders/helpers/TxsDecoderHelper.sol index 6e35c77504f..2f8db8d3378 100644 --- a/l1-contracts/test/decoders/helpers/TxsDecoderHelper.sol +++ b/l1-contracts/test/decoders/helpers/TxsDecoderHelper.sol @@ -16,7 +16,7 @@ contract TxsDecoderHelper { pure returns (bytes32, uint256, uint256) { - return TxsDecoder.computeKernelEncryptedLogsHash(0, _kernelLogs); + return TxsDecoder.computeKernelUnencryptedLogsHash(0, _kernelLogs, false); } function computeTxOutHash(bytes calldata _kernelMsgs) external pure returns (bytes32) { diff --git a/l1-contracts/test/fixtures/empty_block_1.json b/l1-contracts/test/fixtures/empty_block_1.json index 84692ccb0e3..0a718ff2451 100644 --- a/l1-contracts/test/fixtures/empty_block_1.json +++ b/l1-contracts/test/fixtures/empty_block_1.json @@ -8,28 +8,28 @@ "l2ToL1Messages": [] }, "block": { - "archive": "0x14cc4063ccae0d809992631edee86e43cd48aa4465598e54e05f4c91fc7cf9dc", - "blockHash": "0x02baa47f911948eb68e332e631af8c30d801187c66b6d48f1432c7cb98fd755c", + "archive": "0x0fafcb46cf14179b2c9f82f861f0e2c13408687d6b48bcdc3b3b076ad623c716", + "blockHash": "0x245789907f792979d937d01ec9f53675dc2f2b250056fe90d7663dc9ded67dc8", "body": "0x00000000", - "txsEffectsHash": "0x002dcd61493c9a7f3ce4605573ee657e6ced4a3dd10bfb216f44a796b3d585c9", + "txsEffectsHash": "0x00877c1db9d71fd7786d8ce0fa7dd38f6a71c715db372313f6a59616706fd610", "decodedHeader": { "contentCommitment": { "inHash": "0x00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c", "outHash": "0x00f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb", "numTxs": 2, - "txsEffectsHash": "0x002dcd61493c9a7f3ce4605573ee657e6ced4a3dd10bfb216f44a796b3d585c9" + "txsEffectsHash": "0x00877c1db9d71fd7786d8ce0fa7dd38f6a71c715db372313f6a59616706fd610" }, "globalVariables": { "blockNumber": 1, "slotNumber": "0x0000000000000000000000000000000000000000000000000000000000000012", "chainId": 31337, - "timestamp": 1732579818, + "timestamp": 1732895740, "version": 1, - "coinbase": "0xbebcbac2f24abc01241a668cca41d0659589499e", - "feeRecipient": "0x1fb24139a0110fb00ebdcf0b6667bdd95c82ede876a1d34fb8cef074eae1db2c", + "coinbase": "0x17ad712f90d7d8734b3723f6f29ac3acb967a55a", + "feeRecipient": "0x2e84c5024fd1d6e390f8bd37fa9684b45083bbe378140851ef9dea0cb3461a49", "gasFees": { "feePerDaGas": 0, - "feePerL2Gas": 54153599320 + "feePerL2Gas": 54153594950 } }, "totalFees": "0x0000000000000000000000000000000000000000000000000000000000000000", @@ -59,8 +59,8 @@ } } }, - "header": "0x0237797d6a2c04d20d4fa06b74482bd970ccd51a43d9b05b57e9b91fa1ae1cae000000010000000000000000000000000000000000000000000000000000000000000002002dcd61493c9a7f3ce4605573ee657e6ced4a3dd10bfb216f44a796b3d585c900089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c00f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb2e33ee2008411c04b99c24b313513d097a0d21a5040b6193d1f978b8226892d6000000101fd848aa69e1633722fe249a5b7f53b094f1c9cef9f5c694b073fd1cc5850dfb000000800c499b373a1f0fe1b510a63563546d2d39e206895056a5af0143c5f30d6390730000010023c08a6b1297210c5e24c76b9a936250a1ce2721576c26ea797c7ec35f9e46a9000000800000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000674511eabebcbac2f24abc01241a668cca41d0659589499e1fb24139a0110fb00ebdcf0b6667bdd95c82ede876a1d34fb8cef074eae1db2c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c9bce595800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x00f5efb7d5e53918275f835f7103b62acc1d37c11bbf27e0482680f107fc01d4", + "header": "0x0237797d6a2c04d20d4fa06b74482bd970ccd51a43d9b05b57e9b91fa1ae1cae00000001000000000000000000000000000000000000000000000000000000000000000200877c1db9d71fd7786d8ce0fa7dd38f6a71c715db372313f6a59616706fd61000089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c00f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb2e33ee2008411c04b99c24b313513d097a0d21a5040b6193d1f978b8226892d6000000101fd848aa69e1633722fe249a5b7f53b094f1c9cef9f5c694b073fd1cc5850dfb000000800c499b373a1f0fe1b510a63563546d2d39e206895056a5af0143c5f30d6390730000010023c08a6b1297210c5e24c76b9a936250a1ce2721576c26ea797c7ec35f9e46a9000000800000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000006749e3fc17ad712f90d7d8734b3723f6f29ac3acb967a55a2e84c5024fd1d6e390f8bd37fa9684b45083bbe378140851ef9dea0cb3461a4900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c9bce484600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x00dd5a4191deed280ded7ef5e7029ede7a8fed2a2dafc0b5135944e49346d5a3", "numTxs": 0 } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/empty_block_2.json b/l1-contracts/test/fixtures/empty_block_2.json index 1b2bd47c849..5646d6d90a3 100644 --- a/l1-contracts/test/fixtures/empty_block_2.json +++ b/l1-contracts/test/fixtures/empty_block_2.json @@ -8,35 +8,35 @@ "l2ToL1Messages": [] }, "block": { - "archive": "0x1ced42b04845f5bc2a98f47f54a9aac0e7cd55642cbba1da95401a8dd9b1e357", - "blockHash": "0x12caff598a6843ec10beac259597243dd5b069866f03bf67a8e4669e2a56335a", + "archive": "0x17f47e9df1e91a0cc2d64ab507734d0ae6b8b5f48cf5fd584bc33c70456c667d", + "blockHash": "0x2557b79eff9f25a2d7529b97e0af1d7c85ea9bfaf0d8b74389d84e2d2c90cbe4", "body": "0x00000000", - "txsEffectsHash": "0x002dcd61493c9a7f3ce4605573ee657e6ced4a3dd10bfb216f44a796b3d585c9", + "txsEffectsHash": "0x00877c1db9d71fd7786d8ce0fa7dd38f6a71c715db372313f6a59616706fd610", "decodedHeader": { "contentCommitment": { "inHash": "0x00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c", "outHash": "0x00f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb", "numTxs": 2, - "txsEffectsHash": "0x002dcd61493c9a7f3ce4605573ee657e6ced4a3dd10bfb216f44a796b3d585c9" + "txsEffectsHash": "0x00877c1db9d71fd7786d8ce0fa7dd38f6a71c715db372313f6a59616706fd610" }, "globalVariables": { "blockNumber": 2, "slotNumber": "0x0000000000000000000000000000000000000000000000000000000000000013", "chainId": 31337, - "timestamp": 1732579842, + "timestamp": 1732895764, "version": 1, - "coinbase": "0xbebcbac2f24abc01241a668cca41d0659589499e", - "feeRecipient": "0x1fb24139a0110fb00ebdcf0b6667bdd95c82ede876a1d34fb8cef074eae1db2c", + "coinbase": "0x17ad712f90d7d8734b3723f6f29ac3acb967a55a", + "feeRecipient": "0x2e84c5024fd1d6e390f8bd37fa9684b45083bbe378140851ef9dea0cb3461a49", "gasFees": { "feePerDaGas": 0, - "feePerL2Gas": 54153599320 + "feePerL2Gas": 54153594950 } }, "totalFees": "0x0000000000000000000000000000000000000000000000000000000000000000", "totalManaUsed": "0x0000000000000000000000000000000000000000000000000000000000000000", "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x14cc4063ccae0d809992631edee86e43cd48aa4465598e54e05f4c91fc7cf9dc" + "root": "0x0fafcb46cf14179b2c9f82f861f0e2c13408687d6b48bcdc3b3b076ad623c716" }, "stateReference": { "l1ToL2MessageTree": { @@ -59,8 +59,8 @@ } } }, - "header": "0x14cc4063ccae0d809992631edee86e43cd48aa4465598e54e05f4c91fc7cf9dc000000020000000000000000000000000000000000000000000000000000000000000002002dcd61493c9a7f3ce4605573ee657e6ced4a3dd10bfb216f44a796b3d585c900089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c00f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb2e33ee2008411c04b99c24b313513d097a0d21a5040b6193d1f978b8226892d6000000201fd848aa69e1633722fe249a5b7f53b094f1c9cef9f5c694b073fd1cc5850dfb000001000c499b373a1f0fe1b510a63563546d2d39e206895056a5af0143c5f30d6390730000018023c08a6b1297210c5e24c76b9a936250a1ce2721576c26ea797c7ec35f9e46a9000000800000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000067451202bebcbac2f24abc01241a668cca41d0659589499e1fb24139a0110fb00ebdcf0b6667bdd95c82ede876a1d34fb8cef074eae1db2c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c9bce595800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x004cab0bf8cace3c6a6b2506f12a17d5f1ccaf63db14d8f6e67b3fea6d34fc3d", + "header": "0x0fafcb46cf14179b2c9f82f861f0e2c13408687d6b48bcdc3b3b076ad623c71600000002000000000000000000000000000000000000000000000000000000000000000200877c1db9d71fd7786d8ce0fa7dd38f6a71c715db372313f6a59616706fd61000089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c00f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb2e33ee2008411c04b99c24b313513d097a0d21a5040b6193d1f978b8226892d6000000201fd848aa69e1633722fe249a5b7f53b094f1c9cef9f5c694b073fd1cc5850dfb000001000c499b373a1f0fe1b510a63563546d2d39e206895056a5af0143c5f30d6390730000018023c08a6b1297210c5e24c76b9a936250a1ce2721576c26ea797c7ec35f9e46a9000000800000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000013000000000000000000000000000000000000000000000000000000006749e41417ad712f90d7d8734b3723f6f29ac3acb967a55a2e84c5024fd1d6e390f8bd37fa9684b45083bbe378140851ef9dea0cb3461a4900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c9bce484600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x003923b85214777fa03dd6dd8b7f66c44d98dd8b2cc8f3996a4f5bbfc146a184", "numTxs": 0 } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/mixed_block_1.json b/l1-contracts/test/fixtures/mixed_block_1.json index 65e4c926d83..2a6921e6eaa 100644 --- a/l1-contracts/test/fixtures/mixed_block_1.json +++ b/l1-contracts/test/fixtures/mixed_block_1.json @@ -58,28 +58,28 @@ ] }, "block": { - "archive": "0x0dd5f1f4c97e09c3d85323d27343341b245c49c5e7032c43c8b7c70d8b79629a", - "blockHash": "0x1b22c2fdad7b5b96c8f0d57c83a52cad8b6f03f012d53be9e4987b92f978b29d", - "body": "0x00000004000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000041000000000000000000000000000000000000000000000000000000000000004100100000000000000000000000000000000000000000000000000000000000410020000000000000000000000000000000000000000000000000000000000041003000000000000000000000000000000000000000000000000000000000004100400000000000000000000000000000000000000000000000000000000000410050000000000000000000000000000000000000000000000000000000000041006000000000000000000000000000000000000000000000000000000000004100700000000000000000000000000000000000000000000000000000000000410080000000000000000000000000000000000000000000000000000000000041009000000000000000000000000000000000000000000000000000000000004100a000000000000000000000000000000000000000000000000000000000004100b000000000000000000000000000000000000000000000000000000000004100c000000000000000000000000000000000000000000000000000000000004100d000000000000000000000000000000000000000000000000000000000004100e000000000000000000000000000000000000000000000000000000000004100f0000000000000000000000000000000000000000000000000000000000041010000000000000000000000000000000000000000000000000000000000004101100000000000000000000000000000000000000000000000000000000000410120000000000000000000000000000000000000000000000000000000000041013000000000000000000000000000000000000000000000000000000000004101400000000000000000000000000000000000000000000000000000000000410150000000000000000000000000000000000000000000000000000000000041016000000000000000000000000000000000000000000000000000000000004101700000000000000000000000000000000000000000000000000000000000410180000000000000000000000000000000000000000000000000000000000041019000000000000000000000000000000000000000000000000000000000004101a000000000000000000000000000000000000000000000000000000000004101b000000000000000000000000000000000000000000000000000000000004101c000000000000000000000000000000000000000000000000000000000004101d000000000000000000000000000000000000000000000000000000000004101e000000000000000000000000000000000000000000000000000000000004101f0000000000000000000000000000000000000000000000000000000000041020000000000000000000000000000000000000000000000000000000000004102100000000000000000000000000000000000000000000000000000000000410220000000000000000000000000000000000000000000000000000000000041023000000000000000000000000000000000000000000000000000000000004102400000000000000000000000000000000000000000000000000000000000410250000000000000000000000000000000000000000000000000000000000041026000000000000000000000000000000000000000000000000000000000004102700000000000000000000000000000000000000000000000000000000000410280000000000000000000000000000000000000000000000000000000000041029000000000000000000000000000000000000000000000000000000000004102a000000000000000000000000000000000000000000000000000000000004102b000000000000000000000000000000000000000000000000000000000004102c000000000000000000000000000000000000000000000000000000000004102d000000000000000000000000000000000000000000000000000000000004102e000000000000000000000000000000000000000000000000000000000004102f0000000000000000000000000000000000000000000000000000000000041030000000000000000000000000000000000000000000000000000000000004103100000000000000000000000000000000000000000000000000000000000410320000000000000000000000000000000000000000000000000000000000041033000000000000000000000000000000000000000000000000000000000004103400000000000000000000000000000000000000000000000000000000000410350000000000000000000000000000000000000000000000000000000000041036000000000000000000000000000000000000000000000000000000000004103700000000000000000000000000000000000000000000000000000000000410380000000000000000000000000000000000000000000000000000000000041039000000000000000000000000000000000000000000000000000000000004103a000000000000000000000000000000000000000000000000000000000004103b000000000000000000000000000000000000000000000000000000000004103c000000000000000000000000000000000000000000000000000000000004103d000000000000000000000000000000000000000000000000000000000004103e000000000000000000000000000000000000000000000000000000000004103f3f0000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004110100000000000000000000000000000000000000000000000000000000000411020000000000000000000000000000000000000000000000000000000000041103000000000000000000000000000000000000000000000000000000000004110400000000000000000000000000000000000000000000000000000000000411050000000000000000000000000000000000000000000000000000000000041106000000000000000000000000000000000000000000000000000000000004110700000000000000000000000000000000000000000000000000000000000411080000000000000000000000000000000000000000000000000000000000041109000000000000000000000000000000000000000000000000000000000004110a000000000000000000000000000000000000000000000000000000000004110b000000000000000000000000000000000000000000000000000000000004110c000000000000000000000000000000000000000000000000000000000004110d000000000000000000000000000000000000000000000000000000000004110e000000000000000000000000000000000000000000000000000000000004110f0000000000000000000000000000000000000000000000000000000000041110000000000000000000000000000000000000000000000000000000000004111100000000000000000000000000000000000000000000000000000000000411120000000000000000000000000000000000000000000000000000000000041113000000000000000000000000000000000000000000000000000000000004111400000000000000000000000000000000000000000000000000000000000411150000000000000000000000000000000000000000000000000000000000041116000000000000000000000000000000000000000000000000000000000004111700000000000000000000000000000000000000000000000000000000000411180000000000000000000000000000000000000000000000000000000000041119000000000000000000000000000000000000000000000000000000000004111a000000000000000000000000000000000000000000000000000000000004111b000000000000000000000000000000000000000000000000000000000004111c000000000000000000000000000000000000000000000000000000000004111d000000000000000000000000000000000000000000000000000000000004111e000000000000000000000000000000000000000000000000000000000004111f0000000000000000000000000000000000000000000000000000000000041120000000000000000000000000000000000000000000000000000000000004112100000000000000000000000000000000000000000000000000000000000411220000000000000000000000000000000000000000000000000000000000041123000000000000000000000000000000000000000000000000000000000004112400000000000000000000000000000000000000000000000000000000000411250000000000000000000000000000000000000000000000000000000000041126000000000000000000000000000000000000000000000000000000000004112700000000000000000000000000000000000000000000000000000000000411280000000000000000000000000000000000000000000000000000000000041129000000000000000000000000000000000000000000000000000000000004112a000000000000000000000000000000000000000000000000000000000004112b000000000000000000000000000000000000000000000000000000000004112c000000000000000000000000000000000000000000000000000000000004112d000000000000000000000000000000000000000000000000000000000004112e000000000000000000000000000000000000000000000000000000000004112f0000000000000000000000000000000000000000000000000000000000041130000000000000000000000000000000000000000000000000000000000004113100000000000000000000000000000000000000000000000000000000000411320000000000000000000000000000000000000000000000000000000000041133000000000000000000000000000000000000000000000000000000000004113400000000000000000000000000000000000000000000000000000000000411350000000000000000000000000000000000000000000000000000000000041136000000000000000000000000000000000000000000000000000000000004113700000000000000000000000000000000000000000000000000000000000411380000000000000000000000000000000000000000000000000000000000041139000000000000000000000000000000000000000000000000000000000004113a000000000000000000000000000000000000000000000000000000000004113b000000000000000000000000000000000000000000000000000000000004113c000000000000000000000000000000000000000000000000000000000004113d000000000000000000000000000000000000000000000000000000000004113e080097a6ec570e9b8e257647c9c74c5ad3edc57ca5ef6ae44d80b3c30d1d99b9b300ce48ec41d1edde0066fab553a456ae2f380d14fa8f956af1fb0217513a598900619ff12eaf97f63aa2a2311de3b6571a7b880a5247cb33b6a74787bf3f9bd5007854a2fad4e1801c6404394bf3d37ab08c135ea38a1974242e39a21273685f000f55796e72957a819e68a22e8602d73c3ba3718a5a4bd92b80b0aa444b182a00788b6e9874fb040ee679a7fae257190099a605229b948334e54a57739535d4004f1658ee3c1a91627e5d72f5a731f0796299df82ab41e72c88eee0c82fa85e003ee802add96628c693ed71afa9908138ba5a6fbf0a5f29a9c74e4e42aba6713f0000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000000000000000000000000000000004200a0000000000000000000000000000000000000000000000000000000000042001000000000000000000000000000000000000000000000000000000000004200b0000000000000000000000000000000000000000000000000000000000042002000000000000000000000000000000000000000000000000000000000004200c0000000000000000000000000000000000000000000000000000000000042003000000000000000000000000000000000000000000000000000000000004200d0000000000000000000000000000000000000000000000000000000000042004000000000000000000000000000000000000000000000000000000000004200e0000000000000000000000000000000000000000000000000000000000042005000000000000000000000000000000000000000000000000000000000004200f00000000000000000000000000000000000000000000000000000000000420060000000000000000000000000000000000000000000000000000000000042010000000000000000000000000000000000000000000000000000000000004200700000000000000000000000000000000000000000000000000000000000420110000000000000000000000000000000000000000000000000000000000042008000000000000000000000000000000000000000000000000000000000004201200000000000000000000000000000000000000000000000000000000000420090000000000000000000000000000000000000000000000000000000000042013000000000000000000000000000000000000000000000000000000000004200a0000000000000000000000000000000000000000000000000000000000042014000000000000000000000000000000000000000000000000000000000004200b0000000000000000000000000000000000000000000000000000000000042015000000000000000000000000000000000000000000000000000000000004200c0000000000000000000000000000000000000000000000000000000000042016000000000000000000000000000000000000000000000000000000000004200d0000000000000000000000000000000000000000000000000000000000042017000000000000000000000000000000000000000000000000000000000004200e0000000000000000000000000000000000000000000000000000000000042018000000000000000000000000000000000000000000000000000000000004200f00000000000000000000000000000000000000000000000000000000000420190000000000000000000000000000000000000000000000000000000000042010000000000000000000000000000000000000000000000000000000000004201a0000000000000000000000000000000000000000000000000000000000042011000000000000000000000000000000000000000000000000000000000004201b0000000000000000000000000000000000000000000000000000000000042012000000000000000000000000000000000000000000000000000000000004201c0000000000000000000000000000000000000000000000000000000000042013000000000000000000000000000000000000000000000000000000000004201d0000000000000000000000000000000000000000000000000000000000042014000000000000000000000000000000000000000000000000000000000004201e0000000000000000000000000000000000000000000000000000000000042015000000000000000000000000000000000000000000000000000000000004201f00000000000000000000000000000000000000000000000000000000000420160000000000000000000000000000000000000000000000000000000000042020000000000000000000000000000000000000000000000000000000000004201700000000000000000000000000000000000000000000000000000000000420210000000000000000000000000000000000000000000000000000000000042018000000000000000000000000000000000000000000000000000000000004202200000000000000000000000000000000000000000000000000000000000420190000000000000000000000000000000000000000000000000000000000042023000000000000000000000000000000000000000000000000000000000004201a0000000000000000000000000000000000000000000000000000000000042024000000000000000000000000000000000000000000000000000000000004201b0000000000000000000000000000000000000000000000000000000000042025000000000000000000000000000000000000000000000000000000000004201c0000000000000000000000000000000000000000000000000000000000042026000000000000000000000000000000000000000000000000000000000004201d0000000000000000000000000000000000000000000000000000000000042027000000000000000000000000000000000000000000000000000000000004201e0000000000000000000000000000000000000000000000000000000000042028000000000000000000000000000000000000000000000000000000000004201f00000000000000000000000000000000000000000000000000000000000420290000000000000000000000000000000000000000000000000000000000042020000000000000000000000000000000000000000000000000000000000004202a0000000000000000000000000000000000000000000000000000000000042021000000000000000000000000000000000000000000000000000000000004202b0000000000000000000000000000000000000000000000000000000000042022000000000000000000000000000000000000000000000000000000000004202c0000000000000000000000000000000000000000000000000000000000042023000000000000000000000000000000000000000000000000000000000004202d0000000000000000000000000000000000000000000000000000000000042024000000000000000000000000000000000000000000000000000000000004202e0000000000000000000000000000000000000000000000000000000000042025000000000000000000000000000000000000000000000000000000000004202f00000000000000000000000000000000000000000000000000000000000420260000000000000000000000000000000000000000000000000000000000042030000000000000000000000000000000000000000000000000000000000004202700000000000000000000000000000000000000000000000000000000000420310000000000000000000000000000000000000000000000000000000000042028000000000000000000000000000000000000000000000000000000000004203200000000000000000000000000000000000000000000000000000000000420290000000000000000000000000000000000000000000000000000000000042033000000000000000000000000000000000000000000000000000000000004202a0000000000000000000000000000000000000000000000000000000000042034000000000000000000000000000000000000000000000000000000000004202b0000000000000000000000000000000000000000000000000000000000042035000000000000000000000000000000000000000000000000000000000004202c0000000000000000000000000000000000000000000000000000000000042036000000000000000000000000000000000000000000000000000000000004202d0000000000000000000000000000000000000000000000000000000000042037000000000000000000000000000000000000000000000000000000000004202e0000000000000000000000000000000000000000000000000000000000042038000000000000000000000000000000000000000000000000000000000004202f00000000000000000000000000000000000000000000000000000000000420390000000000000000000000000000000000000000000000000000000000042030000000000000000000000000000000000000000000000000000000000004203a0000000000000000000000000000000000000000000000000000000000042031000000000000000000000000000000000000000000000000000000000004203b0000000000000000000000000000000000000000000000000000000000042032000000000000000000000000000000000000000000000000000000000004203c0000000000000000000000000000000000000000000000000000000000042033000000000000000000000000000000000000000000000000000000000004203d0000000000000000000000000000000000000000000000000000000000042034000000000000000000000000000000000000000000000000000000000004203e0000000000000000000000000000000000000000000000000000000000042035000000000000000000000000000000000000000000000000000000000004203f00000000000000000000000000000000000000000000000000000000000420360000000000000000000000000000000000000000000000000000000000042040000000000000000000000000000000000000000000000000000000000004203700000000000000000000000000000000000000000000000000000000000420410000000000000000000000000000000000000000000000000000000000042038000000000000000000000000000000000000000000000000000000000004204200000000000000000000000000000000000000000000000000000000000420390000000000000000000000000000000000000000000000000000000000042043000000000000000000000000000000000000000000000000000000000004203a0000000000000000000000000000000000000000000000000000000000042044000000000000000000000000000000000000000000000000000000000004203b0000000000000000000000000000000000000000000000000000000000042045000000000000000000000000000000000000000000000000000000000004203c0000000000000000000000000000000000000000000000000000000000042046000000000000000000000000000000000000000000000000000000000004203d0000000000000000000000000000000000000000000000000000000000042047000000000000000000000000000000000000000000000000000000000004203e0000000000000000000000000000000000000000000000000000000000042048000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000081000000000000000000000000000000000000000000000000000000000000008100100000000000000000000000000000000000000000000000000000000000810020000000000000000000000000000000000000000000000000000000000081003000000000000000000000000000000000000000000000000000000000008100400000000000000000000000000000000000000000000000000000000000810050000000000000000000000000000000000000000000000000000000000081006000000000000000000000000000000000000000000000000000000000008100700000000000000000000000000000000000000000000000000000000000810080000000000000000000000000000000000000000000000000000000000081009000000000000000000000000000000000000000000000000000000000008100a000000000000000000000000000000000000000000000000000000000008100b000000000000000000000000000000000000000000000000000000000008100c000000000000000000000000000000000000000000000000000000000008100d000000000000000000000000000000000000000000000000000000000008100e000000000000000000000000000000000000000000000000000000000008100f0000000000000000000000000000000000000000000000000000000000081010000000000000000000000000000000000000000000000000000000000008101100000000000000000000000000000000000000000000000000000000000810120000000000000000000000000000000000000000000000000000000000081013000000000000000000000000000000000000000000000000000000000008101400000000000000000000000000000000000000000000000000000000000810150000000000000000000000000000000000000000000000000000000000081016000000000000000000000000000000000000000000000000000000000008101700000000000000000000000000000000000000000000000000000000000810180000000000000000000000000000000000000000000000000000000000081019000000000000000000000000000000000000000000000000000000000008101a000000000000000000000000000000000000000000000000000000000008101b000000000000000000000000000000000000000000000000000000000008101c000000000000000000000000000000000000000000000000000000000008101d000000000000000000000000000000000000000000000000000000000008101e000000000000000000000000000000000000000000000000000000000008101f0000000000000000000000000000000000000000000000000000000000081020000000000000000000000000000000000000000000000000000000000008102100000000000000000000000000000000000000000000000000000000000810220000000000000000000000000000000000000000000000000000000000081023000000000000000000000000000000000000000000000000000000000008102400000000000000000000000000000000000000000000000000000000000810250000000000000000000000000000000000000000000000000000000000081026000000000000000000000000000000000000000000000000000000000008102700000000000000000000000000000000000000000000000000000000000810280000000000000000000000000000000000000000000000000000000000081029000000000000000000000000000000000000000000000000000000000008102a000000000000000000000000000000000000000000000000000000000008102b000000000000000000000000000000000000000000000000000000000008102c000000000000000000000000000000000000000000000000000000000008102d000000000000000000000000000000000000000000000000000000000008102e000000000000000000000000000000000000000000000000000000000008102f0000000000000000000000000000000000000000000000000000000000081030000000000000000000000000000000000000000000000000000000000008103100000000000000000000000000000000000000000000000000000000000810320000000000000000000000000000000000000000000000000000000000081033000000000000000000000000000000000000000000000000000000000008103400000000000000000000000000000000000000000000000000000000000810350000000000000000000000000000000000000000000000000000000000081036000000000000000000000000000000000000000000000000000000000008103700000000000000000000000000000000000000000000000000000000000810380000000000000000000000000000000000000000000000000000000000081039000000000000000000000000000000000000000000000000000000000008103a000000000000000000000000000000000000000000000000000000000008103b000000000000000000000000000000000000000000000000000000000008103c000000000000000000000000000000000000000000000000000000000008103d000000000000000000000000000000000000000000000000000000000008103e000000000000000000000000000000000000000000000000000000000008103f3f0000000000000000000000000000000000000000000000000000000000081100000000000000000000000000000000000000000000000000000000000008110100000000000000000000000000000000000000000000000000000000000811020000000000000000000000000000000000000000000000000000000000081103000000000000000000000000000000000000000000000000000000000008110400000000000000000000000000000000000000000000000000000000000811050000000000000000000000000000000000000000000000000000000000081106000000000000000000000000000000000000000000000000000000000008110700000000000000000000000000000000000000000000000000000000000811080000000000000000000000000000000000000000000000000000000000081109000000000000000000000000000000000000000000000000000000000008110a000000000000000000000000000000000000000000000000000000000008110b000000000000000000000000000000000000000000000000000000000008110c000000000000000000000000000000000000000000000000000000000008110d000000000000000000000000000000000000000000000000000000000008110e000000000000000000000000000000000000000000000000000000000008110f0000000000000000000000000000000000000000000000000000000000081110000000000000000000000000000000000000000000000000000000000008111100000000000000000000000000000000000000000000000000000000000811120000000000000000000000000000000000000000000000000000000000081113000000000000000000000000000000000000000000000000000000000008111400000000000000000000000000000000000000000000000000000000000811150000000000000000000000000000000000000000000000000000000000081116000000000000000000000000000000000000000000000000000000000008111700000000000000000000000000000000000000000000000000000000000811180000000000000000000000000000000000000000000000000000000000081119000000000000000000000000000000000000000000000000000000000008111a000000000000000000000000000000000000000000000000000000000008111b000000000000000000000000000000000000000000000000000000000008111c000000000000000000000000000000000000000000000000000000000008111d000000000000000000000000000000000000000000000000000000000008111e000000000000000000000000000000000000000000000000000000000008111f0000000000000000000000000000000000000000000000000000000000081120000000000000000000000000000000000000000000000000000000000008112100000000000000000000000000000000000000000000000000000000000811220000000000000000000000000000000000000000000000000000000000081123000000000000000000000000000000000000000000000000000000000008112400000000000000000000000000000000000000000000000000000000000811250000000000000000000000000000000000000000000000000000000000081126000000000000000000000000000000000000000000000000000000000008112700000000000000000000000000000000000000000000000000000000000811280000000000000000000000000000000000000000000000000000000000081129000000000000000000000000000000000000000000000000000000000008112a000000000000000000000000000000000000000000000000000000000008112b000000000000000000000000000000000000000000000000000000000008112c000000000000000000000000000000000000000000000000000000000008112d000000000000000000000000000000000000000000000000000000000008112e000000000000000000000000000000000000000000000000000000000008112f0000000000000000000000000000000000000000000000000000000000081130000000000000000000000000000000000000000000000000000000000008113100000000000000000000000000000000000000000000000000000000000811320000000000000000000000000000000000000000000000000000000000081133000000000000000000000000000000000000000000000000000000000008113400000000000000000000000000000000000000000000000000000000000811350000000000000000000000000000000000000000000000000000000000081136000000000000000000000000000000000000000000000000000000000008113700000000000000000000000000000000000000000000000000000000000811380000000000000000000000000000000000000000000000000000000000081139000000000000000000000000000000000000000000000000000000000008113a000000000000000000000000000000000000000000000000000000000008113b000000000000000000000000000000000000000000000000000000000008113c000000000000000000000000000000000000000000000000000000000008113d000000000000000000000000000000000000000000000000000000000008113e08003c0472260790b0bdfb8ae4dc4d437e7686b73643f2198970d84e1059a5f13500bfd46275a318e438726ff2765ae154b63ab8a0daebcbed668a5f58a0e63dc1007906b9418dc758c6b4f8454c69baa48b7889b6b511d707abe8e2cb8f7c397300aeb60c4d65a44f122e58bf9565dfe2024b3ae654d5cf2e47ecb035d53c927000bf82e8cda20345f37bbb1de3932172324b57f0b98be483392697b168e3bba8000fb4bbad884ef30edf68e45a6cf2733fcf50310c69d7c1432b29af2c0aa8040023e1622d27fee3b4a40ab975ae0eb2e31619ef3dc76eb858f7fddb6a056131004689cd7007daf98dd3218b839b8e6a29f957154347b391fdb376bd0b344be23f0000000000000000000000000000000000000000000000000000000000082000000000000000000000000000000000000000000000000000000000000008200a0000000000000000000000000000000000000000000000000000000000082001000000000000000000000000000000000000000000000000000000000008200b0000000000000000000000000000000000000000000000000000000000082002000000000000000000000000000000000000000000000000000000000008200c0000000000000000000000000000000000000000000000000000000000082003000000000000000000000000000000000000000000000000000000000008200d0000000000000000000000000000000000000000000000000000000000082004000000000000000000000000000000000000000000000000000000000008200e0000000000000000000000000000000000000000000000000000000000082005000000000000000000000000000000000000000000000000000000000008200f00000000000000000000000000000000000000000000000000000000000820060000000000000000000000000000000000000000000000000000000000082010000000000000000000000000000000000000000000000000000000000008200700000000000000000000000000000000000000000000000000000000000820110000000000000000000000000000000000000000000000000000000000082008000000000000000000000000000000000000000000000000000000000008201200000000000000000000000000000000000000000000000000000000000820090000000000000000000000000000000000000000000000000000000000082013000000000000000000000000000000000000000000000000000000000008200a0000000000000000000000000000000000000000000000000000000000082014000000000000000000000000000000000000000000000000000000000008200b0000000000000000000000000000000000000000000000000000000000082015000000000000000000000000000000000000000000000000000000000008200c0000000000000000000000000000000000000000000000000000000000082016000000000000000000000000000000000000000000000000000000000008200d0000000000000000000000000000000000000000000000000000000000082017000000000000000000000000000000000000000000000000000000000008200e0000000000000000000000000000000000000000000000000000000000082018000000000000000000000000000000000000000000000000000000000008200f00000000000000000000000000000000000000000000000000000000000820190000000000000000000000000000000000000000000000000000000000082010000000000000000000000000000000000000000000000000000000000008201a0000000000000000000000000000000000000000000000000000000000082011000000000000000000000000000000000000000000000000000000000008201b0000000000000000000000000000000000000000000000000000000000082012000000000000000000000000000000000000000000000000000000000008201c0000000000000000000000000000000000000000000000000000000000082013000000000000000000000000000000000000000000000000000000000008201d0000000000000000000000000000000000000000000000000000000000082014000000000000000000000000000000000000000000000000000000000008201e0000000000000000000000000000000000000000000000000000000000082015000000000000000000000000000000000000000000000000000000000008201f00000000000000000000000000000000000000000000000000000000000820160000000000000000000000000000000000000000000000000000000000082020000000000000000000000000000000000000000000000000000000000008201700000000000000000000000000000000000000000000000000000000000820210000000000000000000000000000000000000000000000000000000000082018000000000000000000000000000000000000000000000000000000000008202200000000000000000000000000000000000000000000000000000000000820190000000000000000000000000000000000000000000000000000000000082023000000000000000000000000000000000000000000000000000000000008201a0000000000000000000000000000000000000000000000000000000000082024000000000000000000000000000000000000000000000000000000000008201b0000000000000000000000000000000000000000000000000000000000082025000000000000000000000000000000000000000000000000000000000008201c0000000000000000000000000000000000000000000000000000000000082026000000000000000000000000000000000000000000000000000000000008201d0000000000000000000000000000000000000000000000000000000000082027000000000000000000000000000000000000000000000000000000000008201e0000000000000000000000000000000000000000000000000000000000082028000000000000000000000000000000000000000000000000000000000008201f00000000000000000000000000000000000000000000000000000000000820290000000000000000000000000000000000000000000000000000000000082020000000000000000000000000000000000000000000000000000000000008202a0000000000000000000000000000000000000000000000000000000000082021000000000000000000000000000000000000000000000000000000000008202b0000000000000000000000000000000000000000000000000000000000082022000000000000000000000000000000000000000000000000000000000008202c0000000000000000000000000000000000000000000000000000000000082023000000000000000000000000000000000000000000000000000000000008202d0000000000000000000000000000000000000000000000000000000000082024000000000000000000000000000000000000000000000000000000000008202e0000000000000000000000000000000000000000000000000000000000082025000000000000000000000000000000000000000000000000000000000008202f00000000000000000000000000000000000000000000000000000000000820260000000000000000000000000000000000000000000000000000000000082030000000000000000000000000000000000000000000000000000000000008202700000000000000000000000000000000000000000000000000000000000820310000000000000000000000000000000000000000000000000000000000082028000000000000000000000000000000000000000000000000000000000008203200000000000000000000000000000000000000000000000000000000000820290000000000000000000000000000000000000000000000000000000000082033000000000000000000000000000000000000000000000000000000000008202a0000000000000000000000000000000000000000000000000000000000082034000000000000000000000000000000000000000000000000000000000008202b0000000000000000000000000000000000000000000000000000000000082035000000000000000000000000000000000000000000000000000000000008202c0000000000000000000000000000000000000000000000000000000000082036000000000000000000000000000000000000000000000000000000000008202d0000000000000000000000000000000000000000000000000000000000082037000000000000000000000000000000000000000000000000000000000008202e0000000000000000000000000000000000000000000000000000000000082038000000000000000000000000000000000000000000000000000000000008202f00000000000000000000000000000000000000000000000000000000000820390000000000000000000000000000000000000000000000000000000000082030000000000000000000000000000000000000000000000000000000000008203a0000000000000000000000000000000000000000000000000000000000082031000000000000000000000000000000000000000000000000000000000008203b0000000000000000000000000000000000000000000000000000000000082032000000000000000000000000000000000000000000000000000000000008203c0000000000000000000000000000000000000000000000000000000000082033000000000000000000000000000000000000000000000000000000000008203d0000000000000000000000000000000000000000000000000000000000082034000000000000000000000000000000000000000000000000000000000008203e0000000000000000000000000000000000000000000000000000000000082035000000000000000000000000000000000000000000000000000000000008203f00000000000000000000000000000000000000000000000000000000000820360000000000000000000000000000000000000000000000000000000000082040000000000000000000000000000000000000000000000000000000000008203700000000000000000000000000000000000000000000000000000000000820410000000000000000000000000000000000000000000000000000000000082038000000000000000000000000000000000000000000000000000000000008204200000000000000000000000000000000000000000000000000000000000820390000000000000000000000000000000000000000000000000000000000082043000000000000000000000000000000000000000000000000000000000008203a0000000000000000000000000000000000000000000000000000000000082044000000000000000000000000000000000000000000000000000000000008203b0000000000000000000000000000000000000000000000000000000000082045000000000000000000000000000000000000000000000000000000000008203c0000000000000000000000000000000000000000000000000000000000082046000000000000000000000000000000000000000000000000000000000008203d0000000000000000000000000000000000000000000000000000000000082047000000000000000000000000000000000000000000000000000000000008203e00000000000000000000000000000000000000000000000000000000000820480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000c100000000000000000000000000000000000000000000000000000000000000c100100000000000000000000000000000000000000000000000000000000000c100200000000000000000000000000000000000000000000000000000000000c100300000000000000000000000000000000000000000000000000000000000c100400000000000000000000000000000000000000000000000000000000000c100500000000000000000000000000000000000000000000000000000000000c100600000000000000000000000000000000000000000000000000000000000c100700000000000000000000000000000000000000000000000000000000000c100800000000000000000000000000000000000000000000000000000000000c100900000000000000000000000000000000000000000000000000000000000c100a00000000000000000000000000000000000000000000000000000000000c100b00000000000000000000000000000000000000000000000000000000000c100c00000000000000000000000000000000000000000000000000000000000c100d00000000000000000000000000000000000000000000000000000000000c100e00000000000000000000000000000000000000000000000000000000000c100f00000000000000000000000000000000000000000000000000000000000c101000000000000000000000000000000000000000000000000000000000000c101100000000000000000000000000000000000000000000000000000000000c101200000000000000000000000000000000000000000000000000000000000c101300000000000000000000000000000000000000000000000000000000000c101400000000000000000000000000000000000000000000000000000000000c101500000000000000000000000000000000000000000000000000000000000c101600000000000000000000000000000000000000000000000000000000000c101700000000000000000000000000000000000000000000000000000000000c101800000000000000000000000000000000000000000000000000000000000c101900000000000000000000000000000000000000000000000000000000000c101a00000000000000000000000000000000000000000000000000000000000c101b00000000000000000000000000000000000000000000000000000000000c101c00000000000000000000000000000000000000000000000000000000000c101d00000000000000000000000000000000000000000000000000000000000c101e00000000000000000000000000000000000000000000000000000000000c101f00000000000000000000000000000000000000000000000000000000000c102000000000000000000000000000000000000000000000000000000000000c102100000000000000000000000000000000000000000000000000000000000c102200000000000000000000000000000000000000000000000000000000000c102300000000000000000000000000000000000000000000000000000000000c102400000000000000000000000000000000000000000000000000000000000c102500000000000000000000000000000000000000000000000000000000000c102600000000000000000000000000000000000000000000000000000000000c102700000000000000000000000000000000000000000000000000000000000c102800000000000000000000000000000000000000000000000000000000000c102900000000000000000000000000000000000000000000000000000000000c102a00000000000000000000000000000000000000000000000000000000000c102b00000000000000000000000000000000000000000000000000000000000c102c00000000000000000000000000000000000000000000000000000000000c102d00000000000000000000000000000000000000000000000000000000000c102e00000000000000000000000000000000000000000000000000000000000c102f00000000000000000000000000000000000000000000000000000000000c103000000000000000000000000000000000000000000000000000000000000c103100000000000000000000000000000000000000000000000000000000000c103200000000000000000000000000000000000000000000000000000000000c103300000000000000000000000000000000000000000000000000000000000c103400000000000000000000000000000000000000000000000000000000000c103500000000000000000000000000000000000000000000000000000000000c103600000000000000000000000000000000000000000000000000000000000c103700000000000000000000000000000000000000000000000000000000000c103800000000000000000000000000000000000000000000000000000000000c103900000000000000000000000000000000000000000000000000000000000c103a00000000000000000000000000000000000000000000000000000000000c103b00000000000000000000000000000000000000000000000000000000000c103c00000000000000000000000000000000000000000000000000000000000c103d00000000000000000000000000000000000000000000000000000000000c103e00000000000000000000000000000000000000000000000000000000000c103f3f00000000000000000000000000000000000000000000000000000000000c110000000000000000000000000000000000000000000000000000000000000c110100000000000000000000000000000000000000000000000000000000000c110200000000000000000000000000000000000000000000000000000000000c110300000000000000000000000000000000000000000000000000000000000c110400000000000000000000000000000000000000000000000000000000000c110500000000000000000000000000000000000000000000000000000000000c110600000000000000000000000000000000000000000000000000000000000c110700000000000000000000000000000000000000000000000000000000000c110800000000000000000000000000000000000000000000000000000000000c110900000000000000000000000000000000000000000000000000000000000c110a00000000000000000000000000000000000000000000000000000000000c110b00000000000000000000000000000000000000000000000000000000000c110c00000000000000000000000000000000000000000000000000000000000c110d00000000000000000000000000000000000000000000000000000000000c110e00000000000000000000000000000000000000000000000000000000000c110f00000000000000000000000000000000000000000000000000000000000c111000000000000000000000000000000000000000000000000000000000000c111100000000000000000000000000000000000000000000000000000000000c111200000000000000000000000000000000000000000000000000000000000c111300000000000000000000000000000000000000000000000000000000000c111400000000000000000000000000000000000000000000000000000000000c111500000000000000000000000000000000000000000000000000000000000c111600000000000000000000000000000000000000000000000000000000000c111700000000000000000000000000000000000000000000000000000000000c111800000000000000000000000000000000000000000000000000000000000c111900000000000000000000000000000000000000000000000000000000000c111a00000000000000000000000000000000000000000000000000000000000c111b00000000000000000000000000000000000000000000000000000000000c111c00000000000000000000000000000000000000000000000000000000000c111d00000000000000000000000000000000000000000000000000000000000c111e00000000000000000000000000000000000000000000000000000000000c111f00000000000000000000000000000000000000000000000000000000000c112000000000000000000000000000000000000000000000000000000000000c112100000000000000000000000000000000000000000000000000000000000c112200000000000000000000000000000000000000000000000000000000000c112300000000000000000000000000000000000000000000000000000000000c112400000000000000000000000000000000000000000000000000000000000c112500000000000000000000000000000000000000000000000000000000000c112600000000000000000000000000000000000000000000000000000000000c112700000000000000000000000000000000000000000000000000000000000c112800000000000000000000000000000000000000000000000000000000000c112900000000000000000000000000000000000000000000000000000000000c112a00000000000000000000000000000000000000000000000000000000000c112b00000000000000000000000000000000000000000000000000000000000c112c00000000000000000000000000000000000000000000000000000000000c112d00000000000000000000000000000000000000000000000000000000000c112e00000000000000000000000000000000000000000000000000000000000c112f00000000000000000000000000000000000000000000000000000000000c113000000000000000000000000000000000000000000000000000000000000c113100000000000000000000000000000000000000000000000000000000000c113200000000000000000000000000000000000000000000000000000000000c113300000000000000000000000000000000000000000000000000000000000c113400000000000000000000000000000000000000000000000000000000000c113500000000000000000000000000000000000000000000000000000000000c113600000000000000000000000000000000000000000000000000000000000c113700000000000000000000000000000000000000000000000000000000000c113800000000000000000000000000000000000000000000000000000000000c113900000000000000000000000000000000000000000000000000000000000c113a00000000000000000000000000000000000000000000000000000000000c113b00000000000000000000000000000000000000000000000000000000000c113c00000000000000000000000000000000000000000000000000000000000c113d00000000000000000000000000000000000000000000000000000000000c113e0800f8029be42ec3f25204907ca981fb71e5b357093eb5db10fc01ca98a4e4154c0030e13d351a5bf1d5a040e82a163ca57017f39162693f85c571e441e36d702d00a550ae0f39f977d9473d6de1be3232fc68ed0c4a601d53542148695102cfc9005580bc65e4bff9c8fffa64db02c0fa6af14d9d26fd962f4c5904cbd3ddec2500758c4a0d43dfec788b2f580877c4f473adec8f168ea24424f2600e4eb4916f00342602bf90d10f8ca8e582a894dcc4c02bb89fe458532e0c632b53bae54b4d00ca43ab78ab834337e9964d84a0674c9adabdca140539c5a6bc96e0ba9a51f6004ffbfd91be292a7c6a0e255e50caa156ac2d628b40ad2128c4ab63a92d8a1c3f00000000000000000000000000000000000000000000000000000000000c200000000000000000000000000000000000000000000000000000000000000c200a00000000000000000000000000000000000000000000000000000000000c200100000000000000000000000000000000000000000000000000000000000c200b00000000000000000000000000000000000000000000000000000000000c200200000000000000000000000000000000000000000000000000000000000c200c00000000000000000000000000000000000000000000000000000000000c200300000000000000000000000000000000000000000000000000000000000c200d00000000000000000000000000000000000000000000000000000000000c200400000000000000000000000000000000000000000000000000000000000c200e00000000000000000000000000000000000000000000000000000000000c200500000000000000000000000000000000000000000000000000000000000c200f00000000000000000000000000000000000000000000000000000000000c200600000000000000000000000000000000000000000000000000000000000c201000000000000000000000000000000000000000000000000000000000000c200700000000000000000000000000000000000000000000000000000000000c201100000000000000000000000000000000000000000000000000000000000c200800000000000000000000000000000000000000000000000000000000000c201200000000000000000000000000000000000000000000000000000000000c200900000000000000000000000000000000000000000000000000000000000c201300000000000000000000000000000000000000000000000000000000000c200a00000000000000000000000000000000000000000000000000000000000c201400000000000000000000000000000000000000000000000000000000000c200b00000000000000000000000000000000000000000000000000000000000c201500000000000000000000000000000000000000000000000000000000000c200c00000000000000000000000000000000000000000000000000000000000c201600000000000000000000000000000000000000000000000000000000000c200d00000000000000000000000000000000000000000000000000000000000c201700000000000000000000000000000000000000000000000000000000000c200e00000000000000000000000000000000000000000000000000000000000c201800000000000000000000000000000000000000000000000000000000000c200f00000000000000000000000000000000000000000000000000000000000c201900000000000000000000000000000000000000000000000000000000000c201000000000000000000000000000000000000000000000000000000000000c201a00000000000000000000000000000000000000000000000000000000000c201100000000000000000000000000000000000000000000000000000000000c201b00000000000000000000000000000000000000000000000000000000000c201200000000000000000000000000000000000000000000000000000000000c201c00000000000000000000000000000000000000000000000000000000000c201300000000000000000000000000000000000000000000000000000000000c201d00000000000000000000000000000000000000000000000000000000000c201400000000000000000000000000000000000000000000000000000000000c201e00000000000000000000000000000000000000000000000000000000000c201500000000000000000000000000000000000000000000000000000000000c201f00000000000000000000000000000000000000000000000000000000000c201600000000000000000000000000000000000000000000000000000000000c202000000000000000000000000000000000000000000000000000000000000c201700000000000000000000000000000000000000000000000000000000000c202100000000000000000000000000000000000000000000000000000000000c201800000000000000000000000000000000000000000000000000000000000c202200000000000000000000000000000000000000000000000000000000000c201900000000000000000000000000000000000000000000000000000000000c202300000000000000000000000000000000000000000000000000000000000c201a00000000000000000000000000000000000000000000000000000000000c202400000000000000000000000000000000000000000000000000000000000c201b00000000000000000000000000000000000000000000000000000000000c202500000000000000000000000000000000000000000000000000000000000c201c00000000000000000000000000000000000000000000000000000000000c202600000000000000000000000000000000000000000000000000000000000c201d00000000000000000000000000000000000000000000000000000000000c202700000000000000000000000000000000000000000000000000000000000c201e00000000000000000000000000000000000000000000000000000000000c202800000000000000000000000000000000000000000000000000000000000c201f00000000000000000000000000000000000000000000000000000000000c202900000000000000000000000000000000000000000000000000000000000c202000000000000000000000000000000000000000000000000000000000000c202a00000000000000000000000000000000000000000000000000000000000c202100000000000000000000000000000000000000000000000000000000000c202b00000000000000000000000000000000000000000000000000000000000c202200000000000000000000000000000000000000000000000000000000000c202c00000000000000000000000000000000000000000000000000000000000c202300000000000000000000000000000000000000000000000000000000000c202d00000000000000000000000000000000000000000000000000000000000c202400000000000000000000000000000000000000000000000000000000000c202e00000000000000000000000000000000000000000000000000000000000c202500000000000000000000000000000000000000000000000000000000000c202f00000000000000000000000000000000000000000000000000000000000c202600000000000000000000000000000000000000000000000000000000000c203000000000000000000000000000000000000000000000000000000000000c202700000000000000000000000000000000000000000000000000000000000c203100000000000000000000000000000000000000000000000000000000000c202800000000000000000000000000000000000000000000000000000000000c203200000000000000000000000000000000000000000000000000000000000c202900000000000000000000000000000000000000000000000000000000000c203300000000000000000000000000000000000000000000000000000000000c202a00000000000000000000000000000000000000000000000000000000000c203400000000000000000000000000000000000000000000000000000000000c202b00000000000000000000000000000000000000000000000000000000000c203500000000000000000000000000000000000000000000000000000000000c202c00000000000000000000000000000000000000000000000000000000000c203600000000000000000000000000000000000000000000000000000000000c202d00000000000000000000000000000000000000000000000000000000000c203700000000000000000000000000000000000000000000000000000000000c202e00000000000000000000000000000000000000000000000000000000000c203800000000000000000000000000000000000000000000000000000000000c202f00000000000000000000000000000000000000000000000000000000000c203900000000000000000000000000000000000000000000000000000000000c203000000000000000000000000000000000000000000000000000000000000c203a00000000000000000000000000000000000000000000000000000000000c203100000000000000000000000000000000000000000000000000000000000c203b00000000000000000000000000000000000000000000000000000000000c203200000000000000000000000000000000000000000000000000000000000c203c00000000000000000000000000000000000000000000000000000000000c203300000000000000000000000000000000000000000000000000000000000c203d00000000000000000000000000000000000000000000000000000000000c203400000000000000000000000000000000000000000000000000000000000c203e00000000000000000000000000000000000000000000000000000000000c203500000000000000000000000000000000000000000000000000000000000c203f00000000000000000000000000000000000000000000000000000000000c203600000000000000000000000000000000000000000000000000000000000c204000000000000000000000000000000000000000000000000000000000000c203700000000000000000000000000000000000000000000000000000000000c204100000000000000000000000000000000000000000000000000000000000c203800000000000000000000000000000000000000000000000000000000000c204200000000000000000000000000000000000000000000000000000000000c203900000000000000000000000000000000000000000000000000000000000c204300000000000000000000000000000000000000000000000000000000000c203a00000000000000000000000000000000000000000000000000000000000c204400000000000000000000000000000000000000000000000000000000000c203b00000000000000000000000000000000000000000000000000000000000c204500000000000000000000000000000000000000000000000000000000000c203c00000000000000000000000000000000000000000000000000000000000c204600000000000000000000000000000000000000000000000000000000000c203d00000000000000000000000000000000000000000000000000000000000c204700000000000000000000000000000000000000000000000000000000000c203e00000000000000000000000000000000000000000000000000000000000c2048000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000101000000000000000000000000000000000000000000000000000000000000010100100000000000000000000000000000000000000000000000000000000001010020000000000000000000000000000000000000000000000000000000000101003000000000000000000000000000000000000000000000000000000000010100400000000000000000000000000000000000000000000000000000000001010050000000000000000000000000000000000000000000000000000000000101006000000000000000000000000000000000000000000000000000000000010100700000000000000000000000000000000000000000000000000000000001010080000000000000000000000000000000000000000000000000000000000101009000000000000000000000000000000000000000000000000000000000010100a000000000000000000000000000000000000000000000000000000000010100b000000000000000000000000000000000000000000000000000000000010100c000000000000000000000000000000000000000000000000000000000010100d000000000000000000000000000000000000000000000000000000000010100e000000000000000000000000000000000000000000000000000000000010100f0000000000000000000000000000000000000000000000000000000000101010000000000000000000000000000000000000000000000000000000000010101100000000000000000000000000000000000000000000000000000000001010120000000000000000000000000000000000000000000000000000000000101013000000000000000000000000000000000000000000000000000000000010101400000000000000000000000000000000000000000000000000000000001010150000000000000000000000000000000000000000000000000000000000101016000000000000000000000000000000000000000000000000000000000010101700000000000000000000000000000000000000000000000000000000001010180000000000000000000000000000000000000000000000000000000000101019000000000000000000000000000000000000000000000000000000000010101a000000000000000000000000000000000000000000000000000000000010101b000000000000000000000000000000000000000000000000000000000010101c000000000000000000000000000000000000000000000000000000000010101d000000000000000000000000000000000000000000000000000000000010101e000000000000000000000000000000000000000000000000000000000010101f0000000000000000000000000000000000000000000000000000000000101020000000000000000000000000000000000000000000000000000000000010102100000000000000000000000000000000000000000000000000000000001010220000000000000000000000000000000000000000000000000000000000101023000000000000000000000000000000000000000000000000000000000010102400000000000000000000000000000000000000000000000000000000001010250000000000000000000000000000000000000000000000000000000000101026000000000000000000000000000000000000000000000000000000000010102700000000000000000000000000000000000000000000000000000000001010280000000000000000000000000000000000000000000000000000000000101029000000000000000000000000000000000000000000000000000000000010102a000000000000000000000000000000000000000000000000000000000010102b000000000000000000000000000000000000000000000000000000000010102c000000000000000000000000000000000000000000000000000000000010102d000000000000000000000000000000000000000000000000000000000010102e000000000000000000000000000000000000000000000000000000000010102f0000000000000000000000000000000000000000000000000000000000101030000000000000000000000000000000000000000000000000000000000010103100000000000000000000000000000000000000000000000000000000001010320000000000000000000000000000000000000000000000000000000000101033000000000000000000000000000000000000000000000000000000000010103400000000000000000000000000000000000000000000000000000000001010350000000000000000000000000000000000000000000000000000000000101036000000000000000000000000000000000000000000000000000000000010103700000000000000000000000000000000000000000000000000000000001010380000000000000000000000000000000000000000000000000000000000101039000000000000000000000000000000000000000000000000000000000010103a000000000000000000000000000000000000000000000000000000000010103b000000000000000000000000000000000000000000000000000000000010103c000000000000000000000000000000000000000000000000000000000010103d000000000000000000000000000000000000000000000000000000000010103e000000000000000000000000000000000000000000000000000000000010103f3f0000000000000000000000000000000000000000000000000000000000101100000000000000000000000000000000000000000000000000000000000010110100000000000000000000000000000000000000000000000000000000001011020000000000000000000000000000000000000000000000000000000000101103000000000000000000000000000000000000000000000000000000000010110400000000000000000000000000000000000000000000000000000000001011050000000000000000000000000000000000000000000000000000000000101106000000000000000000000000000000000000000000000000000000000010110700000000000000000000000000000000000000000000000000000000001011080000000000000000000000000000000000000000000000000000000000101109000000000000000000000000000000000000000000000000000000000010110a000000000000000000000000000000000000000000000000000000000010110b000000000000000000000000000000000000000000000000000000000010110c000000000000000000000000000000000000000000000000000000000010110d000000000000000000000000000000000000000000000000000000000010110e000000000000000000000000000000000000000000000000000000000010110f0000000000000000000000000000000000000000000000000000000000101110000000000000000000000000000000000000000000000000000000000010111100000000000000000000000000000000000000000000000000000000001011120000000000000000000000000000000000000000000000000000000000101113000000000000000000000000000000000000000000000000000000000010111400000000000000000000000000000000000000000000000000000000001011150000000000000000000000000000000000000000000000000000000000101116000000000000000000000000000000000000000000000000000000000010111700000000000000000000000000000000000000000000000000000000001011180000000000000000000000000000000000000000000000000000000000101119000000000000000000000000000000000000000000000000000000000010111a000000000000000000000000000000000000000000000000000000000010111b000000000000000000000000000000000000000000000000000000000010111c000000000000000000000000000000000000000000000000000000000010111d000000000000000000000000000000000000000000000000000000000010111e000000000000000000000000000000000000000000000000000000000010111f0000000000000000000000000000000000000000000000000000000000101120000000000000000000000000000000000000000000000000000000000010112100000000000000000000000000000000000000000000000000000000001011220000000000000000000000000000000000000000000000000000000000101123000000000000000000000000000000000000000000000000000000000010112400000000000000000000000000000000000000000000000000000000001011250000000000000000000000000000000000000000000000000000000000101126000000000000000000000000000000000000000000000000000000000010112700000000000000000000000000000000000000000000000000000000001011280000000000000000000000000000000000000000000000000000000000101129000000000000000000000000000000000000000000000000000000000010112a000000000000000000000000000000000000000000000000000000000010112b000000000000000000000000000000000000000000000000000000000010112c000000000000000000000000000000000000000000000000000000000010112d000000000000000000000000000000000000000000000000000000000010112e000000000000000000000000000000000000000000000000000000000010112f0000000000000000000000000000000000000000000000000000000000101130000000000000000000000000000000000000000000000000000000000010113100000000000000000000000000000000000000000000000000000000001011320000000000000000000000000000000000000000000000000000000000101133000000000000000000000000000000000000000000000000000000000010113400000000000000000000000000000000000000000000000000000000001011350000000000000000000000000000000000000000000000000000000000101136000000000000000000000000000000000000000000000000000000000010113700000000000000000000000000000000000000000000000000000000001011380000000000000000000000000000000000000000000000000000000000101139000000000000000000000000000000000000000000000000000000000010113a000000000000000000000000000000000000000000000000000000000010113b000000000000000000000000000000000000000000000000000000000010113c000000000000000000000000000000000000000000000000000000000010113d000000000000000000000000000000000000000000000000000000000010113e080099145b6c0d32753835121f8b271186d01236948a4622ce78a98347fcfc98390085277a27c6acbd5ffc4c19cd65fc30056999e9bec36998f753132db0ff8e2300f3cf77a7261759ebd5f4149f6ad56746f4499cfcd4adf27a1d373f77da64d5009bc6e0e994a23cde8c95b90c1acc1b4a480c6599d1df2c3f9f6e76f3d1aff200d7a1c4a2700dacaaf07f1f0ff33837bdbabcf0b9ace17efabe0761708c4bb900dbeb8e96d14f21e57d5786b6d6ae7e5ddb1bb35935c0fb246d4bdbca62e02c00fbf12b5e0df6223b801088798e4e04d2a92ffe9a11639b7f0ce314e3412a8000d796e0724de03b796ba77069fcd6cf921e566f3aed15eb3e77258add74e9ff3f0000000000000000000000000000000000000000000000000000000000102000000000000000000000000000000000000000000000000000000000000010200a0000000000000000000000000000000000000000000000000000000000102001000000000000000000000000000000000000000000000000000000000010200b0000000000000000000000000000000000000000000000000000000000102002000000000000000000000000000000000000000000000000000000000010200c0000000000000000000000000000000000000000000000000000000000102003000000000000000000000000000000000000000000000000000000000010200d0000000000000000000000000000000000000000000000000000000000102004000000000000000000000000000000000000000000000000000000000010200e0000000000000000000000000000000000000000000000000000000000102005000000000000000000000000000000000000000000000000000000000010200f00000000000000000000000000000000000000000000000000000000001020060000000000000000000000000000000000000000000000000000000000102010000000000000000000000000000000000000000000000000000000000010200700000000000000000000000000000000000000000000000000000000001020110000000000000000000000000000000000000000000000000000000000102008000000000000000000000000000000000000000000000000000000000010201200000000000000000000000000000000000000000000000000000000001020090000000000000000000000000000000000000000000000000000000000102013000000000000000000000000000000000000000000000000000000000010200a0000000000000000000000000000000000000000000000000000000000102014000000000000000000000000000000000000000000000000000000000010200b0000000000000000000000000000000000000000000000000000000000102015000000000000000000000000000000000000000000000000000000000010200c0000000000000000000000000000000000000000000000000000000000102016000000000000000000000000000000000000000000000000000000000010200d0000000000000000000000000000000000000000000000000000000000102017000000000000000000000000000000000000000000000000000000000010200e0000000000000000000000000000000000000000000000000000000000102018000000000000000000000000000000000000000000000000000000000010200f00000000000000000000000000000000000000000000000000000000001020190000000000000000000000000000000000000000000000000000000000102010000000000000000000000000000000000000000000000000000000000010201a0000000000000000000000000000000000000000000000000000000000102011000000000000000000000000000000000000000000000000000000000010201b0000000000000000000000000000000000000000000000000000000000102012000000000000000000000000000000000000000000000000000000000010201c0000000000000000000000000000000000000000000000000000000000102013000000000000000000000000000000000000000000000000000000000010201d0000000000000000000000000000000000000000000000000000000000102014000000000000000000000000000000000000000000000000000000000010201e0000000000000000000000000000000000000000000000000000000000102015000000000000000000000000000000000000000000000000000000000010201f00000000000000000000000000000000000000000000000000000000001020160000000000000000000000000000000000000000000000000000000000102020000000000000000000000000000000000000000000000000000000000010201700000000000000000000000000000000000000000000000000000000001020210000000000000000000000000000000000000000000000000000000000102018000000000000000000000000000000000000000000000000000000000010202200000000000000000000000000000000000000000000000000000000001020190000000000000000000000000000000000000000000000000000000000102023000000000000000000000000000000000000000000000000000000000010201a0000000000000000000000000000000000000000000000000000000000102024000000000000000000000000000000000000000000000000000000000010201b0000000000000000000000000000000000000000000000000000000000102025000000000000000000000000000000000000000000000000000000000010201c0000000000000000000000000000000000000000000000000000000000102026000000000000000000000000000000000000000000000000000000000010201d0000000000000000000000000000000000000000000000000000000000102027000000000000000000000000000000000000000000000000000000000010201e0000000000000000000000000000000000000000000000000000000000102028000000000000000000000000000000000000000000000000000000000010201f00000000000000000000000000000000000000000000000000000000001020290000000000000000000000000000000000000000000000000000000000102020000000000000000000000000000000000000000000000000000000000010202a0000000000000000000000000000000000000000000000000000000000102021000000000000000000000000000000000000000000000000000000000010202b0000000000000000000000000000000000000000000000000000000000102022000000000000000000000000000000000000000000000000000000000010202c0000000000000000000000000000000000000000000000000000000000102023000000000000000000000000000000000000000000000000000000000010202d0000000000000000000000000000000000000000000000000000000000102024000000000000000000000000000000000000000000000000000000000010202e0000000000000000000000000000000000000000000000000000000000102025000000000000000000000000000000000000000000000000000000000010202f00000000000000000000000000000000000000000000000000000000001020260000000000000000000000000000000000000000000000000000000000102030000000000000000000000000000000000000000000000000000000000010202700000000000000000000000000000000000000000000000000000000001020310000000000000000000000000000000000000000000000000000000000102028000000000000000000000000000000000000000000000000000000000010203200000000000000000000000000000000000000000000000000000000001020290000000000000000000000000000000000000000000000000000000000102033000000000000000000000000000000000000000000000000000000000010202a0000000000000000000000000000000000000000000000000000000000102034000000000000000000000000000000000000000000000000000000000010202b0000000000000000000000000000000000000000000000000000000000102035000000000000000000000000000000000000000000000000000000000010202c0000000000000000000000000000000000000000000000000000000000102036000000000000000000000000000000000000000000000000000000000010202d0000000000000000000000000000000000000000000000000000000000102037000000000000000000000000000000000000000000000000000000000010202e0000000000000000000000000000000000000000000000000000000000102038000000000000000000000000000000000000000000000000000000000010202f00000000000000000000000000000000000000000000000000000000001020390000000000000000000000000000000000000000000000000000000000102030000000000000000000000000000000000000000000000000000000000010203a0000000000000000000000000000000000000000000000000000000000102031000000000000000000000000000000000000000000000000000000000010203b0000000000000000000000000000000000000000000000000000000000102032000000000000000000000000000000000000000000000000000000000010203c0000000000000000000000000000000000000000000000000000000000102033000000000000000000000000000000000000000000000000000000000010203d0000000000000000000000000000000000000000000000000000000000102034000000000000000000000000000000000000000000000000000000000010203e0000000000000000000000000000000000000000000000000000000000102035000000000000000000000000000000000000000000000000000000000010203f00000000000000000000000000000000000000000000000000000000001020360000000000000000000000000000000000000000000000000000000000102040000000000000000000000000000000000000000000000000000000000010203700000000000000000000000000000000000000000000000000000000001020410000000000000000000000000000000000000000000000000000000000102038000000000000000000000000000000000000000000000000000000000010204200000000000000000000000000000000000000000000000000000000001020390000000000000000000000000000000000000000000000000000000000102043000000000000000000000000000000000000000000000000000000000010203a0000000000000000000000000000000000000000000000000000000000102044000000000000000000000000000000000000000000000000000000000010203b0000000000000000000000000000000000000000000000000000000000102045000000000000000000000000000000000000000000000000000000000010203c0000000000000000000000000000000000000000000000000000000000102046000000000000000000000000000000000000000000000000000000000010203d0000000000000000000000000000000000000000000000000000000000102047000000000000000000000000000000000000000000000000000000000010203e0000000000000000000000000000000000000000000000000000000000102048000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "txsEffectsHash": "0x00db66b36b24ebccb7543a74620018056cad2f0b08eaf251ad00362551f0a2d0", + "archive": "0x1cff61d39a2f942d4f96fe19dd6acba151dda8180b9251f5db3ad4865ff4cbf7", + "blockHash": "0x1145ae8e8b4198948eb566676224c83550d5a9f58589c3e306a7d1ff391a4f96", + "body": "0x00000004000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000041000000000000000000000000000000000000000000000000000000000000004100100000000000000000000000000000000000000000000000000000000000410020000000000000000000000000000000000000000000000000000000000041003000000000000000000000000000000000000000000000000000000000004100400000000000000000000000000000000000000000000000000000000000410050000000000000000000000000000000000000000000000000000000000041006000000000000000000000000000000000000000000000000000000000004100700000000000000000000000000000000000000000000000000000000000410080000000000000000000000000000000000000000000000000000000000041009000000000000000000000000000000000000000000000000000000000004100a000000000000000000000000000000000000000000000000000000000004100b000000000000000000000000000000000000000000000000000000000004100c000000000000000000000000000000000000000000000000000000000004100d000000000000000000000000000000000000000000000000000000000004100e000000000000000000000000000000000000000000000000000000000004100f0000000000000000000000000000000000000000000000000000000000041010000000000000000000000000000000000000000000000000000000000004101100000000000000000000000000000000000000000000000000000000000410120000000000000000000000000000000000000000000000000000000000041013000000000000000000000000000000000000000000000000000000000004101400000000000000000000000000000000000000000000000000000000000410150000000000000000000000000000000000000000000000000000000000041016000000000000000000000000000000000000000000000000000000000004101700000000000000000000000000000000000000000000000000000000000410180000000000000000000000000000000000000000000000000000000000041019000000000000000000000000000000000000000000000000000000000004101a000000000000000000000000000000000000000000000000000000000004101b000000000000000000000000000000000000000000000000000000000004101c000000000000000000000000000000000000000000000000000000000004101d000000000000000000000000000000000000000000000000000000000004101e000000000000000000000000000000000000000000000000000000000004101f0000000000000000000000000000000000000000000000000000000000041020000000000000000000000000000000000000000000000000000000000004102100000000000000000000000000000000000000000000000000000000000410220000000000000000000000000000000000000000000000000000000000041023000000000000000000000000000000000000000000000000000000000004102400000000000000000000000000000000000000000000000000000000000410250000000000000000000000000000000000000000000000000000000000041026000000000000000000000000000000000000000000000000000000000004102700000000000000000000000000000000000000000000000000000000000410280000000000000000000000000000000000000000000000000000000000041029000000000000000000000000000000000000000000000000000000000004102a000000000000000000000000000000000000000000000000000000000004102b000000000000000000000000000000000000000000000000000000000004102c000000000000000000000000000000000000000000000000000000000004102d000000000000000000000000000000000000000000000000000000000004102e000000000000000000000000000000000000000000000000000000000004102f0000000000000000000000000000000000000000000000000000000000041030000000000000000000000000000000000000000000000000000000000004103100000000000000000000000000000000000000000000000000000000000410320000000000000000000000000000000000000000000000000000000000041033000000000000000000000000000000000000000000000000000000000004103400000000000000000000000000000000000000000000000000000000000410350000000000000000000000000000000000000000000000000000000000041036000000000000000000000000000000000000000000000000000000000004103700000000000000000000000000000000000000000000000000000000000410380000000000000000000000000000000000000000000000000000000000041039000000000000000000000000000000000000000000000000000000000004103a000000000000000000000000000000000000000000000000000000000004103b000000000000000000000000000000000000000000000000000000000004103c000000000000000000000000000000000000000000000000000000000004103d000000000000000000000000000000000000000000000000000000000004103e000000000000000000000000000000000000000000000000000000000004103f4000000000000000000000000000000000000000000000000000000000000400010000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004110100000000000000000000000000000000000000000000000000000000000411020000000000000000000000000000000000000000000000000000000000041103000000000000000000000000000000000000000000000000000000000004110400000000000000000000000000000000000000000000000000000000000411050000000000000000000000000000000000000000000000000000000000041106000000000000000000000000000000000000000000000000000000000004110700000000000000000000000000000000000000000000000000000000000411080000000000000000000000000000000000000000000000000000000000041109000000000000000000000000000000000000000000000000000000000004110a000000000000000000000000000000000000000000000000000000000004110b000000000000000000000000000000000000000000000000000000000004110c000000000000000000000000000000000000000000000000000000000004110d000000000000000000000000000000000000000000000000000000000004110e000000000000000000000000000000000000000000000000000000000004110f0000000000000000000000000000000000000000000000000000000000041110000000000000000000000000000000000000000000000000000000000004111100000000000000000000000000000000000000000000000000000000000411120000000000000000000000000000000000000000000000000000000000041113000000000000000000000000000000000000000000000000000000000004111400000000000000000000000000000000000000000000000000000000000411150000000000000000000000000000000000000000000000000000000000041116000000000000000000000000000000000000000000000000000000000004111700000000000000000000000000000000000000000000000000000000000411180000000000000000000000000000000000000000000000000000000000041119000000000000000000000000000000000000000000000000000000000004111a000000000000000000000000000000000000000000000000000000000004111b000000000000000000000000000000000000000000000000000000000004111c000000000000000000000000000000000000000000000000000000000004111d000000000000000000000000000000000000000000000000000000000004111e000000000000000000000000000000000000000000000000000000000004111f0000000000000000000000000000000000000000000000000000000000041120000000000000000000000000000000000000000000000000000000000004112100000000000000000000000000000000000000000000000000000000000411220000000000000000000000000000000000000000000000000000000000041123000000000000000000000000000000000000000000000000000000000004112400000000000000000000000000000000000000000000000000000000000411250000000000000000000000000000000000000000000000000000000000041126000000000000000000000000000000000000000000000000000000000004112700000000000000000000000000000000000000000000000000000000000411280000000000000000000000000000000000000000000000000000000000041129000000000000000000000000000000000000000000000000000000000004112a000000000000000000000000000000000000000000000000000000000004112b000000000000000000000000000000000000000000000000000000000004112c000000000000000000000000000000000000000000000000000000000004112d000000000000000000000000000000000000000000000000000000000004112e000000000000000000000000000000000000000000000000000000000004112f0000000000000000000000000000000000000000000000000000000000041130000000000000000000000000000000000000000000000000000000000004113100000000000000000000000000000000000000000000000000000000000411320000000000000000000000000000000000000000000000000000000000041133000000000000000000000000000000000000000000000000000000000004113400000000000000000000000000000000000000000000000000000000000411350000000000000000000000000000000000000000000000000000000000041136000000000000000000000000000000000000000000000000000000000004113700000000000000000000000000000000000000000000000000000000000411380000000000000000000000000000000000000000000000000000000000041139000000000000000000000000000000000000000000000000000000000004113a000000000000000000000000000000000000000000000000000000000004113b000000000000000000000000000000000000000000000000000000000004113c000000000000000000000000000000000000000000000000000000000004113d000000000000000000000000000000000000000000000000000000000004113e080097a6ec570e9b8e257647c9c74c5ad3edc57ca5ef6ae44d80b3c30d1d99b9b300ce48ec41d1edde0066fab553a456ae2f380d14fa8f956af1fb0217513a598900619ff12eaf97f63aa2a2311de3b6571a7b880a5247cb33b6a74787bf3f9bd5007854a2fad4e1801c6404394bf3d37ab08c135ea38a1974242e39a21273685f000f55796e72957a819e68a22e8602d73c3ba3718a5a4bd92b80b0aa444b182a00788b6e9874fb040ee679a7fae257190099a605229b948334e54a57739535d4004f1658ee3c1a91627e5d72f5a731f0796299df82ab41e72c88eee0c82fa85e003ee802add96628c693ed71afa9908138ba5a6fbf0a5f29a9c74e4e42aba6713f0000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000000000000000000000000000000004200a0000000000000000000000000000000000000000000000000000000000042001000000000000000000000000000000000000000000000000000000000004200b0000000000000000000000000000000000000000000000000000000000042002000000000000000000000000000000000000000000000000000000000004200c0000000000000000000000000000000000000000000000000000000000042003000000000000000000000000000000000000000000000000000000000004200d0000000000000000000000000000000000000000000000000000000000042004000000000000000000000000000000000000000000000000000000000004200e0000000000000000000000000000000000000000000000000000000000042005000000000000000000000000000000000000000000000000000000000004200f00000000000000000000000000000000000000000000000000000000000420060000000000000000000000000000000000000000000000000000000000042010000000000000000000000000000000000000000000000000000000000004200700000000000000000000000000000000000000000000000000000000000420110000000000000000000000000000000000000000000000000000000000042008000000000000000000000000000000000000000000000000000000000004201200000000000000000000000000000000000000000000000000000000000420090000000000000000000000000000000000000000000000000000000000042013000000000000000000000000000000000000000000000000000000000004200a0000000000000000000000000000000000000000000000000000000000042014000000000000000000000000000000000000000000000000000000000004200b0000000000000000000000000000000000000000000000000000000000042015000000000000000000000000000000000000000000000000000000000004200c0000000000000000000000000000000000000000000000000000000000042016000000000000000000000000000000000000000000000000000000000004200d0000000000000000000000000000000000000000000000000000000000042017000000000000000000000000000000000000000000000000000000000004200e0000000000000000000000000000000000000000000000000000000000042018000000000000000000000000000000000000000000000000000000000004200f00000000000000000000000000000000000000000000000000000000000420190000000000000000000000000000000000000000000000000000000000042010000000000000000000000000000000000000000000000000000000000004201a0000000000000000000000000000000000000000000000000000000000042011000000000000000000000000000000000000000000000000000000000004201b0000000000000000000000000000000000000000000000000000000000042012000000000000000000000000000000000000000000000000000000000004201c0000000000000000000000000000000000000000000000000000000000042013000000000000000000000000000000000000000000000000000000000004201d0000000000000000000000000000000000000000000000000000000000042014000000000000000000000000000000000000000000000000000000000004201e0000000000000000000000000000000000000000000000000000000000042015000000000000000000000000000000000000000000000000000000000004201f00000000000000000000000000000000000000000000000000000000000420160000000000000000000000000000000000000000000000000000000000042020000000000000000000000000000000000000000000000000000000000004201700000000000000000000000000000000000000000000000000000000000420210000000000000000000000000000000000000000000000000000000000042018000000000000000000000000000000000000000000000000000000000004202200000000000000000000000000000000000000000000000000000000000420190000000000000000000000000000000000000000000000000000000000042023000000000000000000000000000000000000000000000000000000000004201a0000000000000000000000000000000000000000000000000000000000042024000000000000000000000000000000000000000000000000000000000004201b0000000000000000000000000000000000000000000000000000000000042025000000000000000000000000000000000000000000000000000000000004201c0000000000000000000000000000000000000000000000000000000000042026000000000000000000000000000000000000000000000000000000000004201d0000000000000000000000000000000000000000000000000000000000042027000000000000000000000000000000000000000000000000000000000004201e0000000000000000000000000000000000000000000000000000000000042028000000000000000000000000000000000000000000000000000000000004201f00000000000000000000000000000000000000000000000000000000000420290000000000000000000000000000000000000000000000000000000000042020000000000000000000000000000000000000000000000000000000000004202a0000000000000000000000000000000000000000000000000000000000042021000000000000000000000000000000000000000000000000000000000004202b0000000000000000000000000000000000000000000000000000000000042022000000000000000000000000000000000000000000000000000000000004202c0000000000000000000000000000000000000000000000000000000000042023000000000000000000000000000000000000000000000000000000000004202d0000000000000000000000000000000000000000000000000000000000042024000000000000000000000000000000000000000000000000000000000004202e0000000000000000000000000000000000000000000000000000000000042025000000000000000000000000000000000000000000000000000000000004202f00000000000000000000000000000000000000000000000000000000000420260000000000000000000000000000000000000000000000000000000000042030000000000000000000000000000000000000000000000000000000000004202700000000000000000000000000000000000000000000000000000000000420310000000000000000000000000000000000000000000000000000000000042028000000000000000000000000000000000000000000000000000000000004203200000000000000000000000000000000000000000000000000000000000420290000000000000000000000000000000000000000000000000000000000042033000000000000000000000000000000000000000000000000000000000004202a0000000000000000000000000000000000000000000000000000000000042034000000000000000000000000000000000000000000000000000000000004202b0000000000000000000000000000000000000000000000000000000000042035000000000000000000000000000000000000000000000000000000000004202c0000000000000000000000000000000000000000000000000000000000042036000000000000000000000000000000000000000000000000000000000004202d0000000000000000000000000000000000000000000000000000000000042037000000000000000000000000000000000000000000000000000000000004202e0000000000000000000000000000000000000000000000000000000000042038000000000000000000000000000000000000000000000000000000000004202f00000000000000000000000000000000000000000000000000000000000420390000000000000000000000000000000000000000000000000000000000042030000000000000000000000000000000000000000000000000000000000004203a0000000000000000000000000000000000000000000000000000000000042031000000000000000000000000000000000000000000000000000000000004203b0000000000000000000000000000000000000000000000000000000000042032000000000000000000000000000000000000000000000000000000000004203c0000000000000000000000000000000000000000000000000000000000042033000000000000000000000000000000000000000000000000000000000004203d0000000000000000000000000000000000000000000000000000000000042034000000000000000000000000000000000000000000000000000000000004203e0000000000000000000000000000000000000000000000000000000000042035000000000000000000000000000000000000000000000000000000000004203f00000000000000000000000000000000000000000000000000000000000420360000000000000000000000000000000000000000000000000000000000042040000000000000000000000000000000000000000000000000000000000004203700000000000000000000000000000000000000000000000000000000000420410000000000000000000000000000000000000000000000000000000000042038000000000000000000000000000000000000000000000000000000000004204200000000000000000000000000000000000000000000000000000000000420390000000000000000000000000000000000000000000000000000000000042043000000000000000000000000000000000000000000000000000000000004203a0000000000000000000000000000000000000000000000000000000000042044000000000000000000000000000000000000000000000000000000000004203b0000000000000000000000000000000000000000000000000000000000042045000000000000000000000000000000000000000000000000000000000004203c0000000000000000000000000000000000000000000000000000000000042046000000000000000000000000000000000000000000000000000000000004203d0000000000000000000000000000000000000000000000000000000000042047000000000000000000000000000000000000000000000000000000000004203e0000000000000000000000000000000000000000000000000000000000042048200000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004170100000000000000000000000000000000000000000000000000000000000417020000000000000000000000000000000000000000000000000000000000041703000000000000000000000000000000000000000000000000000000000004170400000000000000000000000000000000000000000000000000000000000417050000000000000000000000000000000000000000000000000000000000041706000000000000000000000000000000000000000000000000000000000004170700000000000000000000000000000000000000000000000000000000000417080000000000000000000000000000000000000000000000000000000000041709000000000000000000000000000000000000000000000000000000000004170a000000000000000000000000000000000000000000000000000000000004170b000000000000000000000000000000000000000000000000000000000004170c000000000000000000000000000000000000000000000000000000000004170d000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f00000000000000000000000000000000000000000000000000000000000417100000000000000000000000000000000000000000000000000000000000041711000000000000000000000000000000000000000000000000000000000004170100000000000000000000000000000000000000000000000000000000000417020000000000000000000000000000000000000000000000000000000000041703000000000000000000000000000000000000000000000000000000000004170400000000000000000000000000000000000000000000000000000000000417050000000000000000000000000000000000000000000000000000000000041706000000000000000000000000000000000000000000000000000000000004170700000000000000000000000000000000000000000000000000000000000417080000000000000000000000000000000000000000000000000000000000041709000000000000000000000000000000000000000000000000000000000004170a000000000000000000000000000000000000000000000000000000000004170b000000000000000000000000000000000000000000000000000000000004170c000000000000000000000000000000000000000000000000000000000004170d000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f00000000000000000000000000000000000000000000000000000000000417100000000000000000000000000000000000000000000000000000000000041711000000000000000000000000000000000000000000000000000000000004171200000000000000000000000000000000000000000000000000000000000417020000000000000000000000000000000000000000000000000000000000041703000000000000000000000000000000000000000000000000000000000004170400000000000000000000000000000000000000000000000000000000000417050000000000000000000000000000000000000000000000000000000000041706000000000000000000000000000000000000000000000000000000000004170700000000000000000000000000000000000000000000000000000000000417080000000000000000000000000000000000000000000000000000000000041709000000000000000000000000000000000000000000000000000000000004170a000000000000000000000000000000000000000000000000000000000004170b000000000000000000000000000000000000000000000000000000000004170c000000000000000000000000000000000000000000000000000000000004170d000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f00000000000000000000000000000000000000000000000000000000000417100000000000000000000000000000000000000000000000000000000000041711000000000000000000000000000000000000000000000000000000000004171200000000000000000000000000000000000000000000000000000000000417130000000000000000000000000000000000000000000000000000000000041703000000000000000000000000000000000000000000000000000000000004170400000000000000000000000000000000000000000000000000000000000417050000000000000000000000000000000000000000000000000000000000041706000000000000000000000000000000000000000000000000000000000004170700000000000000000000000000000000000000000000000000000000000417080000000000000000000000000000000000000000000000000000000000041709000000000000000000000000000000000000000000000000000000000004170a000000000000000000000000000000000000000000000000000000000004170b000000000000000000000000000000000000000000000000000000000004170c000000000000000000000000000000000000000000000000000000000004170d000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f00000000000000000000000000000000000000000000000000000000000417100000000000000000000000000000000000000000000000000000000000041711000000000000000000000000000000000000000000000000000000000004171200000000000000000000000000000000000000000000000000000000000417130000000000000000000000000000000000000000000000000000000000041714000000000000000000000000000000000000000000000000000000000004170400000000000000000000000000000000000000000000000000000000000417050000000000000000000000000000000000000000000000000000000000041706000000000000000000000000000000000000000000000000000000000004170700000000000000000000000000000000000000000000000000000000000417080000000000000000000000000000000000000000000000000000000000041709000000000000000000000000000000000000000000000000000000000004170a000000000000000000000000000000000000000000000000000000000004170b000000000000000000000000000000000000000000000000000000000004170c000000000000000000000000000000000000000000000000000000000004170d000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f00000000000000000000000000000000000000000000000000000000000417100000000000000000000000000000000000000000000000000000000000041711000000000000000000000000000000000000000000000000000000000004171200000000000000000000000000000000000000000000000000000000000417130000000000000000000000000000000000000000000000000000000000041714000000000000000000000000000000000000000000000000000000000004171500000000000000000000000000000000000000000000000000000000000417050000000000000000000000000000000000000000000000000000000000041706000000000000000000000000000000000000000000000000000000000004170700000000000000000000000000000000000000000000000000000000000417080000000000000000000000000000000000000000000000000000000000041709000000000000000000000000000000000000000000000000000000000004170a000000000000000000000000000000000000000000000000000000000004170b000000000000000000000000000000000000000000000000000000000004170c000000000000000000000000000000000000000000000000000000000004170d000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f00000000000000000000000000000000000000000000000000000000000417100000000000000000000000000000000000000000000000000000000000041711000000000000000000000000000000000000000000000000000000000004171200000000000000000000000000000000000000000000000000000000000417130000000000000000000000000000000000000000000000000000000000041714000000000000000000000000000000000000000000000000000000000004171500000000000000000000000000000000000000000000000000000000000417160000000000000000000000000000000000000000000000000000000000041706000000000000000000000000000000000000000000000000000000000004170700000000000000000000000000000000000000000000000000000000000417080000000000000000000000000000000000000000000000000000000000041709000000000000000000000000000000000000000000000000000000000004170a000000000000000000000000000000000000000000000000000000000004170b000000000000000000000000000000000000000000000000000000000004170c000000000000000000000000000000000000000000000000000000000004170d000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f00000000000000000000000000000000000000000000000000000000000417100000000000000000000000000000000000000000000000000000000000041711000000000000000000000000000000000000000000000000000000000004171200000000000000000000000000000000000000000000000000000000000417130000000000000000000000000000000000000000000000000000000000041714000000000000000000000000000000000000000000000000000000000004171500000000000000000000000000000000000000000000000000000000000417160000000000000000000000000000000000000000000000000000000000041717000000000000000000000000000000000000000000000000000000000004170700000000000000000000000000000000000000000000000000000000000417080000000000000000000000000000000000000000000000000000000000041709000000000000000000000000000000000000000000000000000000000004170a000000000000000000000000000000000000000000000000000000000004170b000000000000000000000000000000000000000000000000000000000004170c000000000000000000000000000000000000000000000000000000000004170d000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f00000000000000000000000000000000000000000000000000000000000417100000000000000000000000000000000000000000000000000000000000041711000000000000000000000000000000000000000000000000000000000004171200000000000000000000000000000000000000000000000000000000000417130000000000000000000000000000000000000000000000000000000000041714000000000000000000000000000000000000000000000000000000000004171500000000000000000000000000000000000000000000000000000000000417160000000000000000000000000000000000000000000000000000000000041717000000000000000000000000000000000000000000000000000000000004171800000000000000000000000000000000000000000000000000000000000417080000000000000000000000000000000000000000000000000000000000041709000000000000000000000000000000000000000000000000000000000004170a000000000000000000000000000000000000000000000000000000000004170b000000000000000000000000000000000000000000000000000000000004170c000000000000000000000000000000000000000000000000000000000004170d000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f00000000000000000000000000000000000000000000000000000000000417100000000000000000000000000000000000000000000000000000000000041711000000000000000000000000000000000000000000000000000000000004171200000000000000000000000000000000000000000000000000000000000417130000000000000000000000000000000000000000000000000000000000041714000000000000000000000000000000000000000000000000000000000004171500000000000000000000000000000000000000000000000000000000000417160000000000000000000000000000000000000000000000000000000000041717000000000000000000000000000000000000000000000000000000000004171800000000000000000000000000000000000000000000000000000000000417190000000000000000000000000000000000000000000000000000000000041709000000000000000000000000000000000000000000000000000000000004170a000000000000000000000000000000000000000000000000000000000004170b000000000000000000000000000000000000000000000000000000000004170c000000000000000000000000000000000000000000000000000000000004170d000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f0000000000000000000000000000000000000000000000000000000000041710000000000000000000000000000000000000000000000000000000000004171100000000000000000000000000000000000000000000000000000000000417120000000000000000000000000000000000000000000000000000000000041713000000000000000000000000000000000000000000000000000000000004171400000000000000000000000000000000000000000000000000000000000417150000000000000000000000000000000000000000000000000000000000041716000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004170a000000000000000000000000000000000000000000000000000000000004170b000000000000000000000000000000000000000000000000000000000004170c000000000000000000000000000000000000000000000000000000000004170d000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f0000000000000000000000000000000000000000000000000000000000041710000000000000000000000000000000000000000000000000000000000004171100000000000000000000000000000000000000000000000000000000000417120000000000000000000000000000000000000000000000000000000000041713000000000000000000000000000000000000000000000000000000000004171400000000000000000000000000000000000000000000000000000000000417150000000000000000000000000000000000000000000000000000000000041716000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004170b000000000000000000000000000000000000000000000000000000000004170c000000000000000000000000000000000000000000000000000000000004170d000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f0000000000000000000000000000000000000000000000000000000000041710000000000000000000000000000000000000000000000000000000000004171100000000000000000000000000000000000000000000000000000000000417120000000000000000000000000000000000000000000000000000000000041713000000000000000000000000000000000000000000000000000000000004171400000000000000000000000000000000000000000000000000000000000417150000000000000000000000000000000000000000000000000000000000041716000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004170c000000000000000000000000000000000000000000000000000000000004170d000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f0000000000000000000000000000000000000000000000000000000000041710000000000000000000000000000000000000000000000000000000000004171100000000000000000000000000000000000000000000000000000000000417120000000000000000000000000000000000000000000000000000000000041713000000000000000000000000000000000000000000000000000000000004171400000000000000000000000000000000000000000000000000000000000417150000000000000000000000000000000000000000000000000000000000041716000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004170d000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f0000000000000000000000000000000000000000000000000000000000041710000000000000000000000000000000000000000000000000000000000004171100000000000000000000000000000000000000000000000000000000000417120000000000000000000000000000000000000000000000000000000000041713000000000000000000000000000000000000000000000000000000000004171400000000000000000000000000000000000000000000000000000000000417150000000000000000000000000000000000000000000000000000000000041716000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f0000000000000000000000000000000000000000000000000000000000041710000000000000000000000000000000000000000000000000000000000004171100000000000000000000000000000000000000000000000000000000000417120000000000000000000000000000000000000000000000000000000000041713000000000000000000000000000000000000000000000000000000000004171400000000000000000000000000000000000000000000000000000000000417150000000000000000000000000000000000000000000000000000000000041716000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f000000000000000000000000000000000000000000000000000000000004170f0000000000000000000000000000000000000000000000000000000000041710000000000000000000000000000000000000000000000000000000000004171100000000000000000000000000000000000000000000000000000000000417120000000000000000000000000000000000000000000000000000000000041713000000000000000000000000000000000000000000000000000000000004171400000000000000000000000000000000000000000000000000000000000417150000000000000000000000000000000000000000000000000000000000041716000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f00000000000000000000000000000000000000000000000000000000000417200000000000000000000000000000000000000000000000000000000000041710000000000000000000000000000000000000000000000000000000000004171100000000000000000000000000000000000000000000000000000000000417120000000000000000000000000000000000000000000000000000000000041713000000000000000000000000000000000000000000000000000000000004171400000000000000000000000000000000000000000000000000000000000417150000000000000000000000000000000000000000000000000000000000041716000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f00000000000000000000000000000000000000000000000000000000000417200000000000000000000000000000000000000000000000000000000000041721000000000000000000000000000000000000000000000000000000000004171100000000000000000000000000000000000000000000000000000000000417120000000000000000000000000000000000000000000000000000000000041713000000000000000000000000000000000000000000000000000000000004171400000000000000000000000000000000000000000000000000000000000417150000000000000000000000000000000000000000000000000000000000041716000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f00000000000000000000000000000000000000000000000000000000000417200000000000000000000000000000000000000000000000000000000000041721000000000000000000000000000000000000000000000000000000000004172200000000000000000000000000000000000000000000000000000000000417120000000000000000000000000000000000000000000000000000000000041713000000000000000000000000000000000000000000000000000000000004171400000000000000000000000000000000000000000000000000000000000417150000000000000000000000000000000000000000000000000000000000041716000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f00000000000000000000000000000000000000000000000000000000000417200000000000000000000000000000000000000000000000000000000000041721000000000000000000000000000000000000000000000000000000000004172200000000000000000000000000000000000000000000000000000000000417230000000000000000000000000000000000000000000000000000000000041713000000000000000000000000000000000000000000000000000000000004171400000000000000000000000000000000000000000000000000000000000417150000000000000000000000000000000000000000000000000000000000041716000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f00000000000000000000000000000000000000000000000000000000000417200000000000000000000000000000000000000000000000000000000000041721000000000000000000000000000000000000000000000000000000000004172200000000000000000000000000000000000000000000000000000000000417230000000000000000000000000000000000000000000000000000000000041724000000000000000000000000000000000000000000000000000000000004171400000000000000000000000000000000000000000000000000000000000417150000000000000000000000000000000000000000000000000000000000041716000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f00000000000000000000000000000000000000000000000000000000000417200000000000000000000000000000000000000000000000000000000000041721000000000000000000000000000000000000000000000000000000000004172200000000000000000000000000000000000000000000000000000000000417230000000000000000000000000000000000000000000000000000000000041724000000000000000000000000000000000000000000000000000000000004172500000000000000000000000000000000000000000000000000000000000417150000000000000000000000000000000000000000000000000000000000041716000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f00000000000000000000000000000000000000000000000000000000000417200000000000000000000000000000000000000000000000000000000000041721000000000000000000000000000000000000000000000000000000000004172200000000000000000000000000000000000000000000000000000000000417230000000000000000000000000000000000000000000000000000000000041724000000000000000000000000000000000000000000000000000000000004172500000000000000000000000000000000000000000000000000000000000417260000000000000000000000000000000000000000000000000000000000041716000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f00000000000000000000000000000000000000000000000000000000000417200000000000000000000000000000000000000000000000000000000000041721000000000000000000000000000000000000000000000000000000000004172200000000000000000000000000000000000000000000000000000000000417230000000000000000000000000000000000000000000000000000000000041724000000000000000000000000000000000000000000000000000000000004172500000000000000000000000000000000000000000000000000000000000417260000000000000000000000000000000000000000000000000000000000041727000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f00000000000000000000000000000000000000000000000000000000000417200000000000000000000000000000000000000000000000000000000000041721000000000000000000000000000000000000000000000000000000000004172200000000000000000000000000000000000000000000000000000000000417230000000000000000000000000000000000000000000000000000000000041724000000000000000000000000000000000000000000000000000000000004172500000000000000000000000000000000000000000000000000000000000417260000000000000000000000000000000000000000000000000000000000041727000000000000000000000000000000000000000000000000000000000004172800000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f00000000000000000000000000000000000000000000000000000000000417200000000000000000000000000000000000000000000000000000000000041721000000000000000000000000000000000000000000000000000000000004172200000000000000000000000000000000000000000000000000000000000417230000000000000000000000000000000000000000000000000000000000041724000000000000000000000000000000000000000000000000000000000004172500000000000000000000000000000000000000000000000000000000000417260000000000000000000000000000000000000000000000000000000000041727000000000000000000000000000000000000000000000000000000000004172800000000000000000000000000000000000000000000000000000000000417290000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f0000000000000000000000000000000000000000000000000000000000041720000000000000000000000000000000000000000000000000000000000004172100000000000000000000000000000000000000000000000000000000000417220000000000000000000000000000000000000000000000000000000000041723000000000000000000000000000000000000000000000000000000000004172400000000000000000000000000000000000000000000000000000000000417250000000000000000000000000000000000000000000000000000000000041726000000000000000000000000000000000000000000000000000000000004172700000000000000000000000000000000000000000000000000000000000417280000000000000000000000000000000000000000000000000000000000041729000000000000000000000000000000000000000000000000000000000004172a000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f0000000000000000000000000000000000000000000000000000000000041720000000000000000000000000000000000000000000000000000000000004172100000000000000000000000000000000000000000000000000000000000417220000000000000000000000000000000000000000000000000000000000041723000000000000000000000000000000000000000000000000000000000004172400000000000000000000000000000000000000000000000000000000000417250000000000000000000000000000000000000000000000000000000000041726000000000000000000000000000000000000000000000000000000000004172700000000000000000000000000000000000000000000000000000000000417280000000000000000000000000000000000000000000000000000000000041729000000000000000000000000000000000000000000000000000000000004172a000000000000000000000000000000000000000000000000000000000004172b000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f0000000000000000000000000000000000000000000000000000000000041720000000000000000000000000000000000000000000000000000000000004172100000000000000000000000000000000000000000000000000000000000417220000000000000000000000000000000000000000000000000000000000041723000000000000000000000000000000000000000000000000000000000004172400000000000000000000000000000000000000000000000000000000000417250000000000000000000000000000000000000000000000000000000000041726000000000000000000000000000000000000000000000000000000000004172700000000000000000000000000000000000000000000000000000000000417280000000000000000000000000000000000000000000000000000000000041729000000000000000000000000000000000000000000000000000000000004172a000000000000000000000000000000000000000000000000000000000004172b000000000000000000000000000000000000000000000000000000000004172c000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f0000000000000000000000000000000000000000000000000000000000041720000000000000000000000000000000000000000000000000000000000004172100000000000000000000000000000000000000000000000000000000000417220000000000000000000000000000000000000000000000000000000000041723000000000000000000000000000000000000000000000000000000000004172400000000000000000000000000000000000000000000000000000000000417250000000000000000000000000000000000000000000000000000000000041726000000000000000000000000000000000000000000000000000000000004172700000000000000000000000000000000000000000000000000000000000417280000000000000000000000000000000000000000000000000000000000041729000000000000000000000000000000000000000000000000000000000004172a000000000000000000000000000000000000000000000000000000000004172b000000000000000000000000000000000000000000000000000000000004172c000000000000000000000000000000000000000000000000000000000004172d000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f0000000000000000000000000000000000000000000000000000000000041720000000000000000000000000000000000000000000000000000000000004172100000000000000000000000000000000000000000000000000000000000417220000000000000000000000000000000000000000000000000000000000041723000000000000000000000000000000000000000000000000000000000004172400000000000000000000000000000000000000000000000000000000000417250000000000000000000000000000000000000000000000000000000000041726000000000000000000000000000000000000000000000000000000000004172700000000000000000000000000000000000000000000000000000000000417280000000000000000000000000000000000000000000000000000000000041729000000000000000000000000000000000000000000000000000000000004172a000000000000000000000000000000000000000000000000000000000004172b000000000000000000000000000000000000000000000000000000000004172c000000000000000000000000000000000000000000000000000000000004172d000000000000000000000000000000000000000000000000000000000004172e000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f0000000000000000000000000000000000000000000000000000000000041720000000000000000000000000000000000000000000000000000000000004172100000000000000000000000000000000000000000000000000000000000417220000000000000000000000000000000000000000000000000000000000041723000000000000000000000000000000000000000000000000000000000004172400000000000000000000000000000000000000000000000000000000000417250000000000000000000000000000000000000000000000000000000000041726000000000000000000000000000000000000000000000000000000000004172700000000000000000000000000000000000000000000000000000000000417280000000000000000000000000000000000000000000000000000000000041729000000000000000000000000000000000000000000000000000000000004172a000000000000000000000000000000000000000000000000000000000004172b000000000000000000000000000000000000000000000000000000000004172c000000000000000000000000000000000000000000000000000000000004172d000000000000000000000000000000000000000000000000000000000004172e000000000000000000000000000000000000000000000000000000000004172f000000000000000000000000000000000000000000000000000000000004171f0000000000000000000000000000000000000000000000000000000000041720000000000000000000000000000000000000000000000000000000000004172100000000000000000000000000000000000000000000000000000000000417220000000000000000000000000000000000000000000000000000000000041723000000000000000000000000000000000000000000000000000000000004172400000000000000000000000000000000000000000000000000000000000417250000000000000000000000000000000000000000000000000000000000041726000000000000000000000000000000000000000000000000000000000004172700000000000000000000000000000000000000000000000000000000000417280000000000000000000000000000000000000000000000000000000000041729000000000000000000000000000000000000000000000000000000000004172a000000000000000000000000000000000000000000000000000000000004172b000000000000000000000000000000000000000000000000000000000004172c000000000000000000000000000000000000000000000000000000000004172d000000000000000000000000000000000000000000000000000000000004172e000000000000000000000000000000000000000000000000000000000004172f0000000000000000000000000000000000000000000000000000000000041730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000081000000000000000000000000000000000000000000000000000000000000008100100000000000000000000000000000000000000000000000000000000000810020000000000000000000000000000000000000000000000000000000000081003000000000000000000000000000000000000000000000000000000000008100400000000000000000000000000000000000000000000000000000000000810050000000000000000000000000000000000000000000000000000000000081006000000000000000000000000000000000000000000000000000000000008100700000000000000000000000000000000000000000000000000000000000810080000000000000000000000000000000000000000000000000000000000081009000000000000000000000000000000000000000000000000000000000008100a000000000000000000000000000000000000000000000000000000000008100b000000000000000000000000000000000000000000000000000000000008100c000000000000000000000000000000000000000000000000000000000008100d000000000000000000000000000000000000000000000000000000000008100e000000000000000000000000000000000000000000000000000000000008100f0000000000000000000000000000000000000000000000000000000000081010000000000000000000000000000000000000000000000000000000000008101100000000000000000000000000000000000000000000000000000000000810120000000000000000000000000000000000000000000000000000000000081013000000000000000000000000000000000000000000000000000000000008101400000000000000000000000000000000000000000000000000000000000810150000000000000000000000000000000000000000000000000000000000081016000000000000000000000000000000000000000000000000000000000008101700000000000000000000000000000000000000000000000000000000000810180000000000000000000000000000000000000000000000000000000000081019000000000000000000000000000000000000000000000000000000000008101a000000000000000000000000000000000000000000000000000000000008101b000000000000000000000000000000000000000000000000000000000008101c000000000000000000000000000000000000000000000000000000000008101d000000000000000000000000000000000000000000000000000000000008101e000000000000000000000000000000000000000000000000000000000008101f0000000000000000000000000000000000000000000000000000000000081020000000000000000000000000000000000000000000000000000000000008102100000000000000000000000000000000000000000000000000000000000810220000000000000000000000000000000000000000000000000000000000081023000000000000000000000000000000000000000000000000000000000008102400000000000000000000000000000000000000000000000000000000000810250000000000000000000000000000000000000000000000000000000000081026000000000000000000000000000000000000000000000000000000000008102700000000000000000000000000000000000000000000000000000000000810280000000000000000000000000000000000000000000000000000000000081029000000000000000000000000000000000000000000000000000000000008102a000000000000000000000000000000000000000000000000000000000008102b000000000000000000000000000000000000000000000000000000000008102c000000000000000000000000000000000000000000000000000000000008102d000000000000000000000000000000000000000000000000000000000008102e000000000000000000000000000000000000000000000000000000000008102f0000000000000000000000000000000000000000000000000000000000081030000000000000000000000000000000000000000000000000000000000008103100000000000000000000000000000000000000000000000000000000000810320000000000000000000000000000000000000000000000000000000000081033000000000000000000000000000000000000000000000000000000000008103400000000000000000000000000000000000000000000000000000000000810350000000000000000000000000000000000000000000000000000000000081036000000000000000000000000000000000000000000000000000000000008103700000000000000000000000000000000000000000000000000000000000810380000000000000000000000000000000000000000000000000000000000081039000000000000000000000000000000000000000000000000000000000008103a000000000000000000000000000000000000000000000000000000000008103b000000000000000000000000000000000000000000000000000000000008103c000000000000000000000000000000000000000000000000000000000008103d000000000000000000000000000000000000000000000000000000000008103e000000000000000000000000000000000000000000000000000000000008103f4000000000000000000000000000000000000000000000000000000000000800010000000000000000000000000000000000000000000000000000000000081100000000000000000000000000000000000000000000000000000000000008110100000000000000000000000000000000000000000000000000000000000811020000000000000000000000000000000000000000000000000000000000081103000000000000000000000000000000000000000000000000000000000008110400000000000000000000000000000000000000000000000000000000000811050000000000000000000000000000000000000000000000000000000000081106000000000000000000000000000000000000000000000000000000000008110700000000000000000000000000000000000000000000000000000000000811080000000000000000000000000000000000000000000000000000000000081109000000000000000000000000000000000000000000000000000000000008110a000000000000000000000000000000000000000000000000000000000008110b000000000000000000000000000000000000000000000000000000000008110c000000000000000000000000000000000000000000000000000000000008110d000000000000000000000000000000000000000000000000000000000008110e000000000000000000000000000000000000000000000000000000000008110f0000000000000000000000000000000000000000000000000000000000081110000000000000000000000000000000000000000000000000000000000008111100000000000000000000000000000000000000000000000000000000000811120000000000000000000000000000000000000000000000000000000000081113000000000000000000000000000000000000000000000000000000000008111400000000000000000000000000000000000000000000000000000000000811150000000000000000000000000000000000000000000000000000000000081116000000000000000000000000000000000000000000000000000000000008111700000000000000000000000000000000000000000000000000000000000811180000000000000000000000000000000000000000000000000000000000081119000000000000000000000000000000000000000000000000000000000008111a000000000000000000000000000000000000000000000000000000000008111b000000000000000000000000000000000000000000000000000000000008111c000000000000000000000000000000000000000000000000000000000008111d000000000000000000000000000000000000000000000000000000000008111e000000000000000000000000000000000000000000000000000000000008111f0000000000000000000000000000000000000000000000000000000000081120000000000000000000000000000000000000000000000000000000000008112100000000000000000000000000000000000000000000000000000000000811220000000000000000000000000000000000000000000000000000000000081123000000000000000000000000000000000000000000000000000000000008112400000000000000000000000000000000000000000000000000000000000811250000000000000000000000000000000000000000000000000000000000081126000000000000000000000000000000000000000000000000000000000008112700000000000000000000000000000000000000000000000000000000000811280000000000000000000000000000000000000000000000000000000000081129000000000000000000000000000000000000000000000000000000000008112a000000000000000000000000000000000000000000000000000000000008112b000000000000000000000000000000000000000000000000000000000008112c000000000000000000000000000000000000000000000000000000000008112d000000000000000000000000000000000000000000000000000000000008112e000000000000000000000000000000000000000000000000000000000008112f0000000000000000000000000000000000000000000000000000000000081130000000000000000000000000000000000000000000000000000000000008113100000000000000000000000000000000000000000000000000000000000811320000000000000000000000000000000000000000000000000000000000081133000000000000000000000000000000000000000000000000000000000008113400000000000000000000000000000000000000000000000000000000000811350000000000000000000000000000000000000000000000000000000000081136000000000000000000000000000000000000000000000000000000000008113700000000000000000000000000000000000000000000000000000000000811380000000000000000000000000000000000000000000000000000000000081139000000000000000000000000000000000000000000000000000000000008113a000000000000000000000000000000000000000000000000000000000008113b000000000000000000000000000000000000000000000000000000000008113c000000000000000000000000000000000000000000000000000000000008113d000000000000000000000000000000000000000000000000000000000008113e08003c0472260790b0bdfb8ae4dc4d437e7686b73643f2198970d84e1059a5f13500bfd46275a318e438726ff2765ae154b63ab8a0daebcbed668a5f58a0e63dc1007906b9418dc758c6b4f8454c69baa48b7889b6b511d707abe8e2cb8f7c397300aeb60c4d65a44f122e58bf9565dfe2024b3ae654d5cf2e47ecb035d53c927000bf82e8cda20345f37bbb1de3932172324b57f0b98be483392697b168e3bba8000fb4bbad884ef30edf68e45a6cf2733fcf50310c69d7c1432b29af2c0aa8040023e1622d27fee3b4a40ab975ae0eb2e31619ef3dc76eb858f7fddb6a056131004689cd7007daf98dd3218b839b8e6a29f957154347b391fdb376bd0b344be23f0000000000000000000000000000000000000000000000000000000000082000000000000000000000000000000000000000000000000000000000000008200a0000000000000000000000000000000000000000000000000000000000082001000000000000000000000000000000000000000000000000000000000008200b0000000000000000000000000000000000000000000000000000000000082002000000000000000000000000000000000000000000000000000000000008200c0000000000000000000000000000000000000000000000000000000000082003000000000000000000000000000000000000000000000000000000000008200d0000000000000000000000000000000000000000000000000000000000082004000000000000000000000000000000000000000000000000000000000008200e0000000000000000000000000000000000000000000000000000000000082005000000000000000000000000000000000000000000000000000000000008200f00000000000000000000000000000000000000000000000000000000000820060000000000000000000000000000000000000000000000000000000000082010000000000000000000000000000000000000000000000000000000000008200700000000000000000000000000000000000000000000000000000000000820110000000000000000000000000000000000000000000000000000000000082008000000000000000000000000000000000000000000000000000000000008201200000000000000000000000000000000000000000000000000000000000820090000000000000000000000000000000000000000000000000000000000082013000000000000000000000000000000000000000000000000000000000008200a0000000000000000000000000000000000000000000000000000000000082014000000000000000000000000000000000000000000000000000000000008200b0000000000000000000000000000000000000000000000000000000000082015000000000000000000000000000000000000000000000000000000000008200c0000000000000000000000000000000000000000000000000000000000082016000000000000000000000000000000000000000000000000000000000008200d0000000000000000000000000000000000000000000000000000000000082017000000000000000000000000000000000000000000000000000000000008200e0000000000000000000000000000000000000000000000000000000000082018000000000000000000000000000000000000000000000000000000000008200f00000000000000000000000000000000000000000000000000000000000820190000000000000000000000000000000000000000000000000000000000082010000000000000000000000000000000000000000000000000000000000008201a0000000000000000000000000000000000000000000000000000000000082011000000000000000000000000000000000000000000000000000000000008201b0000000000000000000000000000000000000000000000000000000000082012000000000000000000000000000000000000000000000000000000000008201c0000000000000000000000000000000000000000000000000000000000082013000000000000000000000000000000000000000000000000000000000008201d0000000000000000000000000000000000000000000000000000000000082014000000000000000000000000000000000000000000000000000000000008201e0000000000000000000000000000000000000000000000000000000000082015000000000000000000000000000000000000000000000000000000000008201f00000000000000000000000000000000000000000000000000000000000820160000000000000000000000000000000000000000000000000000000000082020000000000000000000000000000000000000000000000000000000000008201700000000000000000000000000000000000000000000000000000000000820210000000000000000000000000000000000000000000000000000000000082018000000000000000000000000000000000000000000000000000000000008202200000000000000000000000000000000000000000000000000000000000820190000000000000000000000000000000000000000000000000000000000082023000000000000000000000000000000000000000000000000000000000008201a0000000000000000000000000000000000000000000000000000000000082024000000000000000000000000000000000000000000000000000000000008201b0000000000000000000000000000000000000000000000000000000000082025000000000000000000000000000000000000000000000000000000000008201c0000000000000000000000000000000000000000000000000000000000082026000000000000000000000000000000000000000000000000000000000008201d0000000000000000000000000000000000000000000000000000000000082027000000000000000000000000000000000000000000000000000000000008201e0000000000000000000000000000000000000000000000000000000000082028000000000000000000000000000000000000000000000000000000000008201f00000000000000000000000000000000000000000000000000000000000820290000000000000000000000000000000000000000000000000000000000082020000000000000000000000000000000000000000000000000000000000008202a0000000000000000000000000000000000000000000000000000000000082021000000000000000000000000000000000000000000000000000000000008202b0000000000000000000000000000000000000000000000000000000000082022000000000000000000000000000000000000000000000000000000000008202c0000000000000000000000000000000000000000000000000000000000082023000000000000000000000000000000000000000000000000000000000008202d0000000000000000000000000000000000000000000000000000000000082024000000000000000000000000000000000000000000000000000000000008202e0000000000000000000000000000000000000000000000000000000000082025000000000000000000000000000000000000000000000000000000000008202f00000000000000000000000000000000000000000000000000000000000820260000000000000000000000000000000000000000000000000000000000082030000000000000000000000000000000000000000000000000000000000008202700000000000000000000000000000000000000000000000000000000000820310000000000000000000000000000000000000000000000000000000000082028000000000000000000000000000000000000000000000000000000000008203200000000000000000000000000000000000000000000000000000000000820290000000000000000000000000000000000000000000000000000000000082033000000000000000000000000000000000000000000000000000000000008202a0000000000000000000000000000000000000000000000000000000000082034000000000000000000000000000000000000000000000000000000000008202b0000000000000000000000000000000000000000000000000000000000082035000000000000000000000000000000000000000000000000000000000008202c0000000000000000000000000000000000000000000000000000000000082036000000000000000000000000000000000000000000000000000000000008202d0000000000000000000000000000000000000000000000000000000000082037000000000000000000000000000000000000000000000000000000000008202e0000000000000000000000000000000000000000000000000000000000082038000000000000000000000000000000000000000000000000000000000008202f00000000000000000000000000000000000000000000000000000000000820390000000000000000000000000000000000000000000000000000000000082030000000000000000000000000000000000000000000000000000000000008203a0000000000000000000000000000000000000000000000000000000000082031000000000000000000000000000000000000000000000000000000000008203b0000000000000000000000000000000000000000000000000000000000082032000000000000000000000000000000000000000000000000000000000008203c0000000000000000000000000000000000000000000000000000000000082033000000000000000000000000000000000000000000000000000000000008203d0000000000000000000000000000000000000000000000000000000000082034000000000000000000000000000000000000000000000000000000000008203e0000000000000000000000000000000000000000000000000000000000082035000000000000000000000000000000000000000000000000000000000008203f00000000000000000000000000000000000000000000000000000000000820360000000000000000000000000000000000000000000000000000000000082040000000000000000000000000000000000000000000000000000000000008203700000000000000000000000000000000000000000000000000000000000820410000000000000000000000000000000000000000000000000000000000082038000000000000000000000000000000000000000000000000000000000008204200000000000000000000000000000000000000000000000000000000000820390000000000000000000000000000000000000000000000000000000000082043000000000000000000000000000000000000000000000000000000000008203a0000000000000000000000000000000000000000000000000000000000082044000000000000000000000000000000000000000000000000000000000008203b0000000000000000000000000000000000000000000000000000000000082045000000000000000000000000000000000000000000000000000000000008203c0000000000000000000000000000000000000000000000000000000000082046000000000000000000000000000000000000000000000000000000000008203d0000000000000000000000000000000000000000000000000000000000082047000000000000000000000000000000000000000000000000000000000008203e0000000000000000000000000000000000000000000000000000000000082048200000000000000000000000000000000000000000000000000000000000081700000000000000000000000000000000000000000000000000000000000008170100000000000000000000000000000000000000000000000000000000000817020000000000000000000000000000000000000000000000000000000000081703000000000000000000000000000000000000000000000000000000000008170400000000000000000000000000000000000000000000000000000000000817050000000000000000000000000000000000000000000000000000000000081706000000000000000000000000000000000000000000000000000000000008170700000000000000000000000000000000000000000000000000000000000817080000000000000000000000000000000000000000000000000000000000081709000000000000000000000000000000000000000000000000000000000008170a000000000000000000000000000000000000000000000000000000000008170b000000000000000000000000000000000000000000000000000000000008170c000000000000000000000000000000000000000000000000000000000008170d000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f00000000000000000000000000000000000000000000000000000000000817100000000000000000000000000000000000000000000000000000000000081711000000000000000000000000000000000000000000000000000000000008170100000000000000000000000000000000000000000000000000000000000817020000000000000000000000000000000000000000000000000000000000081703000000000000000000000000000000000000000000000000000000000008170400000000000000000000000000000000000000000000000000000000000817050000000000000000000000000000000000000000000000000000000000081706000000000000000000000000000000000000000000000000000000000008170700000000000000000000000000000000000000000000000000000000000817080000000000000000000000000000000000000000000000000000000000081709000000000000000000000000000000000000000000000000000000000008170a000000000000000000000000000000000000000000000000000000000008170b000000000000000000000000000000000000000000000000000000000008170c000000000000000000000000000000000000000000000000000000000008170d000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f00000000000000000000000000000000000000000000000000000000000817100000000000000000000000000000000000000000000000000000000000081711000000000000000000000000000000000000000000000000000000000008171200000000000000000000000000000000000000000000000000000000000817020000000000000000000000000000000000000000000000000000000000081703000000000000000000000000000000000000000000000000000000000008170400000000000000000000000000000000000000000000000000000000000817050000000000000000000000000000000000000000000000000000000000081706000000000000000000000000000000000000000000000000000000000008170700000000000000000000000000000000000000000000000000000000000817080000000000000000000000000000000000000000000000000000000000081709000000000000000000000000000000000000000000000000000000000008170a000000000000000000000000000000000000000000000000000000000008170b000000000000000000000000000000000000000000000000000000000008170c000000000000000000000000000000000000000000000000000000000008170d000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f00000000000000000000000000000000000000000000000000000000000817100000000000000000000000000000000000000000000000000000000000081711000000000000000000000000000000000000000000000000000000000008171200000000000000000000000000000000000000000000000000000000000817130000000000000000000000000000000000000000000000000000000000081703000000000000000000000000000000000000000000000000000000000008170400000000000000000000000000000000000000000000000000000000000817050000000000000000000000000000000000000000000000000000000000081706000000000000000000000000000000000000000000000000000000000008170700000000000000000000000000000000000000000000000000000000000817080000000000000000000000000000000000000000000000000000000000081709000000000000000000000000000000000000000000000000000000000008170a000000000000000000000000000000000000000000000000000000000008170b000000000000000000000000000000000000000000000000000000000008170c000000000000000000000000000000000000000000000000000000000008170d000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f00000000000000000000000000000000000000000000000000000000000817100000000000000000000000000000000000000000000000000000000000081711000000000000000000000000000000000000000000000000000000000008171200000000000000000000000000000000000000000000000000000000000817130000000000000000000000000000000000000000000000000000000000081714000000000000000000000000000000000000000000000000000000000008170400000000000000000000000000000000000000000000000000000000000817050000000000000000000000000000000000000000000000000000000000081706000000000000000000000000000000000000000000000000000000000008170700000000000000000000000000000000000000000000000000000000000817080000000000000000000000000000000000000000000000000000000000081709000000000000000000000000000000000000000000000000000000000008170a000000000000000000000000000000000000000000000000000000000008170b000000000000000000000000000000000000000000000000000000000008170c000000000000000000000000000000000000000000000000000000000008170d000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f00000000000000000000000000000000000000000000000000000000000817100000000000000000000000000000000000000000000000000000000000081711000000000000000000000000000000000000000000000000000000000008171200000000000000000000000000000000000000000000000000000000000817130000000000000000000000000000000000000000000000000000000000081714000000000000000000000000000000000000000000000000000000000008171500000000000000000000000000000000000000000000000000000000000817050000000000000000000000000000000000000000000000000000000000081706000000000000000000000000000000000000000000000000000000000008170700000000000000000000000000000000000000000000000000000000000817080000000000000000000000000000000000000000000000000000000000081709000000000000000000000000000000000000000000000000000000000008170a000000000000000000000000000000000000000000000000000000000008170b000000000000000000000000000000000000000000000000000000000008170c000000000000000000000000000000000000000000000000000000000008170d000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f00000000000000000000000000000000000000000000000000000000000817100000000000000000000000000000000000000000000000000000000000081711000000000000000000000000000000000000000000000000000000000008171200000000000000000000000000000000000000000000000000000000000817130000000000000000000000000000000000000000000000000000000000081714000000000000000000000000000000000000000000000000000000000008171500000000000000000000000000000000000000000000000000000000000817160000000000000000000000000000000000000000000000000000000000081706000000000000000000000000000000000000000000000000000000000008170700000000000000000000000000000000000000000000000000000000000817080000000000000000000000000000000000000000000000000000000000081709000000000000000000000000000000000000000000000000000000000008170a000000000000000000000000000000000000000000000000000000000008170b000000000000000000000000000000000000000000000000000000000008170c000000000000000000000000000000000000000000000000000000000008170d000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f00000000000000000000000000000000000000000000000000000000000817100000000000000000000000000000000000000000000000000000000000081711000000000000000000000000000000000000000000000000000000000008171200000000000000000000000000000000000000000000000000000000000817130000000000000000000000000000000000000000000000000000000000081714000000000000000000000000000000000000000000000000000000000008171500000000000000000000000000000000000000000000000000000000000817160000000000000000000000000000000000000000000000000000000000081717000000000000000000000000000000000000000000000000000000000008170700000000000000000000000000000000000000000000000000000000000817080000000000000000000000000000000000000000000000000000000000081709000000000000000000000000000000000000000000000000000000000008170a000000000000000000000000000000000000000000000000000000000008170b000000000000000000000000000000000000000000000000000000000008170c000000000000000000000000000000000000000000000000000000000008170d000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f00000000000000000000000000000000000000000000000000000000000817100000000000000000000000000000000000000000000000000000000000081711000000000000000000000000000000000000000000000000000000000008171200000000000000000000000000000000000000000000000000000000000817130000000000000000000000000000000000000000000000000000000000081714000000000000000000000000000000000000000000000000000000000008171500000000000000000000000000000000000000000000000000000000000817160000000000000000000000000000000000000000000000000000000000081717000000000000000000000000000000000000000000000000000000000008171800000000000000000000000000000000000000000000000000000000000817080000000000000000000000000000000000000000000000000000000000081709000000000000000000000000000000000000000000000000000000000008170a000000000000000000000000000000000000000000000000000000000008170b000000000000000000000000000000000000000000000000000000000008170c000000000000000000000000000000000000000000000000000000000008170d000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f00000000000000000000000000000000000000000000000000000000000817100000000000000000000000000000000000000000000000000000000000081711000000000000000000000000000000000000000000000000000000000008171200000000000000000000000000000000000000000000000000000000000817130000000000000000000000000000000000000000000000000000000000081714000000000000000000000000000000000000000000000000000000000008171500000000000000000000000000000000000000000000000000000000000817160000000000000000000000000000000000000000000000000000000000081717000000000000000000000000000000000000000000000000000000000008171800000000000000000000000000000000000000000000000000000000000817190000000000000000000000000000000000000000000000000000000000081709000000000000000000000000000000000000000000000000000000000008170a000000000000000000000000000000000000000000000000000000000008170b000000000000000000000000000000000000000000000000000000000008170c000000000000000000000000000000000000000000000000000000000008170d000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f0000000000000000000000000000000000000000000000000000000000081710000000000000000000000000000000000000000000000000000000000008171100000000000000000000000000000000000000000000000000000000000817120000000000000000000000000000000000000000000000000000000000081713000000000000000000000000000000000000000000000000000000000008171400000000000000000000000000000000000000000000000000000000000817150000000000000000000000000000000000000000000000000000000000081716000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008170a000000000000000000000000000000000000000000000000000000000008170b000000000000000000000000000000000000000000000000000000000008170c000000000000000000000000000000000000000000000000000000000008170d000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f0000000000000000000000000000000000000000000000000000000000081710000000000000000000000000000000000000000000000000000000000008171100000000000000000000000000000000000000000000000000000000000817120000000000000000000000000000000000000000000000000000000000081713000000000000000000000000000000000000000000000000000000000008171400000000000000000000000000000000000000000000000000000000000817150000000000000000000000000000000000000000000000000000000000081716000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008170b000000000000000000000000000000000000000000000000000000000008170c000000000000000000000000000000000000000000000000000000000008170d000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f0000000000000000000000000000000000000000000000000000000000081710000000000000000000000000000000000000000000000000000000000008171100000000000000000000000000000000000000000000000000000000000817120000000000000000000000000000000000000000000000000000000000081713000000000000000000000000000000000000000000000000000000000008171400000000000000000000000000000000000000000000000000000000000817150000000000000000000000000000000000000000000000000000000000081716000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008170c000000000000000000000000000000000000000000000000000000000008170d000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f0000000000000000000000000000000000000000000000000000000000081710000000000000000000000000000000000000000000000000000000000008171100000000000000000000000000000000000000000000000000000000000817120000000000000000000000000000000000000000000000000000000000081713000000000000000000000000000000000000000000000000000000000008171400000000000000000000000000000000000000000000000000000000000817150000000000000000000000000000000000000000000000000000000000081716000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008170d000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f0000000000000000000000000000000000000000000000000000000000081710000000000000000000000000000000000000000000000000000000000008171100000000000000000000000000000000000000000000000000000000000817120000000000000000000000000000000000000000000000000000000000081713000000000000000000000000000000000000000000000000000000000008171400000000000000000000000000000000000000000000000000000000000817150000000000000000000000000000000000000000000000000000000000081716000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f0000000000000000000000000000000000000000000000000000000000081710000000000000000000000000000000000000000000000000000000000008171100000000000000000000000000000000000000000000000000000000000817120000000000000000000000000000000000000000000000000000000000081713000000000000000000000000000000000000000000000000000000000008171400000000000000000000000000000000000000000000000000000000000817150000000000000000000000000000000000000000000000000000000000081716000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f000000000000000000000000000000000000000000000000000000000008170f0000000000000000000000000000000000000000000000000000000000081710000000000000000000000000000000000000000000000000000000000008171100000000000000000000000000000000000000000000000000000000000817120000000000000000000000000000000000000000000000000000000000081713000000000000000000000000000000000000000000000000000000000008171400000000000000000000000000000000000000000000000000000000000817150000000000000000000000000000000000000000000000000000000000081716000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f00000000000000000000000000000000000000000000000000000000000817200000000000000000000000000000000000000000000000000000000000081710000000000000000000000000000000000000000000000000000000000008171100000000000000000000000000000000000000000000000000000000000817120000000000000000000000000000000000000000000000000000000000081713000000000000000000000000000000000000000000000000000000000008171400000000000000000000000000000000000000000000000000000000000817150000000000000000000000000000000000000000000000000000000000081716000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f00000000000000000000000000000000000000000000000000000000000817200000000000000000000000000000000000000000000000000000000000081721000000000000000000000000000000000000000000000000000000000008171100000000000000000000000000000000000000000000000000000000000817120000000000000000000000000000000000000000000000000000000000081713000000000000000000000000000000000000000000000000000000000008171400000000000000000000000000000000000000000000000000000000000817150000000000000000000000000000000000000000000000000000000000081716000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f00000000000000000000000000000000000000000000000000000000000817200000000000000000000000000000000000000000000000000000000000081721000000000000000000000000000000000000000000000000000000000008172200000000000000000000000000000000000000000000000000000000000817120000000000000000000000000000000000000000000000000000000000081713000000000000000000000000000000000000000000000000000000000008171400000000000000000000000000000000000000000000000000000000000817150000000000000000000000000000000000000000000000000000000000081716000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f00000000000000000000000000000000000000000000000000000000000817200000000000000000000000000000000000000000000000000000000000081721000000000000000000000000000000000000000000000000000000000008172200000000000000000000000000000000000000000000000000000000000817230000000000000000000000000000000000000000000000000000000000081713000000000000000000000000000000000000000000000000000000000008171400000000000000000000000000000000000000000000000000000000000817150000000000000000000000000000000000000000000000000000000000081716000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f00000000000000000000000000000000000000000000000000000000000817200000000000000000000000000000000000000000000000000000000000081721000000000000000000000000000000000000000000000000000000000008172200000000000000000000000000000000000000000000000000000000000817230000000000000000000000000000000000000000000000000000000000081724000000000000000000000000000000000000000000000000000000000008171400000000000000000000000000000000000000000000000000000000000817150000000000000000000000000000000000000000000000000000000000081716000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f00000000000000000000000000000000000000000000000000000000000817200000000000000000000000000000000000000000000000000000000000081721000000000000000000000000000000000000000000000000000000000008172200000000000000000000000000000000000000000000000000000000000817230000000000000000000000000000000000000000000000000000000000081724000000000000000000000000000000000000000000000000000000000008172500000000000000000000000000000000000000000000000000000000000817150000000000000000000000000000000000000000000000000000000000081716000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f00000000000000000000000000000000000000000000000000000000000817200000000000000000000000000000000000000000000000000000000000081721000000000000000000000000000000000000000000000000000000000008172200000000000000000000000000000000000000000000000000000000000817230000000000000000000000000000000000000000000000000000000000081724000000000000000000000000000000000000000000000000000000000008172500000000000000000000000000000000000000000000000000000000000817260000000000000000000000000000000000000000000000000000000000081716000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f00000000000000000000000000000000000000000000000000000000000817200000000000000000000000000000000000000000000000000000000000081721000000000000000000000000000000000000000000000000000000000008172200000000000000000000000000000000000000000000000000000000000817230000000000000000000000000000000000000000000000000000000000081724000000000000000000000000000000000000000000000000000000000008172500000000000000000000000000000000000000000000000000000000000817260000000000000000000000000000000000000000000000000000000000081727000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f00000000000000000000000000000000000000000000000000000000000817200000000000000000000000000000000000000000000000000000000000081721000000000000000000000000000000000000000000000000000000000008172200000000000000000000000000000000000000000000000000000000000817230000000000000000000000000000000000000000000000000000000000081724000000000000000000000000000000000000000000000000000000000008172500000000000000000000000000000000000000000000000000000000000817260000000000000000000000000000000000000000000000000000000000081727000000000000000000000000000000000000000000000000000000000008172800000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f00000000000000000000000000000000000000000000000000000000000817200000000000000000000000000000000000000000000000000000000000081721000000000000000000000000000000000000000000000000000000000008172200000000000000000000000000000000000000000000000000000000000817230000000000000000000000000000000000000000000000000000000000081724000000000000000000000000000000000000000000000000000000000008172500000000000000000000000000000000000000000000000000000000000817260000000000000000000000000000000000000000000000000000000000081727000000000000000000000000000000000000000000000000000000000008172800000000000000000000000000000000000000000000000000000000000817290000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f0000000000000000000000000000000000000000000000000000000000081720000000000000000000000000000000000000000000000000000000000008172100000000000000000000000000000000000000000000000000000000000817220000000000000000000000000000000000000000000000000000000000081723000000000000000000000000000000000000000000000000000000000008172400000000000000000000000000000000000000000000000000000000000817250000000000000000000000000000000000000000000000000000000000081726000000000000000000000000000000000000000000000000000000000008172700000000000000000000000000000000000000000000000000000000000817280000000000000000000000000000000000000000000000000000000000081729000000000000000000000000000000000000000000000000000000000008172a000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f0000000000000000000000000000000000000000000000000000000000081720000000000000000000000000000000000000000000000000000000000008172100000000000000000000000000000000000000000000000000000000000817220000000000000000000000000000000000000000000000000000000000081723000000000000000000000000000000000000000000000000000000000008172400000000000000000000000000000000000000000000000000000000000817250000000000000000000000000000000000000000000000000000000000081726000000000000000000000000000000000000000000000000000000000008172700000000000000000000000000000000000000000000000000000000000817280000000000000000000000000000000000000000000000000000000000081729000000000000000000000000000000000000000000000000000000000008172a000000000000000000000000000000000000000000000000000000000008172b000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f0000000000000000000000000000000000000000000000000000000000081720000000000000000000000000000000000000000000000000000000000008172100000000000000000000000000000000000000000000000000000000000817220000000000000000000000000000000000000000000000000000000000081723000000000000000000000000000000000000000000000000000000000008172400000000000000000000000000000000000000000000000000000000000817250000000000000000000000000000000000000000000000000000000000081726000000000000000000000000000000000000000000000000000000000008172700000000000000000000000000000000000000000000000000000000000817280000000000000000000000000000000000000000000000000000000000081729000000000000000000000000000000000000000000000000000000000008172a000000000000000000000000000000000000000000000000000000000008172b000000000000000000000000000000000000000000000000000000000008172c000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f0000000000000000000000000000000000000000000000000000000000081720000000000000000000000000000000000000000000000000000000000008172100000000000000000000000000000000000000000000000000000000000817220000000000000000000000000000000000000000000000000000000000081723000000000000000000000000000000000000000000000000000000000008172400000000000000000000000000000000000000000000000000000000000817250000000000000000000000000000000000000000000000000000000000081726000000000000000000000000000000000000000000000000000000000008172700000000000000000000000000000000000000000000000000000000000817280000000000000000000000000000000000000000000000000000000000081729000000000000000000000000000000000000000000000000000000000008172a000000000000000000000000000000000000000000000000000000000008172b000000000000000000000000000000000000000000000000000000000008172c000000000000000000000000000000000000000000000000000000000008172d000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f0000000000000000000000000000000000000000000000000000000000081720000000000000000000000000000000000000000000000000000000000008172100000000000000000000000000000000000000000000000000000000000817220000000000000000000000000000000000000000000000000000000000081723000000000000000000000000000000000000000000000000000000000008172400000000000000000000000000000000000000000000000000000000000817250000000000000000000000000000000000000000000000000000000000081726000000000000000000000000000000000000000000000000000000000008172700000000000000000000000000000000000000000000000000000000000817280000000000000000000000000000000000000000000000000000000000081729000000000000000000000000000000000000000000000000000000000008172a000000000000000000000000000000000000000000000000000000000008172b000000000000000000000000000000000000000000000000000000000008172c000000000000000000000000000000000000000000000000000000000008172d000000000000000000000000000000000000000000000000000000000008172e000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f0000000000000000000000000000000000000000000000000000000000081720000000000000000000000000000000000000000000000000000000000008172100000000000000000000000000000000000000000000000000000000000817220000000000000000000000000000000000000000000000000000000000081723000000000000000000000000000000000000000000000000000000000008172400000000000000000000000000000000000000000000000000000000000817250000000000000000000000000000000000000000000000000000000000081726000000000000000000000000000000000000000000000000000000000008172700000000000000000000000000000000000000000000000000000000000817280000000000000000000000000000000000000000000000000000000000081729000000000000000000000000000000000000000000000000000000000008172a000000000000000000000000000000000000000000000000000000000008172b000000000000000000000000000000000000000000000000000000000008172c000000000000000000000000000000000000000000000000000000000008172d000000000000000000000000000000000000000000000000000000000008172e000000000000000000000000000000000000000000000000000000000008172f000000000000000000000000000000000000000000000000000000000008171f0000000000000000000000000000000000000000000000000000000000081720000000000000000000000000000000000000000000000000000000000008172100000000000000000000000000000000000000000000000000000000000817220000000000000000000000000000000000000000000000000000000000081723000000000000000000000000000000000000000000000000000000000008172400000000000000000000000000000000000000000000000000000000000817250000000000000000000000000000000000000000000000000000000000081726000000000000000000000000000000000000000000000000000000000008172700000000000000000000000000000000000000000000000000000000000817280000000000000000000000000000000000000000000000000000000000081729000000000000000000000000000000000000000000000000000000000008172a000000000000000000000000000000000000000000000000000000000008172b000000000000000000000000000000000000000000000000000000000008172c000000000000000000000000000000000000000000000000000000000008172d000000000000000000000000000000000000000000000000000000000008172e000000000000000000000000000000000000000000000000000000000008172f00000000000000000000000000000000000000000000000000000000000817300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000c100000000000000000000000000000000000000000000000000000000000000c100100000000000000000000000000000000000000000000000000000000000c100200000000000000000000000000000000000000000000000000000000000c100300000000000000000000000000000000000000000000000000000000000c100400000000000000000000000000000000000000000000000000000000000c100500000000000000000000000000000000000000000000000000000000000c100600000000000000000000000000000000000000000000000000000000000c100700000000000000000000000000000000000000000000000000000000000c100800000000000000000000000000000000000000000000000000000000000c100900000000000000000000000000000000000000000000000000000000000c100a00000000000000000000000000000000000000000000000000000000000c100b00000000000000000000000000000000000000000000000000000000000c100c00000000000000000000000000000000000000000000000000000000000c100d00000000000000000000000000000000000000000000000000000000000c100e00000000000000000000000000000000000000000000000000000000000c100f00000000000000000000000000000000000000000000000000000000000c101000000000000000000000000000000000000000000000000000000000000c101100000000000000000000000000000000000000000000000000000000000c101200000000000000000000000000000000000000000000000000000000000c101300000000000000000000000000000000000000000000000000000000000c101400000000000000000000000000000000000000000000000000000000000c101500000000000000000000000000000000000000000000000000000000000c101600000000000000000000000000000000000000000000000000000000000c101700000000000000000000000000000000000000000000000000000000000c101800000000000000000000000000000000000000000000000000000000000c101900000000000000000000000000000000000000000000000000000000000c101a00000000000000000000000000000000000000000000000000000000000c101b00000000000000000000000000000000000000000000000000000000000c101c00000000000000000000000000000000000000000000000000000000000c101d00000000000000000000000000000000000000000000000000000000000c101e00000000000000000000000000000000000000000000000000000000000c101f00000000000000000000000000000000000000000000000000000000000c102000000000000000000000000000000000000000000000000000000000000c102100000000000000000000000000000000000000000000000000000000000c102200000000000000000000000000000000000000000000000000000000000c102300000000000000000000000000000000000000000000000000000000000c102400000000000000000000000000000000000000000000000000000000000c102500000000000000000000000000000000000000000000000000000000000c102600000000000000000000000000000000000000000000000000000000000c102700000000000000000000000000000000000000000000000000000000000c102800000000000000000000000000000000000000000000000000000000000c102900000000000000000000000000000000000000000000000000000000000c102a00000000000000000000000000000000000000000000000000000000000c102b00000000000000000000000000000000000000000000000000000000000c102c00000000000000000000000000000000000000000000000000000000000c102d00000000000000000000000000000000000000000000000000000000000c102e00000000000000000000000000000000000000000000000000000000000c102f00000000000000000000000000000000000000000000000000000000000c103000000000000000000000000000000000000000000000000000000000000c103100000000000000000000000000000000000000000000000000000000000c103200000000000000000000000000000000000000000000000000000000000c103300000000000000000000000000000000000000000000000000000000000c103400000000000000000000000000000000000000000000000000000000000c103500000000000000000000000000000000000000000000000000000000000c103600000000000000000000000000000000000000000000000000000000000c103700000000000000000000000000000000000000000000000000000000000c103800000000000000000000000000000000000000000000000000000000000c103900000000000000000000000000000000000000000000000000000000000c103a00000000000000000000000000000000000000000000000000000000000c103b00000000000000000000000000000000000000000000000000000000000c103c00000000000000000000000000000000000000000000000000000000000c103d00000000000000000000000000000000000000000000000000000000000c103e00000000000000000000000000000000000000000000000000000000000c103f4000000000000000000000000000000000000000000000000000000000000c000100000000000000000000000000000000000000000000000000000000000c110000000000000000000000000000000000000000000000000000000000000c110100000000000000000000000000000000000000000000000000000000000c110200000000000000000000000000000000000000000000000000000000000c110300000000000000000000000000000000000000000000000000000000000c110400000000000000000000000000000000000000000000000000000000000c110500000000000000000000000000000000000000000000000000000000000c110600000000000000000000000000000000000000000000000000000000000c110700000000000000000000000000000000000000000000000000000000000c110800000000000000000000000000000000000000000000000000000000000c110900000000000000000000000000000000000000000000000000000000000c110a00000000000000000000000000000000000000000000000000000000000c110b00000000000000000000000000000000000000000000000000000000000c110c00000000000000000000000000000000000000000000000000000000000c110d00000000000000000000000000000000000000000000000000000000000c110e00000000000000000000000000000000000000000000000000000000000c110f00000000000000000000000000000000000000000000000000000000000c111000000000000000000000000000000000000000000000000000000000000c111100000000000000000000000000000000000000000000000000000000000c111200000000000000000000000000000000000000000000000000000000000c111300000000000000000000000000000000000000000000000000000000000c111400000000000000000000000000000000000000000000000000000000000c111500000000000000000000000000000000000000000000000000000000000c111600000000000000000000000000000000000000000000000000000000000c111700000000000000000000000000000000000000000000000000000000000c111800000000000000000000000000000000000000000000000000000000000c111900000000000000000000000000000000000000000000000000000000000c111a00000000000000000000000000000000000000000000000000000000000c111b00000000000000000000000000000000000000000000000000000000000c111c00000000000000000000000000000000000000000000000000000000000c111d00000000000000000000000000000000000000000000000000000000000c111e00000000000000000000000000000000000000000000000000000000000c111f00000000000000000000000000000000000000000000000000000000000c112000000000000000000000000000000000000000000000000000000000000c112100000000000000000000000000000000000000000000000000000000000c112200000000000000000000000000000000000000000000000000000000000c112300000000000000000000000000000000000000000000000000000000000c112400000000000000000000000000000000000000000000000000000000000c112500000000000000000000000000000000000000000000000000000000000c112600000000000000000000000000000000000000000000000000000000000c112700000000000000000000000000000000000000000000000000000000000c112800000000000000000000000000000000000000000000000000000000000c112900000000000000000000000000000000000000000000000000000000000c112a00000000000000000000000000000000000000000000000000000000000c112b00000000000000000000000000000000000000000000000000000000000c112c00000000000000000000000000000000000000000000000000000000000c112d00000000000000000000000000000000000000000000000000000000000c112e00000000000000000000000000000000000000000000000000000000000c112f00000000000000000000000000000000000000000000000000000000000c113000000000000000000000000000000000000000000000000000000000000c113100000000000000000000000000000000000000000000000000000000000c113200000000000000000000000000000000000000000000000000000000000c113300000000000000000000000000000000000000000000000000000000000c113400000000000000000000000000000000000000000000000000000000000c113500000000000000000000000000000000000000000000000000000000000c113600000000000000000000000000000000000000000000000000000000000c113700000000000000000000000000000000000000000000000000000000000c113800000000000000000000000000000000000000000000000000000000000c113900000000000000000000000000000000000000000000000000000000000c113a00000000000000000000000000000000000000000000000000000000000c113b00000000000000000000000000000000000000000000000000000000000c113c00000000000000000000000000000000000000000000000000000000000c113d00000000000000000000000000000000000000000000000000000000000c113e0800f8029be42ec3f25204907ca981fb71e5b357093eb5db10fc01ca98a4e4154c0030e13d351a5bf1d5a040e82a163ca57017f39162693f85c571e441e36d702d00a550ae0f39f977d9473d6de1be3232fc68ed0c4a601d53542148695102cfc9005580bc65e4bff9c8fffa64db02c0fa6af14d9d26fd962f4c5904cbd3ddec2500758c4a0d43dfec788b2f580877c4f473adec8f168ea24424f2600e4eb4916f00342602bf90d10f8ca8e582a894dcc4c02bb89fe458532e0c632b53bae54b4d00ca43ab78ab834337e9964d84a0674c9adabdca140539c5a6bc96e0ba9a51f6004ffbfd91be292a7c6a0e255e50caa156ac2d628b40ad2128c4ab63a92d8a1c3f00000000000000000000000000000000000000000000000000000000000c200000000000000000000000000000000000000000000000000000000000000c200a00000000000000000000000000000000000000000000000000000000000c200100000000000000000000000000000000000000000000000000000000000c200b00000000000000000000000000000000000000000000000000000000000c200200000000000000000000000000000000000000000000000000000000000c200c00000000000000000000000000000000000000000000000000000000000c200300000000000000000000000000000000000000000000000000000000000c200d00000000000000000000000000000000000000000000000000000000000c200400000000000000000000000000000000000000000000000000000000000c200e00000000000000000000000000000000000000000000000000000000000c200500000000000000000000000000000000000000000000000000000000000c200f00000000000000000000000000000000000000000000000000000000000c200600000000000000000000000000000000000000000000000000000000000c201000000000000000000000000000000000000000000000000000000000000c200700000000000000000000000000000000000000000000000000000000000c201100000000000000000000000000000000000000000000000000000000000c200800000000000000000000000000000000000000000000000000000000000c201200000000000000000000000000000000000000000000000000000000000c200900000000000000000000000000000000000000000000000000000000000c201300000000000000000000000000000000000000000000000000000000000c200a00000000000000000000000000000000000000000000000000000000000c201400000000000000000000000000000000000000000000000000000000000c200b00000000000000000000000000000000000000000000000000000000000c201500000000000000000000000000000000000000000000000000000000000c200c00000000000000000000000000000000000000000000000000000000000c201600000000000000000000000000000000000000000000000000000000000c200d00000000000000000000000000000000000000000000000000000000000c201700000000000000000000000000000000000000000000000000000000000c200e00000000000000000000000000000000000000000000000000000000000c201800000000000000000000000000000000000000000000000000000000000c200f00000000000000000000000000000000000000000000000000000000000c201900000000000000000000000000000000000000000000000000000000000c201000000000000000000000000000000000000000000000000000000000000c201a00000000000000000000000000000000000000000000000000000000000c201100000000000000000000000000000000000000000000000000000000000c201b00000000000000000000000000000000000000000000000000000000000c201200000000000000000000000000000000000000000000000000000000000c201c00000000000000000000000000000000000000000000000000000000000c201300000000000000000000000000000000000000000000000000000000000c201d00000000000000000000000000000000000000000000000000000000000c201400000000000000000000000000000000000000000000000000000000000c201e00000000000000000000000000000000000000000000000000000000000c201500000000000000000000000000000000000000000000000000000000000c201f00000000000000000000000000000000000000000000000000000000000c201600000000000000000000000000000000000000000000000000000000000c202000000000000000000000000000000000000000000000000000000000000c201700000000000000000000000000000000000000000000000000000000000c202100000000000000000000000000000000000000000000000000000000000c201800000000000000000000000000000000000000000000000000000000000c202200000000000000000000000000000000000000000000000000000000000c201900000000000000000000000000000000000000000000000000000000000c202300000000000000000000000000000000000000000000000000000000000c201a00000000000000000000000000000000000000000000000000000000000c202400000000000000000000000000000000000000000000000000000000000c201b00000000000000000000000000000000000000000000000000000000000c202500000000000000000000000000000000000000000000000000000000000c201c00000000000000000000000000000000000000000000000000000000000c202600000000000000000000000000000000000000000000000000000000000c201d00000000000000000000000000000000000000000000000000000000000c202700000000000000000000000000000000000000000000000000000000000c201e00000000000000000000000000000000000000000000000000000000000c202800000000000000000000000000000000000000000000000000000000000c201f00000000000000000000000000000000000000000000000000000000000c202900000000000000000000000000000000000000000000000000000000000c202000000000000000000000000000000000000000000000000000000000000c202a00000000000000000000000000000000000000000000000000000000000c202100000000000000000000000000000000000000000000000000000000000c202b00000000000000000000000000000000000000000000000000000000000c202200000000000000000000000000000000000000000000000000000000000c202c00000000000000000000000000000000000000000000000000000000000c202300000000000000000000000000000000000000000000000000000000000c202d00000000000000000000000000000000000000000000000000000000000c202400000000000000000000000000000000000000000000000000000000000c202e00000000000000000000000000000000000000000000000000000000000c202500000000000000000000000000000000000000000000000000000000000c202f00000000000000000000000000000000000000000000000000000000000c202600000000000000000000000000000000000000000000000000000000000c203000000000000000000000000000000000000000000000000000000000000c202700000000000000000000000000000000000000000000000000000000000c203100000000000000000000000000000000000000000000000000000000000c202800000000000000000000000000000000000000000000000000000000000c203200000000000000000000000000000000000000000000000000000000000c202900000000000000000000000000000000000000000000000000000000000c203300000000000000000000000000000000000000000000000000000000000c202a00000000000000000000000000000000000000000000000000000000000c203400000000000000000000000000000000000000000000000000000000000c202b00000000000000000000000000000000000000000000000000000000000c203500000000000000000000000000000000000000000000000000000000000c202c00000000000000000000000000000000000000000000000000000000000c203600000000000000000000000000000000000000000000000000000000000c202d00000000000000000000000000000000000000000000000000000000000c203700000000000000000000000000000000000000000000000000000000000c202e00000000000000000000000000000000000000000000000000000000000c203800000000000000000000000000000000000000000000000000000000000c202f00000000000000000000000000000000000000000000000000000000000c203900000000000000000000000000000000000000000000000000000000000c203000000000000000000000000000000000000000000000000000000000000c203a00000000000000000000000000000000000000000000000000000000000c203100000000000000000000000000000000000000000000000000000000000c203b00000000000000000000000000000000000000000000000000000000000c203200000000000000000000000000000000000000000000000000000000000c203c00000000000000000000000000000000000000000000000000000000000c203300000000000000000000000000000000000000000000000000000000000c203d00000000000000000000000000000000000000000000000000000000000c203400000000000000000000000000000000000000000000000000000000000c203e00000000000000000000000000000000000000000000000000000000000c203500000000000000000000000000000000000000000000000000000000000c203f00000000000000000000000000000000000000000000000000000000000c203600000000000000000000000000000000000000000000000000000000000c204000000000000000000000000000000000000000000000000000000000000c203700000000000000000000000000000000000000000000000000000000000c204100000000000000000000000000000000000000000000000000000000000c203800000000000000000000000000000000000000000000000000000000000c204200000000000000000000000000000000000000000000000000000000000c203900000000000000000000000000000000000000000000000000000000000c204300000000000000000000000000000000000000000000000000000000000c203a00000000000000000000000000000000000000000000000000000000000c204400000000000000000000000000000000000000000000000000000000000c203b00000000000000000000000000000000000000000000000000000000000c204500000000000000000000000000000000000000000000000000000000000c203c00000000000000000000000000000000000000000000000000000000000c204600000000000000000000000000000000000000000000000000000000000c203d00000000000000000000000000000000000000000000000000000000000c204700000000000000000000000000000000000000000000000000000000000c203e00000000000000000000000000000000000000000000000000000000000c20482000000000000000000000000000000000000000000000000000000000000c170000000000000000000000000000000000000000000000000000000000000c170100000000000000000000000000000000000000000000000000000000000c170200000000000000000000000000000000000000000000000000000000000c170300000000000000000000000000000000000000000000000000000000000c170400000000000000000000000000000000000000000000000000000000000c170500000000000000000000000000000000000000000000000000000000000c170600000000000000000000000000000000000000000000000000000000000c170700000000000000000000000000000000000000000000000000000000000c170800000000000000000000000000000000000000000000000000000000000c170900000000000000000000000000000000000000000000000000000000000c170a00000000000000000000000000000000000000000000000000000000000c170b00000000000000000000000000000000000000000000000000000000000c170c00000000000000000000000000000000000000000000000000000000000c170d00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c170100000000000000000000000000000000000000000000000000000000000c170200000000000000000000000000000000000000000000000000000000000c170300000000000000000000000000000000000000000000000000000000000c170400000000000000000000000000000000000000000000000000000000000c170500000000000000000000000000000000000000000000000000000000000c170600000000000000000000000000000000000000000000000000000000000c170700000000000000000000000000000000000000000000000000000000000c170800000000000000000000000000000000000000000000000000000000000c170900000000000000000000000000000000000000000000000000000000000c170a00000000000000000000000000000000000000000000000000000000000c170b00000000000000000000000000000000000000000000000000000000000c170c00000000000000000000000000000000000000000000000000000000000c170d00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c170200000000000000000000000000000000000000000000000000000000000c170300000000000000000000000000000000000000000000000000000000000c170400000000000000000000000000000000000000000000000000000000000c170500000000000000000000000000000000000000000000000000000000000c170600000000000000000000000000000000000000000000000000000000000c170700000000000000000000000000000000000000000000000000000000000c170800000000000000000000000000000000000000000000000000000000000c170900000000000000000000000000000000000000000000000000000000000c170a00000000000000000000000000000000000000000000000000000000000c170b00000000000000000000000000000000000000000000000000000000000c170c00000000000000000000000000000000000000000000000000000000000c170d00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c170300000000000000000000000000000000000000000000000000000000000c170400000000000000000000000000000000000000000000000000000000000c170500000000000000000000000000000000000000000000000000000000000c170600000000000000000000000000000000000000000000000000000000000c170700000000000000000000000000000000000000000000000000000000000c170800000000000000000000000000000000000000000000000000000000000c170900000000000000000000000000000000000000000000000000000000000c170a00000000000000000000000000000000000000000000000000000000000c170b00000000000000000000000000000000000000000000000000000000000c170c00000000000000000000000000000000000000000000000000000000000c170d00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c170400000000000000000000000000000000000000000000000000000000000c170500000000000000000000000000000000000000000000000000000000000c170600000000000000000000000000000000000000000000000000000000000c170700000000000000000000000000000000000000000000000000000000000c170800000000000000000000000000000000000000000000000000000000000c170900000000000000000000000000000000000000000000000000000000000c170a00000000000000000000000000000000000000000000000000000000000c170b00000000000000000000000000000000000000000000000000000000000c170c00000000000000000000000000000000000000000000000000000000000c170d00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c170500000000000000000000000000000000000000000000000000000000000c170600000000000000000000000000000000000000000000000000000000000c170700000000000000000000000000000000000000000000000000000000000c170800000000000000000000000000000000000000000000000000000000000c170900000000000000000000000000000000000000000000000000000000000c170a00000000000000000000000000000000000000000000000000000000000c170b00000000000000000000000000000000000000000000000000000000000c170c00000000000000000000000000000000000000000000000000000000000c170d00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c170600000000000000000000000000000000000000000000000000000000000c170700000000000000000000000000000000000000000000000000000000000c170800000000000000000000000000000000000000000000000000000000000c170900000000000000000000000000000000000000000000000000000000000c170a00000000000000000000000000000000000000000000000000000000000c170b00000000000000000000000000000000000000000000000000000000000c170c00000000000000000000000000000000000000000000000000000000000c170d00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c170700000000000000000000000000000000000000000000000000000000000c170800000000000000000000000000000000000000000000000000000000000c170900000000000000000000000000000000000000000000000000000000000c170a00000000000000000000000000000000000000000000000000000000000c170b00000000000000000000000000000000000000000000000000000000000c170c00000000000000000000000000000000000000000000000000000000000c170d00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c170800000000000000000000000000000000000000000000000000000000000c170900000000000000000000000000000000000000000000000000000000000c170a00000000000000000000000000000000000000000000000000000000000c170b00000000000000000000000000000000000000000000000000000000000c170c00000000000000000000000000000000000000000000000000000000000c170d00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c170900000000000000000000000000000000000000000000000000000000000c170a00000000000000000000000000000000000000000000000000000000000c170b00000000000000000000000000000000000000000000000000000000000c170c00000000000000000000000000000000000000000000000000000000000c170d00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c170a00000000000000000000000000000000000000000000000000000000000c170b00000000000000000000000000000000000000000000000000000000000c170c00000000000000000000000000000000000000000000000000000000000c170d00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c170b00000000000000000000000000000000000000000000000000000000000c170c00000000000000000000000000000000000000000000000000000000000c170d00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c170c00000000000000000000000000000000000000000000000000000000000c170d00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c170d00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c172700000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c172700000000000000000000000000000000000000000000000000000000000c172800000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c172700000000000000000000000000000000000000000000000000000000000c172800000000000000000000000000000000000000000000000000000000000c172900000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c172700000000000000000000000000000000000000000000000000000000000c172800000000000000000000000000000000000000000000000000000000000c172900000000000000000000000000000000000000000000000000000000000c172a00000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c172700000000000000000000000000000000000000000000000000000000000c172800000000000000000000000000000000000000000000000000000000000c172900000000000000000000000000000000000000000000000000000000000c172a00000000000000000000000000000000000000000000000000000000000c172b00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c172700000000000000000000000000000000000000000000000000000000000c172800000000000000000000000000000000000000000000000000000000000c172900000000000000000000000000000000000000000000000000000000000c172a00000000000000000000000000000000000000000000000000000000000c172b00000000000000000000000000000000000000000000000000000000000c172c00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c172700000000000000000000000000000000000000000000000000000000000c172800000000000000000000000000000000000000000000000000000000000c172900000000000000000000000000000000000000000000000000000000000c172a00000000000000000000000000000000000000000000000000000000000c172b00000000000000000000000000000000000000000000000000000000000c172c00000000000000000000000000000000000000000000000000000000000c172d00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c172700000000000000000000000000000000000000000000000000000000000c172800000000000000000000000000000000000000000000000000000000000c172900000000000000000000000000000000000000000000000000000000000c172a00000000000000000000000000000000000000000000000000000000000c172b00000000000000000000000000000000000000000000000000000000000c172c00000000000000000000000000000000000000000000000000000000000c172d00000000000000000000000000000000000000000000000000000000000c172e00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c172700000000000000000000000000000000000000000000000000000000000c172800000000000000000000000000000000000000000000000000000000000c172900000000000000000000000000000000000000000000000000000000000c172a00000000000000000000000000000000000000000000000000000000000c172b00000000000000000000000000000000000000000000000000000000000c172c00000000000000000000000000000000000000000000000000000000000c172d00000000000000000000000000000000000000000000000000000000000c172e00000000000000000000000000000000000000000000000000000000000c172f00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c172700000000000000000000000000000000000000000000000000000000000c172800000000000000000000000000000000000000000000000000000000000c172900000000000000000000000000000000000000000000000000000000000c172a00000000000000000000000000000000000000000000000000000000000c172b00000000000000000000000000000000000000000000000000000000000c172c00000000000000000000000000000000000000000000000000000000000c172d00000000000000000000000000000000000000000000000000000000000c172e00000000000000000000000000000000000000000000000000000000000c172f00000000000000000000000000000000000000000000000000000000000c1730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000101000000000000000000000000000000000000000000000000000000000000010100100000000000000000000000000000000000000000000000000000000001010020000000000000000000000000000000000000000000000000000000000101003000000000000000000000000000000000000000000000000000000000010100400000000000000000000000000000000000000000000000000000000001010050000000000000000000000000000000000000000000000000000000000101006000000000000000000000000000000000000000000000000000000000010100700000000000000000000000000000000000000000000000000000000001010080000000000000000000000000000000000000000000000000000000000101009000000000000000000000000000000000000000000000000000000000010100a000000000000000000000000000000000000000000000000000000000010100b000000000000000000000000000000000000000000000000000000000010100c000000000000000000000000000000000000000000000000000000000010100d000000000000000000000000000000000000000000000000000000000010100e000000000000000000000000000000000000000000000000000000000010100f0000000000000000000000000000000000000000000000000000000000101010000000000000000000000000000000000000000000000000000000000010101100000000000000000000000000000000000000000000000000000000001010120000000000000000000000000000000000000000000000000000000000101013000000000000000000000000000000000000000000000000000000000010101400000000000000000000000000000000000000000000000000000000001010150000000000000000000000000000000000000000000000000000000000101016000000000000000000000000000000000000000000000000000000000010101700000000000000000000000000000000000000000000000000000000001010180000000000000000000000000000000000000000000000000000000000101019000000000000000000000000000000000000000000000000000000000010101a000000000000000000000000000000000000000000000000000000000010101b000000000000000000000000000000000000000000000000000000000010101c000000000000000000000000000000000000000000000000000000000010101d000000000000000000000000000000000000000000000000000000000010101e000000000000000000000000000000000000000000000000000000000010101f0000000000000000000000000000000000000000000000000000000000101020000000000000000000000000000000000000000000000000000000000010102100000000000000000000000000000000000000000000000000000000001010220000000000000000000000000000000000000000000000000000000000101023000000000000000000000000000000000000000000000000000000000010102400000000000000000000000000000000000000000000000000000000001010250000000000000000000000000000000000000000000000000000000000101026000000000000000000000000000000000000000000000000000000000010102700000000000000000000000000000000000000000000000000000000001010280000000000000000000000000000000000000000000000000000000000101029000000000000000000000000000000000000000000000000000000000010102a000000000000000000000000000000000000000000000000000000000010102b000000000000000000000000000000000000000000000000000000000010102c000000000000000000000000000000000000000000000000000000000010102d000000000000000000000000000000000000000000000000000000000010102e000000000000000000000000000000000000000000000000000000000010102f0000000000000000000000000000000000000000000000000000000000101030000000000000000000000000000000000000000000000000000000000010103100000000000000000000000000000000000000000000000000000000001010320000000000000000000000000000000000000000000000000000000000101033000000000000000000000000000000000000000000000000000000000010103400000000000000000000000000000000000000000000000000000000001010350000000000000000000000000000000000000000000000000000000000101036000000000000000000000000000000000000000000000000000000000010103700000000000000000000000000000000000000000000000000000000001010380000000000000000000000000000000000000000000000000000000000101039000000000000000000000000000000000000000000000000000000000010103a000000000000000000000000000000000000000000000000000000000010103b000000000000000000000000000000000000000000000000000000000010103c000000000000000000000000000000000000000000000000000000000010103d000000000000000000000000000000000000000000000000000000000010103e000000000000000000000000000000000000000000000000000000000010103f4000000000000000000000000000000000000000000000000000000000001000010000000000000000000000000000000000000000000000000000000000101100000000000000000000000000000000000000000000000000000000000010110100000000000000000000000000000000000000000000000000000000001011020000000000000000000000000000000000000000000000000000000000101103000000000000000000000000000000000000000000000000000000000010110400000000000000000000000000000000000000000000000000000000001011050000000000000000000000000000000000000000000000000000000000101106000000000000000000000000000000000000000000000000000000000010110700000000000000000000000000000000000000000000000000000000001011080000000000000000000000000000000000000000000000000000000000101109000000000000000000000000000000000000000000000000000000000010110a000000000000000000000000000000000000000000000000000000000010110b000000000000000000000000000000000000000000000000000000000010110c000000000000000000000000000000000000000000000000000000000010110d000000000000000000000000000000000000000000000000000000000010110e000000000000000000000000000000000000000000000000000000000010110f0000000000000000000000000000000000000000000000000000000000101110000000000000000000000000000000000000000000000000000000000010111100000000000000000000000000000000000000000000000000000000001011120000000000000000000000000000000000000000000000000000000000101113000000000000000000000000000000000000000000000000000000000010111400000000000000000000000000000000000000000000000000000000001011150000000000000000000000000000000000000000000000000000000000101116000000000000000000000000000000000000000000000000000000000010111700000000000000000000000000000000000000000000000000000000001011180000000000000000000000000000000000000000000000000000000000101119000000000000000000000000000000000000000000000000000000000010111a000000000000000000000000000000000000000000000000000000000010111b000000000000000000000000000000000000000000000000000000000010111c000000000000000000000000000000000000000000000000000000000010111d000000000000000000000000000000000000000000000000000000000010111e000000000000000000000000000000000000000000000000000000000010111f0000000000000000000000000000000000000000000000000000000000101120000000000000000000000000000000000000000000000000000000000010112100000000000000000000000000000000000000000000000000000000001011220000000000000000000000000000000000000000000000000000000000101123000000000000000000000000000000000000000000000000000000000010112400000000000000000000000000000000000000000000000000000000001011250000000000000000000000000000000000000000000000000000000000101126000000000000000000000000000000000000000000000000000000000010112700000000000000000000000000000000000000000000000000000000001011280000000000000000000000000000000000000000000000000000000000101129000000000000000000000000000000000000000000000000000000000010112a000000000000000000000000000000000000000000000000000000000010112b000000000000000000000000000000000000000000000000000000000010112c000000000000000000000000000000000000000000000000000000000010112d000000000000000000000000000000000000000000000000000000000010112e000000000000000000000000000000000000000000000000000000000010112f0000000000000000000000000000000000000000000000000000000000101130000000000000000000000000000000000000000000000000000000000010113100000000000000000000000000000000000000000000000000000000001011320000000000000000000000000000000000000000000000000000000000101133000000000000000000000000000000000000000000000000000000000010113400000000000000000000000000000000000000000000000000000000001011350000000000000000000000000000000000000000000000000000000000101136000000000000000000000000000000000000000000000000000000000010113700000000000000000000000000000000000000000000000000000000001011380000000000000000000000000000000000000000000000000000000000101139000000000000000000000000000000000000000000000000000000000010113a000000000000000000000000000000000000000000000000000000000010113b000000000000000000000000000000000000000000000000000000000010113c000000000000000000000000000000000000000000000000000000000010113d000000000000000000000000000000000000000000000000000000000010113e080099145b6c0d32753835121f8b271186d01236948a4622ce78a98347fcfc98390085277a27c6acbd5ffc4c19cd65fc30056999e9bec36998f753132db0ff8e2300f3cf77a7261759ebd5f4149f6ad56746f4499cfcd4adf27a1d373f77da64d5009bc6e0e994a23cde8c95b90c1acc1b4a480c6599d1df2c3f9f6e76f3d1aff200d7a1c4a2700dacaaf07f1f0ff33837bdbabcf0b9ace17efabe0761708c4bb900dbeb8e96d14f21e57d5786b6d6ae7e5ddb1bb35935c0fb246d4bdbca62e02c00fbf12b5e0df6223b801088798e4e04d2a92ffe9a11639b7f0ce314e3412a8000d796e0724de03b796ba77069fcd6cf921e566f3aed15eb3e77258add74e9ff3f0000000000000000000000000000000000000000000000000000000000102000000000000000000000000000000000000000000000000000000000000010200a0000000000000000000000000000000000000000000000000000000000102001000000000000000000000000000000000000000000000000000000000010200b0000000000000000000000000000000000000000000000000000000000102002000000000000000000000000000000000000000000000000000000000010200c0000000000000000000000000000000000000000000000000000000000102003000000000000000000000000000000000000000000000000000000000010200d0000000000000000000000000000000000000000000000000000000000102004000000000000000000000000000000000000000000000000000000000010200e0000000000000000000000000000000000000000000000000000000000102005000000000000000000000000000000000000000000000000000000000010200f00000000000000000000000000000000000000000000000000000000001020060000000000000000000000000000000000000000000000000000000000102010000000000000000000000000000000000000000000000000000000000010200700000000000000000000000000000000000000000000000000000000001020110000000000000000000000000000000000000000000000000000000000102008000000000000000000000000000000000000000000000000000000000010201200000000000000000000000000000000000000000000000000000000001020090000000000000000000000000000000000000000000000000000000000102013000000000000000000000000000000000000000000000000000000000010200a0000000000000000000000000000000000000000000000000000000000102014000000000000000000000000000000000000000000000000000000000010200b0000000000000000000000000000000000000000000000000000000000102015000000000000000000000000000000000000000000000000000000000010200c0000000000000000000000000000000000000000000000000000000000102016000000000000000000000000000000000000000000000000000000000010200d0000000000000000000000000000000000000000000000000000000000102017000000000000000000000000000000000000000000000000000000000010200e0000000000000000000000000000000000000000000000000000000000102018000000000000000000000000000000000000000000000000000000000010200f00000000000000000000000000000000000000000000000000000000001020190000000000000000000000000000000000000000000000000000000000102010000000000000000000000000000000000000000000000000000000000010201a0000000000000000000000000000000000000000000000000000000000102011000000000000000000000000000000000000000000000000000000000010201b0000000000000000000000000000000000000000000000000000000000102012000000000000000000000000000000000000000000000000000000000010201c0000000000000000000000000000000000000000000000000000000000102013000000000000000000000000000000000000000000000000000000000010201d0000000000000000000000000000000000000000000000000000000000102014000000000000000000000000000000000000000000000000000000000010201e0000000000000000000000000000000000000000000000000000000000102015000000000000000000000000000000000000000000000000000000000010201f00000000000000000000000000000000000000000000000000000000001020160000000000000000000000000000000000000000000000000000000000102020000000000000000000000000000000000000000000000000000000000010201700000000000000000000000000000000000000000000000000000000001020210000000000000000000000000000000000000000000000000000000000102018000000000000000000000000000000000000000000000000000000000010202200000000000000000000000000000000000000000000000000000000001020190000000000000000000000000000000000000000000000000000000000102023000000000000000000000000000000000000000000000000000000000010201a0000000000000000000000000000000000000000000000000000000000102024000000000000000000000000000000000000000000000000000000000010201b0000000000000000000000000000000000000000000000000000000000102025000000000000000000000000000000000000000000000000000000000010201c0000000000000000000000000000000000000000000000000000000000102026000000000000000000000000000000000000000000000000000000000010201d0000000000000000000000000000000000000000000000000000000000102027000000000000000000000000000000000000000000000000000000000010201e0000000000000000000000000000000000000000000000000000000000102028000000000000000000000000000000000000000000000000000000000010201f00000000000000000000000000000000000000000000000000000000001020290000000000000000000000000000000000000000000000000000000000102020000000000000000000000000000000000000000000000000000000000010202a0000000000000000000000000000000000000000000000000000000000102021000000000000000000000000000000000000000000000000000000000010202b0000000000000000000000000000000000000000000000000000000000102022000000000000000000000000000000000000000000000000000000000010202c0000000000000000000000000000000000000000000000000000000000102023000000000000000000000000000000000000000000000000000000000010202d0000000000000000000000000000000000000000000000000000000000102024000000000000000000000000000000000000000000000000000000000010202e0000000000000000000000000000000000000000000000000000000000102025000000000000000000000000000000000000000000000000000000000010202f00000000000000000000000000000000000000000000000000000000001020260000000000000000000000000000000000000000000000000000000000102030000000000000000000000000000000000000000000000000000000000010202700000000000000000000000000000000000000000000000000000000001020310000000000000000000000000000000000000000000000000000000000102028000000000000000000000000000000000000000000000000000000000010203200000000000000000000000000000000000000000000000000000000001020290000000000000000000000000000000000000000000000000000000000102033000000000000000000000000000000000000000000000000000000000010202a0000000000000000000000000000000000000000000000000000000000102034000000000000000000000000000000000000000000000000000000000010202b0000000000000000000000000000000000000000000000000000000000102035000000000000000000000000000000000000000000000000000000000010202c0000000000000000000000000000000000000000000000000000000000102036000000000000000000000000000000000000000000000000000000000010202d0000000000000000000000000000000000000000000000000000000000102037000000000000000000000000000000000000000000000000000000000010202e0000000000000000000000000000000000000000000000000000000000102038000000000000000000000000000000000000000000000000000000000010202f00000000000000000000000000000000000000000000000000000000001020390000000000000000000000000000000000000000000000000000000000102030000000000000000000000000000000000000000000000000000000000010203a0000000000000000000000000000000000000000000000000000000000102031000000000000000000000000000000000000000000000000000000000010203b0000000000000000000000000000000000000000000000000000000000102032000000000000000000000000000000000000000000000000000000000010203c0000000000000000000000000000000000000000000000000000000000102033000000000000000000000000000000000000000000000000000000000010203d0000000000000000000000000000000000000000000000000000000000102034000000000000000000000000000000000000000000000000000000000010203e0000000000000000000000000000000000000000000000000000000000102035000000000000000000000000000000000000000000000000000000000010203f00000000000000000000000000000000000000000000000000000000001020360000000000000000000000000000000000000000000000000000000000102040000000000000000000000000000000000000000000000000000000000010203700000000000000000000000000000000000000000000000000000000001020410000000000000000000000000000000000000000000000000000000000102038000000000000000000000000000000000000000000000000000000000010204200000000000000000000000000000000000000000000000000000000001020390000000000000000000000000000000000000000000000000000000000102043000000000000000000000000000000000000000000000000000000000010203a0000000000000000000000000000000000000000000000000000000000102044000000000000000000000000000000000000000000000000000000000010203b0000000000000000000000000000000000000000000000000000000000102045000000000000000000000000000000000000000000000000000000000010203c0000000000000000000000000000000000000000000000000000000000102046000000000000000000000000000000000000000000000000000000000010203d0000000000000000000000000000000000000000000000000000000000102047000000000000000000000000000000000000000000000000000000000010203e0000000000000000000000000000000000000000000000000000000000102048200000000000000000000000000000000000000000000000000000000000101700000000000000000000000000000000000000000000000000000000000010170100000000000000000000000000000000000000000000000000000000001017020000000000000000000000000000000000000000000000000000000000101703000000000000000000000000000000000000000000000000000000000010170400000000000000000000000000000000000000000000000000000000001017050000000000000000000000000000000000000000000000000000000000101706000000000000000000000000000000000000000000000000000000000010170700000000000000000000000000000000000000000000000000000000001017080000000000000000000000000000000000000000000000000000000000101709000000000000000000000000000000000000000000000000000000000010170a000000000000000000000000000000000000000000000000000000000010170b000000000000000000000000000000000000000000000000000000000010170c000000000000000000000000000000000000000000000000000000000010170d000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f00000000000000000000000000000000000000000000000000000000001017100000000000000000000000000000000000000000000000000000000000101711000000000000000000000000000000000000000000000000000000000010170100000000000000000000000000000000000000000000000000000000001017020000000000000000000000000000000000000000000000000000000000101703000000000000000000000000000000000000000000000000000000000010170400000000000000000000000000000000000000000000000000000000001017050000000000000000000000000000000000000000000000000000000000101706000000000000000000000000000000000000000000000000000000000010170700000000000000000000000000000000000000000000000000000000001017080000000000000000000000000000000000000000000000000000000000101709000000000000000000000000000000000000000000000000000000000010170a000000000000000000000000000000000000000000000000000000000010170b000000000000000000000000000000000000000000000000000000000010170c000000000000000000000000000000000000000000000000000000000010170d000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f00000000000000000000000000000000000000000000000000000000001017100000000000000000000000000000000000000000000000000000000000101711000000000000000000000000000000000000000000000000000000000010171200000000000000000000000000000000000000000000000000000000001017020000000000000000000000000000000000000000000000000000000000101703000000000000000000000000000000000000000000000000000000000010170400000000000000000000000000000000000000000000000000000000001017050000000000000000000000000000000000000000000000000000000000101706000000000000000000000000000000000000000000000000000000000010170700000000000000000000000000000000000000000000000000000000001017080000000000000000000000000000000000000000000000000000000000101709000000000000000000000000000000000000000000000000000000000010170a000000000000000000000000000000000000000000000000000000000010170b000000000000000000000000000000000000000000000000000000000010170c000000000000000000000000000000000000000000000000000000000010170d000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f00000000000000000000000000000000000000000000000000000000001017100000000000000000000000000000000000000000000000000000000000101711000000000000000000000000000000000000000000000000000000000010171200000000000000000000000000000000000000000000000000000000001017130000000000000000000000000000000000000000000000000000000000101703000000000000000000000000000000000000000000000000000000000010170400000000000000000000000000000000000000000000000000000000001017050000000000000000000000000000000000000000000000000000000000101706000000000000000000000000000000000000000000000000000000000010170700000000000000000000000000000000000000000000000000000000001017080000000000000000000000000000000000000000000000000000000000101709000000000000000000000000000000000000000000000000000000000010170a000000000000000000000000000000000000000000000000000000000010170b000000000000000000000000000000000000000000000000000000000010170c000000000000000000000000000000000000000000000000000000000010170d000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f00000000000000000000000000000000000000000000000000000000001017100000000000000000000000000000000000000000000000000000000000101711000000000000000000000000000000000000000000000000000000000010171200000000000000000000000000000000000000000000000000000000001017130000000000000000000000000000000000000000000000000000000000101714000000000000000000000000000000000000000000000000000000000010170400000000000000000000000000000000000000000000000000000000001017050000000000000000000000000000000000000000000000000000000000101706000000000000000000000000000000000000000000000000000000000010170700000000000000000000000000000000000000000000000000000000001017080000000000000000000000000000000000000000000000000000000000101709000000000000000000000000000000000000000000000000000000000010170a000000000000000000000000000000000000000000000000000000000010170b000000000000000000000000000000000000000000000000000000000010170c000000000000000000000000000000000000000000000000000000000010170d000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f00000000000000000000000000000000000000000000000000000000001017100000000000000000000000000000000000000000000000000000000000101711000000000000000000000000000000000000000000000000000000000010171200000000000000000000000000000000000000000000000000000000001017130000000000000000000000000000000000000000000000000000000000101714000000000000000000000000000000000000000000000000000000000010171500000000000000000000000000000000000000000000000000000000001017050000000000000000000000000000000000000000000000000000000000101706000000000000000000000000000000000000000000000000000000000010170700000000000000000000000000000000000000000000000000000000001017080000000000000000000000000000000000000000000000000000000000101709000000000000000000000000000000000000000000000000000000000010170a000000000000000000000000000000000000000000000000000000000010170b000000000000000000000000000000000000000000000000000000000010170c000000000000000000000000000000000000000000000000000000000010170d000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f00000000000000000000000000000000000000000000000000000000001017100000000000000000000000000000000000000000000000000000000000101711000000000000000000000000000000000000000000000000000000000010171200000000000000000000000000000000000000000000000000000000001017130000000000000000000000000000000000000000000000000000000000101714000000000000000000000000000000000000000000000000000000000010171500000000000000000000000000000000000000000000000000000000001017160000000000000000000000000000000000000000000000000000000000101706000000000000000000000000000000000000000000000000000000000010170700000000000000000000000000000000000000000000000000000000001017080000000000000000000000000000000000000000000000000000000000101709000000000000000000000000000000000000000000000000000000000010170a000000000000000000000000000000000000000000000000000000000010170b000000000000000000000000000000000000000000000000000000000010170c000000000000000000000000000000000000000000000000000000000010170d000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f00000000000000000000000000000000000000000000000000000000001017100000000000000000000000000000000000000000000000000000000000101711000000000000000000000000000000000000000000000000000000000010171200000000000000000000000000000000000000000000000000000000001017130000000000000000000000000000000000000000000000000000000000101714000000000000000000000000000000000000000000000000000000000010171500000000000000000000000000000000000000000000000000000000001017160000000000000000000000000000000000000000000000000000000000101717000000000000000000000000000000000000000000000000000000000010170700000000000000000000000000000000000000000000000000000000001017080000000000000000000000000000000000000000000000000000000000101709000000000000000000000000000000000000000000000000000000000010170a000000000000000000000000000000000000000000000000000000000010170b000000000000000000000000000000000000000000000000000000000010170c000000000000000000000000000000000000000000000000000000000010170d000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f00000000000000000000000000000000000000000000000000000000001017100000000000000000000000000000000000000000000000000000000000101711000000000000000000000000000000000000000000000000000000000010171200000000000000000000000000000000000000000000000000000000001017130000000000000000000000000000000000000000000000000000000000101714000000000000000000000000000000000000000000000000000000000010171500000000000000000000000000000000000000000000000000000000001017160000000000000000000000000000000000000000000000000000000000101717000000000000000000000000000000000000000000000000000000000010171800000000000000000000000000000000000000000000000000000000001017080000000000000000000000000000000000000000000000000000000000101709000000000000000000000000000000000000000000000000000000000010170a000000000000000000000000000000000000000000000000000000000010170b000000000000000000000000000000000000000000000000000000000010170c000000000000000000000000000000000000000000000000000000000010170d000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f00000000000000000000000000000000000000000000000000000000001017100000000000000000000000000000000000000000000000000000000000101711000000000000000000000000000000000000000000000000000000000010171200000000000000000000000000000000000000000000000000000000001017130000000000000000000000000000000000000000000000000000000000101714000000000000000000000000000000000000000000000000000000000010171500000000000000000000000000000000000000000000000000000000001017160000000000000000000000000000000000000000000000000000000000101717000000000000000000000000000000000000000000000000000000000010171800000000000000000000000000000000000000000000000000000000001017190000000000000000000000000000000000000000000000000000000000101709000000000000000000000000000000000000000000000000000000000010170a000000000000000000000000000000000000000000000000000000000010170b000000000000000000000000000000000000000000000000000000000010170c000000000000000000000000000000000000000000000000000000000010170d000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f0000000000000000000000000000000000000000000000000000000000101710000000000000000000000000000000000000000000000000000000000010171100000000000000000000000000000000000000000000000000000000001017120000000000000000000000000000000000000000000000000000000000101713000000000000000000000000000000000000000000000000000000000010171400000000000000000000000000000000000000000000000000000000001017150000000000000000000000000000000000000000000000000000000000101716000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010170a000000000000000000000000000000000000000000000000000000000010170b000000000000000000000000000000000000000000000000000000000010170c000000000000000000000000000000000000000000000000000000000010170d000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f0000000000000000000000000000000000000000000000000000000000101710000000000000000000000000000000000000000000000000000000000010171100000000000000000000000000000000000000000000000000000000001017120000000000000000000000000000000000000000000000000000000000101713000000000000000000000000000000000000000000000000000000000010171400000000000000000000000000000000000000000000000000000000001017150000000000000000000000000000000000000000000000000000000000101716000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010170b000000000000000000000000000000000000000000000000000000000010170c000000000000000000000000000000000000000000000000000000000010170d000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f0000000000000000000000000000000000000000000000000000000000101710000000000000000000000000000000000000000000000000000000000010171100000000000000000000000000000000000000000000000000000000001017120000000000000000000000000000000000000000000000000000000000101713000000000000000000000000000000000000000000000000000000000010171400000000000000000000000000000000000000000000000000000000001017150000000000000000000000000000000000000000000000000000000000101716000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010170c000000000000000000000000000000000000000000000000000000000010170d000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f0000000000000000000000000000000000000000000000000000000000101710000000000000000000000000000000000000000000000000000000000010171100000000000000000000000000000000000000000000000000000000001017120000000000000000000000000000000000000000000000000000000000101713000000000000000000000000000000000000000000000000000000000010171400000000000000000000000000000000000000000000000000000000001017150000000000000000000000000000000000000000000000000000000000101716000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010170d000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f0000000000000000000000000000000000000000000000000000000000101710000000000000000000000000000000000000000000000000000000000010171100000000000000000000000000000000000000000000000000000000001017120000000000000000000000000000000000000000000000000000000000101713000000000000000000000000000000000000000000000000000000000010171400000000000000000000000000000000000000000000000000000000001017150000000000000000000000000000000000000000000000000000000000101716000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f0000000000000000000000000000000000000000000000000000000000101710000000000000000000000000000000000000000000000000000000000010171100000000000000000000000000000000000000000000000000000000001017120000000000000000000000000000000000000000000000000000000000101713000000000000000000000000000000000000000000000000000000000010171400000000000000000000000000000000000000000000000000000000001017150000000000000000000000000000000000000000000000000000000000101716000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f000000000000000000000000000000000000000000000000000000000010170f0000000000000000000000000000000000000000000000000000000000101710000000000000000000000000000000000000000000000000000000000010171100000000000000000000000000000000000000000000000000000000001017120000000000000000000000000000000000000000000000000000000000101713000000000000000000000000000000000000000000000000000000000010171400000000000000000000000000000000000000000000000000000000001017150000000000000000000000000000000000000000000000000000000000101716000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f00000000000000000000000000000000000000000000000000000000001017200000000000000000000000000000000000000000000000000000000000101710000000000000000000000000000000000000000000000000000000000010171100000000000000000000000000000000000000000000000000000000001017120000000000000000000000000000000000000000000000000000000000101713000000000000000000000000000000000000000000000000000000000010171400000000000000000000000000000000000000000000000000000000001017150000000000000000000000000000000000000000000000000000000000101716000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f00000000000000000000000000000000000000000000000000000000001017200000000000000000000000000000000000000000000000000000000000101721000000000000000000000000000000000000000000000000000000000010171100000000000000000000000000000000000000000000000000000000001017120000000000000000000000000000000000000000000000000000000000101713000000000000000000000000000000000000000000000000000000000010171400000000000000000000000000000000000000000000000000000000001017150000000000000000000000000000000000000000000000000000000000101716000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f00000000000000000000000000000000000000000000000000000000001017200000000000000000000000000000000000000000000000000000000000101721000000000000000000000000000000000000000000000000000000000010172200000000000000000000000000000000000000000000000000000000001017120000000000000000000000000000000000000000000000000000000000101713000000000000000000000000000000000000000000000000000000000010171400000000000000000000000000000000000000000000000000000000001017150000000000000000000000000000000000000000000000000000000000101716000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f00000000000000000000000000000000000000000000000000000000001017200000000000000000000000000000000000000000000000000000000000101721000000000000000000000000000000000000000000000000000000000010172200000000000000000000000000000000000000000000000000000000001017230000000000000000000000000000000000000000000000000000000000101713000000000000000000000000000000000000000000000000000000000010171400000000000000000000000000000000000000000000000000000000001017150000000000000000000000000000000000000000000000000000000000101716000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f00000000000000000000000000000000000000000000000000000000001017200000000000000000000000000000000000000000000000000000000000101721000000000000000000000000000000000000000000000000000000000010172200000000000000000000000000000000000000000000000000000000001017230000000000000000000000000000000000000000000000000000000000101724000000000000000000000000000000000000000000000000000000000010171400000000000000000000000000000000000000000000000000000000001017150000000000000000000000000000000000000000000000000000000000101716000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f00000000000000000000000000000000000000000000000000000000001017200000000000000000000000000000000000000000000000000000000000101721000000000000000000000000000000000000000000000000000000000010172200000000000000000000000000000000000000000000000000000000001017230000000000000000000000000000000000000000000000000000000000101724000000000000000000000000000000000000000000000000000000000010172500000000000000000000000000000000000000000000000000000000001017150000000000000000000000000000000000000000000000000000000000101716000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f00000000000000000000000000000000000000000000000000000000001017200000000000000000000000000000000000000000000000000000000000101721000000000000000000000000000000000000000000000000000000000010172200000000000000000000000000000000000000000000000000000000001017230000000000000000000000000000000000000000000000000000000000101724000000000000000000000000000000000000000000000000000000000010172500000000000000000000000000000000000000000000000000000000001017260000000000000000000000000000000000000000000000000000000000101716000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f00000000000000000000000000000000000000000000000000000000001017200000000000000000000000000000000000000000000000000000000000101721000000000000000000000000000000000000000000000000000000000010172200000000000000000000000000000000000000000000000000000000001017230000000000000000000000000000000000000000000000000000000000101724000000000000000000000000000000000000000000000000000000000010172500000000000000000000000000000000000000000000000000000000001017260000000000000000000000000000000000000000000000000000000000101727000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f00000000000000000000000000000000000000000000000000000000001017200000000000000000000000000000000000000000000000000000000000101721000000000000000000000000000000000000000000000000000000000010172200000000000000000000000000000000000000000000000000000000001017230000000000000000000000000000000000000000000000000000000000101724000000000000000000000000000000000000000000000000000000000010172500000000000000000000000000000000000000000000000000000000001017260000000000000000000000000000000000000000000000000000000000101727000000000000000000000000000000000000000000000000000000000010172800000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f00000000000000000000000000000000000000000000000000000000001017200000000000000000000000000000000000000000000000000000000000101721000000000000000000000000000000000000000000000000000000000010172200000000000000000000000000000000000000000000000000000000001017230000000000000000000000000000000000000000000000000000000000101724000000000000000000000000000000000000000000000000000000000010172500000000000000000000000000000000000000000000000000000000001017260000000000000000000000000000000000000000000000000000000000101727000000000000000000000000000000000000000000000000000000000010172800000000000000000000000000000000000000000000000000000000001017290000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f0000000000000000000000000000000000000000000000000000000000101720000000000000000000000000000000000000000000000000000000000010172100000000000000000000000000000000000000000000000000000000001017220000000000000000000000000000000000000000000000000000000000101723000000000000000000000000000000000000000000000000000000000010172400000000000000000000000000000000000000000000000000000000001017250000000000000000000000000000000000000000000000000000000000101726000000000000000000000000000000000000000000000000000000000010172700000000000000000000000000000000000000000000000000000000001017280000000000000000000000000000000000000000000000000000000000101729000000000000000000000000000000000000000000000000000000000010172a000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f0000000000000000000000000000000000000000000000000000000000101720000000000000000000000000000000000000000000000000000000000010172100000000000000000000000000000000000000000000000000000000001017220000000000000000000000000000000000000000000000000000000000101723000000000000000000000000000000000000000000000000000000000010172400000000000000000000000000000000000000000000000000000000001017250000000000000000000000000000000000000000000000000000000000101726000000000000000000000000000000000000000000000000000000000010172700000000000000000000000000000000000000000000000000000000001017280000000000000000000000000000000000000000000000000000000000101729000000000000000000000000000000000000000000000000000000000010172a000000000000000000000000000000000000000000000000000000000010172b000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f0000000000000000000000000000000000000000000000000000000000101720000000000000000000000000000000000000000000000000000000000010172100000000000000000000000000000000000000000000000000000000001017220000000000000000000000000000000000000000000000000000000000101723000000000000000000000000000000000000000000000000000000000010172400000000000000000000000000000000000000000000000000000000001017250000000000000000000000000000000000000000000000000000000000101726000000000000000000000000000000000000000000000000000000000010172700000000000000000000000000000000000000000000000000000000001017280000000000000000000000000000000000000000000000000000000000101729000000000000000000000000000000000000000000000000000000000010172a000000000000000000000000000000000000000000000000000000000010172b000000000000000000000000000000000000000000000000000000000010172c000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f0000000000000000000000000000000000000000000000000000000000101720000000000000000000000000000000000000000000000000000000000010172100000000000000000000000000000000000000000000000000000000001017220000000000000000000000000000000000000000000000000000000000101723000000000000000000000000000000000000000000000000000000000010172400000000000000000000000000000000000000000000000000000000001017250000000000000000000000000000000000000000000000000000000000101726000000000000000000000000000000000000000000000000000000000010172700000000000000000000000000000000000000000000000000000000001017280000000000000000000000000000000000000000000000000000000000101729000000000000000000000000000000000000000000000000000000000010172a000000000000000000000000000000000000000000000000000000000010172b000000000000000000000000000000000000000000000000000000000010172c000000000000000000000000000000000000000000000000000000000010172d000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f0000000000000000000000000000000000000000000000000000000000101720000000000000000000000000000000000000000000000000000000000010172100000000000000000000000000000000000000000000000000000000001017220000000000000000000000000000000000000000000000000000000000101723000000000000000000000000000000000000000000000000000000000010172400000000000000000000000000000000000000000000000000000000001017250000000000000000000000000000000000000000000000000000000000101726000000000000000000000000000000000000000000000000000000000010172700000000000000000000000000000000000000000000000000000000001017280000000000000000000000000000000000000000000000000000000000101729000000000000000000000000000000000000000000000000000000000010172a000000000000000000000000000000000000000000000000000000000010172b000000000000000000000000000000000000000000000000000000000010172c000000000000000000000000000000000000000000000000000000000010172d000000000000000000000000000000000000000000000000000000000010172e000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f0000000000000000000000000000000000000000000000000000000000101720000000000000000000000000000000000000000000000000000000000010172100000000000000000000000000000000000000000000000000000000001017220000000000000000000000000000000000000000000000000000000000101723000000000000000000000000000000000000000000000000000000000010172400000000000000000000000000000000000000000000000000000000001017250000000000000000000000000000000000000000000000000000000000101726000000000000000000000000000000000000000000000000000000000010172700000000000000000000000000000000000000000000000000000000001017280000000000000000000000000000000000000000000000000000000000101729000000000000000000000000000000000000000000000000000000000010172a000000000000000000000000000000000000000000000000000000000010172b000000000000000000000000000000000000000000000000000000000010172c000000000000000000000000000000000000000000000000000000000010172d000000000000000000000000000000000000000000000000000000000010172e000000000000000000000000000000000000000000000000000000000010172f000000000000000000000000000000000000000000000000000000000010171f0000000000000000000000000000000000000000000000000000000000101720000000000000000000000000000000000000000000000000000000000010172100000000000000000000000000000000000000000000000000000000001017220000000000000000000000000000000000000000000000000000000000101723000000000000000000000000000000000000000000000000000000000010172400000000000000000000000000000000000000000000000000000000001017250000000000000000000000000000000000000000000000000000000000101726000000000000000000000000000000000000000000000000000000000010172700000000000000000000000000000000000000000000000000000000001017280000000000000000000000000000000000000000000000000000000000101729000000000000000000000000000000000000000000000000000000000010172a000000000000000000000000000000000000000000000000000000000010172b000000000000000000000000000000000000000000000000000000000010172c000000000000000000000000000000000000000000000000000000000010172d000000000000000000000000000000000000000000000000000000000010172e000000000000000000000000000000000000000000000000000000000010172f0000000000000000000000000000000000000000000000000000000000101730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "txsEffectsHash": "0x00b9377a9906113c4237e09edce4d55e149267628834409b8d922ce2a8082fea", "decodedHeader": { "contentCommitment": { "inHash": "0x00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c", "outHash": "0x000ca4a4610ad22c97c9161cedcf01faa3619f1b85457f1627d09627b71903a6", "numTxs": 4, - "txsEffectsHash": "0x00db66b36b24ebccb7543a74620018056cad2f0b08eaf251ad00362551f0a2d0" + "txsEffectsHash": "0x00b9377a9906113c4237e09edce4d55e149267628834409b8d922ce2a8082fea" }, "globalVariables": { "blockNumber": 1, "slotNumber": "0x000000000000000000000000000000000000000000000000000000000000001a", "chainId": 31337, - "timestamp": 1732579038, + "timestamp": 1732894948, "version": 1, - "coinbase": "0x7bf63a9118e60cc630c4faa654223f715d4bd20e", - "feeRecipient": "0x2f2bacf41d88061f8a9e9234dfb8f6cdf5287e15eeeb4a6af5b0691d846bad5d", + "coinbase": "0x6bb9503e73901291188976cb74f3ee186877aed7", + "feeRecipient": "0x1560bcdb97a3f65361a878c5fde7c89bd762de8a4e92dd872bb5e1f39f86d30c", "gasFees": { "feePerDaGas": 0, - "feePerL2Gas": 54166854910 + "feePerL2Gas": 54165220200 } }, "totalFees": "0x0000000000000000000000000000000000000000000000000000000000000000", @@ -100,7 +100,7 @@ }, "nullifierTree": { "nextAvailableLeafIndex": 384, - "root": "0x1d52eeaaacb445d9193d29e0df8f0ad4bf69bc457fe955b8e05b48ae3fdc3b3f" + "root": "0x0627376bc9d9804095498d2fe262c2dceeb5ecfc696966496eaee65f1798fed5" }, "publicDataTree": { "nextAvailableLeafIndex": 380, @@ -109,8 +109,8 @@ } } }, - "header": "0x0237797d6a2c04d20d4fa06b74482bd970ccd51a43d9b05b57e9b91fa1ae1cae00000001000000000000000000000000000000000000000000000000000000000000000400db66b36b24ebccb7543a74620018056cad2f0b08eaf251ad00362551f0a2d000089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c000ca4a4610ad22c97c9161cedcf01faa3619f1b85457f1627d09627b71903a62e33ee2008411c04b99c24b313513d097a0d21a5040b6193d1f978b8226892d60000001000553ea03210e12bf95ed15f0105108f39db784d318cfe9b52cba413618711ce000001001d52eeaaacb445d9193d29e0df8f0ad4bf69bc457fe955b8e05b48ae3fdc3b3f0000018020a27b2839a892ce7ac7c3a76b625388d4efdd4d736f29f86d41bb32d4bc73cf0000017c0000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000067450ede7bf63a9118e60cc630c4faa654223f715d4bd20e2f2bacf41d88061f8a9e9234dfb8f6cdf5287e15eeeb4a6af5b0691d846bad5d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c9c989cfe00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x00f895b5ad3a835f2abbcc0793d4799b7316a18e690c18b45c96e6a12d2a3231", + "header": "0x0237797d6a2c04d20d4fa06b74482bd970ccd51a43d9b05b57e9b91fa1ae1cae00000001000000000000000000000000000000000000000000000000000000000000000400b9377a9906113c4237e09edce4d55e149267628834409b8d922ce2a8082fea00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c000ca4a4610ad22c97c9161cedcf01faa3619f1b85457f1627d09627b71903a62e33ee2008411c04b99c24b313513d097a0d21a5040b6193d1f978b8226892d60000001000553ea03210e12bf95ed15f0105108f39db784d318cfe9b52cba413618711ce000001000627376bc9d9804095498d2fe262c2dceeb5ecfc696966496eaee65f1798fed50000018020a27b2839a892ce7ac7c3a76b625388d4efdd4d736f29f86d41bb32d4bc73cf0000017c0000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000006749e0e46bb9503e73901291188976cb74f3ee186877aed71560bcdb97a3f65361a878c5fde7c89bd762de8a4e92dd872bb5e1f39f86d30c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c9c7fab6800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x00e238c1a9cef83aa07f67d4447c43e1df27285e5fe4059262ff48d52c540364", "numTxs": 4 } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/mixed_block_2.json b/l1-contracts/test/fixtures/mixed_block_2.json index 309977c2b3a..95d14f79e71 100644 --- a/l1-contracts/test/fixtures/mixed_block_2.json +++ b/l1-contracts/test/fixtures/mixed_block_2.json @@ -58,35 +58,35 @@ ] }, "block": { - "archive": "0x1a67606f67cc90d680873608c953ab58de942279a740dd8f4221cbd39327449a", - "blockHash": "0x0a3664a7aa5b6e62973e4b7be7807869ada474cc3aacd49dacc82e55dd1ccd26", - "body": "0x00000004000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000141000000000000000000000000000000000000000000000000000000000000014100100000000000000000000000000000000000000000000000000000000001410020000000000000000000000000000000000000000000000000000000000141003000000000000000000000000000000000000000000000000000000000014100400000000000000000000000000000000000000000000000000000000001410050000000000000000000000000000000000000000000000000000000000141006000000000000000000000000000000000000000000000000000000000014100700000000000000000000000000000000000000000000000000000000001410080000000000000000000000000000000000000000000000000000000000141009000000000000000000000000000000000000000000000000000000000014100a000000000000000000000000000000000000000000000000000000000014100b000000000000000000000000000000000000000000000000000000000014100c000000000000000000000000000000000000000000000000000000000014100d000000000000000000000000000000000000000000000000000000000014100e000000000000000000000000000000000000000000000000000000000014100f0000000000000000000000000000000000000000000000000000000000141010000000000000000000000000000000000000000000000000000000000014101100000000000000000000000000000000000000000000000000000000001410120000000000000000000000000000000000000000000000000000000000141013000000000000000000000000000000000000000000000000000000000014101400000000000000000000000000000000000000000000000000000000001410150000000000000000000000000000000000000000000000000000000000141016000000000000000000000000000000000000000000000000000000000014101700000000000000000000000000000000000000000000000000000000001410180000000000000000000000000000000000000000000000000000000000141019000000000000000000000000000000000000000000000000000000000014101a000000000000000000000000000000000000000000000000000000000014101b000000000000000000000000000000000000000000000000000000000014101c000000000000000000000000000000000000000000000000000000000014101d000000000000000000000000000000000000000000000000000000000014101e000000000000000000000000000000000000000000000000000000000014101f0000000000000000000000000000000000000000000000000000000000141020000000000000000000000000000000000000000000000000000000000014102100000000000000000000000000000000000000000000000000000000001410220000000000000000000000000000000000000000000000000000000000141023000000000000000000000000000000000000000000000000000000000014102400000000000000000000000000000000000000000000000000000000001410250000000000000000000000000000000000000000000000000000000000141026000000000000000000000000000000000000000000000000000000000014102700000000000000000000000000000000000000000000000000000000001410280000000000000000000000000000000000000000000000000000000000141029000000000000000000000000000000000000000000000000000000000014102a000000000000000000000000000000000000000000000000000000000014102b000000000000000000000000000000000000000000000000000000000014102c000000000000000000000000000000000000000000000000000000000014102d000000000000000000000000000000000000000000000000000000000014102e000000000000000000000000000000000000000000000000000000000014102f0000000000000000000000000000000000000000000000000000000000141030000000000000000000000000000000000000000000000000000000000014103100000000000000000000000000000000000000000000000000000000001410320000000000000000000000000000000000000000000000000000000000141033000000000000000000000000000000000000000000000000000000000014103400000000000000000000000000000000000000000000000000000000001410350000000000000000000000000000000000000000000000000000000000141036000000000000000000000000000000000000000000000000000000000014103700000000000000000000000000000000000000000000000000000000001410380000000000000000000000000000000000000000000000000000000000141039000000000000000000000000000000000000000000000000000000000014103a000000000000000000000000000000000000000000000000000000000014103b000000000000000000000000000000000000000000000000000000000014103c000000000000000000000000000000000000000000000000000000000014103d000000000000000000000000000000000000000000000000000000000014103e000000000000000000000000000000000000000000000000000000000014103f3f0000000000000000000000000000000000000000000000000000000000141100000000000000000000000000000000000000000000000000000000000014110100000000000000000000000000000000000000000000000000000000001411020000000000000000000000000000000000000000000000000000000000141103000000000000000000000000000000000000000000000000000000000014110400000000000000000000000000000000000000000000000000000000001411050000000000000000000000000000000000000000000000000000000000141106000000000000000000000000000000000000000000000000000000000014110700000000000000000000000000000000000000000000000000000000001411080000000000000000000000000000000000000000000000000000000000141109000000000000000000000000000000000000000000000000000000000014110a000000000000000000000000000000000000000000000000000000000014110b000000000000000000000000000000000000000000000000000000000014110c000000000000000000000000000000000000000000000000000000000014110d000000000000000000000000000000000000000000000000000000000014110e000000000000000000000000000000000000000000000000000000000014110f0000000000000000000000000000000000000000000000000000000000141110000000000000000000000000000000000000000000000000000000000014111100000000000000000000000000000000000000000000000000000000001411120000000000000000000000000000000000000000000000000000000000141113000000000000000000000000000000000000000000000000000000000014111400000000000000000000000000000000000000000000000000000000001411150000000000000000000000000000000000000000000000000000000000141116000000000000000000000000000000000000000000000000000000000014111700000000000000000000000000000000000000000000000000000000001411180000000000000000000000000000000000000000000000000000000000141119000000000000000000000000000000000000000000000000000000000014111a000000000000000000000000000000000000000000000000000000000014111b000000000000000000000000000000000000000000000000000000000014111c000000000000000000000000000000000000000000000000000000000014111d000000000000000000000000000000000000000000000000000000000014111e000000000000000000000000000000000000000000000000000000000014111f0000000000000000000000000000000000000000000000000000000000141120000000000000000000000000000000000000000000000000000000000014112100000000000000000000000000000000000000000000000000000000001411220000000000000000000000000000000000000000000000000000000000141123000000000000000000000000000000000000000000000000000000000014112400000000000000000000000000000000000000000000000000000000001411250000000000000000000000000000000000000000000000000000000000141126000000000000000000000000000000000000000000000000000000000014112700000000000000000000000000000000000000000000000000000000001411280000000000000000000000000000000000000000000000000000000000141129000000000000000000000000000000000000000000000000000000000014112a000000000000000000000000000000000000000000000000000000000014112b000000000000000000000000000000000000000000000000000000000014112c000000000000000000000000000000000000000000000000000000000014112d000000000000000000000000000000000000000000000000000000000014112e000000000000000000000000000000000000000000000000000000000014112f0000000000000000000000000000000000000000000000000000000000141130000000000000000000000000000000000000000000000000000000000014113100000000000000000000000000000000000000000000000000000000001411320000000000000000000000000000000000000000000000000000000000141133000000000000000000000000000000000000000000000000000000000014113400000000000000000000000000000000000000000000000000000000001411350000000000000000000000000000000000000000000000000000000000141136000000000000000000000000000000000000000000000000000000000014113700000000000000000000000000000000000000000000000000000000001411380000000000000000000000000000000000000000000000000000000000141139000000000000000000000000000000000000000000000000000000000014113a000000000000000000000000000000000000000000000000000000000014113b000000000000000000000000000000000000000000000000000000000014113c000000000000000000000000000000000000000000000000000000000014113d000000000000000000000000000000000000000000000000000000000014113e08005c015113cb57d67dd6c0febd596819ac0298b6a23fc80aba17d445d540059a00f20b7d1308051fe7b68031a7c336b0b4b56738928b6510133aff1b818d5a9a0063eec1883a4f95f4933f9275e850d84b3d035f5061ed986c437a07331fd30e00d3a32d6bbc4fd843686fd0c5e118a73b847529977dca5b9e0e81f6604f22ca00c2f4f5133d9194d41e853e5e951e16690babce8461f25342c0bad20f2aa1e3000a6bf4739e7eb387913d955dc2e8f14f8cce27696b9d2e128b6acefafb80ee005763f7e0648f958b559677622a648f318fc79ebc0cb539170d49c26456e69200302e2b8a92cda941e9af8761b89899a58a587656d9710594e1d865b16522993f0000000000000000000000000000000000000000000000000000000000142000000000000000000000000000000000000000000000000000000000000014200a0000000000000000000000000000000000000000000000000000000000142001000000000000000000000000000000000000000000000000000000000014200b0000000000000000000000000000000000000000000000000000000000142002000000000000000000000000000000000000000000000000000000000014200c0000000000000000000000000000000000000000000000000000000000142003000000000000000000000000000000000000000000000000000000000014200d0000000000000000000000000000000000000000000000000000000000142004000000000000000000000000000000000000000000000000000000000014200e0000000000000000000000000000000000000000000000000000000000142005000000000000000000000000000000000000000000000000000000000014200f00000000000000000000000000000000000000000000000000000000001420060000000000000000000000000000000000000000000000000000000000142010000000000000000000000000000000000000000000000000000000000014200700000000000000000000000000000000000000000000000000000000001420110000000000000000000000000000000000000000000000000000000000142008000000000000000000000000000000000000000000000000000000000014201200000000000000000000000000000000000000000000000000000000001420090000000000000000000000000000000000000000000000000000000000142013000000000000000000000000000000000000000000000000000000000014200a0000000000000000000000000000000000000000000000000000000000142014000000000000000000000000000000000000000000000000000000000014200b0000000000000000000000000000000000000000000000000000000000142015000000000000000000000000000000000000000000000000000000000014200c0000000000000000000000000000000000000000000000000000000000142016000000000000000000000000000000000000000000000000000000000014200d0000000000000000000000000000000000000000000000000000000000142017000000000000000000000000000000000000000000000000000000000014200e0000000000000000000000000000000000000000000000000000000000142018000000000000000000000000000000000000000000000000000000000014200f00000000000000000000000000000000000000000000000000000000001420190000000000000000000000000000000000000000000000000000000000142010000000000000000000000000000000000000000000000000000000000014201a0000000000000000000000000000000000000000000000000000000000142011000000000000000000000000000000000000000000000000000000000014201b0000000000000000000000000000000000000000000000000000000000142012000000000000000000000000000000000000000000000000000000000014201c0000000000000000000000000000000000000000000000000000000000142013000000000000000000000000000000000000000000000000000000000014201d0000000000000000000000000000000000000000000000000000000000142014000000000000000000000000000000000000000000000000000000000014201e0000000000000000000000000000000000000000000000000000000000142015000000000000000000000000000000000000000000000000000000000014201f00000000000000000000000000000000000000000000000000000000001420160000000000000000000000000000000000000000000000000000000000142020000000000000000000000000000000000000000000000000000000000014201700000000000000000000000000000000000000000000000000000000001420210000000000000000000000000000000000000000000000000000000000142018000000000000000000000000000000000000000000000000000000000014202200000000000000000000000000000000000000000000000000000000001420190000000000000000000000000000000000000000000000000000000000142023000000000000000000000000000000000000000000000000000000000014201a0000000000000000000000000000000000000000000000000000000000142024000000000000000000000000000000000000000000000000000000000014201b0000000000000000000000000000000000000000000000000000000000142025000000000000000000000000000000000000000000000000000000000014201c0000000000000000000000000000000000000000000000000000000000142026000000000000000000000000000000000000000000000000000000000014201d0000000000000000000000000000000000000000000000000000000000142027000000000000000000000000000000000000000000000000000000000014201e0000000000000000000000000000000000000000000000000000000000142028000000000000000000000000000000000000000000000000000000000014201f00000000000000000000000000000000000000000000000000000000001420290000000000000000000000000000000000000000000000000000000000142020000000000000000000000000000000000000000000000000000000000014202a0000000000000000000000000000000000000000000000000000000000142021000000000000000000000000000000000000000000000000000000000014202b0000000000000000000000000000000000000000000000000000000000142022000000000000000000000000000000000000000000000000000000000014202c0000000000000000000000000000000000000000000000000000000000142023000000000000000000000000000000000000000000000000000000000014202d0000000000000000000000000000000000000000000000000000000000142024000000000000000000000000000000000000000000000000000000000014202e0000000000000000000000000000000000000000000000000000000000142025000000000000000000000000000000000000000000000000000000000014202f00000000000000000000000000000000000000000000000000000000001420260000000000000000000000000000000000000000000000000000000000142030000000000000000000000000000000000000000000000000000000000014202700000000000000000000000000000000000000000000000000000000001420310000000000000000000000000000000000000000000000000000000000142028000000000000000000000000000000000000000000000000000000000014203200000000000000000000000000000000000000000000000000000000001420290000000000000000000000000000000000000000000000000000000000142033000000000000000000000000000000000000000000000000000000000014202a0000000000000000000000000000000000000000000000000000000000142034000000000000000000000000000000000000000000000000000000000014202b0000000000000000000000000000000000000000000000000000000000142035000000000000000000000000000000000000000000000000000000000014202c0000000000000000000000000000000000000000000000000000000000142036000000000000000000000000000000000000000000000000000000000014202d0000000000000000000000000000000000000000000000000000000000142037000000000000000000000000000000000000000000000000000000000014202e0000000000000000000000000000000000000000000000000000000000142038000000000000000000000000000000000000000000000000000000000014202f00000000000000000000000000000000000000000000000000000000001420390000000000000000000000000000000000000000000000000000000000142030000000000000000000000000000000000000000000000000000000000014203a0000000000000000000000000000000000000000000000000000000000142031000000000000000000000000000000000000000000000000000000000014203b0000000000000000000000000000000000000000000000000000000000142032000000000000000000000000000000000000000000000000000000000014203c0000000000000000000000000000000000000000000000000000000000142033000000000000000000000000000000000000000000000000000000000014203d0000000000000000000000000000000000000000000000000000000000142034000000000000000000000000000000000000000000000000000000000014203e0000000000000000000000000000000000000000000000000000000000142035000000000000000000000000000000000000000000000000000000000014203f00000000000000000000000000000000000000000000000000000000001420360000000000000000000000000000000000000000000000000000000000142040000000000000000000000000000000000000000000000000000000000014203700000000000000000000000000000000000000000000000000000000001420410000000000000000000000000000000000000000000000000000000000142038000000000000000000000000000000000000000000000000000000000014204200000000000000000000000000000000000000000000000000000000001420390000000000000000000000000000000000000000000000000000000000142043000000000000000000000000000000000000000000000000000000000014203a0000000000000000000000000000000000000000000000000000000000142044000000000000000000000000000000000000000000000000000000000014203b0000000000000000000000000000000000000000000000000000000000142045000000000000000000000000000000000000000000000000000000000014203c0000000000000000000000000000000000000000000000000000000000142046000000000000000000000000000000000000000000000000000000000014203d0000000000000000000000000000000000000000000000000000000000142047000000000000000000000000000000000000000000000000000000000014203e0000000000000000000000000000000000000000000000000000000000142048000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000181000000000000000000000000000000000000000000000000000000000000018100100000000000000000000000000000000000000000000000000000000001810020000000000000000000000000000000000000000000000000000000000181003000000000000000000000000000000000000000000000000000000000018100400000000000000000000000000000000000000000000000000000000001810050000000000000000000000000000000000000000000000000000000000181006000000000000000000000000000000000000000000000000000000000018100700000000000000000000000000000000000000000000000000000000001810080000000000000000000000000000000000000000000000000000000000181009000000000000000000000000000000000000000000000000000000000018100a000000000000000000000000000000000000000000000000000000000018100b000000000000000000000000000000000000000000000000000000000018100c000000000000000000000000000000000000000000000000000000000018100d000000000000000000000000000000000000000000000000000000000018100e000000000000000000000000000000000000000000000000000000000018100f0000000000000000000000000000000000000000000000000000000000181010000000000000000000000000000000000000000000000000000000000018101100000000000000000000000000000000000000000000000000000000001810120000000000000000000000000000000000000000000000000000000000181013000000000000000000000000000000000000000000000000000000000018101400000000000000000000000000000000000000000000000000000000001810150000000000000000000000000000000000000000000000000000000000181016000000000000000000000000000000000000000000000000000000000018101700000000000000000000000000000000000000000000000000000000001810180000000000000000000000000000000000000000000000000000000000181019000000000000000000000000000000000000000000000000000000000018101a000000000000000000000000000000000000000000000000000000000018101b000000000000000000000000000000000000000000000000000000000018101c000000000000000000000000000000000000000000000000000000000018101d000000000000000000000000000000000000000000000000000000000018101e000000000000000000000000000000000000000000000000000000000018101f0000000000000000000000000000000000000000000000000000000000181020000000000000000000000000000000000000000000000000000000000018102100000000000000000000000000000000000000000000000000000000001810220000000000000000000000000000000000000000000000000000000000181023000000000000000000000000000000000000000000000000000000000018102400000000000000000000000000000000000000000000000000000000001810250000000000000000000000000000000000000000000000000000000000181026000000000000000000000000000000000000000000000000000000000018102700000000000000000000000000000000000000000000000000000000001810280000000000000000000000000000000000000000000000000000000000181029000000000000000000000000000000000000000000000000000000000018102a000000000000000000000000000000000000000000000000000000000018102b000000000000000000000000000000000000000000000000000000000018102c000000000000000000000000000000000000000000000000000000000018102d000000000000000000000000000000000000000000000000000000000018102e000000000000000000000000000000000000000000000000000000000018102f0000000000000000000000000000000000000000000000000000000000181030000000000000000000000000000000000000000000000000000000000018103100000000000000000000000000000000000000000000000000000000001810320000000000000000000000000000000000000000000000000000000000181033000000000000000000000000000000000000000000000000000000000018103400000000000000000000000000000000000000000000000000000000001810350000000000000000000000000000000000000000000000000000000000181036000000000000000000000000000000000000000000000000000000000018103700000000000000000000000000000000000000000000000000000000001810380000000000000000000000000000000000000000000000000000000000181039000000000000000000000000000000000000000000000000000000000018103a000000000000000000000000000000000000000000000000000000000018103b000000000000000000000000000000000000000000000000000000000018103c000000000000000000000000000000000000000000000000000000000018103d000000000000000000000000000000000000000000000000000000000018103e000000000000000000000000000000000000000000000000000000000018103f3f0000000000000000000000000000000000000000000000000000000000181100000000000000000000000000000000000000000000000000000000000018110100000000000000000000000000000000000000000000000000000000001811020000000000000000000000000000000000000000000000000000000000181103000000000000000000000000000000000000000000000000000000000018110400000000000000000000000000000000000000000000000000000000001811050000000000000000000000000000000000000000000000000000000000181106000000000000000000000000000000000000000000000000000000000018110700000000000000000000000000000000000000000000000000000000001811080000000000000000000000000000000000000000000000000000000000181109000000000000000000000000000000000000000000000000000000000018110a000000000000000000000000000000000000000000000000000000000018110b000000000000000000000000000000000000000000000000000000000018110c000000000000000000000000000000000000000000000000000000000018110d000000000000000000000000000000000000000000000000000000000018110e000000000000000000000000000000000000000000000000000000000018110f0000000000000000000000000000000000000000000000000000000000181110000000000000000000000000000000000000000000000000000000000018111100000000000000000000000000000000000000000000000000000000001811120000000000000000000000000000000000000000000000000000000000181113000000000000000000000000000000000000000000000000000000000018111400000000000000000000000000000000000000000000000000000000001811150000000000000000000000000000000000000000000000000000000000181116000000000000000000000000000000000000000000000000000000000018111700000000000000000000000000000000000000000000000000000000001811180000000000000000000000000000000000000000000000000000000000181119000000000000000000000000000000000000000000000000000000000018111a000000000000000000000000000000000000000000000000000000000018111b000000000000000000000000000000000000000000000000000000000018111c000000000000000000000000000000000000000000000000000000000018111d000000000000000000000000000000000000000000000000000000000018111e000000000000000000000000000000000000000000000000000000000018111f0000000000000000000000000000000000000000000000000000000000181120000000000000000000000000000000000000000000000000000000000018112100000000000000000000000000000000000000000000000000000000001811220000000000000000000000000000000000000000000000000000000000181123000000000000000000000000000000000000000000000000000000000018112400000000000000000000000000000000000000000000000000000000001811250000000000000000000000000000000000000000000000000000000000181126000000000000000000000000000000000000000000000000000000000018112700000000000000000000000000000000000000000000000000000000001811280000000000000000000000000000000000000000000000000000000000181129000000000000000000000000000000000000000000000000000000000018112a000000000000000000000000000000000000000000000000000000000018112b000000000000000000000000000000000000000000000000000000000018112c000000000000000000000000000000000000000000000000000000000018112d000000000000000000000000000000000000000000000000000000000018112e000000000000000000000000000000000000000000000000000000000018112f0000000000000000000000000000000000000000000000000000000000181130000000000000000000000000000000000000000000000000000000000018113100000000000000000000000000000000000000000000000000000000001811320000000000000000000000000000000000000000000000000000000000181133000000000000000000000000000000000000000000000000000000000018113400000000000000000000000000000000000000000000000000000000001811350000000000000000000000000000000000000000000000000000000000181136000000000000000000000000000000000000000000000000000000000018113700000000000000000000000000000000000000000000000000000000001811380000000000000000000000000000000000000000000000000000000000181139000000000000000000000000000000000000000000000000000000000018113a000000000000000000000000000000000000000000000000000000000018113b000000000000000000000000000000000000000000000000000000000018113c000000000000000000000000000000000000000000000000000000000018113d000000000000000000000000000000000000000000000000000000000018113e0800f872eb9653f03af10f331da1361fa1524d3cd958cb72dacea1d424f19df3af00ffc548a17cd6ba1f2d228f30e4ddb19ecc46ad3b609977d52bb0f49e1206410032f8058bd779c520eabae2743b02ec4f71670428506fcceb2d4b69f26fb11800c0283e15fbf74ffa4eafb984030394f3c2ea6733cc0eacb0431a9475eff28f00b7f55314bfd9d441c1c624e241908228fe4da3d3a0a7fbd56814e1c8cd5d3e00f430f33a786675271736fd728c7bf7428b8c24ac948d7faf76ddb8783a496c0048fc235ead8d4b9d44929662a6384074fc4e5076bec5b7deb34f612393684300fd9b61cb1ad9b4b28f58399906e73933e3cccee8fc98a393f0eedb95b13ee63f0000000000000000000000000000000000000000000000000000000000182000000000000000000000000000000000000000000000000000000000000018200a0000000000000000000000000000000000000000000000000000000000182001000000000000000000000000000000000000000000000000000000000018200b0000000000000000000000000000000000000000000000000000000000182002000000000000000000000000000000000000000000000000000000000018200c0000000000000000000000000000000000000000000000000000000000182003000000000000000000000000000000000000000000000000000000000018200d0000000000000000000000000000000000000000000000000000000000182004000000000000000000000000000000000000000000000000000000000018200e0000000000000000000000000000000000000000000000000000000000182005000000000000000000000000000000000000000000000000000000000018200f00000000000000000000000000000000000000000000000000000000001820060000000000000000000000000000000000000000000000000000000000182010000000000000000000000000000000000000000000000000000000000018200700000000000000000000000000000000000000000000000000000000001820110000000000000000000000000000000000000000000000000000000000182008000000000000000000000000000000000000000000000000000000000018201200000000000000000000000000000000000000000000000000000000001820090000000000000000000000000000000000000000000000000000000000182013000000000000000000000000000000000000000000000000000000000018200a0000000000000000000000000000000000000000000000000000000000182014000000000000000000000000000000000000000000000000000000000018200b0000000000000000000000000000000000000000000000000000000000182015000000000000000000000000000000000000000000000000000000000018200c0000000000000000000000000000000000000000000000000000000000182016000000000000000000000000000000000000000000000000000000000018200d0000000000000000000000000000000000000000000000000000000000182017000000000000000000000000000000000000000000000000000000000018200e0000000000000000000000000000000000000000000000000000000000182018000000000000000000000000000000000000000000000000000000000018200f00000000000000000000000000000000000000000000000000000000001820190000000000000000000000000000000000000000000000000000000000182010000000000000000000000000000000000000000000000000000000000018201a0000000000000000000000000000000000000000000000000000000000182011000000000000000000000000000000000000000000000000000000000018201b0000000000000000000000000000000000000000000000000000000000182012000000000000000000000000000000000000000000000000000000000018201c0000000000000000000000000000000000000000000000000000000000182013000000000000000000000000000000000000000000000000000000000018201d0000000000000000000000000000000000000000000000000000000000182014000000000000000000000000000000000000000000000000000000000018201e0000000000000000000000000000000000000000000000000000000000182015000000000000000000000000000000000000000000000000000000000018201f00000000000000000000000000000000000000000000000000000000001820160000000000000000000000000000000000000000000000000000000000182020000000000000000000000000000000000000000000000000000000000018201700000000000000000000000000000000000000000000000000000000001820210000000000000000000000000000000000000000000000000000000000182018000000000000000000000000000000000000000000000000000000000018202200000000000000000000000000000000000000000000000000000000001820190000000000000000000000000000000000000000000000000000000000182023000000000000000000000000000000000000000000000000000000000018201a0000000000000000000000000000000000000000000000000000000000182024000000000000000000000000000000000000000000000000000000000018201b0000000000000000000000000000000000000000000000000000000000182025000000000000000000000000000000000000000000000000000000000018201c0000000000000000000000000000000000000000000000000000000000182026000000000000000000000000000000000000000000000000000000000018201d0000000000000000000000000000000000000000000000000000000000182027000000000000000000000000000000000000000000000000000000000018201e0000000000000000000000000000000000000000000000000000000000182028000000000000000000000000000000000000000000000000000000000018201f00000000000000000000000000000000000000000000000000000000001820290000000000000000000000000000000000000000000000000000000000182020000000000000000000000000000000000000000000000000000000000018202a0000000000000000000000000000000000000000000000000000000000182021000000000000000000000000000000000000000000000000000000000018202b0000000000000000000000000000000000000000000000000000000000182022000000000000000000000000000000000000000000000000000000000018202c0000000000000000000000000000000000000000000000000000000000182023000000000000000000000000000000000000000000000000000000000018202d0000000000000000000000000000000000000000000000000000000000182024000000000000000000000000000000000000000000000000000000000018202e0000000000000000000000000000000000000000000000000000000000182025000000000000000000000000000000000000000000000000000000000018202f00000000000000000000000000000000000000000000000000000000001820260000000000000000000000000000000000000000000000000000000000182030000000000000000000000000000000000000000000000000000000000018202700000000000000000000000000000000000000000000000000000000001820310000000000000000000000000000000000000000000000000000000000182028000000000000000000000000000000000000000000000000000000000018203200000000000000000000000000000000000000000000000000000000001820290000000000000000000000000000000000000000000000000000000000182033000000000000000000000000000000000000000000000000000000000018202a0000000000000000000000000000000000000000000000000000000000182034000000000000000000000000000000000000000000000000000000000018202b0000000000000000000000000000000000000000000000000000000000182035000000000000000000000000000000000000000000000000000000000018202c0000000000000000000000000000000000000000000000000000000000182036000000000000000000000000000000000000000000000000000000000018202d0000000000000000000000000000000000000000000000000000000000182037000000000000000000000000000000000000000000000000000000000018202e0000000000000000000000000000000000000000000000000000000000182038000000000000000000000000000000000000000000000000000000000018202f00000000000000000000000000000000000000000000000000000000001820390000000000000000000000000000000000000000000000000000000000182030000000000000000000000000000000000000000000000000000000000018203a0000000000000000000000000000000000000000000000000000000000182031000000000000000000000000000000000000000000000000000000000018203b0000000000000000000000000000000000000000000000000000000000182032000000000000000000000000000000000000000000000000000000000018203c0000000000000000000000000000000000000000000000000000000000182033000000000000000000000000000000000000000000000000000000000018203d0000000000000000000000000000000000000000000000000000000000182034000000000000000000000000000000000000000000000000000000000018203e0000000000000000000000000000000000000000000000000000000000182035000000000000000000000000000000000000000000000000000000000018203f00000000000000000000000000000000000000000000000000000000001820360000000000000000000000000000000000000000000000000000000000182040000000000000000000000000000000000000000000000000000000000018203700000000000000000000000000000000000000000000000000000000001820410000000000000000000000000000000000000000000000000000000000182038000000000000000000000000000000000000000000000000000000000018204200000000000000000000000000000000000000000000000000000000001820390000000000000000000000000000000000000000000000000000000000182043000000000000000000000000000000000000000000000000000000000018203a0000000000000000000000000000000000000000000000000000000000182044000000000000000000000000000000000000000000000000000000000018203b0000000000000000000000000000000000000000000000000000000000182045000000000000000000000000000000000000000000000000000000000018203c0000000000000000000000000000000000000000000000000000000000182046000000000000000000000000000000000000000000000000000000000018203d0000000000000000000000000000000000000000000000000000000000182047000000000000000000000000000000000000000000000000000000000018203e00000000000000000000000000000000000000000000000000000000001820480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c100100000000000000000000000000000000000000000000000000000000001c100200000000000000000000000000000000000000000000000000000000001c100300000000000000000000000000000000000000000000000000000000001c100400000000000000000000000000000000000000000000000000000000001c100500000000000000000000000000000000000000000000000000000000001c100600000000000000000000000000000000000000000000000000000000001c100700000000000000000000000000000000000000000000000000000000001c100800000000000000000000000000000000000000000000000000000000001c100900000000000000000000000000000000000000000000000000000000001c100a00000000000000000000000000000000000000000000000000000000001c100b00000000000000000000000000000000000000000000000000000000001c100c00000000000000000000000000000000000000000000000000000000001c100d00000000000000000000000000000000000000000000000000000000001c100e00000000000000000000000000000000000000000000000000000000001c100f00000000000000000000000000000000000000000000000000000000001c101000000000000000000000000000000000000000000000000000000000001c101100000000000000000000000000000000000000000000000000000000001c101200000000000000000000000000000000000000000000000000000000001c101300000000000000000000000000000000000000000000000000000000001c101400000000000000000000000000000000000000000000000000000000001c101500000000000000000000000000000000000000000000000000000000001c101600000000000000000000000000000000000000000000000000000000001c101700000000000000000000000000000000000000000000000000000000001c101800000000000000000000000000000000000000000000000000000000001c101900000000000000000000000000000000000000000000000000000000001c101a00000000000000000000000000000000000000000000000000000000001c101b00000000000000000000000000000000000000000000000000000000001c101c00000000000000000000000000000000000000000000000000000000001c101d00000000000000000000000000000000000000000000000000000000001c101e00000000000000000000000000000000000000000000000000000000001c101f00000000000000000000000000000000000000000000000000000000001c102000000000000000000000000000000000000000000000000000000000001c102100000000000000000000000000000000000000000000000000000000001c102200000000000000000000000000000000000000000000000000000000001c102300000000000000000000000000000000000000000000000000000000001c102400000000000000000000000000000000000000000000000000000000001c102500000000000000000000000000000000000000000000000000000000001c102600000000000000000000000000000000000000000000000000000000001c102700000000000000000000000000000000000000000000000000000000001c102800000000000000000000000000000000000000000000000000000000001c102900000000000000000000000000000000000000000000000000000000001c102a00000000000000000000000000000000000000000000000000000000001c102b00000000000000000000000000000000000000000000000000000000001c102c00000000000000000000000000000000000000000000000000000000001c102d00000000000000000000000000000000000000000000000000000000001c102e00000000000000000000000000000000000000000000000000000000001c102f00000000000000000000000000000000000000000000000000000000001c103000000000000000000000000000000000000000000000000000000000001c103100000000000000000000000000000000000000000000000000000000001c103200000000000000000000000000000000000000000000000000000000001c103300000000000000000000000000000000000000000000000000000000001c103400000000000000000000000000000000000000000000000000000000001c103500000000000000000000000000000000000000000000000000000000001c103600000000000000000000000000000000000000000000000000000000001c103700000000000000000000000000000000000000000000000000000000001c103800000000000000000000000000000000000000000000000000000000001c103900000000000000000000000000000000000000000000000000000000001c103a00000000000000000000000000000000000000000000000000000000001c103b00000000000000000000000000000000000000000000000000000000001c103c00000000000000000000000000000000000000000000000000000000001c103d00000000000000000000000000000000000000000000000000000000001c103e00000000000000000000000000000000000000000000000000000000001c103f3f00000000000000000000000000000000000000000000000000000000001c110000000000000000000000000000000000000000000000000000000000001c110100000000000000000000000000000000000000000000000000000000001c110200000000000000000000000000000000000000000000000000000000001c110300000000000000000000000000000000000000000000000000000000001c110400000000000000000000000000000000000000000000000000000000001c110500000000000000000000000000000000000000000000000000000000001c110600000000000000000000000000000000000000000000000000000000001c110700000000000000000000000000000000000000000000000000000000001c110800000000000000000000000000000000000000000000000000000000001c110900000000000000000000000000000000000000000000000000000000001c110a00000000000000000000000000000000000000000000000000000000001c110b00000000000000000000000000000000000000000000000000000000001c110c00000000000000000000000000000000000000000000000000000000001c110d00000000000000000000000000000000000000000000000000000000001c110e00000000000000000000000000000000000000000000000000000000001c110f00000000000000000000000000000000000000000000000000000000001c111000000000000000000000000000000000000000000000000000000000001c111100000000000000000000000000000000000000000000000000000000001c111200000000000000000000000000000000000000000000000000000000001c111300000000000000000000000000000000000000000000000000000000001c111400000000000000000000000000000000000000000000000000000000001c111500000000000000000000000000000000000000000000000000000000001c111600000000000000000000000000000000000000000000000000000000001c111700000000000000000000000000000000000000000000000000000000001c111800000000000000000000000000000000000000000000000000000000001c111900000000000000000000000000000000000000000000000000000000001c111a00000000000000000000000000000000000000000000000000000000001c111b00000000000000000000000000000000000000000000000000000000001c111c00000000000000000000000000000000000000000000000000000000001c111d00000000000000000000000000000000000000000000000000000000001c111e00000000000000000000000000000000000000000000000000000000001c111f00000000000000000000000000000000000000000000000000000000001c112000000000000000000000000000000000000000000000000000000000001c112100000000000000000000000000000000000000000000000000000000001c112200000000000000000000000000000000000000000000000000000000001c112300000000000000000000000000000000000000000000000000000000001c112400000000000000000000000000000000000000000000000000000000001c112500000000000000000000000000000000000000000000000000000000001c112600000000000000000000000000000000000000000000000000000000001c112700000000000000000000000000000000000000000000000000000000001c112800000000000000000000000000000000000000000000000000000000001c112900000000000000000000000000000000000000000000000000000000001c112a00000000000000000000000000000000000000000000000000000000001c112b00000000000000000000000000000000000000000000000000000000001c112c00000000000000000000000000000000000000000000000000000000001c112d00000000000000000000000000000000000000000000000000000000001c112e00000000000000000000000000000000000000000000000000000000001c112f00000000000000000000000000000000000000000000000000000000001c113000000000000000000000000000000000000000000000000000000000001c113100000000000000000000000000000000000000000000000000000000001c113200000000000000000000000000000000000000000000000000000000001c113300000000000000000000000000000000000000000000000000000000001c113400000000000000000000000000000000000000000000000000000000001c113500000000000000000000000000000000000000000000000000000000001c113600000000000000000000000000000000000000000000000000000000001c113700000000000000000000000000000000000000000000000000000000001c113800000000000000000000000000000000000000000000000000000000001c113900000000000000000000000000000000000000000000000000000000001c113a00000000000000000000000000000000000000000000000000000000001c113b00000000000000000000000000000000000000000000000000000000001c113c00000000000000000000000000000000000000000000000000000000001c113d00000000000000000000000000000000000000000000000000000000001c113e08006838aa99533bea0d4204cad17cb3c147e99c2f9089e54a4289d54733eeada2002ab314bd11ace2494a3fb0970d276da39f0fe7da19c9a2438b9c7c334d32470071703d79d8425a7eca52006df6a8f9728508a83639e3e1c2ebae2b853a087c00c9501ac04a78ac5413c9131b08708064ed2c2515b8893f12c2d1cda15a44f100a0955f93e109778d26f9e5b0d46e45c539e59b0941517bfa888eb2d7d2d8a6005adc3be9406cc5f102c6adb44746e8529a256e2396353a8659344cc3e914c4007a5fe572cf6af804f472dabf095c5eb6b30efc5fd627ad3245a8ef0f3f578c003dcaa91dfc9fdad7ba8da68a48fc662dfc0a995cbb0c1bc62099c8257d240d3f00000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c200a00000000000000000000000000000000000000000000000000000000001c200100000000000000000000000000000000000000000000000000000000001c200b00000000000000000000000000000000000000000000000000000000001c200200000000000000000000000000000000000000000000000000000000001c200c00000000000000000000000000000000000000000000000000000000001c200300000000000000000000000000000000000000000000000000000000001c200d00000000000000000000000000000000000000000000000000000000001c200400000000000000000000000000000000000000000000000000000000001c200e00000000000000000000000000000000000000000000000000000000001c200500000000000000000000000000000000000000000000000000000000001c200f00000000000000000000000000000000000000000000000000000000001c200600000000000000000000000000000000000000000000000000000000001c201000000000000000000000000000000000000000000000000000000000001c200700000000000000000000000000000000000000000000000000000000001c201100000000000000000000000000000000000000000000000000000000001c200800000000000000000000000000000000000000000000000000000000001c201200000000000000000000000000000000000000000000000000000000001c200900000000000000000000000000000000000000000000000000000000001c201300000000000000000000000000000000000000000000000000000000001c200a00000000000000000000000000000000000000000000000000000000001c201400000000000000000000000000000000000000000000000000000000001c200b00000000000000000000000000000000000000000000000000000000001c201500000000000000000000000000000000000000000000000000000000001c200c00000000000000000000000000000000000000000000000000000000001c201600000000000000000000000000000000000000000000000000000000001c200d00000000000000000000000000000000000000000000000000000000001c201700000000000000000000000000000000000000000000000000000000001c200e00000000000000000000000000000000000000000000000000000000001c201800000000000000000000000000000000000000000000000000000000001c200f00000000000000000000000000000000000000000000000000000000001c201900000000000000000000000000000000000000000000000000000000001c201000000000000000000000000000000000000000000000000000000000001c201a00000000000000000000000000000000000000000000000000000000001c201100000000000000000000000000000000000000000000000000000000001c201b00000000000000000000000000000000000000000000000000000000001c201200000000000000000000000000000000000000000000000000000000001c201c00000000000000000000000000000000000000000000000000000000001c201300000000000000000000000000000000000000000000000000000000001c201d00000000000000000000000000000000000000000000000000000000001c201400000000000000000000000000000000000000000000000000000000001c201e00000000000000000000000000000000000000000000000000000000001c201500000000000000000000000000000000000000000000000000000000001c201f00000000000000000000000000000000000000000000000000000000001c201600000000000000000000000000000000000000000000000000000000001c202000000000000000000000000000000000000000000000000000000000001c201700000000000000000000000000000000000000000000000000000000001c202100000000000000000000000000000000000000000000000000000000001c201800000000000000000000000000000000000000000000000000000000001c202200000000000000000000000000000000000000000000000000000000001c201900000000000000000000000000000000000000000000000000000000001c202300000000000000000000000000000000000000000000000000000000001c201a00000000000000000000000000000000000000000000000000000000001c202400000000000000000000000000000000000000000000000000000000001c201b00000000000000000000000000000000000000000000000000000000001c202500000000000000000000000000000000000000000000000000000000001c201c00000000000000000000000000000000000000000000000000000000001c202600000000000000000000000000000000000000000000000000000000001c201d00000000000000000000000000000000000000000000000000000000001c202700000000000000000000000000000000000000000000000000000000001c201e00000000000000000000000000000000000000000000000000000000001c202800000000000000000000000000000000000000000000000000000000001c201f00000000000000000000000000000000000000000000000000000000001c202900000000000000000000000000000000000000000000000000000000001c202000000000000000000000000000000000000000000000000000000000001c202a00000000000000000000000000000000000000000000000000000000001c202100000000000000000000000000000000000000000000000000000000001c202b00000000000000000000000000000000000000000000000000000000001c202200000000000000000000000000000000000000000000000000000000001c202c00000000000000000000000000000000000000000000000000000000001c202300000000000000000000000000000000000000000000000000000000001c202d00000000000000000000000000000000000000000000000000000000001c202400000000000000000000000000000000000000000000000000000000001c202e00000000000000000000000000000000000000000000000000000000001c202500000000000000000000000000000000000000000000000000000000001c202f00000000000000000000000000000000000000000000000000000000001c202600000000000000000000000000000000000000000000000000000000001c203000000000000000000000000000000000000000000000000000000000001c202700000000000000000000000000000000000000000000000000000000001c203100000000000000000000000000000000000000000000000000000000001c202800000000000000000000000000000000000000000000000000000000001c203200000000000000000000000000000000000000000000000000000000001c202900000000000000000000000000000000000000000000000000000000001c203300000000000000000000000000000000000000000000000000000000001c202a00000000000000000000000000000000000000000000000000000000001c203400000000000000000000000000000000000000000000000000000000001c202b00000000000000000000000000000000000000000000000000000000001c203500000000000000000000000000000000000000000000000000000000001c202c00000000000000000000000000000000000000000000000000000000001c203600000000000000000000000000000000000000000000000000000000001c202d00000000000000000000000000000000000000000000000000000000001c203700000000000000000000000000000000000000000000000000000000001c202e00000000000000000000000000000000000000000000000000000000001c203800000000000000000000000000000000000000000000000000000000001c202f00000000000000000000000000000000000000000000000000000000001c203900000000000000000000000000000000000000000000000000000000001c203000000000000000000000000000000000000000000000000000000000001c203a00000000000000000000000000000000000000000000000000000000001c203100000000000000000000000000000000000000000000000000000000001c203b00000000000000000000000000000000000000000000000000000000001c203200000000000000000000000000000000000000000000000000000000001c203c00000000000000000000000000000000000000000000000000000000001c203300000000000000000000000000000000000000000000000000000000001c203d00000000000000000000000000000000000000000000000000000000001c203400000000000000000000000000000000000000000000000000000000001c203e00000000000000000000000000000000000000000000000000000000001c203500000000000000000000000000000000000000000000000000000000001c203f00000000000000000000000000000000000000000000000000000000001c203600000000000000000000000000000000000000000000000000000000001c204000000000000000000000000000000000000000000000000000000000001c203700000000000000000000000000000000000000000000000000000000001c204100000000000000000000000000000000000000000000000000000000001c203800000000000000000000000000000000000000000000000000000000001c204200000000000000000000000000000000000000000000000000000000001c203900000000000000000000000000000000000000000000000000000000001c204300000000000000000000000000000000000000000000000000000000001c203a00000000000000000000000000000000000000000000000000000000001c204400000000000000000000000000000000000000000000000000000000001c203b00000000000000000000000000000000000000000000000000000000001c204500000000000000000000000000000000000000000000000000000000001c203c00000000000000000000000000000000000000000000000000000000001c204600000000000000000000000000000000000000000000000000000000001c203d00000000000000000000000000000000000000000000000000000000001c204700000000000000000000000000000000000000000000000000000000001c203e00000000000000000000000000000000000000000000000000000000001c2048000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000201000000000000000000000000000000000000000000000000000000000000020100100000000000000000000000000000000000000000000000000000000002010020000000000000000000000000000000000000000000000000000000000201003000000000000000000000000000000000000000000000000000000000020100400000000000000000000000000000000000000000000000000000000002010050000000000000000000000000000000000000000000000000000000000201006000000000000000000000000000000000000000000000000000000000020100700000000000000000000000000000000000000000000000000000000002010080000000000000000000000000000000000000000000000000000000000201009000000000000000000000000000000000000000000000000000000000020100a000000000000000000000000000000000000000000000000000000000020100b000000000000000000000000000000000000000000000000000000000020100c000000000000000000000000000000000000000000000000000000000020100d000000000000000000000000000000000000000000000000000000000020100e000000000000000000000000000000000000000000000000000000000020100f0000000000000000000000000000000000000000000000000000000000201010000000000000000000000000000000000000000000000000000000000020101100000000000000000000000000000000000000000000000000000000002010120000000000000000000000000000000000000000000000000000000000201013000000000000000000000000000000000000000000000000000000000020101400000000000000000000000000000000000000000000000000000000002010150000000000000000000000000000000000000000000000000000000000201016000000000000000000000000000000000000000000000000000000000020101700000000000000000000000000000000000000000000000000000000002010180000000000000000000000000000000000000000000000000000000000201019000000000000000000000000000000000000000000000000000000000020101a000000000000000000000000000000000000000000000000000000000020101b000000000000000000000000000000000000000000000000000000000020101c000000000000000000000000000000000000000000000000000000000020101d000000000000000000000000000000000000000000000000000000000020101e000000000000000000000000000000000000000000000000000000000020101f0000000000000000000000000000000000000000000000000000000000201020000000000000000000000000000000000000000000000000000000000020102100000000000000000000000000000000000000000000000000000000002010220000000000000000000000000000000000000000000000000000000000201023000000000000000000000000000000000000000000000000000000000020102400000000000000000000000000000000000000000000000000000000002010250000000000000000000000000000000000000000000000000000000000201026000000000000000000000000000000000000000000000000000000000020102700000000000000000000000000000000000000000000000000000000002010280000000000000000000000000000000000000000000000000000000000201029000000000000000000000000000000000000000000000000000000000020102a000000000000000000000000000000000000000000000000000000000020102b000000000000000000000000000000000000000000000000000000000020102c000000000000000000000000000000000000000000000000000000000020102d000000000000000000000000000000000000000000000000000000000020102e000000000000000000000000000000000000000000000000000000000020102f0000000000000000000000000000000000000000000000000000000000201030000000000000000000000000000000000000000000000000000000000020103100000000000000000000000000000000000000000000000000000000002010320000000000000000000000000000000000000000000000000000000000201033000000000000000000000000000000000000000000000000000000000020103400000000000000000000000000000000000000000000000000000000002010350000000000000000000000000000000000000000000000000000000000201036000000000000000000000000000000000000000000000000000000000020103700000000000000000000000000000000000000000000000000000000002010380000000000000000000000000000000000000000000000000000000000201039000000000000000000000000000000000000000000000000000000000020103a000000000000000000000000000000000000000000000000000000000020103b000000000000000000000000000000000000000000000000000000000020103c000000000000000000000000000000000000000000000000000000000020103d000000000000000000000000000000000000000000000000000000000020103e000000000000000000000000000000000000000000000000000000000020103f3f0000000000000000000000000000000000000000000000000000000000201100000000000000000000000000000000000000000000000000000000000020110100000000000000000000000000000000000000000000000000000000002011020000000000000000000000000000000000000000000000000000000000201103000000000000000000000000000000000000000000000000000000000020110400000000000000000000000000000000000000000000000000000000002011050000000000000000000000000000000000000000000000000000000000201106000000000000000000000000000000000000000000000000000000000020110700000000000000000000000000000000000000000000000000000000002011080000000000000000000000000000000000000000000000000000000000201109000000000000000000000000000000000000000000000000000000000020110a000000000000000000000000000000000000000000000000000000000020110b000000000000000000000000000000000000000000000000000000000020110c000000000000000000000000000000000000000000000000000000000020110d000000000000000000000000000000000000000000000000000000000020110e000000000000000000000000000000000000000000000000000000000020110f0000000000000000000000000000000000000000000000000000000000201110000000000000000000000000000000000000000000000000000000000020111100000000000000000000000000000000000000000000000000000000002011120000000000000000000000000000000000000000000000000000000000201113000000000000000000000000000000000000000000000000000000000020111400000000000000000000000000000000000000000000000000000000002011150000000000000000000000000000000000000000000000000000000000201116000000000000000000000000000000000000000000000000000000000020111700000000000000000000000000000000000000000000000000000000002011180000000000000000000000000000000000000000000000000000000000201119000000000000000000000000000000000000000000000000000000000020111a000000000000000000000000000000000000000000000000000000000020111b000000000000000000000000000000000000000000000000000000000020111c000000000000000000000000000000000000000000000000000000000020111d000000000000000000000000000000000000000000000000000000000020111e000000000000000000000000000000000000000000000000000000000020111f0000000000000000000000000000000000000000000000000000000000201120000000000000000000000000000000000000000000000000000000000020112100000000000000000000000000000000000000000000000000000000002011220000000000000000000000000000000000000000000000000000000000201123000000000000000000000000000000000000000000000000000000000020112400000000000000000000000000000000000000000000000000000000002011250000000000000000000000000000000000000000000000000000000000201126000000000000000000000000000000000000000000000000000000000020112700000000000000000000000000000000000000000000000000000000002011280000000000000000000000000000000000000000000000000000000000201129000000000000000000000000000000000000000000000000000000000020112a000000000000000000000000000000000000000000000000000000000020112b000000000000000000000000000000000000000000000000000000000020112c000000000000000000000000000000000000000000000000000000000020112d000000000000000000000000000000000000000000000000000000000020112e000000000000000000000000000000000000000000000000000000000020112f0000000000000000000000000000000000000000000000000000000000201130000000000000000000000000000000000000000000000000000000000020113100000000000000000000000000000000000000000000000000000000002011320000000000000000000000000000000000000000000000000000000000201133000000000000000000000000000000000000000000000000000000000020113400000000000000000000000000000000000000000000000000000000002011350000000000000000000000000000000000000000000000000000000000201136000000000000000000000000000000000000000000000000000000000020113700000000000000000000000000000000000000000000000000000000002011380000000000000000000000000000000000000000000000000000000000201139000000000000000000000000000000000000000000000000000000000020113a000000000000000000000000000000000000000000000000000000000020113b000000000000000000000000000000000000000000000000000000000020113c000000000000000000000000000000000000000000000000000000000020113d000000000000000000000000000000000000000000000000000000000020113e0800e9805e8a4faa87fc419af08a6d956f18976c46ea694bbd4cf6946e6d02033200e0925a6b172b4b01bb76eb1d3f7dd2ced118bca70d223a6d61afa1b75915ae00383590492d2f99a0283d1de57015b4b6b0759a8023af2c68fb4929dee2f303007ed57100dd77e2b6405f780503ef61b7b53e13f344b6e6a6eff3e3c13de0d0001ab1b0c348c46184dbc86ff79f248e7da1b09d3f9c6a986e98fe45389f060d0023d134bc68d7efa25e255001069827dc0bee766c08c988d6300071ed27fe6c0031cbb780b07f632cbaf767dc80608cc0a8e1d1df3ecd6f5d8bc0ca6703e4f4002c7dc9e731fc5f6456b2a70b4e636ac17d5e0cd36d3a591116a9e124f735863f0000000000000000000000000000000000000000000000000000000000202000000000000000000000000000000000000000000000000000000000000020200a0000000000000000000000000000000000000000000000000000000000202001000000000000000000000000000000000000000000000000000000000020200b0000000000000000000000000000000000000000000000000000000000202002000000000000000000000000000000000000000000000000000000000020200c0000000000000000000000000000000000000000000000000000000000202003000000000000000000000000000000000000000000000000000000000020200d0000000000000000000000000000000000000000000000000000000000202004000000000000000000000000000000000000000000000000000000000020200e0000000000000000000000000000000000000000000000000000000000202005000000000000000000000000000000000000000000000000000000000020200f00000000000000000000000000000000000000000000000000000000002020060000000000000000000000000000000000000000000000000000000000202010000000000000000000000000000000000000000000000000000000000020200700000000000000000000000000000000000000000000000000000000002020110000000000000000000000000000000000000000000000000000000000202008000000000000000000000000000000000000000000000000000000000020201200000000000000000000000000000000000000000000000000000000002020090000000000000000000000000000000000000000000000000000000000202013000000000000000000000000000000000000000000000000000000000020200a0000000000000000000000000000000000000000000000000000000000202014000000000000000000000000000000000000000000000000000000000020200b0000000000000000000000000000000000000000000000000000000000202015000000000000000000000000000000000000000000000000000000000020200c0000000000000000000000000000000000000000000000000000000000202016000000000000000000000000000000000000000000000000000000000020200d0000000000000000000000000000000000000000000000000000000000202017000000000000000000000000000000000000000000000000000000000020200e0000000000000000000000000000000000000000000000000000000000202018000000000000000000000000000000000000000000000000000000000020200f00000000000000000000000000000000000000000000000000000000002020190000000000000000000000000000000000000000000000000000000000202010000000000000000000000000000000000000000000000000000000000020201a0000000000000000000000000000000000000000000000000000000000202011000000000000000000000000000000000000000000000000000000000020201b0000000000000000000000000000000000000000000000000000000000202012000000000000000000000000000000000000000000000000000000000020201c0000000000000000000000000000000000000000000000000000000000202013000000000000000000000000000000000000000000000000000000000020201d0000000000000000000000000000000000000000000000000000000000202014000000000000000000000000000000000000000000000000000000000020201e0000000000000000000000000000000000000000000000000000000000202015000000000000000000000000000000000000000000000000000000000020201f00000000000000000000000000000000000000000000000000000000002020160000000000000000000000000000000000000000000000000000000000202020000000000000000000000000000000000000000000000000000000000020201700000000000000000000000000000000000000000000000000000000002020210000000000000000000000000000000000000000000000000000000000202018000000000000000000000000000000000000000000000000000000000020202200000000000000000000000000000000000000000000000000000000002020190000000000000000000000000000000000000000000000000000000000202023000000000000000000000000000000000000000000000000000000000020201a0000000000000000000000000000000000000000000000000000000000202024000000000000000000000000000000000000000000000000000000000020201b0000000000000000000000000000000000000000000000000000000000202025000000000000000000000000000000000000000000000000000000000020201c0000000000000000000000000000000000000000000000000000000000202026000000000000000000000000000000000000000000000000000000000020201d0000000000000000000000000000000000000000000000000000000000202027000000000000000000000000000000000000000000000000000000000020201e0000000000000000000000000000000000000000000000000000000000202028000000000000000000000000000000000000000000000000000000000020201f00000000000000000000000000000000000000000000000000000000002020290000000000000000000000000000000000000000000000000000000000202020000000000000000000000000000000000000000000000000000000000020202a0000000000000000000000000000000000000000000000000000000000202021000000000000000000000000000000000000000000000000000000000020202b0000000000000000000000000000000000000000000000000000000000202022000000000000000000000000000000000000000000000000000000000020202c0000000000000000000000000000000000000000000000000000000000202023000000000000000000000000000000000000000000000000000000000020202d0000000000000000000000000000000000000000000000000000000000202024000000000000000000000000000000000000000000000000000000000020202e0000000000000000000000000000000000000000000000000000000000202025000000000000000000000000000000000000000000000000000000000020202f00000000000000000000000000000000000000000000000000000000002020260000000000000000000000000000000000000000000000000000000000202030000000000000000000000000000000000000000000000000000000000020202700000000000000000000000000000000000000000000000000000000002020310000000000000000000000000000000000000000000000000000000000202028000000000000000000000000000000000000000000000000000000000020203200000000000000000000000000000000000000000000000000000000002020290000000000000000000000000000000000000000000000000000000000202033000000000000000000000000000000000000000000000000000000000020202a0000000000000000000000000000000000000000000000000000000000202034000000000000000000000000000000000000000000000000000000000020202b0000000000000000000000000000000000000000000000000000000000202035000000000000000000000000000000000000000000000000000000000020202c0000000000000000000000000000000000000000000000000000000000202036000000000000000000000000000000000000000000000000000000000020202d0000000000000000000000000000000000000000000000000000000000202037000000000000000000000000000000000000000000000000000000000020202e0000000000000000000000000000000000000000000000000000000000202038000000000000000000000000000000000000000000000000000000000020202f00000000000000000000000000000000000000000000000000000000002020390000000000000000000000000000000000000000000000000000000000202030000000000000000000000000000000000000000000000000000000000020203a0000000000000000000000000000000000000000000000000000000000202031000000000000000000000000000000000000000000000000000000000020203b0000000000000000000000000000000000000000000000000000000000202032000000000000000000000000000000000000000000000000000000000020203c0000000000000000000000000000000000000000000000000000000000202033000000000000000000000000000000000000000000000000000000000020203d0000000000000000000000000000000000000000000000000000000000202034000000000000000000000000000000000000000000000000000000000020203e0000000000000000000000000000000000000000000000000000000000202035000000000000000000000000000000000000000000000000000000000020203f00000000000000000000000000000000000000000000000000000000002020360000000000000000000000000000000000000000000000000000000000202040000000000000000000000000000000000000000000000000000000000020203700000000000000000000000000000000000000000000000000000000002020410000000000000000000000000000000000000000000000000000000000202038000000000000000000000000000000000000000000000000000000000020204200000000000000000000000000000000000000000000000000000000002020390000000000000000000000000000000000000000000000000000000000202043000000000000000000000000000000000000000000000000000000000020203a0000000000000000000000000000000000000000000000000000000000202044000000000000000000000000000000000000000000000000000000000020203b0000000000000000000000000000000000000000000000000000000000202045000000000000000000000000000000000000000000000000000000000020203c0000000000000000000000000000000000000000000000000000000000202046000000000000000000000000000000000000000000000000000000000020203d0000000000000000000000000000000000000000000000000000000000202047000000000000000000000000000000000000000000000000000000000020203e0000000000000000000000000000000000000000000000000000000000202048000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "txsEffectsHash": "0x00e0afd1e2cddfe35e364bde6047d93fec56b54e7b925edc28b31546b645822d", + "archive": "0x05d151154c5fc1ff94e0cf57a45bd86df6e0555b7e0e7741eee40a3b2d0dcaf1", + "blockHash": "0x22b5ab33961e9aa80ad6dd79558ef6ae56e4eb0afb9d361155c95fd3455f4065", + "body": "0x00000004000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000141000000000000000000000000000000000000000000000000000000000000014100100000000000000000000000000000000000000000000000000000000001410020000000000000000000000000000000000000000000000000000000000141003000000000000000000000000000000000000000000000000000000000014100400000000000000000000000000000000000000000000000000000000001410050000000000000000000000000000000000000000000000000000000000141006000000000000000000000000000000000000000000000000000000000014100700000000000000000000000000000000000000000000000000000000001410080000000000000000000000000000000000000000000000000000000000141009000000000000000000000000000000000000000000000000000000000014100a000000000000000000000000000000000000000000000000000000000014100b000000000000000000000000000000000000000000000000000000000014100c000000000000000000000000000000000000000000000000000000000014100d000000000000000000000000000000000000000000000000000000000014100e000000000000000000000000000000000000000000000000000000000014100f0000000000000000000000000000000000000000000000000000000000141010000000000000000000000000000000000000000000000000000000000014101100000000000000000000000000000000000000000000000000000000001410120000000000000000000000000000000000000000000000000000000000141013000000000000000000000000000000000000000000000000000000000014101400000000000000000000000000000000000000000000000000000000001410150000000000000000000000000000000000000000000000000000000000141016000000000000000000000000000000000000000000000000000000000014101700000000000000000000000000000000000000000000000000000000001410180000000000000000000000000000000000000000000000000000000000141019000000000000000000000000000000000000000000000000000000000014101a000000000000000000000000000000000000000000000000000000000014101b000000000000000000000000000000000000000000000000000000000014101c000000000000000000000000000000000000000000000000000000000014101d000000000000000000000000000000000000000000000000000000000014101e000000000000000000000000000000000000000000000000000000000014101f0000000000000000000000000000000000000000000000000000000000141020000000000000000000000000000000000000000000000000000000000014102100000000000000000000000000000000000000000000000000000000001410220000000000000000000000000000000000000000000000000000000000141023000000000000000000000000000000000000000000000000000000000014102400000000000000000000000000000000000000000000000000000000001410250000000000000000000000000000000000000000000000000000000000141026000000000000000000000000000000000000000000000000000000000014102700000000000000000000000000000000000000000000000000000000001410280000000000000000000000000000000000000000000000000000000000141029000000000000000000000000000000000000000000000000000000000014102a000000000000000000000000000000000000000000000000000000000014102b000000000000000000000000000000000000000000000000000000000014102c000000000000000000000000000000000000000000000000000000000014102d000000000000000000000000000000000000000000000000000000000014102e000000000000000000000000000000000000000000000000000000000014102f0000000000000000000000000000000000000000000000000000000000141030000000000000000000000000000000000000000000000000000000000014103100000000000000000000000000000000000000000000000000000000001410320000000000000000000000000000000000000000000000000000000000141033000000000000000000000000000000000000000000000000000000000014103400000000000000000000000000000000000000000000000000000000001410350000000000000000000000000000000000000000000000000000000000141036000000000000000000000000000000000000000000000000000000000014103700000000000000000000000000000000000000000000000000000000001410380000000000000000000000000000000000000000000000000000000000141039000000000000000000000000000000000000000000000000000000000014103a000000000000000000000000000000000000000000000000000000000014103b000000000000000000000000000000000000000000000000000000000014103c000000000000000000000000000000000000000000000000000000000014103d000000000000000000000000000000000000000000000000000000000014103e000000000000000000000000000000000000000000000000000000000014103f4000000000000000000000000000000000000000000000000000000000001400010000000000000000000000000000000000000000000000000000000000141100000000000000000000000000000000000000000000000000000000000014110100000000000000000000000000000000000000000000000000000000001411020000000000000000000000000000000000000000000000000000000000141103000000000000000000000000000000000000000000000000000000000014110400000000000000000000000000000000000000000000000000000000001411050000000000000000000000000000000000000000000000000000000000141106000000000000000000000000000000000000000000000000000000000014110700000000000000000000000000000000000000000000000000000000001411080000000000000000000000000000000000000000000000000000000000141109000000000000000000000000000000000000000000000000000000000014110a000000000000000000000000000000000000000000000000000000000014110b000000000000000000000000000000000000000000000000000000000014110c000000000000000000000000000000000000000000000000000000000014110d000000000000000000000000000000000000000000000000000000000014110e000000000000000000000000000000000000000000000000000000000014110f0000000000000000000000000000000000000000000000000000000000141110000000000000000000000000000000000000000000000000000000000014111100000000000000000000000000000000000000000000000000000000001411120000000000000000000000000000000000000000000000000000000000141113000000000000000000000000000000000000000000000000000000000014111400000000000000000000000000000000000000000000000000000000001411150000000000000000000000000000000000000000000000000000000000141116000000000000000000000000000000000000000000000000000000000014111700000000000000000000000000000000000000000000000000000000001411180000000000000000000000000000000000000000000000000000000000141119000000000000000000000000000000000000000000000000000000000014111a000000000000000000000000000000000000000000000000000000000014111b000000000000000000000000000000000000000000000000000000000014111c000000000000000000000000000000000000000000000000000000000014111d000000000000000000000000000000000000000000000000000000000014111e000000000000000000000000000000000000000000000000000000000014111f0000000000000000000000000000000000000000000000000000000000141120000000000000000000000000000000000000000000000000000000000014112100000000000000000000000000000000000000000000000000000000001411220000000000000000000000000000000000000000000000000000000000141123000000000000000000000000000000000000000000000000000000000014112400000000000000000000000000000000000000000000000000000000001411250000000000000000000000000000000000000000000000000000000000141126000000000000000000000000000000000000000000000000000000000014112700000000000000000000000000000000000000000000000000000000001411280000000000000000000000000000000000000000000000000000000000141129000000000000000000000000000000000000000000000000000000000014112a000000000000000000000000000000000000000000000000000000000014112b000000000000000000000000000000000000000000000000000000000014112c000000000000000000000000000000000000000000000000000000000014112d000000000000000000000000000000000000000000000000000000000014112e000000000000000000000000000000000000000000000000000000000014112f0000000000000000000000000000000000000000000000000000000000141130000000000000000000000000000000000000000000000000000000000014113100000000000000000000000000000000000000000000000000000000001411320000000000000000000000000000000000000000000000000000000000141133000000000000000000000000000000000000000000000000000000000014113400000000000000000000000000000000000000000000000000000000001411350000000000000000000000000000000000000000000000000000000000141136000000000000000000000000000000000000000000000000000000000014113700000000000000000000000000000000000000000000000000000000001411380000000000000000000000000000000000000000000000000000000000141139000000000000000000000000000000000000000000000000000000000014113a000000000000000000000000000000000000000000000000000000000014113b000000000000000000000000000000000000000000000000000000000014113c000000000000000000000000000000000000000000000000000000000014113d000000000000000000000000000000000000000000000000000000000014113e08005c015113cb57d67dd6c0febd596819ac0298b6a23fc80aba17d445d540059a00f20b7d1308051fe7b68031a7c336b0b4b56738928b6510133aff1b818d5a9a0063eec1883a4f95f4933f9275e850d84b3d035f5061ed986c437a07331fd30e00d3a32d6bbc4fd843686fd0c5e118a73b847529977dca5b9e0e81f6604f22ca00c2f4f5133d9194d41e853e5e951e16690babce8461f25342c0bad20f2aa1e3000a6bf4739e7eb387913d955dc2e8f14f8cce27696b9d2e128b6acefafb80ee005763f7e0648f958b559677622a648f318fc79ebc0cb539170d49c26456e69200302e2b8a92cda941e9af8761b89899a58a587656d9710594e1d865b16522993f0000000000000000000000000000000000000000000000000000000000142000000000000000000000000000000000000000000000000000000000000014200a0000000000000000000000000000000000000000000000000000000000142001000000000000000000000000000000000000000000000000000000000014200b0000000000000000000000000000000000000000000000000000000000142002000000000000000000000000000000000000000000000000000000000014200c0000000000000000000000000000000000000000000000000000000000142003000000000000000000000000000000000000000000000000000000000014200d0000000000000000000000000000000000000000000000000000000000142004000000000000000000000000000000000000000000000000000000000014200e0000000000000000000000000000000000000000000000000000000000142005000000000000000000000000000000000000000000000000000000000014200f00000000000000000000000000000000000000000000000000000000001420060000000000000000000000000000000000000000000000000000000000142010000000000000000000000000000000000000000000000000000000000014200700000000000000000000000000000000000000000000000000000000001420110000000000000000000000000000000000000000000000000000000000142008000000000000000000000000000000000000000000000000000000000014201200000000000000000000000000000000000000000000000000000000001420090000000000000000000000000000000000000000000000000000000000142013000000000000000000000000000000000000000000000000000000000014200a0000000000000000000000000000000000000000000000000000000000142014000000000000000000000000000000000000000000000000000000000014200b0000000000000000000000000000000000000000000000000000000000142015000000000000000000000000000000000000000000000000000000000014200c0000000000000000000000000000000000000000000000000000000000142016000000000000000000000000000000000000000000000000000000000014200d0000000000000000000000000000000000000000000000000000000000142017000000000000000000000000000000000000000000000000000000000014200e0000000000000000000000000000000000000000000000000000000000142018000000000000000000000000000000000000000000000000000000000014200f00000000000000000000000000000000000000000000000000000000001420190000000000000000000000000000000000000000000000000000000000142010000000000000000000000000000000000000000000000000000000000014201a0000000000000000000000000000000000000000000000000000000000142011000000000000000000000000000000000000000000000000000000000014201b0000000000000000000000000000000000000000000000000000000000142012000000000000000000000000000000000000000000000000000000000014201c0000000000000000000000000000000000000000000000000000000000142013000000000000000000000000000000000000000000000000000000000014201d0000000000000000000000000000000000000000000000000000000000142014000000000000000000000000000000000000000000000000000000000014201e0000000000000000000000000000000000000000000000000000000000142015000000000000000000000000000000000000000000000000000000000014201f00000000000000000000000000000000000000000000000000000000001420160000000000000000000000000000000000000000000000000000000000142020000000000000000000000000000000000000000000000000000000000014201700000000000000000000000000000000000000000000000000000000001420210000000000000000000000000000000000000000000000000000000000142018000000000000000000000000000000000000000000000000000000000014202200000000000000000000000000000000000000000000000000000000001420190000000000000000000000000000000000000000000000000000000000142023000000000000000000000000000000000000000000000000000000000014201a0000000000000000000000000000000000000000000000000000000000142024000000000000000000000000000000000000000000000000000000000014201b0000000000000000000000000000000000000000000000000000000000142025000000000000000000000000000000000000000000000000000000000014201c0000000000000000000000000000000000000000000000000000000000142026000000000000000000000000000000000000000000000000000000000014201d0000000000000000000000000000000000000000000000000000000000142027000000000000000000000000000000000000000000000000000000000014201e0000000000000000000000000000000000000000000000000000000000142028000000000000000000000000000000000000000000000000000000000014201f00000000000000000000000000000000000000000000000000000000001420290000000000000000000000000000000000000000000000000000000000142020000000000000000000000000000000000000000000000000000000000014202a0000000000000000000000000000000000000000000000000000000000142021000000000000000000000000000000000000000000000000000000000014202b0000000000000000000000000000000000000000000000000000000000142022000000000000000000000000000000000000000000000000000000000014202c0000000000000000000000000000000000000000000000000000000000142023000000000000000000000000000000000000000000000000000000000014202d0000000000000000000000000000000000000000000000000000000000142024000000000000000000000000000000000000000000000000000000000014202e0000000000000000000000000000000000000000000000000000000000142025000000000000000000000000000000000000000000000000000000000014202f00000000000000000000000000000000000000000000000000000000001420260000000000000000000000000000000000000000000000000000000000142030000000000000000000000000000000000000000000000000000000000014202700000000000000000000000000000000000000000000000000000000001420310000000000000000000000000000000000000000000000000000000000142028000000000000000000000000000000000000000000000000000000000014203200000000000000000000000000000000000000000000000000000000001420290000000000000000000000000000000000000000000000000000000000142033000000000000000000000000000000000000000000000000000000000014202a0000000000000000000000000000000000000000000000000000000000142034000000000000000000000000000000000000000000000000000000000014202b0000000000000000000000000000000000000000000000000000000000142035000000000000000000000000000000000000000000000000000000000014202c0000000000000000000000000000000000000000000000000000000000142036000000000000000000000000000000000000000000000000000000000014202d0000000000000000000000000000000000000000000000000000000000142037000000000000000000000000000000000000000000000000000000000014202e0000000000000000000000000000000000000000000000000000000000142038000000000000000000000000000000000000000000000000000000000014202f00000000000000000000000000000000000000000000000000000000001420390000000000000000000000000000000000000000000000000000000000142030000000000000000000000000000000000000000000000000000000000014203a0000000000000000000000000000000000000000000000000000000000142031000000000000000000000000000000000000000000000000000000000014203b0000000000000000000000000000000000000000000000000000000000142032000000000000000000000000000000000000000000000000000000000014203c0000000000000000000000000000000000000000000000000000000000142033000000000000000000000000000000000000000000000000000000000014203d0000000000000000000000000000000000000000000000000000000000142034000000000000000000000000000000000000000000000000000000000014203e0000000000000000000000000000000000000000000000000000000000142035000000000000000000000000000000000000000000000000000000000014203f00000000000000000000000000000000000000000000000000000000001420360000000000000000000000000000000000000000000000000000000000142040000000000000000000000000000000000000000000000000000000000014203700000000000000000000000000000000000000000000000000000000001420410000000000000000000000000000000000000000000000000000000000142038000000000000000000000000000000000000000000000000000000000014204200000000000000000000000000000000000000000000000000000000001420390000000000000000000000000000000000000000000000000000000000142043000000000000000000000000000000000000000000000000000000000014203a0000000000000000000000000000000000000000000000000000000000142044000000000000000000000000000000000000000000000000000000000014203b0000000000000000000000000000000000000000000000000000000000142045000000000000000000000000000000000000000000000000000000000014203c0000000000000000000000000000000000000000000000000000000000142046000000000000000000000000000000000000000000000000000000000014203d0000000000000000000000000000000000000000000000000000000000142047000000000000000000000000000000000000000000000000000000000014203e0000000000000000000000000000000000000000000000000000000000142048200000000000000000000000000000000000000000000000000000000000141700000000000000000000000000000000000000000000000000000000000014170100000000000000000000000000000000000000000000000000000000001417020000000000000000000000000000000000000000000000000000000000141703000000000000000000000000000000000000000000000000000000000014170400000000000000000000000000000000000000000000000000000000001417050000000000000000000000000000000000000000000000000000000000141706000000000000000000000000000000000000000000000000000000000014170700000000000000000000000000000000000000000000000000000000001417080000000000000000000000000000000000000000000000000000000000141709000000000000000000000000000000000000000000000000000000000014170a000000000000000000000000000000000000000000000000000000000014170b000000000000000000000000000000000000000000000000000000000014170c000000000000000000000000000000000000000000000000000000000014170d000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f00000000000000000000000000000000000000000000000000000000001417100000000000000000000000000000000000000000000000000000000000141711000000000000000000000000000000000000000000000000000000000014170100000000000000000000000000000000000000000000000000000000001417020000000000000000000000000000000000000000000000000000000000141703000000000000000000000000000000000000000000000000000000000014170400000000000000000000000000000000000000000000000000000000001417050000000000000000000000000000000000000000000000000000000000141706000000000000000000000000000000000000000000000000000000000014170700000000000000000000000000000000000000000000000000000000001417080000000000000000000000000000000000000000000000000000000000141709000000000000000000000000000000000000000000000000000000000014170a000000000000000000000000000000000000000000000000000000000014170b000000000000000000000000000000000000000000000000000000000014170c000000000000000000000000000000000000000000000000000000000014170d000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f00000000000000000000000000000000000000000000000000000000001417100000000000000000000000000000000000000000000000000000000000141711000000000000000000000000000000000000000000000000000000000014171200000000000000000000000000000000000000000000000000000000001417020000000000000000000000000000000000000000000000000000000000141703000000000000000000000000000000000000000000000000000000000014170400000000000000000000000000000000000000000000000000000000001417050000000000000000000000000000000000000000000000000000000000141706000000000000000000000000000000000000000000000000000000000014170700000000000000000000000000000000000000000000000000000000001417080000000000000000000000000000000000000000000000000000000000141709000000000000000000000000000000000000000000000000000000000014170a000000000000000000000000000000000000000000000000000000000014170b000000000000000000000000000000000000000000000000000000000014170c000000000000000000000000000000000000000000000000000000000014170d000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f00000000000000000000000000000000000000000000000000000000001417100000000000000000000000000000000000000000000000000000000000141711000000000000000000000000000000000000000000000000000000000014171200000000000000000000000000000000000000000000000000000000001417130000000000000000000000000000000000000000000000000000000000141703000000000000000000000000000000000000000000000000000000000014170400000000000000000000000000000000000000000000000000000000001417050000000000000000000000000000000000000000000000000000000000141706000000000000000000000000000000000000000000000000000000000014170700000000000000000000000000000000000000000000000000000000001417080000000000000000000000000000000000000000000000000000000000141709000000000000000000000000000000000000000000000000000000000014170a000000000000000000000000000000000000000000000000000000000014170b000000000000000000000000000000000000000000000000000000000014170c000000000000000000000000000000000000000000000000000000000014170d000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f00000000000000000000000000000000000000000000000000000000001417100000000000000000000000000000000000000000000000000000000000141711000000000000000000000000000000000000000000000000000000000014171200000000000000000000000000000000000000000000000000000000001417130000000000000000000000000000000000000000000000000000000000141714000000000000000000000000000000000000000000000000000000000014170400000000000000000000000000000000000000000000000000000000001417050000000000000000000000000000000000000000000000000000000000141706000000000000000000000000000000000000000000000000000000000014170700000000000000000000000000000000000000000000000000000000001417080000000000000000000000000000000000000000000000000000000000141709000000000000000000000000000000000000000000000000000000000014170a000000000000000000000000000000000000000000000000000000000014170b000000000000000000000000000000000000000000000000000000000014170c000000000000000000000000000000000000000000000000000000000014170d000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f00000000000000000000000000000000000000000000000000000000001417100000000000000000000000000000000000000000000000000000000000141711000000000000000000000000000000000000000000000000000000000014171200000000000000000000000000000000000000000000000000000000001417130000000000000000000000000000000000000000000000000000000000141714000000000000000000000000000000000000000000000000000000000014171500000000000000000000000000000000000000000000000000000000001417050000000000000000000000000000000000000000000000000000000000141706000000000000000000000000000000000000000000000000000000000014170700000000000000000000000000000000000000000000000000000000001417080000000000000000000000000000000000000000000000000000000000141709000000000000000000000000000000000000000000000000000000000014170a000000000000000000000000000000000000000000000000000000000014170b000000000000000000000000000000000000000000000000000000000014170c000000000000000000000000000000000000000000000000000000000014170d000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f00000000000000000000000000000000000000000000000000000000001417100000000000000000000000000000000000000000000000000000000000141711000000000000000000000000000000000000000000000000000000000014171200000000000000000000000000000000000000000000000000000000001417130000000000000000000000000000000000000000000000000000000000141714000000000000000000000000000000000000000000000000000000000014171500000000000000000000000000000000000000000000000000000000001417160000000000000000000000000000000000000000000000000000000000141706000000000000000000000000000000000000000000000000000000000014170700000000000000000000000000000000000000000000000000000000001417080000000000000000000000000000000000000000000000000000000000141709000000000000000000000000000000000000000000000000000000000014170a000000000000000000000000000000000000000000000000000000000014170b000000000000000000000000000000000000000000000000000000000014170c000000000000000000000000000000000000000000000000000000000014170d000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f00000000000000000000000000000000000000000000000000000000001417100000000000000000000000000000000000000000000000000000000000141711000000000000000000000000000000000000000000000000000000000014171200000000000000000000000000000000000000000000000000000000001417130000000000000000000000000000000000000000000000000000000000141714000000000000000000000000000000000000000000000000000000000014171500000000000000000000000000000000000000000000000000000000001417160000000000000000000000000000000000000000000000000000000000141717000000000000000000000000000000000000000000000000000000000014170700000000000000000000000000000000000000000000000000000000001417080000000000000000000000000000000000000000000000000000000000141709000000000000000000000000000000000000000000000000000000000014170a000000000000000000000000000000000000000000000000000000000014170b000000000000000000000000000000000000000000000000000000000014170c000000000000000000000000000000000000000000000000000000000014170d000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f00000000000000000000000000000000000000000000000000000000001417100000000000000000000000000000000000000000000000000000000000141711000000000000000000000000000000000000000000000000000000000014171200000000000000000000000000000000000000000000000000000000001417130000000000000000000000000000000000000000000000000000000000141714000000000000000000000000000000000000000000000000000000000014171500000000000000000000000000000000000000000000000000000000001417160000000000000000000000000000000000000000000000000000000000141717000000000000000000000000000000000000000000000000000000000014171800000000000000000000000000000000000000000000000000000000001417080000000000000000000000000000000000000000000000000000000000141709000000000000000000000000000000000000000000000000000000000014170a000000000000000000000000000000000000000000000000000000000014170b000000000000000000000000000000000000000000000000000000000014170c000000000000000000000000000000000000000000000000000000000014170d000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f00000000000000000000000000000000000000000000000000000000001417100000000000000000000000000000000000000000000000000000000000141711000000000000000000000000000000000000000000000000000000000014171200000000000000000000000000000000000000000000000000000000001417130000000000000000000000000000000000000000000000000000000000141714000000000000000000000000000000000000000000000000000000000014171500000000000000000000000000000000000000000000000000000000001417160000000000000000000000000000000000000000000000000000000000141717000000000000000000000000000000000000000000000000000000000014171800000000000000000000000000000000000000000000000000000000001417190000000000000000000000000000000000000000000000000000000000141709000000000000000000000000000000000000000000000000000000000014170a000000000000000000000000000000000000000000000000000000000014170b000000000000000000000000000000000000000000000000000000000014170c000000000000000000000000000000000000000000000000000000000014170d000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f0000000000000000000000000000000000000000000000000000000000141710000000000000000000000000000000000000000000000000000000000014171100000000000000000000000000000000000000000000000000000000001417120000000000000000000000000000000000000000000000000000000000141713000000000000000000000000000000000000000000000000000000000014171400000000000000000000000000000000000000000000000000000000001417150000000000000000000000000000000000000000000000000000000000141716000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014170a000000000000000000000000000000000000000000000000000000000014170b000000000000000000000000000000000000000000000000000000000014170c000000000000000000000000000000000000000000000000000000000014170d000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f0000000000000000000000000000000000000000000000000000000000141710000000000000000000000000000000000000000000000000000000000014171100000000000000000000000000000000000000000000000000000000001417120000000000000000000000000000000000000000000000000000000000141713000000000000000000000000000000000000000000000000000000000014171400000000000000000000000000000000000000000000000000000000001417150000000000000000000000000000000000000000000000000000000000141716000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014170b000000000000000000000000000000000000000000000000000000000014170c000000000000000000000000000000000000000000000000000000000014170d000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f0000000000000000000000000000000000000000000000000000000000141710000000000000000000000000000000000000000000000000000000000014171100000000000000000000000000000000000000000000000000000000001417120000000000000000000000000000000000000000000000000000000000141713000000000000000000000000000000000000000000000000000000000014171400000000000000000000000000000000000000000000000000000000001417150000000000000000000000000000000000000000000000000000000000141716000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014170c000000000000000000000000000000000000000000000000000000000014170d000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f0000000000000000000000000000000000000000000000000000000000141710000000000000000000000000000000000000000000000000000000000014171100000000000000000000000000000000000000000000000000000000001417120000000000000000000000000000000000000000000000000000000000141713000000000000000000000000000000000000000000000000000000000014171400000000000000000000000000000000000000000000000000000000001417150000000000000000000000000000000000000000000000000000000000141716000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014170d000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f0000000000000000000000000000000000000000000000000000000000141710000000000000000000000000000000000000000000000000000000000014171100000000000000000000000000000000000000000000000000000000001417120000000000000000000000000000000000000000000000000000000000141713000000000000000000000000000000000000000000000000000000000014171400000000000000000000000000000000000000000000000000000000001417150000000000000000000000000000000000000000000000000000000000141716000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f0000000000000000000000000000000000000000000000000000000000141710000000000000000000000000000000000000000000000000000000000014171100000000000000000000000000000000000000000000000000000000001417120000000000000000000000000000000000000000000000000000000000141713000000000000000000000000000000000000000000000000000000000014171400000000000000000000000000000000000000000000000000000000001417150000000000000000000000000000000000000000000000000000000000141716000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f000000000000000000000000000000000000000000000000000000000014170f0000000000000000000000000000000000000000000000000000000000141710000000000000000000000000000000000000000000000000000000000014171100000000000000000000000000000000000000000000000000000000001417120000000000000000000000000000000000000000000000000000000000141713000000000000000000000000000000000000000000000000000000000014171400000000000000000000000000000000000000000000000000000000001417150000000000000000000000000000000000000000000000000000000000141716000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f00000000000000000000000000000000000000000000000000000000001417200000000000000000000000000000000000000000000000000000000000141710000000000000000000000000000000000000000000000000000000000014171100000000000000000000000000000000000000000000000000000000001417120000000000000000000000000000000000000000000000000000000000141713000000000000000000000000000000000000000000000000000000000014171400000000000000000000000000000000000000000000000000000000001417150000000000000000000000000000000000000000000000000000000000141716000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f00000000000000000000000000000000000000000000000000000000001417200000000000000000000000000000000000000000000000000000000000141721000000000000000000000000000000000000000000000000000000000014171100000000000000000000000000000000000000000000000000000000001417120000000000000000000000000000000000000000000000000000000000141713000000000000000000000000000000000000000000000000000000000014171400000000000000000000000000000000000000000000000000000000001417150000000000000000000000000000000000000000000000000000000000141716000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f00000000000000000000000000000000000000000000000000000000001417200000000000000000000000000000000000000000000000000000000000141721000000000000000000000000000000000000000000000000000000000014172200000000000000000000000000000000000000000000000000000000001417120000000000000000000000000000000000000000000000000000000000141713000000000000000000000000000000000000000000000000000000000014171400000000000000000000000000000000000000000000000000000000001417150000000000000000000000000000000000000000000000000000000000141716000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f00000000000000000000000000000000000000000000000000000000001417200000000000000000000000000000000000000000000000000000000000141721000000000000000000000000000000000000000000000000000000000014172200000000000000000000000000000000000000000000000000000000001417230000000000000000000000000000000000000000000000000000000000141713000000000000000000000000000000000000000000000000000000000014171400000000000000000000000000000000000000000000000000000000001417150000000000000000000000000000000000000000000000000000000000141716000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f00000000000000000000000000000000000000000000000000000000001417200000000000000000000000000000000000000000000000000000000000141721000000000000000000000000000000000000000000000000000000000014172200000000000000000000000000000000000000000000000000000000001417230000000000000000000000000000000000000000000000000000000000141724000000000000000000000000000000000000000000000000000000000014171400000000000000000000000000000000000000000000000000000000001417150000000000000000000000000000000000000000000000000000000000141716000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f00000000000000000000000000000000000000000000000000000000001417200000000000000000000000000000000000000000000000000000000000141721000000000000000000000000000000000000000000000000000000000014172200000000000000000000000000000000000000000000000000000000001417230000000000000000000000000000000000000000000000000000000000141724000000000000000000000000000000000000000000000000000000000014172500000000000000000000000000000000000000000000000000000000001417150000000000000000000000000000000000000000000000000000000000141716000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f00000000000000000000000000000000000000000000000000000000001417200000000000000000000000000000000000000000000000000000000000141721000000000000000000000000000000000000000000000000000000000014172200000000000000000000000000000000000000000000000000000000001417230000000000000000000000000000000000000000000000000000000000141724000000000000000000000000000000000000000000000000000000000014172500000000000000000000000000000000000000000000000000000000001417260000000000000000000000000000000000000000000000000000000000141716000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f00000000000000000000000000000000000000000000000000000000001417200000000000000000000000000000000000000000000000000000000000141721000000000000000000000000000000000000000000000000000000000014172200000000000000000000000000000000000000000000000000000000001417230000000000000000000000000000000000000000000000000000000000141724000000000000000000000000000000000000000000000000000000000014172500000000000000000000000000000000000000000000000000000000001417260000000000000000000000000000000000000000000000000000000000141727000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f00000000000000000000000000000000000000000000000000000000001417200000000000000000000000000000000000000000000000000000000000141721000000000000000000000000000000000000000000000000000000000014172200000000000000000000000000000000000000000000000000000000001417230000000000000000000000000000000000000000000000000000000000141724000000000000000000000000000000000000000000000000000000000014172500000000000000000000000000000000000000000000000000000000001417260000000000000000000000000000000000000000000000000000000000141727000000000000000000000000000000000000000000000000000000000014172800000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f00000000000000000000000000000000000000000000000000000000001417200000000000000000000000000000000000000000000000000000000000141721000000000000000000000000000000000000000000000000000000000014172200000000000000000000000000000000000000000000000000000000001417230000000000000000000000000000000000000000000000000000000000141724000000000000000000000000000000000000000000000000000000000014172500000000000000000000000000000000000000000000000000000000001417260000000000000000000000000000000000000000000000000000000000141727000000000000000000000000000000000000000000000000000000000014172800000000000000000000000000000000000000000000000000000000001417290000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f0000000000000000000000000000000000000000000000000000000000141720000000000000000000000000000000000000000000000000000000000014172100000000000000000000000000000000000000000000000000000000001417220000000000000000000000000000000000000000000000000000000000141723000000000000000000000000000000000000000000000000000000000014172400000000000000000000000000000000000000000000000000000000001417250000000000000000000000000000000000000000000000000000000000141726000000000000000000000000000000000000000000000000000000000014172700000000000000000000000000000000000000000000000000000000001417280000000000000000000000000000000000000000000000000000000000141729000000000000000000000000000000000000000000000000000000000014172a000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f0000000000000000000000000000000000000000000000000000000000141720000000000000000000000000000000000000000000000000000000000014172100000000000000000000000000000000000000000000000000000000001417220000000000000000000000000000000000000000000000000000000000141723000000000000000000000000000000000000000000000000000000000014172400000000000000000000000000000000000000000000000000000000001417250000000000000000000000000000000000000000000000000000000000141726000000000000000000000000000000000000000000000000000000000014172700000000000000000000000000000000000000000000000000000000001417280000000000000000000000000000000000000000000000000000000000141729000000000000000000000000000000000000000000000000000000000014172a000000000000000000000000000000000000000000000000000000000014172b000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f0000000000000000000000000000000000000000000000000000000000141720000000000000000000000000000000000000000000000000000000000014172100000000000000000000000000000000000000000000000000000000001417220000000000000000000000000000000000000000000000000000000000141723000000000000000000000000000000000000000000000000000000000014172400000000000000000000000000000000000000000000000000000000001417250000000000000000000000000000000000000000000000000000000000141726000000000000000000000000000000000000000000000000000000000014172700000000000000000000000000000000000000000000000000000000001417280000000000000000000000000000000000000000000000000000000000141729000000000000000000000000000000000000000000000000000000000014172a000000000000000000000000000000000000000000000000000000000014172b000000000000000000000000000000000000000000000000000000000014172c000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f0000000000000000000000000000000000000000000000000000000000141720000000000000000000000000000000000000000000000000000000000014172100000000000000000000000000000000000000000000000000000000001417220000000000000000000000000000000000000000000000000000000000141723000000000000000000000000000000000000000000000000000000000014172400000000000000000000000000000000000000000000000000000000001417250000000000000000000000000000000000000000000000000000000000141726000000000000000000000000000000000000000000000000000000000014172700000000000000000000000000000000000000000000000000000000001417280000000000000000000000000000000000000000000000000000000000141729000000000000000000000000000000000000000000000000000000000014172a000000000000000000000000000000000000000000000000000000000014172b000000000000000000000000000000000000000000000000000000000014172c000000000000000000000000000000000000000000000000000000000014172d000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f0000000000000000000000000000000000000000000000000000000000141720000000000000000000000000000000000000000000000000000000000014172100000000000000000000000000000000000000000000000000000000001417220000000000000000000000000000000000000000000000000000000000141723000000000000000000000000000000000000000000000000000000000014172400000000000000000000000000000000000000000000000000000000001417250000000000000000000000000000000000000000000000000000000000141726000000000000000000000000000000000000000000000000000000000014172700000000000000000000000000000000000000000000000000000000001417280000000000000000000000000000000000000000000000000000000000141729000000000000000000000000000000000000000000000000000000000014172a000000000000000000000000000000000000000000000000000000000014172b000000000000000000000000000000000000000000000000000000000014172c000000000000000000000000000000000000000000000000000000000014172d000000000000000000000000000000000000000000000000000000000014172e000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f0000000000000000000000000000000000000000000000000000000000141720000000000000000000000000000000000000000000000000000000000014172100000000000000000000000000000000000000000000000000000000001417220000000000000000000000000000000000000000000000000000000000141723000000000000000000000000000000000000000000000000000000000014172400000000000000000000000000000000000000000000000000000000001417250000000000000000000000000000000000000000000000000000000000141726000000000000000000000000000000000000000000000000000000000014172700000000000000000000000000000000000000000000000000000000001417280000000000000000000000000000000000000000000000000000000000141729000000000000000000000000000000000000000000000000000000000014172a000000000000000000000000000000000000000000000000000000000014172b000000000000000000000000000000000000000000000000000000000014172c000000000000000000000000000000000000000000000000000000000014172d000000000000000000000000000000000000000000000000000000000014172e000000000000000000000000000000000000000000000000000000000014172f000000000000000000000000000000000000000000000000000000000014171f0000000000000000000000000000000000000000000000000000000000141720000000000000000000000000000000000000000000000000000000000014172100000000000000000000000000000000000000000000000000000000001417220000000000000000000000000000000000000000000000000000000000141723000000000000000000000000000000000000000000000000000000000014172400000000000000000000000000000000000000000000000000000000001417250000000000000000000000000000000000000000000000000000000000141726000000000000000000000000000000000000000000000000000000000014172700000000000000000000000000000000000000000000000000000000001417280000000000000000000000000000000000000000000000000000000000141729000000000000000000000000000000000000000000000000000000000014172a000000000000000000000000000000000000000000000000000000000014172b000000000000000000000000000000000000000000000000000000000014172c000000000000000000000000000000000000000000000000000000000014172d000000000000000000000000000000000000000000000000000000000014172e000000000000000000000000000000000000000000000000000000000014172f0000000000000000000000000000000000000000000000000000000000141730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000181000000000000000000000000000000000000000000000000000000000000018100100000000000000000000000000000000000000000000000000000000001810020000000000000000000000000000000000000000000000000000000000181003000000000000000000000000000000000000000000000000000000000018100400000000000000000000000000000000000000000000000000000000001810050000000000000000000000000000000000000000000000000000000000181006000000000000000000000000000000000000000000000000000000000018100700000000000000000000000000000000000000000000000000000000001810080000000000000000000000000000000000000000000000000000000000181009000000000000000000000000000000000000000000000000000000000018100a000000000000000000000000000000000000000000000000000000000018100b000000000000000000000000000000000000000000000000000000000018100c000000000000000000000000000000000000000000000000000000000018100d000000000000000000000000000000000000000000000000000000000018100e000000000000000000000000000000000000000000000000000000000018100f0000000000000000000000000000000000000000000000000000000000181010000000000000000000000000000000000000000000000000000000000018101100000000000000000000000000000000000000000000000000000000001810120000000000000000000000000000000000000000000000000000000000181013000000000000000000000000000000000000000000000000000000000018101400000000000000000000000000000000000000000000000000000000001810150000000000000000000000000000000000000000000000000000000000181016000000000000000000000000000000000000000000000000000000000018101700000000000000000000000000000000000000000000000000000000001810180000000000000000000000000000000000000000000000000000000000181019000000000000000000000000000000000000000000000000000000000018101a000000000000000000000000000000000000000000000000000000000018101b000000000000000000000000000000000000000000000000000000000018101c000000000000000000000000000000000000000000000000000000000018101d000000000000000000000000000000000000000000000000000000000018101e000000000000000000000000000000000000000000000000000000000018101f0000000000000000000000000000000000000000000000000000000000181020000000000000000000000000000000000000000000000000000000000018102100000000000000000000000000000000000000000000000000000000001810220000000000000000000000000000000000000000000000000000000000181023000000000000000000000000000000000000000000000000000000000018102400000000000000000000000000000000000000000000000000000000001810250000000000000000000000000000000000000000000000000000000000181026000000000000000000000000000000000000000000000000000000000018102700000000000000000000000000000000000000000000000000000000001810280000000000000000000000000000000000000000000000000000000000181029000000000000000000000000000000000000000000000000000000000018102a000000000000000000000000000000000000000000000000000000000018102b000000000000000000000000000000000000000000000000000000000018102c000000000000000000000000000000000000000000000000000000000018102d000000000000000000000000000000000000000000000000000000000018102e000000000000000000000000000000000000000000000000000000000018102f0000000000000000000000000000000000000000000000000000000000181030000000000000000000000000000000000000000000000000000000000018103100000000000000000000000000000000000000000000000000000000001810320000000000000000000000000000000000000000000000000000000000181033000000000000000000000000000000000000000000000000000000000018103400000000000000000000000000000000000000000000000000000000001810350000000000000000000000000000000000000000000000000000000000181036000000000000000000000000000000000000000000000000000000000018103700000000000000000000000000000000000000000000000000000000001810380000000000000000000000000000000000000000000000000000000000181039000000000000000000000000000000000000000000000000000000000018103a000000000000000000000000000000000000000000000000000000000018103b000000000000000000000000000000000000000000000000000000000018103c000000000000000000000000000000000000000000000000000000000018103d000000000000000000000000000000000000000000000000000000000018103e000000000000000000000000000000000000000000000000000000000018103f4000000000000000000000000000000000000000000000000000000000001800010000000000000000000000000000000000000000000000000000000000181100000000000000000000000000000000000000000000000000000000000018110100000000000000000000000000000000000000000000000000000000001811020000000000000000000000000000000000000000000000000000000000181103000000000000000000000000000000000000000000000000000000000018110400000000000000000000000000000000000000000000000000000000001811050000000000000000000000000000000000000000000000000000000000181106000000000000000000000000000000000000000000000000000000000018110700000000000000000000000000000000000000000000000000000000001811080000000000000000000000000000000000000000000000000000000000181109000000000000000000000000000000000000000000000000000000000018110a000000000000000000000000000000000000000000000000000000000018110b000000000000000000000000000000000000000000000000000000000018110c000000000000000000000000000000000000000000000000000000000018110d000000000000000000000000000000000000000000000000000000000018110e000000000000000000000000000000000000000000000000000000000018110f0000000000000000000000000000000000000000000000000000000000181110000000000000000000000000000000000000000000000000000000000018111100000000000000000000000000000000000000000000000000000000001811120000000000000000000000000000000000000000000000000000000000181113000000000000000000000000000000000000000000000000000000000018111400000000000000000000000000000000000000000000000000000000001811150000000000000000000000000000000000000000000000000000000000181116000000000000000000000000000000000000000000000000000000000018111700000000000000000000000000000000000000000000000000000000001811180000000000000000000000000000000000000000000000000000000000181119000000000000000000000000000000000000000000000000000000000018111a000000000000000000000000000000000000000000000000000000000018111b000000000000000000000000000000000000000000000000000000000018111c000000000000000000000000000000000000000000000000000000000018111d000000000000000000000000000000000000000000000000000000000018111e000000000000000000000000000000000000000000000000000000000018111f0000000000000000000000000000000000000000000000000000000000181120000000000000000000000000000000000000000000000000000000000018112100000000000000000000000000000000000000000000000000000000001811220000000000000000000000000000000000000000000000000000000000181123000000000000000000000000000000000000000000000000000000000018112400000000000000000000000000000000000000000000000000000000001811250000000000000000000000000000000000000000000000000000000000181126000000000000000000000000000000000000000000000000000000000018112700000000000000000000000000000000000000000000000000000000001811280000000000000000000000000000000000000000000000000000000000181129000000000000000000000000000000000000000000000000000000000018112a000000000000000000000000000000000000000000000000000000000018112b000000000000000000000000000000000000000000000000000000000018112c000000000000000000000000000000000000000000000000000000000018112d000000000000000000000000000000000000000000000000000000000018112e000000000000000000000000000000000000000000000000000000000018112f0000000000000000000000000000000000000000000000000000000000181130000000000000000000000000000000000000000000000000000000000018113100000000000000000000000000000000000000000000000000000000001811320000000000000000000000000000000000000000000000000000000000181133000000000000000000000000000000000000000000000000000000000018113400000000000000000000000000000000000000000000000000000000001811350000000000000000000000000000000000000000000000000000000000181136000000000000000000000000000000000000000000000000000000000018113700000000000000000000000000000000000000000000000000000000001811380000000000000000000000000000000000000000000000000000000000181139000000000000000000000000000000000000000000000000000000000018113a000000000000000000000000000000000000000000000000000000000018113b000000000000000000000000000000000000000000000000000000000018113c000000000000000000000000000000000000000000000000000000000018113d000000000000000000000000000000000000000000000000000000000018113e0800f872eb9653f03af10f331da1361fa1524d3cd958cb72dacea1d424f19df3af00ffc548a17cd6ba1f2d228f30e4ddb19ecc46ad3b609977d52bb0f49e1206410032f8058bd779c520eabae2743b02ec4f71670428506fcceb2d4b69f26fb11800c0283e15fbf74ffa4eafb984030394f3c2ea6733cc0eacb0431a9475eff28f00b7f55314bfd9d441c1c624e241908228fe4da3d3a0a7fbd56814e1c8cd5d3e00f430f33a786675271736fd728c7bf7428b8c24ac948d7faf76ddb8783a496c0048fc235ead8d4b9d44929662a6384074fc4e5076bec5b7deb34f612393684300fd9b61cb1ad9b4b28f58399906e73933e3cccee8fc98a393f0eedb95b13ee63f0000000000000000000000000000000000000000000000000000000000182000000000000000000000000000000000000000000000000000000000000018200a0000000000000000000000000000000000000000000000000000000000182001000000000000000000000000000000000000000000000000000000000018200b0000000000000000000000000000000000000000000000000000000000182002000000000000000000000000000000000000000000000000000000000018200c0000000000000000000000000000000000000000000000000000000000182003000000000000000000000000000000000000000000000000000000000018200d0000000000000000000000000000000000000000000000000000000000182004000000000000000000000000000000000000000000000000000000000018200e0000000000000000000000000000000000000000000000000000000000182005000000000000000000000000000000000000000000000000000000000018200f00000000000000000000000000000000000000000000000000000000001820060000000000000000000000000000000000000000000000000000000000182010000000000000000000000000000000000000000000000000000000000018200700000000000000000000000000000000000000000000000000000000001820110000000000000000000000000000000000000000000000000000000000182008000000000000000000000000000000000000000000000000000000000018201200000000000000000000000000000000000000000000000000000000001820090000000000000000000000000000000000000000000000000000000000182013000000000000000000000000000000000000000000000000000000000018200a0000000000000000000000000000000000000000000000000000000000182014000000000000000000000000000000000000000000000000000000000018200b0000000000000000000000000000000000000000000000000000000000182015000000000000000000000000000000000000000000000000000000000018200c0000000000000000000000000000000000000000000000000000000000182016000000000000000000000000000000000000000000000000000000000018200d0000000000000000000000000000000000000000000000000000000000182017000000000000000000000000000000000000000000000000000000000018200e0000000000000000000000000000000000000000000000000000000000182018000000000000000000000000000000000000000000000000000000000018200f00000000000000000000000000000000000000000000000000000000001820190000000000000000000000000000000000000000000000000000000000182010000000000000000000000000000000000000000000000000000000000018201a0000000000000000000000000000000000000000000000000000000000182011000000000000000000000000000000000000000000000000000000000018201b0000000000000000000000000000000000000000000000000000000000182012000000000000000000000000000000000000000000000000000000000018201c0000000000000000000000000000000000000000000000000000000000182013000000000000000000000000000000000000000000000000000000000018201d0000000000000000000000000000000000000000000000000000000000182014000000000000000000000000000000000000000000000000000000000018201e0000000000000000000000000000000000000000000000000000000000182015000000000000000000000000000000000000000000000000000000000018201f00000000000000000000000000000000000000000000000000000000001820160000000000000000000000000000000000000000000000000000000000182020000000000000000000000000000000000000000000000000000000000018201700000000000000000000000000000000000000000000000000000000001820210000000000000000000000000000000000000000000000000000000000182018000000000000000000000000000000000000000000000000000000000018202200000000000000000000000000000000000000000000000000000000001820190000000000000000000000000000000000000000000000000000000000182023000000000000000000000000000000000000000000000000000000000018201a0000000000000000000000000000000000000000000000000000000000182024000000000000000000000000000000000000000000000000000000000018201b0000000000000000000000000000000000000000000000000000000000182025000000000000000000000000000000000000000000000000000000000018201c0000000000000000000000000000000000000000000000000000000000182026000000000000000000000000000000000000000000000000000000000018201d0000000000000000000000000000000000000000000000000000000000182027000000000000000000000000000000000000000000000000000000000018201e0000000000000000000000000000000000000000000000000000000000182028000000000000000000000000000000000000000000000000000000000018201f00000000000000000000000000000000000000000000000000000000001820290000000000000000000000000000000000000000000000000000000000182020000000000000000000000000000000000000000000000000000000000018202a0000000000000000000000000000000000000000000000000000000000182021000000000000000000000000000000000000000000000000000000000018202b0000000000000000000000000000000000000000000000000000000000182022000000000000000000000000000000000000000000000000000000000018202c0000000000000000000000000000000000000000000000000000000000182023000000000000000000000000000000000000000000000000000000000018202d0000000000000000000000000000000000000000000000000000000000182024000000000000000000000000000000000000000000000000000000000018202e0000000000000000000000000000000000000000000000000000000000182025000000000000000000000000000000000000000000000000000000000018202f00000000000000000000000000000000000000000000000000000000001820260000000000000000000000000000000000000000000000000000000000182030000000000000000000000000000000000000000000000000000000000018202700000000000000000000000000000000000000000000000000000000001820310000000000000000000000000000000000000000000000000000000000182028000000000000000000000000000000000000000000000000000000000018203200000000000000000000000000000000000000000000000000000000001820290000000000000000000000000000000000000000000000000000000000182033000000000000000000000000000000000000000000000000000000000018202a0000000000000000000000000000000000000000000000000000000000182034000000000000000000000000000000000000000000000000000000000018202b0000000000000000000000000000000000000000000000000000000000182035000000000000000000000000000000000000000000000000000000000018202c0000000000000000000000000000000000000000000000000000000000182036000000000000000000000000000000000000000000000000000000000018202d0000000000000000000000000000000000000000000000000000000000182037000000000000000000000000000000000000000000000000000000000018202e0000000000000000000000000000000000000000000000000000000000182038000000000000000000000000000000000000000000000000000000000018202f00000000000000000000000000000000000000000000000000000000001820390000000000000000000000000000000000000000000000000000000000182030000000000000000000000000000000000000000000000000000000000018203a0000000000000000000000000000000000000000000000000000000000182031000000000000000000000000000000000000000000000000000000000018203b0000000000000000000000000000000000000000000000000000000000182032000000000000000000000000000000000000000000000000000000000018203c0000000000000000000000000000000000000000000000000000000000182033000000000000000000000000000000000000000000000000000000000018203d0000000000000000000000000000000000000000000000000000000000182034000000000000000000000000000000000000000000000000000000000018203e0000000000000000000000000000000000000000000000000000000000182035000000000000000000000000000000000000000000000000000000000018203f00000000000000000000000000000000000000000000000000000000001820360000000000000000000000000000000000000000000000000000000000182040000000000000000000000000000000000000000000000000000000000018203700000000000000000000000000000000000000000000000000000000001820410000000000000000000000000000000000000000000000000000000000182038000000000000000000000000000000000000000000000000000000000018204200000000000000000000000000000000000000000000000000000000001820390000000000000000000000000000000000000000000000000000000000182043000000000000000000000000000000000000000000000000000000000018203a0000000000000000000000000000000000000000000000000000000000182044000000000000000000000000000000000000000000000000000000000018203b0000000000000000000000000000000000000000000000000000000000182045000000000000000000000000000000000000000000000000000000000018203c0000000000000000000000000000000000000000000000000000000000182046000000000000000000000000000000000000000000000000000000000018203d0000000000000000000000000000000000000000000000000000000000182047000000000000000000000000000000000000000000000000000000000018203e0000000000000000000000000000000000000000000000000000000000182048200000000000000000000000000000000000000000000000000000000000181700000000000000000000000000000000000000000000000000000000000018170100000000000000000000000000000000000000000000000000000000001817020000000000000000000000000000000000000000000000000000000000181703000000000000000000000000000000000000000000000000000000000018170400000000000000000000000000000000000000000000000000000000001817050000000000000000000000000000000000000000000000000000000000181706000000000000000000000000000000000000000000000000000000000018170700000000000000000000000000000000000000000000000000000000001817080000000000000000000000000000000000000000000000000000000000181709000000000000000000000000000000000000000000000000000000000018170a000000000000000000000000000000000000000000000000000000000018170b000000000000000000000000000000000000000000000000000000000018170c000000000000000000000000000000000000000000000000000000000018170d000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f00000000000000000000000000000000000000000000000000000000001817100000000000000000000000000000000000000000000000000000000000181711000000000000000000000000000000000000000000000000000000000018170100000000000000000000000000000000000000000000000000000000001817020000000000000000000000000000000000000000000000000000000000181703000000000000000000000000000000000000000000000000000000000018170400000000000000000000000000000000000000000000000000000000001817050000000000000000000000000000000000000000000000000000000000181706000000000000000000000000000000000000000000000000000000000018170700000000000000000000000000000000000000000000000000000000001817080000000000000000000000000000000000000000000000000000000000181709000000000000000000000000000000000000000000000000000000000018170a000000000000000000000000000000000000000000000000000000000018170b000000000000000000000000000000000000000000000000000000000018170c000000000000000000000000000000000000000000000000000000000018170d000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f00000000000000000000000000000000000000000000000000000000001817100000000000000000000000000000000000000000000000000000000000181711000000000000000000000000000000000000000000000000000000000018171200000000000000000000000000000000000000000000000000000000001817020000000000000000000000000000000000000000000000000000000000181703000000000000000000000000000000000000000000000000000000000018170400000000000000000000000000000000000000000000000000000000001817050000000000000000000000000000000000000000000000000000000000181706000000000000000000000000000000000000000000000000000000000018170700000000000000000000000000000000000000000000000000000000001817080000000000000000000000000000000000000000000000000000000000181709000000000000000000000000000000000000000000000000000000000018170a000000000000000000000000000000000000000000000000000000000018170b000000000000000000000000000000000000000000000000000000000018170c000000000000000000000000000000000000000000000000000000000018170d000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f00000000000000000000000000000000000000000000000000000000001817100000000000000000000000000000000000000000000000000000000000181711000000000000000000000000000000000000000000000000000000000018171200000000000000000000000000000000000000000000000000000000001817130000000000000000000000000000000000000000000000000000000000181703000000000000000000000000000000000000000000000000000000000018170400000000000000000000000000000000000000000000000000000000001817050000000000000000000000000000000000000000000000000000000000181706000000000000000000000000000000000000000000000000000000000018170700000000000000000000000000000000000000000000000000000000001817080000000000000000000000000000000000000000000000000000000000181709000000000000000000000000000000000000000000000000000000000018170a000000000000000000000000000000000000000000000000000000000018170b000000000000000000000000000000000000000000000000000000000018170c000000000000000000000000000000000000000000000000000000000018170d000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f00000000000000000000000000000000000000000000000000000000001817100000000000000000000000000000000000000000000000000000000000181711000000000000000000000000000000000000000000000000000000000018171200000000000000000000000000000000000000000000000000000000001817130000000000000000000000000000000000000000000000000000000000181714000000000000000000000000000000000000000000000000000000000018170400000000000000000000000000000000000000000000000000000000001817050000000000000000000000000000000000000000000000000000000000181706000000000000000000000000000000000000000000000000000000000018170700000000000000000000000000000000000000000000000000000000001817080000000000000000000000000000000000000000000000000000000000181709000000000000000000000000000000000000000000000000000000000018170a000000000000000000000000000000000000000000000000000000000018170b000000000000000000000000000000000000000000000000000000000018170c000000000000000000000000000000000000000000000000000000000018170d000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f00000000000000000000000000000000000000000000000000000000001817100000000000000000000000000000000000000000000000000000000000181711000000000000000000000000000000000000000000000000000000000018171200000000000000000000000000000000000000000000000000000000001817130000000000000000000000000000000000000000000000000000000000181714000000000000000000000000000000000000000000000000000000000018171500000000000000000000000000000000000000000000000000000000001817050000000000000000000000000000000000000000000000000000000000181706000000000000000000000000000000000000000000000000000000000018170700000000000000000000000000000000000000000000000000000000001817080000000000000000000000000000000000000000000000000000000000181709000000000000000000000000000000000000000000000000000000000018170a000000000000000000000000000000000000000000000000000000000018170b000000000000000000000000000000000000000000000000000000000018170c000000000000000000000000000000000000000000000000000000000018170d000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f00000000000000000000000000000000000000000000000000000000001817100000000000000000000000000000000000000000000000000000000000181711000000000000000000000000000000000000000000000000000000000018171200000000000000000000000000000000000000000000000000000000001817130000000000000000000000000000000000000000000000000000000000181714000000000000000000000000000000000000000000000000000000000018171500000000000000000000000000000000000000000000000000000000001817160000000000000000000000000000000000000000000000000000000000181706000000000000000000000000000000000000000000000000000000000018170700000000000000000000000000000000000000000000000000000000001817080000000000000000000000000000000000000000000000000000000000181709000000000000000000000000000000000000000000000000000000000018170a000000000000000000000000000000000000000000000000000000000018170b000000000000000000000000000000000000000000000000000000000018170c000000000000000000000000000000000000000000000000000000000018170d000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f00000000000000000000000000000000000000000000000000000000001817100000000000000000000000000000000000000000000000000000000000181711000000000000000000000000000000000000000000000000000000000018171200000000000000000000000000000000000000000000000000000000001817130000000000000000000000000000000000000000000000000000000000181714000000000000000000000000000000000000000000000000000000000018171500000000000000000000000000000000000000000000000000000000001817160000000000000000000000000000000000000000000000000000000000181717000000000000000000000000000000000000000000000000000000000018170700000000000000000000000000000000000000000000000000000000001817080000000000000000000000000000000000000000000000000000000000181709000000000000000000000000000000000000000000000000000000000018170a000000000000000000000000000000000000000000000000000000000018170b000000000000000000000000000000000000000000000000000000000018170c000000000000000000000000000000000000000000000000000000000018170d000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f00000000000000000000000000000000000000000000000000000000001817100000000000000000000000000000000000000000000000000000000000181711000000000000000000000000000000000000000000000000000000000018171200000000000000000000000000000000000000000000000000000000001817130000000000000000000000000000000000000000000000000000000000181714000000000000000000000000000000000000000000000000000000000018171500000000000000000000000000000000000000000000000000000000001817160000000000000000000000000000000000000000000000000000000000181717000000000000000000000000000000000000000000000000000000000018171800000000000000000000000000000000000000000000000000000000001817080000000000000000000000000000000000000000000000000000000000181709000000000000000000000000000000000000000000000000000000000018170a000000000000000000000000000000000000000000000000000000000018170b000000000000000000000000000000000000000000000000000000000018170c000000000000000000000000000000000000000000000000000000000018170d000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f00000000000000000000000000000000000000000000000000000000001817100000000000000000000000000000000000000000000000000000000000181711000000000000000000000000000000000000000000000000000000000018171200000000000000000000000000000000000000000000000000000000001817130000000000000000000000000000000000000000000000000000000000181714000000000000000000000000000000000000000000000000000000000018171500000000000000000000000000000000000000000000000000000000001817160000000000000000000000000000000000000000000000000000000000181717000000000000000000000000000000000000000000000000000000000018171800000000000000000000000000000000000000000000000000000000001817190000000000000000000000000000000000000000000000000000000000181709000000000000000000000000000000000000000000000000000000000018170a000000000000000000000000000000000000000000000000000000000018170b000000000000000000000000000000000000000000000000000000000018170c000000000000000000000000000000000000000000000000000000000018170d000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f0000000000000000000000000000000000000000000000000000000000181710000000000000000000000000000000000000000000000000000000000018171100000000000000000000000000000000000000000000000000000000001817120000000000000000000000000000000000000000000000000000000000181713000000000000000000000000000000000000000000000000000000000018171400000000000000000000000000000000000000000000000000000000001817150000000000000000000000000000000000000000000000000000000000181716000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018170a000000000000000000000000000000000000000000000000000000000018170b000000000000000000000000000000000000000000000000000000000018170c000000000000000000000000000000000000000000000000000000000018170d000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f0000000000000000000000000000000000000000000000000000000000181710000000000000000000000000000000000000000000000000000000000018171100000000000000000000000000000000000000000000000000000000001817120000000000000000000000000000000000000000000000000000000000181713000000000000000000000000000000000000000000000000000000000018171400000000000000000000000000000000000000000000000000000000001817150000000000000000000000000000000000000000000000000000000000181716000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018170b000000000000000000000000000000000000000000000000000000000018170c000000000000000000000000000000000000000000000000000000000018170d000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f0000000000000000000000000000000000000000000000000000000000181710000000000000000000000000000000000000000000000000000000000018171100000000000000000000000000000000000000000000000000000000001817120000000000000000000000000000000000000000000000000000000000181713000000000000000000000000000000000000000000000000000000000018171400000000000000000000000000000000000000000000000000000000001817150000000000000000000000000000000000000000000000000000000000181716000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018170c000000000000000000000000000000000000000000000000000000000018170d000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f0000000000000000000000000000000000000000000000000000000000181710000000000000000000000000000000000000000000000000000000000018171100000000000000000000000000000000000000000000000000000000001817120000000000000000000000000000000000000000000000000000000000181713000000000000000000000000000000000000000000000000000000000018171400000000000000000000000000000000000000000000000000000000001817150000000000000000000000000000000000000000000000000000000000181716000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018170d000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f0000000000000000000000000000000000000000000000000000000000181710000000000000000000000000000000000000000000000000000000000018171100000000000000000000000000000000000000000000000000000000001817120000000000000000000000000000000000000000000000000000000000181713000000000000000000000000000000000000000000000000000000000018171400000000000000000000000000000000000000000000000000000000001817150000000000000000000000000000000000000000000000000000000000181716000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f0000000000000000000000000000000000000000000000000000000000181710000000000000000000000000000000000000000000000000000000000018171100000000000000000000000000000000000000000000000000000000001817120000000000000000000000000000000000000000000000000000000000181713000000000000000000000000000000000000000000000000000000000018171400000000000000000000000000000000000000000000000000000000001817150000000000000000000000000000000000000000000000000000000000181716000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f000000000000000000000000000000000000000000000000000000000018170f0000000000000000000000000000000000000000000000000000000000181710000000000000000000000000000000000000000000000000000000000018171100000000000000000000000000000000000000000000000000000000001817120000000000000000000000000000000000000000000000000000000000181713000000000000000000000000000000000000000000000000000000000018171400000000000000000000000000000000000000000000000000000000001817150000000000000000000000000000000000000000000000000000000000181716000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f00000000000000000000000000000000000000000000000000000000001817200000000000000000000000000000000000000000000000000000000000181710000000000000000000000000000000000000000000000000000000000018171100000000000000000000000000000000000000000000000000000000001817120000000000000000000000000000000000000000000000000000000000181713000000000000000000000000000000000000000000000000000000000018171400000000000000000000000000000000000000000000000000000000001817150000000000000000000000000000000000000000000000000000000000181716000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f00000000000000000000000000000000000000000000000000000000001817200000000000000000000000000000000000000000000000000000000000181721000000000000000000000000000000000000000000000000000000000018171100000000000000000000000000000000000000000000000000000000001817120000000000000000000000000000000000000000000000000000000000181713000000000000000000000000000000000000000000000000000000000018171400000000000000000000000000000000000000000000000000000000001817150000000000000000000000000000000000000000000000000000000000181716000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f00000000000000000000000000000000000000000000000000000000001817200000000000000000000000000000000000000000000000000000000000181721000000000000000000000000000000000000000000000000000000000018172200000000000000000000000000000000000000000000000000000000001817120000000000000000000000000000000000000000000000000000000000181713000000000000000000000000000000000000000000000000000000000018171400000000000000000000000000000000000000000000000000000000001817150000000000000000000000000000000000000000000000000000000000181716000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f00000000000000000000000000000000000000000000000000000000001817200000000000000000000000000000000000000000000000000000000000181721000000000000000000000000000000000000000000000000000000000018172200000000000000000000000000000000000000000000000000000000001817230000000000000000000000000000000000000000000000000000000000181713000000000000000000000000000000000000000000000000000000000018171400000000000000000000000000000000000000000000000000000000001817150000000000000000000000000000000000000000000000000000000000181716000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f00000000000000000000000000000000000000000000000000000000001817200000000000000000000000000000000000000000000000000000000000181721000000000000000000000000000000000000000000000000000000000018172200000000000000000000000000000000000000000000000000000000001817230000000000000000000000000000000000000000000000000000000000181724000000000000000000000000000000000000000000000000000000000018171400000000000000000000000000000000000000000000000000000000001817150000000000000000000000000000000000000000000000000000000000181716000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f00000000000000000000000000000000000000000000000000000000001817200000000000000000000000000000000000000000000000000000000000181721000000000000000000000000000000000000000000000000000000000018172200000000000000000000000000000000000000000000000000000000001817230000000000000000000000000000000000000000000000000000000000181724000000000000000000000000000000000000000000000000000000000018172500000000000000000000000000000000000000000000000000000000001817150000000000000000000000000000000000000000000000000000000000181716000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f00000000000000000000000000000000000000000000000000000000001817200000000000000000000000000000000000000000000000000000000000181721000000000000000000000000000000000000000000000000000000000018172200000000000000000000000000000000000000000000000000000000001817230000000000000000000000000000000000000000000000000000000000181724000000000000000000000000000000000000000000000000000000000018172500000000000000000000000000000000000000000000000000000000001817260000000000000000000000000000000000000000000000000000000000181716000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f00000000000000000000000000000000000000000000000000000000001817200000000000000000000000000000000000000000000000000000000000181721000000000000000000000000000000000000000000000000000000000018172200000000000000000000000000000000000000000000000000000000001817230000000000000000000000000000000000000000000000000000000000181724000000000000000000000000000000000000000000000000000000000018172500000000000000000000000000000000000000000000000000000000001817260000000000000000000000000000000000000000000000000000000000181727000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f00000000000000000000000000000000000000000000000000000000001817200000000000000000000000000000000000000000000000000000000000181721000000000000000000000000000000000000000000000000000000000018172200000000000000000000000000000000000000000000000000000000001817230000000000000000000000000000000000000000000000000000000000181724000000000000000000000000000000000000000000000000000000000018172500000000000000000000000000000000000000000000000000000000001817260000000000000000000000000000000000000000000000000000000000181727000000000000000000000000000000000000000000000000000000000018172800000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f00000000000000000000000000000000000000000000000000000000001817200000000000000000000000000000000000000000000000000000000000181721000000000000000000000000000000000000000000000000000000000018172200000000000000000000000000000000000000000000000000000000001817230000000000000000000000000000000000000000000000000000000000181724000000000000000000000000000000000000000000000000000000000018172500000000000000000000000000000000000000000000000000000000001817260000000000000000000000000000000000000000000000000000000000181727000000000000000000000000000000000000000000000000000000000018172800000000000000000000000000000000000000000000000000000000001817290000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f0000000000000000000000000000000000000000000000000000000000181720000000000000000000000000000000000000000000000000000000000018172100000000000000000000000000000000000000000000000000000000001817220000000000000000000000000000000000000000000000000000000000181723000000000000000000000000000000000000000000000000000000000018172400000000000000000000000000000000000000000000000000000000001817250000000000000000000000000000000000000000000000000000000000181726000000000000000000000000000000000000000000000000000000000018172700000000000000000000000000000000000000000000000000000000001817280000000000000000000000000000000000000000000000000000000000181729000000000000000000000000000000000000000000000000000000000018172a000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f0000000000000000000000000000000000000000000000000000000000181720000000000000000000000000000000000000000000000000000000000018172100000000000000000000000000000000000000000000000000000000001817220000000000000000000000000000000000000000000000000000000000181723000000000000000000000000000000000000000000000000000000000018172400000000000000000000000000000000000000000000000000000000001817250000000000000000000000000000000000000000000000000000000000181726000000000000000000000000000000000000000000000000000000000018172700000000000000000000000000000000000000000000000000000000001817280000000000000000000000000000000000000000000000000000000000181729000000000000000000000000000000000000000000000000000000000018172a000000000000000000000000000000000000000000000000000000000018172b000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f0000000000000000000000000000000000000000000000000000000000181720000000000000000000000000000000000000000000000000000000000018172100000000000000000000000000000000000000000000000000000000001817220000000000000000000000000000000000000000000000000000000000181723000000000000000000000000000000000000000000000000000000000018172400000000000000000000000000000000000000000000000000000000001817250000000000000000000000000000000000000000000000000000000000181726000000000000000000000000000000000000000000000000000000000018172700000000000000000000000000000000000000000000000000000000001817280000000000000000000000000000000000000000000000000000000000181729000000000000000000000000000000000000000000000000000000000018172a000000000000000000000000000000000000000000000000000000000018172b000000000000000000000000000000000000000000000000000000000018172c000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f0000000000000000000000000000000000000000000000000000000000181720000000000000000000000000000000000000000000000000000000000018172100000000000000000000000000000000000000000000000000000000001817220000000000000000000000000000000000000000000000000000000000181723000000000000000000000000000000000000000000000000000000000018172400000000000000000000000000000000000000000000000000000000001817250000000000000000000000000000000000000000000000000000000000181726000000000000000000000000000000000000000000000000000000000018172700000000000000000000000000000000000000000000000000000000001817280000000000000000000000000000000000000000000000000000000000181729000000000000000000000000000000000000000000000000000000000018172a000000000000000000000000000000000000000000000000000000000018172b000000000000000000000000000000000000000000000000000000000018172c000000000000000000000000000000000000000000000000000000000018172d000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f0000000000000000000000000000000000000000000000000000000000181720000000000000000000000000000000000000000000000000000000000018172100000000000000000000000000000000000000000000000000000000001817220000000000000000000000000000000000000000000000000000000000181723000000000000000000000000000000000000000000000000000000000018172400000000000000000000000000000000000000000000000000000000001817250000000000000000000000000000000000000000000000000000000000181726000000000000000000000000000000000000000000000000000000000018172700000000000000000000000000000000000000000000000000000000001817280000000000000000000000000000000000000000000000000000000000181729000000000000000000000000000000000000000000000000000000000018172a000000000000000000000000000000000000000000000000000000000018172b000000000000000000000000000000000000000000000000000000000018172c000000000000000000000000000000000000000000000000000000000018172d000000000000000000000000000000000000000000000000000000000018172e000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f0000000000000000000000000000000000000000000000000000000000181720000000000000000000000000000000000000000000000000000000000018172100000000000000000000000000000000000000000000000000000000001817220000000000000000000000000000000000000000000000000000000000181723000000000000000000000000000000000000000000000000000000000018172400000000000000000000000000000000000000000000000000000000001817250000000000000000000000000000000000000000000000000000000000181726000000000000000000000000000000000000000000000000000000000018172700000000000000000000000000000000000000000000000000000000001817280000000000000000000000000000000000000000000000000000000000181729000000000000000000000000000000000000000000000000000000000018172a000000000000000000000000000000000000000000000000000000000018172b000000000000000000000000000000000000000000000000000000000018172c000000000000000000000000000000000000000000000000000000000018172d000000000000000000000000000000000000000000000000000000000018172e000000000000000000000000000000000000000000000000000000000018172f000000000000000000000000000000000000000000000000000000000018171f0000000000000000000000000000000000000000000000000000000000181720000000000000000000000000000000000000000000000000000000000018172100000000000000000000000000000000000000000000000000000000001817220000000000000000000000000000000000000000000000000000000000181723000000000000000000000000000000000000000000000000000000000018172400000000000000000000000000000000000000000000000000000000001817250000000000000000000000000000000000000000000000000000000000181726000000000000000000000000000000000000000000000000000000000018172700000000000000000000000000000000000000000000000000000000001817280000000000000000000000000000000000000000000000000000000000181729000000000000000000000000000000000000000000000000000000000018172a000000000000000000000000000000000000000000000000000000000018172b000000000000000000000000000000000000000000000000000000000018172c000000000000000000000000000000000000000000000000000000000018172d000000000000000000000000000000000000000000000000000000000018172e000000000000000000000000000000000000000000000000000000000018172f00000000000000000000000000000000000000000000000000000000001817300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c100100000000000000000000000000000000000000000000000000000000001c100200000000000000000000000000000000000000000000000000000000001c100300000000000000000000000000000000000000000000000000000000001c100400000000000000000000000000000000000000000000000000000000001c100500000000000000000000000000000000000000000000000000000000001c100600000000000000000000000000000000000000000000000000000000001c100700000000000000000000000000000000000000000000000000000000001c100800000000000000000000000000000000000000000000000000000000001c100900000000000000000000000000000000000000000000000000000000001c100a00000000000000000000000000000000000000000000000000000000001c100b00000000000000000000000000000000000000000000000000000000001c100c00000000000000000000000000000000000000000000000000000000001c100d00000000000000000000000000000000000000000000000000000000001c100e00000000000000000000000000000000000000000000000000000000001c100f00000000000000000000000000000000000000000000000000000000001c101000000000000000000000000000000000000000000000000000000000001c101100000000000000000000000000000000000000000000000000000000001c101200000000000000000000000000000000000000000000000000000000001c101300000000000000000000000000000000000000000000000000000000001c101400000000000000000000000000000000000000000000000000000000001c101500000000000000000000000000000000000000000000000000000000001c101600000000000000000000000000000000000000000000000000000000001c101700000000000000000000000000000000000000000000000000000000001c101800000000000000000000000000000000000000000000000000000000001c101900000000000000000000000000000000000000000000000000000000001c101a00000000000000000000000000000000000000000000000000000000001c101b00000000000000000000000000000000000000000000000000000000001c101c00000000000000000000000000000000000000000000000000000000001c101d00000000000000000000000000000000000000000000000000000000001c101e00000000000000000000000000000000000000000000000000000000001c101f00000000000000000000000000000000000000000000000000000000001c102000000000000000000000000000000000000000000000000000000000001c102100000000000000000000000000000000000000000000000000000000001c102200000000000000000000000000000000000000000000000000000000001c102300000000000000000000000000000000000000000000000000000000001c102400000000000000000000000000000000000000000000000000000000001c102500000000000000000000000000000000000000000000000000000000001c102600000000000000000000000000000000000000000000000000000000001c102700000000000000000000000000000000000000000000000000000000001c102800000000000000000000000000000000000000000000000000000000001c102900000000000000000000000000000000000000000000000000000000001c102a00000000000000000000000000000000000000000000000000000000001c102b00000000000000000000000000000000000000000000000000000000001c102c00000000000000000000000000000000000000000000000000000000001c102d00000000000000000000000000000000000000000000000000000000001c102e00000000000000000000000000000000000000000000000000000000001c102f00000000000000000000000000000000000000000000000000000000001c103000000000000000000000000000000000000000000000000000000000001c103100000000000000000000000000000000000000000000000000000000001c103200000000000000000000000000000000000000000000000000000000001c103300000000000000000000000000000000000000000000000000000000001c103400000000000000000000000000000000000000000000000000000000001c103500000000000000000000000000000000000000000000000000000000001c103600000000000000000000000000000000000000000000000000000000001c103700000000000000000000000000000000000000000000000000000000001c103800000000000000000000000000000000000000000000000000000000001c103900000000000000000000000000000000000000000000000000000000001c103a00000000000000000000000000000000000000000000000000000000001c103b00000000000000000000000000000000000000000000000000000000001c103c00000000000000000000000000000000000000000000000000000000001c103d00000000000000000000000000000000000000000000000000000000001c103e00000000000000000000000000000000000000000000000000000000001c103f4000000000000000000000000000000000000000000000000000000000001c000100000000000000000000000000000000000000000000000000000000001c110000000000000000000000000000000000000000000000000000000000001c110100000000000000000000000000000000000000000000000000000000001c110200000000000000000000000000000000000000000000000000000000001c110300000000000000000000000000000000000000000000000000000000001c110400000000000000000000000000000000000000000000000000000000001c110500000000000000000000000000000000000000000000000000000000001c110600000000000000000000000000000000000000000000000000000000001c110700000000000000000000000000000000000000000000000000000000001c110800000000000000000000000000000000000000000000000000000000001c110900000000000000000000000000000000000000000000000000000000001c110a00000000000000000000000000000000000000000000000000000000001c110b00000000000000000000000000000000000000000000000000000000001c110c00000000000000000000000000000000000000000000000000000000001c110d00000000000000000000000000000000000000000000000000000000001c110e00000000000000000000000000000000000000000000000000000000001c110f00000000000000000000000000000000000000000000000000000000001c111000000000000000000000000000000000000000000000000000000000001c111100000000000000000000000000000000000000000000000000000000001c111200000000000000000000000000000000000000000000000000000000001c111300000000000000000000000000000000000000000000000000000000001c111400000000000000000000000000000000000000000000000000000000001c111500000000000000000000000000000000000000000000000000000000001c111600000000000000000000000000000000000000000000000000000000001c111700000000000000000000000000000000000000000000000000000000001c111800000000000000000000000000000000000000000000000000000000001c111900000000000000000000000000000000000000000000000000000000001c111a00000000000000000000000000000000000000000000000000000000001c111b00000000000000000000000000000000000000000000000000000000001c111c00000000000000000000000000000000000000000000000000000000001c111d00000000000000000000000000000000000000000000000000000000001c111e00000000000000000000000000000000000000000000000000000000001c111f00000000000000000000000000000000000000000000000000000000001c112000000000000000000000000000000000000000000000000000000000001c112100000000000000000000000000000000000000000000000000000000001c112200000000000000000000000000000000000000000000000000000000001c112300000000000000000000000000000000000000000000000000000000001c112400000000000000000000000000000000000000000000000000000000001c112500000000000000000000000000000000000000000000000000000000001c112600000000000000000000000000000000000000000000000000000000001c112700000000000000000000000000000000000000000000000000000000001c112800000000000000000000000000000000000000000000000000000000001c112900000000000000000000000000000000000000000000000000000000001c112a00000000000000000000000000000000000000000000000000000000001c112b00000000000000000000000000000000000000000000000000000000001c112c00000000000000000000000000000000000000000000000000000000001c112d00000000000000000000000000000000000000000000000000000000001c112e00000000000000000000000000000000000000000000000000000000001c112f00000000000000000000000000000000000000000000000000000000001c113000000000000000000000000000000000000000000000000000000000001c113100000000000000000000000000000000000000000000000000000000001c113200000000000000000000000000000000000000000000000000000000001c113300000000000000000000000000000000000000000000000000000000001c113400000000000000000000000000000000000000000000000000000000001c113500000000000000000000000000000000000000000000000000000000001c113600000000000000000000000000000000000000000000000000000000001c113700000000000000000000000000000000000000000000000000000000001c113800000000000000000000000000000000000000000000000000000000001c113900000000000000000000000000000000000000000000000000000000001c113a00000000000000000000000000000000000000000000000000000000001c113b00000000000000000000000000000000000000000000000000000000001c113c00000000000000000000000000000000000000000000000000000000001c113d00000000000000000000000000000000000000000000000000000000001c113e08006838aa99533bea0d4204cad17cb3c147e99c2f9089e54a4289d54733eeada2002ab314bd11ace2494a3fb0970d276da39f0fe7da19c9a2438b9c7c334d32470071703d79d8425a7eca52006df6a8f9728508a83639e3e1c2ebae2b853a087c00c9501ac04a78ac5413c9131b08708064ed2c2515b8893f12c2d1cda15a44f100a0955f93e109778d26f9e5b0d46e45c539e59b0941517bfa888eb2d7d2d8a6005adc3be9406cc5f102c6adb44746e8529a256e2396353a8659344cc3e914c4007a5fe572cf6af804f472dabf095c5eb6b30efc5fd627ad3245a8ef0f3f578c003dcaa91dfc9fdad7ba8da68a48fc662dfc0a995cbb0c1bc62099c8257d240d3f00000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c200a00000000000000000000000000000000000000000000000000000000001c200100000000000000000000000000000000000000000000000000000000001c200b00000000000000000000000000000000000000000000000000000000001c200200000000000000000000000000000000000000000000000000000000001c200c00000000000000000000000000000000000000000000000000000000001c200300000000000000000000000000000000000000000000000000000000001c200d00000000000000000000000000000000000000000000000000000000001c200400000000000000000000000000000000000000000000000000000000001c200e00000000000000000000000000000000000000000000000000000000001c200500000000000000000000000000000000000000000000000000000000001c200f00000000000000000000000000000000000000000000000000000000001c200600000000000000000000000000000000000000000000000000000000001c201000000000000000000000000000000000000000000000000000000000001c200700000000000000000000000000000000000000000000000000000000001c201100000000000000000000000000000000000000000000000000000000001c200800000000000000000000000000000000000000000000000000000000001c201200000000000000000000000000000000000000000000000000000000001c200900000000000000000000000000000000000000000000000000000000001c201300000000000000000000000000000000000000000000000000000000001c200a00000000000000000000000000000000000000000000000000000000001c201400000000000000000000000000000000000000000000000000000000001c200b00000000000000000000000000000000000000000000000000000000001c201500000000000000000000000000000000000000000000000000000000001c200c00000000000000000000000000000000000000000000000000000000001c201600000000000000000000000000000000000000000000000000000000001c200d00000000000000000000000000000000000000000000000000000000001c201700000000000000000000000000000000000000000000000000000000001c200e00000000000000000000000000000000000000000000000000000000001c201800000000000000000000000000000000000000000000000000000000001c200f00000000000000000000000000000000000000000000000000000000001c201900000000000000000000000000000000000000000000000000000000001c201000000000000000000000000000000000000000000000000000000000001c201a00000000000000000000000000000000000000000000000000000000001c201100000000000000000000000000000000000000000000000000000000001c201b00000000000000000000000000000000000000000000000000000000001c201200000000000000000000000000000000000000000000000000000000001c201c00000000000000000000000000000000000000000000000000000000001c201300000000000000000000000000000000000000000000000000000000001c201d00000000000000000000000000000000000000000000000000000000001c201400000000000000000000000000000000000000000000000000000000001c201e00000000000000000000000000000000000000000000000000000000001c201500000000000000000000000000000000000000000000000000000000001c201f00000000000000000000000000000000000000000000000000000000001c201600000000000000000000000000000000000000000000000000000000001c202000000000000000000000000000000000000000000000000000000000001c201700000000000000000000000000000000000000000000000000000000001c202100000000000000000000000000000000000000000000000000000000001c201800000000000000000000000000000000000000000000000000000000001c202200000000000000000000000000000000000000000000000000000000001c201900000000000000000000000000000000000000000000000000000000001c202300000000000000000000000000000000000000000000000000000000001c201a00000000000000000000000000000000000000000000000000000000001c202400000000000000000000000000000000000000000000000000000000001c201b00000000000000000000000000000000000000000000000000000000001c202500000000000000000000000000000000000000000000000000000000001c201c00000000000000000000000000000000000000000000000000000000001c202600000000000000000000000000000000000000000000000000000000001c201d00000000000000000000000000000000000000000000000000000000001c202700000000000000000000000000000000000000000000000000000000001c201e00000000000000000000000000000000000000000000000000000000001c202800000000000000000000000000000000000000000000000000000000001c201f00000000000000000000000000000000000000000000000000000000001c202900000000000000000000000000000000000000000000000000000000001c202000000000000000000000000000000000000000000000000000000000001c202a00000000000000000000000000000000000000000000000000000000001c202100000000000000000000000000000000000000000000000000000000001c202b00000000000000000000000000000000000000000000000000000000001c202200000000000000000000000000000000000000000000000000000000001c202c00000000000000000000000000000000000000000000000000000000001c202300000000000000000000000000000000000000000000000000000000001c202d00000000000000000000000000000000000000000000000000000000001c202400000000000000000000000000000000000000000000000000000000001c202e00000000000000000000000000000000000000000000000000000000001c202500000000000000000000000000000000000000000000000000000000001c202f00000000000000000000000000000000000000000000000000000000001c202600000000000000000000000000000000000000000000000000000000001c203000000000000000000000000000000000000000000000000000000000001c202700000000000000000000000000000000000000000000000000000000001c203100000000000000000000000000000000000000000000000000000000001c202800000000000000000000000000000000000000000000000000000000001c203200000000000000000000000000000000000000000000000000000000001c202900000000000000000000000000000000000000000000000000000000001c203300000000000000000000000000000000000000000000000000000000001c202a00000000000000000000000000000000000000000000000000000000001c203400000000000000000000000000000000000000000000000000000000001c202b00000000000000000000000000000000000000000000000000000000001c203500000000000000000000000000000000000000000000000000000000001c202c00000000000000000000000000000000000000000000000000000000001c203600000000000000000000000000000000000000000000000000000000001c202d00000000000000000000000000000000000000000000000000000000001c203700000000000000000000000000000000000000000000000000000000001c202e00000000000000000000000000000000000000000000000000000000001c203800000000000000000000000000000000000000000000000000000000001c202f00000000000000000000000000000000000000000000000000000000001c203900000000000000000000000000000000000000000000000000000000001c203000000000000000000000000000000000000000000000000000000000001c203a00000000000000000000000000000000000000000000000000000000001c203100000000000000000000000000000000000000000000000000000000001c203b00000000000000000000000000000000000000000000000000000000001c203200000000000000000000000000000000000000000000000000000000001c203c00000000000000000000000000000000000000000000000000000000001c203300000000000000000000000000000000000000000000000000000000001c203d00000000000000000000000000000000000000000000000000000000001c203400000000000000000000000000000000000000000000000000000000001c203e00000000000000000000000000000000000000000000000000000000001c203500000000000000000000000000000000000000000000000000000000001c203f00000000000000000000000000000000000000000000000000000000001c203600000000000000000000000000000000000000000000000000000000001c204000000000000000000000000000000000000000000000000000000000001c203700000000000000000000000000000000000000000000000000000000001c204100000000000000000000000000000000000000000000000000000000001c203800000000000000000000000000000000000000000000000000000000001c204200000000000000000000000000000000000000000000000000000000001c203900000000000000000000000000000000000000000000000000000000001c204300000000000000000000000000000000000000000000000000000000001c203a00000000000000000000000000000000000000000000000000000000001c204400000000000000000000000000000000000000000000000000000000001c203b00000000000000000000000000000000000000000000000000000000001c204500000000000000000000000000000000000000000000000000000000001c203c00000000000000000000000000000000000000000000000000000000001c204600000000000000000000000000000000000000000000000000000000001c203d00000000000000000000000000000000000000000000000000000000001c204700000000000000000000000000000000000000000000000000000000001c203e00000000000000000000000000000000000000000000000000000000001c20482000000000000000000000000000000000000000000000000000000000001c170000000000000000000000000000000000000000000000000000000000001c170100000000000000000000000000000000000000000000000000000000001c170200000000000000000000000000000000000000000000000000000000001c170300000000000000000000000000000000000000000000000000000000001c170400000000000000000000000000000000000000000000000000000000001c170500000000000000000000000000000000000000000000000000000000001c170600000000000000000000000000000000000000000000000000000000001c170700000000000000000000000000000000000000000000000000000000001c170800000000000000000000000000000000000000000000000000000000001c170900000000000000000000000000000000000000000000000000000000001c170a00000000000000000000000000000000000000000000000000000000001c170b00000000000000000000000000000000000000000000000000000000001c170c00000000000000000000000000000000000000000000000000000000001c170d00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c170100000000000000000000000000000000000000000000000000000000001c170200000000000000000000000000000000000000000000000000000000001c170300000000000000000000000000000000000000000000000000000000001c170400000000000000000000000000000000000000000000000000000000001c170500000000000000000000000000000000000000000000000000000000001c170600000000000000000000000000000000000000000000000000000000001c170700000000000000000000000000000000000000000000000000000000001c170800000000000000000000000000000000000000000000000000000000001c170900000000000000000000000000000000000000000000000000000000001c170a00000000000000000000000000000000000000000000000000000000001c170b00000000000000000000000000000000000000000000000000000000001c170c00000000000000000000000000000000000000000000000000000000001c170d00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c170200000000000000000000000000000000000000000000000000000000001c170300000000000000000000000000000000000000000000000000000000001c170400000000000000000000000000000000000000000000000000000000001c170500000000000000000000000000000000000000000000000000000000001c170600000000000000000000000000000000000000000000000000000000001c170700000000000000000000000000000000000000000000000000000000001c170800000000000000000000000000000000000000000000000000000000001c170900000000000000000000000000000000000000000000000000000000001c170a00000000000000000000000000000000000000000000000000000000001c170b00000000000000000000000000000000000000000000000000000000001c170c00000000000000000000000000000000000000000000000000000000001c170d00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c170300000000000000000000000000000000000000000000000000000000001c170400000000000000000000000000000000000000000000000000000000001c170500000000000000000000000000000000000000000000000000000000001c170600000000000000000000000000000000000000000000000000000000001c170700000000000000000000000000000000000000000000000000000000001c170800000000000000000000000000000000000000000000000000000000001c170900000000000000000000000000000000000000000000000000000000001c170a00000000000000000000000000000000000000000000000000000000001c170b00000000000000000000000000000000000000000000000000000000001c170c00000000000000000000000000000000000000000000000000000000001c170d00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c170400000000000000000000000000000000000000000000000000000000001c170500000000000000000000000000000000000000000000000000000000001c170600000000000000000000000000000000000000000000000000000000001c170700000000000000000000000000000000000000000000000000000000001c170800000000000000000000000000000000000000000000000000000000001c170900000000000000000000000000000000000000000000000000000000001c170a00000000000000000000000000000000000000000000000000000000001c170b00000000000000000000000000000000000000000000000000000000001c170c00000000000000000000000000000000000000000000000000000000001c170d00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c170500000000000000000000000000000000000000000000000000000000001c170600000000000000000000000000000000000000000000000000000000001c170700000000000000000000000000000000000000000000000000000000001c170800000000000000000000000000000000000000000000000000000000001c170900000000000000000000000000000000000000000000000000000000001c170a00000000000000000000000000000000000000000000000000000000001c170b00000000000000000000000000000000000000000000000000000000001c170c00000000000000000000000000000000000000000000000000000000001c170d00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c170600000000000000000000000000000000000000000000000000000000001c170700000000000000000000000000000000000000000000000000000000001c170800000000000000000000000000000000000000000000000000000000001c170900000000000000000000000000000000000000000000000000000000001c170a00000000000000000000000000000000000000000000000000000000001c170b00000000000000000000000000000000000000000000000000000000001c170c00000000000000000000000000000000000000000000000000000000001c170d00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c170700000000000000000000000000000000000000000000000000000000001c170800000000000000000000000000000000000000000000000000000000001c170900000000000000000000000000000000000000000000000000000000001c170a00000000000000000000000000000000000000000000000000000000001c170b00000000000000000000000000000000000000000000000000000000001c170c00000000000000000000000000000000000000000000000000000000001c170d00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c170800000000000000000000000000000000000000000000000000000000001c170900000000000000000000000000000000000000000000000000000000001c170a00000000000000000000000000000000000000000000000000000000001c170b00000000000000000000000000000000000000000000000000000000001c170c00000000000000000000000000000000000000000000000000000000001c170d00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c170900000000000000000000000000000000000000000000000000000000001c170a00000000000000000000000000000000000000000000000000000000001c170b00000000000000000000000000000000000000000000000000000000001c170c00000000000000000000000000000000000000000000000000000000001c170d00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c170a00000000000000000000000000000000000000000000000000000000001c170b00000000000000000000000000000000000000000000000000000000001c170c00000000000000000000000000000000000000000000000000000000001c170d00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c170b00000000000000000000000000000000000000000000000000000000001c170c00000000000000000000000000000000000000000000000000000000001c170d00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c170c00000000000000000000000000000000000000000000000000000000001c170d00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c170d00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c172700000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c172700000000000000000000000000000000000000000000000000000000001c172800000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c172700000000000000000000000000000000000000000000000000000000001c172800000000000000000000000000000000000000000000000000000000001c172900000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c172700000000000000000000000000000000000000000000000000000000001c172800000000000000000000000000000000000000000000000000000000001c172900000000000000000000000000000000000000000000000000000000001c172a00000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c172700000000000000000000000000000000000000000000000000000000001c172800000000000000000000000000000000000000000000000000000000001c172900000000000000000000000000000000000000000000000000000000001c172a00000000000000000000000000000000000000000000000000000000001c172b00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c172700000000000000000000000000000000000000000000000000000000001c172800000000000000000000000000000000000000000000000000000000001c172900000000000000000000000000000000000000000000000000000000001c172a00000000000000000000000000000000000000000000000000000000001c172b00000000000000000000000000000000000000000000000000000000001c172c00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c172700000000000000000000000000000000000000000000000000000000001c172800000000000000000000000000000000000000000000000000000000001c172900000000000000000000000000000000000000000000000000000000001c172a00000000000000000000000000000000000000000000000000000000001c172b00000000000000000000000000000000000000000000000000000000001c172c00000000000000000000000000000000000000000000000000000000001c172d00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c172700000000000000000000000000000000000000000000000000000000001c172800000000000000000000000000000000000000000000000000000000001c172900000000000000000000000000000000000000000000000000000000001c172a00000000000000000000000000000000000000000000000000000000001c172b00000000000000000000000000000000000000000000000000000000001c172c00000000000000000000000000000000000000000000000000000000001c172d00000000000000000000000000000000000000000000000000000000001c172e00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c172700000000000000000000000000000000000000000000000000000000001c172800000000000000000000000000000000000000000000000000000000001c172900000000000000000000000000000000000000000000000000000000001c172a00000000000000000000000000000000000000000000000000000000001c172b00000000000000000000000000000000000000000000000000000000001c172c00000000000000000000000000000000000000000000000000000000001c172d00000000000000000000000000000000000000000000000000000000001c172e00000000000000000000000000000000000000000000000000000000001c172f00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c172700000000000000000000000000000000000000000000000000000000001c172800000000000000000000000000000000000000000000000000000000001c172900000000000000000000000000000000000000000000000000000000001c172a00000000000000000000000000000000000000000000000000000000001c172b00000000000000000000000000000000000000000000000000000000001c172c00000000000000000000000000000000000000000000000000000000001c172d00000000000000000000000000000000000000000000000000000000001c172e00000000000000000000000000000000000000000000000000000000001c172f00000000000000000000000000000000000000000000000000000000001c1730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000201000000000000000000000000000000000000000000000000000000000000020100100000000000000000000000000000000000000000000000000000000002010020000000000000000000000000000000000000000000000000000000000201003000000000000000000000000000000000000000000000000000000000020100400000000000000000000000000000000000000000000000000000000002010050000000000000000000000000000000000000000000000000000000000201006000000000000000000000000000000000000000000000000000000000020100700000000000000000000000000000000000000000000000000000000002010080000000000000000000000000000000000000000000000000000000000201009000000000000000000000000000000000000000000000000000000000020100a000000000000000000000000000000000000000000000000000000000020100b000000000000000000000000000000000000000000000000000000000020100c000000000000000000000000000000000000000000000000000000000020100d000000000000000000000000000000000000000000000000000000000020100e000000000000000000000000000000000000000000000000000000000020100f0000000000000000000000000000000000000000000000000000000000201010000000000000000000000000000000000000000000000000000000000020101100000000000000000000000000000000000000000000000000000000002010120000000000000000000000000000000000000000000000000000000000201013000000000000000000000000000000000000000000000000000000000020101400000000000000000000000000000000000000000000000000000000002010150000000000000000000000000000000000000000000000000000000000201016000000000000000000000000000000000000000000000000000000000020101700000000000000000000000000000000000000000000000000000000002010180000000000000000000000000000000000000000000000000000000000201019000000000000000000000000000000000000000000000000000000000020101a000000000000000000000000000000000000000000000000000000000020101b000000000000000000000000000000000000000000000000000000000020101c000000000000000000000000000000000000000000000000000000000020101d000000000000000000000000000000000000000000000000000000000020101e000000000000000000000000000000000000000000000000000000000020101f0000000000000000000000000000000000000000000000000000000000201020000000000000000000000000000000000000000000000000000000000020102100000000000000000000000000000000000000000000000000000000002010220000000000000000000000000000000000000000000000000000000000201023000000000000000000000000000000000000000000000000000000000020102400000000000000000000000000000000000000000000000000000000002010250000000000000000000000000000000000000000000000000000000000201026000000000000000000000000000000000000000000000000000000000020102700000000000000000000000000000000000000000000000000000000002010280000000000000000000000000000000000000000000000000000000000201029000000000000000000000000000000000000000000000000000000000020102a000000000000000000000000000000000000000000000000000000000020102b000000000000000000000000000000000000000000000000000000000020102c000000000000000000000000000000000000000000000000000000000020102d000000000000000000000000000000000000000000000000000000000020102e000000000000000000000000000000000000000000000000000000000020102f0000000000000000000000000000000000000000000000000000000000201030000000000000000000000000000000000000000000000000000000000020103100000000000000000000000000000000000000000000000000000000002010320000000000000000000000000000000000000000000000000000000000201033000000000000000000000000000000000000000000000000000000000020103400000000000000000000000000000000000000000000000000000000002010350000000000000000000000000000000000000000000000000000000000201036000000000000000000000000000000000000000000000000000000000020103700000000000000000000000000000000000000000000000000000000002010380000000000000000000000000000000000000000000000000000000000201039000000000000000000000000000000000000000000000000000000000020103a000000000000000000000000000000000000000000000000000000000020103b000000000000000000000000000000000000000000000000000000000020103c000000000000000000000000000000000000000000000000000000000020103d000000000000000000000000000000000000000000000000000000000020103e000000000000000000000000000000000000000000000000000000000020103f4000000000000000000000000000000000000000000000000000000000002000010000000000000000000000000000000000000000000000000000000000201100000000000000000000000000000000000000000000000000000000000020110100000000000000000000000000000000000000000000000000000000002011020000000000000000000000000000000000000000000000000000000000201103000000000000000000000000000000000000000000000000000000000020110400000000000000000000000000000000000000000000000000000000002011050000000000000000000000000000000000000000000000000000000000201106000000000000000000000000000000000000000000000000000000000020110700000000000000000000000000000000000000000000000000000000002011080000000000000000000000000000000000000000000000000000000000201109000000000000000000000000000000000000000000000000000000000020110a000000000000000000000000000000000000000000000000000000000020110b000000000000000000000000000000000000000000000000000000000020110c000000000000000000000000000000000000000000000000000000000020110d000000000000000000000000000000000000000000000000000000000020110e000000000000000000000000000000000000000000000000000000000020110f0000000000000000000000000000000000000000000000000000000000201110000000000000000000000000000000000000000000000000000000000020111100000000000000000000000000000000000000000000000000000000002011120000000000000000000000000000000000000000000000000000000000201113000000000000000000000000000000000000000000000000000000000020111400000000000000000000000000000000000000000000000000000000002011150000000000000000000000000000000000000000000000000000000000201116000000000000000000000000000000000000000000000000000000000020111700000000000000000000000000000000000000000000000000000000002011180000000000000000000000000000000000000000000000000000000000201119000000000000000000000000000000000000000000000000000000000020111a000000000000000000000000000000000000000000000000000000000020111b000000000000000000000000000000000000000000000000000000000020111c000000000000000000000000000000000000000000000000000000000020111d000000000000000000000000000000000000000000000000000000000020111e000000000000000000000000000000000000000000000000000000000020111f0000000000000000000000000000000000000000000000000000000000201120000000000000000000000000000000000000000000000000000000000020112100000000000000000000000000000000000000000000000000000000002011220000000000000000000000000000000000000000000000000000000000201123000000000000000000000000000000000000000000000000000000000020112400000000000000000000000000000000000000000000000000000000002011250000000000000000000000000000000000000000000000000000000000201126000000000000000000000000000000000000000000000000000000000020112700000000000000000000000000000000000000000000000000000000002011280000000000000000000000000000000000000000000000000000000000201129000000000000000000000000000000000000000000000000000000000020112a000000000000000000000000000000000000000000000000000000000020112b000000000000000000000000000000000000000000000000000000000020112c000000000000000000000000000000000000000000000000000000000020112d000000000000000000000000000000000000000000000000000000000020112e000000000000000000000000000000000000000000000000000000000020112f0000000000000000000000000000000000000000000000000000000000201130000000000000000000000000000000000000000000000000000000000020113100000000000000000000000000000000000000000000000000000000002011320000000000000000000000000000000000000000000000000000000000201133000000000000000000000000000000000000000000000000000000000020113400000000000000000000000000000000000000000000000000000000002011350000000000000000000000000000000000000000000000000000000000201136000000000000000000000000000000000000000000000000000000000020113700000000000000000000000000000000000000000000000000000000002011380000000000000000000000000000000000000000000000000000000000201139000000000000000000000000000000000000000000000000000000000020113a000000000000000000000000000000000000000000000000000000000020113b000000000000000000000000000000000000000000000000000000000020113c000000000000000000000000000000000000000000000000000000000020113d000000000000000000000000000000000000000000000000000000000020113e0800e9805e8a4faa87fc419af08a6d956f18976c46ea694bbd4cf6946e6d02033200e0925a6b172b4b01bb76eb1d3f7dd2ced118bca70d223a6d61afa1b75915ae00383590492d2f99a0283d1de57015b4b6b0759a8023af2c68fb4929dee2f303007ed57100dd77e2b6405f780503ef61b7b53e13f344b6e6a6eff3e3c13de0d0001ab1b0c348c46184dbc86ff79f248e7da1b09d3f9c6a986e98fe45389f060d0023d134bc68d7efa25e255001069827dc0bee766c08c988d6300071ed27fe6c0031cbb780b07f632cbaf767dc80608cc0a8e1d1df3ecd6f5d8bc0ca6703e4f4002c7dc9e731fc5f6456b2a70b4e636ac17d5e0cd36d3a591116a9e124f735863f0000000000000000000000000000000000000000000000000000000000202000000000000000000000000000000000000000000000000000000000000020200a0000000000000000000000000000000000000000000000000000000000202001000000000000000000000000000000000000000000000000000000000020200b0000000000000000000000000000000000000000000000000000000000202002000000000000000000000000000000000000000000000000000000000020200c0000000000000000000000000000000000000000000000000000000000202003000000000000000000000000000000000000000000000000000000000020200d0000000000000000000000000000000000000000000000000000000000202004000000000000000000000000000000000000000000000000000000000020200e0000000000000000000000000000000000000000000000000000000000202005000000000000000000000000000000000000000000000000000000000020200f00000000000000000000000000000000000000000000000000000000002020060000000000000000000000000000000000000000000000000000000000202010000000000000000000000000000000000000000000000000000000000020200700000000000000000000000000000000000000000000000000000000002020110000000000000000000000000000000000000000000000000000000000202008000000000000000000000000000000000000000000000000000000000020201200000000000000000000000000000000000000000000000000000000002020090000000000000000000000000000000000000000000000000000000000202013000000000000000000000000000000000000000000000000000000000020200a0000000000000000000000000000000000000000000000000000000000202014000000000000000000000000000000000000000000000000000000000020200b0000000000000000000000000000000000000000000000000000000000202015000000000000000000000000000000000000000000000000000000000020200c0000000000000000000000000000000000000000000000000000000000202016000000000000000000000000000000000000000000000000000000000020200d0000000000000000000000000000000000000000000000000000000000202017000000000000000000000000000000000000000000000000000000000020200e0000000000000000000000000000000000000000000000000000000000202018000000000000000000000000000000000000000000000000000000000020200f00000000000000000000000000000000000000000000000000000000002020190000000000000000000000000000000000000000000000000000000000202010000000000000000000000000000000000000000000000000000000000020201a0000000000000000000000000000000000000000000000000000000000202011000000000000000000000000000000000000000000000000000000000020201b0000000000000000000000000000000000000000000000000000000000202012000000000000000000000000000000000000000000000000000000000020201c0000000000000000000000000000000000000000000000000000000000202013000000000000000000000000000000000000000000000000000000000020201d0000000000000000000000000000000000000000000000000000000000202014000000000000000000000000000000000000000000000000000000000020201e0000000000000000000000000000000000000000000000000000000000202015000000000000000000000000000000000000000000000000000000000020201f00000000000000000000000000000000000000000000000000000000002020160000000000000000000000000000000000000000000000000000000000202020000000000000000000000000000000000000000000000000000000000020201700000000000000000000000000000000000000000000000000000000002020210000000000000000000000000000000000000000000000000000000000202018000000000000000000000000000000000000000000000000000000000020202200000000000000000000000000000000000000000000000000000000002020190000000000000000000000000000000000000000000000000000000000202023000000000000000000000000000000000000000000000000000000000020201a0000000000000000000000000000000000000000000000000000000000202024000000000000000000000000000000000000000000000000000000000020201b0000000000000000000000000000000000000000000000000000000000202025000000000000000000000000000000000000000000000000000000000020201c0000000000000000000000000000000000000000000000000000000000202026000000000000000000000000000000000000000000000000000000000020201d0000000000000000000000000000000000000000000000000000000000202027000000000000000000000000000000000000000000000000000000000020201e0000000000000000000000000000000000000000000000000000000000202028000000000000000000000000000000000000000000000000000000000020201f00000000000000000000000000000000000000000000000000000000002020290000000000000000000000000000000000000000000000000000000000202020000000000000000000000000000000000000000000000000000000000020202a0000000000000000000000000000000000000000000000000000000000202021000000000000000000000000000000000000000000000000000000000020202b0000000000000000000000000000000000000000000000000000000000202022000000000000000000000000000000000000000000000000000000000020202c0000000000000000000000000000000000000000000000000000000000202023000000000000000000000000000000000000000000000000000000000020202d0000000000000000000000000000000000000000000000000000000000202024000000000000000000000000000000000000000000000000000000000020202e0000000000000000000000000000000000000000000000000000000000202025000000000000000000000000000000000000000000000000000000000020202f00000000000000000000000000000000000000000000000000000000002020260000000000000000000000000000000000000000000000000000000000202030000000000000000000000000000000000000000000000000000000000020202700000000000000000000000000000000000000000000000000000000002020310000000000000000000000000000000000000000000000000000000000202028000000000000000000000000000000000000000000000000000000000020203200000000000000000000000000000000000000000000000000000000002020290000000000000000000000000000000000000000000000000000000000202033000000000000000000000000000000000000000000000000000000000020202a0000000000000000000000000000000000000000000000000000000000202034000000000000000000000000000000000000000000000000000000000020202b0000000000000000000000000000000000000000000000000000000000202035000000000000000000000000000000000000000000000000000000000020202c0000000000000000000000000000000000000000000000000000000000202036000000000000000000000000000000000000000000000000000000000020202d0000000000000000000000000000000000000000000000000000000000202037000000000000000000000000000000000000000000000000000000000020202e0000000000000000000000000000000000000000000000000000000000202038000000000000000000000000000000000000000000000000000000000020202f00000000000000000000000000000000000000000000000000000000002020390000000000000000000000000000000000000000000000000000000000202030000000000000000000000000000000000000000000000000000000000020203a0000000000000000000000000000000000000000000000000000000000202031000000000000000000000000000000000000000000000000000000000020203b0000000000000000000000000000000000000000000000000000000000202032000000000000000000000000000000000000000000000000000000000020203c0000000000000000000000000000000000000000000000000000000000202033000000000000000000000000000000000000000000000000000000000020203d0000000000000000000000000000000000000000000000000000000000202034000000000000000000000000000000000000000000000000000000000020203e0000000000000000000000000000000000000000000000000000000000202035000000000000000000000000000000000000000000000000000000000020203f00000000000000000000000000000000000000000000000000000000002020360000000000000000000000000000000000000000000000000000000000202040000000000000000000000000000000000000000000000000000000000020203700000000000000000000000000000000000000000000000000000000002020410000000000000000000000000000000000000000000000000000000000202038000000000000000000000000000000000000000000000000000000000020204200000000000000000000000000000000000000000000000000000000002020390000000000000000000000000000000000000000000000000000000000202043000000000000000000000000000000000000000000000000000000000020203a0000000000000000000000000000000000000000000000000000000000202044000000000000000000000000000000000000000000000000000000000020203b0000000000000000000000000000000000000000000000000000000000202045000000000000000000000000000000000000000000000000000000000020203c0000000000000000000000000000000000000000000000000000000000202046000000000000000000000000000000000000000000000000000000000020203d0000000000000000000000000000000000000000000000000000000000202047000000000000000000000000000000000000000000000000000000000020203e0000000000000000000000000000000000000000000000000000000000202048200000000000000000000000000000000000000000000000000000000000201700000000000000000000000000000000000000000000000000000000000020170100000000000000000000000000000000000000000000000000000000002017020000000000000000000000000000000000000000000000000000000000201703000000000000000000000000000000000000000000000000000000000020170400000000000000000000000000000000000000000000000000000000002017050000000000000000000000000000000000000000000000000000000000201706000000000000000000000000000000000000000000000000000000000020170700000000000000000000000000000000000000000000000000000000002017080000000000000000000000000000000000000000000000000000000000201709000000000000000000000000000000000000000000000000000000000020170a000000000000000000000000000000000000000000000000000000000020170b000000000000000000000000000000000000000000000000000000000020170c000000000000000000000000000000000000000000000000000000000020170d000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f00000000000000000000000000000000000000000000000000000000002017100000000000000000000000000000000000000000000000000000000000201711000000000000000000000000000000000000000000000000000000000020170100000000000000000000000000000000000000000000000000000000002017020000000000000000000000000000000000000000000000000000000000201703000000000000000000000000000000000000000000000000000000000020170400000000000000000000000000000000000000000000000000000000002017050000000000000000000000000000000000000000000000000000000000201706000000000000000000000000000000000000000000000000000000000020170700000000000000000000000000000000000000000000000000000000002017080000000000000000000000000000000000000000000000000000000000201709000000000000000000000000000000000000000000000000000000000020170a000000000000000000000000000000000000000000000000000000000020170b000000000000000000000000000000000000000000000000000000000020170c000000000000000000000000000000000000000000000000000000000020170d000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f00000000000000000000000000000000000000000000000000000000002017100000000000000000000000000000000000000000000000000000000000201711000000000000000000000000000000000000000000000000000000000020171200000000000000000000000000000000000000000000000000000000002017020000000000000000000000000000000000000000000000000000000000201703000000000000000000000000000000000000000000000000000000000020170400000000000000000000000000000000000000000000000000000000002017050000000000000000000000000000000000000000000000000000000000201706000000000000000000000000000000000000000000000000000000000020170700000000000000000000000000000000000000000000000000000000002017080000000000000000000000000000000000000000000000000000000000201709000000000000000000000000000000000000000000000000000000000020170a000000000000000000000000000000000000000000000000000000000020170b000000000000000000000000000000000000000000000000000000000020170c000000000000000000000000000000000000000000000000000000000020170d000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f00000000000000000000000000000000000000000000000000000000002017100000000000000000000000000000000000000000000000000000000000201711000000000000000000000000000000000000000000000000000000000020171200000000000000000000000000000000000000000000000000000000002017130000000000000000000000000000000000000000000000000000000000201703000000000000000000000000000000000000000000000000000000000020170400000000000000000000000000000000000000000000000000000000002017050000000000000000000000000000000000000000000000000000000000201706000000000000000000000000000000000000000000000000000000000020170700000000000000000000000000000000000000000000000000000000002017080000000000000000000000000000000000000000000000000000000000201709000000000000000000000000000000000000000000000000000000000020170a000000000000000000000000000000000000000000000000000000000020170b000000000000000000000000000000000000000000000000000000000020170c000000000000000000000000000000000000000000000000000000000020170d000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f00000000000000000000000000000000000000000000000000000000002017100000000000000000000000000000000000000000000000000000000000201711000000000000000000000000000000000000000000000000000000000020171200000000000000000000000000000000000000000000000000000000002017130000000000000000000000000000000000000000000000000000000000201714000000000000000000000000000000000000000000000000000000000020170400000000000000000000000000000000000000000000000000000000002017050000000000000000000000000000000000000000000000000000000000201706000000000000000000000000000000000000000000000000000000000020170700000000000000000000000000000000000000000000000000000000002017080000000000000000000000000000000000000000000000000000000000201709000000000000000000000000000000000000000000000000000000000020170a000000000000000000000000000000000000000000000000000000000020170b000000000000000000000000000000000000000000000000000000000020170c000000000000000000000000000000000000000000000000000000000020170d000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f00000000000000000000000000000000000000000000000000000000002017100000000000000000000000000000000000000000000000000000000000201711000000000000000000000000000000000000000000000000000000000020171200000000000000000000000000000000000000000000000000000000002017130000000000000000000000000000000000000000000000000000000000201714000000000000000000000000000000000000000000000000000000000020171500000000000000000000000000000000000000000000000000000000002017050000000000000000000000000000000000000000000000000000000000201706000000000000000000000000000000000000000000000000000000000020170700000000000000000000000000000000000000000000000000000000002017080000000000000000000000000000000000000000000000000000000000201709000000000000000000000000000000000000000000000000000000000020170a000000000000000000000000000000000000000000000000000000000020170b000000000000000000000000000000000000000000000000000000000020170c000000000000000000000000000000000000000000000000000000000020170d000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f00000000000000000000000000000000000000000000000000000000002017100000000000000000000000000000000000000000000000000000000000201711000000000000000000000000000000000000000000000000000000000020171200000000000000000000000000000000000000000000000000000000002017130000000000000000000000000000000000000000000000000000000000201714000000000000000000000000000000000000000000000000000000000020171500000000000000000000000000000000000000000000000000000000002017160000000000000000000000000000000000000000000000000000000000201706000000000000000000000000000000000000000000000000000000000020170700000000000000000000000000000000000000000000000000000000002017080000000000000000000000000000000000000000000000000000000000201709000000000000000000000000000000000000000000000000000000000020170a000000000000000000000000000000000000000000000000000000000020170b000000000000000000000000000000000000000000000000000000000020170c000000000000000000000000000000000000000000000000000000000020170d000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f00000000000000000000000000000000000000000000000000000000002017100000000000000000000000000000000000000000000000000000000000201711000000000000000000000000000000000000000000000000000000000020171200000000000000000000000000000000000000000000000000000000002017130000000000000000000000000000000000000000000000000000000000201714000000000000000000000000000000000000000000000000000000000020171500000000000000000000000000000000000000000000000000000000002017160000000000000000000000000000000000000000000000000000000000201717000000000000000000000000000000000000000000000000000000000020170700000000000000000000000000000000000000000000000000000000002017080000000000000000000000000000000000000000000000000000000000201709000000000000000000000000000000000000000000000000000000000020170a000000000000000000000000000000000000000000000000000000000020170b000000000000000000000000000000000000000000000000000000000020170c000000000000000000000000000000000000000000000000000000000020170d000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f00000000000000000000000000000000000000000000000000000000002017100000000000000000000000000000000000000000000000000000000000201711000000000000000000000000000000000000000000000000000000000020171200000000000000000000000000000000000000000000000000000000002017130000000000000000000000000000000000000000000000000000000000201714000000000000000000000000000000000000000000000000000000000020171500000000000000000000000000000000000000000000000000000000002017160000000000000000000000000000000000000000000000000000000000201717000000000000000000000000000000000000000000000000000000000020171800000000000000000000000000000000000000000000000000000000002017080000000000000000000000000000000000000000000000000000000000201709000000000000000000000000000000000000000000000000000000000020170a000000000000000000000000000000000000000000000000000000000020170b000000000000000000000000000000000000000000000000000000000020170c000000000000000000000000000000000000000000000000000000000020170d000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f00000000000000000000000000000000000000000000000000000000002017100000000000000000000000000000000000000000000000000000000000201711000000000000000000000000000000000000000000000000000000000020171200000000000000000000000000000000000000000000000000000000002017130000000000000000000000000000000000000000000000000000000000201714000000000000000000000000000000000000000000000000000000000020171500000000000000000000000000000000000000000000000000000000002017160000000000000000000000000000000000000000000000000000000000201717000000000000000000000000000000000000000000000000000000000020171800000000000000000000000000000000000000000000000000000000002017190000000000000000000000000000000000000000000000000000000000201709000000000000000000000000000000000000000000000000000000000020170a000000000000000000000000000000000000000000000000000000000020170b000000000000000000000000000000000000000000000000000000000020170c000000000000000000000000000000000000000000000000000000000020170d000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f0000000000000000000000000000000000000000000000000000000000201710000000000000000000000000000000000000000000000000000000000020171100000000000000000000000000000000000000000000000000000000002017120000000000000000000000000000000000000000000000000000000000201713000000000000000000000000000000000000000000000000000000000020171400000000000000000000000000000000000000000000000000000000002017150000000000000000000000000000000000000000000000000000000000201716000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020170a000000000000000000000000000000000000000000000000000000000020170b000000000000000000000000000000000000000000000000000000000020170c000000000000000000000000000000000000000000000000000000000020170d000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f0000000000000000000000000000000000000000000000000000000000201710000000000000000000000000000000000000000000000000000000000020171100000000000000000000000000000000000000000000000000000000002017120000000000000000000000000000000000000000000000000000000000201713000000000000000000000000000000000000000000000000000000000020171400000000000000000000000000000000000000000000000000000000002017150000000000000000000000000000000000000000000000000000000000201716000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020170b000000000000000000000000000000000000000000000000000000000020170c000000000000000000000000000000000000000000000000000000000020170d000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f0000000000000000000000000000000000000000000000000000000000201710000000000000000000000000000000000000000000000000000000000020171100000000000000000000000000000000000000000000000000000000002017120000000000000000000000000000000000000000000000000000000000201713000000000000000000000000000000000000000000000000000000000020171400000000000000000000000000000000000000000000000000000000002017150000000000000000000000000000000000000000000000000000000000201716000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020170c000000000000000000000000000000000000000000000000000000000020170d000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f0000000000000000000000000000000000000000000000000000000000201710000000000000000000000000000000000000000000000000000000000020171100000000000000000000000000000000000000000000000000000000002017120000000000000000000000000000000000000000000000000000000000201713000000000000000000000000000000000000000000000000000000000020171400000000000000000000000000000000000000000000000000000000002017150000000000000000000000000000000000000000000000000000000000201716000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020170d000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f0000000000000000000000000000000000000000000000000000000000201710000000000000000000000000000000000000000000000000000000000020171100000000000000000000000000000000000000000000000000000000002017120000000000000000000000000000000000000000000000000000000000201713000000000000000000000000000000000000000000000000000000000020171400000000000000000000000000000000000000000000000000000000002017150000000000000000000000000000000000000000000000000000000000201716000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f0000000000000000000000000000000000000000000000000000000000201710000000000000000000000000000000000000000000000000000000000020171100000000000000000000000000000000000000000000000000000000002017120000000000000000000000000000000000000000000000000000000000201713000000000000000000000000000000000000000000000000000000000020171400000000000000000000000000000000000000000000000000000000002017150000000000000000000000000000000000000000000000000000000000201716000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f000000000000000000000000000000000000000000000000000000000020170f0000000000000000000000000000000000000000000000000000000000201710000000000000000000000000000000000000000000000000000000000020171100000000000000000000000000000000000000000000000000000000002017120000000000000000000000000000000000000000000000000000000000201713000000000000000000000000000000000000000000000000000000000020171400000000000000000000000000000000000000000000000000000000002017150000000000000000000000000000000000000000000000000000000000201716000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f00000000000000000000000000000000000000000000000000000000002017200000000000000000000000000000000000000000000000000000000000201710000000000000000000000000000000000000000000000000000000000020171100000000000000000000000000000000000000000000000000000000002017120000000000000000000000000000000000000000000000000000000000201713000000000000000000000000000000000000000000000000000000000020171400000000000000000000000000000000000000000000000000000000002017150000000000000000000000000000000000000000000000000000000000201716000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f00000000000000000000000000000000000000000000000000000000002017200000000000000000000000000000000000000000000000000000000000201721000000000000000000000000000000000000000000000000000000000020171100000000000000000000000000000000000000000000000000000000002017120000000000000000000000000000000000000000000000000000000000201713000000000000000000000000000000000000000000000000000000000020171400000000000000000000000000000000000000000000000000000000002017150000000000000000000000000000000000000000000000000000000000201716000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f00000000000000000000000000000000000000000000000000000000002017200000000000000000000000000000000000000000000000000000000000201721000000000000000000000000000000000000000000000000000000000020172200000000000000000000000000000000000000000000000000000000002017120000000000000000000000000000000000000000000000000000000000201713000000000000000000000000000000000000000000000000000000000020171400000000000000000000000000000000000000000000000000000000002017150000000000000000000000000000000000000000000000000000000000201716000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f00000000000000000000000000000000000000000000000000000000002017200000000000000000000000000000000000000000000000000000000000201721000000000000000000000000000000000000000000000000000000000020172200000000000000000000000000000000000000000000000000000000002017230000000000000000000000000000000000000000000000000000000000201713000000000000000000000000000000000000000000000000000000000020171400000000000000000000000000000000000000000000000000000000002017150000000000000000000000000000000000000000000000000000000000201716000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f00000000000000000000000000000000000000000000000000000000002017200000000000000000000000000000000000000000000000000000000000201721000000000000000000000000000000000000000000000000000000000020172200000000000000000000000000000000000000000000000000000000002017230000000000000000000000000000000000000000000000000000000000201724000000000000000000000000000000000000000000000000000000000020171400000000000000000000000000000000000000000000000000000000002017150000000000000000000000000000000000000000000000000000000000201716000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f00000000000000000000000000000000000000000000000000000000002017200000000000000000000000000000000000000000000000000000000000201721000000000000000000000000000000000000000000000000000000000020172200000000000000000000000000000000000000000000000000000000002017230000000000000000000000000000000000000000000000000000000000201724000000000000000000000000000000000000000000000000000000000020172500000000000000000000000000000000000000000000000000000000002017150000000000000000000000000000000000000000000000000000000000201716000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f00000000000000000000000000000000000000000000000000000000002017200000000000000000000000000000000000000000000000000000000000201721000000000000000000000000000000000000000000000000000000000020172200000000000000000000000000000000000000000000000000000000002017230000000000000000000000000000000000000000000000000000000000201724000000000000000000000000000000000000000000000000000000000020172500000000000000000000000000000000000000000000000000000000002017260000000000000000000000000000000000000000000000000000000000201716000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f00000000000000000000000000000000000000000000000000000000002017200000000000000000000000000000000000000000000000000000000000201721000000000000000000000000000000000000000000000000000000000020172200000000000000000000000000000000000000000000000000000000002017230000000000000000000000000000000000000000000000000000000000201724000000000000000000000000000000000000000000000000000000000020172500000000000000000000000000000000000000000000000000000000002017260000000000000000000000000000000000000000000000000000000000201727000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f00000000000000000000000000000000000000000000000000000000002017200000000000000000000000000000000000000000000000000000000000201721000000000000000000000000000000000000000000000000000000000020172200000000000000000000000000000000000000000000000000000000002017230000000000000000000000000000000000000000000000000000000000201724000000000000000000000000000000000000000000000000000000000020172500000000000000000000000000000000000000000000000000000000002017260000000000000000000000000000000000000000000000000000000000201727000000000000000000000000000000000000000000000000000000000020172800000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f00000000000000000000000000000000000000000000000000000000002017200000000000000000000000000000000000000000000000000000000000201721000000000000000000000000000000000000000000000000000000000020172200000000000000000000000000000000000000000000000000000000002017230000000000000000000000000000000000000000000000000000000000201724000000000000000000000000000000000000000000000000000000000020172500000000000000000000000000000000000000000000000000000000002017260000000000000000000000000000000000000000000000000000000000201727000000000000000000000000000000000000000000000000000000000020172800000000000000000000000000000000000000000000000000000000002017290000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f0000000000000000000000000000000000000000000000000000000000201720000000000000000000000000000000000000000000000000000000000020172100000000000000000000000000000000000000000000000000000000002017220000000000000000000000000000000000000000000000000000000000201723000000000000000000000000000000000000000000000000000000000020172400000000000000000000000000000000000000000000000000000000002017250000000000000000000000000000000000000000000000000000000000201726000000000000000000000000000000000000000000000000000000000020172700000000000000000000000000000000000000000000000000000000002017280000000000000000000000000000000000000000000000000000000000201729000000000000000000000000000000000000000000000000000000000020172a000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f0000000000000000000000000000000000000000000000000000000000201720000000000000000000000000000000000000000000000000000000000020172100000000000000000000000000000000000000000000000000000000002017220000000000000000000000000000000000000000000000000000000000201723000000000000000000000000000000000000000000000000000000000020172400000000000000000000000000000000000000000000000000000000002017250000000000000000000000000000000000000000000000000000000000201726000000000000000000000000000000000000000000000000000000000020172700000000000000000000000000000000000000000000000000000000002017280000000000000000000000000000000000000000000000000000000000201729000000000000000000000000000000000000000000000000000000000020172a000000000000000000000000000000000000000000000000000000000020172b000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f0000000000000000000000000000000000000000000000000000000000201720000000000000000000000000000000000000000000000000000000000020172100000000000000000000000000000000000000000000000000000000002017220000000000000000000000000000000000000000000000000000000000201723000000000000000000000000000000000000000000000000000000000020172400000000000000000000000000000000000000000000000000000000002017250000000000000000000000000000000000000000000000000000000000201726000000000000000000000000000000000000000000000000000000000020172700000000000000000000000000000000000000000000000000000000002017280000000000000000000000000000000000000000000000000000000000201729000000000000000000000000000000000000000000000000000000000020172a000000000000000000000000000000000000000000000000000000000020172b000000000000000000000000000000000000000000000000000000000020172c000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f0000000000000000000000000000000000000000000000000000000000201720000000000000000000000000000000000000000000000000000000000020172100000000000000000000000000000000000000000000000000000000002017220000000000000000000000000000000000000000000000000000000000201723000000000000000000000000000000000000000000000000000000000020172400000000000000000000000000000000000000000000000000000000002017250000000000000000000000000000000000000000000000000000000000201726000000000000000000000000000000000000000000000000000000000020172700000000000000000000000000000000000000000000000000000000002017280000000000000000000000000000000000000000000000000000000000201729000000000000000000000000000000000000000000000000000000000020172a000000000000000000000000000000000000000000000000000000000020172b000000000000000000000000000000000000000000000000000000000020172c000000000000000000000000000000000000000000000000000000000020172d000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f0000000000000000000000000000000000000000000000000000000000201720000000000000000000000000000000000000000000000000000000000020172100000000000000000000000000000000000000000000000000000000002017220000000000000000000000000000000000000000000000000000000000201723000000000000000000000000000000000000000000000000000000000020172400000000000000000000000000000000000000000000000000000000002017250000000000000000000000000000000000000000000000000000000000201726000000000000000000000000000000000000000000000000000000000020172700000000000000000000000000000000000000000000000000000000002017280000000000000000000000000000000000000000000000000000000000201729000000000000000000000000000000000000000000000000000000000020172a000000000000000000000000000000000000000000000000000000000020172b000000000000000000000000000000000000000000000000000000000020172c000000000000000000000000000000000000000000000000000000000020172d000000000000000000000000000000000000000000000000000000000020172e000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f0000000000000000000000000000000000000000000000000000000000201720000000000000000000000000000000000000000000000000000000000020172100000000000000000000000000000000000000000000000000000000002017220000000000000000000000000000000000000000000000000000000000201723000000000000000000000000000000000000000000000000000000000020172400000000000000000000000000000000000000000000000000000000002017250000000000000000000000000000000000000000000000000000000000201726000000000000000000000000000000000000000000000000000000000020172700000000000000000000000000000000000000000000000000000000002017280000000000000000000000000000000000000000000000000000000000201729000000000000000000000000000000000000000000000000000000000020172a000000000000000000000000000000000000000000000000000000000020172b000000000000000000000000000000000000000000000000000000000020172c000000000000000000000000000000000000000000000000000000000020172d000000000000000000000000000000000000000000000000000000000020172e000000000000000000000000000000000000000000000000000000000020172f000000000000000000000000000000000000000000000000000000000020171f0000000000000000000000000000000000000000000000000000000000201720000000000000000000000000000000000000000000000000000000000020172100000000000000000000000000000000000000000000000000000000002017220000000000000000000000000000000000000000000000000000000000201723000000000000000000000000000000000000000000000000000000000020172400000000000000000000000000000000000000000000000000000000002017250000000000000000000000000000000000000000000000000000000000201726000000000000000000000000000000000000000000000000000000000020172700000000000000000000000000000000000000000000000000000000002017280000000000000000000000000000000000000000000000000000000000201729000000000000000000000000000000000000000000000000000000000020172a000000000000000000000000000000000000000000000000000000000020172b000000000000000000000000000000000000000000000000000000000020172c000000000000000000000000000000000000000000000000000000000020172d000000000000000000000000000000000000000000000000000000000020172e000000000000000000000000000000000000000000000000000000000020172f0000000000000000000000000000000000000000000000000000000000201730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "txsEffectsHash": "0x0061d3e24f48b36153518068bf23cd75841f8fbb806641d019a33be2078d3a3e", "decodedHeader": { "contentCommitment": { "inHash": "0x00e1371045bd7d2c3e1f19cba5f536f0e82042ba4bc257d4ba19c146215e8242", "outHash": "0x00a5c37986316b1f5f2df53fa9ddf4965f539e872f5e1374f28d225540faca26", "numTxs": 4, - "txsEffectsHash": "0x00e0afd1e2cddfe35e364bde6047d93fec56b54e7b925edc28b31546b645822d" + "txsEffectsHash": "0x0061d3e24f48b36153518068bf23cd75841f8fbb806641d019a33be2078d3a3e" }, "globalVariables": { "blockNumber": 2, "slotNumber": "0x0000000000000000000000000000000000000000000000000000000000000023", "chainId": 31337, - "timestamp": 1732579254, + "timestamp": 1732895164, "version": 1, - "coinbase": "0x7bf63a9118e60cc630c4faa654223f715d4bd20e", - "feeRecipient": "0x2f2bacf41d88061f8a9e9234dfb8f6cdf5287e15eeeb4a6af5b0691d846bad5d", + "coinbase": "0x6bb9503e73901291188976cb74f3ee186877aed7", + "feeRecipient": "0x1560bcdb97a3f65361a878c5fde7c89bd762de8a4e92dd872bb5e1f39f86d30c", "gasFees": { "feePerDaGas": 0, - "feePerL2Gas": 54154341830 + "feePerL2Gas": 54154247370 } }, "totalFees": "0x0000000000000000000000000000000000000000000000000000000000000000", "totalManaUsed": "0x0000000000000000000000000000000000000000000000000000000000000000", "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x0dd5f1f4c97e09c3d85323d27343341b245c49c5e7032c43c8b7c70d8b79629a" + "root": "0x1cff61d39a2f942d4f96fe19dd6acba151dda8180b9251f5db3ad4865ff4cbf7" }, "stateReference": { "l1ToL2MessageTree": { @@ -100,7 +100,7 @@ }, "nullifierTree": { "nextAvailableLeafIndex": 640, - "root": "0x2ed5c359f01d6a1cacfa324bc48b7fcc6fe75a95ad66bdb1a6e32d6907550957" + "root": "0x137a2b2aa3dc64677f9670d964242d8fbf9fbabaa6b05e2c910eb0cb0f7cc3be" }, "publicDataTree": { "nextAvailableLeafIndex": 632, @@ -109,8 +109,8 @@ } } }, - "header": "0x0dd5f1f4c97e09c3d85323d27343341b245c49c5e7032c43c8b7c70d8b79629a00000002000000000000000000000000000000000000000000000000000000000000000400e0afd1e2cddfe35e364bde6047d93fec56b54e7b925edc28b31546b645822d00e1371045bd7d2c3e1f19cba5f536f0e82042ba4bc257d4ba19c146215e824200a5c37986316b1f5f2df53fa9ddf4965f539e872f5e1374f28d225540faca26026efb6c2a517de2448119d0f1255757265dbec7cdd2952df929ede666e10944000000202494d2575971bca59a28ddc774d19136f4a294951ab67258c7e9c2d8f9805924000002002ed5c359f01d6a1cacfa324bc48b7fcc6fe75a95ad66bdb1a6e32d6907550957000002800c5783f9fe3a18bb5abd12daca67d280f6b5dfef250b7433dc059ce0d868b319000002780000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000230000000000000000000000000000000000000000000000000000000067450fb67bf63a9118e60cc630c4faa654223f715d4bd20e2f2bacf41d88061f8a9e9234dfb8f6cdf5287e15eeeb4a6af5b0691d846bad5d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c9bd9adc600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x00b2ae527c16d61b9ab56a964e90e6cf16142b95d0fc73dd966e5748c296c197", + "header": "0x1cff61d39a2f942d4f96fe19dd6acba151dda8180b9251f5db3ad4865ff4cbf70000000200000000000000000000000000000000000000000000000000000000000000040061d3e24f48b36153518068bf23cd75841f8fbb806641d019a33be2078d3a3e00e1371045bd7d2c3e1f19cba5f536f0e82042ba4bc257d4ba19c146215e824200a5c37986316b1f5f2df53fa9ddf4965f539e872f5e1374f28d225540faca26026efb6c2a517de2448119d0f1255757265dbec7cdd2952df929ede666e10944000000202494d2575971bca59a28ddc774d19136f4a294951ab67258c7e9c2d8f980592400000200137a2b2aa3dc64677f9670d964242d8fbf9fbabaa6b05e2c910eb0cb0f7cc3be000002800c5783f9fe3a18bb5abd12daca67d280f6b5dfef250b7433dc059ce0d868b319000002780000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000023000000000000000000000000000000000000000000000000000000006749e1bc6bb9503e73901291188976cb74f3ee186877aed71560bcdb97a3f65361a878c5fde7c89bd762de8a4e92dd872bb5e1f39f86d30c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c9bd83cca00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x00e2042e2204e7779eaa579f3ef5cfae2100db38ccdc0f345793849673a0d5cb", "numTxs": 4 } } \ No newline at end of file diff --git a/noir-projects/aztec-nr/.gitrepo b/noir-projects/aztec-nr/.gitrepo index 5d7bcc0557d..4696364255e 100644 --- a/noir-projects/aztec-nr/.gitrepo +++ b/noir-projects/aztec-nr/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/aztec-nr branch = master - commit = 3d8f1980d1a62c2e4255135a5c10d93755776679 + commit = 6344f8f2ef40886a0047d49c5685adec9ff1911f method = merge cmdver = 0.4.6 - parent = 8e7c4b1fadd98fc0345705ee243d76eb5cc2008f + parent = b535302b6f9b3ff8d27c1c104060ab7b19af0fb7 diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index ba902167bf4..8284ebc74df 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -12,7 +12,6 @@ use crate::{ }, header::get_header_at, key_validation_request::get_key_validation_request, - logs::{emit_encrypted_event_log, emit_encrypted_note_log}, returns::pack_returns, }, }; @@ -20,12 +19,14 @@ use dep::protocol_types::{ abis::{ call_context::CallContext, function_selector::FunctionSelector, - log_hash::{EncryptedLogHash, LogHash, NoteLogHash}, + log::Log, + log_hash::LogHash, max_block_number::MaxBlockNumber, note_hash::NoteHash, nullifier::Nullifier, private_call_request::PrivateCallRequest, private_circuit_public_inputs::PrivateCircuitPublicInputs, + private_log::PrivateLogData, public_call_request::PublicCallRequest, read_request::ReadRequest, side_effect::Counted, @@ -33,11 +34,12 @@ use dep::protocol_types::{ }, address::{AztecAddress, EthAddress}, constants::{ - MAX_CONTRACT_CLASS_LOGS_PER_CALL, MAX_ENCRYPTED_LOGS_PER_CALL, MAX_ENQUEUED_CALLS_PER_CALL, + MAX_CONTRACT_CLASS_LOGS_PER_CALL, MAX_ENQUEUED_CALLS_PER_CALL, MAX_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_L2_TO_L1_MSGS_PER_CALL, - MAX_NOTE_ENCRYPTED_LOGS_PER_CALL, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, - MAX_NOTE_HASHES_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIERS_PER_CALL, - MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, PUBLIC_DISPATCH_SELECTOR, + MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NOTE_HASHES_PER_CALL, + MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIERS_PER_CALL, + MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PRIVATE_LOGS_PER_CALL, + PRIVATE_LOG_SIZE_IN_FIELDS, PUBLIC_DISPATCH_SELECTOR, }, header::Header, messaging::l2_to_l1_message::L2ToL1Message, @@ -74,8 +76,7 @@ pub struct PrivateContext { // Header of a block whose state is used during private execution (not the block the transaction is included in). pub historical_header: Header, - pub note_encrypted_logs_hashes: BoundedVec, - pub encrypted_logs_hashes: BoundedVec, + pub private_logs: BoundedVec, pub contract_class_logs_hashes: BoundedVec, // Contains the last key validation request for each key type. This is used to cache the last request and avoid @@ -104,8 +105,7 @@ impl PrivateContext { public_call_requests: BoundedVec::new(), public_teardown_call_request: PublicCallRequest::empty(), l2_to_l1_msgs: BoundedVec::new(), - note_encrypted_logs_hashes: BoundedVec::new(), - encrypted_logs_hashes: BoundedVec::new(), + private_logs: BoundedVec::new(), contract_class_logs_hashes: BoundedVec::new(), last_key_validation_requests: [Option::none(); NUM_KEY_TYPES], } @@ -193,8 +193,7 @@ impl PrivateContext { l2_to_l1_msgs: self.l2_to_l1_msgs.storage(), start_side_effect_counter: self.inputs.start_side_effect_counter, end_side_effect_counter: self.side_effect_counter, - note_encrypted_logs_hashes: self.note_encrypted_logs_hashes.storage(), - encrypted_logs_hashes: self.encrypted_logs_hashes.storage(), + private_logs: self.private_logs.storage(), contract_class_logs_hashes: self.contract_class_logs_hashes.storage(), historical_header: self.historical_header, tx_context: self.inputs.tx_context, @@ -304,35 +303,20 @@ impl PrivateContext { } // docs:end:consume_l1_to_l2_message - // NB: A randomness value of 0 signals that the kernels should not mask the contract address - // used in siloing later on e.g. 'handshaking' contract w/ known address. - pub fn emit_raw_event_log_with_masked_address( - &mut self, - randomness: Field, - log: [u8; M], - log_hash: Field, - ) { + pub fn emit_private_log(&mut self, log: [Field; PRIVATE_LOG_SIZE_IN_FIELDS]) { let counter = self.next_counter(); - let contract_address = self.this_address(); - let len = log.len() as Field + 4; - let side_effect = EncryptedLogHash { value: log_hash, counter, length: len, randomness }; - self.encrypted_logs_hashes.push(side_effect); - - emit_encrypted_event_log(contract_address, randomness, log, counter); + let private_log = PrivateLogData { log: Log::new(log), note_hash_counter: 0, counter }; + self.private_logs.push(private_log); } - pub fn emit_raw_note_log( + pub fn emit_raw_note_log( &mut self, + log: [Field; PRIVATE_LOG_SIZE_IN_FIELDS], note_hash_counter: u32, - log: [u8; M], - log_hash: Field, ) { let counter = self.next_counter(); - let len = log.len() as Field + 4; - let side_effect = NoteLogHash { value: log_hash, counter, length: len, note_hash_counter }; - self.note_encrypted_logs_hashes.push(side_effect); - - emit_encrypted_note_log(note_hash_counter, log, counter); + let private_log = PrivateLogData { log: Log::new(log), note_hash_counter, counter }; + self.private_logs.push(private_log); } pub fn call_private_function( @@ -602,8 +586,7 @@ impl Empty for PrivateContext { public_teardown_call_request: PublicCallRequest::empty(), l2_to_l1_msgs: BoundedVec::new(), historical_header: Header::empty(), - note_encrypted_logs_hashes: BoundedVec::new(), - encrypted_logs_hashes: BoundedVec::new(), + private_logs: BoundedVec::new(), contract_class_logs_hashes: BoundedVec::new(), last_key_validation_requests: [Option::none(); NUM_KEY_TYPES], } diff --git a/noir-projects/aztec-nr/aztec/src/encrypted_logs/encrypted_event_emission.nr b/noir-projects/aztec-nr/aztec/src/encrypted_logs/encrypted_event_emission.nr index c8e2bfe6ebe..b80e3c90d24 100644 --- a/noir-projects/aztec-nr/aztec/src/encrypted_logs/encrypted_event_emission.nr +++ b/noir-projects/aztec-nr/aztec/src/encrypted_logs/encrypted_event_emission.nr @@ -1,61 +1,48 @@ use crate::{ context::PrivateContext, encrypted_logs::payload::compute_private_log_payload, - event::event_interface::EventInterface, keys::getters::get_ovsk_app, oracle::random::random, + event::event_interface::EventInterface, keys::getters::get_ovsk_app, }; use dep::protocol_types::{ - address::AztecAddress, constants::PRIVATE_LOG_SIZE_IN_BYTES, hash::sha256_to_field, - public_keys::OvpkM, + address::AztecAddress, constants::PRIVATE_LOG_SIZE_IN_FIELDS, public_keys::OvpkM, }; /// Computes private event log payload and a log hash -fn compute_payload_and_hash( +fn compute_payload( context: PrivateContext, event: Event, - randomness: Field, ovsk_app: Field, ovpk: OvpkM, recipient: AztecAddress, sender: AztecAddress, -) -> ([u8; PRIVATE_LOG_SIZE_IN_BYTES], Field) +) -> [Field; PRIVATE_LOG_SIZE_IN_FIELDS] where Event: EventInterface, { let contract_address: AztecAddress = context.this_address(); - let plaintext = event.private_to_be_bytes(randomness); + let plaintext = event.to_be_bytes(); - let encrypted_log = compute_private_log_payload( + compute_private_log_payload( contract_address, ovsk_app, ovpk, recipient, sender, plaintext, - ); - let log_hash = sha256_to_field(encrypted_log); - (encrypted_log, log_hash) + ) } -unconstrained fn compute_payload_and_hash_unconstrained( +unconstrained fn compute_payload_unconstrained( context: PrivateContext, event: Event, - randomness: Field, ovpk: OvpkM, recipient: AztecAddress, sender: AztecAddress, -) -> ([u8; PRIVATE_LOG_SIZE_IN_BYTES], Field) +) -> [Field; PRIVATE_LOG_SIZE_IN_FIELDS] where Event: EventInterface, { let ovsk_app = get_ovsk_app(ovpk.hash()); - compute_payload_and_hash( - context, - event, - randomness, - ovsk_app, - ovpk, - recipient, - sender, - ) + compute_payload(context, event, ovsk_app, ovpk, recipient, sender) } pub fn encode_and_encrypt_event( @@ -68,15 +55,9 @@ where Event: EventInterface, { |e: Event| { - // We use the randomness to preserve function privacy by making it non brute-forceable, so a malicious sender could - // use non-random values to reveal the plaintext. But they already know it themselves anyway, and is presumably not - // interested in disclosing this information. We can therefore assume that the sender will cooperate in the random - // value generation. - let randomness = unsafe { random() }; let ovsk_app: Field = context.request_ovsk_app(ovpk.hash()); - let (encrypted_log, log_hash) = - compute_payload_and_hash(*context, e, randomness, ovsk_app, ovpk, recipient, sender); - context.emit_raw_event_log_with_masked_address(randomness, encrypted_log, log_hash); + let encrypted_log = compute_payload(*context, e, ovsk_app, ovpk, recipient, sender); + context.emit_private_log(encrypted_log); } } @@ -90,67 +71,10 @@ where Event: EventInterface, { |e: Event| { - // We use the randomness to preserve function privacy by making it non brute-forceable, so a malicious sender could - // use non-random values to reveal the plaintext. But they already know it themselves anyway, and is presumably not - // interested in disclosing this information. We can therefore assume that the sender will cooperate in the random - // value generation. - let randomness = unsafe { random() }; - let (encrypted_log, log_hash) = unsafe { - compute_payload_and_hash_unconstrained(*context, e, randomness, ovpk, recipient, sender) - }; - context.emit_raw_event_log_with_masked_address(randomness, encrypted_log, log_hash); - } -} - -// This function seems to be affected by the following Noir bug: -// https://github.com/noir-lang/noir/issues/5771 -// If you get weird behavior it might be because of it. -pub fn encode_and_encrypt_event_with_randomness( - context: &mut PrivateContext, - randomness: Field, - ovpk: OvpkM, - recipient: AztecAddress, - sender: AztecAddress, -) -> fn[(&mut PrivateContext, OvpkM, Field, AztecAddress, AztecAddress)](Event) -> () -where - Event: EventInterface, -{ - |e: Event| { - let ovsk_app: Field = context.request_ovsk_app(ovpk.hash()); - let (encrypted_log, log_hash) = - compute_payload_and_hash(*context, e, randomness, ovsk_app, ovpk, recipient, sender); - context.emit_raw_event_log_with_masked_address(randomness, encrypted_log, log_hash); - } -} - -pub fn encode_and_encrypt_event_with_randomness_unconstrained( - context: &mut PrivateContext, - randomness: Field, - ovpk: OvpkM, - recipient: AztecAddress, - sender: AztecAddress, -) -> fn[(&mut PrivateContext, Field, OvpkM, AztecAddress, AztecAddress)](Event) -> () -where - Event: EventInterface, -{ - |e: Event| { - // Having the log hash be unconstrained here is fine because the way this works is we send the log hash - // to the kernel, and it gets included as part of its public inputs. Then we send the tx to the sequencer, - // which includes the kernel proof and the log preimages. The sequencer computes the hashes of the logs - // and checks that they are the ones in the public inputs of the kernel, and drops the tx otherwise (proposing - // the block on L1 would later fail if it didn't because of txs effects hash mismatch). - // So if we don't constrain the log hash, then a malicious sender can compute the correct log, submit a bad - // log hash to the kernel, and then submit the bad log preimage to the sequencer. All checks will pass, but - // the submitted log will not be the one that was computed by the app. - // In the unconstrained case, we don't care about the log at all because we don't do anything with it, - // and because it's unconstrained: it could be anything. So if a sender chooses to broadcast the tx with a log - // that is different from the one that was used in the circuit, then they'll be able to, but they were already - // able to change the log before anyway, so the end result is the same. It's important here that we do not - // return the log from this function to the app, otherwise it could try to do stuff with it and then that might - // be wrong. - let (encrypted_log, log_hash) = unsafe { - compute_payload_and_hash_unconstrained(*context, e, randomness, ovpk, recipient, sender) - }; - context.emit_raw_event_log_with_masked_address(randomness, encrypted_log, log_hash); + // Unconstrained logs have both their content and encryption unconstrained - it could occur that the + // recipient is unable to decrypt the payload. + let encrypted_log = + unsafe { compute_payload_unconstrained(*context, e, ovpk, recipient, sender) }; + context.emit_private_log(encrypted_log); } } diff --git a/noir-projects/aztec-nr/aztec/src/encrypted_logs/encrypted_note_emission.nr b/noir-projects/aztec-nr/aztec/src/encrypted_logs/encrypted_note_emission.nr index c538adeddb2..a089813de5f 100644 --- a/noir-projects/aztec-nr/aztec/src/encrypted_logs/encrypted_note_emission.nr +++ b/noir-projects/aztec-nr/aztec/src/encrypted_logs/encrypted_note_emission.nr @@ -5,19 +5,19 @@ use crate::{ note::{note_emission::NoteEmission, note_interface::NoteInterface}, }; use dep::protocol_types::{ - abis::note_hash::NoteHash, address::AztecAddress, constants::PRIVATE_LOG_SIZE_IN_BYTES, - hash::sha256_to_field, public_keys::OvpkM, + abis::note_hash::NoteHash, address::AztecAddress, constants::PRIVATE_LOG_SIZE_IN_FIELDS, + public_keys::OvpkM, }; -/// Computes private note log payload and a log hash -fn compute_payload_and_hash( +/// Computes private note log payload +fn compute_payload( context: PrivateContext, note: Note, ovsk_app: Field, ovpk: OvpkM, recipient: AztecAddress, sender: AztecAddress, -) -> (u32, [u8; PRIVATE_LOG_SIZE_IN_BYTES], Field) +) -> ([Field; PRIVATE_LOG_SIZE_IN_FIELDS], u32) where Note: NoteInterface, { @@ -34,7 +34,7 @@ where let plaintext = note.to_be_bytes(storage_slot); - let encrypted_log = compute_private_log_payload( + let payload = compute_private_log_payload( contract_address, ovsk_app, ovpk, @@ -42,23 +42,22 @@ where sender, plaintext, ); - let log_hash = sha256_to_field(encrypted_log); - (note_hash_counter, encrypted_log, log_hash) + (payload, note_hash_counter) } -unconstrained fn compute_payload_and_hash_unconstrained( +unconstrained fn compute_payload_unconstrained( context: PrivateContext, note: Note, ovpk: OvpkM, recipient: AztecAddress, sender: AztecAddress, -) -> (u32, [u8; PRIVATE_LOG_SIZE_IN_BYTES], Field) +) -> ([Field; PRIVATE_LOG_SIZE_IN_FIELDS], u32) where Note: NoteInterface, { let ovsk_app = get_ovsk_app(ovpk.hash()); - compute_payload_and_hash(context, note, ovsk_app, ovpk, recipient, sender) + compute_payload(context, note, ovsk_app, ovpk, recipient, sender) } // This function seems to be affected by the following Noir bug: @@ -77,9 +76,9 @@ where |e: NoteEmission| { let ovsk_app: Field = context.request_ovsk_app(ovpk.hash()); - let (note_hash_counter, encrypted_log, log_hash) = - compute_payload_and_hash(*context, e.note, ovsk_app, ovpk, recipient, sender); - context.emit_raw_note_log(note_hash_counter, encrypted_log, log_hash); + let (encrypted_log, note_hash_counter) = + compute_payload(*context, e.note, ovsk_app, ovpk, recipient, sender); + context.emit_raw_note_log(encrypted_log, note_hash_counter); } } @@ -94,28 +93,18 @@ where Note: NoteInterface, { |e: NoteEmission| { - // Having the log hash be unconstrained here is fine because the way this works is we send the log hash - // to the kernel, and it gets included as part of its public inputs. Then we send the tx to the sequencer, - // which includes the kernel proof and the log preimages. The sequencer computes the hashes of the logs - // and checks that they are the ones in the public inputs of the kernel, and drops the tx otherwise (proposing - // the block on L1 would later fail if it didn't because of txs effects hash mismatch). - // So if we don't constrain the log hash, then a malicious sender can compute the correct log, submit a bad - // log hash to the kernel, and then submit the bad log preimage to the sequencer. All checks will pass, but - // the submitted log will not be the one that was computed by the app. - // In the unconstrained case, we don't care about the log at all because we don't do anything with it, - // and because it's unconstrained: it could be anything. So if a sender chooses to broadcast the tx with a log - // that is different from the one that was used in the circuit, then they'll be able to, but they were already - // able to change the log before anyway, so the end result is the same. It's important here that we do not - // return the log from this function to the app, otherwise it could try to do stuff with it and then that might - // be wrong. + // Unconstrained logs have both their content and encryption unconstrained - it could occur that the + // recipient is unable to decrypt the payload. // Regarding the note hash counter, this is used for squashing. The kernel assumes that a given note can have // more than one log and removes all of the matching ones, so all a malicious sender could do is either: cause // for the log to be deleted when it shouldn't have (which is fine - they can already make the content be // whatever), or cause for the log to not be deleted when it should have (which is also fine - it'll be a log // for a note that doesn't exist). - let (note_hash_counter, encrypted_log, log_hash) = unsafe { - compute_payload_and_hash_unconstrained(*context, e.note, ovpk, recipient, sender) - }; - context.emit_raw_note_log(note_hash_counter, encrypted_log, log_hash); + // It's important here that we do not + // return the log from this function to the app, otherwise it could try to do stuff with it and then that might + // be wrong. + let (encrypted_log, note_hash_counter) = + unsafe { compute_payload_unconstrained(*context, e.note, ovpk, recipient, sender) }; + context.emit_raw_note_log(encrypted_log, note_hash_counter); } } diff --git a/noir-projects/aztec-nr/aztec/src/encrypted_logs/payload.nr b/noir-projects/aztec-nr/aztec/src/encrypted_logs/payload.nr index 264f2898ec8..e93cb55b3a3 100644 --- a/noir-projects/aztec-nr/aztec/src/encrypted_logs/payload.nr +++ b/noir-projects/aztec-nr/aztec/src/encrypted_logs/payload.nr @@ -1,10 +1,11 @@ use dep::protocol_types::{ address::AztecAddress, - constants::{GENERATOR_INDEX__SYMMETRIC_KEY, PRIVATE_LOG_SIZE_IN_BYTES}, - hash::poseidon2_hash_with_separator, + constants::{GENERATOR_INDEX__SYMMETRIC_KEY, PRIVATE_LOG_SIZE_IN_FIELDS}, + hash::{poseidon2_hash, poseidon2_hash_with_separator}, point::Point, public_keys::{AddressPoint, OvpkM}, scalar::Scalar, + utils::arrays::array_concat, }; use std::{ aes128::aes128_encrypt, embedded_curve_ops::fixed_base_scalar_mul as derive_public_key, @@ -15,33 +16,36 @@ use crate::{ encrypted_logs::header::EncryptedLogHeader, keys::point_to_symmetric_key::point_to_symmetric_key, oracle::{ - notes::{get_app_tag_bytes_as_sender, increment_app_tagging_secret_index_as_sender}, + notes::{get_app_tag_as_sender, increment_app_tagging_secret_index_as_sender}, random::random, }, - utils::point::point_to_bytes, + utils::{bytes::bytes_to_fields, point::point_to_bytes}, }; -pub comptime global PRIVATE_LOG_OVERHEAD_IN_BYTES: u32 = 304; +// 1 field is reserved for tag. +global ENCRYPTED_PAYLOAD_SIZE_IN_BYTES: u32 = (PRIVATE_LOG_SIZE_IN_FIELDS - 1) * 31; -// 1 byte for storage slot, 1 byte for note type id, allowing 6 bytes for custom note fields. -global MAX_PRIVATE_LOG_PLAINTEXT_SIZE_IN_BYTES: u32 = 8 * 32; +comptime global HEADER_SIZE: u32 = 48; -global MAX_PRIVATE_EVENT_LOG_PLAINTEXT_SIZE_IN_BYTES: u32 = - MAX_PRIVATE_LOG_PLAINTEXT_SIZE_IN_BYTES - 32; // Reserve 1 field for address tag. +comptime global OUTGOING_BODY_SIZE: u32 = 112; -// PRIVATE_LOG_SIZE_IN_BYTES -// - PRIVATE_LOG_OVERHEAD_IN_BYTES, consisting of: -// - 32 bytes for incoming_tag -// - 32 bytes for eph_pk -// - 48 bytes for incoming_header -// - 48 bytes for outgoing_header -// - 144 bytes for outgoing_body -// - 16 + MAX_PRIVATE_LOG_PLAINTEXT_SIZE_IN_BYTES for incoming_body, consisting of: -// - 1 byte for plaintext length -// - MAX_PRIVATE_LOG_PLAINTEXT_SIZE_IN_BYTES for the actual plaintext and padded random values -// - 15 bytes for AES padding +// Bytes padded to the overhead, so that the size of the incoming body ciphertext will be a multiple of 16. +comptime global OVERHEAD_PADDING: u32 = 15; -// Note: Update PRIVATE_LOG_SIZE_IN_BYTES in `constants.nr` if any of the above fields change. +pub comptime global OVERHEAD_SIZE: u32 = 32 /* eph_pk */ + + HEADER_SIZE /* incoming_header */ + + HEADER_SIZE /* outgoing_header */ + + OUTGOING_BODY_SIZE /* outgoing_body */ + + OVERHEAD_PADDING /* padding */; + +global PLAINTEXT_LENGTH_SIZE: u32 = 2; + +// This is enough for 8 fields of data. +// 1 field for storage slot, 1 field for note/event type id, allowing 6 fields for custom values. +global MAX_PRIVATE_LOG_PLAINTEXT_SIZE_IN_BYTES: u32 = + ENCRYPTED_PAYLOAD_SIZE_IN_BYTES - OVERHEAD_SIZE - PLAINTEXT_LENGTH_SIZE - 1 /* aes padding */; + +// Note: Might have to update PRIVATE_LOG_SIZE_IN_FIELDS in `constants.nr` if the above changes. // This value ideally should be set by the protocol, allowing users (or `aztec-nr`) to fit data within the defined size limits. // Currently, we adjust this value as the structure changes, then update `constants.nr` to match. // Once the structure is finalized with defined overhead and max note field sizes, this value will be fixed and should remain unaffected by further payload composition changes. @@ -53,37 +57,29 @@ pub fn compute_private_log_payload( recipient: AztecAddress, sender: AztecAddress, plaintext: [u8; P], -) -> [u8; PRIVATE_LOG_SIZE_IN_BYTES] { - let extended_plaintext: [u8; MAX_PRIVATE_LOG_PLAINTEXT_SIZE_IN_BYTES + 1] = - extend_private_log_plaintext(plaintext); - compute_encrypted_log( - contract_address, - ovsk_app, - ovpk, - recipient, - sender, - extended_plaintext, - ) -} +) -> [Field; PRIVATE_LOG_SIZE_IN_FIELDS] { + assert( + P < MAX_PRIVATE_LOG_PLAINTEXT_SIZE_IN_BYTES, + f"plaintext for log must not exceed {MAX_PRIVATE_LOG_PLAINTEXT_SIZE_IN_BYTES}", + ); -pub fn compute_event_log_payload( - contract_address: AztecAddress, - ovsk_app: Field, - ovpk: OvpkM, - recipient: AztecAddress, - sender: AztecAddress, - plaintext: [u8; P], -) -> [u8; PRIVATE_LOG_SIZE_IN_BYTES] { - let extended_plaintext: [u8; MAX_PRIVATE_EVENT_LOG_PLAINTEXT_SIZE_IN_BYTES + 1] = + let extended_plaintext: [u8; MAX_PRIVATE_LOG_PLAINTEXT_SIZE_IN_BYTES + PLAINTEXT_LENGTH_SIZE] = extend_private_log_plaintext(plaintext); - compute_encrypted_log( + let encrypted: [u8; ENCRYPTED_PAYLOAD_SIZE_IN_BYTES] = compute_encrypted_log( contract_address, ovsk_app, ovpk, recipient, - sender, extended_plaintext, - ) + ); + + // We assume that the sender wants for the recipient to find the tagged note, and therefore that they will cooperate + // and use the correct tag. Usage of a bad tag will result in the recipient not being able to find the note + // automatically. + let tag = unsafe { get_app_tag_as_sender(sender, recipient) }; + increment_app_tagging_secret_index_as_sender(sender, recipient); + + array_concat([tag], bytes_to_fields(encrypted)) } pub fn compute_partial_public_log_payload( @@ -94,15 +90,40 @@ pub fn compute_partial_public_log_payload( sender: AztecAddress, plaintext: [u8; P], ) -> [u8; M] { - let extended_plaintext: [u8; P + 1] = extend_private_log_plaintext(plaintext); - compute_encrypted_log( + let extended_plaintext: [u8; P + PLAINTEXT_LENGTH_SIZE] = + extend_private_log_plaintext(plaintext); + let encrypted: [u8; M - 32] = compute_encrypted_log( contract_address, ovsk_app, ovpk, recipient, - sender, extended_plaintext, - ) + ); + + // We assume that the sender wants for the recipient to find the tagged note, and therefore that they will cooperate + // and use the correct tag. Usage of a bad tag will result in the recipient not being able to find the note + // automatically. + let tag = unsafe { get_app_tag_as_sender(sender, recipient) }; + increment_app_tagging_secret_index_as_sender(sender, recipient); + // Silo the tag with contract address. + // This is done by the kernel circuit to the private logs, but since the partial log will be finalized and emitted + // in public as unencrypted log, its tag is not siloed at the moment. + // To avoid querying logs using two types of tags, we silo the tag manually here. + // TODO(#10273) This should be done by the AVM when it's processing the raw logs instead of their hashes. + let siloed_tag_bytes: [u8; 32] = + poseidon2_hash([contract_address.to_field(), tag]).to_be_bytes(); + + // Temporary hack so that the partial public log remains the same format. + // It should return field array and make the tag the first field as compute_private_log_payload does. + let mut log_bytes = [0; M]; + for i in 0..32 { + log_bytes[i] = siloed_tag_bytes[i]; + } + for i in 0..encrypted.len() { + log_bytes[i + 32] = encrypted[i]; + } + + log_bytes } fn compute_encrypted_log( @@ -110,7 +131,6 @@ fn compute_encrypted_log( ovsk_app: Field, ovpk: OvpkM, recipient: AztecAddress, - sender: AztecAddress, plaintext: [u8; P], ) -> [u8; M] { let (eph_sk, eph_pk) = generate_ephemeral_key_pair(); @@ -122,23 +142,12 @@ fn compute_encrypted_log( let outgoing_header_ciphertext: [u8; 48] = header.compute_ciphertext(eph_sk, ovpk); let incoming_body_ciphertext = compute_incoming_body_ciphertext(plaintext, eph_sk, recipient.to_address_point()); - let outgoing_body_ciphertext: [u8; 144] = + let outgoing_body_ciphertext: [u8; 112] = compute_outgoing_body_ciphertext(recipient, fr_to_fq(ovsk_app), eph_sk, eph_pk); let mut encrypted_bytes = [0; M]; let mut offset = 0; - // We assume that the sender wants for the recipient to find the tagged note, and therefore that they will cooperate - // and use the correct tag. Usage of a bad tag will result in the recipient not being able to find the note - // automatically. - let tag_bytes = unsafe { get_app_tag_bytes_as_sender(sender, recipient) }; - increment_app_tagging_secret_index_as_sender(sender, recipient); - - for i in 0..32 { - encrypted_bytes[offset + i] = tag_bytes[i]; - } - offset += 32; - // eph_pk let eph_pk_bytes = point_to_bytes(eph_pk); for i in 0..32 { @@ -148,17 +157,20 @@ fn compute_encrypted_log( // incoming_header // outgoing_header - for i in 0..48 { + for i in 0..HEADER_SIZE { encrypted_bytes[offset + i] = incoming_header_ciphertext[i]; - encrypted_bytes[offset + 48 + i] = outgoing_header_ciphertext[i]; + encrypted_bytes[offset + HEADER_SIZE + i] = outgoing_header_ciphertext[i]; } - offset += 48 * 2; + offset += HEADER_SIZE * 2; // outgoing_body - for i in 0..144 { + for i in 0..OUTGOING_BODY_SIZE { encrypted_bytes[offset + i] = outgoing_body_ciphertext[i]; } - offset += 144; + offset += OUTGOING_BODY_SIZE; + + // Padding. + offset += OVERHEAD_PADDING; // incoming_body // Then we fill in the rest as the incoming body ciphertext @@ -175,9 +187,10 @@ fn compute_encrypted_log( // Fill the remaining bytes with random values to reach a fixed length of N. fn extend_private_log_plaintext(plaintext: [u8; P]) -> [u8; N] { let mut padded = unsafe { get_random_bytes() }; - padded[0] = P as u8; + padded[0] = (P >> 8) as u8; + padded[1] = P as u8; for i in 0..P { - padded[i + 1] = plaintext[i]; + padded[i + PLAINTEXT_LENGTH_SIZE] = plaintext[i]; } padded } @@ -244,10 +257,10 @@ pub fn compute_outgoing_body_ciphertext( ovsk_app: Scalar, eph_sk: Scalar, eph_pk: Point, -) -> [u8; 144] { +) -> [u8; OUTGOING_BODY_SIZE] { // Again, we could compute `eph_pk` here, but we keep the interface more similar // and also make it easier to optimise it later as we just pass it along - let mut buffer = [0 as u8; 128]; + let mut buffer = [0 as u8; 96]; let serialized_eph_sk_high: [u8; 32] = eph_sk.hi.to_be_bytes(); let serialized_eph_sk_low: [u8; 32] = eph_sk.lo.to_be_bytes(); @@ -256,13 +269,13 @@ pub fn compute_outgoing_body_ciphertext( let serialized_recipient_address_point = point_to_bytes(recipient.to_address_point().to_point()); - for i in 0..32 { - buffer[i] = serialized_eph_sk_high[i]; - buffer[i + 32] = serialized_eph_sk_low[i]; - buffer[i + 64] = address_bytes[i]; + for i in 0..16 { + buffer[i] = serialized_eph_sk_high[i + 16]; + buffer[i + 16] = serialized_eph_sk_low[i + 16]; } for i in 0..32 { - buffer[i + 96] = serialized_recipient_address_point[i]; + buffer[i + 32] = address_bytes[i]; + buffer[i + 64] = serialized_recipient_address_point[i]; } // We compute the symmetric key using poseidon. @@ -318,7 +331,7 @@ mod test { 101, 153, 0, 0, 16, 39, ]; - let randomness = 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f; + let randomness = 0x0101010101010101010101010101010101010101010101010101010101010101; let _ = OracleMock::mock("getRandomField").returns(randomness).times( (MAX_PRIVATE_LOG_PLAINTEXT_SIZE_IN_BYTES as u64 + 1 + 30) / 31, ); @@ -338,7 +351,7 @@ mod test { let _ = OracleMock::mock("incrementAppTaggingSecretIndexAsSender").returns(()); - let log = compute_private_log_payload( + let payload = compute_private_log_payload( contract_address, ovsk_app, ovpk_m, @@ -349,40 +362,28 @@ mod test { // The following value was generated by `encrypted_log_payload.test.ts` // --> Run the test with AZTEC_GENERATE_TEST_DATA=1 flag to update test data. - let encrypted_log_from_typescript = [ - 14, 156, 255, 195, 221, 215, 70, 175, 251, 2, 65, 13, 143, 10, 130, 62, 137, 147, 151, - 133, 188, 200, 232, 142, 228, 243, 202, 224, 94, 115, 124, 54, 141, 70, 12, 14, 67, 77, - 132, 110, 193, 234, 40, 110, 64, 144, 235, 86, 55, 111, 242, 123, 221, 193, 170, 202, - 225, 216, 86, 84, 159, 112, 31, 167, 5, 119, 121, 10, 234, 188, 194, 216, 30, 200, 208, - 201, 158, 127, 93, 43, 242, 241, 69, 32, 37, 220, 119, 122, 23, 132, 4, 248, 81, 217, - 61, 232, 24, 146, 63, 133, 24, 120, 113, 217, 155, 223, 149, 214, 149, 239, 240, 169, - 224, 155, 161, 81, 83, 252, 155, 77, 34, 75, 110, 30, 113, 223, 189, 202, 171, 6, 192, - 157, 91, 60, 116, 155, 254, 190, 28, 4, 7, 236, 205, 4, 245, 27, 187, 89, 20, 38, 128, - 200, 160, 145, 185, 127, 198, 203, 207, 97, 246, 194, 175, 155, 142, 188, 143, 120, 83, - 122, 178, 63, 208, 197, 232, 24, 228, 212, 45, 69, 157, 38, 90, 219, 119, 194, 239, 130, - 155, 246, 143, 135, 242, 196, 123, 71, 139, 181, 122, 231, 228, 26, 7, 100, 63, 101, - 195, 83, 8, 61, 85, 123, 148, 227, 29, 164, 162, 161, 49, 39, 73, 141, 46, 179, 240, 52, - 109, 165, 238, 210, 233, 188, 36, 90, 175, 2, 42, 149, 78, 208, 176, 145, 50, 180, 152, - 245, 55, 112, 40, 153, 180, 78, 54, 102, 119, 98, 56, 235, 246, 51, 179, 86, 45, 127, - 18, 77, 187, 168, 41, 24, 232, 113, 149, 138, 148, 33, 143, 215, 150, 188, 105, 131, - 254, 236, 199, 206, 56, 44, 130, 134, 29, 99, 254, 69, 153, 146, 68, 234, 148, 148, 178, - 38, 221, 182, 103, 252, 139, 7, 246, 132, 29, 232, 78, 102, 126, 28, 136, 8, 219, 180, - 162, 14, 62, 71, 118, 40, 147, 93, 87, 188, 231, 32, 93, 56, 193, 194, 197, 120, 153, - 164, 139, 114, 18, 149, 2, 226, 19, 170, 250, 249, 128, 56, 236, 93, 14, 101, 115, 20, - 173, 73, 192, 53, 229, 7, 23, 59, 11, 176, 9, 147, 175, 168, 206, 48, 127, 126, 76, 51, - 211, 66, 232, 16, 132, 243, 14, 196, 181, 118, 12, 71, 236, 250, 253, 71, 249, 122, 30, - 23, 23, 19, 89, 47, 193, 69, 240, 164, 34, 128, 110, 13, 133, 198, 7, 165, 14, 31, 239, - 210, 146, 78, 67, 86, 32, 159, 244, 214, 246, 121, 246, 233, 252, 20, 131, 221, 28, 146, - 222, 119, 222, 162, 250, 252, 189, 18, 147, 12, 142, 177, 222, 178, 122, 248, 113, 197, - 40, 199, 152, 251, 91, 81, 243, 25, 156, 241, 141, 60, 12, 99, 103, 169, 97, 32, 112, - 37, 244, 255, 126, 46, 114, 226, 113, 223, 249, 27, 3, 31, 41, 233, 28, 8, 23, 84, 99, - 25, 186, 65, 33, 9, 35, 74, 16, 52, 169, 48, 161, 134, 233, 242, 136, 39, 162, 105, 205, - 43, 253, 183, 36, 138, 186, 87, 31, 7, 248, 125, 227, 193, 172, 155, 98, 33, 61, 186, - 158, 241, 192, 23, 28, 186, 100, 222, 174, 19, 64, 224, 113, 251, 143, 45, 152, 81, 67, - 116, 16, 95, 189, 83, 31, 124, 39, 155, 142, 66, 0, 120, 197, 221, 161, 62, 75, 192, - 255, 186, 200, 10, 135, 7, + let private_log_payload_from_typescript = [ + 0x0e9cffc3ddd746affb02410d8f0a823e89939785bcc8e88ee4f3cae05e737c36, + 0x008d460c0e434d846ec1ea286e4090eb56376ff27bddc1aacae1d856549f701f, + 0x00a70577790aeabcc2d81ec8d0c99e7f5d2bf2f1452025dc777a178404f851d9, + 0x003de818923f85187871d99bdf95d695eff0a9e09ba15153fc9b4d224b6e1e71, + 0x00dfbdcaab06c09d5b3c749bfebe1c0407eccd04f51bbb59142680c8a091b97f, + 0x00c6cbcf615def593ab09e5b3f7f58f6fc235c90e7c77ed8dadb3b05ee4545a7, + 0x00bc612c9139475fee6070be47efcc43a5cbbc873632f1428fac952df9c181db, + 0x005f9e850b21fe11fedef37b88caee95111bce776e488df219732d0a77d19201, + 0x007047186f41445ecd5c603487f7fb3c8f31010a22af69ce0000000000000000, + 0x0000000000000000a600a61f7d59eeaf52eb51bc0592ff981d9ba3ea8e6ea8ba, + 0x009dc0cec8c70b81e84556a77ce6c3ca47a527f99ffe7b2524bb885a23020b72, + 0x0095748ad19c1083618ad96298b76ee07eb1a56d19cc798710e9f5de96501bd5, + 0x009b3781c9c02a6c95c5912f8936b1500d362afbf0922c85b1ada18db8b95162, + 0x00a6e9d067655cdf669eb387f8e0492a95fdcdb39429d5340b4bebc250ba9bf6, + 0x002c2f49f549f37beed75a668aa51967e0e57547e5a655157bcf381e22f30e25, + 0x00881548ec9606a151b5fbfb2d14ee4b34bf4c1dbd71c7be15ad4c63474bb6f8, + 0x009970aeb3d9489c8edbdff80a1a3a5c28370e534abc870a85ea4318326ea192, + 0x0022fb10df358c765edada497db4284ae30507a2e03e983d23cfa0bd831577e8, ]; - assert_eq(encrypted_log_from_typescript, log); + + assert_eq(payload, private_log_payload_from_typescript); } #[test] @@ -457,14 +458,12 @@ mod test { // The following value was generated by `encrypted_log_payload.test.ts` // --> Run the test with AZTEC_GENERATE_TEST_DATA=1 flag to update test data. let outgoing_body_ciphertext_from_typescript = [ - 127, 182, 227, 75, 192, 197, 54, 47, 168, 134, 233, 148, 251, 46, 86, 12, 73, 50, 238, - 50, 31, 174, 27, 202, 110, 77, 161, 197, 244, 124, 17, 100, 143, 150, 232, 14, 156, 248, - 43, 177, 16, 82, 244, 103, 88, 74, 84, 200, 15, 65, 187, 14, 163, 60, 91, 22, 104, 31, - 211, 190, 124, 121, 79, 92, 238, 182, 194, 225, 34, 71, 67, 116, 27, 231, 68, 161, 147, - 94, 53, 195, 83, 237, 172, 52, 173, 229, 26, 234, 107, 43, 82, 68, 16, 105, 37, 125, - 117, 86, 133, 50, 21, 92, 74, 229, 105, 141, 83, 229, 255, 251, 21, 61, 234, 61, 168, - 221, 106, 231, 8, 73, 208, 60, 251, 46, 251, 228, 148, 144, 187, 195, 38, 18, 223, 153, - 8, 121, 178, 84, 237, 148, 254, 219, 59, 62, + 97, 221, 53, 168, 242, 56, 217, 184, 114, 127, 137, 98, 31, 63, 86, 179, 139, 198, 162, + 162, 216, 158, 255, 205, 90, 212, 141, 55, 9, 245, 6, 146, 202, 137, 129, 36, 190, 31, + 17, 89, 151, 203, 43, 196, 203, 233, 178, 79, 202, 70, 250, 182, 18, 191, 79, 42, 205, + 204, 145, 14, 13, 35, 255, 139, 142, 66, 193, 240, 175, 233, 180, 37, 153, 235, 41, 88, + 232, 52, 235, 213, 50, 26, 153, 227, 25, 242, 161, 92, 45, 152, 100, 106, 29, 192, 131, + 101, 121, 126, 31, 118, 191, 90, 238, 43, 24, 82, 49, 18, 199, 107, 83, 7, ]; assert_eq(outgoing_body_ciphertext_from_typescript, ciphertext); diff --git a/noir-projects/aztec-nr/aztec/src/event/event_interface.nr b/noir-projects/aztec-nr/aztec/src/event/event_interface.nr index 1c76a038de4..a286b6e544f 100644 --- a/noir-projects/aztec-nr/aztec/src/event/event_interface.nr +++ b/noir-projects/aztec-nr/aztec/src/event/event_interface.nr @@ -1,8 +1,7 @@ use dep::protocol_types::abis::event_selector::EventSelector; -use dep::protocol_types::traits::{Deserialize, Serialize}; +use dep::protocol_types::traits::Serialize; pub trait EventInterface: Serialize { - fn private_to_be_bytes(self, randomness: Field) -> [u8; N * 32 + 64]; fn to_be_bytes(self) -> [u8; N * 32 + 32]; fn get_event_type_id() -> EventSelector; fn emit(self, emit: fn[Env](Self) -> ()); diff --git a/noir-projects/aztec-nr/aztec/src/macros/events/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/events/mod.nr index bf7f433eca2..3a72031efc0 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/events/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/events/mod.nr @@ -11,37 +11,13 @@ comptime fn generate_event_interface(s: StructDefinition) -> Quoted { quote { impl aztec::event::event_interface::EventInterface<$content_len> for $name { - - fn private_to_be_bytes(self, randomness: Field) -> [u8; $content_len * 32 + 64] { - let mut buffer: [u8; $content_len * 32 + 64] = [0; $content_len * 32 + 64]; - - let randomness_bytes: [u8; 32] = randomness.to_be_bytes(); - let event_type_id_bytes: [u8; 32] = $name::get_event_type_id().to_field().to_be_bytes(); - - for i in 0..32 { - buffer[i] = randomness_bytes[i]; - buffer[32 + i] = event_type_id_bytes[i]; - } - - let serialized_event = self.serialize(); - - for i in 0..serialized_event.len() { - let bytes: [u8; 32] = serialized_event[i].to_be_bytes(); - for j in 0..32 { - buffer[64 + i * 32 + j] = bytes[j]; - } - } - - buffer - } - fn to_be_bytes(self) -> [u8; $content_len * 32 + 32] { let mut buffer: [u8; $content_len * 32 + 32] = [0; $content_len * 32 + 32]; let event_type_id_bytes: [u8; 32] = $name::get_event_type_id().to_field().to_be_bytes(); for i in 0..32 { - buffer[32 + i] = event_type_id_bytes[i]; + buffer[i] = event_type_id_bytes[i]; } let serialized_event = self.serialize(); @@ -49,7 +25,7 @@ comptime fn generate_event_interface(s: StructDefinition) -> Quoted { for i in 0..serialized_event.len() { let bytes: [u8; 32] = serialized_event[i].to_be_bytes(); for j in 0..32 { - buffer[64 + i * 32 + j] = bytes[j]; + buffer[32 + i * 32 + j] = bytes[j]; } } diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index e3b11d000cc..43695823182 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -1,5 +1,5 @@ use crate::{ - encrypted_logs::payload::PRIVATE_LOG_OVERHEAD_IN_BYTES, + encrypted_logs::payload::OVERHEAD_SIZE, note::{note_getter_options::PropertySelector, note_header::NoteHeader}, prelude::Point, }; @@ -438,10 +438,11 @@ comptime fn generate_setup_payload( get_setup_log_plaintext_body(s, log_plaintext_length, indexed_nullable_fields); // Then we compute values for `encrypt_log(...)` function - let encrypted_log_byte_length = PRIVATE_LOG_OVERHEAD_IN_BYTES + let encrypted_log_byte_length = 32 /* tag */ + + OVERHEAD_SIZE + log_plaintext_length /* log_plaintext */ - + 1 /* log_plaintext_length */ - + 15 /* AES padding */; + + 2 /* log_plaintext_length */ + + 14 /* AES padding */; // Each field contains 31 bytes so the length in fields is computed as ceil(encrypted_log_byte_length / 31) // --> we achieve rouding by adding 30 and then dividing without remainder let encrypted_log_field_length = (encrypted_log_byte_length + 30) / 31; @@ -661,10 +662,11 @@ comptime fn generate_finalization_payload( // Then we compute values for `encrypt_log(...)` function let setup_log_plaintext_length = indexed_fixed_fields.len() * 32 + 64; - let setup_log_byte_length = PRIVATE_LOG_OVERHEAD_IN_BYTES + let setup_log_byte_length = 32 /* tag */ + + OVERHEAD_SIZE + setup_log_plaintext_length - + 1 /* log_plaintext_length */ - + 15 /* AES padding */; + + 2 /* log_plaintext_length */ + + 14 /* AES padding */; // Each field contains 31 bytes so the length in fields is computed as ceil(setup_log_byte_length / 31) // --> we achieve rouding by adding 30 and then dividing without remainder let setup_log_field_length = (setup_log_byte_length + 30) / 31; diff --git a/noir-projects/aztec-nr/aztec/src/oracle/logs.nr b/noir-projects/aztec-nr/aztec/src/oracle/logs.nr index 3db99d00902..019a48e3468 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/logs.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/logs.nr @@ -1,54 +1,5 @@ use dep::protocol_types::address::AztecAddress; -/// Informs the simulator that an encrypted note log has been emitted, helping it keep track of side-effects and easing -/// debugging. -pub fn emit_encrypted_note_log( - note_hash_counter: u32, - encrypted_note: [u8; M], - counter: u32, -) { - // This oracle call returns nothing: we only call it for its side effects. It is therefore always safe to call. - unsafe { - emit_encrypted_note_log_oracle_wrapper(note_hash_counter, encrypted_note, counter) - } -} - -/// Informs the simulator that an encrypted event log has been emitted, helping it keep track of side-effects and easing -/// debugging. -pub fn emit_encrypted_event_log( - contract_address: AztecAddress, - randomness: Field, - encrypted_event: [u8; M], - counter: u32, -) { - // This oracle call returns nothing: we only call it for its side effects. It is therefore always safe to call. - unsafe { - emit_encrypted_event_log_oracle_wrapper( - contract_address, - randomness, - encrypted_event, - counter, - ) - } -} - -unconstrained fn emit_encrypted_note_log_oracle_wrapper( - note_hash_counter: u32, - encrypted_note: [u8; M], - counter: u32, -) { - emit_encrypted_note_log_oracle(note_hash_counter, encrypted_note, counter) -} - -unconstrained fn emit_encrypted_event_log_oracle_wrapper( - contract_address: AztecAddress, - randomness: Field, - encrypted_event: [u8; M], - counter: u32, -) { - emit_encrypted_event_log_oracle(contract_address, randomness, encrypted_event, counter) -} - /// Temporary substitute that is used for handling contract class registration. This /// variant returns the log hash, which would be too large to compute inside a circuit. pub unconstrained fn emit_contract_class_unencrypted_log_private( @@ -59,22 +10,6 @@ pub unconstrained fn emit_contract_class_unencrypted_log_private( emit_contract_class_unencrypted_log_private_oracle(contract_address, message, counter) } -// = 480 + 32 * N bytes -#[oracle(emitEncryptedNoteLog)] -unconstrained fn emit_encrypted_note_log_oracle( - _note_hash_counter: u32, - _encrypted_note: [u8; M], - _counter: u32, -) {} - -#[oracle(emitEncryptedEventLog)] -unconstrained fn emit_encrypted_event_log_oracle( - _contract_address: AztecAddress, - _randomness: Field, - _encrypted_event: [u8; M], - _counter: u32, -) {} - #[oracle(emitContractClassLog)] unconstrained fn emit_contract_class_unencrypted_log_private_oracle( contract_address: AztecAddress, diff --git a/noir-projects/aztec-nr/aztec/src/oracle/notes.nr b/noir-projects/aztec-nr/aztec/src/oracle/notes.nr index 4bbc97be9f9..737f69d20f4 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/notes.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/notes.nr @@ -204,14 +204,9 @@ pub unconstrained fn check_nullifier_exists(inner_nullifier: Field) -> bool { #[oracle(checkNullifierExists)] unconstrained fn check_nullifier_exists_oracle(_inner_nullifier: Field) -> Field {} -/// Same as `get_app_tagging_secret_as_sender`, except it returns the derived tag as an array of bytes, ready to be included in a -/// log. -pub unconstrained fn get_app_tag_bytes_as_sender( - sender: AztecAddress, - recipient: AztecAddress, -) -> [u8; 32] { - let tag = get_app_tagging_secret_as_sender(sender, recipient).compute_tag(recipient); - tag.to_be_bytes() +/// Same as `get_app_tagging_secret_as_sender`, except it returns the derived tag, ready to be included in a log. +pub unconstrained fn get_app_tag_as_sender(sender: AztecAddress, recipient: AztecAddress) -> Field { + get_app_tagging_secret_as_sender(sender, recipient).compute_tag(recipient) } /// Returns the tagging secret for a given sender and recipient pair, siloed for the current contract address. diff --git a/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr b/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr index 44c129f8710..04ef191bc9f 100644 --- a/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr @@ -2,17 +2,14 @@ use dep::aztec::macros::aztec; #[aztec] contract ContractInstanceDeployer { - use dep::aztec::{ - macros::{events::event, functions::private}, - utils::to_bytes::arr_to_be_bytes_arr, - }; + use dep::aztec::macros::{events::event, functions::private}; use dep::aztec::protocol_types::{ - address::{AztecAddress, PartialAddress, PublicKeysHash}, + address::{AztecAddress, PartialAddress}, constants::DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE, contract_class_id::ContractClassId, - hash::sha256_to_field, public_keys::PublicKeys, traits::Serialize, + utils::arrays::array_concat, }; use std::meta::derive; @@ -117,14 +114,7 @@ contract ContractInstanceDeployer { let payload = event.serialize(); dep::aztec::oracle::debug_log::debug_log_format("ContractInstanceDeployed: {}", payload); - // @todo This is very inefficient, we are doing a lot of back and forth conversions. - let serialized_log = arr_to_be_bytes_arr(payload); - let log_hash = sha256_to_field(serialized_log); - - // Note: we are cheating a bit here because this is actually not encrypted - // but needs to be emitted from private, where we have removed unencrypted_logs, - // and has 15 fields (the max enc log len is 8). - // TODO(Miranda): split into 2 logs - context.emit_raw_event_log_with_masked_address(0, serialized_log, log_hash); + let padded_log = array_concat(payload, [0; 3]); + context.emit_private_log(padded_log); } } diff --git a/noir-projects/noir-contracts/contracts/nft_contract/src/main.nr b/noir-projects/noir-contracts/contracts/nft_contract/src/main.nr index 0f7c9b35fb1..ecec8c4a226 100644 --- a/noir-projects/noir-contracts/contracts/nft_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/nft_contract/src/main.nr @@ -228,7 +228,7 @@ contract NFT { fn _store_payload_in_transient_storage_unsafe( slot: Field, point: Point, - setup_log: [Field; 15], + setup_log: [Field; 14], ) { context.storage_write(slot, point); context.storage_write(slot + aztec::protocol_types::point::POINT_LENGTH as Field, setup_log); diff --git a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr index 8a8091e6422..30210cbdadb 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -6,7 +6,7 @@ use dep::aztec::macros::aztec; #[aztec] contract Test { - use dep::aztec::encrypted_logs::encrypted_event_emission::encode_and_encrypt_event_with_randomness_unconstrained; + use dep::aztec::encrypted_logs::encrypted_event_emission::encode_and_encrypt_event_unconstrained; use dep::aztec::encrypted_logs::encrypted_note_emission::encode_and_encrypt_note; use dep::aztec::prelude::{ AztecAddress, EthAddress, FunctionSelector, NoteGetterOptions, NoteViewerOptions, @@ -14,8 +14,10 @@ contract Test { }; use dep::aztec::protocol_types::{ - constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, point::Point, public_keys::IvpkM, + constants::{MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, PRIVATE_LOG_SIZE_IN_FIELDS}, + point::Point, traits::Serialize, + utils::arrays::array_concat, }; use dep::aztec::keys::getters::get_public_keys; @@ -298,10 +300,8 @@ contract Test { value4: fields[4], }; - event.emit(encode_and_encrypt_event_with_randomness_unconstrained( + event.emit(encode_and_encrypt_event_unconstrained( &mut context, - // testing only - a secret random value is passed in here to salt / mask the address - 5, outgoing_viewer_ovpk_m, owner, outgoing_viewer, @@ -314,16 +314,9 @@ contract Test { .emit_array_as_encrypted_log([0, 0, 0, 0, 0], owner, outgoing_viewer, false) .call(&mut context); - let otherEvent = ExampleEvent { value0: 1, value1: 2, value2: 3, value3: 4, value4: 5 }; - - otherEvent.emit(encode_and_encrypt_event_with_randomness_unconstrained( - &mut context, - // testing only - a randomness of 0 signals the kernels to not mask the address - 0, - outgoing_viewer_ovpk_m, - owner, - outgoing_viewer, - )); + // Emit a log with non-encrypted content for testing purpose. + let leaky_log = array_concat(event.serialize(), [0; PRIVATE_LOG_SIZE_IN_FIELDS - 5]); + context.emit_private_log(leaky_log); } } diff --git a/noir-projects/noir-contracts/contracts/test_log_contract/src/main.nr b/noir-projects/noir-contracts/contracts/test_log_contract/src/main.nr index dcfa7720837..fa7c33be0b3 100644 --- a/noir-projects/noir-contracts/contracts/test_log_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_log_contract/src/main.nr @@ -2,7 +2,7 @@ use dep::aztec::macros::aztec; #[aztec] contract TestLog { - use dep::aztec::encrypted_logs::encrypted_event_emission::encode_and_encrypt_event_with_randomness; + use dep::aztec::encrypted_logs::encrypted_event_emission::encode_and_encrypt_event; use dep::aztec::keys::getters::get_public_keys; use dep::aztec::macros::{events::event, functions::{private, public}, storage::storage}; use dep::aztec::prelude::PrivateSet; @@ -36,15 +36,14 @@ contract TestLog { global EXAMPLE_EVENT_0_CIPHERTEXT_BYTES_LEN: Field = 144; #[private] - fn emit_encrypted_events(other: AztecAddress, randomness: [Field; 2], preimages: [Field; 4]) { + fn emit_encrypted_events(other: AztecAddress, preimages: [Field; 4]) { let event0 = ExampleEvent0 { value0: preimages[0], value1: preimages[1] }; let other_ovpk_m = get_public_keys(other).ovpk_m; let msg_sender_ovpk_m = get_public_keys(context.msg_sender()).ovpk_m; - event0.emit(encode_and_encrypt_event_with_randomness( + event0.emit(encode_and_encrypt_event( &mut context, - randomness[0], // outgoing is set to other, incoming is set to msg sender other_ovpk_m, context.msg_sender(), @@ -52,9 +51,8 @@ contract TestLog { )); // We duplicate the emission, but specifying different incoming and outgoing parties - event0.emit(encode_and_encrypt_event_with_randomness( + event0.emit(encode_and_encrypt_event( &mut context, - randomness[0], // outgoing is set to msg sender, incoming is set to other msg_sender_ovpk_m, other, @@ -66,9 +64,8 @@ contract TestLog { value3: preimages[3] as u8, }; - event1.emit(encode_and_encrypt_event_with_randomness( + event1.emit(encode_and_encrypt_event( &mut context, - randomness[1], // outgoing is set to other, incoming is set to msg sender other_ovpk_m, context.msg_sender(), diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr index 53eff85b18e..b2cd2094edc 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr @@ -701,7 +701,7 @@ contract Token { fn _store_payload_in_transient_storage_unsafe( slot: Field, point: Point, - setup_log: [Field; 15], + setup_log: [Field; 14], ) { context.storage_write(slot, point); context.storage_write(slot + aztec::protocol_types::point::POINT_LENGTH as Field, setup_log); diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/previous_kernel_validator.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/previous_kernel_validator.nr index 4476930b3a4..fea9effd5ce 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/previous_kernel_validator.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/previous_kernel_validator.nr @@ -4,9 +4,7 @@ use crate::components::previous_kernel_validator::previous_kernel_validator_hint generate_previous_kernel_validator_hints, PreviousKernelValidatorHints, }; use dep::types::{ - abis::{log_hash::ScopedEncryptedLogHash, private_kernel_data::PrivateKernelData}, - address::AztecAddress, - traits::is_empty, + abis::private_kernel_data::PrivateKernelData, address::AztecAddress, traits::is_empty, utils::arrays::array_length, }; @@ -41,8 +39,8 @@ impl PreviousKernelValidator { fn validate_common(self) { self.validate_empty_private_call_stack(); self.verify_empty_validation_requests(); - self.verify_sorted_siloed_values(); - self.validate_no_transient_data(); + self.verify_siloed_values(); + self.verify_no_transient_data(); } fn validate_empty_private_call_stack(self) { @@ -138,9 +136,9 @@ impl PreviousKernelValidator { ); } - fn verify_sorted_siloed_values(self) { - // Check that the data are already siloed and/or sorted in the reset circuit. - // Any unprocessed data added after the last reset with siloing was called should be caught here. + // Ensure that the data has been properly siloed in the reset circuit. + fn verify_siloed_values(self) { + // note_hashes let num_note_hashes = array_length(self.previous_kernel.public_inputs.end.note_hashes); if num_note_hashes != 0 { let note_hash = self.previous_kernel.public_inputs.end.note_hashes[num_note_hashes - 1]; @@ -151,6 +149,7 @@ impl PreviousKernelValidator { ); } + // nullifiers let num_nullifiers = array_length(self.previous_kernel.public_inputs.end.nullifiers); let nullifier = self.previous_kernel.public_inputs.end.nullifiers[num_nullifiers - 1]; // - 1 without checking because there's at least 1 nullifier. assert_eq( @@ -159,27 +158,20 @@ impl PreviousKernelValidator { "nullifiers have not been siloed in a reset", ); - // Note logs are not siloed, but they are sorted and their note_hash_counter should've been set to 0 in the reset circuit. - let num_note_logs = array_length( - self.previous_kernel.public_inputs.end.note_encrypted_logs_hashes, - ); - if num_note_logs != 0 { - let note_log = self.previous_kernel.public_inputs.end.note_encrypted_logs_hashes[ - num_note_logs - - 1]; - assert_eq(note_log.note_hash_counter, 0, "note logs have not been sorted in a reset"); + // private_logs + let num_private_logs = array_length(self.previous_kernel.public_inputs.end.private_logs); + if num_private_logs != 0 { + let private_log = + self.previous_kernel.public_inputs.end.private_logs[num_private_logs - 1]; + assert_eq( + private_log.contract_address, + AztecAddress::zero(), + "private logs have not been siloed in a reset", + ); } - - // We need to check the entire array because randomness can be 0 for encrypted logs if the app wants to reveal the actual contract address. - assert( - self.previous_kernel.public_inputs.end.encrypted_logs_hashes.all( - |h: ScopedEncryptedLogHash| h.log_hash.randomness == 0, - ), - "encrypted logs have not been siloed in a reset", - ); } - fn validate_no_transient_data(self) { + fn verify_no_transient_data(self) { let nullifiers = self.previous_kernel.public_inputs.end.nullifiers; let note_hashes = self.previous_kernel.public_inputs.end.note_hashes; let note_hash_indexes_for_nullifiers = self.hints.note_hash_indexes_for_nullifiers; @@ -197,6 +189,9 @@ impl PreviousKernelValidator { note_hash.counter() < nullifier.counter(), "Cannot link a note hash emitted after a nullifier", ); + // No need to verify logs linked to a note hash are squashed. + // When a note hash is squashed, all associated logs are guaranteed to be removed. + // See reset-kernel-lib/src/reset/transient_data.nr for details. } } } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/private_call_data_validator.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/private_call_data_validator.nr index 0d20c84272f..ebe27282cca 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/private_call_data_validator.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/private_call_data_validator.nr @@ -9,7 +9,6 @@ use crate::components::private_call_data_validator::{ }; use dep::types::{ abis::{ - call_context::CallContext, kernel_circuit_public_inputs::PrivateKernelCircuitPublicInputs, note_hash::ScopedNoteHash, private_call_request::PrivateCallRequest, @@ -102,7 +101,7 @@ impl PrivateCallDataValidator { self.validate_private_call_requests(); self.validate_public_call_requests(); self.validate_counters(); - self.validate_note_logs(accumulated_note_hashes); + self.validate_logs(accumulated_note_hashes); } pub fn validate_as_first_call(self) { @@ -208,14 +207,9 @@ impl PrivateCallDataValidator { "l2_to_l1_msgs must be empty for static calls", ); assert_eq( - self.array_lengths.note_encrypted_logs_hashes, + self.array_lengths.private_logs, 0, - "note_encrypted_logs_hashes must be empty for static calls", - ); - assert_eq( - self.array_lengths.encrypted_logs_hashes, - 0, - "encrypted_logs_hashes must be empty for static calls", + "private_logs must be empty for static calls", ); assert_eq( self.array_lengths.contract_class_logs_hashes, @@ -352,8 +346,8 @@ impl PrivateCallDataValidator { validate_incrementing_counters_within_range( counter_start, counter_end, - public_inputs.encrypted_logs_hashes, - self.array_lengths.encrypted_logs_hashes, + public_inputs.private_logs, + self.array_lengths.private_logs, ); validate_incrementing_counters_within_range( counter_start, @@ -377,31 +371,28 @@ impl PrivateCallDataValidator { ); } - fn validate_note_logs(self, accumulated_note_hashes: [ScopedNoteHash; N]) { - let note_logs = self.data.public_inputs.note_encrypted_logs_hashes; - let num_logs = self.array_lengths.note_encrypted_logs_hashes; + fn validate_logs(self, accumulated_note_hashes: [ScopedNoteHash; N]) { + let logs = self.data.public_inputs.private_logs; let contract_address = self.data.public_inputs.call_context.contract_address; - let mut should_check = true; - for i in 0..note_logs.len() { - should_check &= i != num_logs; - if should_check { - let note_log = note_logs[i]; + for i in 0..logs.len() { + let log = logs[i]; + if log.note_hash_counter != 0 { let note_index = unsafe { find_index_hint( accumulated_note_hashes, - |n: ScopedNoteHash| n.counter() == note_log.note_hash_counter, + |n: ScopedNoteHash| n.counter() == log.note_hash_counter, ) }; assert(note_index != N, "could not find note hash linked to note log"); + let note_hash = accumulated_note_hashes[note_index]; assert_eq( - note_log.note_hash_counter, - accumulated_note_hashes[note_index].counter(), + log.note_hash_counter, + note_hash.counter(), "could not find note hash linked to note log", ); - // If the note_index points to an empty note hash, the following check will fail. assert_eq( - accumulated_note_hashes[note_index].contract_address, contract_address, + note_hash.contract_address, "could not link a note log to a note hash in another contract", ); } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/private_kernel_circuit_output_validator.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/private_kernel_circuit_output_validator.nr index 66eee01a1b9..d1d0042e115 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/private_kernel_circuit_output_validator.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/private_kernel_circuit_output_validator.nr @@ -13,8 +13,8 @@ use dep::types::{ traits::is_empty, transaction::tx_request::TxRequest, utils::arrays::{ - assert_array_appended, assert_array_appended_reversed, assert_array_appended_scoped, - assert_array_prepended, + assert_array_appended, assert_array_appended_and_scoped, assert_array_appended_reversed, + assert_array_appended_scoped, assert_array_prepended, }, }; @@ -232,14 +232,9 @@ impl PrivateKernelCircuitOutputValidator { array_lengths.l2_to_l1_msgs, ); assert_array_prepended( - self.output.end.note_encrypted_logs_hashes, - previous_kernel.end.note_encrypted_logs_hashes, - array_lengths.note_encrypted_logs_hashes, - ); - assert_array_prepended( - self.output.end.encrypted_logs_hashes, - previous_kernel.end.encrypted_logs_hashes, - array_lengths.encrypted_logs_hashes, + self.output.end.private_logs, + previous_kernel.end.private_logs, + array_lengths.private_logs, ); assert_array_prepended( self.output.end.contract_class_logs_hashes, @@ -310,17 +305,11 @@ impl PrivateKernelCircuitOutputValidator { offsets.l2_to_l1_msgs, contract_address, ); - assert_array_appended( - self.output.end.note_encrypted_logs_hashes, - private_call.note_encrypted_logs_hashes, - array_lengths.note_encrypted_logs_hashes, - offsets.note_encrypted_logs_hashes, - ); - assert_array_appended_scoped( - self.output.end.encrypted_logs_hashes, - private_call.encrypted_logs_hashes, - array_lengths.encrypted_logs_hashes, - offsets.encrypted_logs_hashes, + assert_array_appended_and_scoped( + self.output.end.private_logs, + private_call.private_logs, + array_lengths.private_logs, + offsets.private_logs, contract_address, ); assert_array_appended_scoped( diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/private_kernel_circuit_public_inputs_composer.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/private_kernel_circuit_public_inputs_composer.nr index 09d6d7944f1..9527a685a43 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/private_kernel_circuit_public_inputs_composer.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/private_kernel_circuit_public_inputs_composer.nr @@ -73,9 +73,7 @@ impl PrivateKernelCircuitPublicInputsComposer { public_inputs.end.note_hashes = array_to_bounded_vec(start.note_hashes); public_inputs.end.nullifiers = array_to_bounded_vec(start.nullifiers); public_inputs.end.l2_to_l1_msgs = array_to_bounded_vec(start.l2_to_l1_msgs); - public_inputs.end.note_encrypted_logs_hashes = - array_to_bounded_vec(start.note_encrypted_logs_hashes); - public_inputs.end.encrypted_logs_hashes = array_to_bounded_vec(start.encrypted_logs_hashes); + public_inputs.end.private_logs = array_to_bounded_vec(start.private_logs); public_inputs.end.contract_class_logs_hashes = array_to_bounded_vec(start.contract_class_logs_hashes); public_inputs.end.public_call_requests = array_to_bounded_vec(start.public_call_requests); @@ -99,7 +97,7 @@ impl PrivateKernelCircuitPublicInputsComposer { } pub unconstrained fn sort_ordered_values(&mut self) { - // Note hashes, nullifiers, note_encrypted_logs_hashes, and encrypted_logs_hashes are sorted in the reset circuit. + // Note hashes, nullifiers, and private logs are sorted in the reset circuit. self.public_inputs.end.l2_to_l1_msgs.storage = sort_by_counter_asc(self.public_inputs.end.l2_to_l1_msgs.storage); self.public_inputs.end.contract_class_logs_hashes.storage = @@ -227,11 +225,11 @@ impl PrivateKernelCircuitPublicInputsComposer { } fn propagate_logs(&mut self, private_call: PrivateCircuitPublicInputs) { - let encrypted_logs = private_call.encrypted_logs_hashes; - for i in 0..encrypted_logs.len() { - let log = encrypted_logs[i]; + let private_logs = private_call.private_logs; + for i in 0..private_logs.len() { + let log = private_logs[i]; if !is_empty(log) { - self.public_inputs.end.encrypted_logs_hashes.push(log.scope( + self.public_inputs.end.private_logs.push(log.scope( private_call.call_context.contract_address, )); } @@ -246,13 +244,6 @@ impl PrivateKernelCircuitPublicInputsComposer { )); } } - - let note_logs = private_call.note_encrypted_logs_hashes; - for i in 0..note_logs.len() { - if !is_empty(note_logs[i]) { - self.public_inputs.end.note_encrypted_logs_hashes.push(note_logs[i]); - } - } } fn propagate_private_call_requests(&mut self, private_call: PrivateCircuitPublicInputs) { diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/reset_output_composer.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/reset_output_composer.nr index 003669e9e8f..20816db17ac 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/reset_output_composer.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/reset_output_composer.nr @@ -6,17 +6,12 @@ use crate::components::reset_output_composer::reset_output_hints::generate_reset use dep::reset_kernel_lib::{PrivateValidationRequestProcessor, TransientDataIndexHint}; use dep::types::{ abis::{ - kernel_circuit_public_inputs::PrivateKernelCircuitPublicInputs, - log_hash::{NoteLogHash, ScopedEncryptedLogHash}, - note_hash::ScopedNoteHash, - nullifier::ScopedNullifier, + kernel_circuit_public_inputs::PrivateKernelCircuitPublicInputs, note_hash::ScopedNoteHash, + nullifier::ScopedNullifier, private_log::PrivateLogData, side_effect::scoped::Scoped, }, address::AztecAddress, - constants::{ - MAX_ENCRYPTED_LOGS_PER_TX, MAX_NOTE_ENCRYPTED_LOGS_PER_TX, MAX_NOTE_HASHES_PER_TX, - MAX_NULLIFIERS_PER_TX, - }, - hash::{mask_encrypted_log_hash, silo_note_hash, silo_nullifier}, + constants::{MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, MAX_PRIVATE_LOGS_PER_TX}, + hash::{compute_siloed_private_log_field, silo_note_hash, silo_nullifier}, utils::arrays::sort_by_counter_asc, }; @@ -25,7 +20,7 @@ pub struct ResetOutputComposer, pub note_hash_siloing_amount: u32, pub nullifier_siloing_amount: u32, - pub encrypted_log_siloing_amount: u32, + pub private_log_siloing_amount: u32, pub hints: ResetOutputHints, } @@ -36,7 +31,7 @@ impl Self { let hints = generate_reset_output_hints(previous_kernel, transient_data_index_hints); ResetOutputComposer { @@ -44,7 +39,7 @@ impl [NoteLogHash; MAX_NOTE_ENCRYPTED_LOGS_PER_TX] { - let mut log_hashes = sort_by_counter_asc(self.hints.kept_note_encrypted_log_hashes); - for i in 0..log_hashes.len() { - log_hashes[i].note_hash_counter = 0; + ) -> [Scoped; MAX_PRIVATE_LOGS_PER_TX] { + let mut private_logs = sort_by_counter_asc(self.hints.kept_private_logs); + for i in 0..private_logs.len() { + private_logs[i].inner = silo_private_log(private_logs[i]); + // The following modifies self.hints.kept_private_logs :( + // private_logs[i].inner.log = silo_private_log(private_logs[i]); + private_logs[i].contract_address = AztecAddress::zero(); } - log_hashes + private_logs } +} - unconstrained fn get_sorted_masked_encrypted_log_hashes( - self, - ) -> [ScopedEncryptedLogHash; MAX_ENCRYPTED_LOGS_PER_TX] { - let mut log_hashes = sort_by_counter_asc(self.previous_kernel.end.encrypted_logs_hashes); - for i in 0..log_hashes.len() { - log_hashes[i].contract_address = mask_encrypted_log_hash(log_hashes[i]); - log_hashes[i].log_hash.randomness = 0; - } - log_hashes +fn silo_private_log(scoped: Scoped) -> PrivateLogData { + let mut serialized = scoped.inner.serialize(); + if !scoped.contract_address.is_zero() { + serialized[0] = compute_siloed_private_log_field(scoped.contract_address, serialized[0]); } + PrivateLogData::deserialize(serialized) } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/reset_output_composer/reset_output_hints.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/reset_output_composer/reset_output_hints.nr index 64d0b55aade..c181955431b 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/reset_output_composer/reset_output_hints.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/reset_output_composer/reset_output_hints.nr @@ -1,5 +1,5 @@ -mod get_transient_or_propagated_note_hash_indexes_for_logs; -mod squash_transient_data; +pub mod get_transient_or_propagated_note_hash_indexes_for_logs; +pub mod squash_transient_data; use crate::components::reset_output_composer::reset_output_hints::{ get_transient_or_propagated_note_hash_indexes_for_logs::get_transient_or_propagated_note_hash_indexes_for_logs, @@ -8,13 +8,10 @@ use crate::components::reset_output_composer::reset_output_hints::{ use dep::reset_kernel_lib::TransientDataIndexHint; use dep::types::{ abis::{ - kernel_circuit_public_inputs::PrivateKernelCircuitPublicInputs, log_hash::NoteLogHash, - note_hash::ScopedNoteHash, nullifier::ScopedNullifier, - }, - constants::{ - MAX_ENCRYPTED_LOGS_PER_TX, MAX_NOTE_ENCRYPTED_LOGS_PER_TX, MAX_NOTE_HASHES_PER_TX, - MAX_NULLIFIERS_PER_TX, + kernel_circuit_public_inputs::PrivateKernelCircuitPublicInputs, note_hash::ScopedNoteHash, + nullifier::ScopedNullifier, private_log::PrivateLogData, side_effect::scoped::Scoped, }, + constants::{MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, MAX_PRIVATE_LOGS_PER_TX}, utils::arrays::{get_order_hints_asc, OrderHint}, }; @@ -25,22 +22,20 @@ pub struct ResetOutputHints { // nullifiers pub kept_nullifiers: [ScopedNullifier; MAX_NULLIFIERS_PER_TX], pub sorted_nullifier_indexes: [u32; MAX_NULLIFIERS_PER_TX], - // note_encrypted_log_hashes - pub kept_note_encrypted_log_hashes: [NoteLogHash; MAX_NOTE_ENCRYPTED_LOGS_PER_TX], - pub sorted_note_encrypted_log_hash_indexes: [u32; MAX_NOTE_ENCRYPTED_LOGS_PER_TX], - pub transient_or_propagated_note_hash_indexes_for_logs: [u32; MAX_NOTE_ENCRYPTED_LOGS_PER_TX], - // encrypted_log_hashes - pub sorted_encrypted_log_hash_indexes: [u32; MAX_ENCRYPTED_LOGS_PER_TX], + // private_logs + pub kept_private_logs: [Scoped; MAX_PRIVATE_LOGS_PER_TX], + pub transient_or_propagated_note_hash_indexes_for_logs: [u32; MAX_PRIVATE_LOGS_PER_TX], + pub sorted_private_log_indexes: [u32; MAX_PRIVATE_LOGS_PER_TX], } pub unconstrained fn generate_reset_output_hints( previous_kernel: PrivateKernelCircuitPublicInputs, transient_data_index_hints: [TransientDataIndexHint; NUM_TRANSIENT_DATA_INDEX_HINTS], ) -> ResetOutputHints { - let (kept_note_hashes, kept_nullifiers, kept_note_encrypted_log_hashes) = squash_transient_data( + let (kept_note_hashes, kept_nullifiers, kept_private_logs) = squash_transient_data( previous_kernel.end.note_hashes, previous_kernel.end.nullifiers, - previous_kernel.end.note_encrypted_logs_hashes, + previous_kernel.end.private_logs, transient_data_index_hints, ); @@ -52,30 +47,23 @@ pub unconstrained fn generate_reset_output_hints( - note_logs: [NoteLogHash; NUM_LOGS], + logs: [Scoped; NUM_LOGS], note_hashes: [ScopedNoteHash; NUM_NOTE_HASHES], expected_note_hashes: [ScopedNoteHash; NUM_NOTE_HASHES], transient_data_index_hints: [TransientDataIndexHint; NUM_INDEX_HINTS], ) -> [u32; NUM_LOGS] { let mut indexes = [0; NUM_LOGS]; - for i in 0..note_logs.len() { - let log_note_hash_counter = note_logs[i].note_hash_counter; - let mut propagated = false; - for j in 0..expected_note_hashes.len() { - if !propagated & (expected_note_hashes[j].counter() == log_note_hash_counter) { - indexes[i] = j; - propagated = true; + for i in 0..logs.len() { + let log_note_hash_counter = logs[i].inner.note_hash_counter; + if log_note_hash_counter != 0 { + let mut propagated = false; + for j in 0..expected_note_hashes.len() { + if !propagated & (expected_note_hashes[j].counter() == log_note_hash_counter) { + indexes[i] = j; + propagated = true; + } } - } - if !propagated { - for j in 0..note_hashes.len() { - if note_hashes[j].counter() == log_note_hash_counter { - indexes[i] = find_index_hint( - transient_data_index_hints, - |hint: TransientDataIndexHint| hint.note_hash_index == j, - ); + if !propagated { + for j in 0..note_hashes.len() { + if note_hashes[j].counter() == log_note_hash_counter { + indexes[i] = find_index_hint( + transient_data_index_hints, + |hint: TransientDataIndexHint| hint.note_hash_index == j, + ); + } } } } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/reset_output_composer/reset_output_hints/squash_transient_data.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/reset_output_composer/reset_output_hints/squash_transient_data.nr index fd7bef196ec..888705bdbb7 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/reset_output_composer/reset_output_hints/squash_transient_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/reset_output_composer/reset_output_hints/squash_transient_data.nr @@ -1,14 +1,15 @@ use dep::reset_kernel_lib::TransientDataIndexHint; use dep::types::abis::{ - log_hash::NoteLogHash, note_hash::ScopedNoteHash, nullifier::ScopedNullifier, + note_hash::ScopedNoteHash, nullifier::ScopedNullifier, private_log::PrivateLogData, + side_effect::scoped::Scoped, }; pub unconstrained fn squash_transient_data( note_hashes: [ScopedNoteHash; M], nullifiers: [ScopedNullifier; N], - logs: [NoteLogHash; P], + logs: [Scoped; P], transient_data_index_hints: [TransientDataIndexHint; NUM_TRANSIENT_DATA_INDEX_HINTS], -) -> ([ScopedNoteHash; M], [ScopedNullifier; N], [NoteLogHash; P]) { +) -> ([ScopedNoteHash; M], [ScopedNullifier; N], [Scoped; P]) { let mut transient_nullifier_indexes_for_note_hashes = [N; M]; let mut transient_note_hash_indexes_for_nullifiers = [M; N]; for i in 0..transient_data_index_hints.len() { @@ -37,13 +38,17 @@ pub unconstrained fn squash_transient_data) -> bool { + let siloed_field = + compute_siloed_private_log_field(prev.contract_address, prev.inner.log.fields[0]); + let mut is_valid = (out.fields[0] == siloed_field) | prev.contract_address.is_zero(); + for i in 1..PRIVATE_LOG_SIZE_IN_FIELDS { + is_valid &= out.fields[i] == prev.inner.log.fields[i]; + } + is_valid +} + pub struct ResetOutputValidator { output: PrivateKernelCircuitPublicInputs, previous_kernel: PrivateKernelCircuitPublicInputs, @@ -23,7 +39,7 @@ pub struct ResetOutputValidator Self { ResetOutputValidator { @@ -45,7 +61,7 @@ impl validate_note_logs. - // note_hash_counter was used when squashing the note log along with its corresponding note hash. - // It won't be used later on, so we can set it to 0 here. - // It serves as a clue for the tail circuit to check that all the note logs are sorted in a reset circuit. - // This is not capped because we don't know how many logs there are. There can be any number of logs for each note hash. - // Consider adding a constant for it only when this becomes too costly. - assert_sorted_transformed_value_array( - self.hints.kept_note_encrypted_log_hashes, - self.output.end.note_encrypted_logs_hashes, - |prev: NoteLogHash, out: NoteLogHash| { - (out.value == prev.value) - & (out.length == prev.length) - & (out.counter == prev.counter) - & (out.note_hash_counter == 0) - }, - self.hints.sorted_note_encrypted_log_hash_indexes, - ); - } - - fn validate_sorted_masked_encrypted_logs(self) { - // Don't need to check that the logs are already masked. - // If run repeatedly, it will return the masked contract address when randomness becomes 0. + fn validate_sorted_siloed_private_logs(self) { assert_sorted_transformed_value_array_capped_size( - self.previous_kernel.end.encrypted_logs_hashes, - self.output.end.encrypted_logs_hashes, - |prev: ScopedEncryptedLogHash, out: ScopedEncryptedLogHash| { - (out.contract_address == mask_encrypted_log_hash(prev)) - & (out.log_hash.value == prev.log_hash.value) - & (out.log_hash.length == prev.log_hash.length) - & (out.log_hash.counter == prev.log_hash.counter) - & (out.log_hash.randomness == 0) + self.hints.kept_private_logs, + self.output.end.private_logs, + |prev: Scoped, out: Scoped| { + is_valid_siloed_private_log(out.inner.log, prev) + & (out.inner.note_hash_counter == prev.inner.note_hash_counter) + & (out.inner.counter == prev.inner.counter) + & out.contract_address.is_zero() }, - self.hints.sorted_encrypted_log_hash_indexes, - self.encrypted_log_siloing_amount, + self.hints.sorted_private_log_indexes, + self.private_log_siloing_amount, ); } } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_output_composer.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_output_composer.nr index 94874b8c86b..dd37b20866e 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_output_composer.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_output_composer.nr @@ -1,21 +1,21 @@ mod meter_gas_used; -use crate::components::{ - private_kernel_circuit_public_inputs_composer::PrivateKernelCircuitPublicInputsComposer, - tail_output_composer::meter_gas_used::meter_gas_used, -}; +use crate::components::private_kernel_circuit_public_inputs_composer::PrivateKernelCircuitPublicInputsComposer; use dep::types::{ abis::{ accumulated_data::combined_accumulated_data::CombinedAccumulatedData, combined_constant_data::CombinedConstantData, global_variables::GlobalVariables, kernel_circuit_public_inputs::{KernelCircuitPublicInputs, PrivateKernelCircuitPublicInputs}, - log_hash::{NoteLogHash, ScopedEncryptedLogHash, ScopedLogHash}, + log_hash::ScopedLogHash, note_hash::ScopedNoteHash, nullifier::ScopedNullifier, + private_log::PrivateLogData, + side_effect::scoped::Scoped, }, messaging::l2_to_l1_message::ScopedL2ToL1Message, }; +pub use meter_gas_used::meter_gas_used; pub struct TailOutputComposer { output_composer: PrivateKernelCircuitPublicInputsComposer, @@ -42,26 +42,17 @@ impl TailOutputComposer { output } - fn build_combined_accumulated_data(self) -> CombinedAccumulatedData { + unconstrained fn build_combined_accumulated_data(self) -> CombinedAccumulatedData { let source = self.output_composer.public_inputs.end; let mut data = CombinedAccumulatedData::empty(); data.note_hashes = source.note_hashes.storage.map(|n: ScopedNoteHash| n.note_hash.value); data.nullifiers = source.nullifiers.storage.map(|n: ScopedNullifier| n.nullifier.value); data.l2_to_l1_msgs = source.l2_to_l1_msgs.storage.map(|m: ScopedL2ToL1Message| m.expose_to_public()); - data.note_encrypted_logs_hashes = - source.note_encrypted_logs_hashes.storage.map(|l: NoteLogHash| l.expose_to_public()); - data.encrypted_logs_hashes = source.encrypted_logs_hashes.storage.map( - |l: ScopedEncryptedLogHash| l.expose_to_public(), - ); + data.private_logs = + source.private_logs.storage.map(|l: Scoped| l.inner.log); data.contract_class_logs_hashes = source.contract_class_logs_hashes.storage.map(|l: ScopedLogHash| l.expose_to_public()); - data.note_encrypted_log_preimages_length = - source.note_encrypted_logs_hashes.storage.fold(0, |len, l: NoteLogHash| len + l.length); - data.encrypted_log_preimages_length = source.encrypted_logs_hashes.storage.fold( - 0, - |len, l: ScopedEncryptedLogHash| len + l.log_hash.length, - ); data.contract_class_log_preimages_length = source.contract_class_logs_hashes.storage.fold( 0, |len, l: ScopedLogHash| len + l.log_hash.length, diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_output_composer/meter_gas_used.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_output_composer/meter_gas_used.nr index 57aa52bdd86..a2eaeed7b8b 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_output_composer/meter_gas_used.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_output_composer/meter_gas_used.nr @@ -1,33 +1,34 @@ use dep::types::{ abis::{accumulated_data::combined_accumulated_data::CombinedAccumulatedData, gas::Gas}, constants::{ - DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE, L2_GAS_PER_LOG_BYTE, L2_GAS_PER_NOTE_HASH, - L2_GAS_PER_NULLIFIER, + DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE, L2_GAS_PER_L2_TO_L1_MSG, L2_GAS_PER_LOG_BYTE, + L2_GAS_PER_NOTE_HASH, L2_GAS_PER_NULLIFIER, L2_GAS_PER_PRIVATE_LOG, + PRIVATE_LOG_SIZE_IN_FIELDS, }, utils::arrays::array_length, }; pub fn meter_gas_used(data: CombinedAccumulatedData) -> Gas { - let mut metered_da_bytes = 0; + let mut metered_da_fields = 0; let mut metered_l2_gas = 0; let num_note_hashes = array_length(data.note_hashes); - metered_da_bytes += num_note_hashes * DA_BYTES_PER_FIELD; + metered_da_fields += num_note_hashes; metered_l2_gas += num_note_hashes * L2_GAS_PER_NOTE_HASH; let num_nullifiers = array_length(data.nullifiers); - metered_da_bytes += num_nullifiers * DA_BYTES_PER_FIELD; + metered_da_fields += num_nullifiers; metered_l2_gas += num_nullifiers * L2_GAS_PER_NULLIFIER; let num_l2_to_l1_msgs = array_length(data.l2_to_l1_msgs); - metered_da_bytes += num_l2_to_l1_msgs * DA_BYTES_PER_FIELD; + metered_da_fields += num_l2_to_l1_msgs; + metered_l2_gas += num_l2_to_l1_msgs * L2_GAS_PER_L2_TO_L1_MSG; - metered_da_bytes += data.note_encrypted_log_preimages_length as u32; - metered_l2_gas += data.note_encrypted_log_preimages_length as u32 * L2_GAS_PER_LOG_BYTE; - - metered_da_bytes += data.encrypted_log_preimages_length as u32; - metered_l2_gas += data.encrypted_log_preimages_length as u32 * L2_GAS_PER_LOG_BYTE; + let num_private_logs = array_length(data.private_logs); + metered_da_fields += num_private_logs * PRIVATE_LOG_SIZE_IN_FIELDS; + metered_l2_gas += num_private_logs * L2_GAS_PER_PRIVATE_LOG; + let mut metered_da_bytes = metered_da_fields * DA_BYTES_PER_FIELD; metered_da_bytes += data.contract_class_log_preimages_length as u32; metered_l2_gas += data.contract_class_log_preimages_length as u32 * L2_GAS_PER_LOG_BYTE; diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_output_validator.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_output_validator.nr index 458a65a26f0..693fe8b6a58 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_output_validator.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_output_validator.nr @@ -1,18 +1,18 @@ mod tail_output_hints; -use crate::components::{ - tail_output_composer::meter_gas_used::meter_gas_used, - tail_output_validator::tail_output_hints::{generate_tail_output_hints, TailOutputHints}, -}; +use crate::components::tail_output_composer::meter_gas_used; use dep::types::{ abis::{ kernel_circuit_public_inputs::{KernelCircuitPublicInputs, PrivateKernelCircuitPublicInputs}, - log_hash::{NoteLogHash, ScopedEncryptedLogHash, ScopedLogHash}, + log_hash::ScopedLogHash, + private_log::PrivateLogData, + side_effect::scoped::Scoped, }, messaging::l2_to_l1_message::ScopedL2ToL1Message, traits::{is_empty, is_empty_array}, utils::arrays::assert_exposed_sorted_transformed_value_array, }; +use tail_output_hints::{generate_tail_output_hints, TailOutputHints}; pub struct TailOutputValidator { output: KernelCircuitPublicInputs, @@ -92,22 +92,11 @@ impl TailOutputValidator { assert_eq(nullifiers[i].value(), self.output.end.nullifiers[i], "mismatch nullifiers"); } - // note_encrypted_logs_hashes - assert_eq( - self.previous_kernel.end.note_encrypted_logs_hashes.map(|log: NoteLogHash| { - log.expose_to_public() - }), - self.output.end.note_encrypted_logs_hashes, - "mismatch note_encrypted_logs_hashes", - ); - - // encrypted_logs_hashes + // private_logs assert_eq( - self.previous_kernel.end.encrypted_logs_hashes.map(|log: ScopedEncryptedLogHash| { - log.expose_to_public() - }), - self.output.end.encrypted_logs_hashes, - "mismatch encrypted_logs_hashes", + self.previous_kernel.end.private_logs.map(|l: Scoped| l.inner.log), + self.output.end.private_logs, + "mismatch private_logs", ); } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_composer.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_composer.nr index 05191951423..c4a1d85e924 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_composer.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_composer.nr @@ -1,15 +1,12 @@ mod meter_gas_used; mod split_to_public; -use crate::components::{ - private_kernel_circuit_public_inputs_composer::PrivateKernelCircuitPublicInputsComposer, - tail_to_public_output_composer::{ - meter_gas_used::meter_gas_used, split_to_public::split_to_public, - }, -}; +use crate::components::private_kernel_circuit_public_inputs_composer::PrivateKernelCircuitPublicInputsComposer; use dep::types::abis::kernel_circuit_public_inputs::{ PrivateKernelCircuitPublicInputs, PrivateToPublicKernelCircuitPublicInputs, }; +use split_to_public::split_to_public; +pub use meter_gas_used::meter_gas_used; pub struct TailToPublicOutputComposer { output_composer: PrivateKernelCircuitPublicInputsComposer, diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_composer/meter_gas_used.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_composer/meter_gas_used.nr index c12b75696b5..30f85b35545 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_composer/meter_gas_used.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_composer/meter_gas_used.nr @@ -1,42 +1,38 @@ use dep::types::{ abis::{ - accumulated_data::PrivateToPublicAccumulatedData, - gas::Gas, - log_hash::{LogHash, ScopedLogHash}, + accumulated_data::PrivateToPublicAccumulatedData, gas::Gas, log_hash::ScopedLogHash, public_call_request::PublicCallRequest, }, constants::{ - DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE, FIXED_AVM_STARTUP_L2_GAS, L2_GAS_PER_LOG_BYTE, - L2_GAS_PER_NOTE_HASH, L2_GAS_PER_NULLIFIER, + DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE, FIXED_AVM_STARTUP_L2_GAS, L2_GAS_PER_L2_TO_L1_MSG, + L2_GAS_PER_LOG_BYTE, L2_GAS_PER_NOTE_HASH, L2_GAS_PER_NULLIFIER, L2_GAS_PER_PRIVATE_LOG, + PRIVATE_LOG_SIZE_IN_FIELDS, }, traits::is_empty, utils::arrays::array_length, }; fn meter_accumulated_data_gas_used(data: PrivateToPublicAccumulatedData) -> Gas { - let mut metered_da_bytes = 0; + let mut metered_da_fields = 0; let mut metered_l2_gas = 0; let num_note_hashes = array_length(data.note_hashes); - metered_da_bytes += num_note_hashes * DA_BYTES_PER_FIELD; + metered_da_fields += num_note_hashes; metered_l2_gas += num_note_hashes * L2_GAS_PER_NOTE_HASH; let num_nullifiers = array_length(data.nullifiers); - metered_da_bytes += num_nullifiers * DA_BYTES_PER_FIELD; + metered_da_fields += num_nullifiers; metered_l2_gas += num_nullifiers * L2_GAS_PER_NULLIFIER; - metered_da_bytes += array_length(data.l2_to_l1_msgs) * DA_BYTES_PER_FIELD; + let num_l2_to_l1_msgs = array_length(data.l2_to_l1_msgs); + metered_da_fields += num_l2_to_l1_msgs; + metered_l2_gas += num_l2_to_l1_msgs * L2_GAS_PER_L2_TO_L1_MSG; - let note_encrypted_log_preimages_length = - data.note_encrypted_logs_hashes.fold(0, |len, l: LogHash| len + l.length); - metered_da_bytes += note_encrypted_log_preimages_length as u32; - metered_l2_gas += note_encrypted_log_preimages_length as u32 * L2_GAS_PER_LOG_BYTE; - - let encrypted_log_preimages_length = - data.encrypted_logs_hashes.fold(0, |len, l: ScopedLogHash| len + l.log_hash.length); - metered_da_bytes += encrypted_log_preimages_length as u32; - metered_l2_gas += encrypted_log_preimages_length as u32 * L2_GAS_PER_LOG_BYTE; + let num_private_logs = array_length(data.private_logs); + metered_da_fields += num_private_logs * PRIVATE_LOG_SIZE_IN_FIELDS; + metered_l2_gas += num_private_logs * L2_GAS_PER_PRIVATE_LOG; + let mut metered_da_bytes = metered_da_fields * DA_BYTES_PER_FIELD; let contract_class_log_preimages_length = data.contract_class_logs_hashes.fold(0, |len, l: ScopedLogHash| len + l.log_hash.length); metered_da_bytes += contract_class_log_preimages_length as u32; diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_composer/split_to_public.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_composer/split_to_public.nr index 5d723d0804d..eae36df71cc 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_composer/split_to_public.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_composer/split_to_public.nr @@ -47,28 +47,14 @@ pub unconstrained fn split_to_public( } } - let note_encrypted_logs_hashes = data.note_encrypted_logs_hashes; - for i in 0..note_encrypted_logs_hashes.max_len() { - if i < note_encrypted_logs_hashes.len() { - let note_encrypted_log_hash = note_encrypted_logs_hashes.get_unchecked(i); - let public_log_hash = note_encrypted_log_hash.expose_to_public(); - if note_encrypted_log_hash.counter < min_revertible_side_effect_counter { - non_revertible_builder.note_encrypted_logs_hashes.push(public_log_hash); + let private_logs = data.private_logs; + for i in 0..private_logs.max_len() { + if i < private_logs.len() { + let private_log = private_logs.get_unchecked(i); + if private_log.inner.counter < min_revertible_side_effect_counter { + non_revertible_builder.private_logs.push(private_log.inner.log); } else { - revertible_builder.note_encrypted_logs_hashes.push(public_log_hash); - } - } - } - - let encrypted_logs_hashes = data.encrypted_logs_hashes; - for i in 0..encrypted_logs_hashes.max_len() { - if i < encrypted_logs_hashes.len() { - let encrypted_log_hash = encrypted_logs_hashes.get_unchecked(i); - let public_log_hash = encrypted_log_hash.expose_to_public(); - if encrypted_log_hash.counter() < min_revertible_side_effect_counter { - non_revertible_builder.encrypted_logs_hashes.push(public_log_hash); - } else { - revertible_builder.encrypted_logs_hashes.push(public_log_hash); + revertible_builder.private_logs.push(private_log.inner.log); } } } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_validator.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_validator.nr index ef1437dafc1..8f85ec7f367 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_validator.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_validator.nr @@ -1,21 +1,17 @@ mod tail_to_public_output_hints; -use crate::components::{ - tail_to_public_output_composer::meter_gas_used::meter_gas_used, - tail_to_public_output_validator::tail_to_public_output_hints::{ - generate_tail_to_public_output_hints, TailToPublicOutputHints, - }, -}; +use crate::components::tail_to_public_output_composer::meter_gas_used; use dep::types::{ abis::{ kernel_circuit_public_inputs::{ PrivateKernelCircuitPublicInputs, PrivateToPublicKernelCircuitPublicInputs, }, - log_hash::{LogHash, NoteLogHash, ScopedEncryptedLogHash, ScopedLogHash}, + log_hash::ScopedLogHash, note_hash::ScopedNoteHash, nullifier::ScopedNullifier, + private_log::{PrivateLog, PrivateLogData}, public_call_request::PublicCallRequest, - side_effect::Counted, + side_effect::{Counted, scoped::Scoped}, }, messaging::l2_to_l1_message::ScopedL2ToL1Message, utils::arrays::{ @@ -23,6 +19,7 @@ use dep::types::{ assert_split_sorted_transformed_value_arrays_desc, assert_split_transformed_value_arrays, }, }; +use tail_to_public_output_hints::{generate_tail_to_public_output_hints, TailToPublicOutputHints}; pub struct TailToPublicOutputValidator { output: PrivateToPublicKernelCircuitPublicInputs, @@ -88,21 +85,12 @@ impl TailToPublicOutputValidator { split_counter, ); - // note_encrypted_logs_hashes - assert_split_transformed_value_arrays( - prev_data.note_encrypted_logs_hashes, - output_non_revertible.note_encrypted_logs_hashes, - output_revertible.note_encrypted_logs_hashes, - |prev: NoteLogHash, out: LogHash| out == prev.expose_to_public(), - split_counter, - ); - - // encrypted_logs_hashes + // private_logs assert_split_transformed_value_arrays( - prev_data.encrypted_logs_hashes, - output_non_revertible.encrypted_logs_hashes, - output_revertible.encrypted_logs_hashes, - |prev: ScopedEncryptedLogHash, out: ScopedLogHash| out == prev.expose_to_public(), + prev_data.private_logs, + output_non_revertible.private_logs, + output_revertible.private_logs, + |l: Scoped, out: PrivateLog| out == l.inner.log, split_counter, ); } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr index 5f6eceb0c47..aee9521cd15 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr @@ -113,11 +113,11 @@ mod tests { // note_hash_read_requests builder.private_call.append_note_hash_read_requests(2); - let note_hash_read_requests = builder.private_call.note_hash_read_requests.storage; + let note_hash_read_requests = builder.private_call.note_hash_read_requests.storage(); - // encrypted_logs_hashes - builder.private_call.append_encrypted_log_hashes(1); - let encrypted_log_hashes = builder.private_call.encrypted_logs_hashes.storage; + // private_logs + builder.private_call.append_private_logs(2); + let private_logs = builder.private_call.private_logs.storage(); let public_inputs = builder.execute(); assert_array_eq( @@ -125,8 +125,8 @@ mod tests { [note_hash_read_requests[0], note_hash_read_requests[1]], ); assert_array_eq( - public_inputs.end.encrypted_logs_hashes, - [encrypted_log_hashes[0]], + public_inputs.end.private_logs, + [private_logs[0], private_logs[1]], ); } } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr index dba69275d12..e226b38865d 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr @@ -131,11 +131,11 @@ mod tests { builder.private_call.append_note_hash_read_requests(2); let curr_note_hash_read_requests = builder.private_call.note_hash_read_requests.storage; - // encrypted_logs_hashes - builder.previous_kernel.append_encrypted_log_hashes(2); - let prev_encrypted_log_hashes = builder.previous_kernel.encrypted_logs_hashes.storage; - builder.private_call.append_encrypted_log_hashes(1); - let curr_encrypted_log_hashes = builder.private_call.encrypted_logs_hashes.storage; + // private_logs + builder.previous_kernel.append_private_logs(2); + let prev_private_logs = builder.previous_kernel.private_logs.storage(); + builder.private_call.append_private_logs(1); + let curr_private_logs = builder.private_call.private_logs.storage(); let public_inputs = builder.execute(); assert_array_eq( @@ -147,12 +147,8 @@ mod tests { ], ); assert_array_eq( - public_inputs.end.encrypted_logs_hashes, - [ - prev_encrypted_log_hashes[0], - prev_encrypted_log_hashes[1], - curr_encrypted_log_hashes[0], - ], + public_inputs.end.private_logs, + [prev_private_logs[0], prev_private_logs[1], curr_private_logs[0]], ); } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_reset.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_reset.nr index 8a2a11b7e09..4f1ca592194 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_reset.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_reset.nr @@ -30,7 +30,7 @@ pub struct PrivateKernelResetCircuitPrivateInputs PrivateKernelResetCircuitPrivateInputs { - fn new( + pub fn new( previous_kernel: PrivateKernelDataWithoutPublicInputs, previous_kernel_public_inputs: PrivateKernelCircuitPublicInputs, hints: PrivateKernelResetHints, @@ -46,7 +46,7 @@ impl, note_hash_siloing_amount: u32, nullifier_siloing_amount: u32, - encrypted_log_siloing_amount: u32, + private_log_siloing_amount: u32, ) -> (PrivateKernelCircuitPublicInputs, ResetOutputHints) { let composer = ResetOutputComposer::new( self.previous_kernel.public_inputs, @@ -54,7 +54,7 @@ impl PrivateKernelCircuitPublicInputs { let previous_public_inputs = self.previous_kernel.public_inputs; let validation_request_processor = PrivateValidationRequestProcessor { @@ -96,7 +96,7 @@ impl { + global NOTE_HASH_PENDING_AMOUNT: u32 = 6; + global NOTE_HASH_SETTLED_AMOUNT: u32 = 3; + global NULLIFIER_PENDING_AMOUNT: u32 = 5; + global NULLIFIER_SETTLED_AMOUNT: u32 = 2; + global NULLIFIER_KEYS: u32 = 2; + global TRANSIENT_DATA_AMOUNT: u32 = 6; + global NOTE_HASH_SILOING_AMOUNT: u32 = 6; + global NULLIFIER_SILOING_AMOUNT: u32 = 6; + global PRIVATE_LOG_SILOING_AMOUNT: u32 = 5; + + struct PrivateKernelResetInputsBuilder { previous_kernel: FixtureBuilder, - transient_data_index_hints: [TransientDataIndexHint; NUM_INDEX_HINTS], - note_hash_read_request_hints_builder: NoteHashReadRequestHintsBuilder<6, 3>, - nullifier_read_request_hints_builder: NullifierReadRequestHintsBuilder<5, 2>, + transient_data_index_hints: [TransientDataIndexHint; TRANSIENT_DATA_AMOUNT], + note_hash_read_request_hints_builder: NoteHashReadRequestHintsBuilder, + nullifier_read_request_hints_builder: NullifierReadRequestHintsBuilder, validation_requests_split_counter: u32, note_hash_siloing_amount: u32, nullifier_siloing_amount: u32, - encrypted_log_siloing_amount: u32, + private_log_siloing_amount: u32, } - impl PrivateKernelResetInputsBuilder<6> { + impl PrivateKernelResetInputsBuilder { pub fn new() -> Self { let mut previous_kernel = FixtureBuilder::new().in_vk_tree(PRIVATE_KERNEL_INNER_INDEX); previous_kernel.set_first_nullifier(); @@ -177,23 +185,22 @@ mod tests { Self { previous_kernel, transient_data_index_hints: [ - TransientDataIndexHint::nada(MAX_NULLIFIERS_PER_TX, MAX_NOTE_HASHES_PER_TX); 6 - ], - note_hash_read_request_hints_builder: NoteHashReadRequestHintsBuilder::new(), - nullifier_read_request_hints_builder: NullifierReadRequestHintsBuilder::new(), - validation_requests_split_counter: 0, - note_hash_siloing_amount: 0, - nullifier_siloing_amount: 0, - encrypted_log_siloing_amount: 0, + TransientDataIndexHint::nada(MAX_NULLIFIERS_PER_TX, MAX_NOTE_HASHES_PER_TX); + TRANSIENT_DATA_AMOUNT + ], + note_hash_read_request_hints_builder: NoteHashReadRequestHintsBuilder::new(), + nullifier_read_request_hints_builder: NullifierReadRequestHintsBuilder::new(), + validation_requests_split_counter: 0, + note_hash_siloing_amount: 0, + nullifier_siloing_amount: 0, + private_log_siloing_amount: 0, + } } - } - } - impl PrivateKernelResetInputsBuilder { pub fn with_siloing(&mut self) -> Self { - self.note_hash_siloing_amount = 6; - self.nullifier_siloing_amount = 6; - self.encrypted_log_siloing_amount = 4; + self.note_hash_siloing_amount = NOTE_HASH_SILOING_AMOUNT; + self.nullifier_siloing_amount = NULLIFIER_SILOING_AMOUNT; + self.private_log_siloing_amount = PRIVATE_LOG_SILOING_AMOUNT; *self } @@ -258,25 +265,14 @@ mod tests { output } - pub fn compute_output_note_logs( - _self: Self, - logs: [NoteLogHash; N], - ) -> [NoteLogHash; N] { - let mut output = logs; - for i in 0..N { - output[i].note_hash_counter = 0; - } - output - } - - pub fn compute_output_encrypted_logs( + pub fn compute_output_private_logs( _self: Self, - logs: [ScopedEncryptedLogHash; N], - ) -> [ScopedEncryptedLogHash; N] { - let mut output = logs; + private_logs: [Scoped; N], + ) -> [Scoped; N] { + let mut output = private_logs; for i in 0..N { - output[i].contract_address = mask_encrypted_log_hash(output[i]); - output[i].log_hash.randomness = 0; + output[i].inner.log = silo_private_log(output[i]); + output[i].contract_address = AztecAddress::zero(); } output } @@ -290,7 +286,7 @@ mod tests { note_hash_read_request_hints, nullifier_read_request_hints, key_validation_hints: [ - KeyValidationHint::nada(MAX_KEY_VALIDATION_REQUESTS_PER_TX); 2 + KeyValidationHint::nada(MAX_KEY_VALIDATION_REQUESTS_PER_TX); NULLIFIER_KEYS ], transient_data_index_hints: self.transient_data_index_hints, validation_requests_split_counter: self.validation_requests_split_counter, @@ -303,7 +299,7 @@ mod tests { kernel.execute( self.note_hash_siloing_amount, self.nullifier_siloing_amount, - self.encrypted_log_siloing_amount, + self.private_log_siloing_amount, ) } @@ -460,7 +456,7 @@ mod tests { // The nullifier at index 1 is chopped. assert_array_eq(public_inputs.end.nullifiers, [nullifiers[0], nullifiers[2]]); - assert(is_empty_array(public_inputs.end.note_encrypted_logs_hashes)); + assert(is_empty_array(public_inputs.end.private_logs)); } #[test] @@ -472,7 +468,7 @@ mod tests { builder.nullify_pending_note_hash(1, 0); let note_hashes = builder.previous_kernel.note_hashes.storage(); let nullifiers = builder.previous_kernel.nullifiers.storage(); - let note_logs = builder.previous_kernel.note_encrypted_logs_hashes.storage(); + let private_logs = builder.previous_kernel.private_logs.storage(); let public_inputs = builder.execute(); // The 0th hash is chopped. @@ -481,8 +477,8 @@ mod tests { // The nullifier at index 1 is chopped. assert_array_eq(public_inputs.end.nullifiers, [nullifiers[0], nullifiers[2]]); - // The 0th note log is chopped. - assert_array_eq(public_inputs.end.note_encrypted_logs_hashes, [note_logs[1]]); + // The 0th log is chopped. + assert_array_eq(public_inputs.end.private_logs, [private_logs[1]]); } #[test] @@ -501,7 +497,7 @@ mod tests { // Only the first nullifier is left after squashing. assert_array_eq(public_inputs.end.nullifiers, [nullifiers[0]]); - assert(is_empty_array(public_inputs.end.note_encrypted_logs_hashes)); + assert(is_empty_array(public_inputs.end.private_logs)); } #[test] @@ -536,7 +532,7 @@ mod tests { // Only the first nullifier is left after squashing. assert_array_eq(public_inputs.end.nullifiers, [nullifiers[0]]); - assert(is_empty_array(public_inputs.end.note_encrypted_logs_hashes)); + assert(is_empty_array(public_inputs.end.private_logs)); } #[test(should_fail_with = "Value of the hinted transient note hash does not match")] @@ -581,26 +577,24 @@ mod tests { fn squashing_and_siloing_and_ordering_succeeds() { let mut builder = PrivateKernelResetInputsBuilder::new().with_siloing(); - builder.previous_kernel.append_note_hashes_with_logs(4); + builder.previous_kernel.append_note_hashes_with_logs(1); + builder.previous_kernel.append_private_logs(1); // Log at index 1 is a non-note log. + builder.previous_kernel.append_note_hashes_with_logs(2); + builder.previous_kernel.append_private_logs(1); // Log at index 4 is a non-note log. + builder.previous_kernel.append_note_hashes(1); builder.previous_kernel.append_nullifiers(3); - builder.previous_kernel.append_encrypted_log_hashes(3); + // The nullifier at index 2 is nullifying a note hash that doesn't exist yet. builder.previous_kernel.nullifiers.storage[2].nullifier.note_hash = 9988; // Get ordered items before shuffling. let note_hashes = builder.previous_kernel.note_hashes.storage(); let nullifiers = builder.previous_kernel.nullifiers.storage(); - let note_logs = builder.previous_kernel.note_encrypted_logs_hashes.storage(); - let encrypted_logs = builder.previous_kernel.encrypted_logs_hashes.storage(); + let private_logs = builder.previous_kernel.private_logs.storage(); // Shuffle. swap_items(&mut builder.previous_kernel.note_hashes, 1, 0); swap_items(&mut builder.previous_kernel.note_hashes, 3, 2); swap_items(&mut builder.previous_kernel.nullifiers, 2, 3); - swap_items( - &mut builder.previous_kernel.note_encrypted_logs_hashes, - 1, - 3, - ); - swap_items(&mut builder.previous_kernel.encrypted_logs_hashes, 1, 2); - // The nullifier at index 1 is nullifying the note hash at index 3 (original index 2). + swap_items(&mut builder.previous_kernel.private_logs, 1, 2); + // The nullifier at index 1 is nullifying the note hash at index 2 (original index 2). builder.nullify_pending_note_hash(1, 3); let public_inputs = builder.execute(); @@ -615,20 +609,14 @@ mod tests { builder.compute_output_nullifiers([nullifiers[0], nullifiers[2], nullifiers[3]]); assert_array_eq(public_inputs.end.nullifiers, output_nullifiers); - // The note log at index 2 is chopped. - let output_note_logs = - builder.compute_output_note_logs([note_logs[0], note_logs[1], note_logs[3]]); - assert_array_eq( - public_inputs.end.note_encrypted_logs_hashes, - output_note_logs, - ); - - let output_logs = builder.compute_output_encrypted_logs([ - encrypted_logs[0], - encrypted_logs[1], - encrypted_logs[2], + // The note log at index 3 is chopped. + let output_logs = builder.compute_output_private_logs([ + private_logs[0], + private_logs[1], + private_logs[2], + private_logs[4], ]); - assert_array_eq(public_inputs.end.encrypted_logs_hashes, output_logs); + assert_array_eq(public_inputs.end.private_logs, output_logs); } #[test(should_fail_with = "note hashes have been siloed in a previous reset")] diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr index df248d4e3c0..fab13095851 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr @@ -67,7 +67,8 @@ mod tests { }; use dep::types::constants::{ DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE, EMPTY_NESTED_INDEX, GENERATOR_INDEX__IVSK_M, - L2_GAS_PER_LOG_BYTE, L2_GAS_PER_NULLIFIER, PRIVATE_KERNEL_INNER_INDEX, + L2_GAS_PER_L2_TO_L1_MSG, L2_GAS_PER_LOG_BYTE, L2_GAS_PER_NULLIFIER, L2_GAS_PER_PRIVATE_LOG, + PRIVATE_KERNEL_INNER_INDEX, PRIVATE_LOG_SIZE_IN_FIELDS, }; // TODO: Reduce the duplicated code/tests for PrivateKernelTailInputs and PrivateKernelTailToPublicInputs. @@ -121,32 +122,15 @@ mod tests { fn measuring_of_log_lengths() { let mut builder = PrivateKernelTailInputsBuilder::new(); // Logs for the previous call stack. - let prev_encrypted_logs_hash = 80; - let prev_encrypted_log_preimages_length = 13; let prev_contract_class_logs_hash = 956; let prev_contract_class_log_preimages_length = 24; - builder.previous_kernel.add_masked_encrypted_log_hash( - prev_encrypted_logs_hash, - prev_encrypted_log_preimages_length, - ); builder.previous_kernel.add_contract_class_log_hash( prev_contract_class_logs_hash, prev_contract_class_log_preimages_length, ); - // Logs for the current call stack. - let encrypted_logs_hash = 26; - let encrypted_log_preimages_length = 50; - builder.previous_kernel.add_masked_encrypted_log_hash( - encrypted_logs_hash, - encrypted_log_preimages_length, - ); let public_inputs = builder.execute(); - assert_eq( - public_inputs.end.encrypted_log_preimages_length, - prev_encrypted_log_preimages_length + encrypted_log_preimages_length, - ); assert_eq( public_inputs.end.contract_class_log_preimages_length, prev_contract_class_log_preimages_length, @@ -264,7 +248,7 @@ mod tests { Gas::tx_overhead() + Gas::new( 4 * DA_BYTES_PER_FIELD * DA_GAS_PER_BYTE, - 1 * L2_GAS_PER_NULLIFIER, + 1 * L2_GAS_PER_NULLIFIER + 3 * L2_GAS_PER_L2_TO_L1_MSG, ), public_inputs.gas_used, ); @@ -273,22 +257,21 @@ mod tests { #[test] unconstrained fn tx_consumed_gas_from_logs() { let mut builder = PrivateKernelTailInputsBuilder::new(); - builder.previous_kernel.add_masked_encrypted_log_hash(42, 3); - builder.previous_kernel.add_masked_encrypted_log_hash(42, 4); - builder.previous_kernel.add_contract_class_log_hash(42, 12); + builder.previous_kernel.append_siloed_private_logs_for_note(1, 33); + builder.previous_kernel.add_contract_class_log_hash(999, 12); builder.previous_kernel.end_setup(); - builder.previous_kernel.add_masked_encrypted_log_hash(42, 6); + builder.previous_kernel.append_siloed_private_logs_for_note(2, 44); let public_inputs = builder.execute(); - assert_eq( - Gas::tx_overhead() - + Gas::new( - (1 * DA_BYTES_PER_FIELD + 25) * DA_GAS_PER_BYTE, - 1 * L2_GAS_PER_NULLIFIER + 25 * L2_GAS_PER_LOG_BYTE, - ), - public_inputs.gas_used, - ); + let num_private_logs = 1 + 2; + let num_da_fields = 1 /* nullifier */ + num_private_logs * PRIVATE_LOG_SIZE_IN_FIELDS; + let num_da_bytes = (num_da_fields * DA_BYTES_PER_FIELD) + 12 /* contract_class_logs */; + let da_gas = num_da_bytes * DA_GAS_PER_BYTE; + let l2_gas = 1 * L2_GAS_PER_NULLIFIER + + num_private_logs * L2_GAS_PER_PRIVATE_LOG + + 12 * L2_GAS_PER_LOG_BYTE; + assert_eq(Gas::tx_overhead() + Gas::new(da_gas, l2_gas), public_inputs.gas_used); } #[test(should_fail_with = "The gas used exceeds the gas limits")] diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr index 8af1c421811..cbcb984f479 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr @@ -57,11 +57,8 @@ mod tests { }; use dep::types::{ abis::{ - gas::Gas, - kernel_circuit_public_inputs::PrivateToPublicKernelCircuitPublicInputs, - log_hash::{LogHash, NoteLogHash}, - note_hash::ScopedNoteHash, - nullifier::{Nullifier, ScopedNullifier}, + gas::Gas, kernel_circuit_public_inputs::PrivateToPublicKernelCircuitPublicInputs, + note_hash::ScopedNoteHash, nullifier::ScopedNullifier, }, address::{AztecAddress, EthAddress}, point::Point, @@ -69,8 +66,9 @@ mod tests { }; use dep::types::constants::{ DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE, EMPTY_NESTED_INDEX, FIXED_AVM_STARTUP_L2_GAS, - GENERATOR_INDEX__TSK_M, L2_GAS_PER_LOG_BYTE, L2_GAS_PER_NOTE_HASH, L2_GAS_PER_NULLIFIER, - PRIVATE_KERNEL_INNER_INDEX, + GENERATOR_INDEX__TSK_M, L2_GAS_PER_L2_TO_L1_MSG, L2_GAS_PER_LOG_BYTE, L2_GAS_PER_NOTE_HASH, + L2_GAS_PER_NULLIFIER, L2_GAS_PER_PRIVATE_LOG, PRIVATE_KERNEL_INNER_INDEX, + PRIVATE_LOG_SIZE_IN_FIELDS, }; // TODO: Reduce the duplicated code/tests for PrivateKernelTailToPublicInputs and PrivateKernelTailInputs. @@ -317,26 +315,30 @@ mod tests { + 1 /* revertible */; let num_side_effects = num_msgs + 1 /* tx nullifier */; let da_gas = num_side_effects * DA_BYTES_PER_FIELD * DA_GAS_PER_BYTE; - let l2_gas = FIXED_AVM_STARTUP_L2_GAS + 1 * L2_GAS_PER_NULLIFIER; + let l2_gas = FIXED_AVM_STARTUP_L2_GAS + + 1 * L2_GAS_PER_NULLIFIER + + num_msgs * L2_GAS_PER_L2_TO_L1_MSG; assert_eq(public_inputs.gas_used, Gas::tx_overhead() + Gas::new(da_gas, l2_gas)); } #[test] unconstrained fn tx_consumed_gas_from_logs() { let mut builder = PrivateKernelTailToPublicInputsBuilder::new(); - builder.previous_kernel.add_masked_encrypted_log_hash(42, 3); - builder.previous_kernel.add_masked_encrypted_log_hash(42, 4); - builder.previous_kernel.add_contract_class_log_hash(42, 12); + builder.previous_kernel.append_siloed_private_logs_for_note(2, 11); + builder.previous_kernel.add_contract_class_log_hash(420, 12); builder.previous_kernel.end_setup(); - builder.previous_kernel.add_masked_encrypted_log_hash(42, 6); + builder.previous_kernel.append_siloed_private_logs_for_note(1, 33); let public_inputs = builder.execute(); - let num_log_bytes = 3 + 4 + 12 + 6; - let da_gas = (1 * DA_BYTES_PER_FIELD + num_log_bytes) * DA_GAS_PER_BYTE; + let num_private_logs = 3; + let num_da_fields = 1 /* nullifier */ + num_private_logs * PRIVATE_LOG_SIZE_IN_FIELDS; + let num_da_bytes = (num_da_fields * DA_BYTES_PER_FIELD) + 12 /* contract_class_logs */; + let da_gas = num_da_bytes * DA_GAS_PER_BYTE; let l2_gas = FIXED_AVM_STARTUP_L2_GAS + 1 * L2_GAS_PER_NULLIFIER - + num_log_bytes * L2_GAS_PER_LOG_BYTE; + + num_private_logs * L2_GAS_PER_PRIVATE_LOG + + 12 * L2_GAS_PER_LOG_BYTE /* contract_class_logs */; assert_eq(public_inputs.gas_used, Gas::tx_overhead() + Gas::new(da_gas, l2_gas)); } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_call_data_validator_builder/validate_arrays.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_call_data_validator_builder/validate_arrays.nr index 10daa7a993a..98aaa81fb68 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_call_data_validator_builder/validate_arrays.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_call_data_validator_builder/validate_arrays.nr @@ -91,21 +91,11 @@ fn validate_arrays_malformed_public_call_stack_fails() { } #[test(should_fail_with = "invalid array")] -fn validate_arrays_malformed_note_encrypted_logs_hashes() { +fn validate_arrays_malformed_private_logs() { let mut builder = PrivateCallDataValidatorBuilder::new(); - builder.private_call.append_note_encrypted_log_hashes(1); - unshift_empty_item(&mut builder.private_call.note_encrypted_logs_hashes); - - builder.validate(); -} - -#[test(should_fail_with = "invalid array")] -fn validate_arrays_malformed_encrypted_logs_hashes_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.append_encrypted_log_hashes(1); - unshift_empty_item(&mut builder.private_call.encrypted_logs_hashes); + builder.private_call.append_private_logs(1); + unshift_empty_item(&mut builder.private_call.private_logs); builder.validate(); } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_call_data_validator_builder/validate_call.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_call_data_validator_builder/validate_call.nr index 37b5c400c23..75472d34de4 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_call_data_validator_builder/validate_call.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_call_data_validator_builder/validate_call.nr @@ -39,20 +39,11 @@ fn validate_call_is_static_creating_l2_to_l1_msgs_fails() { builder.validate(); } -#[test(should_fail_with = "note_encrypted_logs_hashes must be empty for static calls")] -fn validate_call_is_static_creating_note_encrypted_logs_hashes_fails() { +#[test(should_fail_with = "private_logs must be empty for static calls")] +fn validate_call_is_static_creating_private_logs_fails() { let mut builder = PrivateCallDataValidatorBuilder::new().is_static_call(); - builder.private_call.append_note_encrypted_log_hashes(1); - - builder.validate(); -} - -#[test(should_fail_with = "encrypted_logs_hashes must be empty for static calls")] -fn validate_call_is_static_creating_encrypted_logs_hashes_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new().is_static_call(); - - builder.private_call.append_encrypted_log_hashes(1); + builder.private_call.append_private_logs(1); builder.validate(); } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_call_data_validator_builder/validate_note_logs.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_call_data_validator_builder/validate_note_logs.nr index f0c3442bfbb..7dc3b6adfae 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_call_data_validator_builder/validate_note_logs.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_call_data_validator_builder/validate_note_logs.nr @@ -16,18 +16,7 @@ fn validate_note_logs_random_note_hash_counter_fails() { builder.private_call.append_note_hashes_with_logs(2); // Tweak the note_hash_counter to not match any note hash's counter. - builder.private_call.note_encrypted_logs_hashes.storage[1].note_hash_counter += 100; - - builder.validate(); -} - -#[test(should_fail_with = "could not link a note log to a note hash in another contract")] -fn validate_note_logs_zero_note_hash_counter_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.append_note_hashes_with_logs(2); - // Tweak the note_hash_counter to be 0. - builder.private_call.note_encrypted_logs_hashes.storage[1].note_hash_counter = 0; + builder.private_call.private_logs.storage[1].inner.note_hash_counter += 100; builder.validate(); } @@ -41,8 +30,8 @@ fn validate_note_logs_mismatch_contract_address_fails() { let previous_note_hash = NoteHash { value: 1, counter: 17 }.scope(another_contract_address); builder.previous_note_hashes.push(previous_note_hash); - // Add a not log linked to the previous note hash. - builder.private_call.add_note_encrypted_log_hash(123, 2, previous_note_hash.counter()); + // Add a note log linked to the previous note hash. + builder.private_call.append_private_logs_for_note(1, previous_note_hash.counter()); builder.validate(); } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_kernel_circuit_output_validator_builder/validate_propagated_from_previous_kernel.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_kernel_circuit_output_validator_builder/validate_propagated_from_previous_kernel.nr index b7bb2d4ea67..47eb0b63a25 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_kernel_circuit_output_validator_builder/validate_propagated_from_previous_kernel.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_kernel_circuit_output_validator_builder/validate_propagated_from_previous_kernel.nr @@ -214,49 +214,25 @@ fn validate_propagated_from_previous_kernel_l2_to_l1_msgs_less_than_fails() { } /** - * note_encrypted_log_hashes + * private_logs */ #[test] -fn validate_propagated_from_previous_kernel_note_encrypted_log_hashes_succeeds() { +fn validate_propagated_from_previous_kernel_private_logs_succeeds() { let mut builder = PrivateKernelCircuitOutputValidatorBuilder::new(); - builder.previous_kernel.append_note_encrypted_log_hashes(2); - builder.output.append_note_encrypted_log_hashes(2); + builder.previous_kernel.append_private_logs(2); + builder.output.append_private_logs(2); builder.validate_as_inner_call(); } #[test(should_fail_with = "source item does not prepend to dest")] -fn validate_propagated_from_previous_kernel_note_encrypted_log_hashes_less_than_fails() { +fn validate_propagated_from_previous_kernel_private_logs_less_than_fails() { let mut builder = PrivateKernelCircuitOutputValidatorBuilder::new(); - builder.previous_kernel.append_note_encrypted_log_hashes(2); + builder.previous_kernel.append_private_logs(2); // Propagate 1 less item to the output. - builder.output.append_note_encrypted_log_hashes(1); - - builder.validate_as_inner_call(); -} - -/** - * encrypted_log_hashes - */ -#[test] -fn validate_propagated_from_previous_kernel_encrypted_log_hashes_succeeds() { - let mut builder = PrivateKernelCircuitOutputValidatorBuilder::new(); - - builder.previous_kernel.append_encrypted_log_hashes(2); - builder.output.append_encrypted_log_hashes(2); - - builder.validate_as_inner_call(); -} - -#[test(should_fail_with = "source item does not prepend to dest")] -fn validate_propagated_from_previous_kernel_encrypted_log_hashes_less_than_fails() { - let mut builder = PrivateKernelCircuitOutputValidatorBuilder::new(); - - builder.previous_kernel.append_encrypted_log_hashes(2); - // Propagate 1 less item to the output. - builder.output.append_encrypted_log_hashes(1); + builder.output.append_private_logs(1); builder.validate_as_inner_call(); } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_kernel_circuit_output_validator_builder/validate_propagated_from_private_call.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_kernel_circuit_output_validator_builder/validate_propagated_from_private_call.nr index 9028ded0bb6..3798abb8ed9 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_kernel_circuit_output_validator_builder/validate_propagated_from_private_call.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_kernel_circuit_output_validator_builder/validate_propagated_from_private_call.nr @@ -307,63 +307,39 @@ fn validate_propagated_from_private_call_l2_to_l1_msgs_output_one_more_fails() { } /** - * note_encrypted_log_hashes + * private_logs */ #[test] -fn validate_propagated_from_private_call_note_encrypted_log_hashes_succeeds() { +fn validate_propagated_from_private_call_private_logs_succeeds() { let mut builder = PrivateKernelCircuitOutputValidatorBuilder::new(); - builder.private_call.append_note_encrypted_log_hashes(2); - builder.output.append_note_encrypted_log_hashes(2); + builder.private_call.append_private_logs(2); + builder.output.append_private_logs(2); builder.validate_as_inner_call(); } #[test(should_fail_with = "output should be appended with empty items")] -fn validate_propagated_from_private_call_note_encrypted_log_hashes_output_one_more_fails() { +fn validate_propagated_from_private_call_private_logs_output_one_more_fails() { let mut builder = PrivateKernelCircuitOutputValidatorBuilder::new(); - builder.private_call.append_note_encrypted_log_hashes(2); + builder.private_call.append_private_logs(2); // Propagate 1 more item to the output. - builder.output.append_note_encrypted_log_hashes(3); + builder.output.append_private_logs(3); builder.validate_as_inner_call(); } #[test(should_fail_with = "number of total items exceeds limit")] -fn validate_propagated_from_private_call_note_encrypted_log_hashes_with_previous_output_exceeds_max_fails() { +fn validate_propagated_from_private_call_private_logs_with_previous_output_exceeds_max_fails() { let mut builder = PrivateKernelCircuitOutputValidatorBuilder::new(); // Make the previous array to be full, therefore no more items can be added. - let max_len = builder.previous_kernel.note_encrypted_logs_hashes.max_len(); - builder.previous_kernel.append_note_encrypted_log_hashes(max_len); - builder.output.append_note_encrypted_log_hashes(max_len); + let max_len = builder.previous_kernel.private_logs.max_len(); + builder.previous_kernel.append_private_logs(max_len); + builder.output.append_private_logs(max_len); // Add 1 item to the current call. - builder.private_call.append_note_encrypted_log_hashes(1); - - builder.validate_as_inner_call(); -} - -/** - * encrypted_log_hashes - */ -#[test] -fn validate_propagated_from_private_call_encrypted_log_hashes_succeeds() { - let mut builder = PrivateKernelCircuitOutputValidatorBuilder::new(); - - builder.private_call.append_encrypted_log_hashes(2); - builder.output.append_encrypted_log_hashes(2); - - builder.validate_as_inner_call(); -} - -#[test(should_fail_with = "output should be appended with empty items")] -fn validate_propagated_from_private_call_encrypted_log_hashes_output_one_more_fails() { - let mut builder = PrivateKernelCircuitOutputValidatorBuilder::new(); - - builder.private_call.append_encrypted_log_hashes(2); - // Propagate 1 more item to the output. - builder.output.append_encrypted_log_hashes(3); + builder.private_call.append_private_logs(1); builder.validate_as_inner_call(); } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_kernel_circuit_public_inputs_composer_builder/new_from_previous_kernel_with_private_call.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_kernel_circuit_public_inputs_composer_builder/new_from_previous_kernel_with_private_call.nr index 5a2b04052f7..206da091af4 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_kernel_circuit_public_inputs_composer_builder/new_from_previous_kernel_with_private_call.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_kernel_circuit_public_inputs_composer_builder/new_from_previous_kernel_with_private_call.nr @@ -191,35 +191,18 @@ fn new_from_previous_kernel_with_private_call_l2_to_l1_msgs_succeeds() { } #[test] -fn new_from_previous_kernel_with_private_call_note_encrypted_log_hashes_succeeds() { +fn new_from_previous_kernel_with_private_call_private_logs_succeeds() { let mut builder = PrivateKernelCircuitPublicInputsComposerBuilder::new(); - builder.previous_kernel.append_note_encrypted_log_hashes(2); - let prev = builder.previous_kernel.note_encrypted_logs_hashes.storage; - builder.private_call.append_note_encrypted_log_hashes(2); - let curr = builder.private_call.note_encrypted_logs_hashes.storage; + builder.previous_kernel.append_private_logs(2); + let prev = builder.previous_kernel.private_logs.storage; + builder.private_call.append_private_logs(2); + let curr = builder.private_call.private_logs.storage; let output = builder.compose_from_previous_kernel(); assert_array_eq( - output.end.note_encrypted_logs_hashes, - [prev[0], prev[1], curr[0], curr[1]], - ); -} - -#[test] -fn new_from_previous_kernel_with_private_call_encrypted_log_hashes_succeeds() { - let mut builder = PrivateKernelCircuitPublicInputsComposerBuilder::new(); - - builder.previous_kernel.append_encrypted_log_hashes(2); - let prev = builder.previous_kernel.encrypted_logs_hashes.storage; - builder.private_call.append_encrypted_log_hashes(2); - let curr = builder.private_call.encrypted_logs_hashes.storage; - - let output = builder.compose_from_previous_kernel(); - - assert_array_eq( - output.end.encrypted_logs_hashes, + output.end.private_logs, [prev[0], prev[1], curr[0], curr[1]], ); } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_kernel_circuit_public_inputs_composer_builder/propagate_from_private_call.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_kernel_circuit_public_inputs_composer_builder/propagate_from_private_call.nr index 0206f75d389..c40e653f6f4 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_kernel_circuit_public_inputs_composer_builder/propagate_from_private_call.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_kernel_circuit_public_inputs_composer_builder/propagate_from_private_call.nr @@ -137,27 +137,15 @@ fn propagate_from_private_call_l2_to_l1_msgs_succeeds() { } #[test] -fn propagate_from_private_call_note_encrypted_log_hashes_succeeds() { +fn propagate_from_private_call_private_logs_succeeds() { let mut builder = PrivateKernelCircuitPublicInputsComposerBuilder::new(); - builder.private_call.append_note_encrypted_log_hashes(2); - let res = builder.private_call.note_encrypted_logs_hashes.storage; + builder.private_call.append_private_logs(2); + let res = builder.private_call.private_logs.storage; let output = builder.compose_from_tx_request(); - assert_array_eq(output.end.note_encrypted_logs_hashes, [res[0], res[1]]); -} - -#[test] -fn propagate_from_private_call_encrypted_log_hashes_succeeds() { - let mut builder = PrivateKernelCircuitPublicInputsComposerBuilder::new(); - - builder.private_call.append_encrypted_log_hashes(2); - let res = builder.private_call.encrypted_logs_hashes.storage; - - let output = builder.compose_from_tx_request(); - - assert_array_eq(output.end.encrypted_logs_hashes, [res[0], res[1]]); + assert_array_eq(output.end.private_logs, [res[0], res[1]]); } #[test] diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/reset_output_validator_builder/mod.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/reset_output_validator_builder/mod.nr index 71955e0ebd5..72e42d57afa 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/reset_output_validator_builder/mod.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/reset_output_validator_builder/mod.nr @@ -16,16 +16,23 @@ use dep::types::{ tests::fixture_builder::FixtureBuilder, }; +global NOTE_HASH_PENDING_AMOUNT: u32 = 6; +global NOTE_HASH_SETTLED_AMOUNT: u32 = 3; +global NULLIFIER_PENDING_AMOUNT: u32 = 5; +global NULLIFIER_SETTLED_AMOUNT: u32 = 2; +global NULLIFIER_KEYS: u32 = 2; +global TRANSIENT_DATA_AMOUNT: u32 = 5; + pub struct ResetOutputValidatorBuilder { output: FixtureBuilder, previous_kernel: FixtureBuilder, - note_hash_read_request_hints_builder: NoteHashReadRequestHintsBuilder<6, 3>, - nullifier_read_request_hints_builder: NullifierReadRequestHintsBuilder<5, 2>, - key_validation_hints: [KeyValidationHint; 2], - transient_data_index_hints: [TransientDataIndexHint; 5], + note_hash_read_request_hints_builder: NoteHashReadRequestHintsBuilder, + nullifier_read_request_hints_builder: NullifierReadRequestHintsBuilder, + key_validation_hints: [KeyValidationHint; NULLIFIER_KEYS], + transient_data_index_hints: [TransientDataIndexHint; TRANSIENT_DATA_AMOUNT], note_hash_siloing_amount: u32, nullifier_siloing_amount: u32, - encrypted_log_siloing_amount: u32, + private_log_siloing_amount: u32, } impl ResetOutputValidatorBuilder { @@ -39,26 +46,29 @@ impl ResetOutputValidatorBuilder { let note_hash_read_request_hints_builder = NoteHashReadRequestHintsBuilder::new(); let nullifier_read_request_hints_builder = NullifierReadRequestHintsBuilder::new(); - let key_validation_hints = [KeyValidationHint::nada(MAX_KEY_VALIDATION_REQUESTS_PER_TX); 2]; - let transient_data_index_hints = - [TransientDataIndexHint::nada(MAX_NULLIFIERS_PER_TX, MAX_NOTE_HASHES_PER_TX); 5]; + let key_validation_hints = + [KeyValidationHint::nada(MAX_KEY_VALIDATION_REQUESTS_PER_TX); NULLIFIER_KEYS]; + let transient_data_index_hints = [ + TransientDataIndexHint::nada(MAX_NULLIFIERS_PER_TX, MAX_NOTE_HASHES_PER_TX); + TRANSIENT_DATA_AMOUNT + ]; - ResetOutputValidatorBuilder { - output, - previous_kernel, - note_hash_read_request_hints_builder, - nullifier_read_request_hints_builder, - key_validation_hints, - transient_data_index_hints, - note_hash_siloing_amount: 0, - nullifier_siloing_amount: 0, - encrypted_log_siloing_amount: 0, + ResetOutputValidatorBuilder { + output, + previous_kernel, + note_hash_read_request_hints_builder, + nullifier_read_request_hints_builder, + key_validation_hints, + transient_data_index_hints, + note_hash_siloing_amount: 0, + nullifier_siloing_amount: 0, + private_log_siloing_amount: 0, + } } - } pub fn get_validation_request_processor( self, - ) -> PrivateValidationRequestProcessor<6, 3, 5, 2, 2> { + ) -> PrivateValidationRequestProcessor { let previous_kernel = self.previous_kernel.to_private_kernel_circuit_public_inputs(); let note_hash_read_request_hints = unsafe { self.note_hash_read_request_hints_builder.to_hints() }; @@ -96,7 +106,7 @@ impl ResetOutputValidatorBuilder { self.transient_data_index_hints, self.note_hash_siloing_amount, self.nullifier_siloing_amount, - self.encrypted_log_siloing_amount, + self.private_log_siloing_amount, hints, ) .validate(); diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_output_composer_builder/meter_gas_used.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_output_composer_builder/meter_gas_used.nr index 82fff15a88d..a0dd0501ea6 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_output_composer_builder/meter_gas_used.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_output_composer_builder/meter_gas_used.nr @@ -1,9 +1,10 @@ -use crate::components::tail_output_composer::meter_gas_used::meter_gas_used; +use crate::components::tail_output_composer::meter_gas_used; use dep::types::{ abis::gas::Gas, constants::{ - DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE, L2_GAS_PER_LOG_BYTE, L2_GAS_PER_NOTE_HASH, - L2_GAS_PER_NULLIFIER, + DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE, L2_GAS_PER_L2_TO_L1_MSG, L2_GAS_PER_LOG_BYTE, + L2_GAS_PER_NOTE_HASH, L2_GAS_PER_NULLIFIER, L2_GAS_PER_PRIVATE_LOG, + PRIVATE_LOG_SIZE_IN_FIELDS, }, tests::fixture_builder::FixtureBuilder, }; @@ -37,26 +38,15 @@ fn meter_gas_used_everything_succeeds() { builder.append_l2_to_l1_msgs(1); metered_da_bytes += 1 * DA_BYTES_PER_FIELD; + computed_l2_gas += 1 * L2_GAS_PER_L2_TO_L1_MSG; - builder.add_note_encrypted_log_hash(1001, 12, 0); - metered_da_bytes += 12; - computed_l2_gas += 12 * L2_GAS_PER_LOG_BYTE; + builder.append_private_logs(3); + metered_da_bytes += 3 * PRIVATE_LOG_SIZE_IN_FIELDS * DA_BYTES_PER_FIELD; + computed_l2_gas += 3 * L2_GAS_PER_PRIVATE_LOG; - builder.add_note_encrypted_log_hash(1002, 8, 0); - metered_da_bytes += 8; - computed_l2_gas += 8 * L2_GAS_PER_LOG_BYTE; - - builder.add_note_encrypted_log_hash(1003, 20, 0); - metered_da_bytes += 20; - computed_l2_gas += 20 * L2_GAS_PER_LOG_BYTE; - - builder.add_encrypted_log_hash(2001, 2); - metered_da_bytes += 2; - computed_l2_gas += 2 * L2_GAS_PER_LOG_BYTE; - - builder.add_encrypted_log_hash(2002, 6); - metered_da_bytes += 6; - computed_l2_gas += 6 * L2_GAS_PER_LOG_BYTE; + builder.add_contract_class_log_hash(3001, 51); + metered_da_bytes += 51; + computed_l2_gas += 51 * L2_GAS_PER_LOG_BYTE; let data = builder.to_combined_accumulated_data(); let gas = meter_gas_used(data); diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_output_validator_builder/mod.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_output_validator_builder/mod.nr index 61d4290dd00..30a032dad21 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_output_validator_builder/mod.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_output_validator_builder/mod.nr @@ -4,7 +4,7 @@ mod validate_propagated_sorted_values; mod validate_propagated_values; use crate::components::{ - tail_output_composer::meter_gas_used::meter_gas_used, + tail_output_composer::meter_gas_used, tail_output_validator::{ tail_output_hints::{generate_tail_output_hints, TailOutputHints}, TailOutputValidator, diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_output_validator_builder/validate_gas_used.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_output_validator_builder/validate_gas_used.nr index f8393d50aa7..3ac6fda045c 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_output_validator_builder/validate_gas_used.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_output_validator_builder/validate_gas_used.nr @@ -7,8 +7,8 @@ impl TailOutputValidatorBuilder { builder.previous_kernel.append_siloed_note_hashes(3); builder.output.append_siloed_note_hashes(3); - builder.previous_kernel.append_note_encrypted_log_hashes(3); - builder.output.append_note_encrypted_log_hashes(3); + builder.previous_kernel.append_private_logs(3); + builder.output.append_private_logs(3); builder } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_output_validator_builder/validate_propagated_values.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_output_validator_builder/validate_propagated_values.nr index f9674389c67..c5552e9cfc3 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_output_validator_builder/validate_propagated_values.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_output_validator_builder/validate_propagated_values.nr @@ -191,83 +191,27 @@ fn validate_propagated_values_nullifiers_extra_item_fails() { } /** - * note_encrypted_log_hashes + * private_logs */ #[test] -fn validate_propagated_values_note_encrypted_log_hashes_succeeds() { +fn validate_propagated_values_private_logs_succeeds() { let mut builder = TailOutputValidatorBuilder::new(); - builder.previous_kernel.append_note_encrypted_log_hashes(3); - builder.output.append_note_encrypted_log_hashes(3); + builder.previous_kernel.append_private_logs(3); + builder.output.append_private_logs(3); builder.validate(); } -#[test(should_fail_with = "mismatch note_encrypted_logs_hashes")] -fn validate_propagated_values_note_encrypted_log_hashes_mismatch_fails() { +#[test(should_fail_with = "mismatch private_logs")] +fn validate_propagated_values_private_logs_mismatch_fails() { let mut builder = TailOutputValidatorBuilder::new(); - builder.previous_kernel.append_note_encrypted_log_hashes(3); - builder.output.append_note_encrypted_log_hashes(3); + builder.previous_kernel.append_private_logs(3); + builder.output.append_private_logs(3); // Tweak the value at index 1. - builder.output.note_encrypted_logs_hashes.storage[1].value += 1; + builder.output.private_logs.storage[1].inner.log.fields[0] += 1; builder.validate(); } - -#[test(should_fail_with = "mismatch note_encrypted_logs_hashes")] -fn validate_propagated_values_note_encrypted_log_hashes_non_zero_counter_fails() { - let mut builder = TailOutputValidatorBuilder::new(); - - builder.previous_kernel.append_note_encrypted_log_hashes(3); - builder.output.append_note_encrypted_log_hashes(3); - - let mut output = builder.export_output(); - // Set the counter at index 1. - output.end.note_encrypted_logs_hashes[1].counter = - builder.previous_kernel.note_encrypted_logs_hashes.storage[1].counter; - - builder.validate_with_output(output); -} - -/** - * encrypted_log_hashes - */ -#[test] -fn validate_propagated_values_encrypted_log_hashes_succeeds() { - let mut builder = TailOutputValidatorBuilder::new(); - - builder.previous_kernel.append_encrypted_log_hashes(3); - builder.output.append_encrypted_log_hashes(3); - - builder.validate(); -} - -#[test(should_fail_with = "mismatch encrypted_logs_hashes")] -fn validate_propagated_values_encrypted_logs_hashes_mismatch_fails() { - let mut builder = TailOutputValidatorBuilder::new(); - - builder.previous_kernel.append_encrypted_log_hashes(3); - builder.output.append_encrypted_log_hashes(3); - - // Tweak the value at index 1. - builder.output.encrypted_logs_hashes.storage[1].log_hash.value += 1; - - builder.validate(); -} - -#[test(should_fail_with = "mismatch encrypted_logs_hashes")] -fn validate_propagated_values_encrypted_logs_hashes_non_zero_counter_fails() { - let mut builder = TailOutputValidatorBuilder::new(); - - builder.previous_kernel.append_encrypted_log_hashes(3); - builder.output.append_encrypted_log_hashes(3); - - let mut output = builder.export_output(); - // Set the counter at index 1. - output.end.encrypted_logs_hashes[1].log_hash.counter = - builder.previous_kernel.encrypted_logs_hashes.storage[1].log_hash.counter; - - builder.validate_with_output(output); -} diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_to_public_output_composer_builder/meter_gas_used.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_to_public_output_composer_builder/meter_gas_used.nr index 1257df16703..e1208a12eb6 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_to_public_output_composer_builder/meter_gas_used.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_to_public_output_composer_builder/meter_gas_used.nr @@ -1,9 +1,10 @@ -use crate::components::tail_to_public_output_composer::meter_gas_used::meter_gas_used; +use crate::components::tail_to_public_output_composer::meter_gas_used; use dep::types::{ abis::{gas::Gas, public_call_request::PublicCallRequest}, constants::{ - DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE, FIXED_AVM_STARTUP_L2_GAS, L2_GAS_PER_LOG_BYTE, - L2_GAS_PER_NOTE_HASH, L2_GAS_PER_NULLIFIER, + DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE, FIXED_AVM_STARTUP_L2_GAS, L2_GAS_PER_L2_TO_L1_MSG, + L2_GAS_PER_LOG_BYTE, L2_GAS_PER_NOTE_HASH, L2_GAS_PER_NULLIFIER, L2_GAS_PER_PRIVATE_LOG, + PRIVATE_LOG_SIZE_IN_FIELDS, }, tests::fixture_builder::FixtureBuilder, }; @@ -50,17 +51,14 @@ fn meter_gas_used_everything_succeeds() { non_revertible_builder.append_note_hashes(3); non_revertible_builder.append_nullifiers(1); non_revertible_builder.append_l2_to_l1_msgs(0); - non_revertible_builder.add_note_encrypted_log_hash(1001, 12, 0); - non_revertible_builder.add_encrypted_log_hash(2001, 2); + non_revertible_builder.append_private_logs(3); non_revertible_builder.add_contract_class_log_hash(3001, 51); non_revertible_builder.append_public_call_requests(1); revertible_builder.append_note_hashes(1); revertible_builder.append_nullifiers(2); revertible_builder.append_l2_to_l1_msgs(1); - revertible_builder.add_note_encrypted_log_hash(1002, 8, 0); - revertible_builder.add_note_encrypted_log_hash(1003, 20, 0); - revertible_builder.add_encrypted_log_hash(2002, 6); + non_revertible_builder.append_private_logs(2); revertible_builder.append_public_call_requests(1); let non_revertible_data = non_revertible_builder.to_private_to_public_accumulated_data(); @@ -77,17 +75,15 @@ fn meter_gas_used_everything_succeeds() { ); let total_num_side_effects = 4 + 3 + 1; - let total_log_length = 12 - + 8 - + 20 // note_encrypted_log_hash - + 2 - + 6 // encrypted_log_hash - + 51; // contract_class_log_hash + let total_log_bytes = 5 * PRIVATE_LOG_SIZE_IN_FIELDS * DA_BYTES_PER_FIELD // private_logs + + 51; // contract_class_logs let computed_da_gas = - (total_num_side_effects * DA_BYTES_PER_FIELD + total_log_length) * DA_GAS_PER_BYTE; + (total_num_side_effects * DA_BYTES_PER_FIELD + total_log_bytes) * DA_GAS_PER_BYTE; let computed_l2_gas = 4 * L2_GAS_PER_NOTE_HASH + 3 * L2_GAS_PER_NULLIFIER - + total_log_length * L2_GAS_PER_LOG_BYTE + + 1 * L2_GAS_PER_L2_TO_L1_MSG + + 5 * L2_GAS_PER_PRIVATE_LOG + + 51 * L2_GAS_PER_LOG_BYTE /* contract_class_logs */ + 2 * FIXED_AVM_STARTUP_L2_GAS; assert_eq( diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_to_public_output_composer_builder/split_to_public.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_to_public_output_composer_builder/split_to_public.nr index 6617e5abbfa..a657138cbee 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_to_public_output_composer_builder/split_to_public.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_to_public_output_composer_builder/split_to_public.nr @@ -9,8 +9,7 @@ fn split_to_public_succeeds() { builder.append_note_hashes(2); builder.append_nullifiers(2); builder.append_l2_to_l1_msgs(1); - builder.append_note_encrypted_log_hashes(3); - builder.append_encrypted_log_hashes(2); + builder.append_private_logs(2); builder.add_contract_class_log_hash(2, 200); builder.append_public_call_requests(1); builder.end_setup(); @@ -18,8 +17,7 @@ fn split_to_public_succeeds() { builder.append_note_hashes(3); builder.append_nullifiers(1); builder.append_l2_to_l1_msgs(1); - builder.append_note_encrypted_log_hashes(1); - builder.append_encrypted_log_hashes(2); + builder.append_private_logs(2); builder.append_public_call_requests(2); let combined_data = builder.to_private_to_public_accumulated_data(); @@ -48,21 +46,10 @@ fn split_to_public_succeeds() { assert_array_eq(non_revertible.l2_to_l1_msgs, [expected[0]]); assert_array_eq(revertible.l2_to_l1_msgs, [expected[1]]); - // note_encrypted_logs_hashes - let expected = combined_data.note_encrypted_logs_hashes; - assert_array_eq( - non_revertible.note_encrypted_logs_hashes, - [expected[0], expected[1], expected[2]], - ); - assert_array_eq(revertible.note_encrypted_logs_hashes, [expected[3]]); - - // encrypted_logs_hashes - let expected = combined_data.encrypted_logs_hashes; - assert_array_eq( - non_revertible.encrypted_logs_hashes, - [expected[0], expected[1]], - ); - assert_array_eq(revertible.encrypted_logs_hashes, [expected[2], expected[3]]); + // private_logs + let expected = combined_data.private_logs; + assert_array_eq(non_revertible.private_logs, [expected[0], expected[1]]); + assert_array_eq(revertible.private_logs, [expected[2], expected[3]]); // contract_class_logs_hashes let expected = combined_data.contract_class_logs_hashes; diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_to_public_output_composer_builder/tail_to_public_output_composer.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_to_public_output_composer_builder/tail_to_public_output_composer.nr index ea5e7c6362d..d4a76a03014 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_to_public_output_composer_builder/tail_to_public_output_composer.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_to_public_output_composer_builder/tail_to_public_output_composer.nr @@ -2,8 +2,9 @@ use crate::tests::tail_to_public_output_composer_builder::TailToPublicOutputComp use dep::types::{ abis::gas::Gas, constants::{ - DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE, FIXED_AVM_STARTUP_L2_GAS, L2_GAS_PER_LOG_BYTE, - L2_GAS_PER_NOTE_HASH, L2_GAS_PER_NULLIFIER, + DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE, FIXED_AVM_STARTUP_L2_GAS, L2_GAS_PER_L2_TO_L1_MSG, + L2_GAS_PER_LOG_BYTE, L2_GAS_PER_NOTE_HASH, L2_GAS_PER_NULLIFIER, L2_GAS_PER_PRIVATE_LOG, + PRIVATE_LOG_SIZE_IN_FIELDS, }, tests::utils::{assert_array_eq, swap_items}, }; @@ -15,17 +16,14 @@ fn tail_to_public_output_composer_succeeds() { let teardown_gas_limits = Gas::new(789, 3254); builder.previous_kernel.tx_context.gas_settings.teardown_gas_limits = teardown_gas_limits; - // Non-revertibles. + // Non-revertible. builder.previous_kernel.append_siloed_note_hashes(4); builder.previous_kernel.append_siloed_nullifiers(2); builder.previous_kernel.append_l2_to_l1_msgs(1); - builder.previous_kernel.add_note_encrypted_log_hash(1001, 12, 0); - builder.previous_kernel.add_note_encrypted_log_hash(1002, 8, 0); - - builder.previous_kernel.add_masked_encrypted_log_hash(2001, 2); + builder.previous_kernel.append_private_logs(2); builder.previous_kernel.add_contract_class_log_hash(3002, 9); @@ -33,7 +31,7 @@ fn tail_to_public_output_composer_succeeds() { builder.previous_kernel.end_setup(); - // Revertibles. + // Revertible. builder.previous_kernel.set_public_teardown_call_request(); builder.previous_kernel.append_siloed_note_hashes(2); @@ -42,10 +40,7 @@ fn tail_to_public_output_composer_succeeds() { builder.previous_kernel.append_l2_to_l1_msgs(1); - builder.previous_kernel.add_note_encrypted_log_hash(1003, 20, 0); - - builder.previous_kernel.add_masked_encrypted_log_hash(2002, 6); - builder.previous_kernel.add_masked_encrypted_log_hash(2003, 24); + builder.previous_kernel.append_private_logs(1); builder.previous_kernel.append_public_call_requests(3); @@ -54,7 +49,8 @@ fn tail_to_public_output_composer_succeeds() { // Shuffle ordered items. swap_items(&mut builder.previous_kernel.l2_to_l1_msgs, 0, 1); - swap_items(&mut builder.previous_kernel.public_call_requests, 1, 2); + swap_items(&mut builder.previous_kernel.private_logs, 1, 2); + swap_items(&mut builder.previous_kernel.public_call_requests, 1, 3); // Output. let output = builder.finish(); @@ -89,26 +85,15 @@ fn tail_to_public_output_composer_succeeds() { ); assert_array_eq(output.revertible_accumulated_data.l2_to_l1_msgs, [msgs[1]]); - // note_encrypted_logs_hashes - let log_hashes = data.note_encrypted_logs_hashes; - assert_array_eq( - output.non_revertible_accumulated_data.note_encrypted_logs_hashes, - [log_hashes[0], log_hashes[1]], - ); - assert_array_eq( - output.revertible_accumulated_data.note_encrypted_logs_hashes, - [log_hashes[2]], - ); - - // encrypted_logs_hashes - let log_hashes = data.encrypted_logs_hashes; + // private_logs + let private_logs = data.private_logs; assert_array_eq( - output.non_revertible_accumulated_data.encrypted_logs_hashes, - [log_hashes[0]], + output.non_revertible_accumulated_data.private_logs, + [private_logs[0], private_logs[1]], ); assert_array_eq( - output.revertible_accumulated_data.encrypted_logs_hashes, - [log_hashes[1], log_hashes[2]], + output.revertible_accumulated_data.private_logs, + [private_logs[2]], ); // contract_class_logs_hashes @@ -134,29 +119,30 @@ fn tail_to_public_output_composer_succeeds() { let mut num_note_hashes = 4; let mut num_nullifiers = 3; let mut num_msgs = 1; + let mut num_private_logs = 2; let mut num_public_calls = 2; - let mut total_log_length = 12 - + 8 // note_encrypted_log_hash - + 2 // encrypted_log_hash - + 9; // contract_class_log_hash + let contract_class_log_bytes = 9; // Gas: revertible { num_note_hashes += 2; num_nullifiers += 1; + num_private_logs += 1; num_public_calls += 3; num_msgs += 1; - total_log_length += 20 // note_encrypted_log_hash - + 6 - + 24; // encrypted_log_hash } - let num_da_effects = num_note_hashes + num_nullifiers + num_msgs; + let num_da_fields = num_note_hashes + + num_nullifiers + + num_msgs + + (num_private_logs * PRIVATE_LOG_SIZE_IN_FIELDS); let computed_da_gas = - (num_da_effects * DA_BYTES_PER_FIELD + total_log_length) * DA_GAS_PER_BYTE; + (num_da_fields * DA_BYTES_PER_FIELD + contract_class_log_bytes) * DA_GAS_PER_BYTE; let computed_l2_gas = num_note_hashes * L2_GAS_PER_NOTE_HASH + num_nullifiers * L2_GAS_PER_NULLIFIER - + total_log_length * L2_GAS_PER_LOG_BYTE + + num_msgs * L2_GAS_PER_L2_TO_L1_MSG + + num_private_logs * L2_GAS_PER_PRIVATE_LOG + + contract_class_log_bytes * L2_GAS_PER_LOG_BYTE + num_public_calls * FIXED_AVM_STARTUP_L2_GAS; assert_eq( diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-reset-simulated/src/main.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-reset-simulated/src/main.nr index 7ae49c443c7..5b73744f4f7 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-reset-simulated/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-reset-simulated/src/main.nr @@ -3,9 +3,9 @@ use dep::private_kernel_lib::private_kernel_reset::{ }; use dep::types::{ constants::{ - MAX_ENCRYPTED_LOGS_PER_TX, MAX_KEY_VALIDATION_REQUESTS_PER_TX, - MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NOTE_HASHES_PER_TX, - MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_NULLIFIERS_PER_TX, + MAX_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, + MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_NULLIFIERS_PER_TX, + MAX_PRIVATE_LOGS_PER_TX, }, PrivateKernelCircuitPublicInputs, }; @@ -19,7 +19,7 @@ global NULLIFIER_KEYS: u32 = MAX_KEY_VALIDATION_REQUESTS_PER_TX; // 64 global TRANSIENT_DATA_AMOUNT: u32 = MAX_NULLIFIERS_PER_TX; // 64 global NOTE_HASH_SILOING_AMOUNT: u32 = MAX_NOTE_HASHES_PER_TX; // 64 global NULLIFIER_SILOING_AMOUNT: u32 = MAX_NULLIFIERS_PER_TX; // 64 -global ENCRYPTED_LOG_SILOING_AMOUNT: u32 = MAX_ENCRYPTED_LOGS_PER_TX; // 8 +global PRIVATE_LOG_SILOING_AMOUNT: u32 = MAX_PRIVATE_LOGS_PER_TX; // 64 unconstrained fn main( previous_kernel: PrivateKernelDataWithoutPublicInputs, @@ -34,7 +34,7 @@ unconstrained fn main( private_inputs.execute( NOTE_HASH_SILOING_AMOUNT, NULLIFIER_SILOING_AMOUNT, - ENCRYPTED_LOG_SILOING_AMOUNT, + PRIVATE_LOG_SILOING_AMOUNT, ) } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-reset/src/main.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-reset/src/main.nr index 03b594983f5..816dbc36271 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-reset/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-reset/src/main.nr @@ -3,9 +3,9 @@ use dep::private_kernel_lib::private_kernel_reset::{ }; use dep::types::{ constants::{ - MAX_ENCRYPTED_LOGS_PER_TX, MAX_KEY_VALIDATION_REQUESTS_PER_TX, - MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NOTE_HASHES_PER_TX, - MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_NULLIFIERS_PER_TX, + MAX_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, + MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_NULLIFIERS_PER_TX, + MAX_PRIVATE_LOGS_PER_TX, }, PrivateKernelCircuitPublicInputs, }; @@ -19,7 +19,7 @@ global NULLIFIER_KEYS: u32 = MAX_KEY_VALIDATION_REQUESTS_PER_TX; // 64 global TRANSIENT_DATA_AMOUNT: u32 = MAX_NULLIFIERS_PER_TX; // 64 global NOTE_HASH_SILOING_AMOUNT: u32 = MAX_NOTE_HASHES_PER_TX; // 64 global NULLIFIER_SILOING_AMOUNT: u32 = MAX_NULLIFIERS_PER_TX; // 64 -global ENCRYPTED_LOG_SILOING_AMOUNT: u32 = MAX_ENCRYPTED_LOGS_PER_TX; // 8 +global PRIVATE_LOG_SILOING_AMOUNT: u32 = MAX_PRIVATE_LOGS_PER_TX; // 64 fn main( previous_kernel: PrivateKernelDataWithoutPublicInputs, @@ -34,7 +34,7 @@ fn main( private_inputs.execute( NOTE_HASH_SILOING_AMOUNT, NULLIFIER_SILOING_AMOUNT, - ENCRYPTED_LOG_SILOING_AMOUNT, + PRIVATE_LOG_SILOING_AMOUNT, ) } diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/transient_data.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/transient_data.nr index d53e1889e49..c2c464098ee 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/transient_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/transient_data.nr @@ -1,5 +1,8 @@ use dep::types::{ - abis::{log_hash::NoteLogHash, note_hash::ScopedNoteHash, nullifier::ScopedNullifier}, + abis::{ + note_hash::ScopedNoteHash, nullifier::ScopedNullifier, private_log::PrivateLogData, + side_effect::scoped::Scoped, + }, traits::is_empty, }; @@ -17,11 +20,15 @@ impl TransientDataIndexHint { pub fn verify_squashed_transient_data_with_hint_indexes( note_hashes: [ScopedNoteHash; NUM_NOTE_HASHES], nullifiers: [ScopedNullifier; NUM_NULLIFIERS], - note_logs: [NoteLogHash; NUM_LOGS], + logs: [Scoped; NUM_LOGS], expected_note_hashes: [ScopedNoteHash; NUM_NOTE_HASHES], expected_nullifiers: [ScopedNullifier; NUM_NULLIFIERS], - expected_note_logs: [NoteLogHash; NUM_LOGS], + expected_logs: [Scoped; NUM_LOGS], transient_data_index_hints: [TransientDataIndexHint; NUM_INDEX_HINTS], + // This array maps each log to its associated note hash index, identifying whether the log corresponds to a transient or propagated note hash. + // If a log is associated with a propagated note hash, the index refers to its position in the expected_note_hashes array. + // If a log is associated with a squashed note hash, the index is for the hint in transient_data_index_hints. + // For non-note logs or empty logs (where note_hash_counter is 0), the value does not matter. transient_or_propagated_note_hash_indexes_for_logs: [u32; NUM_LOGS], split_counter: u32, squashed_note_hash_hints: [bool; NUM_NOTE_HASHES], @@ -100,37 +107,43 @@ pub fn verify_squashed_transient_data_with_hint_indexes( note_hashes: [ScopedNoteHash; NUM_NOTE_HASHES], nullifiers: [ScopedNullifier; NUM_NULLIFIERS], - note_logs: [NoteLogHash; NUM_LOGS], + logs: [Scoped; NUM_LOGS], expected_note_hashes: [ScopedNoteHash; NUM_NOTE_HASHES], expected_nullifiers: [ScopedNullifier; NUM_NULLIFIERS], - expected_note_logs: [NoteLogHash; NUM_LOGS], + expected_logs: [Scoped; NUM_LOGS], transient_data_index_hints: [TransientDataIndexHint; NUM_INDEX_HINTS], transient_or_propagated_note_hash_indexes_for_logs: [u32; NUM_LOGS], split_counter: u32, @@ -179,10 +192,10 @@ pub fn verify_squashed_transient_data PrivateLog { + PrivateLog::new([filled_with; PRIVATE_LOG_SIZE_IN_FIELDS]) + } + struct TestDataBuilder { note_hashes: [ScopedNoteHash; NUM_NOTE_HASHES], nullifiers: [ScopedNullifier; NUM_NULLIFIERS], - note_logs: [NoteLogHash; NUM_LOGS], + logs: [Scoped; NUM_LOGS], expected_note_hashes: [ScopedNoteHash; NUM_NOTE_HASHES], expected_nullifiers: [ScopedNullifier; NUM_NULLIFIERS], - expected_note_logs: [NoteLogHash; NUM_LOGS], + expected_logs: [Scoped; NUM_LOGS], transient_data_index_hints: [TransientDataIndexHint; NUM_INDEX_HINTS], transient_or_propagated_note_hash_indexes_for_logs: [u32; NUM_LOGS], split_counter: u32, } - impl TestDataBuilder<5, 4, 3, 2> { + impl TestDataBuilder<5, 4, 6, 2> { pub fn new() -> Self { let note_hashes = [ NoteHash { value: 11, counter: 100 }.scope(contract_address), @@ -236,32 +256,43 @@ mod tests { ScopedNullifier::empty(), ]; - let note_logs = [ - NoteLogHash { value: 77, counter: 700, length: 70, note_hash_counter: 100 }, - NoteLogHash { value: 88, counter: 800, length: 80, note_hash_counter: 200 }, - NoteLogHash::empty(), - ]; + let logs = pad_end( + [ + PrivateLogData { log: mock_log(77), counter: 700, note_hash_counter: 100 } + .scope(contract_address), + PrivateLogData { log: mock_log(88), counter: 800, note_hash_counter: 200 } + .scope(contract_address), + PrivateLogData { log: mock_log(99), counter: 900, note_hash_counter: 0 }.scope( + contract_address, + ), + ], + Scoped::empty(), + ); let mut expected_note_hashes = [ScopedNoteHash::empty(); 5]; expected_note_hashes[0] = note_hashes[1]; let mut expected_nullifiers = [ScopedNullifier::empty(); 4]; expected_nullifiers[0] = nullifiers[2]; - let mut expected_note_logs = [NoteLogHash::empty(); 3]; - expected_note_logs[0] = note_logs[1]; + let mut expected_logs = [Scoped::empty(); 6]; + expected_logs[0] = logs[1]; + expected_logs[1] = logs[2]; let transient_data_index_hints = [ TransientDataIndexHint { nullifier_index: 0, note_hash_index: 2 }, TransientDataIndexHint { nullifier_index: 1, note_hash_index: 0 }, ]; - let transient_or_propagated_note_hash_indexes_for_logs = [1, 0, 1]; + let mut transient_or_propagated_note_hash_indexes_for_logs = [0; 6]; + transient_or_propagated_note_hash_indexes_for_logs[0] = 1; // Points to transient_data_index_hints[1]. + transient_or_propagated_note_hash_indexes_for_logs[1] = 0; // Points to expected_note_hashes[0]. + transient_or_propagated_note_hash_indexes_for_logs[2] = 3; // This can be any value < NUM_NOTES. The log has 0 note_hash_counter and will always be propagated. TestDataBuilder { note_hashes, nullifiers, - note_logs, + logs, expected_note_hashes, expected_nullifiers, - expected_note_logs, + expected_logs, transient_data_index_hints, transient_or_propagated_note_hash_indexes_for_logs, split_counter: 0, @@ -284,16 +315,24 @@ mod tests { ]; // tests removing two logs for one note hash - let note_logs = [ - NoteLogHash { value: 77, counter: 700, length: 70, note_hash_counter: 100 }, - NoteLogHash { value: 88, counter: 800, length: 80, note_hash_counter: 300 }, - NoteLogHash { value: 99, counter: 900, length: 90, note_hash_counter: 200 }, - NoteLogHash { value: 111, counter: 1000, length: 100, note_hash_counter: 300 }, + let logs = [ + PrivateLogData { log: mock_log(77), counter: 700, note_hash_counter: 100 }.scope( + contract_address, + ), + PrivateLogData { log: mock_log(88), counter: 800, note_hash_counter: 300 }.scope( + contract_address, + ), + PrivateLogData { log: mock_log(99), counter: 900, note_hash_counter: 200 }.scope( + contract_address, + ), + PrivateLogData { log: mock_log(111), counter: 1000, note_hash_counter: 300 }.scope( + contract_address, + ), ]; let expected_note_hashes = [ScopedNoteHash::empty(); 3]; let expected_nullifiers = [ScopedNullifier::empty(); 3]; - let expected_note_logs = [NoteLogHash::empty(); 4]; + let expected_logs = [Scoped::empty(); 4]; let transient_data_index_hints = [ TransientDataIndexHint { nullifier_index: 0, note_hash_index: 2 }, @@ -305,10 +344,10 @@ mod tests { TestDataBuilder { note_hashes, nullifiers, - note_logs, + logs, expected_note_hashes, expected_nullifiers, - expected_note_logs, + expected_logs, transient_data_index_hints, transient_or_propagated_note_hash_indexes_for_logs, split_counter: 0, @@ -316,7 +355,7 @@ mod tests { } } - impl TestDataBuilder<3, 3, 4, 3> { + impl TestDataBuilder<3, 3, 5, 3> { pub fn new_identical_note_hashes() -> Self { let note_hashes = [ NoteHash { value: 11, counter: 100 }.scope(contract_address), @@ -330,34 +369,46 @@ mod tests { Nullifier { value: 55, counter: 500, note_hash: 11 }.scope(contract_address), ]; - let note_logs = [ - NoteLogHash { value: 77, counter: 701, length: 70, note_hash_counter: 200 }, - NoteLogHash { value: 77, counter: 702, length: 70, note_hash_counter: 200 }, - NoteLogHash { value: 77, counter: 703, length: 70, note_hash_counter: 200 }, - NoteLogHash { value: 88, counter: 800, length: 80, note_hash_counter: 600 }, + let logs = [ + PrivateLogData { log: mock_log(77), counter: 701, note_hash_counter: 200 }.scope( + contract_address, + ), + PrivateLogData { log: mock_log(88), counter: 800, note_hash_counter: 0 }.scope( + contract_address, + ), + PrivateLogData { log: mock_log(77), counter: 702, note_hash_counter: 200 }.scope( + contract_address, + ), + PrivateLogData { log: mock_log(99), counter: 900, note_hash_counter: 600 }.scope( + contract_address, + ), + PrivateLogData { log: mock_log(77), counter: 703, note_hash_counter: 200 }.scope( + contract_address, + ), ]; let expected_note_hashes = [note_hashes[2], ScopedNoteHash::empty(), ScopedNoteHash::empty()]; let expected_nullifiers = [nullifiers[1], ScopedNullifier::empty(), ScopedNullifier::empty()]; - let expected_note_logs = - [note_logs[3], NoteLogHash::empty(), NoteLogHash::empty(), NoteLogHash::empty()]; + let mut expected_logs = [Scoped::empty(); 5]; + expected_logs[0] = logs[1]; + expected_logs[1] = logs[3]; let transient_data_index_hints = [ TransientDataIndexHint { nullifier_index: 0, note_hash_index: 0 }, TransientDataIndexHint { nullifier_index: 2, note_hash_index: 1 }, TransientDataIndexHint { nullifier_index: 3, note_hash_index: 3 }, ]; - let transient_or_propagated_note_hash_indexes_for_logs = [1, 1, 1, 0]; + let transient_or_propagated_note_hash_indexes_for_logs = [1, 0, 1, 0, 1]; TestDataBuilder { note_hashes, nullifiers, - note_logs, + logs, expected_note_hashes, expected_nullifiers, - expected_note_logs, + expected_logs, transient_data_index_hints, transient_or_propagated_note_hash_indexes_for_logs, split_counter: 0, @@ -386,10 +437,10 @@ mod tests { verify_squashed_transient_data( self.note_hashes, self.nullifiers, - self.note_logs, + self.logs, self.expected_note_hashes, self.expected_nullifiers, - self.expected_note_logs, + self.expected_logs, self.transient_data_index_hints, self.transient_or_propagated_note_hash_indexes_for_logs, self.split_counter, @@ -404,10 +455,10 @@ mod tests { verify_squashed_transient_data_with_hint_indexes( self.note_hashes, self.nullifiers, - self.note_logs, + self.logs, self.expected_note_hashes, self.expected_nullifiers, - self.expected_note_logs, + self.expected_logs, self.transient_data_index_hints, self.transient_or_propagated_note_hash_indexes_for_logs, self.split_counter, @@ -444,8 +495,8 @@ mod tests { // Keep the logs for note hash at index 0. builder.transient_or_propagated_note_hash_indexes_for_logs[1] = 0; // Point it to the expected not hash at index 0. builder.transient_or_propagated_note_hash_indexes_for_logs[3] = 0; // Point it to the expected not hash at index 0. - builder.expected_note_logs[0] = builder.note_logs[1]; - builder.expected_note_logs[1] = builder.note_logs[3]; + builder.expected_logs[0] = builder.logs[1]; + builder.expected_logs[1] = builder.logs[3]; builder.verify(); } @@ -651,25 +702,25 @@ mod tests { fn fails_unexpected_log_value() { let mut builder = TestDataBuilder::new_clear_all(); - builder.expected_note_logs[2].value = 1; + builder.expected_logs[2].inner.log.fields[0] = 1; builder.verify(); } - #[test(should_fail_with = "Propagated note log does not match")] + #[test(should_fail_with = "Propagated private log does not match")] fn fails_wrong_expected_log_value() { let mut builder = TestDataBuilder::new(); - builder.expected_note_logs[0].value += 1; + builder.expected_logs[0].inner.log.fields[0] += 1; builder.verify(); } - #[test(should_fail_with = "Propagated note log does not match")] + #[test(should_fail_with = "Propagated private log does not match")] fn fails_wrong_expected_log_counter() { let mut builder = TestDataBuilder::new(); - builder.expected_note_logs[0].counter += 1; + builder.expected_logs[0].inner.counter += 1; builder.verify(); } @@ -687,7 +738,7 @@ mod tests { fn fails_wrong_log_note_hash() { let mut builder = TestDataBuilder::new(); - builder.note_logs[0].note_hash_counter += 1; + builder.logs[0].inner.note_hash_counter += 1; builder.verify(); } @@ -697,7 +748,7 @@ mod tests { let mut builder = TestDataBuilder::new_clear_all(); // Keep the log. - builder.expected_note_logs[1] = builder.note_logs[0]; + builder.expected_logs[1] = builder.logs[0]; builder.verify(); } diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/components/public_data_tree.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/components/public_data_tree.nr index 4afaf9c75ce..e3d152ba98d 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/components/public_data_tree.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/components/public_data_tree.nr @@ -57,11 +57,16 @@ pub(crate) fn public_data_tree_insert( }, |write: PublicDataTreeLeaf, low_preimage: PublicDataTreeLeafPreimage| { // Build insertion leaf - PublicDataTreeLeafPreimage { - slot: write.slot, - value: write.value, - next_slot: low_preimage.next_slot, - next_index: low_preimage.next_index, + let is_update = low_preimage.slot == write.slot; + if is_update { + PublicDataTreeLeafPreimage::empty() + } else { + PublicDataTreeLeafPreimage { + slot: write.slot, + value: write.value, + next_slot: low_preimage.next_slot, + next_index: low_preimage.next_index, + } } }, ) diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/public_base_rollup.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/public_base_rollup.nr index c7a689749da..c994027d7ec 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/public_base_rollup.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/public_base_rollup.nr @@ -16,12 +16,9 @@ use crate::{ use dep::types::{ abis::{ accumulated_data::CombinedAccumulatedData, - append_only_tree_snapshot::AppendOnlyTreeSnapshot, - avm_circuit_public_inputs::AvmProofData, - combined_constant_data::CombinedConstantData, - log_hash::{LogHash, ScopedLogHash}, - nullifier_leaf_preimage::NullifierLeafPreimage, - public_data_write::PublicDataWrite, + append_only_tree_snapshot::AppendOnlyTreeSnapshot, avm_circuit_public_inputs::AvmProofData, + combined_constant_data::CombinedConstantData, log_hash::ScopedLogHash, + nullifier_leaf_preimage::NullifierLeafPreimage, public_data_write::PublicDataWrite, tube::PublicTubeData, }, constants::{ @@ -57,20 +54,12 @@ impl PublicBaseRollupInputs { let from_private = self.tube_data.public_inputs; let from_public = self.avm_proof_data.public_inputs; - let note_encrypted_logs_hashes = if reverted { - from_private.non_revertible_accumulated_data.note_encrypted_logs_hashes + let private_logs = if reverted { + from_private.non_revertible_accumulated_data.private_logs } else { array_merge( - from_private.non_revertible_accumulated_data.note_encrypted_logs_hashes, - from_private.revertible_accumulated_data.note_encrypted_logs_hashes, - ) - }; - let encrypted_logs_hashes = if reverted { - from_private.non_revertible_accumulated_data.encrypted_logs_hashes - } else { - array_merge( - from_private.non_revertible_accumulated_data.encrypted_logs_hashes, - from_private.revertible_accumulated_data.encrypted_logs_hashes, + from_private.non_revertible_accumulated_data.private_logs, + from_private.revertible_accumulated_data.private_logs, ) }; let contract_class_logs_hashes = if reverted { @@ -81,10 +70,6 @@ impl PublicBaseRollupInputs { from_private.revertible_accumulated_data.contract_class_logs_hashes, ) }; - let note_encrypted_log_preimages_length = - note_encrypted_logs_hashes.fold(0, |len, l: LogHash| len + l.length); - let encrypted_log_preimages_length = - encrypted_logs_hashes.fold(0, |len, l: ScopedLogHash| len + l.log_hash.length); let contract_class_log_preimages_length = contract_class_logs_hashes.fold(0, |len, l: ScopedLogHash| len + l.log_hash.length); let unencrypted_log_preimages_length = from_public @@ -96,12 +81,9 @@ impl PublicBaseRollupInputs { note_hashes: from_public.accumulated_data.note_hashes, nullifiers: from_public.accumulated_data.nullifiers, l2_to_l1_msgs: from_public.accumulated_data.l2_to_l1_msgs, - note_encrypted_logs_hashes, - encrypted_logs_hashes, + private_logs, unencrypted_logs_hashes: from_public.accumulated_data.unencrypted_logs_hashes, contract_class_logs_hashes, - note_encrypted_log_preimages_length, - encrypted_log_preimages_length, unencrypted_log_preimages_length, contract_class_log_preimages_length, public_data_writes: from_public.accumulated_data.public_data_writes, diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr index b64c764295a..508aa5c2b39 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr @@ -12,13 +12,11 @@ use dep::types::{ public_data_write::PublicDataWrite, }, constants::{ - AZTEC_MAX_EPOCH_DURATION, MAX_CONTRACT_CLASS_LOGS_PER_TX, MAX_L2_TO_L1_MSGS_PER_TX, - MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - MAX_UNENCRYPTED_LOGS_PER_TX, - }, - hash::{ - accumulate_sha256, compute_tx_logs_hash, silo_encrypted_log_hash, silo_unencrypted_log_hash, + AZTEC_MAX_EPOCH_DURATION, MAX_L2_TO_L1_MSGS_PER_TX, MAX_NOTE_HASHES_PER_TX, + MAX_NULLIFIERS_PER_TX, MAX_PRIVATE_LOGS_PER_TX, + MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PRIVATE_LOG_SIZE_IN_FIELDS, }, + hash::{accumulate_sha256, compute_tx_logs_hash, silo_unencrypted_log_hash}, merkle_tree::VariableMerkleTree, traits::is_empty, utils::arrays::{array_length, array_merge}, @@ -219,19 +217,6 @@ fn silo_and_hash_unencrypted_logs( compute_tx_logs_hash(siloed_logs) } -fn silo_and_hash_encrypted_logs( - encrypted_logs_hashes: [ScopedLogHash; MAX_UNENCRYPTED_LOGS_PER_TX], -) -> Field { - let siloed_encrypted_logs = encrypted_logs_hashes.map(|log: ScopedLogHash| { - LogHash { - value: silo_encrypted_log_hash(log), - counter: log.log_hash.counter, - length: log.log_hash.length, - } - }); - compute_tx_logs_hash(siloed_encrypted_logs) -} - // Tx effects hash consists of // 1 field for revert code // 1 field for transaction fee @@ -239,15 +224,12 @@ fn silo_and_hash_encrypted_logs( // MAX_NULLIFIERS_PER_TX fields for nullifiers // 1 field for L2 to L1 messages (represented by the out_hash) // MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX public data update requests -> MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * 2 fields +// MAX_PRIVATE_LOGS_PER_TX * PRIVATE_LOG_SIZE_IN_FIELDS fields for private logs // __ -// 1 note encrypted logs length --> 1 field | -// 1 encrypted logs length --> 1 field | -> 4 types of logs - 4 fields for its lengths -// 1 unencrypted logs length --> 1 field | +// 1 unencrypted logs length --> 1 field |-> 2 types of flexible-length logs - 2 fields for their lengths // 1 contract class logs length --> 1 field __| // __ -// 1 note encrypted logs hash --> 1 sha256 hash -> 31 bytes -> 1 fields | Beware when populating bytes that we fill (prepend) to 32! | -// 1 encrypted logs hash --> 1 sha256 hash -> 31 bytes -> 1 fields | Beware when populating bytes that we fill (prepend) to 32! | -> 4 types of logs - 4 fields for its hashes -// 1 unencrypted logs hash --> 1 sha256 hash -> 31 bytes -> 1 fields | Beware when populating bytes that we fill (prepend) to 32! | +// 1 unencrypted logs hash --> 1 sha256 hash -> 31 bytes -> 1 fields | Beware when populating bytes that we fill (prepend) to 32! |-> 2 types of flexible-length logs - 2 fields for their hashes // 1 contract class logs hash --> 1 sha256 hash -> 31 bytes -> 1 fields | Beware when populating bytes that we fill (prepend) to 32! __| global TX_EFFECTS_HASH_INPUT_FIELDS: u32 = 1 + 1 @@ -255,8 +237,9 @@ global TX_EFFECTS_HASH_INPUT_FIELDS: u32 = 1 + MAX_NULLIFIERS_PER_TX + 1 + MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * 2 - + 4 - + 4; + + MAX_PRIVATE_LOGS_PER_TX * PRIVATE_LOG_SIZE_IN_FIELDS + + 2 + + 2; // Computes the tx effects hash for a base rollup (a single transaction) pub fn compute_tx_effects_hash( @@ -266,96 +249,63 @@ pub fn compute_tx_effects_hash( all_public_data_update_requests: [PublicDataWrite; MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], out_hash: Field, ) -> Field { - let mut tx_effects_hash_input = [0; TX_EFFECTS_HASH_INPUT_FIELDS]; - - let note_hashes = combined.note_hashes; - let nullifiers = combined.nullifiers; + let mut tx_effects_hash_input: BoundedVec = + BoundedVec::new(); // Public writes are the concatenation of all non-empty user update requests and protocol update requests, then padded with zeroes. // The incoming all_public_data_update_requests may have empty update requests in the middle, so we move those to the end of the array. let public_data_update_requests = get_all_update_requests_for_tx_effects(all_public_data_update_requests); - let note_logs_length = combined.note_encrypted_log_preimages_length; - let encrypted_logs_length = combined.encrypted_log_preimages_length; + let unencrypted_logs_length = combined.unencrypted_log_preimages_length; let contract_class_logs_length = combined.contract_class_log_preimages_length; - let note_encrypted_logs_hash = compute_tx_logs_hash(combined.note_encrypted_logs_hashes); - let encrypted_logs_hash = silo_and_hash_encrypted_logs(combined.encrypted_logs_hashes); let unencrypted_logs_hash = silo_and_hash_unencrypted_logs(combined.unencrypted_logs_hashes); let contract_class_logs_hash = silo_and_hash_unencrypted_logs(combined.contract_class_logs_hashes); - let mut offset = 0; - // REVERT CODE // upcast to Field to have the same size for the purposes of the hash - tx_effects_hash_input[offset] = revert_code as Field; - offset += 1; + tx_effects_hash_input.push(revert_code as Field); // TX FEE - tx_effects_hash_input[offset] = transaction_fee; - offset += 1; + tx_effects_hash_input.push(transaction_fee); // NOTE HASHES - for j in 0..MAX_NOTE_HASHES_PER_TX { - tx_effects_hash_input[offset + j] = note_hashes[j]; - } - offset += MAX_NOTE_HASHES_PER_TX; + tx_effects_hash_input.extend_from_array(combined.note_hashes); // NULLIFIERS - for j in 0..MAX_NULLIFIERS_PER_TX { - tx_effects_hash_input[offset + j] = nullifiers[j]; - } - offset += MAX_NULLIFIERS_PER_TX; + tx_effects_hash_input.extend_from_array(combined.nullifiers); // L2 TO L1 MESSAGES - tx_effects_hash_input[offset] = out_hash; - offset += 1; + tx_effects_hash_input.push(out_hash); // PUBLIC DATA UPDATE REQUESTS for j in 0..MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX { - tx_effects_hash_input[offset + j * 2] = public_data_update_requests[j].leaf_slot; - tx_effects_hash_input[offset + j * 2 + 1] = public_data_update_requests[j].value; + tx_effects_hash_input.extend_from_array(public_data_update_requests[j].serialize()); } - offset += MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * 2; - // NOTE ENCRYPTED LOGS LENGTH - tx_effects_hash_input[offset] = note_logs_length; - offset += 1; - - // ENCRYPTED LOGS LENGTH - tx_effects_hash_input[offset] = encrypted_logs_length; - offset += 1; + // PRIVATE_LOGS + for j in 0..MAX_PRIVATE_LOGS_PER_TX { + tx_effects_hash_input.extend_from_array(combined.private_logs[j].fields); + } // UNENCRYPTED LOGS LENGTH - tx_effects_hash_input[offset] = unencrypted_logs_length; - offset += 1; + tx_effects_hash_input.push(unencrypted_logs_length); // CONTRACT CLASS LOGS LENGTH - tx_effects_hash_input[offset] = contract_class_logs_length; - offset += 1; - - // NOTE ENCRYPTED LOGS HASH - tx_effects_hash_input[offset] = note_encrypted_logs_hash; - offset += 1; - - // ENCRYPTED LOGS HASH - tx_effects_hash_input[offset] = encrypted_logs_hash; - offset += 1; + tx_effects_hash_input.push(contract_class_logs_length); // UNENCRYPTED LOGS HASH - tx_effects_hash_input[offset] = unencrypted_logs_hash; - offset += 1; + tx_effects_hash_input.push(unencrypted_logs_hash); // CONTRACT CLASS LOGS HASH - tx_effects_hash_input[offset] = contract_class_logs_hash; - offset += 1; + tx_effects_hash_input.push(contract_class_logs_hash); - assert_eq(offset, TX_EFFECTS_HASH_INPUT_FIELDS); // Sanity check + assert_eq(tx_effects_hash_input.len(), TX_EFFECTS_HASH_INPUT_FIELDS); // Sanity check let mut hash_input_flattened = [0; TX_EFFECTS_HASH_INPUT_FIELDS * 32]; for offset in 0..TX_EFFECTS_HASH_INPUT_FIELDS { // TODO: This is not checking that the decomposition is smaller than P - let input_as_bytes: [u8; 32] = tx_effects_hash_input[offset].to_be_radix(256); + let input_as_bytes: [u8; 32] = tx_effects_hash_input.get_unchecked(offset).to_be_radix(256); for byte_index in 0..32 { hash_input_flattened[offset * 32 + byte_index] = input_as_bytes[byte_index]; } @@ -377,19 +327,3 @@ fn get_all_update_requests_for_tx_effects( } all_update_requests.storage() } - -#[test] -fn consistent_TX_EFFECTS_HASH_INPUT_FIELDS() { - let expected_size = 1 // revert code - + 1 // transaction fee - + MAX_NOTE_HASHES_PER_TX - + MAX_NULLIFIERS_PER_TX - + MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * 2 - + 1 // out hash - + 4 // logs lengths - + 4; // logs hashes - assert( - TX_EFFECTS_HASH_INPUT_FIELDS == expected_size, - "tx effects hash input size is incorrect", - ); -} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr index 440dbcfa3cb..35d706bbbe3 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr @@ -1,9 +1,9 @@ use crate::{ - abis::{log_hash::{LogHash, ScopedLogHash}, public_data_write::PublicDataWrite}, + abis::{log_hash::ScopedLogHash, private_log::PrivateLog, public_data_write::PublicDataWrite}, constants::{ - COMBINED_ACCUMULATED_DATA_LENGTH, MAX_CONTRACT_CLASS_LOGS_PER_TX, MAX_ENCRYPTED_LOGS_PER_TX, - MAX_L2_TO_L1_MSGS_PER_TX, MAX_NOTE_ENCRYPTED_LOGS_PER_TX, MAX_NOTE_HASHES_PER_TX, - MAX_NULLIFIERS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX, + COMBINED_ACCUMULATED_DATA_LENGTH, MAX_CONTRACT_CLASS_LOGS_PER_TX, MAX_L2_TO_L1_MSGS_PER_TX, + MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, MAX_PRIVATE_LOGS_PER_TX, + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX, }, messaging::l2_to_l1_message::ScopedL2ToL1Message, traits::{Deserialize, Empty, Serialize}, @@ -15,15 +15,12 @@ pub struct CombinedAccumulatedData { pub nullifiers: [Field; MAX_NULLIFIERS_PER_TX], pub l2_to_l1_msgs: [ScopedL2ToL1Message; MAX_L2_TO_L1_MSGS_PER_TX], - pub note_encrypted_logs_hashes: [LogHash; MAX_NOTE_ENCRYPTED_LOGS_PER_TX], - pub encrypted_logs_hashes: [ScopedLogHash; MAX_ENCRYPTED_LOGS_PER_TX], + pub private_logs: [PrivateLog; MAX_PRIVATE_LOGS_PER_TX], pub unencrypted_logs_hashes: [ScopedLogHash; MAX_UNENCRYPTED_LOGS_PER_TX], pub contract_class_logs_hashes: [ScopedLogHash; MAX_CONTRACT_CLASS_LOGS_PER_TX], // Here so that the gas cost of this request can be measured by circuits, without actually needing to feed in the // variable-length data. - pub note_encrypted_log_preimages_length: Field, - pub encrypted_log_preimages_length: Field, pub unencrypted_log_preimages_length: Field, pub contract_class_log_preimages_length: Field, @@ -36,12 +33,9 @@ impl Empty for CombinedAccumulatedData { note_hashes: [0; MAX_NOTE_HASHES_PER_TX], nullifiers: [0; MAX_NULLIFIERS_PER_TX], l2_to_l1_msgs: [ScopedL2ToL1Message::empty(); MAX_L2_TO_L1_MSGS_PER_TX], - note_encrypted_logs_hashes: [LogHash::empty(); MAX_NOTE_ENCRYPTED_LOGS_PER_TX], - encrypted_logs_hashes: [ScopedLogHash::empty(); MAX_ENCRYPTED_LOGS_PER_TX], + private_logs: [PrivateLog::empty(); MAX_PRIVATE_LOGS_PER_TX], unencrypted_logs_hashes: [ScopedLogHash::empty(); MAX_UNENCRYPTED_LOGS_PER_TX], contract_class_logs_hashes: [ScopedLogHash::empty(); MAX_CONTRACT_CLASS_LOGS_PER_TX], - note_encrypted_log_preimages_length: 0, - encrypted_log_preimages_length: 0, unencrypted_log_preimages_length: 0, contract_class_log_preimages_length: 0, public_data_writes: [PublicDataWrite::empty(); MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], @@ -58,11 +52,8 @@ impl Serialize for CombinedAccumulatedData { for i in 0..self.l2_to_l1_msgs.len() { fields.extend_from_array(self.l2_to_l1_msgs[i].serialize()); } - for i in 0..self.note_encrypted_logs_hashes.len() { - fields.extend_from_array(self.note_encrypted_logs_hashes[i].serialize()); - } - for i in 0..self.encrypted_logs_hashes.len() { - fields.extend_from_array(self.encrypted_logs_hashes[i].serialize()); + for i in 0..self.private_logs.len() { + fields.extend_from_array(self.private_logs[i].serialize()); } for i in 0..self.unencrypted_logs_hashes.len() { fields.extend_from_array(self.unencrypted_logs_hashes[i].serialize()); @@ -70,8 +61,6 @@ impl Serialize for CombinedAccumulatedData { for i in 0..self.contract_class_logs_hashes.len() { fields.extend_from_array(self.contract_class_logs_hashes[i].serialize()); } - fields.push(self.note_encrypted_log_preimages_length); - fields.push(self.encrypted_log_preimages_length); fields.push(self.unencrypted_log_preimages_length); fields.push(self.contract_class_log_preimages_length); @@ -96,13 +85,9 @@ impl Deserialize for CombinedAccumulatedData { ScopedL2ToL1Message::deserialize, [ScopedL2ToL1Message::empty(); MAX_L2_TO_L1_MSGS_PER_TX], ), - note_encrypted_logs_hashes: reader.read_struct_array( - LogHash::deserialize, - [LogHash::empty(); MAX_NOTE_ENCRYPTED_LOGS_PER_TX], - ), - encrypted_logs_hashes: reader.read_struct_array( - ScopedLogHash::deserialize, - [ScopedLogHash::empty(); MAX_ENCRYPTED_LOGS_PER_TX], + private_logs: reader.read_struct_array( + PrivateLog::deserialize, + [PrivateLog::empty(); MAX_PRIVATE_LOGS_PER_TX], ), unencrypted_logs_hashes: reader.read_struct_array( ScopedLogHash::deserialize, @@ -112,8 +97,6 @@ impl Deserialize for CombinedAccumulatedData { ScopedLogHash::deserialize, [ScopedLogHash::empty(); MAX_CONTRACT_CLASS_LOGS_PER_TX], ), - note_encrypted_log_preimages_length: reader.read(), - encrypted_log_preimages_length: reader.read(), unencrypted_log_preimages_length: reader.read(), contract_class_log_preimages_length: reader.read(), public_data_writes: reader.read_struct_array( @@ -131,15 +114,9 @@ impl Eq for CombinedAccumulatedData { (self.note_hashes == other.note_hashes) & (self.nullifiers == other.nullifiers) & (self.l2_to_l1_msgs == other.l2_to_l1_msgs) - & (self.note_encrypted_logs_hashes == other.note_encrypted_logs_hashes) - & (self.encrypted_logs_hashes == other.encrypted_logs_hashes) + & (self.private_logs == other.private_logs) & (self.unencrypted_logs_hashes == other.unencrypted_logs_hashes) & (self.contract_class_logs_hashes == other.contract_class_logs_hashes) - & ( - self.note_encrypted_log_preimages_length - == other.note_encrypted_log_preimages_length - ) - & (self.encrypted_log_preimages_length == other.encrypted_log_preimages_length) & (self.unencrypted_log_preimages_length == other.unencrypted_log_preimages_length) & ( self.contract_class_log_preimages_length diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data.nr index 2cbe86491a7..57007f52eb4 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data.nr @@ -1,20 +1,21 @@ use crate::{ abis::{ - log_hash::{NoteLogHash, ScopedEncryptedLogHash, ScopedLogHash}, + log_hash::ScopedLogHash, note_hash::ScopedNoteHash, nullifier::ScopedNullifier, private_call_request::PrivateCallRequest, + private_log::PrivateLogData, public_call_request::PublicCallRequest, - side_effect::Counted, + side_effect::{Counted, scoped::Scoped}, }, messaging::l2_to_l1_message::ScopedL2ToL1Message, traits::{Deserialize, Empty, Serialize}, utils::reader::Reader, }; use crate::constants::{ - MAX_CONTRACT_CLASS_LOGS_PER_TX, MAX_ENCRYPTED_LOGS_PER_TX, MAX_ENQUEUED_CALLS_PER_TX, - MAX_L2_TO_L1_MSGS_PER_TX, MAX_NOTE_ENCRYPTED_LOGS_PER_TX, MAX_NOTE_HASHES_PER_TX, - MAX_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, PRIVATE_ACCUMULATED_DATA_LENGTH, + MAX_CONTRACT_CLASS_LOGS_PER_TX, MAX_ENQUEUED_CALLS_PER_TX, MAX_L2_TO_L1_MSGS_PER_TX, + MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, + MAX_PRIVATE_LOGS_PER_TX, PRIVATE_ACCUMULATED_DATA_LENGTH, }; pub struct PrivateAccumulatedData { @@ -22,8 +23,7 @@ pub struct PrivateAccumulatedData { pub nullifiers: [ScopedNullifier; MAX_NULLIFIERS_PER_TX], pub l2_to_l1_msgs: [ScopedL2ToL1Message; MAX_L2_TO_L1_MSGS_PER_TX], - pub note_encrypted_logs_hashes: [NoteLogHash; MAX_NOTE_ENCRYPTED_LOGS_PER_TX], - pub encrypted_logs_hashes: [ScopedEncryptedLogHash; MAX_ENCRYPTED_LOGS_PER_TX], + pub private_logs: [Scoped; MAX_PRIVATE_LOGS_PER_TX], pub contract_class_logs_hashes: [ScopedLogHash; MAX_CONTRACT_CLASS_LOGS_PER_TX], pub public_call_requests: [Counted; MAX_ENQUEUED_CALLS_PER_TX], @@ -46,12 +46,8 @@ impl Serialize for PrivateAccumulatedData { fields.extend_from_array(self.l2_to_l1_msgs[i].serialize()); } - for i in 0..MAX_NOTE_ENCRYPTED_LOGS_PER_TX { - fields.extend_from_array(self.note_encrypted_logs_hashes[i].serialize()); - } - - for i in 0..MAX_ENCRYPTED_LOGS_PER_TX { - fields.extend_from_array(self.encrypted_logs_hashes[i].serialize()); + for i in 0..MAX_PRIVATE_LOGS_PER_TX { + fields.extend_from_array(self.private_logs[i].serialize()); } for i in 0..MAX_CONTRACT_CLASS_LOGS_PER_TX { @@ -89,13 +85,9 @@ impl Deserialize for PrivateAccumulatedData { ScopedL2ToL1Message::deserialize, [ScopedL2ToL1Message::empty(); MAX_L2_TO_L1_MSGS_PER_TX], ), - note_encrypted_logs_hashes: reader.read_struct_array( - NoteLogHash::deserialize, - [NoteLogHash::empty(); MAX_NOTE_ENCRYPTED_LOGS_PER_TX], - ), - encrypted_logs_hashes: reader.read_struct_array( - ScopedEncryptedLogHash::deserialize, - [ScopedEncryptedLogHash::empty(); MAX_ENCRYPTED_LOGS_PER_TX], + private_logs: reader.read_struct_array( + Scoped::deserialize, + [Scoped::empty(); MAX_PRIVATE_LOGS_PER_TX], ), contract_class_logs_hashes: reader.read_struct_array( ScopedLogHash::deserialize, @@ -120,8 +112,7 @@ impl Eq for PrivateAccumulatedData { (self.note_hashes == other.note_hashes) & (self.nullifiers == other.nullifiers) & (self.l2_to_l1_msgs == other.l2_to_l1_msgs) - & (self.note_encrypted_logs_hashes == other.note_encrypted_logs_hashes) - & (self.encrypted_logs_hashes == other.encrypted_logs_hashes) + & (self.private_logs == other.private_logs) & (self.contract_class_logs_hashes == other.contract_class_logs_hashes) & (self.public_call_requests == other.public_call_requests) & (self.private_call_stack == other.private_call_stack) @@ -134,8 +125,7 @@ impl Empty for PrivateAccumulatedData { note_hashes: [ScopedNoteHash::empty(); MAX_NOTE_HASHES_PER_TX], nullifiers: [ScopedNullifier::empty(); MAX_NULLIFIERS_PER_TX], l2_to_l1_msgs: [ScopedL2ToL1Message::empty(); MAX_L2_TO_L1_MSGS_PER_TX], - note_encrypted_logs_hashes: [NoteLogHash::empty(); MAX_NOTE_ENCRYPTED_LOGS_PER_TX], - encrypted_logs_hashes: [ScopedEncryptedLogHash::empty(); MAX_ENCRYPTED_LOGS_PER_TX], + private_logs: [Scoped::empty(); MAX_PRIVATE_LOGS_PER_TX], contract_class_logs_hashes: [ScopedLogHash::empty(); MAX_CONTRACT_CLASS_LOGS_PER_TX], public_call_requests: [Counted::empty(); MAX_ENQUEUED_CALLS_PER_TX], private_call_stack: [PrivateCallRequest::empty(); MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX], diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data_builder.nr index c4071413800..76352b2f569 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data_builder.nr @@ -1,17 +1,18 @@ use crate::{ abis::{ accumulated_data::private_accumulated_data::PrivateAccumulatedData, - log_hash::{NoteLogHash, ScopedEncryptedLogHash, ScopedLogHash}, + log_hash::ScopedLogHash, note_hash::ScopedNoteHash, nullifier::ScopedNullifier, private_call_request::PrivateCallRequest, + private_log::PrivateLogData, public_call_request::PublicCallRequest, - side_effect::Counted, + side_effect::{Counted, scoped::Scoped}, }, constants::{ - MAX_CONTRACT_CLASS_LOGS_PER_TX, MAX_ENCRYPTED_LOGS_PER_TX, MAX_ENQUEUED_CALLS_PER_TX, - MAX_L2_TO_L1_MSGS_PER_TX, MAX_NOTE_ENCRYPTED_LOGS_PER_TX, MAX_NOTE_HASHES_PER_TX, - MAX_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, + MAX_CONTRACT_CLASS_LOGS_PER_TX, MAX_ENQUEUED_CALLS_PER_TX, MAX_L2_TO_L1_MSGS_PER_TX, + MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, + MAX_PRIVATE_LOGS_PER_TX, }, messaging::l2_to_l1_message::ScopedL2ToL1Message, traits::Empty, @@ -22,8 +23,7 @@ pub struct PrivateAccumulatedDataBuilder { pub nullifiers: BoundedVec, pub l2_to_l1_msgs: BoundedVec, - pub note_encrypted_logs_hashes: BoundedVec, - pub encrypted_logs_hashes: BoundedVec, + pub private_logs: BoundedVec, MAX_PRIVATE_LOGS_PER_TX>, pub contract_class_logs_hashes: BoundedVec, pub public_call_requests: BoundedVec, MAX_ENQUEUED_CALLS_PER_TX>, @@ -36,8 +36,7 @@ impl PrivateAccumulatedDataBuilder { note_hashes: self.note_hashes.storage(), nullifiers: self.nullifiers.storage(), l2_to_l1_msgs: self.l2_to_l1_msgs.storage(), - note_encrypted_logs_hashes: self.note_encrypted_logs_hashes.storage(), - encrypted_logs_hashes: self.encrypted_logs_hashes.storage(), + private_logs: self.private_logs.storage(), contract_class_logs_hashes: self.contract_class_logs_hashes.storage(), public_call_requests: self.public_call_requests.storage(), private_call_stack: self.private_call_stack.storage(), @@ -51,8 +50,7 @@ impl Empty for PrivateAccumulatedDataBuilder { note_hashes: BoundedVec::new(), nullifiers: BoundedVec::new(), l2_to_l1_msgs: BoundedVec::new(), - note_encrypted_logs_hashes: BoundedVec::new(), - encrypted_logs_hashes: BoundedVec::new(), + private_logs: BoundedVec::new(), contract_class_logs_hashes: BoundedVec::new(), public_call_requests: BoundedVec::new(), private_call_stack: BoundedVec::new(), diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_to_public_accumulated_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_to_public_accumulated_data.nr index 9b80a20cf36..9a386a7a0dc 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_to_public_accumulated_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_to_public_accumulated_data.nr @@ -1,21 +1,22 @@ use crate::{ - abis::{log_hash::{LogHash, ScopedLogHash}, public_call_request::PublicCallRequest}, + abis::{ + log_hash::ScopedLogHash, private_log::PrivateLog, public_call_request::PublicCallRequest, + }, messaging::l2_to_l1_message::ScopedL2ToL1Message, traits::{Deserialize, Empty, Serialize}, utils::reader::Reader, }; use crate::constants::{ - MAX_CONTRACT_CLASS_LOGS_PER_TX, MAX_ENCRYPTED_LOGS_PER_TX, MAX_ENQUEUED_CALLS_PER_TX, - MAX_L2_TO_L1_MSGS_PER_TX, MAX_NOTE_ENCRYPTED_LOGS_PER_TX, MAX_NOTE_HASHES_PER_TX, - MAX_NULLIFIERS_PER_TX, PRIVATE_TO_PUBLIC_ACCUMULATED_DATA_LENGTH, + MAX_CONTRACT_CLASS_LOGS_PER_TX, MAX_ENQUEUED_CALLS_PER_TX, MAX_L2_TO_L1_MSGS_PER_TX, + MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, MAX_PRIVATE_LOGS_PER_TX, + PRIVATE_TO_PUBLIC_ACCUMULATED_DATA_LENGTH, }; pub struct PrivateToPublicAccumulatedData { pub note_hashes: [Field; MAX_NOTE_HASHES_PER_TX], pub nullifiers: [Field; MAX_NULLIFIERS_PER_TX], pub l2_to_l1_msgs: [ScopedL2ToL1Message; MAX_L2_TO_L1_MSGS_PER_TX], - pub note_encrypted_logs_hashes: [LogHash; MAX_NOTE_ENCRYPTED_LOGS_PER_TX], - pub encrypted_logs_hashes: [ScopedLogHash; MAX_ENCRYPTED_LOGS_PER_TX], + pub private_logs: [PrivateLog; MAX_PRIVATE_LOGS_PER_TX], pub contract_class_logs_hashes: [ScopedLogHash; MAX_CONTRACT_CLASS_LOGS_PER_TX], pub public_call_requests: [PublicCallRequest; MAX_ENQUEUED_CALLS_PER_TX], } @@ -26,8 +27,7 @@ impl Empty for PrivateToPublicAccumulatedData { note_hashes: [0; MAX_NOTE_HASHES_PER_TX], nullifiers: [0; MAX_NULLIFIERS_PER_TX], l2_to_l1_msgs: [ScopedL2ToL1Message::empty(); MAX_L2_TO_L1_MSGS_PER_TX], - note_encrypted_logs_hashes: [LogHash::empty(); MAX_NOTE_ENCRYPTED_LOGS_PER_TX], - encrypted_logs_hashes: [ScopedLogHash::empty(); MAX_ENCRYPTED_LOGS_PER_TX], + private_logs: [PrivateLog::empty(); MAX_PRIVATE_LOGS_PER_TX], contract_class_logs_hashes: [ScopedLogHash::empty(); MAX_CONTRACT_CLASS_LOGS_PER_TX], public_call_requests: [PublicCallRequest::empty(); MAX_ENQUEUED_CALLS_PER_TX], } @@ -39,8 +39,7 @@ impl Eq for PrivateToPublicAccumulatedData { (self.note_hashes == other.note_hashes) & (self.nullifiers == other.nullifiers) & (self.l2_to_l1_msgs == other.l2_to_l1_msgs) - & (self.note_encrypted_logs_hashes == other.note_encrypted_logs_hashes) - & (self.encrypted_logs_hashes == other.encrypted_logs_hashes) + & (self.private_logs == other.private_logs) & (self.contract_class_logs_hashes == other.contract_class_logs_hashes) & (self.public_call_requests == other.public_call_requests) } @@ -56,11 +55,8 @@ impl Serialize for PrivateToPublicAcc for i in 0..self.l2_to_l1_msgs.len() { fields.extend_from_array(self.l2_to_l1_msgs[i].serialize()); } - for i in 0..self.note_encrypted_logs_hashes.len() { - fields.extend_from_array(self.note_encrypted_logs_hashes[i].serialize()); - } - for i in 0..self.encrypted_logs_hashes.len() { - fields.extend_from_array(self.encrypted_logs_hashes[i].serialize()); + for i in 0..self.private_logs.len() { + fields.extend_from_array(self.private_logs[i].serialize()); } for i in 0..self.contract_class_logs_hashes.len() { fields.extend_from_array(self.contract_class_logs_hashes[i].serialize()); @@ -88,13 +84,9 @@ impl Deserialize for PrivateToPublicA ScopedL2ToL1Message::deserialize, [ScopedL2ToL1Message::empty(); MAX_L2_TO_L1_MSGS_PER_TX], ), - note_encrypted_logs_hashes: reader.read_struct_array( - LogHash::deserialize, - [LogHash::empty(); MAX_NOTE_ENCRYPTED_LOGS_PER_TX], - ), - encrypted_logs_hashes: reader.read_struct_array( - ScopedLogHash::deserialize, - [ScopedLogHash::empty(); MAX_ENCRYPTED_LOGS_PER_TX], + private_logs: reader.read_struct_array( + PrivateLog::deserialize, + [PrivateLog::empty(); MAX_PRIVATE_LOGS_PER_TX], ), contract_class_logs_hashes: reader.read_struct_array( ScopedLogHash::deserialize, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_to_public_accumulated_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_to_public_accumulated_data_builder.nr index 18090601cd5..8d32e356de7 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_to_public_accumulated_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_to_public_accumulated_data_builder.nr @@ -1,13 +1,11 @@ use crate::{ abis::{ accumulated_data::private_to_public_accumulated_data::PrivateToPublicAccumulatedData, - log_hash::{LogHash, ScopedLogHash}, - public_call_request::PublicCallRequest, + log_hash::ScopedLogHash, private_log::PrivateLog, public_call_request::PublicCallRequest, }, constants::{ - MAX_CONTRACT_CLASS_LOGS_PER_TX, MAX_ENCRYPTED_LOGS_PER_TX, MAX_ENQUEUED_CALLS_PER_TX, - MAX_L2_TO_L1_MSGS_PER_TX, MAX_NOTE_ENCRYPTED_LOGS_PER_TX, MAX_NOTE_HASHES_PER_TX, - MAX_NULLIFIERS_PER_TX, + MAX_CONTRACT_CLASS_LOGS_PER_TX, MAX_ENQUEUED_CALLS_PER_TX, MAX_L2_TO_L1_MSGS_PER_TX, + MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, MAX_PRIVATE_LOGS_PER_TX, }, messaging::l2_to_l1_message::ScopedL2ToL1Message, traits::Empty, @@ -18,8 +16,7 @@ pub struct PrivateToPublicAccumulatedDataBuilder { note_hashes: BoundedVec, nullifiers: BoundedVec, l2_to_l1_msgs: BoundedVec, - note_encrypted_logs_hashes: BoundedVec, - encrypted_logs_hashes: BoundedVec, + private_logs: BoundedVec, contract_class_logs_hashes: BoundedVec, public_call_requests: BoundedVec, } @@ -30,8 +27,7 @@ impl PrivateToPublicAccumulatedDataBuilder { note_hashes: array_to_bounded_vec(data.note_hashes), nullifiers: array_to_bounded_vec(data.nullifiers), l2_to_l1_msgs: array_to_bounded_vec(data.l2_to_l1_msgs), - note_encrypted_logs_hashes: array_to_bounded_vec(data.note_encrypted_logs_hashes), - encrypted_logs_hashes: array_to_bounded_vec(data.encrypted_logs_hashes), + private_logs: array_to_bounded_vec(data.private_logs), contract_class_logs_hashes: array_to_bounded_vec(data.contract_class_logs_hashes), public_call_requests: array_to_bounded_vec(data.public_call_requests), } @@ -42,8 +38,7 @@ impl PrivateToPublicAccumulatedDataBuilder { note_hashes: self.note_hashes.storage(), nullifiers: self.nullifiers.storage(), l2_to_l1_msgs: self.l2_to_l1_msgs.storage(), - note_encrypted_logs_hashes: self.note_encrypted_logs_hashes.storage(), - encrypted_logs_hashes: self.encrypted_logs_hashes.storage(), + private_logs: self.private_logs.storage(), contract_class_logs_hashes: self.contract_class_logs_hashes.storage(), public_call_requests: self.public_call_requests.storage(), } @@ -56,8 +51,7 @@ impl Empty for PrivateToPublicAccumulatedDataBuilder { note_hashes: BoundedVec::new(), nullifiers: BoundedVec::new(), l2_to_l1_msgs: BoundedVec::new(), - note_encrypted_logs_hashes: BoundedVec::new(), - encrypted_logs_hashes: BoundedVec::new(), + private_logs: BoundedVec::new(), contract_class_logs_hashes: BoundedVec::new(), public_call_requests: BoundedVec::new(), } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs.nr index c99ace67a29..7bcf3403299 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs.nr @@ -10,17 +10,16 @@ use crate::{ }; pub struct PrivateKernelCircuitPublicInputsArrayLengths { - note_hash_read_requests: u32, - nullifier_read_requests: u32, - scoped_key_validation_requests_and_generators: u32, - note_hashes: u32, - nullifiers: u32, - l2_to_l1_msgs: u32, - note_encrypted_logs_hashes: u32, - encrypted_logs_hashes: u32, - contract_class_logs_hashes: u32, - public_call_requests: u32, - private_call_stack: u32, + pub note_hash_read_requests: u32, + pub nullifier_read_requests: u32, + pub scoped_key_validation_requests_and_generators: u32, + pub note_hashes: u32, + pub nullifiers: u32, + pub l2_to_l1_msgs: u32, + pub private_logs: u32, + pub contract_class_logs_hashes: u32, + pub public_call_requests: u32, + pub private_call_stack: u32, } impl PrivateKernelCircuitPublicInputsArrayLengths { @@ -38,8 +37,7 @@ impl PrivateKernelCircuitPublicInputsArrayLengths { note_hashes: array_length(public_inputs.end.note_hashes), nullifiers: array_length(public_inputs.end.nullifiers), l2_to_l1_msgs: array_length(public_inputs.end.l2_to_l1_msgs), - note_encrypted_logs_hashes: array_length(public_inputs.end.note_encrypted_logs_hashes), - encrypted_logs_hashes: array_length(public_inputs.end.encrypted_logs_hashes), + private_logs: array_length(public_inputs.end.private_logs), contract_class_logs_hashes: array_length(public_inputs.end.contract_class_logs_hashes), public_call_requests: array_length(public_inputs.end.public_call_requests), private_call_stack: array_length(public_inputs.end.private_call_stack), @@ -54,8 +52,7 @@ impl PrivateKernelCircuitPublicInputsArrayLengths { note_hashes: 0, nullifiers: 0, l2_to_l1_msgs: 0, - note_encrypted_logs_hashes: 0, - encrypted_logs_hashes: 0, + private_logs: 0, contract_class_logs_hashes: 0, public_call_requests: 0, private_call_stack: 0, @@ -74,8 +71,7 @@ impl Eq for PrivateKernelCircuitPublicInputsArrayLengths { & (self.note_hashes == other.note_hashes) & (self.nullifiers == other.nullifiers) & (self.l2_to_l1_msgs == other.l2_to_l1_msgs) - & (self.note_encrypted_logs_hashes == other.note_encrypted_logs_hashes) - & (self.encrypted_logs_hashes == other.encrypted_logs_hashes) + & (self.private_logs == other.private_logs) & (self.contract_class_logs_hashes == other.contract_class_logs_hashes) & (self.public_call_requests == other.public_call_requests) & (self.private_call_stack == other.private_call_stack) diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/log.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/log.nr new file mode 100644 index 00000000000..cca781cf0f5 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/log.nr @@ -0,0 +1,43 @@ +use crate::traits::{Deserialize, Empty, Serialize}; + +pub struct Log { + pub fields: [Field; N], +} + +impl Log { + pub fn new(fields: [Field; N]) -> Self { + Self { fields } + } +} + +impl Eq for Log { + fn eq(self, other: Log) -> bool { + (self.fields == other.fields) + } +} + +impl Empty for Log { + fn empty() -> Log { + Log { fields: [0; N] } + } +} + +impl Serialize for Log { + fn serialize(self) -> [Field; N] { + self.fields + } +} + +impl Deserialize for Log { + fn deserialize(fields: [Field; N]) -> Log { + Log { fields } + } +} + +#[test] +fn serialization_of_empty_log() { + let item: Log<5> = Log::empty(); + let serialized = item.serialize(); + let deserialized = Log::deserialize(serialized); + assert(item.eq(deserialized)); +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/log_hash.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/log_hash.nr index 2b085fffd6a..54068a15e3f 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/log_hash.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/log_hash.nr @@ -1,10 +1,7 @@ use crate::{ abis::side_effect::{Ordered, OrderedValue, Scoped}, address::AztecAddress, - constants::{ - ENCRYPTED_LOG_HASH_LENGTH, LOG_HASH_LENGTH, NOTE_LOG_HASH_LENGTH, - SCOPED_ENCRYPTED_LOG_HASH_LENGTH, SCOPED_LOG_HASH_LENGTH, - }, + constants::{LOG_HASH_LENGTH, SCOPED_LOG_HASH_LENGTH}, traits::{Deserialize, Empty, Serialize}, utils::{arrays::array_concat, reader::Reader}, }; @@ -137,206 +134,3 @@ impl ScopedLogHash { } } } - -pub struct EncryptedLogHash { - pub value: Field, - pub counter: u32, - pub length: Field, - pub randomness: Field, -} - -impl Ordered for EncryptedLogHash { - fn counter(self) -> u32 { - self.counter - } -} - -impl OrderedValue for EncryptedLogHash { - fn value(self) -> Field { - self.value - } - fn counter(self) -> u32 { - self.counter - } -} - -impl Eq for EncryptedLogHash { - fn eq(self, other: EncryptedLogHash) -> bool { - (self.value == other.value) - & (self.counter == other.counter) - & (self.length == other.length) - & (self.randomness == other.randomness) - } -} - -impl Empty for EncryptedLogHash { - fn empty() -> Self { - EncryptedLogHash { value: 0, counter: 0, length: 0, randomness: 0 } - } -} - -impl Serialize for EncryptedLogHash { - fn serialize(self) -> [Field; ENCRYPTED_LOG_HASH_LENGTH] { - [self.value, self.counter as Field, self.length, self.randomness] - } -} - -impl Deserialize for EncryptedLogHash { - fn deserialize(values: [Field; ENCRYPTED_LOG_HASH_LENGTH]) -> Self { - Self { - value: values[0], - counter: values[1] as u32, - length: values[2], - randomness: values[3], - } - } -} - -impl EncryptedLogHash { - pub fn scope(self, contract_address: AztecAddress) -> ScopedEncryptedLogHash { - ScopedEncryptedLogHash { log_hash: self, contract_address } - } -} - -pub struct ScopedEncryptedLogHash { - pub log_hash: EncryptedLogHash, - pub contract_address: AztecAddress, -} - -impl Scoped for ScopedEncryptedLogHash { - fn inner(self) -> EncryptedLogHash { - self.log_hash - } - fn contract_address(self) -> AztecAddress { - self.contract_address - } -} - -impl ScopedEncryptedLogHash { - pub fn expose_to_public(self) -> ScopedLogHash { - // Hide the secret randomness and counter when exposing to public - // Expose as a ScopedLogHash. The contract address is assumed to be masked before calling this. - ScopedLogHash { - contract_address: self.contract_address, - log_hash: LogHash { - value: self.log_hash.value, - counter: 0, - length: self.log_hash.length, - }, - } - } -} - -impl Ordered for ScopedEncryptedLogHash { - fn counter(self) -> u32 { - self.log_hash.counter - } -} - -impl OrderedValue for ScopedEncryptedLogHash { - fn value(self) -> Field { - self.log_hash.value - } - fn counter(self) -> u32 { - self.log_hash.counter - } -} - -impl Eq for ScopedEncryptedLogHash { - fn eq(self, other: ScopedEncryptedLogHash) -> bool { - (self.log_hash == other.log_hash) & (self.contract_address == other.contract_address) - } -} - -impl Empty for ScopedEncryptedLogHash { - fn empty() -> Self { - ScopedEncryptedLogHash { - log_hash: EncryptedLogHash::empty(), - contract_address: AztecAddress::empty(), - } - } -} - -impl Serialize for ScopedEncryptedLogHash { - fn serialize(self) -> [Field; SCOPED_ENCRYPTED_LOG_HASH_LENGTH] { - array_concat( - self.log_hash.serialize(), - [self.contract_address.to_field()], - ) - } -} - -impl Deserialize for ScopedEncryptedLogHash { - fn deserialize(values: [Field; SCOPED_ENCRYPTED_LOG_HASH_LENGTH]) -> Self { - let mut reader = Reader::new(values); - let res = Self { - log_hash: reader.read_struct(EncryptedLogHash::deserialize), - contract_address: reader.read_struct(AztecAddress::deserialize), - }; - reader.finish(); - res - } -} - -pub struct NoteLogHash { - pub value: Field, - pub counter: u32, - pub length: Field, - pub note_hash_counter: u32, -} - -impl NoteLogHash { - pub fn expose_to_public(self) -> LogHash { - // Hide the actual counter and note hash counter when exposing it to the public kernel. - // The counter is usually note_hash.counter + 1, so it can be revealing. - // Expose as a LogHash rather than NoteLogHash to avoid bringing an unnec. 0 value around - LogHash { value: self.value, counter: 0, length: self.length } - } -} - -impl Ordered for NoteLogHash { - fn counter(self) -> u32 { - self.counter - } -} - -impl OrderedValue for NoteLogHash { - fn value(self) -> Field { - self.value - } - fn counter(self) -> u32 { - self.counter - } -} - -impl Eq for NoteLogHash { - fn eq(self, other: NoteLogHash) -> bool { - (self.value == other.value) - & (self.counter == other.counter) - & (self.length == other.length) - & (self.note_hash_counter == other.note_hash_counter) - } -} - -impl Empty for NoteLogHash { - fn empty() -> Self { - NoteLogHash { value: 0, counter: 0, length: 0, note_hash_counter: 0 } - } -} - -impl Serialize for NoteLogHash { - fn serialize(self) -> [Field; NOTE_LOG_HASH_LENGTH] { - [self.value, self.counter as Field, self.length, self.note_hash_counter as Field] - } -} - -impl Deserialize for NoteLogHash { - fn deserialize(values: [Field; NOTE_LOG_HASH_LENGTH]) -> Self { - Self { - value: values[0], - counter: values[1] as u32, - length: values[2], - note_hash_counter: values[3] as u32, - } - } -} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/mod.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/mod.nr index 890d2d4429d..dd095c4a498 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/mod.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/mod.nr @@ -16,6 +16,8 @@ pub mod combined_constant_data; pub mod side_effect; pub mod read_request; +pub mod log; +pub mod private_log; pub mod log_hash; pub mod note_hash; pub mod nullifier; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr index 78dad89c218..c4e9a850257 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr @@ -1,22 +1,18 @@ use crate::{ abis::{ - call_context::CallContext, - log_hash::{EncryptedLogHash, LogHash, NoteLogHash}, - max_block_number::MaxBlockNumber, - note_hash::NoteHash, - nullifier::Nullifier, - private_call_request::PrivateCallRequest, - public_call_request::PublicCallRequest, - read_request::ReadRequest, - side_effect::Counted, + call_context::CallContext, log_hash::LogHash, max_block_number::MaxBlockNumber, + note_hash::NoteHash, nullifier::Nullifier, private_call_request::PrivateCallRequest, + private_log::PrivateLogData, public_call_request::PublicCallRequest, + read_request::ReadRequest, side_effect::Counted, validation_requests::KeyValidationRequestAndGenerator, }, constants::{ - MAX_CONTRACT_CLASS_LOGS_PER_CALL, MAX_ENCRYPTED_LOGS_PER_CALL, MAX_ENQUEUED_CALLS_PER_CALL, + MAX_CONTRACT_CLASS_LOGS_PER_CALL, MAX_ENQUEUED_CALLS_PER_CALL, MAX_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_L2_TO_L1_MSGS_PER_CALL, - MAX_NOTE_ENCRYPTED_LOGS_PER_CALL, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, - MAX_NOTE_HASHES_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIERS_PER_CALL, - MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH, + MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NOTE_HASHES_PER_CALL, + MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIERS_PER_CALL, + MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PRIVATE_LOGS_PER_CALL, + PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH, }, header::Header, messaging::l2_to_l1_message::L2ToL1Message, @@ -26,17 +22,16 @@ use crate::{ }; pub struct PrivateCircuitPublicInputsArrayLengths { - note_hash_read_requests: u32, - nullifier_read_requests: u32, - key_validation_requests_and_generators: u32, - note_hashes: u32, - nullifiers: u32, - l2_to_l1_msgs: u32, - private_call_requests: u32, - public_call_requests: u32, - note_encrypted_logs_hashes: u32, - encrypted_logs_hashes: u32, - contract_class_logs_hashes: u32, + pub note_hash_read_requests: u32, + pub nullifier_read_requests: u32, + pub key_validation_requests_and_generators: u32, + pub note_hashes: u32, + pub nullifiers: u32, + pub l2_to_l1_msgs: u32, + pub private_call_requests: u32, + pub public_call_requests: u32, + pub private_logs: u32, + pub contract_class_logs_hashes: u32, } impl PrivateCircuitPublicInputsArrayLengths { @@ -52,8 +47,7 @@ impl PrivateCircuitPublicInputsArrayLengths { l2_to_l1_msgs: validate_array(public_inputs.l2_to_l1_msgs), private_call_requests: validate_array(public_inputs.private_call_requests), public_call_requests: validate_array(public_inputs.public_call_requests), - note_encrypted_logs_hashes: validate_array(public_inputs.note_encrypted_logs_hashes), - encrypted_logs_hashes: validate_array(public_inputs.encrypted_logs_hashes), + private_logs: validate_array(public_inputs.private_logs), contract_class_logs_hashes: validate_array(public_inputs.contract_class_logs_hashes), } } @@ -81,12 +75,11 @@ pub struct PrivateCircuitPublicInputs { pub public_call_requests: [Counted; MAX_ENQUEUED_CALLS_PER_CALL], pub public_teardown_call_request: PublicCallRequest, pub l2_to_l1_msgs: [L2ToL1Message; MAX_L2_TO_L1_MSGS_PER_CALL], + pub private_logs: [PrivateLogData; MAX_PRIVATE_LOGS_PER_CALL], + pub contract_class_logs_hashes: [LogHash; MAX_CONTRACT_CLASS_LOGS_PER_CALL], pub start_side_effect_counter: u32, pub end_side_effect_counter: u32, - pub note_encrypted_logs_hashes: [NoteLogHash; MAX_NOTE_ENCRYPTED_LOGS_PER_CALL], - pub encrypted_logs_hashes: [EncryptedLogHash; MAX_ENCRYPTED_LOGS_PER_CALL], - pub contract_class_logs_hashes: [LogHash; MAX_CONTRACT_CLASS_LOGS_PER_CALL], // Header of a block whose state is used during private execution (not the block the transaction is included in). pub historical_header: Header, @@ -116,11 +109,10 @@ impl Eq for PrivateCircuitPublicInputs { & (self.private_call_requests == other.private_call_requests) & (self.public_call_requests == other.public_call_requests) & (self.l2_to_l1_msgs == other.l2_to_l1_msgs) + & (self.private_logs == other.private_logs) + & (self.contract_class_logs_hashes == other.contract_class_logs_hashes) & (self.start_side_effect_counter == other.start_side_effect_counter) & (self.end_side_effect_counter == other.end_side_effect_counter) - & (self.note_encrypted_logs_hashes == other.note_encrypted_logs_hashes) - & (self.encrypted_logs_hashes == other.encrypted_logs_hashes) - & (self.contract_class_logs_hashes == other.contract_class_logs_hashes) & self.historical_header.eq(other.historical_header) & self.tx_context.eq(other.tx_context) } @@ -163,17 +155,14 @@ impl Serialize for PrivateCircuitPublicInp for i in 0..self.l2_to_l1_msgs.len() { fields.extend_from_array(self.l2_to_l1_msgs[i].serialize()); } - fields.push(self.start_side_effect_counter as Field); - fields.push(self.end_side_effect_counter as Field); - for i in 0..self.note_encrypted_logs_hashes.len() { - fields.extend_from_array(self.note_encrypted_logs_hashes[i].serialize()); - } - for i in 0..self.encrypted_logs_hashes.len() { - fields.extend_from_array(self.encrypted_logs_hashes[i].serialize()); + for i in 0..self.private_logs.len() { + fields.extend_from_array(self.private_logs[i].serialize()); } for i in 0..self.contract_class_logs_hashes.len() { fields.extend_from_array(self.contract_class_logs_hashes[i].serialize()); } + fields.push(self.start_side_effect_counter as Field); + fields.push(self.end_side_effect_counter as Field); fields.extend_from_array(self.historical_header.serialize()); fields.extend_from_array(self.tx_context.serialize()); @@ -227,20 +216,16 @@ impl Deserialize for PrivateCircuitPublicI L2ToL1Message::deserialize, [L2ToL1Message::empty(); MAX_L2_TO_L1_MSGS_PER_CALL], ), - start_side_effect_counter: reader.read() as u32, - end_side_effect_counter: reader.read() as u32, - note_encrypted_logs_hashes: reader.read_struct_array( - NoteLogHash::deserialize, - [NoteLogHash::empty(); MAX_NOTE_ENCRYPTED_LOGS_PER_CALL], - ), - encrypted_logs_hashes: reader.read_struct_array( - EncryptedLogHash::deserialize, - [EncryptedLogHash::empty(); MAX_ENCRYPTED_LOGS_PER_CALL], + private_logs: reader.read_struct_array( + PrivateLogData::deserialize, + [PrivateLogData::empty(); MAX_PRIVATE_LOGS_PER_CALL], ), contract_class_logs_hashes: reader.read_struct_array( LogHash::deserialize, [LogHash::empty(); MAX_CONTRACT_CLASS_LOGS_PER_CALL], ), + start_side_effect_counter: reader.read() as u32, + end_side_effect_counter: reader.read() as u32, historical_header: reader.read_struct(Header::deserialize), tx_context: reader.read_struct(TxContext::deserialize), }; @@ -272,11 +257,10 @@ impl Empty for PrivateCircuitPublicInputs { public_call_requests: [Counted::empty(); MAX_ENQUEUED_CALLS_PER_CALL], public_teardown_call_request: PublicCallRequest::empty(), l2_to_l1_msgs: [L2ToL1Message::empty(); MAX_L2_TO_L1_MSGS_PER_CALL], + private_logs: [PrivateLogData::empty(); MAX_PRIVATE_LOGS_PER_CALL], + contract_class_logs_hashes: [LogHash::empty(); MAX_CONTRACT_CLASS_LOGS_PER_CALL], start_side_effect_counter: 0 as u32, end_side_effect_counter: 0 as u32, - note_encrypted_logs_hashes: [NoteLogHash::empty(); MAX_NOTE_ENCRYPTED_LOGS_PER_CALL], - encrypted_logs_hashes: [EncryptedLogHash::empty(); MAX_ENCRYPTED_LOGS_PER_CALL], - contract_class_logs_hashes: [LogHash::empty(); MAX_CONTRACT_CLASS_LOGS_PER_CALL], historical_header: Header::empty(), tx_context: TxContext::empty(), } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_log.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_log.nr new file mode 100644 index 00000000000..a4937ca9c6c --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_log.nr @@ -0,0 +1,76 @@ +use crate::{ + abis::{log::Log, side_effect::{Ordered, scoped::Scoped}}, + address::AztecAddress, + constants::{PRIVATE_LOG_DATA_LENGTH, PRIVATE_LOG_SIZE_IN_FIELDS}, + traits::{Deserialize, Empty, Serialize}, + utils::{arrays::array_concat, reader::Reader}, +}; + +pub type PrivateLog = Log; + +pub struct PrivateLogData { + pub log: PrivateLog, + // The counter of the note hash this log is for. 0 if it does not link to a note hash. + pub note_hash_counter: u32, + pub counter: u32, +} + +impl Ordered for PrivateLogData { + fn counter(self) -> u32 { + self.counter + } +} + +impl Eq for PrivateLogData { + fn eq(self, other: PrivateLogData) -> bool { + (self.log == other.log) + & (self.note_hash_counter == other.note_hash_counter) + & (self.counter == other.counter) + } +} + +impl Empty for PrivateLogData { + fn empty() -> Self { + PrivateLogData { log: PrivateLog::empty(), note_hash_counter: 0, counter: 0 } + } +} + +impl Serialize for PrivateLogData { + fn serialize(self) -> [Field; PRIVATE_LOG_DATA_LENGTH] { + array_concat( + self.log.serialize(), + [self.note_hash_counter as Field, self.counter as Field], + ) + } +} + +impl Deserialize for PrivateLogData { + fn deserialize(fields: [Field; PRIVATE_LOG_DATA_LENGTH]) -> Self { + let mut reader = Reader::new(fields); + Self { + log: reader.read_struct(PrivateLog::deserialize), + note_hash_counter: reader.read_u32(), + counter: reader.read_u32(), + } + } +} + +impl PrivateLogData { + pub fn scope(self, contract_address: AztecAddress) -> Scoped { + Scoped { inner: self, contract_address } + } +} + +impl Ordered for Scoped { + fn counter(self) -> u32 { + self.inner.counter + } +} + +#[test] +fn serialization_of_empty_private_log() { + let item = PrivateLogData::empty(); + let serialized = item.serialize(); + let deserialized = PrivateLogData::deserialize(serialized); + assert(item.eq(deserialized)); +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/side_effect.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/side_effect/counted.nr similarity index 63% rename from noir-projects/noir-protocol-circuits/crates/types/src/abis/side_effect.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/side_effect/counted.nr index ca005878c92..ae639315a28 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/side_effect.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/side_effect/counted.nr @@ -1,41 +1,5 @@ -use crate::{ - address::AztecAddress, - traits::{Deserialize, Empty, Serialize}, - utils::{arrays::array_concat, reader::Reader}, -}; - -pub trait Ordered { - fn counter(self) -> u32; -} - -pub trait RangeOrdered { - fn counter_start(self) -> u32; - fn counter_end(self) -> u32; -} - -pub trait OrderedValue -where - T: Eq, -{ - fn value(self) -> T; - fn counter(self) -> u32; -} - -pub trait Scoped -where - T: Eq, -{ - fn contract_address(self) -> AztecAddress; - fn inner(self) -> T; -} - -pub trait Readable { - fn assert_match_read_request(self, read_request: T); -} - -pub trait Inner { - fn inner(self) -> T; -} +use crate::{traits::{Deserialize, Empty, Serialize}, utils::{arrays::array_concat, reader::Reader}}; +use super::Ordered; pub struct Counted { pub inner: T, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/side_effect/mod.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/side_effect/mod.nr new file mode 100644 index 00000000000..d0025825da9 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/side_effect/mod.nr @@ -0,0 +1,39 @@ +pub mod counted; +pub mod scoped; + +pub use counted::Counted; + +use crate::address::AztecAddress; + +pub trait Ordered { + fn counter(self) -> u32; +} + +pub trait RangeOrdered { + fn counter_start(self) -> u32; + fn counter_end(self) -> u32; +} + +pub trait OrderedValue +where + T: Eq, +{ + fn value(self) -> T; + fn counter(self) -> u32; +} + +pub trait Scoped +where + T: Eq, +{ + fn contract_address(self) -> AztecAddress; + fn inner(self) -> T; +} + +pub trait Readable { + fn assert_match_read_request(self, read_request: T); +} + +pub trait Inner { + fn inner(self) -> T; +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/side_effect/scoped.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/side_effect/scoped.nr new file mode 100644 index 00000000000..c13771b2b66 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/side_effect/scoped.nr @@ -0,0 +1,67 @@ +use crate::{ + address::AztecAddress, + tests::types::TestValue, + traits::{Deserialize, Empty, Serialize}, + utils::{arrays::array_concat, reader::Reader}, +}; + +pub struct Scoped { + pub inner: T, + pub contract_address: AztecAddress, +} + +impl Scoped { + pub fn new(inner: T, contract_address: AztecAddress) -> Self { + Self { inner, contract_address } + } +} + +impl Eq for Scoped +where + T: Eq, +{ + fn eq(self, other: Self) -> bool { + (self.inner == other.inner) & (self.contract_address == other.contract_address) + } +} + +impl Empty for Scoped +where + T: Empty, +{ + fn empty() -> Self { + Self { inner: T::empty(), contract_address: AztecAddress::empty() } + } +} + +impl Serialize for Scoped +where + T: Serialize, +{ + fn serialize(self) -> [Field; N] { + array_concat(self.inner.serialize(), [self.contract_address.to_field()]) + } +} + +impl Deserialize for Scoped +where + T: Deserialize, +{ + fn deserialize(fields: [Field; N]) -> Self { + let mut reader = Reader::new(fields); + let deserialized = Self { + inner: reader.read_struct(T::deserialize), + contract_address: reader.read_struct(AztecAddress::deserialize), + }; + reader.finish(); + deserialized + } +} + +#[test] +fn serialization_of_empty_scoped() { + let item: Scoped = Scoped::empty(); + let serialized = item.serialize(); + let deserialized: Scoped = Scoped::deserialize(serialized); + assert(item.eq(deserialized)); +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index ed9b45dd0a3..3695c499bbf 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -38,8 +38,7 @@ pub global MAX_NULLIFIER_READ_REQUESTS_PER_CALL: u32 = 16; pub global MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL: u32 = 16; pub global MAX_L1_TO_L2_MSG_READ_REQUESTS_PER_CALL: u32 = 16; pub global MAX_KEY_VALIDATION_REQUESTS_PER_CALL: u32 = 16; -pub global MAX_NOTE_ENCRYPTED_LOGS_PER_CALL: u32 = 16; -pub global MAX_ENCRYPTED_LOGS_PER_CALL: u32 = 4; +pub global MAX_PRIVATE_LOGS_PER_CALL: u32 = 16; pub global MAX_UNENCRYPTED_LOGS_PER_CALL: u32 = 4; pub global MAX_CONTRACT_CLASS_LOGS_PER_CALL: u32 = 1; @@ -91,8 +90,7 @@ pub global MAX_L1_TO_L2_MSG_READ_REQUESTS_PER_TX: u32 = 64; // TODO: for large multisends we might run out of key validation requests here but not dealing with this now as // databus will hopefully make the issue go away. pub global MAX_KEY_VALIDATION_REQUESTS_PER_TX: u32 = 64; -pub global MAX_NOTE_ENCRYPTED_LOGS_PER_TX: u32 = 64; -pub global MAX_ENCRYPTED_LOGS_PER_TX: u32 = 8; +pub global MAX_PRIVATE_LOGS_PER_TX: u32 = 32; pub global MAX_UNENCRYPTED_LOGS_PER_TX: u32 = 8; pub global MAX_CONTRACT_CLASS_LOGS_PER_TX: u32 = 1; // docs:end:constants @@ -129,7 +127,7 @@ pub global FUNCTION_SELECTOR_NUM_BYTES: Field = 4; // to be large enough so that it's ensured that it doesn't collide with storage slots of other variables. pub global INITIALIZATION_SLOT_SEPARATOR: Field = 1000_000_000; pub global INITIAL_L2_BLOCK_NUM: Field = 1; -pub global PRIVATE_LOG_SIZE_IN_BYTES: u32 = 576; // This is currently defined by aztec-nr/aztec/src/encrypted_logs/payload.nr. See the comment there for how this value is calculated. +pub global PRIVATE_LOG_SIZE_IN_FIELDS: u32 = 18; // This is currently affected by the size of the log overhead defined in aztec-nr/aztec/src/encrypted_logs/payload.nr. pub global BLOB_SIZE_IN_BYTES: Field = 31 * 4096; pub global AZTEC_MAX_EPOCH_DURATION: u32 = 32; // The following is taken from building a block and looking at the `lastArchive` value in it. @@ -214,6 +212,8 @@ pub global L2_GAS_PER_L1_TO_L2_MSG_READ_REQUEST: u32 = // Gas for hashing and validating logs pub global L2_GAS_PER_LOG_BYTE: u32 = 4; +// Zero gas because we don't have to hash and validate the private logs +pub global L2_GAS_PER_PRIVATE_LOG: u32 = 0; // Gas for writing message to L1 portal pub global L2_GAS_PER_L2_TO_L1_MSG: u32 = 200; @@ -277,11 +277,12 @@ pub global SCOPED_KEY_VALIDATION_REQUEST_AND_GENERATOR_LENGTH: u32 = pub global PARTIAL_STATE_REFERENCE_LENGTH: u32 = 6; pub global READ_REQUEST_LENGTH: u32 = 2; pub global TREE_LEAF_READ_REQUEST_LENGTH: u32 = 2; +pub global PRIVATE_LOG_DATA_LENGTH: u32 = PRIVATE_LOG_SIZE_IN_FIELDS + + 1 /* note_hash_counter */ + + 1 /* counter */; +pub global SCOPED_PRIVATE_LOG_DATA_LENGTH: u32 = PRIVATE_LOG_DATA_LENGTH + 1; pub global LOG_HASH_LENGTH: u32 = 3; pub global SCOPED_LOG_HASH_LENGTH: u32 = LOG_HASH_LENGTH + 1; -pub global ENCRYPTED_LOG_HASH_LENGTH: u32 = 4; -pub global SCOPED_ENCRYPTED_LOG_HASH_LENGTH: u32 = ENCRYPTED_LOG_HASH_LENGTH + 1; -pub global NOTE_LOG_HASH_LENGTH: u32 = 4; pub global NOTE_HASH_LENGTH: u32 = 2; pub global SCOPED_NOTE_HASH_LENGTH: u32 = NOTE_HASH_LENGTH + 1; pub global NULLIFIER_LENGTH: u32 = 3; @@ -325,8 +326,7 @@ pub global PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH: u32 = CALL_CONTEXT_LENGTH + PUBLIC_CALL_REQUEST_LENGTH + (L2_TO_L1_MESSAGE_LENGTH * MAX_L2_TO_L1_MSGS_PER_CALL) + 2 - + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_CALL) - + (ENCRYPTED_LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_CALL) + + (PRIVATE_LOG_DATA_LENGTH * MAX_PRIVATE_LOGS_PER_CALL) + (LOG_HASH_LENGTH * MAX_CONTRACT_CLASS_LOGS_PER_CALL) + HEADER_LENGTH + TX_CONTEXT_LENGTH; @@ -367,11 +367,11 @@ pub global PRIVATE_VALIDATION_REQUESTS_LENGTH: u32 = ROLLUP_VALIDATION_REQUESTS_ pub global COMBINED_ACCUMULATED_DATA_LENGTH: u32 = MAX_NOTE_HASHES_PER_TX + MAX_NULLIFIERS_PER_TX + (MAX_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH) - + (LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_TX) - + (SCOPED_LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_TX) - + 4 + + (PRIVATE_LOG_SIZE_IN_FIELDS * MAX_PRIVATE_LOGS_PER_TX) + (SCOPED_LOG_HASH_LENGTH * MAX_UNENCRYPTED_LOGS_PER_TX) + + 1 /* unencrypted_log_preimages_length */ + (SCOPED_LOG_HASH_LENGTH * MAX_CONTRACT_CLASS_LOGS_PER_TX) + + 1 /* contract_class_log_preimages_length */ + (MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_WRITE_LENGTH); pub global TX_CONSTANT_DATA_LENGTH: u32 = HEADER_LENGTH + TX_CONTEXT_LENGTH @@ -382,8 +382,7 @@ pub global COMBINED_CONSTANT_DATA_LENGTH: u32 = TX_CONSTANT_DATA_LENGTH + GLOBAL pub global PRIVATE_ACCUMULATED_DATA_LENGTH: u32 = (SCOPED_NOTE_HASH_LENGTH * MAX_NOTE_HASHES_PER_TX) + (SCOPED_NULLIFIER_LENGTH * MAX_NULLIFIERS_PER_TX) + (MAX_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH) - + (NOTE_LOG_HASH_LENGTH * MAX_NOTE_ENCRYPTED_LOGS_PER_TX) - + (SCOPED_ENCRYPTED_LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_TX) + + (SCOPED_PRIVATE_LOG_DATA_LENGTH * MAX_PRIVATE_LOGS_PER_TX) + (SCOPED_LOG_HASH_LENGTH * MAX_CONTRACT_CLASS_LOGS_PER_TX) + (PRIVATE_CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX) + (COUNTED_PUBLIC_CALL_REQUEST_LENGTH * MAX_ENQUEUED_CALLS_PER_TX); @@ -397,8 +396,7 @@ pub global PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH: u32 = TX_CONSTANT_DATA_L pub global PRIVATE_TO_PUBLIC_ACCUMULATED_DATA_LENGTH: u32 = MAX_NOTE_HASHES_PER_TX + MAX_NULLIFIERS_PER_TX + (MAX_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH) - + (MAX_NOTE_ENCRYPTED_LOGS_PER_TX * LOG_HASH_LENGTH) - + (MAX_ENCRYPTED_LOGS_PER_TX * SCOPED_LOG_HASH_LENGTH) + + (MAX_PRIVATE_LOGS_PER_TX * PRIVATE_LOG_SIZE_IN_FIELDS) + (MAX_CONTRACT_CLASS_LOGS_PER_TX * SCOPED_LOG_HASH_LENGTH) + (MAX_ENQUEUED_CALLS_PER_TX * PUBLIC_CALL_REQUEST_LENGTH); @@ -474,6 +472,8 @@ pub global NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP: u32 = 32 * MAX_NOTE_HASHES_PER pub global NULLIFIERS_NUM_BYTES_PER_BASE_ROLLUP: u32 = 32 * MAX_NULLIFIERS_PER_TX; pub global PUBLIC_DATA_WRITES_NUM_BYTES_PER_BASE_ROLLUP: u32 = 64 * MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX; // 1 write is 64 bytes +pub global PRIVATE_LOGS_NUM_BYTES_PER_BASE_ROLLUP: u32 = + 32 * PRIVATE_LOG_SIZE_IN_FIELDS * MAX_PRIVATE_LOGS_PER_TX; pub global CONTRACTS_NUM_BYTES_PER_BASE_ROLLUP: Field = 32; pub global CONTRACT_DATA_NUM_BYTES_PER_BASE_ROLLUP: Field = 64; pub global CONTRACT_DATA_NUM_BYTES_PER_BASE_ROLLUP_UNPADDED: Field = 52; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/data/public_data_tree_leaf.nr b/noir-projects/noir-protocol-circuits/crates/types/src/data/public_data_tree_leaf.nr index 9cae7a6a675..e97a2161416 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/data/public_data_tree_leaf.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/data/public_data_tree_leaf.nr @@ -1,4 +1,4 @@ -use crate::{merkle_tree::leaf_preimage::IndexedTreeLeafValue, traits::Empty}; +use crate::traits::Empty; pub struct PublicDataTreeLeaf { pub slot: Field, @@ -17,12 +17,6 @@ impl Empty for PublicDataTreeLeaf { } } -impl IndexedTreeLeafValue for PublicDataTreeLeaf { - fn get_key(self) -> Field { - self.slot - } -} - impl PublicDataTreeLeaf { pub fn is_empty(self) -> bool { (self.slot == 0) & (self.value == 0) diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr b/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr index 4aee1c46d57..f8d1bf3b464 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr @@ -2,9 +2,11 @@ use crate::{ abis::{ contract_class_function_leaf_preimage::ContractClassFunctionLeafPreimage, function_selector::FunctionSelector, - log_hash::{LogHash, ScopedEncryptedLogHash, ScopedLogHash}, + log_hash::{LogHash, ScopedLogHash}, note_hash::ScopedNoteHash, nullifier::ScopedNullifier, + private_log::{PrivateLog, PrivateLogData}, + side_effect::scoped::Scoped, }, address::{AztecAddress, EthAddress}, constants::{ @@ -87,27 +89,17 @@ pub fn silo_nullifier(nullifier: ScopedNullifier) -> Field { } } -pub fn silo_encrypted_log_hash(log_hash: ScopedLogHash) -> Field { - // We assume contract address has already been masked - if log_hash.contract_address.is_zero() { - 0 - } else { - accumulate_sha256( - [log_hash.contract_address.to_field(), log_hash.log_hash.value], - ) - } +pub fn compute_siloed_private_log_field(contract_address: AztecAddress, field: Field) -> Field { + poseidon2_hash([contract_address.to_field(), field]) } -pub fn mask_encrypted_log_hash(scoped_log: ScopedEncryptedLogHash) -> AztecAddress { - if scoped_log.contract_address.is_zero() { - AztecAddress::from_field(0) - } else if (scoped_log.log_hash.randomness == 0) { - scoped_log.contract_address +pub fn silo_private_log(private_log: Scoped) -> PrivateLog { + if private_log.contract_address.is_zero() { + private_log.inner.log } else { - AztecAddress::from_field(poseidon2_hash_with_separator( - [scoped_log.contract_address.to_field(), scoped_log.log_hash.randomness], - 0, - )) + let mut fields = private_log.inner.log.fields; + fields[0] = compute_siloed_private_log_field(private_log.contract_address, fields[0]); + PrivateLog { fields } } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/indexed_tree.nr b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/indexed_tree.nr index 6b1be23c529..d6d2a363fd3 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/indexed_tree.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/indexed_tree.nr @@ -3,7 +3,6 @@ pub mod check_valid_low_leaf; use crate::{ abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot, merkle_tree::{ - leaf_preimage::{IndexedTreeLeafPreimage, IndexedTreeLeafValue}, membership::{assert_check_membership, MembershipWitness}, root::{calculate_empty_tree_root, calculate_subtree_root, root_from_sibling_path}, }, @@ -113,14 +112,14 @@ pub fn insert( build_insertion_leaf: fn(Value, Leaf) -> Leaf, ) -> AppendOnlyTreeSnapshot where - Value: IndexedTreeLeafValue, - Leaf: IndexedTreeLeafPreimage, + Value: Eq + Empty, + Leaf: Hash + Empty, { assert(is_valid_low_leaf(low_leaf_preimage, value), "Invalid low leaf"); // perform membership check for the low leaf against the original root assert_check_membership( - low_leaf_preimage.as_leaf(), + low_leaf_preimage.hash(), low_leaf_membership_witness.leaf_index, low_leaf_membership_witness.sibling_path, snapshot.root, @@ -130,34 +129,29 @@ where let updated_low_leaf = update_low_leaf(low_leaf_preimage, value, snapshot.next_available_leaf_index); - // Update low leaf snapshot.root = root_from_sibling_path( - updated_low_leaf.as_leaf(), + updated_low_leaf.hash(), low_leaf_membership_witness.leaf_index, low_leaf_membership_witness.sibling_path, ); - if low_leaf_preimage.get_key() == value.get_key() { - // If it's an update, we don't need to insert the new leaf and advance the tree - snapshot - } else { - let insertion_leaf = build_insertion_leaf(value, low_leaf_preimage); - assert_check_membership( - 0, - snapshot.next_available_leaf_index as Field, - insertion_sibling_path, - snapshot.root, - ); - - // Calculate the new root - snapshot.root = root_from_sibling_path( - insertion_leaf.as_leaf(), - snapshot.next_available_leaf_index as Field, - insertion_sibling_path, - ); - - snapshot.next_available_leaf_index += 1; - - snapshot - } + let insertion_leaf = build_insertion_leaf(value, low_leaf_preimage); + + assert_check_membership( + 0, + snapshot.next_available_leaf_index as Field, + insertion_sibling_path, + snapshot.root, + ); + + // Calculate the new root + snapshot.root = root_from_sibling_path( + insertion_leaf.hash(), + snapshot.next_available_leaf_index as Field, + insertion_sibling_path, + ); + + snapshot.next_available_leaf_index += 1; + + snapshot } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/indexed_tree/check_valid_low_leaf.nr b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/indexed_tree/check_valid_low_leaf.nr index 9a42a21dafe..6c454c5f583 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/indexed_tree/check_valid_low_leaf.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/indexed_tree/check_valid_low_leaf.nr @@ -16,19 +16,12 @@ mod tests { indexed_tree::check_valid_low_leaf::assert_check_valid_low_leaf, leaf_preimage::IndexedTreeLeafPreimage, }; - use crate::traits::Empty; struct TestLeafPreimage { value: Field, next_value: Field, } - impl Empty for TestLeafPreimage { - fn empty() -> Self { - Self { value: 0, next_value: 0 } - } - } - impl IndexedTreeLeafPreimage for TestLeafPreimage { fn get_key(self) -> Field { self.value diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/leaf_preimage.nr b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/leaf_preimage.nr index dab825f5664..f33dd072d96 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/leaf_preimage.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/leaf_preimage.nr @@ -1,16 +1,10 @@ -use crate::traits::Empty; - pub trait LeafPreimage { fn get_key(self) -> Field; fn as_leaf(self) -> Field; } -pub trait IndexedTreeLeafPreimage: Empty { +pub trait IndexedTreeLeafPreimage { fn get_key(self) -> Field; fn get_next_key(self) -> Field; fn as_leaf(self) -> Field; } - -pub trait IndexedTreeLeafValue: Eq + Empty { - fn get_key(self) -> Field; -} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/membership.nr b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/membership.nr index 34ab55a678d..178449af97d 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/membership.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/membership.nr @@ -93,7 +93,6 @@ mod tests { }, tests::merkle_tree_utils::NonEmptyMerkleTree, }; - use crate::traits::Empty; use std::hash::pedersen_hash; struct TestLeafPreimage { @@ -101,12 +100,6 @@ mod tests { next_value: Field, } - impl Empty for TestLeafPreimage { - fn empty() -> Self { - TestLeafPreimage { value: 0, next_value: 0 } - } - } - impl LeafPreimage for TestLeafPreimage { fn get_key(self) -> Field { self.value diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr index 94294b65c16..2780ca84cb0 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr @@ -15,7 +15,8 @@ use crate::{ KernelCircuitPublicInputs, PrivateKernelCircuitPublicInputs, PrivateToPublicKernelCircuitPublicInputs, }, - log_hash::{EncryptedLogHash, LogHash, NoteLogHash, ScopedEncryptedLogHash, ScopedLogHash}, + log::Log, + log_hash::{LogHash, ScopedLogHash}, max_block_number::MaxBlockNumber, note_hash::{NoteHash, ScopedNoteHash}, nullifier::{Nullifier, ScopedNullifier}, @@ -23,10 +24,11 @@ use crate::{ private_circuit_public_inputs::PrivateCircuitPublicInputs, private_kernel::private_call_data::PrivateCallData, private_kernel_data::PrivateKernelData, + private_log::PrivateLogData, public_call_request::PublicCallRequest, public_data_write::PublicDataWrite, read_request::{ReadRequest, ScopedReadRequest}, - side_effect::Counted, + side_effect::{Counted, scoped::Scoped}, tube::{PrivateTubeData, PublicTubeData}, tx_constant_data::TxConstantData, validation_requests::{ @@ -37,17 +39,18 @@ use crate::{ address::{AztecAddress, EthAddress, SaltedInitializationHash}, constants::{ CLIENT_IVC_VERIFICATION_KEY_LENGTH_IN_FIELDS, FUNCTION_TREE_HEIGHT, - MAX_CONTRACT_CLASS_LOGS_PER_TX, MAX_ENCRYPTED_LOGS_PER_TX, MAX_ENQUEUED_CALLS_PER_TX, - MAX_FIELD_VALUE, MAX_KEY_VALIDATION_REQUESTS_PER_TX, MAX_L2_TO_L1_MSGS_PER_TX, - MAX_NOTE_ENCRYPTED_LOGS_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NOTE_HASHES_PER_TX, + MAX_CONTRACT_CLASS_LOGS_PER_TX, MAX_ENQUEUED_CALLS_PER_TX, MAX_FIELD_VALUE, + MAX_KEY_VALIDATION_REQUESTS_PER_TX, MAX_L2_TO_L1_MSGS_PER_TX, + MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_NULLIFIERS_PER_TX, - MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - MAX_UNENCRYPTED_LOGS_PER_TX, PRIVATE_CALL_REQUEST_LENGTH, PROTOCOL_CONTRACT_TREE_HEIGHT, + MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PRIVATE_LOGS_PER_TX, + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX, + PRIVATE_CALL_REQUEST_LENGTH, PRIVATE_LOG_SIZE_IN_FIELDS, PROTOCOL_CONTRACT_TREE_HEIGHT, PUBLIC_CALL_REQUEST_LENGTH, VK_TREE_HEIGHT, }, hash::{ - compute_l2_to_l1_hash, compute_siloed_nullifier, compute_tx_logs_hash, - mask_encrypted_log_hash, silo_note_hash, silo_unencrypted_log_hash, + compute_l2_to_l1_hash, compute_siloed_nullifier, compute_siloed_private_log_field, + silo_note_hash, }, header::Header, merkle_tree::{membership::MembershipWitness, MerkleTree}, @@ -106,15 +109,9 @@ pub struct FixtureBuilder { pub note_hashes: BoundedVec, pub nullifiers: BoundedVec, pub l2_to_l1_msgs: BoundedVec, - pub note_encrypted_logs_hashes: BoundedVec, - pub encrypted_logs_hashes: BoundedVec, + pub private_logs: BoundedVec, MAX_PRIVATE_LOGS_PER_TX>, pub unencrypted_logs_hashes: BoundedVec, pub contract_class_logs_hashes: BoundedVec, - pub note_encrypted_logs_hash: Field, - pub encrypted_logs_hash: Field, - pub unencrypted_logs_hash: Field, - pub note_encrypted_log_preimages_length: Field, - pub encrypted_log_preimages_length: Field, pub unencrypted_log_preimages_length: Field, pub contract_class_log_preimages_length: Field, pub public_data_writes: BoundedVec, @@ -351,10 +348,9 @@ impl FixtureBuilder { })), start_side_effect_counter: self.counter_start, end_side_effect_counter: self.counter, - note_encrypted_logs_hashes: subarray(self.note_encrypted_logs_hashes.storage()), - encrypted_logs_hashes: subarray(self.encrypted_logs_hashes.storage().map( - |l: ScopedEncryptedLogHash| l.log_hash, - )), + private_logs: subarray(self.private_logs.storage().map(|l: Scoped| { + l.inner + })), contract_class_logs_hashes: subarray(self.contract_class_logs_hashes.storage().map( |l: ScopedLogHash| l.log_hash, )), @@ -383,8 +379,7 @@ impl FixtureBuilder { note_hashes: self.note_hashes, nullifiers: self.nullifiers, l2_to_l1_msgs: self.l2_to_l1_msgs, - note_encrypted_logs_hashes: self.note_encrypted_logs_hashes, - encrypted_logs_hashes: self.encrypted_logs_hashes, + private_logs: self.private_logs, contract_class_logs_hashes: self.contract_class_logs_hashes, public_call_requests: self.public_call_requests, private_call_stack: vec_reverse(self.private_call_requests), @@ -412,12 +407,7 @@ impl FixtureBuilder { l2_to_l1_msgs: self.l2_to_l1_msgs.storage().map(|m: ScopedL2ToL1Message| { m.expose_to_public() }), - note_encrypted_logs_hashes: self.note_encrypted_logs_hashes.storage().map( - |l: NoteLogHash| l.expose_to_public(), - ), - encrypted_logs_hashes: self.encrypted_logs_hashes.storage().map( - |l: ScopedEncryptedLogHash| l.expose_to_public(), - ), + private_logs: self.private_logs.storage().map(|l: Scoped| l.inner.log), contract_class_logs_hashes: self.contract_class_logs_hashes.storage().map( |l: ScopedLogHash| l.expose_to_public(), ), @@ -434,20 +424,13 @@ impl FixtureBuilder { l2_to_l1_msgs: self.l2_to_l1_msgs.storage().map(|m: ScopedL2ToL1Message| { m.expose_to_public() }), - note_encrypted_logs_hashes: self.note_encrypted_logs_hashes.storage().map( - |l: NoteLogHash| l.expose_to_public(), - ), - encrypted_logs_hashes: self.encrypted_logs_hashes.storage().map( - |l: ScopedEncryptedLogHash| l.expose_to_public(), - ), + private_logs: self.private_logs.storage().map(|l: Scoped| l.inner.log), unencrypted_logs_hashes: self.unencrypted_logs_hashes.storage().map(|l: ScopedLogHash| { l.expose_to_public() }), - contract_class_logs_hashes: self.contract_class_logs_hashes.storage.map( + contract_class_logs_hashes: self.contract_class_logs_hashes.storage().map( |l: ScopedLogHash| l.expose_to_public(), ), - note_encrypted_log_preimages_length: self.note_encrypted_log_preimages_length, - encrypted_log_preimages_length: self.encrypted_log_preimages_length, unencrypted_log_preimages_length: self.unencrypted_log_preimages_length, contract_class_log_preimages_length: self.contract_class_log_preimages_length, public_data_writes: self.public_data_writes.storage(), @@ -583,8 +566,7 @@ impl FixtureBuilder { if i < num_note_hashes { let value = self.mock_note_hash_value(index_offset + i); self.add_new_note_hash(value); - let (log_hash, length) = self.mock_note_encrypted_log(index_offset + i); - self.add_note_encrypted_log_hash(log_hash, length, self.counter - 1); + self.append_private_logs_for_note(1, self.counter - 1); } } } @@ -760,55 +742,57 @@ impl FixtureBuilder { } } - pub fn add_note_encrypted_log_hash( + pub fn add_private_log( &mut self, - value: Field, - length: Field, + fields: [Field; PRIVATE_LOG_SIZE_IN_FIELDS], note_hash_counter: u32, ) { - let log_hash = - NoteLogHash { value, counter: self.next_counter(), length, note_hash_counter }; - self.note_encrypted_logs_hashes.push(log_hash); - self.encrypted_log_preimages_length += length; + let log = Log { fields }; + let logData = PrivateLogData { log, note_hash_counter, counter: self.next_counter() }.scope( + self.contract_address, + ); + self.private_logs.push(logData); } - pub fn append_note_encrypted_log_hashes(&mut self, num: u32) { - let index_offset = self.note_encrypted_logs_hashes.len(); - for i in 0..self.note_encrypted_logs_hashes.max_len() { - if i < num { - let (log_hash, length) = self.mock_note_encrypted_log(index_offset + i); - self.add_note_encrypted_log_hash(log_hash, length, 0); + pub fn append_private_logs_for_note(&mut self, num_logs: u32, note_hash_counter: u32) { + let index_offset = self.private_logs.len(); + for i in 0..self.private_logs.max_len() { + if i < num_logs { + let fields = self.mock_private_log_fields(index_offset + i); + self.add_private_log(fields, note_hash_counter); } } } - pub fn add_encrypted_log_hash(&mut self, hash: Field, length: Field) { - let log_hash = - EncryptedLogHash { value: hash, counter: self.next_counter(), length, randomness: 2 }; - self.encrypted_logs_hashes.push(log_hash.scope(self.contract_address)); - self.encrypted_log_preimages_length += length; + pub fn append_private_logs(&mut self, num_logs: u32) { + let index_offset = self.private_logs.len(); + for i in 0..self.private_logs.max_len() { + if i < num_logs { + let fields = self.mock_private_log_fields(index_offset + i); + self.add_private_log(fields, 0 /* note_hash_counter */); + } + } } - pub fn add_masked_encrypted_log_hash(&mut self, hash: Field, length: Field) { - let mut log_hash = EncryptedLogHash { - value: hash, - counter: self.next_counter(), - length, - randomness: 2, - } - .scope(self.contract_address); - log_hash.contract_address = mask_encrypted_log_hash(log_hash); - log_hash.log_hash.randomness = 0; - self.encrypted_logs_hashes.push(log_hash); - self.encrypted_log_preimages_length += length; + pub fn add_siloed_private_log( + &mut self, + fields: [Field; PRIVATE_LOG_SIZE_IN_FIELDS], + note_hash_counter: u32, + ) { + let log = Log { fields }; + let logData = PrivateLogData { log, note_hash_counter, counter: self.next_counter() }.scope( + AztecAddress::zero(), + ); + self.private_logs.push(logData); } - pub fn append_encrypted_log_hashes(&mut self, num: u32) { - let index_offset = self.encrypted_logs_hashes.len(); - for i in 0..self.encrypted_logs_hashes.max_len() { - if i < num { - let (log_hash, length) = self.mock_encrypted_log(index_offset + i); - self.add_encrypted_log_hash(log_hash, length); + pub fn append_siloed_private_logs_for_note(&mut self, num_logs: u32, note_hash_counter: u32) { + let index_offset = self.private_logs.len(); + for i in 0..self.private_logs.max_len() { + if i < num_logs { + let mut fields = self.mock_private_log_fields(index_offset + i); + fields[0] = compute_siloed_private_log_field(self.contract_address, fields[0]); + self.add_siloed_private_log(fields, note_hash_counter); } } } @@ -829,34 +813,12 @@ impl FixtureBuilder { } } - pub fn hash_unencrypted_log_hashes(&mut self) { - let mut log_hashes = - self.unencrypted_logs_hashes.storage().map(|l: ScopedLogHash| l.inner()); - for i in 0..self.unencrypted_logs_hashes.max_len() { - let log_hash = self.unencrypted_logs_hashes.get_unchecked(i); - if !log_hash.contract_address.is_zero() { - log_hashes[i].value = silo_unencrypted_log_hash(log_hash); - } - } - self.unencrypted_logs_hash = compute_tx_logs_hash(log_hashes); - } - pub fn add_contract_class_log_hash(&mut self, hash: Field, length: Field) { let log_hash = LogHash { value: hash, counter: self.next_counter(), length }; self.contract_class_logs_hashes.push(log_hash.scope(self.contract_address)); self.contract_class_log_preimages_length += length; } - pub fn set_encrypted_logs_hash(&mut self, hash: Field, preimages_length: Field) { - self.encrypted_logs_hash = hash; - self.encrypted_log_preimages_length = preimages_length; - } - - pub fn set_unencrypted_logs_hash(&mut self, hash: Field, preimages_length: Field) { - self.unencrypted_logs_hash = hash; - self.unencrypted_log_preimages_length = preimages_length; - } - pub fn add_private_call_request_for_private_call(&mut self, private_call: PrivateCallData) { let public_inputs = private_call.public_inputs; let start_counter = public_inputs.start_side_effect_counter; @@ -987,10 +949,18 @@ impl FixtureBuilder { (value_offset, EthAddress::from_field(1 + value_offset)) } - fn mock_note_encrypted_log(self, index: u32) -> (Field, Field) { - let log_hash = 282828 + self.value_offset + index as Field; - let length = 5 + index as Field; - (log_hash, length) + fn mock_private_log_fields(self, index: u32) -> [Field; PRIVATE_LOG_SIZE_IN_FIELDS] { + let value_offset = + 328732 + self.value_offset + (index * PRIVATE_LOG_SIZE_IN_FIELDS) as Field; + let mut fields = [0; PRIVATE_LOG_SIZE_IN_FIELDS]; + for i in 0..PRIVATE_LOG_SIZE_IN_FIELDS { + fields[i] = value_offset + i as Field; + } + fields + } + + fn mock_private_log_randomness(self, index: u32) -> Field { + 579579 + self.value_offset + index as Field } fn mock_encrypted_log(self, index: u32) -> (Field, Field) { @@ -1095,15 +1065,9 @@ impl Empty for FixtureBuilder { note_hashes: BoundedVec::new(), nullifiers: BoundedVec::new(), l2_to_l1_msgs: BoundedVec::new(), - note_encrypted_logs_hashes: BoundedVec::new(), - encrypted_logs_hashes: BoundedVec::new(), + private_logs: BoundedVec::new(), unencrypted_logs_hashes: BoundedVec::new(), contract_class_logs_hashes: BoundedVec::new(), - note_encrypted_logs_hash: 0, - encrypted_logs_hash: 0, - unencrypted_logs_hash: 0, - note_encrypted_log_preimages_length: 0, - encrypted_log_preimages_length: 0, unencrypted_log_preimages_length: 0, contract_class_log_preimages_length: 0, public_data_writes: BoundedVec::new(), diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/types.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/types.nr index b14e43c7145..cbfde31bea4 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/types.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/types.nr @@ -1,4 +1,4 @@ -use crate::{abis::side_effect::Ordered, traits::Empty}; +use crate::{abis::side_effect::Ordered, traits::{Deserialize, Empty, Serialize}}; pub(crate) struct TestValue { pub(crate) value: Field, @@ -23,6 +23,18 @@ impl Ordered for TestValue { } } +impl Serialize<2> for TestValue { + fn serialize(self) -> [Field; 2] { + [self.value, self.counter as Field] + } +} + +impl Deserialize<2> for TestValue { + fn deserialize(fields: [Field; 2]) -> Self { + Self { value: fields[0], counter: fields[1] as u32 } + } +} + pub(crate) struct TestTwoValues { pub(crate) value_1: Field, pub(crate) value_2: Field, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays.nr b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays.nr index 638cc76ecce..41d609572b7 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays.nr @@ -14,7 +14,8 @@ pub mod sort_by_counter; // Re-exports. pub use assert_array_appended::{ - assert_array_appended, assert_array_appended_reversed, assert_array_appended_scoped, + assert_array_appended, assert_array_appended_and_scoped, assert_array_appended_reversed, + assert_array_appended_scoped, }; pub use assert_array_prepended::assert_array_prepended; pub use assert_combined_array::{assert_combined_array, combine_arrays}; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_array_appended.nr b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_array_appended.nr index 8142b69c430..7e076934009 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_array_appended.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_array_appended.nr @@ -1,5 +1,5 @@ use crate::{ - abis::side_effect::Scoped, + abis::side_effect::{Scoped as ScopedTrait, scoped::Scoped}, address::aztec_address::AztecAddress, traits::{Empty, is_empty}, }; @@ -75,7 +75,7 @@ pub fn assert_array_appended_scoped( contract_address: AztecAddress, ) where - ST: Scoped + Empty + Eq, + ST: ScopedTrait + Empty + Eq, T: Eq, { let items_propagated = num_prepended_items + num_source_items; @@ -103,3 +103,39 @@ where } } } + +pub fn assert_array_appended_and_scoped( + dest: [Scoped; N], + source: [T; M], + num_source_items: u32, + num_prepended_items: u32, + contract_address: AztecAddress, +) +where + T: Eq + Empty, +{ + let items_propagated = num_prepended_items + num_source_items; + assert(items_propagated <= N, "number of total items exceeds limit"); + let mut should_check = false; + let mut is_non_empty_item = true; + for i in 0..dest.len() { + should_check |= i == num_prepended_items; + is_non_empty_item &= i != items_propagated; + if should_check { + if is_non_empty_item { + assert_eq( + dest[i].inner, + source[i - num_prepended_items], + "source item does not append to dest", + ); + assert_eq( + dest[i].contract_address, + contract_address, + "propagated contract address does not match", + ); + } else { + assert(is_empty(dest[i]), "output should be appended with empty items"); + } + } + } +} diff --git a/noir-projects/noir-protocol-circuits/private_kernel_reset_config.json b/noir-projects/noir-protocol-circuits/private_kernel_reset_config.json index e8f1b6fdb12..b132b3c2b99 100644 --- a/noir-projects/noir-protocol-circuits/private_kernel_reset_config.json +++ b/noir-projects/noir-protocol-circuits/private_kernel_reset_config.json @@ -40,16 +40,16 @@ "standalone": [], "cost": 150 }, - "ENCRYPTED_LOG_SILOING_AMOUNT": { - "variants": [1, 8], + "PRIVATE_LOG_SILOING_AMOUNT": { + "variants": [4, 32], "standalone": [], "cost": 150 } }, "specialCases": [ - [4, 4, 4, 4, 4, 4, 4, 4, 1], - [16, 16, 16, 16, 16, 16, 16, 16, 2], - [32, 32, 32, 32, 32, 32, 32, 32, 4], - [64, 64, 64, 64, 64, 64, 64, 64, 8] + [4, 4, 4, 4, 4, 4, 4, 4, 4], + [16, 16, 16, 16, 16, 16, 16, 16, 16], + [32, 32, 32, 32, 32, 32, 32, 32, 32], + [64, 64, 64, 64, 64, 64, 64, 64, 32] ] } diff --git a/noir-projects/noir-protocol-circuits/scripts/generate_variants.js b/noir-projects/noir-protocol-circuits/scripts/generate_variants.js index 6625333516f..239f33ea6ae 100644 --- a/noir-projects/noir-protocol-circuits/scripts/generate_variants.js +++ b/noir-projects/noir-protocol-circuits/scripts/generate_variants.js @@ -11,8 +11,8 @@ const autogeneratedCircuitsFolder = "crates/autogenerated"; const dimensionNames = Object.keys(config.dimensions); const aliases = { - tiny: [4, 4, 4, 4, 4, 4, 4, 4, 1], - full: [64, 64, 64, 64, 64, 64, 64, 64, 8], + tiny: [4, 4, 4, 4, 4, 4, 4, 4, 4], + full: [64, 64, 64, 64, 64, 64, 64, 64, 32], }; function getResetTag(dimensions) { diff --git a/yarn-project/archiver/src/archiver/archiver.test.ts b/yarn-project/archiver/src/archiver/archiver.test.ts index 33255e88afa..69d69ed0b2d 100644 --- a/yarn-project/archiver/src/archiver/archiver.test.ts +++ b/yarn-project/archiver/src/archiver/archiver.test.ts @@ -1,12 +1,5 @@ -import { - EncryptedL2BlockL2Logs, - EncryptedNoteL2BlockL2Logs, - InboxLeaf, - L2Block, - LogType, - UnencryptedL2BlockL2Logs, -} from '@aztec/circuit-types'; -import { GENESIS_ARCHIVE_ROOT } from '@aztec/circuits.js'; +import { InboxLeaf, L2Block } from '@aztec/circuit-types'; +import { GENESIS_ARCHIVE_ROOT, PrivateLog } from '@aztec/circuits.js'; import { DefaultL1ContractsConfig } from '@aztec/ethereum'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; @@ -44,6 +37,14 @@ describe('Archiver', () => { const inboxAddress = EthAddress.ZERO; const registryAddress = EthAddress.ZERO; const blockNumbers = [1, 2, 3]; + const txsPerBlock = 4; + + const getNumPrivateLogsForTx = (blockNumber: number, txIndex: number) => txIndex + blockNumber; + const getNumPrivateLogsForBlock = (blockNumber: number) => + Array(txsPerBlock) + .fill(0) + .map((_, i) => getNumPrivateLogsForTx(i, blockNumber)) + .reduce((accum, num) => accum + num, 0); let publicClient: MockProxy>; let instrumentation: MockProxy; @@ -78,7 +79,14 @@ describe('Archiver', () => { instrumentation, ); - blocks = blockNumbers.map(x => L2Block.random(x, 4, x, x + 1, 2, 2)); + blocks = blockNumbers.map(x => L2Block.random(x, txsPerBlock, x + 1, 2)); + blocks.forEach(block => { + block.body.txEffects.forEach((txEffect, i) => { + txEffect.privateLogs = Array(getNumPrivateLogsForTx(block.number, i)) + .fill(0) + .map(() => PrivateLog.random()); + }); + }); rollupRead = mock(); rollupRead.archiveAt.mockImplementation((args: readonly [bigint]) => @@ -174,33 +182,18 @@ describe('Archiver', () => { } // Expect logs to correspond to what is set by L2Block.random(...) - const noteEncryptedLogs = await archiver.getLogs(1, 100, LogType.NOTEENCRYPTED); - expect(noteEncryptedLogs.length).toEqual(blockNumbers.length); - - for (const [index, x] of blockNumbers.entries()) { - const expectedTotalNumEncryptedLogs = 4 * x * 2; - const totalNumEncryptedLogs = EncryptedNoteL2BlockL2Logs.unrollLogs([noteEncryptedLogs[index]]).length; - expect(totalNumEncryptedLogs).toEqual(expectedTotalNumEncryptedLogs); - } + for (let i = 0; i < blockNumbers.length; i++) { + const blockNumber = blockNumbers[i]; - const encryptedLogs = await archiver.getLogs(1, 100, LogType.ENCRYPTED); - expect(encryptedLogs.length).toEqual(blockNumbers.length); + const privateLogs = await archiver.getPrivateLogs(blockNumber, 1); + expect(privateLogs.length).toBe(getNumPrivateLogsForBlock(blockNumber)); - for (const [index, x] of blockNumbers.entries()) { - const expectedTotalNumEncryptedLogs = 4 * x * 2; - const totalNumEncryptedLogs = EncryptedL2BlockL2Logs.unrollLogs([encryptedLogs[index]]).length; - expect(totalNumEncryptedLogs).toEqual(expectedTotalNumEncryptedLogs); + const unencryptedLogs = (await archiver.getUnencryptedLogs({ fromBlock: blockNumber, toBlock: blockNumber + 1 })) + .logs; + const expectedTotalNumUnencryptedLogs = 4 * (blockNumber + 1) * 2; + expect(unencryptedLogs.length).toEqual(expectedTotalNumUnencryptedLogs); } - const unencryptedLogs = await archiver.getLogs(1, 100, LogType.UNENCRYPTED); - expect(unencryptedLogs.length).toEqual(blockNumbers.length); - - blockNumbers.forEach((x, index) => { - const expectedTotalNumUnencryptedLogs = 4 * (x + 1) * 2; - const totalNumUnencryptedLogs = UnencryptedL2BlockL2Logs.unrollLogs([unencryptedLogs[index]]).length; - expect(totalNumUnencryptedLogs).toEqual(expectedTotalNumUnencryptedLogs); - }); - blockNumbers.forEach(async x => { const expectedTotalNumContractClassLogs = 4; const contractClassLogs = await archiver.getContractClassLogs({ fromBlock: x, toBlock: x + 1 }); @@ -381,11 +374,9 @@ describe('Archiver', () => { expect(await archiver.getTxEffect(txHash)).resolves.toBeUndefined; expect(await archiver.getBlock(2)).resolves.toBeUndefined; - [LogType.NOTEENCRYPTED, LogType.ENCRYPTED, LogType.UNENCRYPTED].forEach(async t => { - expect(await archiver.getLogs(2, 1, t)).toEqual([]); - }); - - // The random blocks don't include contract instances nor classes we we cannot look for those here. + expect(await archiver.getPrivateLogs(2, 1)).toEqual([]); + expect((await archiver.getUnencryptedLogs({ fromBlock: 2, toBlock: 3 })).logs).toEqual([]); + expect((await archiver.getContractClassLogs({ fromBlock: 2, toBlock: 3 })).logs).toEqual([]); }, 10_000); // TODO(palla/reorg): Add a unit test for the archiver handleEpochPrune diff --git a/yarn-project/archiver/src/archiver/archiver.ts b/yarn-project/archiver/src/archiver/archiver.ts index 35a33d7bad4..ff6b9624902 100644 --- a/yarn-project/archiver/src/archiver/archiver.ts +++ b/yarn-project/archiver/src/archiver/archiver.ts @@ -1,18 +1,14 @@ import { - type EncryptedL2Log, - type FromLogType, type GetUnencryptedLogsResponse, type InBlock, type InboxLeaf, type L1ToL2MessageSource, type L2Block, type L2BlockId, - type L2BlockL2Logs, type L2BlockSource, type L2LogsSource, type L2Tips, type LogFilter, - type LogType, type NullifierWithBlockSource, type TxEffect, type TxHash, @@ -22,16 +18,13 @@ import { } from '@aztec/circuit-types'; import { type ContractClassPublic, - ContractClassRegisteredEvent, type ContractDataSource, - ContractInstanceDeployedEvent, type ContractInstanceWithAddress, type ExecutablePrivateFunctionWithMembershipProof, type FunctionSelector, type Header, - PrivateFunctionBroadcastedEvent, + type PrivateLog, type PublicFunction, - UnconstrainedFunctionBroadcastedEvent, type UnconstrainedFunctionWithMembershipProof, computePublicBytecodeCommitment, isValidPrivateFunctionMembershipProof, @@ -47,7 +40,12 @@ import { RunningPromise } from '@aztec/foundation/running-promise'; import { count } from '@aztec/foundation/string'; import { Timer } from '@aztec/foundation/timer'; import { InboxAbi, RollupAbi } from '@aztec/l1-artifacts'; -import { ProtocolContractAddress } from '@aztec/protocol-contracts'; +import { + ContractClassRegisteredEvent, + ContractInstanceDeployedEvent, + PrivateFunctionBroadcastedEvent, + UnconstrainedFunctionBroadcastedEvent, +} from '@aztec/protocol-contracts'; import { type TelemetryClient } from '@aztec/telemetry-client'; import groupBy from 'lodash.groupby'; @@ -629,18 +627,13 @@ export class Archiver implements ArchiveSource { } /** - * Gets up to `limit` amount of logs starting from `from`. - * @param from - Number of the L2 block to which corresponds the first logs to be returned. - * @param limit - The number of logs to return. - * @param logType - Specifies whether to return encrypted or unencrypted logs. - * @returns The requested logs. + * Retrieves all private logs from up to `limit` blocks, starting from the block number `from`. + * @param from - The block number from which to begin retrieving logs. + * @param limit - The maximum number of blocks to retrieve logs from. + * @returns An array of private logs from the specified range of blocks. */ - public getLogs( - from: number, - limit: number, - logType: TLogType, - ): Promise>[]> { - return this.store.getLogs(from, limit, logType); + public getPrivateLogs(from: number, limit: number): Promise { + return this.store.getPrivateLogs(from, limit); } /** @@ -830,10 +823,10 @@ class ArchiverStoreHelper * @param allLogs - All logs emitted in a bunch of blocks. */ async #updateRegisteredContractClasses(allLogs: UnencryptedL2Log[], blockNum: number, operation: Operation) { - const contractClasses = ContractClassRegisteredEvent.fromLogs( - allLogs, - ProtocolContractAddress.ContractClassRegisterer, - ).map(e => e.toContractClassPublic()); + const contractClasses = allLogs + .filter(log => ContractClassRegisteredEvent.isContractClassRegisteredEvent(log.data)) + .map(log => ContractClassRegisteredEvent.fromLog(log.data)) + .map(e => e.toContractClassPublic()); if (contractClasses.length > 0) { contractClasses.forEach(c => this.#log.verbose(`Registering contract class ${c.id.toString()}`)); if (operation == Operation.Store) { @@ -854,8 +847,11 @@ class ArchiverStoreHelper * Extracts and stores contract instances out of ContractInstanceDeployed events emitted by the canonical deployer contract. * @param allLogs - All logs emitted in a bunch of blocks. */ - async #updateDeployedContractInstances(allLogs: EncryptedL2Log[], blockNum: number, operation: Operation) { - const contractInstances = ContractInstanceDeployedEvent.fromLogs(allLogs).map(e => e.toContractInstance()); + async #updateDeployedContractInstances(allLogs: PrivateLog[], blockNum: number, operation: Operation) { + const contractInstances = allLogs + .filter(log => ContractInstanceDeployedEvent.isContractInstanceDeployedEvent(log)) + .map(log => ContractInstanceDeployedEvent.fromLog(log)) + .map(e => e.toContractInstance()); if (contractInstances.length > 0) { contractInstances.forEach(c => this.#log.verbose(`${Operation[operation]} contract instance at ${c.address.toString()}`), @@ -881,14 +877,12 @@ class ArchiverStoreHelper */ async #storeBroadcastedIndividualFunctions(allLogs: UnencryptedL2Log[], _blockNum: number) { // Filter out private and unconstrained function broadcast events - const privateFnEvents = PrivateFunctionBroadcastedEvent.fromLogs( - allLogs, - ProtocolContractAddress.ContractClassRegisterer, - ); - const unconstrainedFnEvents = UnconstrainedFunctionBroadcastedEvent.fromLogs( - allLogs, - ProtocolContractAddress.ContractClassRegisterer, - ); + const privateFnEvents = allLogs + .filter(log => PrivateFunctionBroadcastedEvent.isPrivateFunctionBroadcastedEvent(log.data)) + .map(log => PrivateFunctionBroadcastedEvent.fromLog(log.data)); + const unconstrainedFnEvents = allLogs + .filter(log => UnconstrainedFunctionBroadcastedEvent.isUnconstrainedFunctionBroadcastedEvent(log.data)) + .map(log => UnconstrainedFunctionBroadcastedEvent.fromLog(log.data)); // Group all events by contract class id for (const [classIdString, classEvents] of Object.entries( @@ -936,14 +930,12 @@ class ArchiverStoreHelper const contractClassLogs = block.data.body.txEffects .flatMap(txEffect => (txEffect ? [txEffect.contractClassLogs] : [])) .flatMap(txLog => txLog.unrollLogs()); - // ContractInstanceDeployed event logs are now broadcast in .encryptedLogs - const allEncryptedLogs = block.data.body.txEffects - .flatMap(txEffect => (txEffect ? [txEffect.encryptedLogs] : [])) - .flatMap(txLog => txLog.unrollLogs()); + // ContractInstanceDeployed event logs are broadcast in privateLogs. + const privateLogs = block.data.body.txEffects.flatMap(txEffect => txEffect.privateLogs); return ( await Promise.all([ this.#updateRegisteredContractClasses(contractClassLogs, block.data.number, Operation.Store), - this.#updateDeployedContractInstances(allEncryptedLogs, block.data.number, Operation.Store), + this.#updateDeployedContractInstances(privateLogs, block.data.number, Operation.Store), this.#storeBroadcastedIndividualFunctions(contractClassLogs, block.data.number), ]) ).every(Boolean); @@ -970,12 +962,10 @@ class ArchiverStoreHelper const contractClassLogs = block.data.body.txEffects .flatMap(txEffect => (txEffect ? [txEffect.contractClassLogs] : [])) .flatMap(txLog => txLog.unrollLogs()); - // ContractInstanceDeployed event logs are now broadcast in .encryptedLogs - const allEncryptedLogs = block.data.body.txEffects - .flatMap(txEffect => (txEffect ? [txEffect.encryptedLogs] : [])) - .flatMap(txLog => txLog.unrollLogs()); + // ContractInstanceDeployed event logs are broadcast in privateLogs. + const privateLogs = block.data.body.txEffects.flatMap(txEffect => txEffect.privateLogs); await this.#updateRegisteredContractClasses(contractClassLogs, block.data.number, Operation.Delete); - await this.#updateDeployedContractInstances(allEncryptedLogs, block.data.number, Operation.Delete); + await this.#updateDeployedContractInstances(privateLogs, block.data.number, Operation.Delete); }), )), this.store.deleteLogs(blocks.map(b => b.data)), @@ -1004,12 +994,8 @@ class ArchiverStoreHelper getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise { return this.store.getL1ToL2MessageIndex(l1ToL2Message); } - getLogs( - from: number, - limit: number, - logType: TLogType, - ): Promise>[]> { - return this.store.getLogs(from, limit, logType); + getPrivateLogs(from: number, limit: number): Promise { + return this.store.getPrivateLogs(from, limit); } getLogsByTags(tags: Fr[]): Promise { return this.store.getLogsByTags(tags); diff --git a/yarn-project/archiver/src/archiver/archiver_store.ts b/yarn-project/archiver/src/archiver/archiver_store.ts index 27958e22d80..281fb80c41d 100644 --- a/yarn-project/archiver/src/archiver/archiver_store.ts +++ b/yarn-project/archiver/src/archiver/archiver_store.ts @@ -1,12 +1,9 @@ import { - type FromLogType, type GetUnencryptedLogsResponse, type InBlock, type InboxLeaf, type L2Block, - type L2BlockL2Logs, type LogFilter, - type LogType, type TxEffect, type TxHash, type TxReceipt, @@ -18,6 +15,7 @@ import { type ExecutablePrivateFunctionWithMembershipProof, type Fr, type Header, + type PrivateLog, type UnconstrainedFunctionWithMembershipProof, } from '@aztec/circuits.js'; import { type ContractArtifact, type FunctionSelector } from '@aztec/foundation/abi'; @@ -142,17 +140,12 @@ export interface ArchiverDataStore { getTotalL1ToL2MessageCount(): Promise; /** - * Gets up to `limit` amount of logs starting from `from`. - * @param from - Number of the L2 block to which corresponds the first logs to be returned. - * @param limit - The number of logs to return. - * @param logType - Specifies whether to return encrypted or unencrypted logs. - * @returns The requested logs. + * Retrieves all private logs from up to `limit` blocks, starting from the block number `from`. + * @param from - The block number from which to begin retrieving logs. + * @param limit - The maximum number of blocks to retrieve logs from. + * @returns An array of private logs from the specified range of blocks. */ - getLogs( - from: number, - limit: number, - logType: TLogType, - ): Promise>[]>; + getPrivateLogs(from: number, limit: number): Promise; /** * Gets all logs that match any of the received tags (i.e. logs with their first field equal to a tag). diff --git a/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts b/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts index e7a8e17bbd0..50730dbb56e 100644 --- a/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts +++ b/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts @@ -1,4 +1,14 @@ -import { InboxLeaf, L2Block, LogId, LogType, TxHash, wrapInBlock } from '@aztec/circuit-types'; +import { + InboxLeaf, + L2Block, + LogId, + TxEffect, + TxHash, + UnencryptedFunctionL2Logs, + UnencryptedL2Log, + UnencryptedTxL2Logs, + wrapInBlock, +} from '@aztec/circuit-types'; import '@aztec/circuit-types/jest'; import { AztecAddress, @@ -8,6 +18,8 @@ import { INITIAL_L2_BLOCK_NUM, L1_TO_L2_MSG_SUBTREE_HEIGHT, MAX_NULLIFIERS_PER_TX, + PRIVATE_LOG_SIZE_IN_FIELDS, + PrivateLog, SerializableContractInstance, computePublicBytecodeCommitment, } from '@aztec/circuits.js'; @@ -16,7 +28,6 @@ import { makeExecutablePrivateFunctionWithMembershipProof, makeUnconstrainedFunctionWithMembershipProof, } from '@aztec/circuits.js/testing'; -import { toBufferBE } from '@aztec/foundation/bigint-buffer'; import { times } from '@aztec/foundation/collection'; import { randomBytes, randomInt } from '@aztec/foundation/crypto'; @@ -155,55 +166,41 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch }); describe('addLogs', () => { - it('adds encrypted & unencrypted logs', async () => { + it('adds private & unencrypted logs', async () => { const block = blocks[0].data; await expect(store.addLogs([block])).resolves.toEqual(true); }); }); describe('deleteLogs', () => { - it('deletes encrypted & unencrypted logs', async () => { + it('deletes private & unencrypted logs', async () => { const block = blocks[0].data; await store.addBlocks([blocks[0]]); await expect(store.addLogs([block])).resolves.toEqual(true); - expect((await store.getLogs(1, 1, LogType.NOTEENCRYPTED))[0]).toEqual(block.body.noteEncryptedLogs); - expect((await store.getLogs(1, 1, LogType.ENCRYPTED))[0]).toEqual(block.body.encryptedLogs); - expect((await store.getLogs(1, 1, LogType.UNENCRYPTED))[0]).toEqual(block.body.unencryptedLogs); + expect((await store.getPrivateLogs(1, 1)).length).toEqual( + block.body.txEffects.map(txEffect => txEffect.privateLogs).flat().length, + ); + expect((await store.getUnencryptedLogs({ fromBlock: 1 })).logs.length).toEqual( + block.body.unencryptedLogs.getTotalLogCount(), + ); // This one is a pain for memory as we would never want to just delete memory in the middle. await store.deleteLogs([block]); - expect((await store.getLogs(1, 1, LogType.NOTEENCRYPTED))[0]).toEqual(undefined); - expect((await store.getLogs(1, 1, LogType.ENCRYPTED))[0]).toEqual(undefined); - expect((await store.getLogs(1, 1, LogType.UNENCRYPTED))[0]).toEqual(undefined); + expect((await store.getPrivateLogs(1, 1)).length).toEqual(0); + expect((await store.getUnencryptedLogs({ fromBlock: 1 })).logs.length).toEqual(0); }); }); - describe.each([ - ['note_encrypted', LogType.NOTEENCRYPTED], - ['encrypted', LogType.ENCRYPTED], - ['unencrypted', LogType.UNENCRYPTED], - ])('getLogs (%s)', (_, logType) => { - beforeEach(async () => { - await store.addBlocks(blocks); - await store.addLogs(blocks.map(b => b.data)); - }); + describe('getPrivateLogs', () => { + it('gets added private logs', async () => { + const block = blocks[0].data; + await store.addBlocks([blocks[0]]); + await store.addLogs([block]); - it.each(blockTests)('retrieves previously stored logs', async (from, limit, getExpectedBlocks) => { - const expectedLogs = getExpectedBlocks().map(block => { - switch (logType) { - case LogType.ENCRYPTED: - return block.data.body.encryptedLogs; - case LogType.NOTEENCRYPTED: - return block.data.body.noteEncryptedLogs; - case LogType.UNENCRYPTED: - default: - return block.data.body.unencryptedLogs; - } - }); - const actualLogs = await store.getLogs(from, limit, logType); - expect(actualLogs[0].txLogs[0]).toEqual(expectedLogs[0].txLogs[0]); + const privateLogs = await store.getPrivateLogs(1, 1); + expect(privateLogs).toEqual(block.body.txEffects.map(txEffect => txEffect.privateLogs).flat()); }); }); @@ -373,178 +370,155 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch }); describe('getLogsByTags', () => { - const txsPerBlock = 4; - const numPrivateFunctionCalls = 3; - const numPublicFunctionCalls = 1; - const numEncryptedLogsPerFn = 2; - const numUnencryptedLogsPerFn = 1; - const numBlocks = 10; - let blocks: L1Published[]; - let encryptedLogTags: { [i: number]: { [j: number]: Buffer[] } } = {}; - let unencryptedLogTags: { [i: number]: { [j: number]: Buffer[] } } = {}; - - beforeEach(async () => { - blocks = times(numBlocks, (index: number) => ({ - data: L2Block.random( - index + 1, - txsPerBlock, - numPrivateFunctionCalls, - numPublicFunctionCalls, - numEncryptedLogsPerFn, - numUnencryptedLogsPerFn, - ), - l1: { blockNumber: BigInt(index), blockHash: `0x${index}`, timestamp: BigInt(index) }, - })); - // Last block has the note encrypted log tags of the first tx copied from the previous block - blocks[numBlocks - 1].data.body.noteEncryptedLogs.txLogs[0].functionLogs.forEach((fnLogs, fnIndex) => { - fnLogs.logs.forEach((log, logIndex) => { - const previousLogData = - blocks[numBlocks - 2].data.body.noteEncryptedLogs.txLogs[0].functionLogs[fnIndex].logs[logIndex].data; - previousLogData.copy(log.data, 0, 0, 32); - }); - }); - // Last block has invalid tags in the second tx - const tooBig = toBufferBE(Fr.MODULUS, 32); - blocks[numBlocks - 1].data.body.noteEncryptedLogs.txLogs[1].functionLogs.forEach(fnLogs => { - fnLogs.logs.forEach(log => { - tooBig.copy(log.data, 0, 0, 32); - }); - }); + const numBlocks = 3; + const numTxsPerBlock = 4; + const numPrivateLogsPerTx = 3; + const numUnencryptedLogsPerTx = 2; - await store.addBlocks(blocks); - await store.addLogs(blocks.map(b => b.data)); + let blocks: L1Published[]; - encryptedLogTags = {}; - unencryptedLogTags = {}; - blocks.forEach((b, blockIndex) => { - if (!encryptedLogTags[blockIndex]) { - encryptedLogTags[blockIndex] = {}; - } - if (!unencryptedLogTags[blockIndex]) { - unencryptedLogTags[blockIndex] = {}; - } - b.data.body.noteEncryptedLogs.txLogs.forEach((txLogs, txIndex) => { - if (!encryptedLogTags[blockIndex][txIndex]) { - encryptedLogTags[blockIndex][txIndex] = []; - } - encryptedLogTags[blockIndex][txIndex].push(...txLogs.unrollLogs().map(log => log.data.subarray(0, 32))); - }); - b.data.body.unencryptedLogs.txLogs.forEach((txLogs, txIndex) => { - if (!unencryptedLogTags[blockIndex][txIndex]) { - unencryptedLogTags[blockIndex][txIndex] = []; - } - unencryptedLogTags[blockIndex][txIndex].push(...txLogs.unrollLogs().map(log => log.data.subarray(0, 32))); - }); - }); - }); + const makeTag = (blockNumber: number, txIndex: number, logIndex: number, isPublic = false) => + new Fr((blockNumber * 100 + txIndex * 10 + logIndex) * (isPublic ? 123 : 1)); - it('is possible to batch request encrypted logs of a tx via tags', async () => { - // get random tx from any block that's not the last one - const targetBlockIndex = randomInt(numBlocks - 2); - const targetTxIndex = randomInt(txsPerBlock); + const makePrivateLog = (tag: Fr) => + PrivateLog.fromFields([tag, ...times(PRIVATE_LOG_SIZE_IN_FIELDS - 1, i => new Fr(tag.toNumber() + i))]); - const logsByTags = await store.getLogsByTags( - encryptedLogTags[targetBlockIndex][targetTxIndex].map(buffer => new Fr(buffer)), - ); + const makePublicLog = (tag: Fr) => + Buffer.concat([tag.toBuffer(), ...times(tag.toNumber() % 60, i => new Fr(tag.toNumber() + i).toBuffer())]); - const expectedResponseSize = numPrivateFunctionCalls * numEncryptedLogsPerFn; - expect(logsByTags.length).toEqual(expectedResponseSize); - - logsByTags.forEach((logsByTag, logIndex) => { - expect(logsByTag).toHaveLength(1); - const [scopedLog] = logsByTag; - expect(scopedLog.txHash).toEqual(blocks[targetBlockIndex].data.body.txEffects[targetTxIndex].txHash); - expect(scopedLog.logData).toEqual( - blocks[targetBlockIndex].data.body.noteEncryptedLogs.txLogs[targetTxIndex].unrollLogs()[logIndex].data, - ); + const mockPrivateLogs = (blockNumber: number, txIndex: number) => { + return times(numPrivateLogsPerTx, (logIndex: number) => { + const tag = makeTag(blockNumber, txIndex, logIndex); + return makePrivateLog(tag); }); - }); - - // TODO: Allow this test when #9835 is fixed and tags can be correctly decoded - it.skip('is possible to batch request all logs (encrypted and unencrypted) of a tx via tags', async () => { - // get random tx from any block that's not the last one - const targetBlockIndex = randomInt(numBlocks - 2); - const targetTxIndex = randomInt(txsPerBlock); - - const logsByTags = await store.getLogsByTags( - encryptedLogTags[targetBlockIndex][targetTxIndex] - .concat(unencryptedLogTags[targetBlockIndex][targetTxIndex]) - .map(buffer => new Fr(buffer)), - ); + }; - const expectedResponseSize = - numPrivateFunctionCalls * numEncryptedLogsPerFn + numPublicFunctionCalls * numUnencryptedLogsPerFn; - expect(logsByTags.length).toEqual(expectedResponseSize); - - const encryptedLogsByTags = logsByTags.slice(0, numPrivateFunctionCalls * numEncryptedLogsPerFn); - const unencryptedLogsByTags = logsByTags.slice(numPrivateFunctionCalls * numEncryptedLogsPerFn); - encryptedLogsByTags.forEach((logsByTag, logIndex) => { - expect(logsByTag).toHaveLength(1); - const [scopedLog] = logsByTag; - expect(scopedLog.txHash).toEqual(blocks[targetBlockIndex].data.body.txEffects[targetTxIndex].txHash); - expect(scopedLog.logData).toEqual( - blocks[targetBlockIndex].data.body.noteEncryptedLogs.txLogs[targetTxIndex].unrollLogs()[logIndex].data, - ); + const mockUnencryptedLogs = (blockNumber: number, txIndex: number) => { + const logs = times(numUnencryptedLogsPerTx, (logIndex: number) => { + const tag = makeTag(blockNumber, txIndex, logIndex, /* isPublic */ true); + const log = makePublicLog(tag); + return new UnencryptedL2Log(AztecAddress.fromNumber(txIndex), log); }); - unencryptedLogsByTags.forEach((logsByTag, logIndex) => { - expect(logsByTag).toHaveLength(1); - const [scopedLog] = logsByTag; - expect(scopedLog.logData).toEqual( - blocks[targetBlockIndex].data.body.unencryptedLogs.txLogs[targetTxIndex].unrollLogs()[logIndex].data, - ); + return new UnencryptedTxL2Logs([new UnencryptedFunctionL2Logs(logs)]); + }; + + const mockBlockWithLogs = (blockNumber: number): L1Published => { + const block = L2Block.random(blockNumber); + block.header.globalVariables.blockNumber = new Fr(blockNumber); + + block.body.txEffects = times(numTxsPerBlock, (txIndex: number) => { + const txEffect = TxEffect.random(); + txEffect.privateLogs = mockPrivateLogs(blockNumber, txIndex); + txEffect.unencryptedLogs = mockUnencryptedLogs(blockNumber, txIndex); + return txEffect; }); - }); - it('is possible to batch request logs of different blocks via tags', async () => { - // get first tx of first block and second tx of second block - const logsByTags = await store.getLogsByTags( - [...encryptedLogTags[0][0], ...encryptedLogTags[1][1]].map(buffer => new Fr(buffer)), - ); + return { + data: block, + l1: { blockNumber: BigInt(blockNumber), blockHash: `0x${blockNumber}`, timestamp: BigInt(blockNumber) }, + }; + }; - const expectedResponseSize = 2 * numPrivateFunctionCalls * numEncryptedLogsPerFn; - expect(logsByTags.length).toEqual(expectedResponseSize); + beforeEach(async () => { + blocks = times(numBlocks, (index: number) => mockBlockWithLogs(index)); - logsByTags.forEach(logsByTag => expect(logsByTag).toHaveLength(1)); + await store.addBlocks(blocks); + await store.addLogs(blocks.map(b => b.data)); }); - it('is possible to batch request logs that have the same tag but different content', async () => { - // get first tx of last block - const logsByTags = await store.getLogsByTags(encryptedLogTags[numBlocks - 1][0].map(buffer => new Fr(buffer))); + it('is possible to batch request private logs via tags', async () => { + const tags = [makeTag(1, 1, 2), makeTag(0, 2, 0)]; + + const logsByTags = await store.getLogsByTags(tags); + + expect(logsByTags).toEqual([ + [ + expect.objectContaining({ + blockNumber: 1, + logData: makePrivateLog(tags[0]).toBuffer(), + isFromPublic: false, + }), + ], + [ + expect.objectContaining({ + blockNumber: 0, + logData: makePrivateLog(tags[1]).toBuffer(), + isFromPublic: false, + }), + ], + ]); + }); - const expectedResponseSize = numPrivateFunctionCalls * numEncryptedLogsPerFn; - expect(logsByTags.length).toEqual(expectedResponseSize); + // TODO: Allow this test when #9835 is fixed and tags can be correctly decoded + it.skip('is possible to batch request all logs (private and unencrypted) via tags', async () => { + // Tag(0, 0, 0) is shared with the first private log and the first unencrypted log. + const tags = [makeTag(0, 0, 0)]; + + const logsByTags = await store.getLogsByTags(tags); + + expect(logsByTags).toEqual([ + [ + expect.objectContaining({ + blockNumber: 0, + logData: makePrivateLog(tags[0]).toBuffer(), + isFromPublic: false, + }), + expect.objectContaining({ + blockNumber: 0, + logData: makePublicLog(tags[0]), + isFromPublic: true, + }), + ], + ]); + }); - logsByTags.forEach(logsByTag => { - expect(logsByTag).toHaveLength(2); - const [tag0, tag1] = logsByTag.map(scopedLog => new Fr(scopedLog.logData.subarray(0, 32))); - expect(tag0).toEqual(tag1); - }); + it('is possible to batch request logs that have the same tag but different content', async () => { + const tags = [makeTag(1, 2, 1)]; + + // Create a block containing logs that have the same tag as the blocks before. + const newBlockNumber = numBlocks; + const newBlock = mockBlockWithLogs(newBlockNumber); + const newLog = newBlock.data.body.txEffects[1].privateLogs[1]; + newLog.fields[0] = tags[0]; + newBlock.data.body.txEffects[1].privateLogs[1] = newLog; + await store.addBlocks([newBlock]); + await store.addLogs([newBlock.data]); + + const logsByTags = await store.getLogsByTags(tags); + + expect(logsByTags).toEqual([ + [ + expect.objectContaining({ + blockNumber: 1, + logData: makePrivateLog(tags[0]).toBuffer(), + isFromPublic: false, + }), + expect.objectContaining({ + blockNumber: newBlockNumber, + logData: newLog.toBuffer(), + isFromPublic: false, + }), + ], + ]); }); it('is possible to request logs for non-existing tags and determine their position', async () => { - // get random tx from any block that's not the last one - const targetBlockIndex = randomInt(numBlocks - 2); - const targetTxIndex = randomInt(txsPerBlock); - - const logsByTags = await store.getLogsByTags([ - Fr.random(), - ...encryptedLogTags[targetBlockIndex][targetTxIndex].slice(1).map(buffer => new Fr(buffer)), + const tags = [makeTag(99, 88, 77), makeTag(1, 1, 1)]; + + const logsByTags = await store.getLogsByTags(tags); + + expect(logsByTags).toEqual([ + [ + // No logs for the first tag. + ], + [ + expect.objectContaining({ + blockNumber: 1, + logData: makePrivateLog(tags[1]).toBuffer(), + isFromPublic: false, + }), + ], ]); - - const expectedResponseSize = numPrivateFunctionCalls * numEncryptedLogsPerFn; - expect(logsByTags.length).toEqual(expectedResponseSize); - - const [emptyLogsByTag, ...populatedLogsByTags] = logsByTags; - expect(emptyLogsByTag).toHaveLength(0); - - populatedLogsByTags.forEach((logsByTag, logIndex) => { - expect(logsByTag).toHaveLength(1); - const [scopedLog] = logsByTag; - expect(scopedLog.txHash).toEqual(blocks[targetBlockIndex].data.body.txEffects[targetTxIndex].txHash); - expect(scopedLog.logData).toEqual( - blocks[targetBlockIndex].data.body.noteEncryptedLogs.txLogs[targetTxIndex].unrollLogs()[logIndex + 1].data, - ); - }); }); }); @@ -557,7 +531,7 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch beforeEach(async () => { blocks = times(numBlocks, (index: number) => ({ - data: L2Block.random(index + 1, txsPerBlock, 2, numPublicFunctionCalls, 2, numUnencryptedLogs), + data: L2Block.random(index + 1, txsPerBlock, numPublicFunctionCalls, numUnencryptedLogs), l1: { blockNumber: BigInt(index), blockHash: `0x${index}`, timestamp: BigInt(index) }, })); diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/kv_archiver_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/kv_archiver_store.ts index 21567fd329a..618abf9cbfd 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/kv_archiver_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/kv_archiver_store.ts @@ -1,12 +1,9 @@ import { - type FromLogType, type GetUnencryptedLogsResponse, type InBlock, type InboxLeaf, type L2Block, - type L2BlockL2Logs, type LogFilter, - type LogType, type TxHash, type TxReceipt, type TxScopedL2Log, @@ -17,6 +14,7 @@ import { type ExecutablePrivateFunctionWithMembershipProof, type Fr, type Header, + type PrivateLog, type UnconstrainedFunctionWithMembershipProof, } from '@aztec/circuits.js'; import { type ContractArtifact, FunctionSelector } from '@aztec/foundation/abi'; @@ -266,19 +264,14 @@ export class KVArchiverDataStore implements ArchiverDataStore { } /** - * Gets up to `limit` amount of logs starting from `from`. - * @param start - Number of the L2 block to which corresponds the first logs to be returned. - * @param limit - The number of logs to return. - * @param logType - Specifies whether to return encrypted or unencrypted logs. - * @returns The requested logs. + * Retrieves all private logs from up to `limit` blocks, starting from the block number `from`. + * @param from - The block number from which to begin retrieving logs. + * @param limit - The maximum number of blocks to retrieve logs from. + * @returns An array of private logs from the specified range of blocks. */ - getLogs( - start: number, - limit: number, - logType: TLogType, - ): Promise>[]> { + getPrivateLogs(from: number, limit: number): Promise { try { - return Promise.resolve(Array.from(this.#logStore.getLogs(start, limit, logType))); + return Promise.resolve(Array.from(this.#logStore.getPrivateLogs(from, limit))); } catch (err) { return Promise.reject(err); } diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/log_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/log_store.ts index f6c0abbc327..efb4922d328 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/log_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/log_store.ts @@ -1,23 +1,18 @@ import { - type Body, ContractClass2BlockL2Logs, - EncryptedL2BlockL2Logs, - EncryptedNoteL2BlockL2Logs, ExtendedUnencryptedL2Log, - type FromLogType, type GetUnencryptedLogsResponse, type L2Block, - type L2BlockL2Logs, type LogFilter, LogId, - LogType, TxScopedL2Log, UnencryptedL2BlockL2Logs, type UnencryptedL2Log, } from '@aztec/circuit-types'; -import { Fr } from '@aztec/circuits.js'; +import { Fr, PrivateLog } from '@aztec/circuits.js'; import { INITIAL_L2_BLOCK_NUM, MAX_NOTE_HASHES_PER_TX } from '@aztec/circuits.js/constants'; import { createDebugLogger } from '@aztec/foundation/log'; +import { BufferReader } from '@aztec/foundation/serialize'; import { type AztecKVStore, type AztecMap } from '@aztec/kv-store'; import { type BlockStore } from './block_store.js'; @@ -26,72 +21,83 @@ import { type BlockStore } from './block_store.js'; * A store for logs */ export class LogStore { - #noteEncryptedLogsByBlock: AztecMap; #logsByTag: AztecMap; #logTagsByBlock: AztecMap; - #encryptedLogsByBlock: AztecMap; + #privateLogsByBlock: AztecMap; #unencryptedLogsByBlock: AztecMap; #contractClassLogsByBlock: AztecMap; #logsMaxPageSize: number; #log = createDebugLogger('aztec:archiver:log_store'); constructor(private db: AztecKVStore, private blockStore: BlockStore, logsMaxPageSize: number = 1000) { - this.#noteEncryptedLogsByBlock = db.openMap('archiver_note_encrypted_logs_by_block'); this.#logsByTag = db.openMap('archiver_tagged_logs_by_tag'); this.#logTagsByBlock = db.openMap('archiver_log_tags_by_block'); - this.#encryptedLogsByBlock = db.openMap('archiver_encrypted_logs_by_block'); + this.#privateLogsByBlock = db.openMap('archiver_private_logs_by_block'); this.#unencryptedLogsByBlock = db.openMap('archiver_unencrypted_logs_by_block'); this.#contractClassLogsByBlock = db.openMap('archiver_contract_class_logs_by_block'); this.#logsMaxPageSize = logsMaxPageSize; } - #extractTaggedLogs(block: L2Block, logType: keyof Pick) { + #extractTaggedLogsFromPrivate(block: L2Block) { const taggedLogs = new Map(); const dataStartIndexForBlock = block.header.state.partial.noteHashTree.nextAvailableLeafIndex - block.body.numberOfTxsIncludingPadded * MAX_NOTE_HASHES_PER_TX; - block.body[logType].txLogs.forEach((txLogs, txIndex) => { + block.body.txEffects.forEach((txEffect, txIndex) => { + const txHash = txEffect.txHash; + const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX; + txEffect.privateLogs.forEach(log => { + const tag = log.fields[0]; + const currentLogs = taggedLogs.get(tag.toString()) ?? []; + currentLogs.push( + new TxScopedL2Log( + txHash, + dataStartIndexForTx, + block.number, + /* isFromPublic */ false, + log.toBuffer(), + ).toBuffer(), + ); + taggedLogs.set(tag.toString(), currentLogs); + }); + }); + return taggedLogs; + } + + #extractTaggedLogsFromPublic(block: L2Block) { + const taggedLogs = new Map(); + const dataStartIndexForBlock = + block.header.state.partial.noteHashTree.nextAvailableLeafIndex - + block.body.numberOfTxsIncludingPadded * MAX_NOTE_HASHES_PER_TX; + block.body.unencryptedLogs.txLogs.forEach((txLogs, txIndex) => { const txHash = block.body.txEffects[txIndex].txHash; const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX; const logs = txLogs.unrollLogs(); logs.forEach(log => { - if ( - (logType == 'noteEncryptedLogs' && log.data.length < 32) || + if (log.data.length < 32 * 33) { // TODO remove when #9835 and #9836 are fixed - (logType === 'unencryptedLogs' && log.data.length < 32 * 33) - ) { - this.#log.warn(`Skipping log (${logType}) with invalid data length: ${log.data.length}`); + this.#log.warn(`Skipping unencrypted log with insufficient data length: ${log.data.length}`); return; } try { - let tag = Fr.ZERO; // TODO remove when #9835 and #9836 are fixed. The partial note logs are emitted as bytes, but encoded as Fields. // This means that for every 32 bytes of payload, we only have 1 byte of data. // Also, the tag is not stored in the first 32 bytes of the log, (that's the length of public fields now) but in the next 32. - if (logType === 'unencryptedLogs') { - const correctedBuffer = Buffer.alloc(32); - const initialOffset = 32; - for (let i = 0; i < 32; i++) { - const byte = Fr.fromBuffer( - log.data.subarray(i * 32 + initialOffset, i * 32 + 32 + initialOffset), - ).toNumber(); - correctedBuffer.writeUInt8(byte, i); - } - tag = new Fr(correctedBuffer); - } else { - tag = new Fr(log.data.subarray(0, 32)); + const correctedBuffer = Buffer.alloc(32); + const initialOffset = 32; + for (let i = 0; i < 32; i++) { + const byte = Fr.fromBuffer( + log.data.subarray(i * 32 + initialOffset, i * 32 + 32 + initialOffset), + ).toNumber(); + correctedBuffer.writeUInt8(byte, i); } - this.#log.verbose(`Found tagged (${logType}) log with tag ${tag.toString()} in block ${block.number}`); + const tag = new Fr(correctedBuffer); + + this.#log.verbose(`Found tagged unencrypted log with tag ${tag.toString()} in block ${block.number}`); const currentLogs = taggedLogs.get(tag.toString()) ?? []; currentLogs.push( - new TxScopedL2Log( - txHash, - dataStartIndexForTx, - block.number, - logType === 'unencryptedLogs', - log.data, - ).toBuffer(), + new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, /* isFromPublic */ true, log.data).toBuffer(), ); taggedLogs.set(tag.toString(), currentLogs); } catch (err) { @@ -109,10 +115,7 @@ export class LogStore { */ async addLogs(blocks: L2Block[]): Promise { const taggedLogsToAdd = blocks - .flatMap(block => [ - this.#extractTaggedLogs(block, 'noteEncryptedLogs'), - this.#extractTaggedLogs(block, 'unencryptedLogs'), - ]) + .flatMap(block => [this.#extractTaggedLogsFromPrivate(block), this.#extractTaggedLogsFromPublic(block)]) .reduce((acc, val) => { for (const [tag, logs] of val.entries()) { const currentLogs = acc.get(tag) ?? []; @@ -140,8 +143,13 @@ export class LogStore { tagsInBlock.push(tag); } void this.#logTagsByBlock.set(block.number, tagsInBlock); - void this.#noteEncryptedLogsByBlock.set(block.number, block.body.noteEncryptedLogs.toBuffer()); - void this.#encryptedLogsByBlock.set(block.number, block.body.encryptedLogs.toBuffer()); + + const privateLogsInBlock = block.body.txEffects + .map(txEffect => txEffect.privateLogs) + .flat() + .map(log => log.toBuffer()); + void this.#privateLogsByBlock.set(block.number, Buffer.concat(privateLogsInBlock)); + void this.#unencryptedLogsByBlock.set(block.number, block.body.unencryptedLogs.toBuffer()); void this.#contractClassLogsByBlock.set(block.number, block.body.contractClassLogs.toBuffer()); }); @@ -156,8 +164,7 @@ export class LogStore { }); return this.db.transaction(() => { blocks.forEach(block => { - void this.#noteEncryptedLogsByBlock.delete(block.number); - void this.#encryptedLogsByBlock.delete(block.number); + void this.#privateLogsByBlock.delete(block.number); void this.#unencryptedLogsByBlock.delete(block.number); void this.#logTagsByBlock.delete(block.number); }); @@ -171,43 +178,20 @@ export class LogStore { } /** - * Gets up to `limit` amount of logs starting from `from`. - * @param start - Number of the L2 block to which corresponds the first logs to be returned. - * @param limit - The number of logs to return. - * @param logType - Specifies whether to return encrypted or unencrypted logs. - * @returns The requested logs. + * Retrieves all private logs from up to `limit` blocks, starting from the block number `start`. + * @param start - The block number from which to begin retrieving logs. + * @param limit - The maximum number of blocks to retrieve logs from. + * @returns An array of private logs from the specified range of blocks. */ - *getLogs( - start: number, - limit: number, - logType: TLogType, - ): IterableIterator>> { - const logMap = (() => { - switch (logType) { - case LogType.ENCRYPTED: - return this.#encryptedLogsByBlock; - case LogType.NOTEENCRYPTED: - return this.#noteEncryptedLogsByBlock; - case LogType.UNENCRYPTED: - default: - return this.#unencryptedLogsByBlock; - } - })(); - const logTypeMap = (() => { - switch (logType) { - case LogType.ENCRYPTED: - return EncryptedL2BlockL2Logs; - case LogType.NOTEENCRYPTED: - return EncryptedNoteL2BlockL2Logs; - case LogType.UNENCRYPTED: - default: - return UnencryptedL2BlockL2Logs; + getPrivateLogs(start: number, limit: number) { + const logs = []; + for (const buffer of this.#privateLogsByBlock.values({ start, limit })) { + const reader = new BufferReader(buffer); + while (reader.remainingBytes() > 0) { + logs.push(reader.readObject(PrivateLog)); } - })(); - const L2BlockL2Logs = logTypeMap; - for (const buffer of logMap.values({ start, limit })) { - yield L2BlockL2Logs.fromBuffer(buffer) as L2BlockL2Logs>; } + return logs; } /** @@ -249,7 +233,9 @@ export class LogStore { return { logs: [], maxLogsHit: false }; } - const unencryptedLogsInBlock = this.#getBlockLogs(blockNumber, LogType.UNENCRYPTED); + const buffer = this.#unencryptedLogsByBlock.get(blockNumber) ?? Buffer.alloc(0); + const unencryptedLogsInBlock = UnencryptedL2BlockL2Logs.fromBuffer(buffer); + const txLogs = unencryptedLogsInBlock.txLogs[txIndex].unrollLogs(); const logs: ExtendedUnencryptedL2Log[] = []; @@ -376,40 +362,4 @@ export class LogStore { return maxLogsHit; } - - #getBlockLogs( - blockNumber: number, - logType: TLogType, - ): L2BlockL2Logs> { - const logMap = (() => { - switch (logType) { - case LogType.ENCRYPTED: - return this.#encryptedLogsByBlock; - case LogType.NOTEENCRYPTED: - return this.#noteEncryptedLogsByBlock; - case LogType.UNENCRYPTED: - default: - return this.#unencryptedLogsByBlock; - } - })(); - const logTypeMap = (() => { - switch (logType) { - case LogType.ENCRYPTED: - return EncryptedL2BlockL2Logs; - case LogType.NOTEENCRYPTED: - return EncryptedNoteL2BlockL2Logs; - case LogType.UNENCRYPTED: - default: - return UnencryptedL2BlockL2Logs; - } - })(); - const L2BlockL2Logs = logTypeMap; - const buffer = logMap.get(blockNumber); - - if (!buffer) { - return new L2BlockL2Logs([]) as L2BlockL2Logs>; - } - - return L2BlockL2Logs.fromBuffer(buffer) as L2BlockL2Logs>; - } } diff --git a/yarn-project/archiver/src/archiver/memory_archiver_store/memory_archiver_store.test.ts b/yarn-project/archiver/src/archiver/memory_archiver_store/memory_archiver_store.test.ts index e85608086ed..c74b572761d 100644 --- a/yarn-project/archiver/src/archiver/memory_archiver_store/memory_archiver_store.test.ts +++ b/yarn-project/archiver/src/archiver/memory_archiver_store/memory_archiver_store.test.ts @@ -19,7 +19,7 @@ describe('MemoryArchiverStore', () => { const maxLogs = 5; archiverStore = new MemoryArchiverStore(maxLogs); const blocks = times(10, (index: number) => ({ - data: L2Block.random(index + 1, 4, 2, 3, 2, 2), + data: L2Block.random(index + 1, 4, 3, 2), l1: { blockNumber: BigInt(index), blockHash: `0x${index}`, timestamp: BigInt(index) }, })); diff --git a/yarn-project/archiver/src/archiver/memory_archiver_store/memory_archiver_store.ts b/yarn-project/archiver/src/archiver/memory_archiver_store/memory_archiver_store.ts index df606d16fab..5a0c7085c61 100644 --- a/yarn-project/archiver/src/archiver/memory_archiver_store/memory_archiver_store.ts +++ b/yarn-project/archiver/src/archiver/memory_archiver_store/memory_archiver_store.ts @@ -1,19 +1,13 @@ import { - type Body, type ContractClass2BlockL2Logs, - type EncryptedL2BlockL2Logs, - type EncryptedNoteL2BlockL2Logs, ExtendedUnencryptedL2Log, - type FromLogType, type GetUnencryptedLogsResponse, type InBlock, type InboxLeaf, type L2Block, L2BlockHash, - type L2BlockL2Logs, type LogFilter, LogId, - LogType, type TxEffect, type TxHash, TxReceipt, @@ -31,6 +25,7 @@ import { INITIAL_L2_BLOCK_NUM, MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, + type PrivateLog, type UnconstrainedFunctionWithMembershipProof, } from '@aztec/circuits.js'; import { type ContractArtifact, FunctionSelector } from '@aztec/foundation/abi'; @@ -56,13 +51,11 @@ export class MemoryArchiverStore implements ArchiverDataStore { */ private txEffects: InBlock[] = []; - private noteEncryptedLogsPerBlock: Map = new Map(); - private taggedLogs: Map = new Map(); private logTagsPerBlock: Map = new Map(); - private encryptedLogsPerBlock: Map = new Map(); + private privateLogsPerBlock: Map = new Map(); private unencryptedLogsPerBlock: Map = new Map(); @@ -232,46 +225,61 @@ export class MemoryArchiverStore implements ArchiverDataStore { return Promise.resolve(true); } - #storeTaggedLogs(block: L2Block, logType: keyof Pick): void { + #storeTaggedLogsFromPrivate(block: L2Block): void { + const dataStartIndexForBlock = + block.header.state.partial.noteHashTree.nextAvailableLeafIndex - + block.body.numberOfTxsIncludingPadded * MAX_NOTE_HASHES_PER_TX; + block.body.txEffects.forEach((txEffect, txIndex) => { + const txHash = txEffect.txHash; + const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX; + txEffect.privateLogs.forEach(log => { + const tag = log.fields[0]; + const currentLogs = this.taggedLogs.get(tag.toString()) || []; + this.taggedLogs.set(tag.toString(), [ + ...currentLogs, + new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, /* isFromPublic */ false, log.toBuffer()), + ]); + const currentTagsInBlock = this.logTagsPerBlock.get(block.number) || []; + this.logTagsPerBlock.set(block.number, [...currentTagsInBlock, tag]); + }); + }); + } + + #storeTaggedLogsFromPublic(block: L2Block): void { const dataStartIndexForBlock = block.header.state.partial.noteHashTree.nextAvailableLeafIndex - block.body.numberOfTxsIncludingPadded * MAX_NOTE_HASHES_PER_TX; - block.body[logType].txLogs.forEach((txLogs, txIndex) => { + block.body.unencryptedLogs.txLogs.forEach((txLogs, txIndex) => { const txHash = block.body.txEffects[txIndex].txHash; const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX; const logs = txLogs.unrollLogs(); logs.forEach(log => { if ( - (logType == 'noteEncryptedLogs' && log.data.length < 32) || // TODO remove when #9835 and #9836 are fixed - (logType === 'unencryptedLogs' && log.data.length < 32 * 33) + log.data.length < + 32 * 33 ) { - this.#log.warn(`Skipping log (${logType}) with invalid data length: ${log.data.length}`); + this.#log.warn(`Skipping unencrypted log with invalid data length: ${log.data.length}`); return; } try { - let tag = Fr.ZERO; // TODO remove when #9835 and #9836 are fixed. The partial note logs are emitted as bytes, but encoded as Fields. // This means that for every 32 bytes of payload, we only have 1 byte of data. // Also, the tag is not stored in the first 32 bytes of the log, (that's the length of public fields now) but in the next 32. - if (logType === 'unencryptedLogs') { - const correctedBuffer = Buffer.alloc(32); - const initialOffset = 32; - for (let i = 0; i < 32; i++) { - const byte = Fr.fromBuffer( - log.data.subarray(i * 32 + initialOffset, i * 32 + 32 + initialOffset), - ).toNumber(); - correctedBuffer.writeUInt8(byte, i); - } - tag = new Fr(correctedBuffer); - } else { - tag = new Fr(log.data.subarray(0, 32)); + const correctedBuffer = Buffer.alloc(32); + const initialOffset = 32; + for (let i = 0; i < 32; i++) { + const byte = Fr.fromBuffer( + log.data.subarray(i * 32 + initialOffset, i * 32 + 32 + initialOffset), + ).toNumber(); + correctedBuffer.writeUInt8(byte, i); } - this.#log.verbose(`Storing tagged (${logType}) log with tag ${tag.toString()} in block ${block.number}`); + const tag = new Fr(correctedBuffer); + this.#log.verbose(`Storing unencrypted tagged log with tag ${tag.toString()} in block ${block.number}`); const currentLogs = this.taggedLogs.get(tag.toString()) || []; this.taggedLogs.set(tag.toString(), [ ...currentLogs, - new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, logType === 'unencryptedLogs', log.data), + new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, /* isFromPublic */ true, log.data), ]); const currentTagsInBlock = this.logTagsPerBlock.get(block.number) || []; this.logTagsPerBlock.set(block.number, [...currentTagsInBlock, tag]); @@ -289,10 +297,9 @@ export class MemoryArchiverStore implements ArchiverDataStore { */ addLogs(blocks: L2Block[]): Promise { blocks.forEach(block => { - void this.#storeTaggedLogs(block, 'noteEncryptedLogs'); - void this.#storeTaggedLogs(block, 'unencryptedLogs'); - this.noteEncryptedLogsPerBlock.set(block.number, block.body.noteEncryptedLogs); - this.encryptedLogsPerBlock.set(block.number, block.body.encryptedLogs); + void this.#storeTaggedLogsFromPrivate(block); + void this.#storeTaggedLogsFromPublic(block); + this.privateLogsPerBlock.set(block.number, block.body.txEffects.map(txEffect => txEffect.privateLogs).flat()); this.unencryptedLogsPerBlock.set(block.number, block.body.unencryptedLogs); this.contractClassLogsPerBlock.set(block.number, block.body.contractClassLogs); }); @@ -308,8 +315,7 @@ export class MemoryArchiverStore implements ArchiverDataStore { }); blocks.forEach(block => { - this.encryptedLogsPerBlock.delete(block.number); - this.noteEncryptedLogsPerBlock.delete(block.number); + this.privateLogsPerBlock.delete(block.number); this.unencryptedLogsPerBlock.delete(block.number); this.logTagsPerBlock.delete(block.number); this.contractClassLogsPerBlock.delete(block.number); @@ -471,17 +477,12 @@ export class MemoryArchiverStore implements ArchiverDataStore { } /** - * Gets up to `limit` amount of logs starting from `from`. - * @param from - Number of the L2 block to which corresponds the first logs to be returned. - * @param limit - The number of logs to return. - * @param logType - Specifies whether to return encrypted or unencrypted logs. - * @returns The requested logs. + * Retrieves all private logs from up to `limit` blocks, starting from the block number `from`. + * @param from - The block number from which to begin retrieving logs. + * @param limit - The maximum number of blocks to retrieve logs from. + * @returns An array of private logs from the specified range of blocks. */ - getLogs( - from: number, - limit: number, - logType: TLogType, - ): Promise>[]> { + getPrivateLogs(from: number, limit: number): Promise { if (from < INITIAL_L2_BLOCK_NUM || limit < 1) { return Promise.resolve([]); } @@ -490,34 +491,19 @@ export class MemoryArchiverStore implements ArchiverDataStore { return Promise.resolve([]); } - const logMap = (() => { - switch (logType) { - case LogType.ENCRYPTED: - return this.encryptedLogsPerBlock; - case LogType.NOTEENCRYPTED: - return this.noteEncryptedLogsPerBlock; - case LogType.UNENCRYPTED: - default: - return this.unencryptedLogsPerBlock; - } - })() as Map>>; - const startIndex = from; const endIndex = startIndex + limit; const upper = Math.min(endIndex, this.l2Blocks.length + INITIAL_L2_BLOCK_NUM); - const l = []; + const logsInBlocks = []; for (let i = startIndex; i < upper; i++) { - const log = logMap.get(i); - if (log) { - l.push(log); - } else { - // I hate typescript sometimes - l.push(undefined as unknown as L2BlockL2Logs>); + const logs = this.privateLogsPerBlock.get(i); + if (logs) { + logsInBlocks.push(logs); } } - return Promise.resolve(l); + return Promise.resolve(logsInBlocks.flat()); } /** diff --git a/yarn-project/aztec-node/src/aztec-node/server.test.ts b/yarn-project/aztec-node/src/aztec-node/server.test.ts index 666bd426440..649c9bfe8fe 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.test.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.test.ts @@ -72,7 +72,6 @@ describe('aztec node', () => { p2p, l2BlockSource, l2LogsSource, - l2LogsSource, contractSource, l1ToL2MessageSource, nullifierWithBlockSource, diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index a2c686cdd6c..57f576c55d3 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -4,17 +4,14 @@ import { type AztecNode, type ClientProtocolCircuitVerifier, type EpochProofQuote, - type FromLogType, type GetUnencryptedLogsResponse, type InBlock, type L1ToL2MessageSource, type L2Block, - type L2BlockL2Logs, type L2BlockNumber, type L2BlockSource, type L2LogsSource, type LogFilter, - LogType, MerkleTreeId, NullifierMembershipWitness, type NullifierWithBlockSource, @@ -50,6 +47,7 @@ import { type NULLIFIER_TREE_HEIGHT, type NullifierLeafPreimage, type PUBLIC_DATA_TREE_HEIGHT, + type PrivateLog, type ProtocolContractAddresses, type PublicDataTreeLeafPreimage, } from '@aztec/circuits.js'; @@ -95,8 +93,7 @@ export class AztecNodeService implements AztecNode { protected config: AztecNodeConfig, protected readonly p2pClient: P2P, protected readonly blockSource: L2BlockSource & Partial, - protected readonly encryptedLogsSource: L2LogsSource, - protected readonly unencryptedLogsSource: L2LogsSource, + protected readonly logsSource: L2LogsSource, protected readonly contractDataSource: ContractDataSource, protected readonly l1ToL2MessageSource: L1ToL2MessageSource, protected readonly nullifierSource: NullifierWithBlockSource, @@ -197,7 +194,6 @@ export class AztecNodeService implements AztecNode { archiver, archiver, archiver, - archiver, worldStateSynchronizer, sequencer, ethereumChain.chainInfo.id, @@ -313,19 +309,13 @@ export class AztecNodeService implements AztecNode { } /** - * Gets up to `limit` amount of logs starting from `from`. - * @param from - Number of the L2 block to which corresponds the first logs to be returned. - * @param limit - The maximum number of logs to return. - * @param logType - Specifies whether to return encrypted or unencrypted logs. - * @returns The requested logs. + * Retrieves all private logs from up to `limit` blocks, starting from the block number `from`. + * @param from - The block number from which to begin retrieving logs. + * @param limit - The maximum number of blocks to retrieve logs from. + * @returns An array of private logs from the specified range of blocks. */ - public getLogs( - from: number, - limit: number, - logType: LogType, - ): Promise>[]> { - const logSource = logType === LogType.ENCRYPTED ? this.encryptedLogsSource : this.unencryptedLogsSource; - return logSource.getLogs(from, limit, logType) as Promise>[]>; + public getPrivateLogs(from: number, limit: number): Promise { + return this.logsSource.getPrivateLogs(from, limit); } /** @@ -335,7 +325,7 @@ export class AztecNodeService implements AztecNode { * that tag. */ public getLogsByTags(tags: Fr[]): Promise { - return this.encryptedLogsSource.getLogsByTags(tags); + return this.logsSource.getLogsByTags(tags); } /** @@ -344,7 +334,7 @@ export class AztecNodeService implements AztecNode { * @returns The requested logs. */ getUnencryptedLogs(filter: LogFilter): Promise { - return this.unencryptedLogsSource.getUnencryptedLogs(filter); + return this.logsSource.getUnencryptedLogs(filter); } /** @@ -353,7 +343,7 @@ export class AztecNodeService implements AztecNode { * @returns The requested logs. */ getContractClassLogs(filter: LogFilter): Promise { - return this.unencryptedLogsSource.getContractClassLogs(filter); + return this.logsSource.getContractClassLogs(filter); } /** diff --git a/yarn-project/aztec.js/src/contract/proven_tx.ts b/yarn-project/aztec.js/src/contract/proven_tx.ts index a02eb0c28d3..bb22cc14ddb 100644 --- a/yarn-project/aztec.js/src/contract/proven_tx.ts +++ b/yarn-project/aztec.js/src/contract/proven_tx.ts @@ -11,8 +11,6 @@ export class ProvenTx extends Tx { super( tx.data, tx.clientIvcProof, - tx.noteEncryptedLogs, - tx.encryptedLogs, tx.unencryptedLogs, tx.contractClassLogs, tx.enqueuedPublicFunctionCalls, @@ -25,8 +23,6 @@ export class ProvenTx extends Tx { return new Tx( this.data, this.clientIvcProof, - this.noteEncryptedLogs, - this.encryptedLogs, this.unencryptedLogs, this.contractClassLogs, this.enqueuedPublicFunctionCalls, diff --git a/yarn-project/aztec.js/src/index.ts b/yarn-project/aztec.js/src/index.ts index 5adffcba01f..ca6f1011172 100644 --- a/yarn-project/aztec.js/src/index.ts +++ b/yarn-project/aztec.js/src/index.ts @@ -112,9 +112,7 @@ export { Comparator, CompleteAddress, ContractClass2BlockL2Logs, - EncryptedL2BlockL2Logs, EncryptedLogPayload, - EncryptedNoteL2BlockL2Logs, EpochProofQuote, EpochProofQuotePayload, EventMetadata, @@ -127,9 +125,7 @@ export { L1ToL2Message, L2Actor, L2Block, - L2BlockL2Logs, LogId, - LogType, MerkleTreeId, Note, PackedValues, diff --git a/yarn-project/circuit-types/src/body.ts b/yarn-project/circuit-types/src/body.ts index 7c5d131a5c8..d11e7e6dedc 100644 --- a/yarn-project/circuit-types/src/body.ts +++ b/yarn-project/circuit-types/src/body.ts @@ -5,12 +5,7 @@ import { computeUnbalancedMerkleRoot } from '@aztec/foundation/trees'; import { inspect } from 'util'; import { z } from 'zod'; -import { - ContractClass2BlockL2Logs, - EncryptedL2BlockL2Logs, - EncryptedNoteL2BlockL2Logs, - UnencryptedL2BlockL2Logs, -} from './logs/index.js'; +import { ContractClass2BlockL2Logs, UnencryptedL2BlockL2Logs } from './logs/index.js'; import { TxEffect } from './tx_effect.js'; export class Body { @@ -68,18 +63,6 @@ export class Body { return computeUnbalancedMerkleRoot(leaves, emptyTxEffectHash); } - get noteEncryptedLogs(): EncryptedNoteL2BlockL2Logs { - const logs = this.txEffects.map(txEffect => txEffect.noteEncryptedLogs); - - return new EncryptedNoteL2BlockL2Logs(logs); - } - - get encryptedLogs(): EncryptedL2BlockL2Logs { - const logs = this.txEffects.map(txEffect => txEffect.encryptedLogs); - - return new EncryptedL2BlockL2Logs(logs); - } - get unencryptedLogs(): UnencryptedL2BlockL2Logs { const logs = this.txEffects.map(txEffect => txEffect.unencryptedLogs); @@ -107,15 +90,9 @@ export class Body { return numTxEffects; } - static random( - txsPerBlock = 4, - numPrivateCallsPerTx = 2, - numPublicCallsPerTx = 3, - numEncryptedLogsPerCall = 2, - numUnencryptedLogsPerCall = 1, - ) { + static random(txsPerBlock = 4, numPublicCallsPerTx = 3, numUnencryptedLogsPerCall = 1) { const txEffects = [...new Array(txsPerBlock)].map(_ => - TxEffect.random(numPrivateCallsPerTx, numPublicCallsPerTx, numEncryptedLogsPerCall, numUnencryptedLogsPerCall), + TxEffect.random(numPublicCallsPerTx, numUnencryptedLogsPerCall), ); return new Body(txEffects); diff --git a/yarn-project/circuit-types/src/interfaces/archiver.test.ts b/yarn-project/circuit-types/src/interfaces/archiver.test.ts index 2925ae36d08..c97893fc897 100644 --- a/yarn-project/circuit-types/src/interfaces/archiver.test.ts +++ b/yarn-project/circuit-types/src/interfaces/archiver.test.ts @@ -6,6 +6,7 @@ import { Fr, FunctionSelector, Header, + PrivateLog, type PublicFunction, PublicKeys, computePublicBytecodeCommitment, @@ -26,14 +27,7 @@ import { L2Block } from '../l2_block.js'; import { type L2Tips } from '../l2_block_source.js'; import { ExtendedUnencryptedL2Log } from '../logs/extended_unencrypted_l2_log.js'; import { type GetUnencryptedLogsResponse, TxScopedL2Log } from '../logs/get_logs_response.js'; -import { - EncryptedL2BlockL2Logs, - EncryptedNoteL2BlockL2Logs, - type L2BlockL2Logs, - UnencryptedL2BlockL2Logs, -} from '../logs/l2_block_l2_logs.js'; import { type LogFilter } from '../logs/log_filter.js'; -import { type FromLogType, LogType } from '../logs/log_type.js'; import { TxHash } from '../tx/tx_hash.js'; import { TxReceipt } from '../tx/tx_receipt.js'; import { TxEffect } from '../tx_effect.js'; @@ -157,19 +151,9 @@ describe('ArchiverApiSchema', () => { ]); }); - it('getLogs(Encrypted)', async () => { - const result = await context.client.getLogs(1, 1, LogType.ENCRYPTED); - expect(result).toEqual([expect.any(EncryptedL2BlockL2Logs)]); - }); - - it('getLogs(NoteEncrypted)', async () => { - const result = await context.client.getLogs(1, 1, LogType.NOTEENCRYPTED); - expect(result).toEqual([expect.any(EncryptedNoteL2BlockL2Logs)]); - }); - - it('getLogs(Unencrypted)', async () => { - const result = await context.client.getLogs(1, 1, LogType.UNENCRYPTED); - expect(result).toEqual([expect.any(UnencryptedL2BlockL2Logs)]); + it('getPrivateLogs', async () => { + const result = await context.client.getPrivateLogs(1, 1); + expect(result).toEqual([expect.any(PrivateLog)]); }); it('getLogsByTags', async () => { @@ -335,21 +319,8 @@ class MockArchiver implements ArchiverApi { expect(nullifiers[1]).toBeInstanceOf(Fr); return Promise.resolve([randomInBlock(Fr.random().toBigInt()), undefined]); } - getLogs( - _from: number, - _limit: number, - logType: TLogType, - ): Promise>[]> { - switch (logType) { - case LogType.ENCRYPTED: - return Promise.resolve([EncryptedL2BlockL2Logs.random(1, 1, 1)] as L2BlockL2Logs>[]); - case LogType.NOTEENCRYPTED: - return Promise.resolve([EncryptedNoteL2BlockL2Logs.random(1, 1, 1)] as L2BlockL2Logs>[]); - case LogType.UNENCRYPTED: - return Promise.resolve([UnencryptedL2BlockL2Logs.random(1, 1, 1)] as L2BlockL2Logs>[]); - default: - throw new Error(`Unexpected log type: ${logType}`); - } + getPrivateLogs(_from: number, _limit: number): Promise { + return Promise.resolve([PrivateLog.random()]); } getLogsByTags(tags: Fr[]): Promise { expect(tags[0]).toBeInstanceOf(Fr); diff --git a/yarn-project/circuit-types/src/interfaces/archiver.ts b/yarn-project/circuit-types/src/interfaces/archiver.ts index cfdaafdae74..b032efc6174 100644 --- a/yarn-project/circuit-types/src/interfaces/archiver.ts +++ b/yarn-project/circuit-types/src/interfaces/archiver.ts @@ -3,6 +3,7 @@ import { type ContractDataSource, ContractInstanceWithAddressSchema, Header, + PrivateLog, PublicFunctionSchema, } from '@aztec/circuits.js'; import { ContractArtifactSchema } from '@aztec/foundation/abi'; @@ -14,10 +15,8 @@ import { inBlockSchemaFor } from '../in_block.js'; import { L2Block } from '../l2_block.js'; import { type L2BlockSource, L2TipsSchema } from '../l2_block_source.js'; import { GetUnencryptedLogsResponseSchema, TxScopedL2Log } from '../logs/get_logs_response.js'; -import { L2BlockL2Logs } from '../logs/l2_block_l2_logs.js'; import { type L2LogsSource } from '../logs/l2_logs_source.js'; import { LogFilterSchema } from '../logs/log_filter.js'; -import { LogType } from '../logs/log_type.js'; import { type L1ToL2MessageSource } from '../messaging/l1_to_l2_message_source.js'; import { type NullifierWithBlockSource } from '../nullifier_with_block_source.js'; import { TxHash } from '../tx/tx_hash.js'; @@ -51,10 +50,7 @@ export const ArchiverApiSchema: ApiSchemaFor = { getBlocksForEpoch: z.function().args(schemas.BigInt).returns(z.array(L2Block.schema)), isEpochComplete: z.function().args(schemas.BigInt).returns(z.boolean()), getL2Tips: z.function().args().returns(L2TipsSchema), - getLogs: z - .function() - .args(schemas.Integer, schemas.Integer, z.nativeEnum(LogType)) - .returns(z.array(L2BlockL2Logs.schema)), + getPrivateLogs: z.function().args(z.number(), z.number()).returns(z.array(PrivateLog.schema)), getLogsByTags: z .function() .args(z.array(schemas.Fr)) diff --git a/yarn-project/circuit-types/src/interfaces/aztec-node.test.ts b/yarn-project/circuit-types/src/interfaces/aztec-node.test.ts index ddb1aa3ba77..4e3f9bd4a8d 100644 --- a/yarn-project/circuit-types/src/interfaces/aztec-node.test.ts +++ b/yarn-project/circuit-types/src/interfaces/aztec-node.test.ts @@ -11,6 +11,7 @@ import { NOTE_HASH_TREE_HEIGHT, NULLIFIER_TREE_HEIGHT, PUBLIC_DATA_TREE_HEIGHT, + PrivateLog, type ProtocolContractAddresses, ProtocolContractsNames, PublicKeys, @@ -34,14 +35,7 @@ import { L2Block } from '../l2_block.js'; import { type L2Tips } from '../l2_block_source.js'; import { ExtendedUnencryptedL2Log } from '../logs/extended_unencrypted_l2_log.js'; import { type GetUnencryptedLogsResponse, TxScopedL2Log } from '../logs/get_logs_response.js'; -import { - EncryptedL2BlockL2Logs, - EncryptedNoteL2BlockL2Logs, - type L2BlockL2Logs, - UnencryptedL2BlockL2Logs, -} from '../logs/l2_block_l2_logs.js'; import { type LogFilter } from '../logs/log_filter.js'; -import { type FromLogType, LogType } from '../logs/log_type.js'; import { MerkleTreeId } from '../merkle_tree_id.js'; import { EpochProofQuote } from '../prover_coordination/epoch_proof_quote.js'; import { PublicDataWitness } from '../public_data_witness.js'; @@ -215,19 +209,9 @@ describe('AztecNodeApiSchema', () => { await context.client.addContractArtifact(AztecAddress.random(), artifact); }, 20_000); - it('getLogs(Encrypted)', async () => { - const response = await context.client.getLogs(1, 1, LogType.ENCRYPTED); - expect(response).toEqual([expect.any(EncryptedL2BlockL2Logs)]); - }); - - it('getLogs(NoteEncrypted)', async () => { - const response = await context.client.getLogs(1, 1, LogType.NOTEENCRYPTED); - expect(response).toEqual([expect.any(EncryptedNoteL2BlockL2Logs)]); - }); - - it('getLogs(Unencrypted)', async () => { - const response = await context.client.getLogs(1, 1, LogType.UNENCRYPTED); - expect(response).toEqual([expect.any(UnencryptedL2BlockL2Logs)]); + it('getPrivateLogs', async () => { + const response = await context.client.getPrivateLogs(1, 1); + expect(response).toEqual([expect.any(PrivateLog)]); }); it('getUnencryptedLogs', async () => { @@ -484,21 +468,8 @@ class MockAztecNode implements AztecNode { deepStrictEqual(artifact, this.artifact); return Promise.resolve(); } - getLogs( - _from: number, - _limit: number, - logType: TLogType, - ): Promise>[]> { - switch (logType) { - case LogType.ENCRYPTED: - return Promise.resolve([EncryptedL2BlockL2Logs.random(1, 1, 1)] as L2BlockL2Logs>[]); - case LogType.NOTEENCRYPTED: - return Promise.resolve([EncryptedNoteL2BlockL2Logs.random(1, 1, 1)] as L2BlockL2Logs>[]); - case LogType.UNENCRYPTED: - return Promise.resolve([UnencryptedL2BlockL2Logs.random(1, 1, 1)] as L2BlockL2Logs>[]); - default: - throw new Error(`Unexpected log type: ${logType}`); - } + getPrivateLogs(_from: number, _limit: number): Promise { + return Promise.resolve([PrivateLog.random()]); } getUnencryptedLogs(filter: LogFilter): Promise { expect(filter.contractAddress).toBeInstanceOf(AztecAddress); diff --git a/yarn-project/circuit-types/src/interfaces/aztec-node.ts b/yarn-project/circuit-types/src/interfaces/aztec-node.ts index 34f9383c83c..8e5b2bda55f 100644 --- a/yarn-project/circuit-types/src/interfaces/aztec-node.ts +++ b/yarn-project/circuit-types/src/interfaces/aztec-node.ts @@ -10,6 +10,7 @@ import { NOTE_HASH_TREE_HEIGHT, NULLIFIER_TREE_HEIGHT, PUBLIC_DATA_TREE_HEIGHT, + PrivateLog, type ProtocolContractAddresses, ProtocolContractAddressesSchema, } from '@aztec/circuits.js'; @@ -26,13 +27,10 @@ import { type InBlock, inBlockSchemaFor } from '../in_block.js'; import { L2Block } from '../l2_block.js'; import { type L2BlockSource, type L2Tips, L2TipsSchema } from '../l2_block_source.js'; import { - type FromLogType, type GetUnencryptedLogsResponse, GetUnencryptedLogsResponseSchema, - L2BlockL2Logs, type LogFilter, LogFilterSchema, - LogType, TxScopedL2Log, } from '../logs/index.js'; import { MerkleTreeId } from '../merkle_tree_id.js'; @@ -270,17 +268,12 @@ export interface AztecNode addContractArtifact(address: AztecAddress, artifact: ContractArtifact): Promise; /** - * Gets up to `limit` amount of logs starting from `from`. - * @param from - Number of the L2 block to which corresponds the first logs to be returned. - * @param limit - The maximum number of logs to return. - * @param logType - Specifies whether to return encrypted or unencrypted logs. - * @returns The requested logs. + * Retrieves all private logs from up to `limit` blocks, starting from the block number `from`. + * @param from - The block number from which to begin retrieving logs. + * @param limit - The maximum number of blocks to retrieve logs from. + * @returns An array of private logs from the specified range of blocks. */ - getLogs( - from: number, - limit: number, - logType: TLogType, - ): Promise>[]>; + getPrivateLogs(from: number, limit: number): Promise; /** * Gets unencrypted logs based on the provided filter. @@ -513,7 +506,7 @@ export const AztecNodeApiSchema: ApiSchemaFor = { addContractArtifact: z.function().args(schemas.AztecAddress, ContractArtifactSchema).returns(z.void()), - getLogs: z.function().args(z.number(), z.number(), z.nativeEnum(LogType)).returns(z.array(L2BlockL2Logs.schema)), + getPrivateLogs: z.function().args(z.number(), z.number()).returns(z.array(PrivateLog.schema)), getUnencryptedLogs: z.function().args(LogFilterSchema).returns(GetUnencryptedLogsResponseSchema), diff --git a/yarn-project/circuit-types/src/l2_block.test.ts b/yarn-project/circuit-types/src/l2_block.test.ts index 0b8bace401b..848bed33fd7 100644 --- a/yarn-project/circuit-types/src/l2_block.test.ts +++ b/yarn-project/circuit-types/src/l2_block.test.ts @@ -1,5 +1,4 @@ import { L2Block } from './l2_block.js'; -import { EncryptedTxL2Logs } from './logs/index.js'; describe('L2Block', () => { it('can serialize an L2 block with logs to a buffer and back', () => { @@ -10,62 +9,4 @@ describe('L2Block', () => { expect(recovered).toEqual(block); }); - - // TS equivalent of `testComputeKernelLogsIterationWithoutLogs` in `Decoder.t.sol` - it('correctly computes kernel logs hash when there are no logs', () => { - // The following 2 values are copied from `testComputeKernelLogsIterationWithoutLogs` in `Decoder.t.sol` - const encodedLogs = Buffer.from('0000000400000000', 'hex'); - const logs = EncryptedTxL2Logs.fromBuffer(encodedLogs, true); - const referenceLogsHash = Buffer.alloc(32); - - const logsHash = logs.hash(); - expect(logsHash).toEqual(referenceLogsHash); - }); - - // TS equivalent of `testComputeKernelLogs1Iteration` in `Decoder.t.sol` - it('correctly computes kernel logs hash when are logs from 1 iteration', () => { - // The following 2 values are copied from `testComputeKernelLogs1Iteration` in `Decoder.t.sol` - // maskedAddress = '1100000000000000000000000000000000000000000000000000000000000000' - const encodedLogs = Buffer.from( - '0000002c0000002800000024110000000000000000000000000000000000000000000000000000000000000093e78a70', - 'hex', - ); - const logs = EncryptedTxL2Logs.fromBuffer(encodedLogs, true); - const referenceLogsHash = Buffer.from('00f7bf1d4b3b5c99b8e370989e306b0eb712ca30bba1ce18a651cef3994e6610', 'hex'); - - const logsHash = logs.hash(); - expect(logsHash).toEqual(referenceLogsHash); - }); - - // TS equivalent of `testComputeKernelLogs2Iterations` in `Decoder.t.sol` - it('correctly computes kernel logs hash when are logs from 2 iterations', () => { - // The following 2 values are copied from `testComputeKernelLogs2Iterations` in `Decoder.t.sol` - // maskedAddress1 = '1100000000000000000000000000000000000000000000000000000000000000' - // maskedAddress2 = '1200000000000000000000000000000000000000000000000000000000000000' - const encodedLogs = Buffer.from( - '000000640000002800000024110000000000000000000000000000000000000000000000000000000000000093e78a700000003400000030120000000000000000000000000000000000000000000000000000000000000006a86173c86c6d3f108eefc36e7fb014', - 'hex', - ); - const logs = EncryptedTxL2Logs.fromBuffer(encodedLogs, true); - const referenceLogsHash = Buffer.from('0021b8f5c71dbf2f102772c132c59f9f27b55405a22340f9e021ce11164636a2', 'hex'); - - const logsHash = logs.hash(); - expect(logsHash).toEqual(referenceLogsHash); - }); - - // TS equivalent of `testComputeKernelLogsMiddleIterationWithoutLogs` in `Decoder.t.sol` - it('correctly computes kernel logs hash when are logs from 3 iterations (2nd iter. without logs)', () => { - // The following 2 values are copied from `testComputeKernelLogsMiddleIterationWithoutLogs` in `Decoder.t.sol` - // Note: as of resolving #5017, we skip zero len logs, so we expect this and the prev hash to be the same - const encodedLogs = Buffer.from( - '000000680000002800000024110000000000000000000000000000000000000000000000000000000000000093e78a70000000000000003400000030120000000000000000000000000000000000000000000000000000000000000006a86173c86c6d3f108eefc36e7fb014', - 'hex', - ); - const logs = EncryptedTxL2Logs.fromBuffer(encodedLogs, true); - - const referenceLogsHash = Buffer.from('0021b8f5c71dbf2f102772c132c59f9f27b55405a22340f9e021ce11164636a2', 'hex'); - - const logsHash = logs.hash(); - expect(logsHash).toEqual(referenceLogsHash); - }); }); diff --git a/yarn-project/circuit-types/src/l2_block.ts b/yarn-project/circuit-types/src/l2_block.ts index 169ff874fd6..09d73fe4dd2 100644 --- a/yarn-project/circuit-types/src/l2_block.ts +++ b/yarn-project/circuit-types/src/l2_block.ts @@ -74,9 +74,7 @@ export class L2Block { * Creates an L2 block containing random data. * @param l2BlockNum - The number of the L2 block. * @param txsPerBlock - The number of transactions to include in the block. - * @param numPrivateCallsPerTx - The number of private function calls to include in each transaction. * @param numPublicCallsPerTx - The number of public function calls to include in each transaction. - * @param numEncryptedLogsPerCall - The number of encrypted logs per 1 private function invocation. * @param numUnencryptedLogsPerCall - The number of unencrypted logs per 1 public function invocation. * @param inHash - The hash of the L1 to L2 messages subtree which got inserted in this block. * @returns The L2 block. @@ -84,20 +82,12 @@ export class L2Block { static random( l2BlockNum: number, txsPerBlock = 4, - numPrivateCallsPerTx = 2, numPublicCallsPerTx = 3, - numEncryptedLogsPerCall = 2, numUnencryptedLogsPerCall = 1, inHash: Buffer | undefined = undefined, slotNumber: number | undefined = undefined, ): L2Block { - const body = Body.random( - txsPerBlock, - numPrivateCallsPerTx, - numPublicCallsPerTx, - numEncryptedLogsPerCall, - numUnencryptedLogsPerCall, - ); + const body = Body.random(txsPerBlock, numPublicCallsPerTx, numUnencryptedLogsPerCall); const txsEffectsHash = body.getTxsEffectsHash(); @@ -193,22 +183,6 @@ export class L2Block { */ getStats() { const logsStats = { - noteEncryptedLogLength: this.body.txEffects.reduce( - (logCount, txEffect) => logCount + txEffect.noteEncryptedLogs.getSerializedLength(), - 0, - ), - noteEncryptedLogCount: this.body.txEffects.reduce( - (logCount, txEffect) => logCount + txEffect.noteEncryptedLogs.getTotalLogCount(), - 0, - ), - encryptedLogLength: this.body.txEffects.reduce( - (logCount, txEffect) => logCount + txEffect.encryptedLogs.getSerializedLength(), - 0, - ), - encryptedLogCount: this.body.txEffects.reduce( - (logCount, txEffect) => logCount + txEffect.encryptedLogs.getTotalLogCount(), - 0, - ), unencryptedLogCount: this.body.txEffects.reduce( (logCount, txEffect) => logCount + txEffect.unencryptedLogs.getTotalLogCount(), 0, diff --git a/yarn-project/circuit-types/src/logs/encrypted_l2_log.ts b/yarn-project/circuit-types/src/logs/encrypted_l2_log.ts deleted file mode 100644 index da67376b042..00000000000 --- a/yarn-project/circuit-types/src/logs/encrypted_l2_log.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { Fr, Point } from '@aztec/circuits.js'; -import { randomBytes, sha256Trunc } from '@aztec/foundation/crypto'; -import { schemas } from '@aztec/foundation/schemas'; - -import { z } from 'zod'; - -/** - * Represents an individual encrypted event log entry. - */ -export class EncryptedL2Log { - constructor(public readonly data: Buffer, public readonly maskedContractAddress: Fr) {} - - // We do not 'count' the maskedContractAddress in .length, as this method is called to calculate ciphertext length - get length(): number { - return this.data.length; - } - - /** - * Serializes log to a buffer. - * @returns A buffer containing the serialized log. - */ - public toBuffer(): Buffer { - return Buffer.concat([this.maskedContractAddress.toBuffer(), this.data]); - } - - static get schema() { - return z - .object({ data: schemas.Buffer, maskedContractAddress: schemas.Fr }) - .transform(({ data, maskedContractAddress }) => new EncryptedL2Log(data, maskedContractAddress)); - } - - /** - * Deserializes log from a buffer. - * @param buffer - The buffer containing the log. - * @returns Deserialized instance of `Log`. - */ - public static fromBuffer(data: Buffer): EncryptedL2Log { - return new EncryptedL2Log(data.subarray(32), new Fr(data.subarray(0, 32))); - } - - /** - * Calculates hash of serialized logs. - * @returns Buffer containing 248 bits of information of sha256 hash. - */ - public hash(): Buffer { - return sha256Trunc(this.data); - } - - /** - * Calculates siloed hash of serialized encryptedlogs. - * @returns Buffer containing 248 bits of information of sha256 hash. - */ - public getSiloedHash(): Buffer { - const hash = this.hash(); - return sha256Trunc(Buffer.concat([this.maskedContractAddress.toBuffer(), hash])); - } - - /** - * Crates a random log. - * @returns A random log. - */ - public static random(): EncryptedL2Log { - const randomEphPubKey = Point.random(); - const randomLogContent = randomBytes(144 - Point.COMPRESSED_SIZE_IN_BYTES); - const data = Buffer.concat([Fr.random().toBuffer(), randomLogContent, randomEphPubKey.toCompressedBuffer()]); - return new EncryptedL2Log(data, Fr.random()); - } -} diff --git a/yarn-project/circuit-types/src/logs/encrypted_l2_note_log.ts b/yarn-project/circuit-types/src/logs/encrypted_l2_note_log.ts deleted file mode 100644 index 62d4d7ff62d..00000000000 --- a/yarn-project/circuit-types/src/logs/encrypted_l2_note_log.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { Fr, Point } from '@aztec/circuits.js'; -import { randomBytes, sha256Trunc } from '@aztec/foundation/crypto'; -import { schemas } from '@aztec/foundation/schemas'; - -import { z } from 'zod'; - -/** - * Represents an individual encrypted log entry. - */ -export class EncryptedL2NoteLog { - constructor( - /** The encrypted data contents of the log. */ - public readonly data: Buffer, - ) {} - - get length(): number { - return this.data.length; - } - - /** - * Serializes log to a buffer. - * @returns A buffer containing the serialized log. - */ - public toBuffer(): Buffer { - return this.data; - } - - static get schema() { - return z.object({ data: schemas.Buffer }).transform(({ data }) => new EncryptedL2NoteLog(data)); - } - - /** - * Deserializes log from a buffer. - * @param buffer - The buffer containing the log. - * @returns Deserialized instance of `Log`. - */ - public static fromBuffer(data: Buffer): EncryptedL2NoteLog { - return new EncryptedL2NoteLog(data); - } - - /** - * Calculates hash of serialized logs. - * @returns Buffer containing 248 bits of information of sha256 hash. - */ - public hash(): Buffer { - const preimage = this.toBuffer(); - return sha256Trunc(preimage); - } - - public getSiloedHash(): Buffer { - return this.hash(); - } - - /** - * Crates a random log. - * @returns A random log. - */ - public static random(tag: Fr = Fr.random()): EncryptedL2NoteLog { - const randomEphPubKey = Point.random(); - const randomLogContent = randomBytes(144 - Point.COMPRESSED_SIZE_IN_BYTES); - const data = Buffer.concat([tag.toBuffer(), randomLogContent, randomEphPubKey.toCompressedBuffer()]); - return new EncryptedL2NoteLog(data); - } - - public static empty() { - return new EncryptedL2NoteLog(Buffer.alloc(0)); - } -} diff --git a/yarn-project/circuit-types/src/logs/function_l2_logs.test.ts b/yarn-project/circuit-types/src/logs/function_l2_logs.test.ts index d0f49d57c7c..a4039913e9b 100644 --- a/yarn-project/circuit-types/src/logs/function_l2_logs.test.ts +++ b/yarn-project/circuit-types/src/logs/function_l2_logs.test.ts @@ -1,13 +1,8 @@ import { jsonStringify } from '@aztec/foundation/json-rpc'; -import { EncryptedFunctionL2Logs, EncryptedNoteFunctionL2Logs, UnencryptedFunctionL2Logs } from './function_l2_logs.js'; - -function shouldBehaveLikeFunctionL2Logs( - FunctionL2Logs: - | typeof UnencryptedFunctionL2Logs - | typeof EncryptedNoteFunctionL2Logs - | typeof EncryptedFunctionL2Logs, -) { +import { UnencryptedFunctionL2Logs } from './function_l2_logs.js'; + +function shouldBehaveLikeFunctionL2Logs(FunctionL2Logs: typeof UnencryptedFunctionL2Logs) { describe(FunctionL2Logs.name, () => { it('can encode L2Logs to buffer and back', () => { const l2Logs = FunctionL2Logs.random(3); @@ -51,6 +46,4 @@ function shouldBehaveLikeFunctionL2Logs( }); } -shouldBehaveLikeFunctionL2Logs(EncryptedNoteFunctionL2Logs); shouldBehaveLikeFunctionL2Logs(UnencryptedFunctionL2Logs); -shouldBehaveLikeFunctionL2Logs(EncryptedFunctionL2Logs); diff --git a/yarn-project/circuit-types/src/logs/function_l2_logs.ts b/yarn-project/circuit-types/src/logs/function_l2_logs.ts index 2171fb2c17e..668661924cd 100644 --- a/yarn-project/circuit-types/src/logs/function_l2_logs.ts +++ b/yarn-project/circuit-types/src/logs/function_l2_logs.ts @@ -1,25 +1,18 @@ -import { - MAX_ENCRYPTED_LOGS_PER_CALL, - MAX_NOTE_ENCRYPTED_LOGS_PER_CALL, - MAX_UNENCRYPTED_LOGS_PER_CALL, -} from '@aztec/circuits.js'; +import { MAX_UNENCRYPTED_LOGS_PER_CALL } from '@aztec/circuits.js'; import { sha256Trunc } from '@aztec/foundation/crypto'; -import { type ZodFor } from '@aztec/foundation/schemas'; import { BufferReader, prefixBufferWithLength } from '@aztec/foundation/serialize'; import { z } from 'zod'; -import { EncryptedL2Log } from './encrypted_l2_log.js'; -import { EncryptedL2NoteLog } from './encrypted_l2_note_log.js'; import { UnencryptedL2Log } from './unencrypted_l2_log.js'; /** * Data container of logs emitted in 1 function invocation (corresponds to 1 kernel iteration). */ -export abstract class FunctionL2Logs { +export class UnencryptedFunctionL2Logs { constructor( /** An array of logs. */ - public readonly logs: TLog[], + public readonly logs: UnencryptedL2Log[], ) {} /** @@ -62,105 +55,7 @@ export abstract class FunctionL2Logs l.hash())); return sha256Trunc(preimage); } -} - -export class EncryptedNoteFunctionL2Logs extends FunctionL2Logs { - static get schema() { - return z - .object({ logs: z.array(EncryptedL2NoteLog.schema) }) - .transform(({ logs }) => new EncryptedNoteFunctionL2Logs(logs)); - } - - /** - * Creates an empty L2Logs object with no logs. - * @returns A new FunctionL2Logs object with no logs. - */ - public static empty(): EncryptedNoteFunctionL2Logs { - return new EncryptedNoteFunctionL2Logs([]); - } - - /** - * Deserializes logs from a buffer. - * @param buf - The buffer containing the serialized logs. - * @param isLengthPrefixed - Whether the buffer is prefixed with 4 bytes for its total length. - * @returns Deserialized instance of `FunctionL2Logs`. - */ - public static fromBuffer(buf: Buffer, isLengthPrefixed = true): EncryptedNoteFunctionL2Logs { - const reader = new BufferReader(buf, 0); - - // If the buffer is length prefixed use the length to read the array. Otherwise, the entire buffer is consumed. - const logsBufLength = isLengthPrefixed ? reader.readNumber() : -1; - const logs = reader.readBufferArray(logsBufLength); - - return new EncryptedNoteFunctionL2Logs(logs.map(EncryptedL2NoteLog.fromBuffer)); - } - - /** - * Creates a new L2Logs object with `numLogs` logs. - * @param numLogs - The number of logs to create. - * @returns A new EncryptedNoteFunctionL2Logs object. - */ - public static random(numLogs: number): EncryptedNoteFunctionL2Logs { - if (numLogs > MAX_NOTE_ENCRYPTED_LOGS_PER_CALL) { - throw new Error(`Trying to create ${numLogs} logs for one call (max: ${MAX_NOTE_ENCRYPTED_LOGS_PER_CALL})`); - } - const logs: EncryptedL2NoteLog[] = []; - for (let i = 0; i < numLogs; i++) { - logs.push(EncryptedL2NoteLog.random()); - } - return new EncryptedNoteFunctionL2Logs(logs); - } -} - -export class EncryptedFunctionL2Logs extends FunctionL2Logs { - static get schema(): ZodFor { - return z - .object({ logs: z.array(EncryptedL2Log.schema) }) - .transform(({ logs }) => new EncryptedFunctionL2Logs(logs)); - } - - /** - * Creates an empty L2Logs object with no logs. - * @returns A new FunctionL2Logs object with no logs. - */ - public static empty(): EncryptedFunctionL2Logs { - return new EncryptedFunctionL2Logs([]); - } - - /** - * Deserializes logs from a buffer. - * @param buf - The buffer containing the serialized logs. - * @param isLengthPrefixed - Whether the buffer is prefixed with 4 bytes for its total length. - * @returns Deserialized instance of `FunctionL2Logs`. - */ - public static fromBuffer(buf: Buffer, isLengthPrefixed = true): EncryptedFunctionL2Logs { - const reader = new BufferReader(buf, 0); - - // If the buffer is length prefixed use the length to read the array. Otherwise, the entire buffer is consumed. - const logsBufLength = isLengthPrefixed ? reader.readNumber() : -1; - const logs = reader.readBufferArray(logsBufLength); - - return new EncryptedFunctionL2Logs(logs.map(EncryptedL2Log.fromBuffer)); - } - - /** - * Creates a new L2Logs object with `numLogs` logs. - * @param numLogs - The number of logs to create. - * @returns A new EncryptedFunctionL2Logs object. - */ - public static random(numLogs: number): EncryptedFunctionL2Logs { - if (numLogs > MAX_ENCRYPTED_LOGS_PER_CALL) { - throw new Error(`Trying to create ${numLogs} logs for one call (max: ${MAX_ENCRYPTED_LOGS_PER_CALL})`); - } - const logs: EncryptedL2Log[] = []; - for (let i = 0; i < numLogs; i++) { - logs.push(EncryptedL2Log.random()); - } - return new EncryptedFunctionL2Logs(logs); - } -} -export class UnencryptedFunctionL2Logs extends FunctionL2Logs { static get schema() { return z .object({ logs: z.array(UnencryptedL2Log.schema) }) diff --git a/yarn-project/circuit-types/src/logs/index.ts b/yarn-project/circuit-types/src/logs/index.ts index 2f10eb33f60..cee3f87433b 100644 --- a/yarn-project/circuit-types/src/logs/index.ts +++ b/yarn-project/circuit-types/src/logs/index.ts @@ -1,12 +1,9 @@ -export * from './encrypted_l2_note_log.js'; -export * from './encrypted_l2_log.js'; export * from './event_metadata.js'; export * from './get_logs_response.js'; export * from './function_l2_logs.js'; export * from './l2_block_l2_logs.js'; export * from './l2_logs_source.js'; export * from './log_id.js'; -export * from './log_type.js'; export * from './log_filter.js'; export * from './l1_payload/index.js'; export * from './tx_l2_logs.js'; diff --git a/yarn-project/circuit-types/src/logs/l1_payload/encrypted_log_payload.test.ts b/yarn-project/circuit-types/src/logs/l1_payload/encrypted_log_payload.test.ts index a5beb331492..af663a834ab 100644 --- a/yarn-project/circuit-types/src/logs/l1_payload/encrypted_log_payload.test.ts +++ b/yarn-project/circuit-types/src/logs/l1_payload/encrypted_log_payload.test.ts @@ -3,7 +3,7 @@ import { CompleteAddress, IndexedTaggingSecret, KeyValidationRequest, - PRIVATE_LOG_SIZE_IN_BYTES, + type PrivateLog, computeAddressSecret, computeOvskApp, deriveKeys, @@ -11,12 +11,9 @@ import { } from '@aztec/circuits.js'; import { randomBytes } from '@aztec/foundation/crypto'; import { Fr, GrumpkinScalar } from '@aztec/foundation/fields'; -import { serializeToBuffer } from '@aztec/foundation/serialize'; import { updateInlineTestData } from '@aztec/foundation/testing'; import { EncryptedLogPayload } from './encrypted_log_payload.js'; -import { encrypt } from './encryption_util.js'; -import { derivePoseidonAESSecret } from './shared_secret_derivation.js'; // placeholder value until tagging is implemented const PLACEHOLDER_TAG = new Fr(33); @@ -28,7 +25,7 @@ describe('EncryptedLogPayload', () => { let ivskM: GrumpkinScalar; let original: EncryptedLogPayload; - let encrypted: Buffer; + let payload: PrivateLog; beforeAll(() => { const incomingBodyPlaintext = randomBytes(128); @@ -45,19 +42,19 @@ describe('EncryptedLogPayload', () => { const ephSk = GrumpkinScalar.random(); - encrypted = original.encrypt(ephSk, completeAddress.address, ovKeys); + payload = original.generatePayload(ephSk, completeAddress.address, ovKeys); }); it('decrypt a log as incoming', () => { const addressSecret = computeAddressSecret(completeAddress.getPreaddress(), ivskM); - const recreated = EncryptedLogPayload.decryptAsIncoming(encrypted, addressSecret); + const recreated = EncryptedLogPayload.decryptAsIncoming(payload, addressSecret); expect(recreated?.toBuffer()).toEqual(original.toBuffer()); }); it('decrypt a log as outgoing', () => { - const recreated = EncryptedLogPayload.decryptAsOutgoing(encrypted, ovskM); + const recreated = EncryptedLogPayload.decryptAsOutgoing(payload, ovskM); expect(recreated?.toBuffer()).toEqual(original.toBuffer()); }); @@ -78,21 +75,18 @@ describe('EncryptedLogPayload', () => { const recipient = AztecAddress.fromBigInt(0x25afb798ea6d0b8c1618e50fdeafa463059415013d3b7c75d46abf5e242be70cn); - const outgoingBodyPlaintext = serializeToBuffer( - ephSk.hi, - ephSk.lo, + const addressPoint = recipient.toAddressPoint(); + + const outgoingBodyCiphertext = EncryptedLogPayload.encryptOutgoingBody( + ephSk, + ephPk, recipient, - recipient.toAddressPoint().toCompressedBuffer(), - ); - const outgoingBodyCiphertext = encrypt( - outgoingBodyPlaintext, + addressPoint, senderOvskApp, - ephPk, - derivePoseidonAESSecret, ).toString('hex'); expect(outgoingBodyCiphertext).toMatchInlineSnapshot( - `"7fb6e34bc0c5362fa886e994fb2e560c4932ee321fae1bca6e4da1c5f47c11648f96e80e9cf82bb11052f467584a54c80f41bb0ea33c5b16681fd3be7c794f5ceeb6c2e1224743741be744a1935e35c353edac34ade51aea6b2b52441069257d75568532155c4ae5698d53e5fffb153dea3da8dd6ae70849d03cfb2efbe49490bbc32612df990879b254ed94fedb3b3e"`, + `"61dd35a8f238d9b8727f89621f3f56b38bc6a2a2d89effcd5ad48d3709f50692ca898124be1f115997cb2bc4cbe9b24fca46fab612bf4f2acdcc910e0d23ff8b8e42c1f0afe9b42599eb2958e834ebd5321a99e319f2a15c2d98646a1dc08365797e1f76bf5aee2b18523112c76b5307"`, ); const byteArrayString = `[${outgoingBodyCiphertext.match(/.{1,2}/g)!.map(byte => parseInt(byte, 16))}]`; @@ -117,15 +111,6 @@ describe('EncryptedLogPayload', () => { const logTag = new IndexedTaggingSecret(new Fr(69420), 1337).computeTag( AztecAddress.fromBigInt(0x25afb798ea6d0b8c1618e50fdeafa463059415013d3b7c75d46abf5e242be70cn), ); - const tagString = logTag.toString().slice(2); - - let byteArrayString = `[${tagString.match(/.{1,2}/g)!.map(byte => parseInt(byte, 16))}]`; - updateInlineTestData( - 'noir-projects/aztec-nr/aztec/src/encrypted_logs/payload.nr', - 'encrypted_log_from_typescript', - byteArrayString, - ); - const log = new EncryptedLogPayload(logTag, contract, plaintext); const ovskM = new GrumpkinScalar(0x1d7f6b3c491e99f32aad05c433301f3a2b4ed68de661ff8255d275ff94de6fc4n); @@ -138,35 +123,28 @@ describe('EncryptedLogPayload', () => { ); const fixedRand = (len: number) => { - // The random values in the noir test file after the overhead are [1, 2, ..., 31, 0, 1, 2, ..., 31]. - const offset = plaintext.length + 1; - return Buffer.from( - Array(len) - .fill(0) - .map((_, i) => 1 + ((offset + i) % 31)), - ); + // The random values in the noir test file after the overhead are filled with 1s. + return Buffer.from(Array(len).fill(1)); }; - const encrypted = log.encrypt(ephSk, recipientCompleteAddress.address, ovKeys, fixedRand); - expect(encrypted.length).toBe(PRIVATE_LOG_SIZE_IN_BYTES); + const payload = log.generatePayload(ephSk, recipientCompleteAddress.address, ovKeys, fixedRand); - const encryptedStr = encrypted.toString('hex'); - expect(encryptedStr).toMatchInlineSnapshot( - `"0e9cffc3ddd746affb02410d8f0a823e89939785bcc8e88ee4f3cae05e737c368d460c0e434d846ec1ea286e4090eb56376ff27bddc1aacae1d856549f701fa70577790aeabcc2d81ec8d0c99e7f5d2bf2f1452025dc777a178404f851d93de818923f85187871d99bdf95d695eff0a9e09ba15153fc9b4d224b6e1e71dfbdcaab06c09d5b3c749bfebe1c0407eccd04f51bbb59142680c8a091b97fc6cbcf61f6c2af9b8ebc8f78537ab23fd0c5e818e4d42d459d265adb77c2ef829bf68f87f2c47b478bb57ae7e41a07643f65c353083d557b94e31da4a2a13127498d2eb3f0346da5eed2e9bc245aaf022a954ed0b09132b498f537702899b44e3666776238ebf633b3562d7f124dbba82918e871958a94218fd796bc6983feecc7ce382c82861d63fe45999244ea9494b226ddb667fc8b07f6841de84e667e1c8808dbb4a20e3e477628935d57bce7205d38c1c2c57899a48b72129502e213aafaf98038ec5d0e657314ad49c035e507173b0bb00993afa8ce307f7e4c33d342e81084f30ec4b5760c47ecfafd47f97a1e171713592fc145f0a422806e0d85c607a50e1fefd2924e4356209ff4d6f679f6e9fc1483dd1c92de77dea2fafcbd12930c8eb1deb27af871c528c798fb5b51f3199cf18d3c0c6367a961207025f4ff7e2e72e271dff91b031f29e91c0817546319ba412109234a1034a930a186e9f28827a269cd2bfdb7248aba571f07f87de3c1ac9b62213dba9ef1c0171cba64deae1340e071fb8f2d98514374105fbd531f7c279b8e420078c5dda13e4bc0ffbac80a8707"`, + expect(payload.toBuffer().toString('hex')).toMatchInlineSnapshot( + `"0e9cffc3ddd746affb02410d8f0a823e89939785bcc8e88ee4f3cae05e737c36008d460c0e434d846ec1ea286e4090eb56376ff27bddc1aacae1d856549f701f00a70577790aeabcc2d81ec8d0c99e7f5d2bf2f1452025dc777a178404f851d9003de818923f85187871d99bdf95d695eff0a9e09ba15153fc9b4d224b6e1e7100dfbdcaab06c09d5b3c749bfebe1c0407eccd04f51bbb59142680c8a091b97f00c6cbcf615def593ab09e5b3f7f58f6fc235c90e7c77ed8dadb3b05ee4545a700bc612c9139475fee6070be47efcc43a5cbbc873632f1428fac952df9c181db005f9e850b21fe11fedef37b88caee95111bce776e488df219732d0a77d19201007047186f41445ecd5c603487f7fb3c8f31010a22af69ce00000000000000000000000000000000a600a61f7d59eeaf52eb51bc0592ff981d9ba3ea8e6ea8ba009dc0cec8c70b81e84556a77ce6c3ca47a527f99ffe7b2524bb885a23020b720095748ad19c1083618ad96298b76ee07eb1a56d19cc798710e9f5de96501bd5009b3781c9c02a6c95c5912f8936b1500d362afbf0922c85b1ada18db8b9516200a6e9d067655cdf669eb387f8e0492a95fdcdb39429d5340b4bebc250ba9bf6002c2f49f549f37beed75a668aa51967e0e57547e5a655157bcf381e22f30e2500881548ec9606a151b5fbfb2d14ee4b34bf4c1dbd71c7be15ad4c63474bb6f8009970aeb3d9489c8edbdff80a1a3a5c28370e534abc870a85ea4318326ea1920022fb10df358c765edada497db4284ae30507a2e03e983d23cfa0bd831577e8"`, ); // Run with AZTEC_GENERATE_TEST_DATA=1 to update noir test data - byteArrayString = `[${encryptedStr.match(/.{1,2}/g)!.map(byte => parseInt(byte, 16))}]`; + const fieldArrayStr = `[${payload.fields.map(f => f.toString()).join(',')}]`; updateInlineTestData( 'noir-projects/aztec-nr/aztec/src/encrypted_logs/payload.nr', - 'encrypted_log_from_typescript', - byteArrayString, + 'private_log_payload_from_typescript', + fieldArrayStr, ); const ivskM = new GrumpkinScalar(0x0d6e27b21c89a7632f7766e35cc280d43f75bea3898d7328400a5fefc804d462n); const addressSecret = computeAddressSecret(recipientCompleteAddress.getPreaddress(), ivskM); - const recreated = EncryptedLogPayload.decryptAsIncoming(encrypted, addressSecret); + const recreated = EncryptedLogPayload.decryptAsIncoming(payload, addressSecret); expect(recreated?.toBuffer()).toEqual(log.toBuffer()); }); diff --git a/yarn-project/circuit-types/src/logs/l1_payload/encrypted_log_payload.ts b/yarn-project/circuit-types/src/logs/l1_payload/encrypted_log_payload.ts index 2647121c3be..599d73eb9c5 100644 --- a/yarn-project/circuit-types/src/logs/l1_payload/encrypted_log_payload.ts +++ b/yarn-project/circuit-types/src/logs/l1_payload/encrypted_log_payload.ts @@ -1,37 +1,81 @@ import { AztecAddress, + Fq, Fr, GrumpkinScalar, type KeyValidationRequest, NotOnCurveError, - PRIVATE_LOG_SIZE_IN_BYTES, + PRIVATE_LOG_SIZE_IN_FIELDS, Point, + PrivateLog, type PublicKey, computeOvskApp, derivePublicKeyFromSecretKey, } from '@aztec/circuits.js'; import { randomBytes } from '@aztec/foundation/crypto'; -import { BufferReader, numToUInt8, serializeToBuffer } from '@aztec/foundation/serialize'; +import { BufferReader, type Tuple, numToUInt16BE, serializeToBuffer } from '@aztec/foundation/serialize'; import { decrypt, encrypt } from './encryption_util.js'; import { derivePoseidonAESSecret } from './shared_secret_derivation.js'; +// Below constants should match the values defined in aztec-nr/aztec/src/encrypted_logs/payload.nr. + // Both the incoming and the outgoing header are 48 bytes../shared_secret_derivation.js // 32 bytes for the address, and 16 bytes padding to follow PKCS#7 const HEADER_SIZE = 48; -// The outgoing body is constant size of 144 bytes. -// 128 bytes for the secret key, address and public key, and 16 bytes padding to follow PKCS#7 -const OUTGOING_BODY_SIZE = 144; +// The outgoing body is constant size: +// 96 bytes for the secret key, address and public key, and 16 bytes padding to follow PKCS#7 +const OUTGOING_BODY_SIZE = 112; + +// Padding added to the overhead to make the size of the incoming body ciphertext a multiple of 16. +const OVERHEAD_PADDING = 15; -const ENCRYPTED_LOG_CIPHERTEXT_OVERHEAD_SIZE = - 32 /* incoming_tag */ + +const OVERHEAD_SIZE = 32 /* eph_pk */ + HEADER_SIZE /* incoming_header */ + HEADER_SIZE /* outgoing_header */ + - OUTGOING_BODY_SIZE; /* outgoing_body */ + OUTGOING_BODY_SIZE /* outgoing_body */ + + OVERHEAD_PADDING; /* padding */ + +const ENCRYPTED_PAYLOAD_SIZE_IN_BYTES = (PRIVATE_LOG_SIZE_IN_FIELDS - 1) * 31; + +const MAX_PRIVATE_LOG_PLAINTEXT_SIZE_IN_BYTES = + ENCRYPTED_PAYLOAD_SIZE_IN_BYTES - OVERHEAD_SIZE - 2 /* plaintext */ - 1; /* aes padding */ + +function encryptedBytesToFields(encrypted: Buffer): Fr[] { + const fields = []; + const numFields = Math.ceil(encrypted.length / 31); + for (let i = 0; i < numFields; i++) { + fields.push(new Fr(encrypted.subarray(i * 31, (i + 1) * 31))); + } + return fields; +} + +function fieldsToEncryptedBytes(fields: Fr[]) { + return Buffer.concat(fields.map(f => f.toBuffer().subarray(1))); +} + +class Overhead { + constructor( + public ephPk: Point, + public incomingHeader: Buffer, + public outgoingHeader: Buffer, + public outgoingBody: Buffer, + ) {} -const INCOMING_BODY_SIZE = PRIVATE_LOG_SIZE_IN_BYTES - ENCRYPTED_LOG_CIPHERTEXT_OVERHEAD_SIZE; + static fromBuffer(reader: BufferReader) { + const ephPk = Point.fromCompressedBuffer(reader.readBytes(Point.COMPRESSED_SIZE_IN_BYTES)); + const incomingHeader = reader.readBytes(HEADER_SIZE); + const outgoingHeader = reader.readBytes(HEADER_SIZE); + const outgoingBody = reader.readBytes(OUTGOING_BODY_SIZE); + + // Advance the index to skip the padding. + reader.readBytes(OVERHEAD_PADDING); + + return new Overhead(ephPk, incomingHeader, outgoingHeader, outgoingBody); + } +} /** * Encrypted log payload with a tag used for retrieval by clients. @@ -52,12 +96,12 @@ export class EncryptedLogPayload { public readonly incomingBodyPlaintext: Buffer, ) {} - public encrypt( + public generatePayload( ephSk: GrumpkinScalar, recipient: AztecAddress, ovKeys: KeyValidationRequest, rand: (len: number) => Buffer = randomBytes, - ): Buffer { + ): PrivateLog { const addressPoint = recipient.toAddressPoint(); const ephPk = derivePublicKeyFromSecretKey(ephSk); @@ -71,50 +115,65 @@ export class EncryptedLogPayload { throw new Error(`Invalid outgoing header size: ${outgoingHeaderCiphertext.length}`); } - // The serialization of Fq is [high, low] check `outgoing_body.nr` - const outgoingBodyPlaintext = serializeToBuffer(ephSk.hi, ephSk.lo, recipient, addressPoint.toCompressedBuffer()); - const outgoingBodyCiphertext = encrypt( - outgoingBodyPlaintext, - ovKeys.skAppAsGrumpkinScalar, + const outgoingBodyCiphertext = EncryptedLogPayload.encryptOutgoingBody( + ephSk, ephPk, - derivePoseidonAESSecret, + recipient, + addressPoint, + ovKeys.skAppAsGrumpkinScalar, ); - if (outgoingBodyCiphertext.length !== OUTGOING_BODY_SIZE) { - throw new Error(`Invalid outgoing body size: ${outgoingBodyCiphertext.length}`); - } const overhead = serializeToBuffer( - this.tag, ephPk.toCompressedBuffer(), incomingHeaderCiphertext, outgoingHeaderCiphertext, outgoingBodyCiphertext, + Buffer.alloc(OVERHEAD_PADDING), ); - if (overhead.length !== ENCRYPTED_LOG_CIPHERTEXT_OVERHEAD_SIZE) { - throw new Error( - `Invalid ciphertext overhead size. Expected ${ENCRYPTED_LOG_CIPHERTEXT_OVERHEAD_SIZE}. Got ${overhead.length}.`, - ); + if (overhead.length !== OVERHEAD_SIZE) { + throw new Error(`Invalid ciphertext overhead size. Expected ${OVERHEAD_SIZE}. Got ${overhead.length}.`); } - const numPaddedBytes = - PRIVATE_LOG_SIZE_IN_BYTES - - ENCRYPTED_LOG_CIPHERTEXT_OVERHEAD_SIZE - - 1 /* 1 byte for this.incomingBodyPlaintext.length */ - - 15 /* aes padding */ - - this.incomingBodyPlaintext.length; + if (this.incomingBodyPlaintext.length > MAX_PRIVATE_LOG_PLAINTEXT_SIZE_IN_BYTES) { + throw new Error(`Incoming body plaintext cannot be more than ${MAX_PRIVATE_LOG_PLAINTEXT_SIZE_IN_BYTES} bytes.`); + } + + const numPaddedBytes = MAX_PRIVATE_LOG_PLAINTEXT_SIZE_IN_BYTES - this.incomingBodyPlaintext.length; const paddedIncomingBodyPlaintextWithLength = Buffer.concat([ - numToUInt8(this.incomingBodyPlaintext.length), + numToUInt16BE(this.incomingBodyPlaintext.length), this.incomingBodyPlaintext, rand(numPaddedBytes), ]); const incomingBodyCiphertext = encrypt(paddedIncomingBodyPlaintextWithLength, ephSk, addressPoint); - if (incomingBodyCiphertext.length !== INCOMING_BODY_SIZE) { + + const encryptedPayload = serializeToBuffer(overhead, incomingBodyCiphertext); + + const logFields = [this.tag, ...encryptedBytesToFields(encryptedPayload)] as Tuple< + Fr, + typeof PRIVATE_LOG_SIZE_IN_FIELDS + >; + if (logFields.length !== PRIVATE_LOG_SIZE_IN_FIELDS) { throw new Error( - `Invalid incoming body size. Expected ${INCOMING_BODY_SIZE}. Got ${incomingBodyCiphertext.length}`, + `Expected private log payload to have ${PRIVATE_LOG_SIZE_IN_FIELDS} fields. Got ${logFields.length}.`, ); } - return serializeToBuffer(overhead, incomingBodyCiphertext); + return new PrivateLog(logFields); + } + + public static encryptOutgoingBody( + ephSk: GrumpkinScalar, + ephPk: Point, + recipient: AztecAddress, + addressPoint: Point, + secret: GrumpkinScalar, + ) { + const outgoingBodyPlaintext = serializeToBuffer(ephSk, recipient, addressPoint.toCompressedBuffer()); + const outgoingBodyCiphertext = encrypt(outgoingBodyPlaintext, secret, ephPk, derivePoseidonAESSecret); + if (outgoingBodyCiphertext.length !== OUTGOING_BODY_SIZE) { + throw new Error(`Invalid outgoing body size: ${outgoingBodyCiphertext.length}`); + } + return outgoingBodyCiphertext; } /** @@ -125,34 +184,54 @@ export class EncryptedLogPayload { * * Produces the same output as `decryptAsOutgoing`. * - * @param ciphertext - The ciphertext for the log + * @param payload - The payload for the log * @param addressSecret - The address secret, used to decrypt the logs * @returns The decrypted log payload */ - public static decryptAsIncoming( - ciphertext: Buffer | BufferReader, + public static decryptAsIncoming(payload: PrivateLog, addressSecret: GrumpkinScalar): EncryptedLogPayload | undefined { + try { + const logFields = payload.fields; + const tag = logFields[0]; + const reader = BufferReader.asReader(fieldsToEncryptedBytes(logFields.slice(1))); + + const overhead = Overhead.fromBuffer(reader); + const { contractAddress } = this.#decryptOverhead(overhead, { addressSecret }); + + const ciphertext = reader.readToEnd(); + const incomingBodyPlaintext = this.#decryptIncomingBody(ciphertext, addressSecret, overhead.ephPk); + + return new EncryptedLogPayload(tag, contractAddress, incomingBodyPlaintext); + } catch (e: any) { + // Following error messages are expected to occur when decryption fails + if (!this.isAcceptableError(e)) { + // If we encounter an unexpected error, we rethrow it + throw e; + } + return; + } + } + + /** + * Similar to `decryptAsIncoming`. Except that this is for the payload coming from public, which has tightly packed + * bytes that don't have 0 byte at the beginning of every 32 bytes. + * And the incoming body is of variable size. + */ + public static decryptAsIncomingFromPublic( + payload: Buffer, addressSecret: GrumpkinScalar, ): EncryptedLogPayload | undefined { - const reader = BufferReader.asReader(ciphertext); - try { + const reader = BufferReader.asReader(payload); const tag = reader.readObject(Fr); - const ephPk = Point.fromCompressedBuffer(reader.readBytes(Point.COMPRESSED_SIZE_IN_BYTES)); - - const incomingHeader = decrypt(reader.readBytes(HEADER_SIZE), addressSecret, ephPk); - - // Skipping the outgoing header and body - reader.readBytes(HEADER_SIZE); - reader.readBytes(OUTGOING_BODY_SIZE); + const overhead = Overhead.fromBuffer(reader); + const { contractAddress } = this.#decryptOverhead(overhead, { addressSecret }); // The incoming can be of variable size, so we read until the end const ciphertext = reader.readToEnd(); - const decrypted = decrypt(ciphertext, addressSecret, ephPk); - const length = decrypted.readUint8(0); - const incomingBodyPlaintext = decrypted.subarray(1, 1 + length); + const incomingBodyPlaintext = this.#decryptIncomingBody(ciphertext, addressSecret, overhead.ephPk); - return new EncryptedLogPayload(tag, AztecAddress.fromBuffer(incomingHeader), incomingBodyPlaintext); + return new EncryptedLogPayload(tag, contractAddress, incomingBodyPlaintext); } catch (e: any) { // Following error messages are expected to occur when decryption fails if (!this.isAcceptableError(e)) { @@ -176,43 +255,48 @@ export class EncryptedLogPayload { * @param ovsk - The outgoing viewing secret key, used to decrypt the logs * @returns The decrypted log payload */ - public static decryptAsOutgoing( - ciphertext: Buffer | BufferReader, - ovsk: GrumpkinScalar, - ): EncryptedLogPayload | undefined { - const reader = BufferReader.asReader(ciphertext); - + public static decryptAsOutgoing(payload: PrivateLog, ovsk: GrumpkinScalar): EncryptedLogPayload | undefined { try { - const tag = reader.readObject(Fr); - - const ephPk = Point.fromCompressedBuffer(reader.readBytes(Point.COMPRESSED_SIZE_IN_BYTES)); + const logFields = payload.fields; + const tag = logFields[0]; + const reader = BufferReader.asReader(fieldsToEncryptedBytes(logFields.slice(1))); - // We skip the incoming header - reader.readBytes(HEADER_SIZE); + const overhead = Overhead.fromBuffer(reader); + const { contractAddress, ephSk, recipientAddressPoint } = this.#decryptOverhead(overhead, { ovsk }); - const outgoingHeader = decrypt(reader.readBytes(HEADER_SIZE), ovsk, ephPk); - const contractAddress = AztecAddress.fromBuffer(outgoingHeader); + // Now we decrypt the incoming body using the ephSk and recipientIvpk + const ciphertext = reader.readToEnd(); + const incomingBodyPlaintext = this.#decryptIncomingBody(ciphertext, ephSk, recipientAddressPoint); - const ovskApp = computeOvskApp(ovsk, contractAddress); + return new EncryptedLogPayload(tag, contractAddress, incomingBodyPlaintext); + } catch (e: any) { + // Following error messages are expected to occur when decryption fails + if (!this.isAcceptableError(e)) { + // If we encounter an unexpected error, we rethrow it + throw e; + } + return; + } + } - let ephSk: GrumpkinScalar; - let recipientAddressPoint: PublicKey; - { - const outgoingBody = decrypt(reader.readBytes(OUTGOING_BODY_SIZE), ovskApp, ephPk, derivePoseidonAESSecret); - const obReader = BufferReader.asReader(outgoingBody); + /** + * Similar to `decryptAsOutgoing`. Except that this is for the payload coming from public, which has tightly packed + * bytes that don't have 0 byte at the beginning of every 32 bytes. + * And the incoming body is of variable size. + */ + public static decryptAsOutgoingFromPublic(payload: Buffer, ovsk: GrumpkinScalar): EncryptedLogPayload | undefined { + try { + const reader = BufferReader.asReader(payload); + const tag = reader.readObject(Fr); - // From outgoing body we extract ephSk, recipient and recipientAddressPoint - ephSk = GrumpkinScalar.fromHighLow(obReader.readObject(Fr), obReader.readObject(Fr)); - const _recipient = obReader.readObject(AztecAddress); - recipientAddressPoint = Point.fromCompressedBuffer(obReader.readBytes(Point.COMPRESSED_SIZE_IN_BYTES)); - } + const overhead = Overhead.fromBuffer(reader); + const { contractAddress, ephSk, recipientAddressPoint } = this.#decryptOverhead(overhead, { ovsk }); // Now we decrypt the incoming body using the ephSk and recipientIvpk - const decryptedIncomingBody = decrypt(reader.readToEnd(), ephSk, recipientAddressPoint); - const length = decryptedIncomingBody.readUint8(0); - const incomingBody = decryptedIncomingBody.subarray(1, 1 + length); + const ciphertext = reader.readToEnd(); + const incomingBodyPlaintext = this.#decryptIncomingBody(ciphertext, ephSk, recipientAddressPoint); - return new EncryptedLogPayload(tag, contractAddress, incomingBody); + return new EncryptedLogPayload(tag, contractAddress, incomingBodyPlaintext); } catch (e: any) { // Following error messages are expected to occur when decryption fails if (!this.isAcceptableError(e)) { @@ -237,4 +321,44 @@ export class EncryptedLogPayload { public toBuffer() { return serializeToBuffer(this.tag, this.contractAddress.toBuffer(), this.incomingBodyPlaintext); } + + static #decryptOverhead( + overhead: Overhead, + { addressSecret, ovsk }: { addressSecret?: GrumpkinScalar; ovsk?: GrumpkinScalar }, + ) { + let contractAddress = AztecAddress.ZERO; + + if (addressSecret) { + const incomingHeader = decrypt(overhead.incomingHeader, addressSecret, overhead.ephPk); + contractAddress = AztecAddress.fromBuffer(incomingHeader); + } + + let ephSk = GrumpkinScalar.ZERO; + let recipientAddressPoint = Point.ZERO; + if (ovsk) { + const outgoingHeader = decrypt(overhead.outgoingHeader, ovsk, overhead.ephPk); + contractAddress = AztecAddress.fromBuffer(outgoingHeader!); + + const ovskApp = computeOvskApp(ovsk, contractAddress); + const outgoingBody = decrypt(overhead.outgoingBody, ovskApp, overhead.ephPk, derivePoseidonAESSecret); + + // From outgoing body we extract ephSk, recipient and recipientAddressPoint + const obReader = BufferReader.asReader(outgoingBody); + ephSk = obReader.readObject(Fq); + const _recipient = obReader.readObject(AztecAddress); + recipientAddressPoint = Point.fromCompressedBuffer(obReader.readBytes(Point.COMPRESSED_SIZE_IN_BYTES)); + } + + return { + contractAddress, + ephSk, + recipientAddressPoint, + }; + } + + static #decryptIncomingBody(ciphertext: Buffer, secret: GrumpkinScalar, publicKey: PublicKey) { + const decrypted = decrypt(ciphertext, secret, publicKey); + const length = decrypted.readUint16BE(0); + return decrypted.subarray(2, 2 + length); + } } diff --git a/yarn-project/circuit-types/src/logs/l1_payload/l1_event_payload.ts b/yarn-project/circuit-types/src/logs/l1_payload/l1_event_payload.ts index 429695236a0..364b5836fd5 100644 --- a/yarn-project/circuit-types/src/logs/l1_payload/l1_event_payload.ts +++ b/yarn-project/circuit-types/src/logs/l1_payload/l1_event_payload.ts @@ -1,10 +1,8 @@ -import { AztecAddress } from '@aztec/circuits.js'; +import { AztecAddress, type PrivateLog } from '@aztec/circuits.js'; import { EventSelector } from '@aztec/foundation/abi'; -import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto'; import { type Fq, Fr } from '@aztec/foundation/fields'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; -import { type EncryptedL2Log } from '../encrypted_l2_log.js'; import { EncryptedLogPayload } from './encrypted_log_payload.js'; import { Event } from './payload.js'; @@ -21,10 +19,6 @@ export class L1EventPayload { * Address of the contract this tx is interacting with. */ public contractAddress: AztecAddress, - /** - * Randomness used to mask the contract address. - */ - public randomness: Fr, /** * Type identifier for the underlying event, required to determine how to compute its hash and nullifier. */ @@ -34,30 +28,26 @@ export class L1EventPayload { static #fromIncomingBodyPlaintextAndContractAddress( plaintext: Buffer, contractAddress: AztecAddress, - maskedContractAddress: Fr, ): L1EventPayload | undefined { let payload: L1EventPayload; try { const reader = BufferReader.asReader(plaintext); const fields = reader.readArray(plaintext.length / Fr.SIZE_IN_BYTES, Fr); - const randomness = fields[0]; - const eventTypeId = EventSelector.fromField(fields[1]); + const eventTypeId = EventSelector.fromField(fields[0]); - const event = new Event(fields.slice(2)); + const event = new Event(fields.slice(1)); - payload = new L1EventPayload(event, contractAddress, randomness, eventTypeId); + payload = new L1EventPayload(event, contractAddress, eventTypeId); } catch (e) { return undefined; } - ensureMatchedMaskedContractAddress(contractAddress, payload.randomness, maskedContractAddress); - return payload; } - static decryptAsIncoming(log: EncryptedL2Log, sk: Fq): L1EventPayload | undefined { - const decryptedLog = EncryptedLogPayload.decryptAsIncoming(log.data, sk); + static decryptAsIncoming(log: PrivateLog, sk: Fq): L1EventPayload | undefined { + const decryptedLog = EncryptedLogPayload.decryptAsIncoming(log, sk); if (!decryptedLog) { return undefined; } @@ -65,12 +55,11 @@ export class L1EventPayload { return this.#fromIncomingBodyPlaintextAndContractAddress( decryptedLog.incomingBodyPlaintext, decryptedLog.contractAddress, - log.maskedContractAddress, ); } - static decryptAsOutgoing(log: EncryptedL2Log, sk: Fq): L1EventPayload | undefined { - const decryptedLog = EncryptedLogPayload.decryptAsOutgoing(log.data, sk); + static decryptAsOutgoing(log: PrivateLog, sk: Fq): L1EventPayload | undefined { + const decryptedLog = EncryptedLogPayload.decryptAsOutgoing(log, sk); if (!decryptedLog) { return undefined; } @@ -78,7 +67,6 @@ export class L1EventPayload { return this.#fromIncomingBodyPlaintextAndContractAddress( decryptedLog.incomingBodyPlaintext, decryptedLog.contractAddress, - log.maskedContractAddress, ); } @@ -87,7 +75,7 @@ export class L1EventPayload { * @returns Buffer representation of the L1EventPayload object. */ toIncomingBodyPlaintext() { - const fields = [this.randomness, this.eventTypeId.toField(), ...this.event.items]; + const fields = [this.eventTypeId.toField(), ...this.event.items]; return serializeToBuffer(fields); } @@ -97,23 +85,14 @@ export class L1EventPayload { * @returns A random L1EventPayload object. */ static random(contract = AztecAddress.random()) { - return new L1EventPayload(Event.random(), contract, Fr.random(), EventSelector.random()); + return new L1EventPayload(Event.random(), contract, EventSelector.random()); } public equals(other: L1EventPayload) { return ( this.event.equals(other.event) && this.contractAddress.equals(other.contractAddress) && - this.randomness.equals(other.randomness) && this.eventTypeId.equals(other.eventTypeId) ); } } - -function ensureMatchedMaskedContractAddress(contractAddress: AztecAddress, randomness: Fr, maskedContractAddress: Fr) { - if (!poseidon2HashWithSeparator([contractAddress, randomness], 0).equals(maskedContractAddress)) { - throw new Error( - 'The provided masked contract address does not match with the incoming address from header and randomness from body', - ); - } -} diff --git a/yarn-project/circuit-types/src/logs/l1_payload/l1_note_payload.ts b/yarn-project/circuit-types/src/logs/l1_payload/l1_note_payload.ts index b92f9be282f..7d1d1633efe 100644 --- a/yarn-project/circuit-types/src/logs/l1_payload/l1_note_payload.ts +++ b/yarn-project/circuit-types/src/logs/l1_payload/l1_note_payload.ts @@ -1,4 +1,4 @@ -import { AztecAddress, Vector } from '@aztec/circuits.js'; +import { AztecAddress, type PrivateLog, Vector } from '@aztec/circuits.js'; import { NoteSelector } from '@aztec/foundation/abi'; import { randomInt } from '@aztec/foundation/crypto'; import { type Fq, Fr } from '@aztec/foundation/fields'; @@ -59,9 +59,26 @@ export class L1NotePayload { } } - static decryptAsIncoming(log: Buffer, sk: Fq, isFromPublic = false): L1NotePayload | undefined { - const { publicValues, encryptedLog } = parseLog(log, isFromPublic); - const decryptedLog = EncryptedLogPayload.decryptAsIncoming(encryptedLog, sk); + static decryptAsIncoming(log: PrivateLog, sk: Fq): L1NotePayload | undefined { + const decryptedLog = EncryptedLogPayload.decryptAsIncoming(log, sk); + if (!decryptedLog) { + return undefined; + } + + return this.fromIncomingBodyPlaintextContractAndPublicValues( + decryptedLog.incomingBodyPlaintext, + decryptedLog.contractAddress, + /* publicValues */ [], + ); + } + + static decryptAsIncomingFromPublic(log: Buffer, sk: Fq): L1NotePayload | undefined { + const { privateValues, publicValues } = parseLogFromPublic(log); + if (!privateValues) { + return undefined; + } + + const decryptedLog = EncryptedLogPayload.decryptAsIncomingFromPublic(privateValues, sk); if (!decryptedLog) { return undefined; } @@ -73,9 +90,26 @@ export class L1NotePayload { ); } - static decryptAsOutgoing(log: Buffer, sk: Fq, isFromPublic = false): L1NotePayload | undefined { - const { publicValues, encryptedLog } = parseLog(log, isFromPublic); - const decryptedLog = EncryptedLogPayload.decryptAsOutgoing(encryptedLog, sk); + static decryptAsOutgoing(log: PrivateLog, sk: Fq): L1NotePayload | undefined { + const decryptedLog = EncryptedLogPayload.decryptAsOutgoing(log, sk); + if (!decryptedLog) { + return undefined; + } + + return this.fromIncomingBodyPlaintextContractAndPublicValues( + decryptedLog.incomingBodyPlaintext, + decryptedLog.contractAddress, + /* publicValues */ [], + ); + } + + static decryptAsOutgoingFromPublic(log: Buffer, sk: Fq): L1NotePayload | undefined { + const { privateValues, publicValues } = parseLogFromPublic(log); + if (!privateValues) { + return undefined; + } + + const decryptedLog = EncryptedLogPayload.decryptAsOutgoingFromPublic(privateValues, sk); if (!decryptedLog) { return undefined; } @@ -149,25 +183,28 @@ export class L1NotePayload { * @param log - Log to be parsed. * @returns An object containing the public values and the encrypted log. */ -function parseLog(log: Buffer, isFromPublic: boolean) { +function parseLogFromPublic(log: Buffer) { // First we remove padding bytes - const processedLog = isFromPublic ? removePaddingBytes(log) : log; + const processedLog = removePaddingBytes(log); + if (!processedLog) { + return {}; + } const reader = new BufferReader(processedLog); // Then we extract public values from the log - const numPublicValues = isFromPublic ? reader.readUInt8() : 0; + const numPublicValues = reader.readUInt8(); const publicValuesLength = numPublicValues * Fr.SIZE_IN_BYTES; - const encryptedLogLength = reader.remainingBytes() - publicValuesLength; + const privateValuesLength = reader.remainingBytes() - publicValuesLength; - // Now we get the buffer corresponding to the encrypted log - const encryptedLog = reader.readBytes(encryptedLogLength); + // Now we get the buffer corresponding to the values generated from private. + const privateValues = reader.readBytes(privateValuesLength); // At last we load the public values const publicValues = reader.readArray(numPublicValues, Fr); - return { publicValues, encryptedLog }; + return { publicValues, privateValues }; } /** @@ -180,7 +217,7 @@ function removePaddingBytes(unprocessedLog: Buffer) { // Determine whether first 31 bytes of each 32 bytes block of bytes are 0 const is1FieldPerByte = unprocessedLog.every((byte, index) => index % 32 === 31 || byte === 0); if (!is1FieldPerByte) { - return unprocessedLog; + return; } // We take every 32nd byte from the log and return the result diff --git a/yarn-project/circuit-types/src/logs/l2_block_l2_logs.test.ts b/yarn-project/circuit-types/src/logs/l2_block_l2_logs.test.ts index e16b963525b..bc5f1a2e7fb 100644 --- a/yarn-project/circuit-types/src/logs/l2_block_l2_logs.test.ts +++ b/yarn-project/circuit-types/src/logs/l2_block_l2_logs.test.ts @@ -1,19 +1,9 @@ import { jsonStringify } from '@aztec/foundation/json-rpc'; -import { - L2BlockL2Logs as BaseL2BlockL2Logs, - ContractClass2BlockL2Logs, - EncryptedL2BlockL2Logs, - EncryptedNoteL2BlockL2Logs, - UnencryptedL2BlockL2Logs, -} from './l2_block_l2_logs.js'; +import { ContractClass2BlockL2Logs, UnencryptedL2BlockL2Logs } from './l2_block_l2_logs.js'; function shouldBehaveLikeL2BlockL2Logs( - L2BlockL2Logs: - | typeof EncryptedNoteL2BlockL2Logs - | typeof UnencryptedL2BlockL2Logs - | typeof EncryptedL2BlockL2Logs - | typeof ContractClass2BlockL2Logs, + L2BlockL2Logs: typeof UnencryptedL2BlockL2Logs | typeof ContractClass2BlockL2Logs, ) { describe(L2BlockL2Logs.name, () => { it('can encode L2Logs to buffer and back', () => { @@ -51,14 +41,12 @@ function shouldBehaveLikeL2BlockL2Logs( ? L2BlockL2Logs.random(3, 1, 1) : L2BlockL2Logs.random(3, 4, 2); const json = jsonStringify(l2Logs); - const recovered = BaseL2BlockL2Logs.schema.parse(JSON.parse(json)); + const recovered = L2BlockL2Logs.schema.parse(JSON.parse(json)); expect(recovered).toEqual(l2Logs); expect(recovered).toBeInstanceOf(L2BlockL2Logs); }); }); } -shouldBehaveLikeL2BlockL2Logs(EncryptedNoteL2BlockL2Logs); shouldBehaveLikeL2BlockL2Logs(UnencryptedL2BlockL2Logs); -shouldBehaveLikeL2BlockL2Logs(EncryptedL2BlockL2Logs); shouldBehaveLikeL2BlockL2Logs(ContractClass2BlockL2Logs); diff --git a/yarn-project/circuit-types/src/logs/l2_block_l2_logs.ts b/yarn-project/circuit-types/src/logs/l2_block_l2_logs.ts index 82bf2d4a899..4620740544b 100644 --- a/yarn-project/circuit-types/src/logs/l2_block_l2_logs.ts +++ b/yarn-project/circuit-types/src/logs/l2_block_l2_logs.ts @@ -1,46 +1,23 @@ -import { type ZodFor } from '@aztec/foundation/schemas'; import { BufferReader, prefixBufferWithLength } from '@aztec/foundation/serialize'; import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import isEqual from 'lodash.isequal'; import { z } from 'zod'; -import { type EncryptedL2Log } from './encrypted_l2_log.js'; -import { type EncryptedL2NoteLog } from './encrypted_l2_note_log.js'; -import { - ContractClassTxL2Logs, - EncryptedNoteTxL2Logs, - EncryptedTxL2Logs, - type TxL2Logs, - UnencryptedTxL2Logs, -} from './tx_l2_logs.js'; +import { ContractClassTxL2Logs, type TxL2Logs, UnencryptedTxL2Logs } from './tx_l2_logs.js'; import { type UnencryptedL2Log } from './unencrypted_l2_log.js'; /** * Data container of logs emitted in all txs in a given L2 block. */ -export abstract class L2BlockL2Logs { +abstract class L2BlockL2Logs { constructor( /** * An array containing logs emitted in individual function invocations in this tx. */ - public readonly txLogs: TxL2Logs[], + public readonly txLogs: TxL2Logs[], ) {} - public abstract get type(): string; - - static get schema(): ZodFor< - L2BlockL2Logs | L2BlockL2Logs | L2BlockL2Logs - > { - // TODO(palla/schemas): This should be a discriminated union, but the compiler refuses - return z.union([ - EncryptedNoteL2BlockL2Logs.schema, - EncryptedL2BlockL2Logs.schema, - UnencryptedL2BlockL2Logs.schema, - ContractClass2BlockL2Logs.schema, - ]); - } - /** * Serializes logs into a buffer. * @returns A buffer containing the serialized logs. @@ -74,20 +51,12 @@ export abstract class L2BlockL2Logs): boolean { + public equals(other: L2BlockL2Logs): boolean { return isEqual(this, other); } @@ -96,157 +65,15 @@ export abstract class L2BlockL2Logs( - l2BlockL2logs: L2BlockL2Logs[], - ): number { + public static getTotalLogCount(l2BlockL2logs: L2BlockL2Logs[]): number { return l2BlockL2logs.reduce((sum, log) => sum + log.getTotalLogCount(), 0); } } -export class EncryptedNoteL2BlockL2Logs extends L2BlockL2Logs { - static override get schema() { - return z - .object({ type: z.literal('EncryptedNote'), txLogs: z.array(EncryptedNoteTxL2Logs.schema) }) - .transform(({ txLogs }) => new EncryptedNoteL2BlockL2Logs(txLogs)); - } - - public get type() { - return 'EncryptedNote'; - } - - /** - * Deserializes logs from a buffer. - * @param buffer - The buffer containing the serialized logs. - * @returns A new `L2BlockL2Logs` object. - */ - public static fromBuffer(buffer: Buffer | BufferReader): EncryptedNoteL2BlockL2Logs { - const reader = BufferReader.asReader(buffer); - - const logsBufLength = reader.readNumber(); - const serializedTxLogs = reader.readBufferArray(logsBufLength); - - const txLogs = serializedTxLogs.map(logs => EncryptedNoteTxL2Logs.fromBuffer(logs, false)); - return new EncryptedNoteL2BlockL2Logs(txLogs); - } - - /** - * Deserializes logs from a string. - * @param data - The string containing the serialized logs. - * @returns A new `L2BlockL2Logs` object. - */ - public static fromString(data: string): EncryptedNoteL2BlockL2Logs { - return EncryptedNoteL2BlockL2Logs.fromBuffer(hexToBuffer(data)); - } - - /** - * Creates a new `L2BlockL2Logs` object with `numCalls` function logs and `numLogsPerCall` logs in each function - * call. - * @param numTxs - The number of txs in the block. - * @param numCalls - The number of function calls in the tx. - * @param numLogsPerCall - The number of logs emitted in each function call. - * @param logType - The type of logs to generate. - * @returns A new `L2BlockL2Logs` object. - */ - public static random(numTxs: number, numCalls: number, numLogsPerCall: number): EncryptedNoteL2BlockL2Logs { - const txLogs: EncryptedNoteTxL2Logs[] = []; - for (let i = 0; i < numTxs; i++) { - txLogs.push(EncryptedNoteTxL2Logs.random(numCalls, numLogsPerCall)); - } - return new EncryptedNoteL2BlockL2Logs(txLogs); - } - - /** - * Unrolls logs from a set of blocks. - * @param blockLogs - Input logs from a set of blocks. - * @returns Unrolled logs. - */ - public static unrollLogs(blockLogs: (EncryptedNoteL2BlockL2Logs | undefined)[]): EncryptedL2NoteLog[] { - const logs: EncryptedL2NoteLog[] = []; - for (const blockLog of blockLogs) { - if (blockLog) { - for (const txLog of blockLog.txLogs) { - logs.push(...txLog.unrollLogs()); - } - } - } - return logs; - } -} - -export class EncryptedL2BlockL2Logs extends L2BlockL2Logs { - static override get schema() { - return z - .object({ type: z.literal('Encrypted'), txLogs: z.array(EncryptedTxL2Logs.schema) }) - .transform(({ txLogs }) => new EncryptedL2BlockL2Logs(txLogs)); - } - - public get type() { - return 'Encrypted'; - } - - /** - * Deserializes logs from a buffer. - * @param buffer - The buffer containing the serialized logs. - * @returns A new `L2BlockL2Logs` object. - */ - public static fromBuffer(buffer: Buffer | BufferReader): EncryptedL2BlockL2Logs { - const reader = BufferReader.asReader(buffer); - - const logsBufLength = reader.readNumber(); - const serializedTxLogs = reader.readBufferArray(logsBufLength); - - const txLogs = serializedTxLogs.map(logs => EncryptedTxL2Logs.fromBuffer(logs, false)); - return new EncryptedL2BlockL2Logs(txLogs); - } - - /** - * Deserializes logs from a string. - * @param data - The string containing the serialized logs. - * @returns A new `L2BlockL2Logs` object. - */ - public static fromString(data: string): EncryptedL2BlockL2Logs { - return EncryptedL2BlockL2Logs.fromBuffer(hexToBuffer(data)); - } - - /** - * Creates a new `L2BlockL2Logs` object with `numCalls` function logs and `numLogsPerCall` logs in each function - * call. - * @param numTxs - The number of txs in the block. - * @param numCalls - The number of function calls in the tx. - * @param numLogsPerCall - The number of logs emitted in each function call. - * @param logType - The type of logs to generate. - * @returns A new `L2BlockL2Logs` object. - */ - public static random(numTxs: number, numCalls: number, numLogsPerCall: number): EncryptedL2BlockL2Logs { - const txLogs: EncryptedTxL2Logs[] = []; - for (let i = 0; i < numTxs; i++) { - txLogs.push(EncryptedTxL2Logs.random(numCalls, numLogsPerCall)); - } - return new EncryptedL2BlockL2Logs(txLogs); - } - - /** - * Unrolls logs from a set of blocks. - * @param blockLogs - Input logs from a set of blocks. - * @returns Unrolled logs. - */ - public static unrollLogs(blockLogs: (EncryptedL2BlockL2Logs | undefined)[]): EncryptedL2Log[] { - const logs: EncryptedL2Log[] = []; - for (const blockLog of blockLogs) { - if (blockLog) { - for (const txLog of blockLog.txLogs) { - logs.push(...txLog.unrollLogs()); - } - } - } - return logs; - } -} - -export class UnencryptedL2BlockL2Logs extends L2BlockL2Logs { - static override get schema() { +export class UnencryptedL2BlockL2Logs extends L2BlockL2Logs { + static get schema() { return z - .object({ type: z.literal('Unencrypted'), txLogs: z.array(UnencryptedTxL2Logs.schema) }) + .object({ txLogs: z.array(UnencryptedTxL2Logs.schema) }) .transform(({ txLogs }) => new UnencryptedL2BlockL2Logs(txLogs)); } @@ -284,7 +111,6 @@ export class UnencryptedL2BlockL2Logs extends L2BlockL2Logs { * @param numTxs - The number of txs in the block. * @param numCalls - The number of function calls in the tx. * @param numLogsPerCall - The number of logs emitted in each function call. - * @param logType - The type of logs to generate. * @returns A new `L2BlockL2Logs` object. */ public static random(numTxs: number, numCalls: number, numLogsPerCall: number): UnencryptedL2BlockL2Logs { @@ -313,12 +139,12 @@ export class UnencryptedL2BlockL2Logs extends L2BlockL2Logs { } } -export class ContractClass2BlockL2Logs extends L2BlockL2Logs { +export class ContractClass2BlockL2Logs extends L2BlockL2Logs { // This class is identical in methods to UnencryptedL2BlockL2Logs, but its // consistuent ContractClassTxL2Logs must be treated differently, hence new class. - static override get schema() { + static get schema() { return z - .object({ type: z.literal('ContractClass'), txLogs: z.array(ContractClassTxL2Logs.schema) }) + .object({ txLogs: z.array(ContractClassTxL2Logs.schema) }) .transform(({ txLogs }) => new ContractClass2BlockL2Logs(txLogs)); } @@ -356,7 +182,6 @@ export class ContractClass2BlockL2Logs extends L2BlockL2Logs { * @param numTxs - The number of txs in the block. * @param numCalls - The number of function calls in the tx. * @param numLogsPerCall - The number of logs emitted in each function call. - * @param logType - The type of logs to generate. * @returns A new `L2BlockL2Logs` object. */ public static random(numTxs: number, numCalls: number, numLogsPerCall: number): ContractClass2BlockL2Logs { diff --git a/yarn-project/circuit-types/src/logs/l2_logs_source.ts b/yarn-project/circuit-types/src/logs/l2_logs_source.ts index 804130711e4..766eb84cb94 100644 --- a/yarn-project/circuit-types/src/logs/l2_logs_source.ts +++ b/yarn-project/circuit-types/src/logs/l2_logs_source.ts @@ -1,26 +1,19 @@ -import { type Fr } from '@aztec/circuits.js'; +import { type Fr, type PrivateLog } from '@aztec/circuits.js'; import { type GetUnencryptedLogsResponse, type TxScopedL2Log } from './get_logs_response.js'; -import { type L2BlockL2Logs } from './l2_block_l2_logs.js'; import { type LogFilter } from './log_filter.js'; -import { type FromLogType, type LogType } from './log_type.js'; /** * Interface of classes allowing for the retrieval of logs. */ export interface L2LogsSource { /** - * Gets up to `limit` amount of logs starting from `from`. - * @param from - Number of the L2 block to which corresponds the first logs to be returned. - * @param limit - The maximum number of logs to return. - * @param logType - Specifies whether to return encrypted or unencrypted logs. - * @returns The requested logs. + * Retrieves all private logs from up to `limit` blocks, starting from the block number `from`. + * @param from - The block number from which to begin retrieving logs. + * @param limit - The maximum number of blocks to retrieve logs from. + * @returns An array of private logs from the specified range of blocks. */ - getLogs( - from: number, - limit: number, - logType: TLogType, - ): Promise>[]>; + getPrivateLogs(from: number, limit: number): Promise; /** * Gets all logs that match any of the received tags (i.e. logs with their first field equal to a tag). diff --git a/yarn-project/circuit-types/src/logs/log_type.ts b/yarn-project/circuit-types/src/logs/log_type.ts deleted file mode 100644 index 0dddc39a43e..00000000000 --- a/yarn-project/circuit-types/src/logs/log_type.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { type EncryptedL2Log } from './encrypted_l2_log.js'; -import { type EncryptedL2NoteLog } from './encrypted_l2_note_log.js'; -import { type UnencryptedL2Log } from './unencrypted_l2_log.js'; - -/** - * Defines possible log types. - */ -export enum LogType { - NOTEENCRYPTED, - ENCRYPTED, - UNENCRYPTED, -} - -export type FromLogType = TLogType extends LogType.UNENCRYPTED - ? UnencryptedL2Log - : TLogType extends LogType.ENCRYPTED - ? EncryptedL2Log - : EncryptedL2NoteLog; diff --git a/yarn-project/circuit-types/src/logs/tx_l2_logs.test.ts b/yarn-project/circuit-types/src/logs/tx_l2_logs.test.ts index 6bec9823692..9397740891d 100644 --- a/yarn-project/circuit-types/src/logs/tx_l2_logs.test.ts +++ b/yarn-project/circuit-types/src/logs/tx_l2_logs.test.ts @@ -1,14 +1,8 @@ import { jsonStringify } from '@aztec/foundation/json-rpc'; -import { ContractClassTxL2Logs, EncryptedNoteTxL2Logs, EncryptedTxL2Logs, UnencryptedTxL2Logs } from './tx_l2_logs.js'; - -function shouldBehaveLikeTxL2Logs( - TxL2Logs: - | typeof EncryptedNoteTxL2Logs - | typeof UnencryptedTxL2Logs - | typeof EncryptedTxL2Logs - | typeof ContractClassTxL2Logs, -) { +import { ContractClassTxL2Logs, UnencryptedTxL2Logs } from './tx_l2_logs.js'; + +function shouldBehaveLikeTxL2Logs(TxL2Logs: typeof UnencryptedTxL2Logs | typeof ContractClassTxL2Logs) { describe(TxL2Logs.name, () => { it('can encode TxL2Logs to buffer and back', () => { const l2Logs = TxL2Logs.name == 'ContractClassTxL2Logs' ? TxL2Logs.random(1, 1) : TxL2Logs.random(4, 2); @@ -33,13 +27,7 @@ function shouldBehaveLikeTxL2Logs( const buffer = l2Logs.toBuffer(); const recovered = TxL2Logs.fromBuffer(buffer); - if (TxL2Logs.name == 'EncryptedTxL2Logs') { - // For event logs, we don't 'count' the maskedContractAddress as part of the - // log length, since it's just for siloing later on - expect(recovered.getSerializedLength()).toEqual(buffer.length - 8 * 32); - } else { - expect(recovered.getSerializedLength()).toEqual(buffer.length); - } + expect(recovered.getSerializedLength()).toEqual(buffer.length); }); it('getKernelLength returns the correct length', () => { @@ -52,7 +40,5 @@ function shouldBehaveLikeTxL2Logs( }); } -shouldBehaveLikeTxL2Logs(EncryptedNoteTxL2Logs); shouldBehaveLikeTxL2Logs(UnencryptedTxL2Logs); -shouldBehaveLikeTxL2Logs(EncryptedTxL2Logs); shouldBehaveLikeTxL2Logs(ContractClassTxL2Logs); diff --git a/yarn-project/circuit-types/src/logs/tx_l2_logs.ts b/yarn-project/circuit-types/src/logs/tx_l2_logs.ts index b27b2346f02..8913fd7659e 100644 --- a/yarn-project/circuit-types/src/logs/tx_l2_logs.ts +++ b/yarn-project/circuit-types/src/logs/tx_l2_logs.ts @@ -2,37 +2,27 @@ import { Fr, type LogHash, MAX_CONTRACT_CLASS_LOGS_PER_TX, - MAX_ENCRYPTED_LOGS_PER_TX, - MAX_NOTE_ENCRYPTED_LOGS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX, type ScopedLogHash, } from '@aztec/circuits.js'; -import { AztecAddress } from '@aztec/foundation/aztec-address'; import { sha256Trunc } from '@aztec/foundation/crypto'; import { BufferReader, prefixBufferWithLength } from '@aztec/foundation/serialize'; import isEqual from 'lodash.isequal'; import { z } from 'zod'; -import { type EncryptedL2Log } from './encrypted_l2_log.js'; -import { type EncryptedL2NoteLog } from './encrypted_l2_note_log.js'; -import { - EncryptedFunctionL2Logs, - EncryptedNoteFunctionL2Logs, - type FunctionL2Logs, - UnencryptedFunctionL2Logs, -} from './function_l2_logs.js'; +import { UnencryptedFunctionL2Logs } from './function_l2_logs.js'; import { type UnencryptedL2Log } from './unencrypted_l2_log.js'; /** * Data container of logs emitted in 1 tx. */ -export abstract class TxL2Logs { +export abstract class TxL2Logs { abstract hash(): Buffer; constructor( /** * An array containing logs emitted in individual function invocations in this tx. */ - public readonly functionLogs: FunctionL2Logs[], + public readonly functionLogs: UnencryptedFunctionL2Logs[], ) {} /** @@ -72,7 +62,7 @@ export abstract class TxL2Logs[]) { + public addFunctionLogs(functionLogs: UnencryptedFunctionL2Logs[]) { this.functionLogs.push(...functionLogs); } @@ -80,7 +70,7 @@ export abstract class TxL2Logs functionLog.logs); } @@ -89,7 +79,7 @@ export abstract class TxL2Logs): boolean { + public equals(other: TxL2Logs): boolean { return isEqual(this, other); } @@ -100,7 +90,7 @@ export abstract class TxL2Logs): TxL2Logs { + public filter(logHashes: LogHash[], output: TxL2Logs): TxL2Logs { for (const fnLogs of this.functionLogs) { let include = false; for (const log of fnLogs.logs) { @@ -122,15 +112,13 @@ export abstract class TxL2Logs): TxL2Logs { + public filterScoped(scopedLogHashes: ScopedLogHash[], output: TxL2Logs): TxL2Logs { for (const fnLogs of this.functionLogs) { let include = false; for (const log of fnLogs.logs) { let contractAddress: any; if ('contractAddress' in log) { contractAddress = log.contractAddress; - } else if ('maskedContractAddress' in log) { - contractAddress = new AztecAddress(log.maskedContractAddress); } else { throw new Error("Can't run filterScoped in logs without contractAddress or maskedContractAddress"); } @@ -150,7 +138,7 @@ export abstract class TxL2Logs { +export class UnencryptedTxL2Logs extends TxL2Logs { static get schema() { return z .object({ functionLogs: z.array(UnencryptedFunctionL2Logs.schema) }) @@ -183,7 +171,6 @@ export class UnencryptedTxL2Logs extends TxL2Logs { * Creates a new `TxL2Logs` object with `numCalls` function logs and `numLogsPerCall` logs in each invocation. * @param numCalls - The number of function calls in the tx. * @param numLogsPerCall - The number of logs emitted in each function call. - * @param logType - The type of logs to generate. * @returns A new `TxL2Logs` object. */ public static random(numCalls: number, numLogsPerCall: number): UnencryptedTxL2Logs { @@ -234,174 +221,7 @@ export class UnencryptedTxL2Logs extends TxL2Logs { } } -export class EncryptedNoteTxL2Logs extends TxL2Logs { - static get schema() { - return z - .object({ functionLogs: z.array(EncryptedNoteFunctionL2Logs.schema) }) - .transform(({ functionLogs }) => new EncryptedNoteTxL2Logs(functionLogs)); - } - - /** Creates an empty instance. */ - public static empty() { - return new EncryptedNoteTxL2Logs([]); - } - - /** - * Deserializes logs from a buffer. - * @param buf - The buffer containing the serialized logs. - * @param isLengthPrefixed - Whether the buffer is prefixed with 4 bytes for its total length. - * @returns A new L2Logs object. - */ - public static fromBuffer(buf: Buffer | BufferReader, isLengthPrefixed = true): EncryptedNoteTxL2Logs { - const reader = BufferReader.asReader(buf); - - // If the buffer is length prefixed use the length to read the array. Otherwise, the entire buffer is consumed. - const logsBufLength = isLengthPrefixed ? reader.readNumber() : -1; - const serializedFunctionLogs = reader.readBufferArray(logsBufLength); - - const functionLogs = serializedFunctionLogs.map(logs => EncryptedNoteFunctionL2Logs.fromBuffer(logs, false)); - return new EncryptedNoteTxL2Logs(functionLogs); - } - - /** - * Creates a new `TxL2Logs` object with `numCalls` function logs and `numLogsPerCall` logs in each invocation. - * @param numCalls - The number of function calls in the tx. - * @param numLogsPerCall - The number of logs emitted in each function call. - * @param logType - The type of logs to generate. - * @returns A new `TxL2Logs` object. - */ - public static random(numCalls: number, numLogsPerCall: number): EncryptedNoteTxL2Logs { - if (numCalls * numLogsPerCall > MAX_NOTE_ENCRYPTED_LOGS_PER_TX) { - throw new Error( - `Trying to create ${numCalls * numLogsPerCall} logs for one tx (max: ${MAX_NOTE_ENCRYPTED_LOGS_PER_TX})`, - ); - } - const functionLogs: EncryptedNoteFunctionL2Logs[] = []; - for (let i = 0; i < numCalls; i++) { - functionLogs.push(EncryptedNoteFunctionL2Logs.random(numLogsPerCall)); - } - return new EncryptedNoteTxL2Logs(functionLogs); - } - - /** - * Computes encrypted logs hash as is done in the kernel and decoder contract. - * @param logs - Logs to be hashed. - * @returns The hash of the logs. - * Note: This is a TS implementation of `computeKernelNoteEncryptedLogsHash` function in Decoder.sol. See that function documentation - * for more details. - */ - public override hash(): Buffer { - return EncryptedNoteTxL2Logs.hashNoteLogs(this.unrollLogs().map(log => log.hash())); - } - - /** - * Hashes encrypted note logs hashes as in the same way as the base rollup would. - * @param siloedLogHashes - The note log hashes - * @returns The hash of the log hashes. - */ - public static hashNoteLogs(logHashes: Buffer[]): Buffer { - if (logHashes.length == 0) { - return Buffer.alloc(32); - } - - let allSiloedLogHashes = Buffer.alloc(0); - for (const siloedLogHash of logHashes) { - allSiloedLogHashes = Buffer.concat([allSiloedLogHashes, siloedLogHash]); - } - // pad the end of logs with 0s - for (let i = 0; i < MAX_NOTE_ENCRYPTED_LOGS_PER_TX - logHashes.length; i++) { - allSiloedLogHashes = Buffer.concat([allSiloedLogHashes, Buffer.alloc(32)]); - } - - return sha256Trunc(allSiloedLogHashes); - } -} - -export class EncryptedTxL2Logs extends TxL2Logs { - static get schema() { - return z - .object({ functionLogs: z.array(EncryptedFunctionL2Logs.schema) }) - .transform(({ functionLogs }) => new EncryptedTxL2Logs(functionLogs)); - } - - /** Creates an empty instance. */ - public static empty() { - return new EncryptedTxL2Logs([]); - } - - /** - * Deserializes logs from a buffer. - * @param buf - The buffer containing the serialized logs. - * @param isLengthPrefixed - Whether the buffer is prefixed with 4 bytes for its total length. - * @returns A new L2Logs object. - */ - public static fromBuffer(buf: Buffer | BufferReader, isLengthPrefixed = true): EncryptedTxL2Logs { - const reader = BufferReader.asReader(buf); - - // If the buffer is length prefixed use the length to read the array. Otherwise, the entire buffer is consumed. - const logsBufLength = isLengthPrefixed ? reader.readNumber() : -1; - const serializedFunctionLogs = reader.readBufferArray(logsBufLength); - - const functionLogs = serializedFunctionLogs.map(logs => EncryptedFunctionL2Logs.fromBuffer(logs, false)); - return new EncryptedTxL2Logs(functionLogs); - } - - /** - * Creates a new `TxL2Logs` object with `numCalls` function logs and `numLogsPerCall` logs in each invocation. - * @param numCalls - The number of function calls in the tx. - * @param numLogsPerCall - The number of logs emitted in each function call. - * @param logType - The type of logs to generate. - * @returns A new `TxL2Logs` object. - */ - public static random(numCalls: number, numLogsPerCall: number): EncryptedTxL2Logs { - if (numCalls * numLogsPerCall > MAX_ENCRYPTED_LOGS_PER_TX) { - throw new Error( - `Trying to create ${numCalls * numLogsPerCall} logs for one tx (max: ${MAX_ENCRYPTED_LOGS_PER_TX})`, - ); - } - const functionLogs: EncryptedFunctionL2Logs[] = []; - for (let i = 0; i < numCalls; i++) { - functionLogs.push(EncryptedFunctionL2Logs.random(numLogsPerCall)); - } - return new EncryptedTxL2Logs(functionLogs); - } - - /** - * Computes encrypted logs hash as is done in the kernel and decoder contract. - * @param logs - Logs to be hashed. - * @returns The hash of the logs. - * Note: This is a TS implementation of `computeKernelEncryptedLogsHash` function in Decoder.sol. See that function documentation - * for more details. - */ - public override hash(): Buffer { - const unrolledLogs = this.unrollLogs(); - return EncryptedTxL2Logs.hashSiloedLogs(unrolledLogs.map(log => log.getSiloedHash())); - } - - /** - * Hashes siloed unencrypted logs as in the same way as the base rollup would. - * @param siloedLogHashes - The siloed log hashes - * @returns The hash of the logs. - */ - public static hashSiloedLogs(siloedLogHashes: Buffer[]): Buffer { - if (siloedLogHashes.length == 0) { - return Buffer.alloc(32); - } - - let allSiloedLogHashes = Buffer.alloc(0); - for (const siloedLogHash of siloedLogHashes) { - allSiloedLogHashes = Buffer.concat([allSiloedLogHashes, siloedLogHash]); - } - // pad the end of logs with 0s - for (let i = 0; i < MAX_UNENCRYPTED_LOGS_PER_TX - siloedLogHashes.length; i++) { - allSiloedLogHashes = Buffer.concat([allSiloedLogHashes, Buffer.alloc(32)]); - } - - return sha256Trunc(allSiloedLogHashes); - } -} - -export class ContractClassTxL2Logs extends TxL2Logs { +export class ContractClassTxL2Logs extends TxL2Logs { static get schema() { return z .object({ functionLogs: z.array(UnencryptedFunctionL2Logs.schema) }) @@ -434,7 +254,6 @@ export class ContractClassTxL2Logs extends TxL2Logs { * Creates a new `TxL2Logs` object with `numCalls` function logs and `numLogsPerCall` logs in each invocation. * @param numCalls - The number of function calls in the tx. * @param numLogsPerCall - The number of logs emitted in each function call. - * @param logType - The type of logs to generate. * @returns A new `TxL2Logs` object. */ public static random(numCalls: number, numLogsPerCall: number): ContractClassTxL2Logs { diff --git a/yarn-project/circuit-types/src/mocks.ts b/yarn-project/circuit-types/src/mocks.ts index 2c03510d2ee..4d38c4bc986 100644 --- a/yarn-project/circuit-types/src/mocks.ts +++ b/yarn-project/circuit-types/src/mocks.ts @@ -6,16 +6,12 @@ import { EthAddress, GasFees, GasSettings, - LogHash, - MAX_ENCRYPTED_LOGS_PER_TX, MAX_ENQUEUED_CALLS_PER_TX, - MAX_NOTE_ENCRYPTED_LOGS_PER_TX, Nullifier, PartialPrivateTailPublicInputsForPublic, PrivateCircuitPublicInputs, PrivateKernelTailCircuitPublicInputs, PrivateToPublicAccumulatedDataBuilder, - ScopedLogHash, SerializableContractInstance, computeContractAddressFromInstance, computeContractClassId, @@ -24,20 +20,14 @@ import { import { computeVarArgsHash } from '@aztec/circuits.js/hash'; import { makeCombinedConstantData, makeGas, makePublicCallRequest } from '@aztec/circuits.js/testing'; import { type ContractArtifact, NoteSelector } from '@aztec/foundation/abi'; -import { padArrayEnd, times } from '@aztec/foundation/collection'; +import { times } from '@aztec/foundation/collection'; import { randomBigInt, randomBytes, randomInt } from '@aztec/foundation/crypto'; import { Signature } from '@aztec/foundation/eth-signature'; import { Fr } from '@aztec/foundation/fields'; -import { - ContractClassTxL2Logs, - EncryptedNoteTxL2Logs, - EncryptedTxL2Logs, - Note, - UnencryptedTxL2Logs, -} from './logs/index.js'; +import { ContractClassTxL2Logs, Note, UnencryptedTxL2Logs } from './logs/index.js'; import { ExtendedNote, UniqueNote } from './notes/index.js'; -import { CountedLog, CountedPublicExecutionRequest, PrivateExecutionResult } from './private_execution_result.js'; +import { CountedPublicExecutionRequest, PrivateExecutionResult } from './private_execution_result.js'; import { EpochProofQuote } from './prover_coordination/epoch_proof_quote.js'; import { EpochProofQuotePayload } from './prover_coordination/epoch_proof_quote_payload.js'; import { PublicExecutionRequest } from './public_execution_request.js'; @@ -48,7 +38,6 @@ export const randomTxHash = (): TxHash => new TxHash(randomBytes(32)); export const mockPrivateExecutionResult = ( seed = 1, - hasLogs = false, numberOfNonRevertiblePublicCallRequests = MAX_ENQUEUED_CALLS_PER_TX / 2, numberOfRevertiblePublicCallRequests = MAX_ENQUEUED_CALLS_PER_TX / 2, hasPublicTeardownCallRequest = false, @@ -88,29 +77,17 @@ export const mockPrivateExecutionResult = ( enqueuedPublicFunctionCalls.map((call, index) => new CountedPublicExecutionRequest(call, index)), publicTeardownFunctionCall, [], - hasLogs - ? EncryptedTxL2Logs.random(2, 3) - .unrollLogs() - .map((log, index) => new CountedLog(log, index)) - : [], - hasLogs - ? ContractClassTxL2Logs.random(1, 1) - .unrollLogs() - .map((log, index) => new CountedLog(log, index)) - : [], ); }; export const mockTx = ( seed = 1, { - hasLogs = false, numberOfNonRevertiblePublicCallRequests = MAX_ENQUEUED_CALLS_PER_TX / 2, numberOfRevertiblePublicCallRequests = MAX_ENQUEUED_CALLS_PER_TX / 2, hasPublicTeardownCallRequest = false, feePayer = AztecAddress.ZERO, }: { - hasLogs?: boolean; numberOfNonRevertiblePublicCallRequests?: number; numberOfRevertiblePublicCallRequests?: number; hasPublicTeardownCallRequest?: boolean; @@ -124,15 +101,14 @@ export const mockTx = ( const isForPublic = totalPublicCallRequests > 0; const data = PrivateKernelTailCircuitPublicInputs.empty(); const firstNullifier = new Nullifier(new Fr(seed + 1), 0, Fr.ZERO); - const noteEncryptedLogs = EncryptedNoteTxL2Logs.empty(); // Mock seems to have no new notes => no note logs - const encryptedLogs = hasLogs ? EncryptedTxL2Logs.random(2, 3) : EncryptedTxL2Logs.empty(); // 2 priv function invocations creating 3 encrypted logs each - const contractClassLog = hasLogs ? ContractClassTxL2Logs.random(1, 1) : ContractClassTxL2Logs.empty(); data.constants.txContext.gasSettings = GasSettings.default({ maxFeesPerGas: new GasFees(10, 10) }); data.feePayer = feePayer; let enqueuedPublicFunctionCalls: PublicExecutionRequest[] = []; let publicTeardownFunctionCall = PublicExecutionRequest.empty(); - if (isForPublic) { + if (!isForPublic) { + data.forRollup!.end.nullifiers[0] = firstNullifier.value; + } else { data.forRollup = undefined; data.forPublic = PartialPrivateTailPublicInputsForPublic.empty(); @@ -162,79 +138,13 @@ export const mockTx = ( data.forPublic.revertibleAccumulatedData = revertibleBuilder .withPublicCallRequests(publicCallRequests.slice(0, numberOfRevertiblePublicCallRequests)) .build(); - - if (hasLogs) { - let i = 1; // 0 used in first nullifier - let nonRevertibleIndex = 0; - let revertibleIndex = 0; - let functionCount = 0; - encryptedLogs.functionLogs.forEach(functionLog => { - functionLog.logs.forEach(log => { - // ts complains if we dont check .forPublic here, even though it is defined ^ - if (data.forPublic) { - const hash = new ScopedLogHash( - new LogHash( - Fr.fromBuffer(log.hash()), - i++, - // +4 for encoding the length of the buffer - new Fr(log.length + 4), - ), - new AztecAddress(log.maskedContractAddress), - ); - // make the first log non-revertible - if (functionCount === 0) { - data.forPublic.nonRevertibleAccumulatedData.encryptedLogsHashes[nonRevertibleIndex++] = hash; - } else { - data.forPublic.revertibleAccumulatedData.encryptedLogsHashes[revertibleIndex++] = hash; - } - } - }); - functionCount++; - }); - // We have a single contract class log - const contractClassUnencryptedLog = contractClassLog.functionLogs[0].logs[0]; - if (data.forPublic) { - const hash = new ScopedLogHash( - new LogHash( - Fr.fromBuffer(contractClassUnencryptedLog.hash()), - i++, - // +4 for encoding the length of the buffer - new Fr(contractClassUnencryptedLog.length + 4), - ), - contractClassUnencryptedLog.contractAddress, - ); - data.forPublic.nonRevertibleAccumulatedData.contractClassLogsHashes[0] = hash; - } - } - } else { - data.forRollup!.end.nullifiers[0] = firstNullifier.value; - data.forRollup!.end.noteEncryptedLogsHashes = padArrayEnd( - noteEncryptedLogs.unrollLogs().map(log => new LogHash(Fr.fromBuffer(log.hash()), 0, new Fr(log.length))), - LogHash.empty(), - MAX_NOTE_ENCRYPTED_LOGS_PER_TX, - ); - data.forRollup!.end.encryptedLogsHashes = padArrayEnd( - encryptedLogs - .unrollLogs() - .map( - log => - new ScopedLogHash( - new LogHash(Fr.fromBuffer(log.hash()), 0, new Fr(log.length)), - new AztecAddress(log.maskedContractAddress), - ), - ), - ScopedLogHash.empty(), - MAX_ENCRYPTED_LOGS_PER_TX, - ); } const tx = new Tx( data, ClientIvcProof.empty(), - noteEncryptedLogs, - encryptedLogs, UnencryptedTxL2Logs.empty(), - contractClassLog, + ContractClassTxL2Logs.empty(), enqueuedPublicFunctionCalls, publicTeardownFunctionCall, ); @@ -242,12 +152,12 @@ export const mockTx = ( return tx; }; -export const mockTxForRollup = (seed = 1, { hasLogs = false }: { hasLogs?: boolean } = {}) => - mockTx(seed, { hasLogs, numberOfNonRevertiblePublicCallRequests: 0, numberOfRevertiblePublicCallRequests: 0 }); +export const mockTxForRollup = (seed = 1) => + mockTx(seed, { numberOfNonRevertiblePublicCallRequests: 0, numberOfRevertiblePublicCallRequests: 0 }); -export const mockSimulatedTx = (seed = 1, hasLogs = true) => { - const privateExecutionResult = mockPrivateExecutionResult(seed, hasLogs); - const tx = mockTx(seed, { hasLogs }); +export const mockSimulatedTx = (seed = 1) => { + const privateExecutionResult = mockPrivateExecutionResult(seed); + const tx = mockTx(seed); const output = new PublicSimulationOutput( undefined, makeCombinedConstantData(), diff --git a/yarn-project/circuit-types/src/private_execution_result.test.ts b/yarn-project/circuit-types/src/private_execution_result.test.ts index 1b3a97f766e..91d9b25ead3 100644 --- a/yarn-project/circuit-types/src/private_execution_result.test.ts +++ b/yarn-project/circuit-types/src/private_execution_result.test.ts @@ -23,8 +23,6 @@ function emptyExecutionResult(): PrivateExecutionResult { [], PublicExecutionRequest.empty(), [], - [], - [], ); } diff --git a/yarn-project/circuit-types/src/private_execution_result.ts b/yarn-project/circuit-types/src/private_execution_result.ts index 893ecc0ad4f..2690bc779ad 100644 --- a/yarn-project/circuit-types/src/private_execution_result.ts +++ b/yarn-project/circuit-types/src/private_execution_result.ts @@ -8,15 +8,7 @@ import { type FieldsOf } from '@aztec/foundation/types'; import { z } from 'zod'; -import { - EncryptedFunctionL2Logs, - EncryptedL2Log, - EncryptedL2NoteLog, - EncryptedNoteFunctionL2Logs, - Note, - UnencryptedFunctionL2Logs, - UnencryptedL2Log, -} from './logs/index.js'; +import { Note, UnencryptedFunctionL2Logs, UnencryptedL2Log } from './logs/index.js'; import { PublicExecutionRequest } from './public_execution_request.js'; /** @@ -51,32 +43,20 @@ export class NoteAndSlot { } } -export class CountedLog implements IsEmpty { - constructor(public log: TLog, public counter: number) {} +export class CountedContractClassLog implements IsEmpty { + constructor(public log: UnencryptedL2Log, public counter: number) {} - static get schema(): ZodFor> { - return z - .object({ - log: z.union([EncryptedL2Log.schema, EncryptedL2NoteLog.schema, UnencryptedL2Log.schema]), - counter: schemas.Integer, - }) - .transform(CountedLog.from); - } - - static schemaFor(log: { schema: ZodFor }) { + static get schema() { return z .object({ - log: log.schema, + log: UnencryptedL2Log.schema, counter: schemas.Integer, }) - .transform(({ log, counter }) => new CountedLog(log!, counter) as CountedLog) as ZodFor>; + .transform(CountedContractClassLog.from); } - static from(fields: { - log: TLog; - counter: number; - }): CountedLog { - return new CountedLog(fields.log, fields.counter); + static from(fields: { log: UnencryptedL2Log; counter: number }) { + return new CountedContractClassLog(fields.log, fields.counter); } isEmpty(): boolean { @@ -84,26 +64,6 @@ export class CountedLog { - constructor(log: EncryptedL2NoteLog, counter: number, public noteHashCounter: number) { - super(log, counter); - } - - static override get schema(): ZodFor { - return z - .object({ - log: EncryptedL2NoteLog.schema, - counter: schemas.Integer, - noteHashCounter: schemas.Integer, - }) - .transform(({ log, counter, noteHashCounter }) => new CountedNoteLog(log, counter, noteHashCounter)); - } - - static random() { - return new CountedNoteLog(EncryptedL2NoteLog.random(), randomInt(10), randomInt(10)); - } -} - export class CountedPublicExecutionRequest { constructor(public request: PublicExecutionRequest, public counter: number) {} @@ -158,21 +118,11 @@ export class PrivateExecutionResult { public enqueuedPublicFunctionCalls: CountedPublicExecutionRequest[], /** Public function execution requested for teardown */ public publicTeardownFunctionCall: PublicExecutionRequest, - /** - * Encrypted note logs emitted during execution of this function call. - * Note: These are preimages to `noteEncryptedLogsHashes`. - */ - public noteEncryptedLogs: CountedNoteLog[], - /** - * Encrypted logs emitted during execution of this function call. - * Note: These are preimages to `encryptedLogsHashes`. - */ - public encryptedLogs: CountedLog[], /** * Contract class logs emitted during execution of this function call. * Note: These are preimages to `contractClassLogsHashes`. */ - public contractClassLogs: CountedLog[], + public contractClassLogs: CountedContractClassLog[], ) {} static get schema(): ZodFor { @@ -189,9 +139,7 @@ export class PrivateExecutionResult { nestedExecutions: z.array(z.lazy(() => PrivateExecutionResult.schema)), enqueuedPublicFunctionCalls: z.array(CountedPublicExecutionRequest.schema), publicTeardownFunctionCall: PublicExecutionRequest.schema, - noteEncryptedLogs: z.array(CountedNoteLog.schema), - encryptedLogs: z.array(CountedLog.schemaFor(EncryptedL2Log)), - contractClassLogs: z.array(CountedLog.schemaFor(UnencryptedL2Log)), + contractClassLogs: z.array(CountedContractClassLog.schema), }) .transform(PrivateExecutionResult.from); } @@ -209,8 +157,6 @@ export class PrivateExecutionResult { fields.nestedExecutions, fields.enqueuedPublicFunctionCalls, fields.publicTeardownFunctionCall, - fields.noteEncryptedLogs, - fields.encryptedLogs, fields.contractClassLogs, ); } @@ -228,9 +174,7 @@ export class PrivateExecutionResult { times(nested, () => PrivateExecutionResult.random(0)), [CountedPublicExecutionRequest.random()], PublicExecutionRequest.random(), - [CountedNoteLog.random()], - [new CountedLog(EncryptedL2Log.random(), randomInt(10))], - [new CountedLog(UnencryptedL2Log.random(), randomInt(10))], + [new CountedContractClassLog(UnencryptedL2Log.random(), randomInt(10))], ); } } @@ -253,68 +197,12 @@ export function collectNoteHashNullifierCounterMap( return accum; } -/** - * Collect all encrypted logs across all nested executions. - * @param execResult - The topmost execution result. - * @returns All encrypted logs. - */ -function collectNoteEncryptedLogs( - execResult: PrivateExecutionResult, - noteHashNullifierCounterMap: Map, - minRevertibleSideEffectCounter: number, -): CountedLog[] { - return [ - execResult.noteEncryptedLogs.filter(noteLog => { - const nullifierCounter = noteHashNullifierCounterMap.get(noteLog.noteHashCounter); - return ( - nullifierCounter === undefined || - (noteLog.noteHashCounter < minRevertibleSideEffectCounter && nullifierCounter >= minRevertibleSideEffectCounter) - ); - }), - ...execResult.nestedExecutions.flatMap(res => - collectNoteEncryptedLogs(res, noteHashNullifierCounterMap, minRevertibleSideEffectCounter), - ), - ].flat(); -} - -/** - * Collect all encrypted logs across all nested executions and sorts by counter. - * @param execResult - The topmost execution result. - * @returns All encrypted logs. - */ -export function collectSortedNoteEncryptedLogs(execResult: PrivateExecutionResult): EncryptedNoteFunctionL2Logs { - const noteHashNullifierCounterMap = collectNoteHashNullifierCounterMap(execResult); - const minRevertibleSideEffectCounter = getFinalMinRevertibleSideEffectCounter(execResult); - const allLogs = collectNoteEncryptedLogs(execResult, noteHashNullifierCounterMap, minRevertibleSideEffectCounter); - const sortedLogs = sortByCounter(allLogs); - return new EncryptedNoteFunctionL2Logs(sortedLogs.map(l => l.log)); -} -/** - * Collect all encrypted logs across all nested executions. - * @param execResult - The topmost execution result. - * @returns All encrypted logs. - */ -function collectEncryptedLogs(execResult: PrivateExecutionResult): CountedLog[] { - return [execResult.encryptedLogs, ...execResult.nestedExecutions.flatMap(collectEncryptedLogs)].flat(); -} - -/** - * Collect all encrypted logs across all nested executions and sorts by counter. - * @param execResult - The topmost execution result. - * @returns All encrypted logs. - */ -export function collectSortedEncryptedLogs(execResult: PrivateExecutionResult): EncryptedFunctionL2Logs { - const allLogs = collectEncryptedLogs(execResult); - const sortedLogs = sortByCounter(allLogs); - return new EncryptedFunctionL2Logs(sortedLogs.map(l => l.log)); -} - /** * Collect all contract class logs across all nested executions. * @param execResult - The topmost execution result. * @returns All contract class logs. */ -function collectContractClassLogs(execResult: PrivateExecutionResult): CountedLog[] { +function collectContractClassLogs(execResult: PrivateExecutionResult): CountedContractClassLog[] { return [execResult.contractClassLogs, ...execResult.nestedExecutions.flatMap(collectContractClassLogs)].flat(); } diff --git a/yarn-project/circuit-types/src/stats/stats.ts b/yarn-project/circuit-types/src/stats/stats.ts index a200e9a588c..279e70899b2 100644 --- a/yarn-project/circuit-types/src/stats/stats.ts +++ b/yarn-project/circuit-types/src/stats/stats.ts @@ -16,12 +16,8 @@ export type L2BlockStats = { txCount: number; /** Number of the L2 block. */ blockNumber: number; - /** Number of encrypted logs. */ - encryptedLogCount?: number; /** Number of unencrypted logs. */ unencryptedLogCount?: number; - /** Serialized size of encrypted logs. */ - encryptedLogSize?: number; /** Serialized size of unencrypted logs. */ unencryptedLogSize?: number; }; @@ -209,22 +205,16 @@ export type TxStats = { size: number; /** Size of the proof. */ proofSize: number; - /** Number of note encrypted logs. */ - noteEncryptedLogCount: number; - /** Number of encrypted logs. */ - encryptedLogCount: number; /** Number of unencrypted logs. */ unencryptedLogCount: number; - /** Serialized size of note encrypted logs. */ - noteEncryptedLogSize: number; - /** Serialized size of encrypted logs. */ - encryptedLogSize: number; /** Serialized size of unencrypted logs. */ unencryptedLogSize: number; - /** New commitments count */ - newCommitmentCount: number; - /** New nullifier count */ - newNullifierCount: number; + /** Number of note hashes */ + noteHashCount: number; + /** Number of nullifiers */ + nullifierCount: number; + /** Number of private logs */ + privateLogCount: number; /** How many classes were registered through the canonical class registerer. */ classRegisteredCount: number; /** Serialized size of contract class logs. */ diff --git a/yarn-project/circuit-types/src/test/factories.ts b/yarn-project/circuit-types/src/test/factories.ts index bd303ecd831..1a90a045171 100644 --- a/yarn-project/circuit-types/src/test/factories.ts +++ b/yarn-project/circuit-types/src/test/factories.ts @@ -10,7 +10,6 @@ import { GasSettings, GlobalVariables, type Header, - LogHash, MAX_NULLIFIERS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicCircuitPublicInputs, @@ -18,6 +17,7 @@ import { RevertCode, ScopedLogHash, TxConstantData, + mergeAccumulatedData, } from '@aztec/circuits.js'; import { makeCombinedAccumulatedData, makePrivateToPublicAccumulatedData } from '@aztec/circuits.js/testing'; import { makeTuple } from '@aztec/foundation/array'; @@ -97,6 +97,7 @@ export function makeBloatedProcessedTx({ globalVariables, ); } else { + const nonRevertibleData = tx.data.forPublic!.nonRevertibleAccumulatedData; const revertibleData = makePrivateToPublicAccumulatedData(seed + 0x1000); revertibleData.nullifiers[MAX_NULLIFIERS_PER_TX - 1] = Fr.ZERO; // Leave one space for the tx hash nullifier in nonRevertibleAccumulatedData. @@ -108,7 +109,11 @@ export function makeBloatedProcessedTx({ const avmOutput = AvmCircuitPublicInputs.empty(); avmOutput.globalVariables = globalVariables; avmOutput.accumulatedData.noteHashes = revertibleData.noteHashes; - avmOutput.accumulatedData.nullifiers = revertibleData.nullifiers; + avmOutput.accumulatedData.nullifiers = mergeAccumulatedData( + nonRevertibleData.nullifiers, + revertibleData.nullifiers, + MAX_NULLIFIERS_PER_TX, + ); avmOutput.accumulatedData.l2ToL1Msgs = revertibleData.l2ToL1Msgs; avmOutput.accumulatedData.publicDataWrites = makeTuple( MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, @@ -144,14 +149,7 @@ export function makeBloatedProcessedTx({ } // Remove all logs as it's ugly to mock them at the moment and we are going to change it to have the preimages be part of the public inputs soon. -function clearLogs(data: { - noteEncryptedLogsHashes: LogHash[]; - encryptedLogsHashes: ScopedLogHash[]; - unencryptedLogsHashes?: ScopedLogHash[]; - contractClassLogsHashes: ScopedLogHash[]; -}) { - data.noteEncryptedLogsHashes.forEach((_, i) => (data.noteEncryptedLogsHashes[i] = LogHash.empty())); - data.encryptedLogsHashes.forEach((_, i) => (data.encryptedLogsHashes[i] = ScopedLogHash.empty())); +function clearLogs(data: { unencryptedLogsHashes?: ScopedLogHash[]; contractClassLogsHashes: ScopedLogHash[] }) { data.unencryptedLogsHashes?.forEach((_, i) => (data.unencryptedLogsHashes![i] = ScopedLogHash.empty())); data.contractClassLogsHashes.forEach((_, i) => (data.contractClassLogsHashes[i] = ScopedLogHash.empty())); } diff --git a/yarn-project/circuit-types/src/tx/processed_tx.ts b/yarn-project/circuit-types/src/tx/processed_tx.ts index 69da14b2f12..b52006846b2 100644 --- a/yarn-project/circuit-types/src/tx/processed_tx.ts +++ b/yarn-project/circuit-types/src/tx/processed_tx.ts @@ -138,12 +138,9 @@ export function makeProcessedTxFromPrivateOnlyTx( .map(message => siloL2ToL1Message(message, constants.txContext.version, constants.txContext.chainId)) .filter(h => !h.isZero()), publicDataWrites, - data.end.noteEncryptedLogPreimagesLength, - data.end.encryptedLogPreimagesLength, + data.end.privateLogs.filter(l => !l.isEmpty()), data.end.unencryptedLogPreimagesLength, data.end.contractClassLogPreimagesLength, - tx.noteEncryptedLogs, - tx.encryptedLogs, tx.unencryptedLogs, tx.contractClassLogs, ); @@ -188,8 +185,11 @@ export function makeProcessedTxFromTxWithPublicCalls( } } - const noteEncryptedLogPreimagesLength = tx.noteEncryptedLogs.getKernelLength(); - const encryptedLogPreimagesLength = tx.encryptedLogs.getKernelLength(); + const privateLogs = [ + ...tx.data.forPublic!.nonRevertibleAccumulatedData.privateLogs, + ...(revertCode.isOK() ? tx.data.forPublic!.revertibleAccumulatedData.privateLogs : []), + ].filter(l => !l.isEmpty()); + // Unencrypted logs emitted from public functions are inserted to tx.unencryptedLogs directly :( const unencryptedLogPreimagesLength = tx.unencryptedLogs.getKernelLength(); const contractClassLogPreimagesLength = tx.contractClassLogs.getKernelLength(); @@ -203,12 +203,9 @@ export function makeProcessedTxFromTxWithPublicCalls( .map(message => siloL2ToL1Message(message, constants.txContext.version, constants.txContext.chainId)) .filter(h => !h.isZero()), publicDataWrites, - new Fr(noteEncryptedLogPreimagesLength), - new Fr(encryptedLogPreimagesLength), + privateLogs, new Fr(unencryptedLogPreimagesLength), new Fr(contractClassLogPreimagesLength), - tx.noteEncryptedLogs, - tx.encryptedLogs, tx.unencryptedLogs, tx.contractClassLogs, ); diff --git a/yarn-project/circuit-types/src/tx/simulated_tx.ts b/yarn-project/circuit-types/src/tx/simulated_tx.ts index f53e55e2923..df143b6e092 100644 --- a/yarn-project/circuit-types/src/tx/simulated_tx.ts +++ b/yarn-project/circuit-types/src/tx/simulated_tx.ts @@ -7,19 +7,12 @@ import { type PrivateKernelProverProfileResult, PrivateKernelProverProfileResultSchema, } from '../interfaces/private_kernel_prover.js'; -import { - ContractClassTxL2Logs, - EncryptedNoteTxL2Logs, - EncryptedTxL2Logs, - UnencryptedTxL2Logs, -} from '../logs/tx_l2_logs.js'; +import { ContractClassTxL2Logs, UnencryptedTxL2Logs } from '../logs/tx_l2_logs.js'; import { PrivateExecutionResult, collectEnqueuedPublicFunctionCalls, collectPublicTeardownFunctionCall, collectSortedContractClassLogs, - collectSortedEncryptedLogs, - collectSortedNoteEncryptedLogs, } from '../private_execution_result.js'; import { type GasUsed } from './gas_used.js'; import { NestedProcessReturnValues, PublicSimulationOutput } from './public_simulation_output.js'; @@ -36,9 +29,7 @@ export class PrivateSimulationResult { } toSimulatedTx(): Tx { - const noteEncryptedLogs = new EncryptedNoteTxL2Logs([collectSortedNoteEncryptedLogs(this.privateExecutionResult)]); const contractClassLogs = new ContractClassTxL2Logs([collectSortedContractClassLogs(this.privateExecutionResult)]); - const encryptedLogs = new EncryptedTxL2Logs([collectSortedEncryptedLogs(this.privateExecutionResult)]); const enqueuedPublicFunctions = collectEnqueuedPublicFunctionCalls(this.privateExecutionResult); const teardownPublicFunction = collectPublicTeardownFunctionCall(this.privateExecutionResult); @@ -46,8 +37,6 @@ export class PrivateSimulationResult { const tx = new Tx( this.publicInputs, ClientIvcProof.empty(), - noteEncryptedLogs, - encryptedLogs, UnencryptedTxL2Logs.empty(), // *unencrypted logs contractClassLogs, enqueuedPublicFunctions, @@ -130,9 +119,7 @@ export class TxProvingResult { ) {} toTx(): Tx { - const noteEncryptedLogs = new EncryptedNoteTxL2Logs([collectSortedNoteEncryptedLogs(this.privateExecutionResult)]); const contractClassLogs = new ContractClassTxL2Logs([collectSortedContractClassLogs(this.privateExecutionResult)]); - const encryptedLogs = new EncryptedTxL2Logs([collectSortedEncryptedLogs(this.privateExecutionResult)]); const enqueuedPublicFunctions = collectEnqueuedPublicFunctionCalls(this.privateExecutionResult); const teardownPublicFunction = collectPublicTeardownFunctionCall(this.privateExecutionResult); @@ -140,8 +127,6 @@ export class TxProvingResult { const tx = new Tx( this.publicInputs, this.clientIvcProof, - noteEncryptedLogs, - encryptedLogs, UnencryptedTxL2Logs.empty(), // *unencrypted logs contractClassLogs, enqueuedPublicFunctions, diff --git a/yarn-project/circuit-types/src/tx/tx.ts b/yarn-project/circuit-types/src/tx/tx.ts index d049697cec3..bbdd0037d4d 100644 --- a/yarn-project/circuit-types/src/tx/tx.ts +++ b/yarn-project/circuit-types/src/tx/tx.ts @@ -1,6 +1,5 @@ import { ClientIvcProof, - ContractClassRegisteredEvent, PrivateKernelTailCircuitPublicInputs, type PrivateToPublicAccumulatedData, type ScopedLogHash, @@ -14,12 +13,7 @@ import { z } from 'zod'; import { type GetUnencryptedLogsResponse } from '../logs/get_logs_response.js'; import { type L2LogsSource } from '../logs/l2_logs_source.js'; -import { - ContractClassTxL2Logs, - EncryptedNoteTxL2Logs, - EncryptedTxL2Logs, - UnencryptedTxL2Logs, -} from '../logs/tx_l2_logs.js'; +import { ContractClassTxL2Logs, UnencryptedTxL2Logs } from '../logs/tx_l2_logs.js'; import { Gossipable } from '../p2p/gossipable.js'; import { TopicType, createTopicString } from '../p2p/topic_type.js'; import { PublicExecutionRequest } from '../public_execution_request.js'; @@ -43,14 +37,6 @@ export class Tx extends Gossipable { * */ public readonly clientIvcProof: ClientIvcProof, - /** - * Encrypted note logs generated by the tx. - */ - public noteEncryptedLogs: EncryptedNoteTxL2Logs, - /** - * Encrypted logs generated by the tx. - */ - public encryptedLogs: EncryptedTxL2Logs, /** * Unencrypted logs generated by the tx. * NOTE: These do not get filled, but remain here so enqueued_calls_processor.ts can accumulate public logs @@ -110,8 +96,6 @@ export class Tx extends Gossipable { return new Tx( reader.readObject(PrivateKernelTailCircuitPublicInputs), reader.readObject(ClientIvcProof), - reader.readObject(EncryptedNoteTxL2Logs), - reader.readObject(EncryptedTxL2Logs), reader.readObject(UnencryptedTxL2Logs), reader.readObject(ContractClassTxL2Logs), reader.readArray(reader.readNumber(), PublicExecutionRequest), @@ -126,8 +110,6 @@ export class Tx extends Gossipable { return new Tx( data, ClientIvcProof.empty(), - EncryptedNoteTxL2Logs.empty(), - EncryptedTxL2Logs.empty(), UnencryptedTxL2Logs.empty(), ContractClassTxL2Logs.empty(), [], @@ -143,8 +125,6 @@ export class Tx extends Gossipable { return serializeToBuffer([ this.data, this.clientIvcProof, - this.noteEncryptedLogs, - this.encryptedLogs, this.unencryptedLogs, this.contractClassLogs, this.enqueuedPublicFunctionCalls.length, @@ -158,8 +138,6 @@ export class Tx extends Gossipable { .object({ data: PrivateKernelTailCircuitPublicInputs.schema, clientIvcProof: ClientIvcProof.schema, - noteEncryptedLogs: EncryptedNoteTxL2Logs.schema, - encryptedLogs: EncryptedTxL2Logs.schema, unencryptedLogs: UnencryptedTxL2Logs.schema, contractClassLogs: ContractClassTxL2Logs.schema, enqueuedPublicFunctionCalls: z.array(PublicExecutionRequest.schema), @@ -172,8 +150,6 @@ export class Tx extends Gossipable { return new Tx( fields.data, fields.clientIvcProof, - fields.noteEncryptedLogs, - fields.encryptedLogs, fields.unencryptedLogs, fields.contractClassLogs, fields.enqueuedPublicFunctionCalls, @@ -207,15 +183,12 @@ export class Tx extends Gossipable { getStats(): TxStats { return { txHash: this.getTxHash().toString(), - noteEncryptedLogCount: this.noteEncryptedLogs.getTotalLogCount(), - encryptedLogCount: this.encryptedLogs.getTotalLogCount(), unencryptedLogCount: this.unencryptedLogs.getTotalLogCount(), - noteEncryptedLogSize: this.noteEncryptedLogs.getSerializedLength(), - encryptedLogSize: this.encryptedLogs.getSerializedLength(), unencryptedLogSize: this.unencryptedLogs.getSerializedLength(), - newCommitmentCount: this.data.getNonEmptyNoteHashes().length, - newNullifierCount: this.data.getNonEmptyNullifiers().length, + noteHashCount: this.data.getNonEmptyNoteHashes().length, + nullifierCount: this.data.getNonEmptyNullifiers().length, + privateLogCount: this.data.getNonEmptyPrivateLogs().length, proofSize: this.clientIvcProof.clientIvcProofBuffer.length, size: this.toBuffer().length, @@ -232,10 +205,7 @@ export class Tx extends Gossipable { : 'fpc_private' : 'fee_juice' : 'none', - classRegisteredCount: this.contractClassLogs - .unrollLogs() - // all contract class logs should pass the below check, but just in case: - .filter(log => ContractClassRegisteredEvent.isContractClassRegisteredEvent(log.data)).length, + classRegisteredCount: this.contractClassLogs.unrollLogs().length, contractClassLogSize: this.contractClassLogs.getSerializedLength(), }; } @@ -244,8 +214,6 @@ export class Tx extends Gossipable { return ( this.data.getSize() + this.clientIvcProof.clientIvcProofBuffer.length + - this.noteEncryptedLogs.getSerializedLength() + - this.encryptedLogs.getSerializedLength() + this.unencryptedLogs.getSerializedLength() + this.contractClassLogs.getSerializedLength() + arraySerializedSizeOfNonEmpty(this.enqueuedPublicFunctionCalls) + @@ -279,8 +247,6 @@ export class Tx extends Gossipable { static clone(tx: Tx): Tx { const publicInputs = PrivateKernelTailCircuitPublicInputs.fromBuffer(tx.data.toBuffer()); const clientIvcProof = ClientIvcProof.fromBuffer(tx.clientIvcProof.toBuffer()); - const noteEncryptedLogs = EncryptedNoteTxL2Logs.fromBuffer(Buffer.from(tx.noteEncryptedLogs.toBuffer())); - const encryptedLogs = EncryptedTxL2Logs.fromBuffer(tx.encryptedLogs.toBuffer()); const unencryptedLogs = UnencryptedTxL2Logs.fromBuffer(tx.unencryptedLogs.toBuffer()); const contractClassLogs = ContractClassTxL2Logs.fromBuffer(tx.contractClassLogs.toBuffer()); const enqueuedPublicFunctionCalls = tx.enqueuedPublicFunctionCalls.map(x => @@ -290,8 +256,6 @@ export class Tx extends Gossipable { return new Tx( publicInputs, clientIvcProof, - noteEncryptedLogs, - encryptedLogs, unencryptedLogs, contractClassLogs, enqueuedPublicFunctionCalls, @@ -303,8 +267,6 @@ export class Tx extends Gossipable { return new Tx( PrivateKernelTailCircuitPublicInputs.emptyWithNullifier(), ClientIvcProof.empty(), - EncryptedNoteTxL2Logs.random(1, 1), - EncryptedTxL2Logs.random(1, 1), UnencryptedTxL2Logs.random(1, 1), ContractClassTxL2Logs.random(1, 1), [PublicExecutionRequest.random()], @@ -330,16 +292,6 @@ export class Tx extends Gossipable { privateNonRevertible: PrivateToPublicAccumulatedData, unencryptedLogsHashes: ScopedLogHash[], ) { - this.encryptedLogs = this.encryptedLogs.filterScoped( - privateNonRevertible.encryptedLogsHashes, - EncryptedTxL2Logs.empty(), - ); - - this.noteEncryptedLogs = this.noteEncryptedLogs.filter( - privateNonRevertible.noteEncryptedLogsHashes, - EncryptedNoteTxL2Logs.empty(), - ); - this.contractClassLogs = this.contractClassLogs.filterScoped( privateNonRevertible.contractClassLogsHashes, ContractClassTxL2Logs.empty(), diff --git a/yarn-project/circuit-types/src/tx_effect.test.ts b/yarn-project/circuit-types/src/tx_effect.test.ts index 18df05d6dc4..c3a06435402 100644 --- a/yarn-project/circuit-types/src/tx_effect.test.ts +++ b/yarn-project/circuit-types/src/tx_effect.test.ts @@ -10,6 +10,6 @@ describe('TxEffect', () => { it('hash of empty tx effect matches snapshot', () => { const txEffectHash = TxEffect.empty().hash().toString('hex'); // If you change this you have to change the hardcoded value in TxsDecoder.sol! - expect(txEffectHash).toMatchInlineSnapshot(`"00c2dece9c9f14c67b8aafabdcb80793f1cffe95a801e15d648fd214a0522ee8"`); + expect(txEffectHash).toMatchInlineSnapshot(`"0038249b91f300ff56f2a8135be3bdb4fc493df5771061b67f2ab01b620b22b7"`); }); }); diff --git a/yarn-project/circuit-types/src/tx_effect.ts b/yarn-project/circuit-types/src/tx_effect.ts index 3a00f06c9a2..8a547c0988b 100644 --- a/yarn-project/circuit-types/src/tx_effect.ts +++ b/yarn-project/circuit-types/src/tx_effect.ts @@ -3,7 +3,10 @@ import { MAX_L2_TO_L1_MSGS_PER_TX, MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, + MAX_PRIVATE_LOGS_PER_TX, MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, + PRIVATE_LOG_SIZE_IN_FIELDS, + PrivateLog, PublicDataWrite, RevertCode, } from '@aztec/circuits.js'; @@ -18,7 +21,7 @@ import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { inspect } from 'util'; import { z } from 'zod'; -import { ContractClassTxL2Logs, EncryptedNoteTxL2Logs, EncryptedTxL2Logs, UnencryptedTxL2Logs } from './logs/index.js'; +import { ContractClassTxL2Logs, UnencryptedTxL2Logs } from './logs/index.js'; import { TxHash } from './tx/tx_hash.js'; export { RevertCodeEnum } from '@aztec/circuits.js'; @@ -50,15 +53,15 @@ export class TxEffect { * The public data writes to be inserted into the public data tree. */ public publicDataWrites: PublicDataWrite[], + /** + * The private logs. + */ + public privateLogs: PrivateLog[], /** * The logs and logs lengths of the txEffect */ - public noteEncryptedLogsLength: Fr, - public encryptedLogsLength: Fr, public unencryptedLogsLength: Fr, public contractClassLogsLength: Fr, - public noteEncryptedLogs: EncryptedNoteTxL2Logs, - public encryptedLogs: EncryptedTxL2Logs, public unencryptedLogs: UnencryptedTxL2Logs, public contractClassLogs: ContractClassTxL2Logs, ) { @@ -101,6 +104,15 @@ export class TxEffect { throw new Error('Public data write is empty'); } }); + + if (privateLogs.length > MAX_PRIVATE_LOGS_PER_TX) { + throw new Error(`Too many private logs: ${privateLogs.length}, max: ${MAX_PRIVATE_LOGS_PER_TX}`); + } + privateLogs.forEach(h => { + if (h.isEmpty()) { + throw new Error('Private log is empty'); + } + }); } toBuffer(): Buffer { @@ -111,12 +123,9 @@ export class TxEffect { serializeArrayOfBufferableToVector(this.nullifiers, 1), serializeArrayOfBufferableToVector(this.l2ToL1Msgs, 1), serializeArrayOfBufferableToVector(this.publicDataWrites, 1), - this.noteEncryptedLogsLength, - this.encryptedLogsLength, + serializeArrayOfBufferableToVector(this.privateLogs, 1), this.unencryptedLogsLength, this.contractClassLogsLength, - this.noteEncryptedLogs, - this.encryptedLogs, this.unencryptedLogs, this.contractClassLogs, ]); @@ -137,12 +146,9 @@ export class TxEffect { reader.readVectorUint8Prefix(Fr), reader.readVectorUint8Prefix(Fr), reader.readVectorUint8Prefix(PublicDataWrite), + reader.readVectorUint8Prefix(PrivateLog), Fr.fromBuffer(reader), Fr.fromBuffer(reader), - Fr.fromBuffer(reader), - Fr.fromBuffer(reader), - reader.readObject(EncryptedNoteTxL2Logs), - reader.readObject(EncryptedTxL2Logs), reader.readObject(UnencryptedTxL2Logs), reader.readObject(ContractClassTxL2Logs), ); @@ -163,9 +169,11 @@ export class TxEffect { serializeToBuffer(this.publicDataWrites), PublicDataWrite.SIZE_IN_BYTES * MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, ); + const privateLogsBuffer = padBuffer( + serializeToBuffer(this.privateLogs), + PrivateLog.SIZE_IN_BYTES * MAX_PRIVATE_LOGS_PER_TX, + ); - const noteEncryptedLogsHashKernel0 = this.noteEncryptedLogs.hash(); - const encryptedLogsHashKernel0 = this.encryptedLogs.hash(); const unencryptedLogsHashKernel0 = this.unencryptedLogs.hash(); const contractClassLogsHashKernel0 = this.contractClassLogs.hash(); @@ -176,12 +184,9 @@ export class TxEffect { nullifiersBuffer, outHashBuffer, publicDataWritesBuffer, - this.noteEncryptedLogsLength.toBuffer(), - this.encryptedLogsLength.toBuffer(), + privateLogsBuffer, this.unencryptedLogsLength.toBuffer(), this.contractClassLogsLength.toBuffer(), - noteEncryptedLogsHashKernel0, - encryptedLogsHashKernel0, unencryptedLogsHashKernel0, contractClassLogsHashKernel0, ]); @@ -217,14 +222,7 @@ export class TxEffect { return thisLayer[0]; } - static random( - numPrivateCallsPerTx = 2, - numPublicCallsPerTx = 3, - numEncryptedLogsPerCall = 2, - numUnencryptedLogsPerCall = 1, - ): TxEffect { - const noteEncryptedLogs = EncryptedNoteTxL2Logs.random(numPrivateCallsPerTx, numEncryptedLogsPerCall); - const encryptedLogs = EncryptedTxL2Logs.random(numPrivateCallsPerTx, numEncryptedLogsPerCall); + static random(numPublicCallsPerTx = 3, numUnencryptedLogsPerCall = 1): TxEffect { const unencryptedLogs = UnencryptedTxL2Logs.random(numPublicCallsPerTx, numUnencryptedLogsPerCall); const contractClassLogs = ContractClassTxL2Logs.random(1, 1); return new TxEffect( @@ -234,12 +232,9 @@ export class TxEffect { makeTuple(MAX_NULLIFIERS_PER_TX, Fr.random), makeTuple(MAX_L2_TO_L1_MSGS_PER_TX, Fr.random), makeTuple(MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, () => new PublicDataWrite(Fr.random(), Fr.random())), - new Fr(noteEncryptedLogs.getKernelLength()), - new Fr(encryptedLogs.getKernelLength()), + makeTuple(MAX_PRIVATE_LOGS_PER_TX, () => new PrivateLog(makeTuple(PRIVATE_LOG_SIZE_IN_FIELDS, Fr.random))), new Fr(unencryptedLogs.getKernelLength()), new Fr(contractClassLogs.getKernelLength()), - noteEncryptedLogs, - encryptedLogs, unencryptedLogs, contractClassLogs, ); @@ -253,12 +248,9 @@ export class TxEffect { [], [], [], + [], Fr.ZERO, Fr.ZERO, - Fr.ZERO, - Fr.ZERO, - EncryptedNoteTxL2Logs.empty(), - EncryptedTxL2Logs.empty(), UnencryptedTxL2Logs.empty(), ContractClassTxL2Logs.empty(), ); @@ -281,12 +273,9 @@ export class TxEffect { fields.nullifiers, fields.l2ToL1Msgs, fields.publicDataWrites, - fields.noteEncryptedLogsLength, - fields.encryptedLogsLength, + fields.privateLogs, fields.unencryptedLogsLength, fields.contractClassLogsLength, - fields.noteEncryptedLogs, - fields.encryptedLogs, fields.unencryptedLogs, fields.contractClassLogs, ); @@ -301,12 +290,9 @@ export class TxEffect { nullifiers: z.array(schemas.Fr), l2ToL1Msgs: z.array(schemas.Fr), publicDataWrites: z.array(PublicDataWrite.schema), - noteEncryptedLogsLength: schemas.Fr, - encryptedLogsLength: schemas.Fr, + privateLogs: z.array(PrivateLog.schema), unencryptedLogsLength: schemas.Fr, contractClassLogsLength: schemas.Fr, - noteEncryptedLogs: EncryptedNoteTxL2Logs.schema, - encryptedLogs: EncryptedTxL2Logs.schema, unencryptedLogs: UnencryptedTxL2Logs.schema, contractClassLogs: ContractClassTxL2Logs.schema, }) @@ -321,12 +307,9 @@ export class TxEffect { nullifiers: [${this.nullifiers.map(h => h.toString()).join(', ')}], l2ToL1Msgs: [${this.l2ToL1Msgs.map(h => h.toString()).join(', ')}], publicDataWrites: [${this.publicDataWrites.map(h => h.toString()).join(', ')}], - noteEncryptedLogsLength: ${this.noteEncryptedLogsLength}, - encryptedLogsLength: ${this.encryptedLogsLength}, + privateLogs: [${this.privateLogs.map(l => l.toString()).join(', ')}], unencryptedLogsLength: ${this.unencryptedLogsLength}, contractClassLogsLength: ${this.contractClassLogsLength}, - noteEncryptedLogs: ${jsonStringify(this.noteEncryptedLogs)}, - encryptedLogs: ${jsonStringify(this.encryptedLogs)}, unencryptedLogs: ${jsonStringify(this.unencryptedLogs)} contractClassLogs: ${jsonStringify(this.contractClassLogs)} }`; diff --git a/yarn-project/circuits.js/fixtures/ContractInstanceDeployedEventData.hex b/yarn-project/circuits.js/fixtures/ContractInstanceDeployedEventData.hex deleted file mode 100644 index 48655f0d4d6..00000000000 --- a/yarn-project/circuits.js/fixtures/ContractInstanceDeployedEventData.hex +++ /dev/null @@ -1 +0,0 @@ -0000000085864497636cf755ae7bde03f267ce01a520981c21c3682aaf82a631011870b273ea9661b2893efeb641df4136b3f67b24fc79aed1d5bd779d35e3cd00000000000000000000000000000000000000000000000000000000000000011f99b84f796dd16265d803ef0f80c9cc4988c0797d1f9a895115d3c2c15d016723ced3716a04d81b58822bc3e1843626aa2884888b1a2d2250e79fb7d41a365e1ab0c6a467b58a91aab18f3ec7f996410a1855d75d08d73ed8796a2465a64ac8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file diff --git a/yarn-project/circuits.js/package.json b/yarn-project/circuits.js/package.json index 34f19cb3e6d..9406e50c6ee 100644 --- a/yarn-project/circuits.js/package.json +++ b/yarn-project/circuits.js/package.json @@ -44,14 +44,12 @@ "@aztec/foundation": "workspace:^", "@aztec/types": "workspace:^", "eslint": "^8.35.0", - "lodash.chunk": "^4.2.0", "tslib": "^2.4.0", "zod": "^3.23.8" }, "devDependencies": { "@jest/globals": "^29.5.0", "@types/jest": "^29.5.0", - "@types/lodash.chunk": "^4.2.7", "@types/node": "^18.7.23", "jest": "^29.5.0", "prettier": "^2.8.4", diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index 183e21073d2..8672f42cdea 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -14,8 +14,7 @@ export const MAX_NULLIFIER_READ_REQUESTS_PER_CALL = 16; export const MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL = 16; export const MAX_L1_TO_L2_MSG_READ_REQUESTS_PER_CALL = 16; export const MAX_KEY_VALIDATION_REQUESTS_PER_CALL = 16; -export const MAX_NOTE_ENCRYPTED_LOGS_PER_CALL = 16; -export const MAX_ENCRYPTED_LOGS_PER_CALL = 4; +export const MAX_PRIVATE_LOGS_PER_CALL = 16; export const MAX_UNENCRYPTED_LOGS_PER_CALL = 4; export const MAX_CONTRACT_CLASS_LOGS_PER_CALL = 1; export const ARCHIVE_HEIGHT = 29; @@ -53,8 +52,7 @@ export const MAX_NULLIFIER_READ_REQUESTS_PER_TX = 64; export const MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX = 64; export const MAX_L1_TO_L2_MSG_READ_REQUESTS_PER_TX = 64; export const MAX_KEY_VALIDATION_REQUESTS_PER_TX = 64; -export const MAX_NOTE_ENCRYPTED_LOGS_PER_TX = 64; -export const MAX_ENCRYPTED_LOGS_PER_TX = 8; +export const MAX_PRIVATE_LOGS_PER_TX = 32; export const MAX_UNENCRYPTED_LOGS_PER_TX = 8; export const MAX_CONTRACT_CLASS_LOGS_PER_TX = 1; export const NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP = 16; @@ -79,7 +77,7 @@ export const PRIVATE_KERNEL_RESET_INDEX = 20; export const FUNCTION_SELECTOR_NUM_BYTES = 4; export const INITIALIZATION_SLOT_SEPARATOR = 1000000000; export const INITIAL_L2_BLOCK_NUM = 1; -export const PRIVATE_LOG_SIZE_IN_BYTES = 576; +export const PRIVATE_LOG_SIZE_IN_FIELDS = 18; export const BLOB_SIZE_IN_BYTES = 126976; export const AZTEC_MAX_EPOCH_DURATION = 32; export const GENESIS_ARCHIVE_ROOT = 1002640778211850180189505934749257244705296832326768971348723156503780793518n; @@ -117,6 +115,7 @@ export const L2_GAS_PER_NOTE_HASH_READ_REQUEST = 1200; export const L2_GAS_PER_NULLIFIER_READ_REQUEST = 2400; export const L2_GAS_PER_L1_TO_L2_MSG_READ_REQUEST = 1170; export const L2_GAS_PER_LOG_BYTE = 4; +export const L2_GAS_PER_PRIVATE_LOG = 0; export const L2_GAS_PER_L2_TO_L1_MSG = 200; export const MAX_PROTOCOL_CONTRACTS = 7; export const CANONICAL_AUTH_REGISTRY_ADDRESS = 1; @@ -157,11 +156,10 @@ export const SCOPED_KEY_VALIDATION_REQUEST_AND_GENERATOR_LENGTH = 6; export const PARTIAL_STATE_REFERENCE_LENGTH = 6; export const READ_REQUEST_LENGTH = 2; export const TREE_LEAF_READ_REQUEST_LENGTH = 2; +export const PRIVATE_LOG_DATA_LENGTH = 20; +export const SCOPED_PRIVATE_LOG_DATA_LENGTH = 21; export const LOG_HASH_LENGTH = 3; export const SCOPED_LOG_HASH_LENGTH = 4; -export const ENCRYPTED_LOG_HASH_LENGTH = 4; -export const SCOPED_ENCRYPTED_LOG_HASH_LENGTH = 5; -export const NOTE_LOG_HASH_LENGTH = 4; export const NOTE_HASH_LENGTH = 2; export const SCOPED_NOTE_HASH_LENGTH = 3; export const NULLIFIER_LENGTH = 3; @@ -180,7 +178,7 @@ export const TX_REQUEST_LENGTH = 12; export const TOTAL_FEES_LENGTH = 1; export const TOTAL_MANA_USED_LENGTH = 1; export const HEADER_LENGTH = 25; -export const PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 491; +export const PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 731; export const PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = 867; export const PRIVATE_CONTEXT_INPUTS_LENGTH = 38; export const FEE_RECIPIENT_LENGTH = 2; @@ -188,17 +186,17 @@ export const AGGREGATION_OBJECT_LENGTH = 16; export const SCOPED_READ_REQUEST_LEN = 3; export const PUBLIC_DATA_READ_LENGTH = 3; export const PRIVATE_VALIDATION_REQUESTS_LENGTH = 772; -export const COMBINED_ACCUMULATED_DATA_LENGTH = 550; +export const COMBINED_ACCUMULATED_DATA_LENGTH = 900; export const TX_CONSTANT_DATA_LENGTH = 35; export const COMBINED_CONSTANT_DATA_LENGTH = 44; -export const PRIVATE_ACCUMULATED_DATA_LENGTH = 1036; -export const PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1850; -export const PRIVATE_TO_PUBLIC_ACCUMULATED_DATA_LENGTH = 548; +export const PRIVATE_ACCUMULATED_DATA_LENGTH = 1412; +export const PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 2226; +export const PRIVATE_TO_PUBLIC_ACCUMULATED_DATA_LENGTH = 900; export const PRIVATE_TO_AVM_ACCUMULATED_DATA_LENGTH = 160; export const NUM_PRIVATE_TO_AVM_ACCUMULATED_DATA_ARRAYS = 3; export const AVM_ACCUMULATED_DATA_LENGTH = 318; -export const PRIVATE_TO_PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1141; -export const KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 606; +export const PRIVATE_TO_PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1845; +export const KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 956; export const AVM_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1006; export const CONSTANT_ROLLUP_DATA_LENGTH = 13; export const BASE_OR_MERGE_PUBLIC_INPUTS_LENGTH = 31; @@ -208,6 +206,7 @@ export const GET_NOTES_ORACLE_RETURN_LENGTH = 674; export const NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP = 2048; export const NULLIFIERS_NUM_BYTES_PER_BASE_ROLLUP = 2048; export const PUBLIC_DATA_WRITES_NUM_BYTES_PER_BASE_ROLLUP = 4096; +export const PRIVATE_LOGS_NUM_BYTES_PER_BASE_ROLLUP = 18432; export const CONTRACTS_NUM_BYTES_PER_BASE_ROLLUP = 32; export const CONTRACT_DATA_NUM_BYTES_PER_BASE_ROLLUP = 64; export const CONTRACT_DATA_NUM_BYTES_PER_BASE_ROLLUP_UNPADDED = 52; diff --git a/yarn-project/circuits.js/src/contract/events/contract_instance_deployed_event.test.ts b/yarn-project/circuits.js/src/contract/events/contract_instance_deployed_event.test.ts deleted file mode 100644 index 281a92c5192..00000000000 --- a/yarn-project/circuits.js/src/contract/events/contract_instance_deployed_event.test.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { getSampleContractInstanceDeployedEventPayload } from '../../tests/fixtures.js'; -import { ContractInstanceDeployedEvent } from './contract_instance_deployed_event.js'; - -describe('ContractInstanceDeployedEvent', () => { - it('parses an event as emitted by the ClassInstanceDeployer', () => { - const data = getSampleContractInstanceDeployedEventPayload(); - const event = ContractInstanceDeployedEvent.fromLogData(data); - expect(event.address.toString()).toEqual('0x011870b273ea9661b2893efeb641df4136b3f67b24fc79aed1d5bd779d35e3cd'); - expect(event.contractClassId.toString()).toEqual( - '0x23ced3716a04d81b58822bc3e1843626aa2884888b1a2d2250e79fb7d41a365e', - ); - }); -}); diff --git a/yarn-project/circuits.js/src/contract/index.ts b/yarn-project/circuits.js/src/contract/index.ts index 98449797223..7376d76d662 100644 --- a/yarn-project/circuits.js/src/contract/index.ts +++ b/yarn-project/circuits.js/src/contract/index.ts @@ -2,11 +2,7 @@ export * from './artifact_hash.js'; export * from './contract_address.js'; export * from './contract_class.js'; export * from './contract_class_id.js'; -export * from './events/contract_class_registered_event.js'; export * from './contract_instance.js'; -export * from './events/contract_instance_deployed_event.js'; -export * from './events/private_function_broadcasted_event.js'; -export * from './events/unconstrained_function_broadcasted_event.js'; export * from './private_function.js'; export * from './private_function_membership_proof.js'; export * from './unconstrained_function_membership_proof.js'; diff --git a/yarn-project/circuits.js/src/hints/find_private_kernel_reset_dimensions.test.ts b/yarn-project/circuits.js/src/hints/find_private_kernel_reset_dimensions.test.ts index 245ba0316df..1a845001a9b 100644 --- a/yarn-project/circuits.js/src/hints/find_private_kernel_reset_dimensions.test.ts +++ b/yarn-project/circuits.js/src/hints/find_private_kernel_reset_dimensions.test.ts @@ -56,7 +56,7 @@ describe('findPrivateKernelResetDimensions', () => { standalone: [24], cost: 100, }, - ENCRYPTED_LOG_SILOING_AMOUNT: { + PRIVATE_LOG_SILOING_AMOUNT: { variants: [9], standalone: [18], cost: 100, @@ -88,7 +88,7 @@ describe('findPrivateKernelResetDimensions', () => { TRANSIENT_DATA_AMOUNT, NOTE_HASH_SILOING_AMOUNT, NULLIFIER_SILOING_AMOUNT, - ENCRYPTED_LOG_SILOING_AMOUNT, + PRIVATE_LOG_SILOING_AMOUNT, }: Partial<{ [K in DimensionName]: number }> = {}, ) => { const expected = new PrivateKernelResetDimensions( @@ -100,7 +100,7 @@ describe('findPrivateKernelResetDimensions', () => { TRANSIENT_DATA_AMOUNT ?? 6, NOTE_HASH_SILOING_AMOUNT ?? 7, NULLIFIER_SILOING_AMOUNT ?? 8, - ENCRYPTED_LOG_SILOING_AMOUNT ?? 9, + PRIVATE_LOG_SILOING_AMOUNT ?? 9, ); expect(dimensions).toEqual(expected); @@ -137,7 +137,7 @@ describe('findPrivateKernelResetDimensions', () => { TRANSIENT_DATA_AMOUNT: 4, NOTE_HASH_SILOING_AMOUNT: 9, NULLIFIER_SILOING_AMOUNT: 11, - ENCRYPTED_LOG_SILOING_AMOUNT: 7, + PRIVATE_LOG_SILOING_AMOUNT: 7, }); expectEqualDimensions(dimensions, { @@ -149,7 +149,7 @@ describe('findPrivateKernelResetDimensions', () => { TRANSIENT_DATA_AMOUNT: 6, NOTE_HASH_SILOING_AMOUNT: 14, NULLIFIER_SILOING_AMOUNT: 16, - ENCRYPTED_LOG_SILOING_AMOUNT: 9, + PRIVATE_LOG_SILOING_AMOUNT: 9, }); }); @@ -171,21 +171,21 @@ describe('findPrivateKernelResetDimensions', () => { describe('with standalone', () => { it('uses standalone for one dimension', () => { const dimensions = getDimensions({ - ENCRYPTED_LOG_SILOING_AMOUNT: 8, + PRIVATE_LOG_SILOING_AMOUNT: 8, }); - expectEqualStandalone(dimensions, 'ENCRYPTED_LOG_SILOING_AMOUNT', 18); + expectEqualStandalone(dimensions, 'PRIVATE_LOG_SILOING_AMOUNT', 18); }); it('uses variant for one dimension if standalone is more expensive', () => { // Increase the cost so it's more expensive running all the extra siloing. - config.dimensions.ENCRYPTED_LOG_SILOING_AMOUNT.cost = 9999; + config.dimensions.PRIVATE_LOG_SILOING_AMOUNT.cost = 9999; const dimensions = getDimensions({ - ENCRYPTED_LOG_SILOING_AMOUNT: 8, + PRIVATE_LOG_SILOING_AMOUNT: 8, }); - expectEqualDimensions(dimensions, { ENCRYPTED_LOG_SILOING_AMOUNT: 9 }); + expectEqualDimensions(dimensions, { PRIVATE_LOG_SILOING_AMOUNT: 9 }); }); }); @@ -228,10 +228,10 @@ describe('findPrivateKernelResetDimensions', () => { it('picks cheapest option among standalone', () => { const dimensions = getDimensions({ - ENCRYPTED_LOG_SILOING_AMOUNT: 8, + PRIVATE_LOG_SILOING_AMOUNT: 8, }); - expectEqualStandalone(dimensions, 'ENCRYPTED_LOG_SILOING_AMOUNT', 18); + expectEqualStandalone(dimensions, 'PRIVATE_LOG_SILOING_AMOUNT', 18); }); }); diff --git a/yarn-project/circuits.js/src/hints/find_private_kernel_reset_dimensions.ts b/yarn-project/circuits.js/src/hints/find_private_kernel_reset_dimensions.ts index 5554bea8601..6a40471cae1 100644 --- a/yarn-project/circuits.js/src/hints/find_private_kernel_reset_dimensions.ts +++ b/yarn-project/circuits.js/src/hints/find_private_kernel_reset_dimensions.ts @@ -150,7 +150,7 @@ export function findPrivateKernelResetDimensions( (dimensions: PrivateKernelResetDimensions) => dimensions.NOTE_HASH_SILOING_AMOUNT === 0 && dimensions.NULLIFIER_SILOING_AMOUNT === 0 && - dimensions.ENCRYPTED_LOG_SILOING_AMOUNT === 0 && + dimensions.PRIVATE_LOG_SILOING_AMOUNT === 0 && isEnough(dimensions); const options = [ diff --git a/yarn-project/circuits.js/src/structs/index.ts b/yarn-project/circuits.js/src/structs/index.ts index 96b87bbbc6f..7f76ff4a96d 100644 --- a/yarn-project/circuits.js/src/structs/index.ts +++ b/yarn-project/circuits.js/src/structs/index.ts @@ -52,6 +52,8 @@ export * from './parity/root_parity_inputs.js'; export * from './partial_state_reference.js'; export * from './private_call_request.js'; export * from './private_circuit_public_inputs.js'; +export * from './private_log.js'; +export * from './private_log_data.js'; export * from './private_validation_requests.js'; export * from './proof.js'; export * from './public_call_request.js'; 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 b245c70f7b6..b7d683de60e 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 @@ -9,16 +9,16 @@ import { inspect } from 'util'; import { MAX_CONTRACT_CLASS_LOGS_PER_TX, - MAX_ENCRYPTED_LOGS_PER_TX, MAX_L2_TO_L1_MSGS_PER_TX, - MAX_NOTE_ENCRYPTED_LOGS_PER_TX, MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, + MAX_PRIVATE_LOGS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX, } from '../../constants.gen.js'; import { ScopedL2ToL1Message } from '../l2_to_l1_message.js'; -import { LogHash, ScopedLogHash } from '../log_hash.js'; +import { ScopedLogHash } from '../log_hash.js'; +import { PrivateLog } from '../private_log.js'; import { PublicDataWrite } from '../public_data_write.js'; /** @@ -39,13 +39,9 @@ export class CombinedAccumulatedData { */ public l2ToL1Msgs: Tuple, /** - * Accumulated note logs hashes from all the previous kernel iterations. + * All the logs created emitted from the private functions in this transaction. */ - public noteEncryptedLogsHashes: Tuple, - /** - * Accumulated encrypted logs hashes from all the previous kernel iterations. - */ - public encryptedLogsHashes: Tuple, + public privateLogs: Tuple, /** * Accumulated unencrypted logs hash from all the previous kernel iterations. * Note: Truncated to 31 bytes to fit in Fr. @@ -56,14 +52,6 @@ export class CombinedAccumulatedData { * Note: Truncated to 31 bytes to fit in Fr. */ public contractClassLogsHashes: Tuple, - /** - * Total accumulated length of the encrypted note log preimages emitted in all the previous kernel iterations - */ - public noteEncryptedLogPreimagesLength: Fr, - /** - * Total accumulated length of the encrypted log preimages emitted in all the previous kernel iterations - */ - public encryptedLogPreimagesLength: Fr, /** * Total accumulated length of the unencrypted log preimages emitted in all the previous kernel iterations */ @@ -83,12 +71,9 @@ export class CombinedAccumulatedData { arraySerializedSizeOfNonEmpty(this.noteHashes) + arraySerializedSizeOfNonEmpty(this.nullifiers) + arraySerializedSizeOfNonEmpty(this.l2ToL1Msgs) + - arraySerializedSizeOfNonEmpty(this.noteEncryptedLogsHashes) + - arraySerializedSizeOfNonEmpty(this.encryptedLogsHashes) + + arraySerializedSizeOfNonEmpty(this.privateLogs) + arraySerializedSizeOfNonEmpty(this.unencryptedLogsHashes) + arraySerializedSizeOfNonEmpty(this.contractClassLogsHashes) + - this.noteEncryptedLogPreimagesLength.size + - this.encryptedLogPreimagesLength.size + this.unencryptedLogPreimagesLength.size + this.contractClassLogPreimagesLength.size + arraySerializedSizeOfNonEmpty(this.publicDataWrites) @@ -100,12 +85,9 @@ export class CombinedAccumulatedData { fields.noteHashes, fields.nullifiers, fields.l2ToL1Msgs, - fields.noteEncryptedLogsHashes, - fields.encryptedLogsHashes, + fields.privateLogs, fields.unencryptedLogsHashes, fields.contractClassLogsHashes, - fields.noteEncryptedLogPreimagesLength, - fields.encryptedLogPreimagesLength, fields.unencryptedLogPreimagesLength, fields.contractClassLogPreimagesLength, fields.publicDataWrites, @@ -143,14 +125,11 @@ export class CombinedAccumulatedData { reader.readArray(MAX_NOTE_HASHES_PER_TX, Fr), reader.readArray(MAX_NULLIFIERS_PER_TX, Fr), reader.readArray(MAX_L2_TO_L1_MSGS_PER_TX, ScopedL2ToL1Message), - reader.readArray(MAX_NOTE_ENCRYPTED_LOGS_PER_TX, LogHash), - reader.readArray(MAX_ENCRYPTED_LOGS_PER_TX, ScopedLogHash), + reader.readArray(MAX_PRIVATE_LOGS_PER_TX, PrivateLog), reader.readArray(MAX_UNENCRYPTED_LOGS_PER_TX, ScopedLogHash), reader.readArray(MAX_CONTRACT_CLASS_LOGS_PER_TX, ScopedLogHash), Fr.fromBuffer(reader), Fr.fromBuffer(reader), - Fr.fromBuffer(reader), - Fr.fromBuffer(reader), reader.readArray(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataWrite), ); } @@ -169,14 +148,11 @@ export class CombinedAccumulatedData { makeTuple(MAX_NOTE_HASHES_PER_TX, Fr.zero), makeTuple(MAX_NULLIFIERS_PER_TX, Fr.zero), makeTuple(MAX_L2_TO_L1_MSGS_PER_TX, ScopedL2ToL1Message.empty), - makeTuple(MAX_NOTE_ENCRYPTED_LOGS_PER_TX, LogHash.empty), - makeTuple(MAX_ENCRYPTED_LOGS_PER_TX, ScopedLogHash.empty), + makeTuple(MAX_PRIVATE_LOGS_PER_TX, PrivateLog.empty), makeTuple(MAX_UNENCRYPTED_LOGS_PER_TX, ScopedLogHash.empty), makeTuple(MAX_CONTRACT_CLASS_LOGS_PER_TX, ScopedLogHash.empty), Fr.zero(), Fr.zero(), - Fr.zero(), - Fr.zero(), makeTuple(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataWrite.empty), ); } @@ -195,11 +171,7 @@ export class CombinedAccumulatedData { .filter(x => !x.isEmpty()) .map(x => inspect(x)) .join(', ')}], - noteEncryptedLogsHash: [${this.noteEncryptedLogsHashes - .filter(x => !x.isEmpty()) - .map(x => inspect(x)) - .join(', ')}] - encryptedLogsHash: [${this.encryptedLogsHashes + privateLogs: [${this.privateLogs .filter(x => !x.isEmpty()) .map(x => inspect(x)) .join(', ')}] @@ -211,8 +183,6 @@ export class CombinedAccumulatedData { .filter(x => !x.isEmpty()) .map(x => inspect(x)) .join(', ')}], - noteEncryptedLogPreimagesLength: ${this.noteEncryptedLogPreimagesLength.toString()}, - encryptedLogPreimagesLength: ${this.encryptedLogPreimagesLength.toString()}, unencryptedLogPreimagesLength: ${this.unencryptedLogPreimagesLength.toString()}, contractClassLogPreimagesLength: ${this.contractClassLogPreimagesLength.toString()}, publicDataWrites: [${this.publicDataWrites diff --git a/yarn-project/circuits.js/src/structs/kernel/private_accumulated_data.ts b/yarn-project/circuits.js/src/structs/kernel/private_accumulated_data.ts index a314fdde586..12cbb6a723b 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_accumulated_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_accumulated_data.ts @@ -4,19 +4,19 @@ import { bufferToHex, hexToBuffer } from '@aztec/foundation/string'; import { MAX_CONTRACT_CLASS_LOGS_PER_TX, - MAX_ENCRYPTED_LOGS_PER_TX, MAX_ENQUEUED_CALLS_PER_TX, MAX_L2_TO_L1_MSGS_PER_TX, - MAX_NOTE_ENCRYPTED_LOGS_PER_TX, MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, + MAX_PRIVATE_LOGS_PER_TX, } from '../../constants.gen.js'; import { ScopedL2ToL1Message } from '../l2_to_l1_message.js'; -import { NoteLogHash, ScopedEncryptedLogHash, ScopedLogHash } from '../log_hash.js'; +import { ScopedLogHash } from '../log_hash.js'; import { ScopedNoteHash } from '../note_hash.js'; import { ScopedNullifier } from '../nullifier.js'; import { PrivateCallRequest } from '../private_call_request.js'; +import { ScopedPrivateLogData } from '../private_log_data.js'; import { CountedPublicCallRequest } from '../public_call_request.js'; /** @@ -38,15 +38,9 @@ export class PrivateAccumulatedData { */ public l2ToL1Msgs: Tuple, /** - * Accumulated encrypted note logs hashes from all the previous kernel iterations. - * Note: Truncated to 31 bytes to fit in Fr. - */ - public noteEncryptedLogsHashes: Tuple, - /** - * Accumulated encrypted logs hashes from all the previous kernel iterations. - * Note: Truncated to 31 bytes to fit in Fr. + * Accumulated logs from all the previous kernel iterations. */ - public encryptedLogsHashes: Tuple, + public privateLogs: Tuple, /** * Accumulated contract class logs from all the previous kernel iterations. * Note: Truncated to 31 bytes to fit in Fr. @@ -67,8 +61,7 @@ export class PrivateAccumulatedData { this.noteHashes, this.nullifiers, this.l2ToL1Msgs, - this.noteEncryptedLogsHashes, - this.encryptedLogsHashes, + this.privateLogs, this.contractClassLogsHashes, this.publicCallRequests, this.privateCallStack, @@ -90,8 +83,7 @@ export class PrivateAccumulatedData { reader.readArray(MAX_NOTE_HASHES_PER_TX, ScopedNoteHash), reader.readArray(MAX_NULLIFIERS_PER_TX, ScopedNullifier), reader.readArray(MAX_L2_TO_L1_MSGS_PER_TX, ScopedL2ToL1Message), - reader.readArray(MAX_NOTE_ENCRYPTED_LOGS_PER_TX, NoteLogHash), - reader.readArray(MAX_ENCRYPTED_LOGS_PER_TX, ScopedEncryptedLogHash), + reader.readArray(MAX_PRIVATE_LOGS_PER_TX, ScopedPrivateLogData), reader.readArray(MAX_CONTRACT_CLASS_LOGS_PER_TX, ScopedLogHash), reader.readArray(MAX_ENQUEUED_CALLS_PER_TX, CountedPublicCallRequest), reader.readArray(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, PrivateCallRequest), @@ -112,8 +104,7 @@ export class PrivateAccumulatedData { makeTuple(MAX_NOTE_HASHES_PER_TX, ScopedNoteHash.empty), makeTuple(MAX_NULLIFIERS_PER_TX, ScopedNullifier.empty), makeTuple(MAX_L2_TO_L1_MSGS_PER_TX, ScopedL2ToL1Message.empty), - makeTuple(MAX_NOTE_ENCRYPTED_LOGS_PER_TX, NoteLogHash.empty), - makeTuple(MAX_ENCRYPTED_LOGS_PER_TX, ScopedEncryptedLogHash.empty), + makeTuple(MAX_PRIVATE_LOGS_PER_TX, ScopedPrivateLogData.empty), makeTuple(MAX_CONTRACT_CLASS_LOGS_PER_TX, ScopedLogHash.empty), makeTuple(MAX_ENQUEUED_CALLS_PER_TX, CountedPublicCallRequest.empty), makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, PrivateCallRequest.empty), diff --git a/yarn-project/circuits.js/src/structs/kernel/private_kernel_reset_dimensions.ts b/yarn-project/circuits.js/src/structs/kernel/private_kernel_reset_dimensions.ts index b057dcc696b..80d670b5218 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_kernel_reset_dimensions.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_kernel_reset_dimensions.ts @@ -11,7 +11,7 @@ export class PrivateKernelResetDimensions { public TRANSIENT_DATA_AMOUNT: number, public NOTE_HASH_SILOING_AMOUNT: number, public NULLIFIER_SILOING_AMOUNT: number, - public ENCRYPTED_LOG_SILOING_AMOUNT: number, + public PRIVATE_LOG_SILOING_AMOUNT: number, ) {} toBuffer() { @@ -24,7 +24,7 @@ export class PrivateKernelResetDimensions { this.TRANSIENT_DATA_AMOUNT, this.NOTE_HASH_SILOING_AMOUNT, this.NULLIFIER_SILOING_AMOUNT, - this.ENCRYPTED_LOG_SILOING_AMOUNT, + this.PRIVATE_LOG_SILOING_AMOUNT, ); } @@ -65,7 +65,7 @@ export const privateKernelResetDimensionNames: DimensionName[] = [ 'TRANSIENT_DATA_AMOUNT', 'NOTE_HASH_SILOING_AMOUNT', 'NULLIFIER_SILOING_AMOUNT', - 'ENCRYPTED_LOG_SILOING_AMOUNT', + 'PRIVATE_LOG_SILOING_AMOUNT', ]; export interface DimensionConfig { diff --git a/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_public_inputs.ts index d21a7590db9..869427fa2ec 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_public_inputs.ts @@ -240,6 +240,16 @@ export class PrivateKernelTailCircuitPublicInputs { return nullifiers.filter(n => !n.isZero()); } + getNonEmptyPrivateLogs() { + const privateLogs = this.forPublic + ? mergeAccumulatedData( + this.forPublic.nonRevertibleAccumulatedData.privateLogs, + this.forPublic.revertibleAccumulatedData.privateLogs, + ) + : this.forRollup!.end.privateLogs; + return privateLogs.filter(n => !n.isEmpty()); + } + static fromBuffer(buffer: Buffer | BufferReader): PrivateKernelTailCircuitPublicInputs { const reader = BufferReader.asReader(buffer); const isForPublic = reader.readBoolean(); diff --git a/yarn-project/circuits.js/src/structs/kernel/private_to_public_accumulated_data.ts b/yarn-project/circuits.js/src/structs/kernel/private_to_public_accumulated_data.ts index d460c78d2ca..99a3c48fa22 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_to_public_accumulated_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_to_public_accumulated_data.ts @@ -7,15 +7,15 @@ import { inspect } from 'util'; import { MAX_CONTRACT_CLASS_LOGS_PER_TX, - MAX_ENCRYPTED_LOGS_PER_TX, MAX_ENQUEUED_CALLS_PER_TX, MAX_L2_TO_L1_MSGS_PER_TX, - MAX_NOTE_ENCRYPTED_LOGS_PER_TX, MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, + MAX_PRIVATE_LOGS_PER_TX, } from '../../constants.gen.js'; import { ScopedL2ToL1Message } from '../l2_to_l1_message.js'; -import { LogHash, ScopedLogHash } from '../log_hash.js'; +import { ScopedLogHash } from '../log_hash.js'; +import { PrivateLog } from '../private_log.js'; import { PublicCallRequest } from '../public_call_request.js'; export class PrivateToPublicAccumulatedData { @@ -23,8 +23,7 @@ export class PrivateToPublicAccumulatedData { public readonly noteHashes: Tuple, public readonly nullifiers: Tuple, public readonly l2ToL1Msgs: Tuple, - public readonly noteEncryptedLogsHashes: Tuple, - public readonly encryptedLogsHashes: Tuple, + public readonly privateLogs: Tuple, public readonly contractClassLogsHashes: Tuple, public readonly publicCallRequests: Tuple, ) {} @@ -34,8 +33,7 @@ export class PrivateToPublicAccumulatedData { arraySerializedSizeOfNonEmpty(this.noteHashes) + arraySerializedSizeOfNonEmpty(this.nullifiers) + arraySerializedSizeOfNonEmpty(this.l2ToL1Msgs) + - arraySerializedSizeOfNonEmpty(this.noteEncryptedLogsHashes) + - arraySerializedSizeOfNonEmpty(this.encryptedLogsHashes) + + arraySerializedSizeOfNonEmpty(this.privateLogs) + arraySerializedSizeOfNonEmpty(this.contractClassLogsHashes) + arraySerializedSizeOfNonEmpty(this.publicCallRequests) ); @@ -46,8 +44,7 @@ export class PrivateToPublicAccumulatedData { fields.noteHashes, fields.nullifiers, fields.l2ToL1Msgs, - fields.noteEncryptedLogsHashes, - fields.encryptedLogsHashes, + fields.privateLogs, fields.contractClassLogsHashes, fields.publicCallRequests, ] as const; @@ -59,8 +56,7 @@ export class PrivateToPublicAccumulatedData { reader.readFieldArray(MAX_NOTE_HASHES_PER_TX), reader.readFieldArray(MAX_NULLIFIERS_PER_TX), reader.readArray(MAX_L2_TO_L1_MSGS_PER_TX, ScopedL2ToL1Message), - reader.readArray(MAX_NOTE_ENCRYPTED_LOGS_PER_TX, LogHash), - reader.readArray(MAX_ENCRYPTED_LOGS_PER_TX, ScopedLogHash), + reader.readArray(MAX_PRIVATE_LOGS_PER_TX, PrivateLog), reader.readArray(MAX_CONTRACT_CLASS_LOGS_PER_TX, ScopedLogHash), reader.readArray(MAX_ENQUEUED_CALLS_PER_TX, PublicCallRequest), ); @@ -76,8 +72,7 @@ export class PrivateToPublicAccumulatedData { reader.readArray(MAX_NOTE_HASHES_PER_TX, Fr), reader.readArray(MAX_NULLIFIERS_PER_TX, Fr), reader.readArray(MAX_L2_TO_L1_MSGS_PER_TX, ScopedL2ToL1Message), - reader.readArray(MAX_NOTE_ENCRYPTED_LOGS_PER_TX, LogHash), - reader.readArray(MAX_ENCRYPTED_LOGS_PER_TX, ScopedLogHash), + reader.readArray(MAX_PRIVATE_LOGS_PER_TX, PrivateLog), reader.readArray(MAX_CONTRACT_CLASS_LOGS_PER_TX, ScopedLogHash), reader.readArray(MAX_ENQUEUED_CALLS_PER_TX, PublicCallRequest), ); @@ -92,8 +87,7 @@ export class PrivateToPublicAccumulatedData { makeTuple(MAX_NOTE_HASHES_PER_TX, Fr.zero), makeTuple(MAX_NULLIFIERS_PER_TX, Fr.zero), makeTuple(MAX_L2_TO_L1_MSGS_PER_TX, ScopedL2ToL1Message.empty), - makeTuple(MAX_NOTE_ENCRYPTED_LOGS_PER_TX, LogHash.empty), - makeTuple(MAX_ENCRYPTED_LOGS_PER_TX, ScopedLogHash.empty), + makeTuple(MAX_PRIVATE_LOGS_PER_TX, PrivateLog.empty), makeTuple(MAX_CONTRACT_CLASS_LOGS_PER_TX, ScopedLogHash.empty), makeTuple(MAX_ENQUEUED_CALLS_PER_TX, PublicCallRequest.empty), ); @@ -113,11 +107,7 @@ export class PrivateToPublicAccumulatedData { .filter(x => !x.isEmpty()) .map(x => inspect(x)) .join(', ')}], - noteEncryptedLogsHashes: [${this.noteEncryptedLogsHashes - .filter(x => !x.isEmpty()) - .map(h => inspect(h)) - .join(', ')}], - encryptedLogsHashes: [${this.encryptedLogsHashes + privateLogs: [${this.privateLogs .filter(x => !x.isEmpty()) .map(h => inspect(h)) .join(', ')}], diff --git a/yarn-project/circuits.js/src/structs/kernel/private_to_public_accumulated_data_builder.ts b/yarn-project/circuits.js/src/structs/kernel/private_to_public_accumulated_data_builder.ts index 66733d24df0..3b12e050190 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_to_public_accumulated_data_builder.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_to_public_accumulated_data_builder.ts @@ -3,15 +3,15 @@ import { Fr } from '@aztec/foundation/fields'; import { MAX_CONTRACT_CLASS_LOGS_PER_TX, - MAX_ENCRYPTED_LOGS_PER_TX, MAX_ENQUEUED_CALLS_PER_TX, MAX_L2_TO_L1_MSGS_PER_TX, - MAX_NOTE_ENCRYPTED_LOGS_PER_TX, MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, + MAX_PRIVATE_LOGS_PER_TX, } from '../../constants.gen.js'; import { ScopedL2ToL1Message } from '../l2_to_l1_message.js'; -import { LogHash, ScopedLogHash } from '../log_hash.js'; +import { ScopedLogHash } from '../log_hash.js'; +import { PrivateLog } from '../private_log.js'; import { PublicCallRequest } from '../public_call_request.js'; import { PrivateToPublicAccumulatedData } from './private_to_public_accumulated_data.js'; @@ -25,8 +25,7 @@ export class PrivateToPublicAccumulatedDataBuilder { private noteHashes: Fr[] = []; private nullifiers: Fr[] = []; private l2ToL1Msgs: ScopedL2ToL1Message[] = []; - private noteEncryptedLogsHashes: LogHash[] = []; - private encryptedLogsHashes: ScopedLogHash[] = []; + private privateLogs: PrivateLog[] = []; private contractClassLogsHashes: ScopedLogHash[] = []; private publicCallRequests: PublicCallRequest[] = []; @@ -60,23 +59,13 @@ export class PrivateToPublicAccumulatedDataBuilder { return this; } - pushNoteEncryptedLogsHash(noteEncryptedLogsHash: LogHash) { - this.noteEncryptedLogsHashes.push(noteEncryptedLogsHash); + pushPrivateLog(privateLog: PrivateLog) { + this.privateLogs.push(privateLog); return this; } - withNoteEncryptedLogsHashes(noteEncryptedLogsHashes: LogHash[]) { - this.noteEncryptedLogsHashes = noteEncryptedLogsHashes; - return this; - } - - pushEncryptedLogsHash(encryptedLogsHash: ScopedLogHash) { - this.encryptedLogsHashes.push(encryptedLogsHash); - return this; - } - - withEncryptedLogsHashes(encryptedLogsHashes: ScopedLogHash[]) { - this.encryptedLogsHashes = encryptedLogsHashes; + withPrivateLogs(privateLogs: PrivateLog[]) { + this.privateLogs = privateLogs; return this; } @@ -105,8 +94,7 @@ export class PrivateToPublicAccumulatedDataBuilder { padArrayEnd(this.noteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX), padArrayEnd(this.nullifiers, Fr.ZERO, MAX_NULLIFIERS_PER_TX), padArrayEnd(this.l2ToL1Msgs, ScopedL2ToL1Message.empty(), MAX_L2_TO_L1_MSGS_PER_TX), - padArrayEnd(this.noteEncryptedLogsHashes, LogHash.empty(), MAX_NOTE_ENCRYPTED_LOGS_PER_TX), - padArrayEnd(this.encryptedLogsHashes, ScopedLogHash.empty(), MAX_ENCRYPTED_LOGS_PER_TX), + padArrayEnd(this.privateLogs, PrivateLog.empty(), MAX_PRIVATE_LOGS_PER_TX), padArrayEnd(this.contractClassLogsHashes, ScopedLogHash.empty(), MAX_CONTRACT_CLASS_LOGS_PER_TX), padArrayEnd(this.publicCallRequests, PublicCallRequest.empty(), MAX_ENQUEUED_CALLS_PER_TX), ); diff --git a/yarn-project/circuits.js/src/structs/log_hash.ts b/yarn-project/circuits.js/src/structs/log_hash.ts index b0691826bbf..de06c7c02b4 100644 --- a/yarn-project/circuits.js/src/structs/log_hash.ts +++ b/yarn-project/circuits.js/src/structs/log_hash.ts @@ -94,118 +94,3 @@ export class ScopedLogHash implements Ordered { return sha256Trunc(Buffer.concat([this.contractAddress.toBuffer(), this.value.toBuffer()])); } } - -export class NoteLogHash implements Ordered { - constructor(public value: Fr, public counter: number, public length: Fr, public noteHashCounter: number) {} - - toFields(): Fr[] { - return [this.value, new Fr(this.counter), this.length, new Fr(this.noteHashCounter)]; - } - - static fromFields(fields: Fr[] | FieldReader) { - const reader = FieldReader.asReader(fields); - return new NoteLogHash(reader.readField(), reader.readU32(), reader.readField(), reader.readU32()); - } - - isEmpty() { - return this.value.isZero() && this.length.isZero() && !this.counter && !this.noteHashCounter; - } - - static empty() { - return new NoteLogHash(Fr.zero(), 0, Fr.zero(), 0); - } - - toBuffer(): Buffer { - return serializeToBuffer(this.value, this.counter, this.length, this.noteHashCounter); - } - - static fromBuffer(buffer: Buffer | BufferReader) { - const reader = BufferReader.asReader(buffer); - return new NoteLogHash(Fr.fromBuffer(reader), reader.readNumber(), Fr.fromBuffer(reader), reader.readNumber()); - } - - toString(): string { - return `value=${this.value} counter=${this.counter} length=${this.length} noteHashCounter=${this.noteHashCounter}`; - } -} - -export class EncryptedLogHash implements Ordered { - constructor(public value: Fr, public counter: number, public length: Fr, public randomness: Fr) {} - - toFields(): Fr[] { - return [this.value, new Fr(this.counter), this.length, this.randomness]; - } - - static fromFields(fields: Fr[] | FieldReader) { - const reader = FieldReader.asReader(fields); - return new EncryptedLogHash(reader.readField(), reader.readU32(), reader.readField(), reader.readField()); - } - - isEmpty() { - return this.value.isZero() && this.length.isZero() && !this.counter && this.randomness.isZero(); - } - - static empty() { - return new EncryptedLogHash(Fr.zero(), 0, Fr.zero(), Fr.zero()); - } - - toBuffer(): Buffer { - return serializeToBuffer(this.value, this.counter, this.length, this.randomness); - } - - static fromBuffer(buffer: Buffer | BufferReader) { - const reader = BufferReader.asReader(buffer); - return new EncryptedLogHash( - Fr.fromBuffer(reader), - reader.readNumber(), - Fr.fromBuffer(reader), - Fr.fromBuffer(reader), - ); - } - - toString(): string { - return `value=${this.value} counter=${this.counter} length=${this.length} randomness=${this.randomness}`; - } -} - -export class ScopedEncryptedLogHash implements Ordered { - constructor(public logHash: EncryptedLogHash, public contractAddress: AztecAddress) {} - - get counter() { - return this.logHash.counter; - } - - get value() { - return this.logHash.value; - } - - toFields(): Fr[] { - return [...this.logHash.toFields(), this.contractAddress.toField()]; - } - - static fromFields(fields: Fr[] | FieldReader) { - const reader = FieldReader.asReader(fields); - return new ScopedEncryptedLogHash(reader.readObject(EncryptedLogHash), AztecAddress.fromField(reader.readField())); - } - - isEmpty() { - return this.logHash.isEmpty() && this.contractAddress.isZero(); - } - - static empty() { - return new ScopedEncryptedLogHash(EncryptedLogHash.empty(), AztecAddress.ZERO); - } - - toBuffer(): Buffer { - return serializeToBuffer(this.logHash, this.contractAddress); - } - - static fromBuffer(buffer: Buffer | BufferReader) { - const reader = BufferReader.asReader(buffer); - return new ScopedEncryptedLogHash(EncryptedLogHash.fromBuffer(reader), AztecAddress.fromBuffer(reader)); - } - - toString(): string { - return `logHash=${this.logHash} contractAddress=${this.contractAddress}`; - } -} 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 cded605058d..c6de783a93a 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 @@ -12,16 +12,15 @@ import { type FieldsOf } from '@aztec/foundation/types'; import { MAX_CONTRACT_CLASS_LOGS_PER_CALL, - MAX_ENCRYPTED_LOGS_PER_CALL, MAX_ENQUEUED_CALLS_PER_CALL, MAX_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_L2_TO_L1_MSGS_PER_CALL, - MAX_NOTE_ENCRYPTED_LOGS_PER_CALL, MAX_NOTE_HASHES_PER_CALL, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NULLIFIERS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, + MAX_PRIVATE_LOGS_PER_CALL, PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH, } from '../constants.gen.js'; import { Header } from '../structs/header.js'; @@ -29,11 +28,12 @@ import { isEmptyArray } from '../utils/index.js'; import { CallContext } from './call_context.js'; import { KeyValidationRequestAndGenerator } from './key_validation_request_and_generator.js'; import { L2ToL1Message } from './l2_to_l1_message.js'; -import { EncryptedLogHash, LogHash, NoteLogHash } from './log_hash.js'; +import { LogHash } from './log_hash.js'; import { MaxBlockNumber } from './max_block_number.js'; import { NoteHash } from './note_hash.js'; import { Nullifier } from './nullifier.js'; import { PrivateCallRequest } from './private_call_request.js'; +import { PrivateLogData } from './private_log_data.js'; import { CountedPublicCallRequest, PublicCallRequest } from './public_call_request.js'; import { ReadRequest } from './read_request.js'; import { TxContext } from './tx_context.js'; @@ -107,28 +107,22 @@ export class PrivateCircuitPublicInputs { */ public l2ToL1Msgs: Tuple, /** - * The side effect counter at the start of this call. - */ - public startSideEffectCounter: Fr, - /** - * The end side effect counter for this call. + * Logs emitted in this function call. */ - public endSideEffectCounter: Fr, + public privateLogs: Tuple, /** - * Hash of the encrypted note logs emitted in this function call. + * Hash of the contract class logs emitted in this function call. * Note: Truncated to 31 bytes to fit in Fr. */ - public noteEncryptedLogsHashes: Tuple, + public contractClassLogsHashes: Tuple, /** - * Hash of the encrypted logs emitted in this function call. - * Note: Truncated to 31 bytes to fit in Fr. + * The side effect counter at the start of this call. */ - public encryptedLogsHashes: Tuple, + public startSideEffectCounter: Fr, /** - * Hash of the contract class logs emitted in this function call. - * Note: Truncated to 31 bytes to fit in Fr. + * The end side effect counter for this call. */ - public contractClassLogsHashes: Tuple, + public endSideEffectCounter: Fr, /** * Header of a block whose state is used during private execution (not the block the transaction is included in). */ @@ -175,11 +169,10 @@ export class PrivateCircuitPublicInputs { reader.readArray(MAX_ENQUEUED_CALLS_PER_CALL, CountedPublicCallRequest), reader.readObject(PublicCallRequest), reader.readArray(MAX_L2_TO_L1_MSGS_PER_CALL, L2ToL1Message), + reader.readArray(MAX_PRIVATE_LOGS_PER_CALL, PrivateLogData), + reader.readArray(MAX_CONTRACT_CLASS_LOGS_PER_CALL, LogHash), reader.readObject(Fr), reader.readObject(Fr), - reader.readArray(MAX_NOTE_ENCRYPTED_LOGS_PER_CALL, NoteLogHash), - reader.readArray(MAX_ENCRYPTED_LOGS_PER_CALL, EncryptedLogHash), - reader.readArray(MAX_CONTRACT_CLASS_LOGS_PER_CALL, LogHash), reader.readObject(Header), reader.readObject(TxContext), ); @@ -203,11 +196,10 @@ export class PrivateCircuitPublicInputs { reader.readArray(MAX_ENQUEUED_CALLS_PER_CALL, CountedPublicCallRequest), reader.readObject(PublicCallRequest), reader.readArray(MAX_L2_TO_L1_MSGS_PER_CALL, L2ToL1Message), + reader.readArray(MAX_PRIVATE_LOGS_PER_CALL, PrivateLogData), + reader.readArray(MAX_CONTRACT_CLASS_LOGS_PER_CALL, LogHash), reader.readField(), reader.readField(), - reader.readArray(MAX_NOTE_ENCRYPTED_LOGS_PER_CALL, NoteLogHash), - reader.readArray(MAX_ENCRYPTED_LOGS_PER_CALL, EncryptedLogHash), - reader.readArray(MAX_CONTRACT_CLASS_LOGS_PER_CALL, LogHash), reader.readObject(Header), reader.readObject(TxContext), ); @@ -234,11 +226,10 @@ export class PrivateCircuitPublicInputs { makeTuple(MAX_ENQUEUED_CALLS_PER_CALL, CountedPublicCallRequest.empty), PublicCallRequest.empty(), makeTuple(MAX_L2_TO_L1_MSGS_PER_CALL, L2ToL1Message.empty), + makeTuple(MAX_PRIVATE_LOGS_PER_CALL, PrivateLogData.empty), + makeTuple(MAX_CONTRACT_CLASS_LOGS_PER_CALL, LogHash.empty), Fr.ZERO, Fr.ZERO, - makeTuple(MAX_NOTE_ENCRYPTED_LOGS_PER_CALL, NoteLogHash.empty), - makeTuple(MAX_ENCRYPTED_LOGS_PER_CALL, EncryptedLogHash.empty), - makeTuple(MAX_CONTRACT_CLASS_LOGS_PER_CALL, LogHash.empty), Header.empty(), TxContext.empty(), ); @@ -261,9 +252,10 @@ export class PrivateCircuitPublicInputs { isEmptyArray(this.publicCallRequests) && this.publicTeardownCallRequest.isEmpty() && isEmptyArray(this.l2ToL1Msgs) && - isEmptyArray(this.noteEncryptedLogsHashes) && - isEmptyArray(this.encryptedLogsHashes) && + isEmptyArray(this.privateLogs) && isEmptyArray(this.contractClassLogsHashes) && + this.startSideEffectCounter.isZero() && + this.endSideEffectCounter.isZero() && this.historicalHeader.isEmpty() && this.txContext.isEmpty() ); @@ -291,11 +283,10 @@ export class PrivateCircuitPublicInputs { fields.publicCallRequests, fields.publicTeardownCallRequest, fields.l2ToL1Msgs, + fields.privateLogs, + fields.contractClassLogsHashes, fields.startSideEffectCounter, fields.endSideEffectCounter, - fields.noteEncryptedLogsHashes, - fields.encryptedLogsHashes, - fields.contractClassLogsHashes, fields.historicalHeader, fields.txContext, ] as const; diff --git a/yarn-project/circuits.js/src/structs/private_log.ts b/yarn-project/circuits.js/src/structs/private_log.ts new file mode 100644 index 00000000000..8e019eee09c --- /dev/null +++ b/yarn-project/circuits.js/src/structs/private_log.ts @@ -0,0 +1,59 @@ +import { makeTuple } from '@aztec/foundation/array'; +import { Fr } from '@aztec/foundation/fields'; +import { schemas } from '@aztec/foundation/schemas'; +import { BufferReader, FieldReader, type Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; + +import { inspect } from 'util'; +import { z } from 'zod'; + +import { PRIVATE_LOG_SIZE_IN_FIELDS } from '../constants.gen.js'; + +export class PrivateLog { + static SIZE_IN_BYTES = Fr.SIZE_IN_BYTES * PRIVATE_LOG_SIZE_IN_FIELDS; + + constructor(public fields: Tuple) {} + + toFields(): Fr[] { + return this.fields; + } + + static fromFields(fields: Fr[] | FieldReader) { + const reader = FieldReader.asReader(fields); + return new PrivateLog(reader.readFieldArray(PRIVATE_LOG_SIZE_IN_FIELDS)); + } + + isEmpty() { + return this.fields.every(f => f.isZero()); + } + + static empty() { + return new PrivateLog(makeTuple(PRIVATE_LOG_SIZE_IN_FIELDS, Fr.zero)); + } + + toBuffer(): Buffer { + return serializeToBuffer(this.fields); + } + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new PrivateLog(reader.readArray(PRIVATE_LOG_SIZE_IN_FIELDS, Fr)); + } + + static random() { + return new PrivateLog(makeTuple(PRIVATE_LOG_SIZE_IN_FIELDS, Fr.random)); + } + + static get schema() { + return z + .object({ + fields: z.array(schemas.Fr), + }) + .transform(({ fields }) => PrivateLog.fromFields(fields)); + } + + [inspect.custom](): string { + return `PrivateLog { + fields: [${this.fields.map(x => inspect(x)).join(', ')}], + }`; + } +} diff --git a/yarn-project/circuits.js/src/structs/private_log_data.ts b/yarn-project/circuits.js/src/structs/private_log_data.ts new file mode 100644 index 00000000000..7924e2a6df1 --- /dev/null +++ b/yarn-project/circuits.js/src/structs/private_log_data.ts @@ -0,0 +1,107 @@ +import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { type Fr } from '@aztec/foundation/fields'; +import { BufferReader, FieldReader, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; +import { type FieldsOf } from '@aztec/foundation/types'; + +import { inspect } from 'util'; + +import { PRIVATE_LOG_DATA_LENGTH } from '../constants.gen.js'; +import { PrivateLog } from './private_log.js'; +import { type UInt32 } from './shared.js'; + +export class PrivateLogData { + constructor(public log: PrivateLog, public noteHashCounter: UInt32, public counter: UInt32) {} + + static from(fields: FieldsOf): PrivateLogData { + return new PrivateLogData(...PrivateLogData.getFields(fields)); + } + + static getFields(fields: FieldsOf) { + return [fields.log, fields.noteHashCounter, fields.counter] as const; + } + + static fromFields(fields: Fr[] | FieldReader): PrivateLogData { + const reader = FieldReader.asReader(fields); + return new PrivateLogData(reader.readObject(PrivateLog), reader.readU32(), reader.readU32()); + } + + toFields(): Fr[] { + const fields = serializeToFields(...PrivateLogData.getFields(this)); + if (fields.length !== PRIVATE_LOG_DATA_LENGTH) { + throw new Error( + `Invalid number of fields for PrivateLogData. Expected ${PRIVATE_LOG_DATA_LENGTH}, got ${fields.length}`, + ); + } + return fields; + } + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new PrivateLogData(reader.readObject(PrivateLog), reader.readNumber(), reader.readNumber()); + } + + toBuffer() { + return serializeToBuffer(...PrivateLogData.getFields(this)); + } + + static empty() { + return new PrivateLogData(PrivateLog.empty(), 0, 0); + } + + isEmpty(): boolean { + return this.log.isEmpty() && !this.noteHashCounter && !this.counter; + } + + [inspect.custom]() { + return `PrivateLogData { + log: ${this.log} + noteHashCounter: ${this.noteHashCounter} + counter: ${this.counter} + }`; + } +} + +export class ScopedPrivateLogData { + constructor(public inner: PrivateLogData, public contractAddress: AztecAddress) {} + + static from(fields: FieldsOf): ScopedPrivateLogData { + return new ScopedPrivateLogData(...ScopedPrivateLogData.getFields(fields)); + } + + static getFields(fields: FieldsOf) { + return [fields.inner, fields.contractAddress] as const; + } + + toFields(): Fr[] { + return serializeToFields(...ScopedPrivateLogData.getFields(this)); + } + + static fromFields(fields: Fr[] | FieldReader) { + const reader = FieldReader.asReader(fields); + return new ScopedPrivateLogData(reader.readObject(PrivateLogData), AztecAddress.fromField(reader.readField())); + } + + isEmpty() { + return this.inner.isEmpty() && this.contractAddress.isZero(); + } + + static empty() { + return new ScopedPrivateLogData(PrivateLogData.empty(), AztecAddress.ZERO); + } + + toBuffer(): Buffer { + return serializeToBuffer(...ScopedPrivateLogData.getFields(this)); + } + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new ScopedPrivateLogData(PrivateLogData.fromBuffer(reader), AztecAddress.fromBuffer(reader)); + } + + [inspect.custom]() { + return `ScopedPrivateLogData { + inner: ${this.inner} + contractAddress: ${this.contractAddress} + }`; + } +} diff --git a/yarn-project/circuits.js/src/structs/tagging_secret.ts b/yarn-project/circuits.js/src/structs/tagging_secret.ts index 0c5c7175d7f..97371fe7a8b 100644 --- a/yarn-project/circuits.js/src/structs/tagging_secret.ts +++ b/yarn-project/circuits.js/src/structs/tagging_secret.ts @@ -16,4 +16,9 @@ export class IndexedTaggingSecret { computeTag(recipient: AztecAddress) { return poseidon2Hash([this.secret, recipient, this.index]); } + + computeSiloedTag(recipient: AztecAddress, contractAddress: AztecAddress) { + const tag = this.computeTag(recipient); + return poseidon2Hash([contractAddress, tag]); + } } diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index cfed4e3241f..79d5d63d2c6 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -34,7 +34,6 @@ import { ConstantRollupData, ContractStorageRead, ContractStorageUpdateRequest, - EncryptedLogHash, Fr, FunctionData, FunctionSelector, @@ -46,15 +45,11 @@ import { L2ToL1Message, LogHash, MAX_CONTRACT_CLASS_LOGS_PER_TX, - MAX_ENCRYPTED_LOGS_PER_CALL, - MAX_ENCRYPTED_LOGS_PER_TX, MAX_ENQUEUED_CALLS_PER_CALL, MAX_ENQUEUED_CALLS_PER_TX, MAX_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_L2_TO_L1_MSGS_PER_CALL, MAX_L2_TO_L1_MSGS_PER_TX, - MAX_NOTE_ENCRYPTED_LOGS_PER_CALL, - MAX_NOTE_ENCRYPTED_LOGS_PER_TX, MAX_NOTE_HASHES_PER_CALL, MAX_NOTE_HASHES_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, @@ -62,6 +57,8 @@ import { MAX_NULLIFIERS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, + MAX_PRIVATE_LOGS_PER_CALL, + MAX_PRIVATE_LOGS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX, @@ -76,9 +73,9 @@ import { NUM_BASE_PARITY_PER_ROOT_PARITY, NUM_MSGS_PER_BASE_PARITY, NoteHash, - NoteLogHash, Nullifier, NullifierLeafPreimage, + PRIVATE_LOG_SIZE_IN_FIELDS, PUBLIC_DATA_TREE_HEIGHT, ParityPublicInputs, PartialPrivateTailPublicInputsForPublic, @@ -141,6 +138,8 @@ import { PrivateBaseRollupHints, PrivateBaseRollupInputs, PrivateBaseStateDiffHints, + PrivateLog, + PrivateLogData, PrivateToAvmAccumulatedData, PrivateToAvmAccumulatedDataArrayLengths, PrivateToPublicAccumulatedData, @@ -176,14 +175,6 @@ function makeLogHash(seed: number) { return new LogHash(fr(seed), seed + 1, fr(seed + 2)); } -function makeEncryptedLogHash(seed: number) { - return new EncryptedLogHash(fr(seed), seed + 1, fr(seed + 2), fr(seed + 3)); -} - -function makeNoteLogHash(seed: number) { - return new NoteLogHash(fr(seed + 3), seed + 1, fr(seed + 2), seed); -} - function makeScopedLogHash(seed: number) { return new ScopedLogHash(makeLogHash(seed), makeAztecAddress(seed + 3)); } @@ -196,6 +187,14 @@ function makeNullifier(seed: number) { return new Nullifier(fr(seed), seed + 1, fr(seed + 2)); } +function makePrivateLog(seed: number) { + return new PrivateLog(makeTuple(PRIVATE_LOG_SIZE_IN_FIELDS, fr, seed)); +} + +function makePrivateLogData(seed: number) { + return new PrivateLogData(makePrivateLog(seed + 0x100), seed, seed + 1); +} + /** * Creates an arbitrary tx context with the given seed. * @param seed - The seed to use for generating the tx context. @@ -313,12 +312,9 @@ export function makeCombinedAccumulatedData(seed = 1, full = false): CombinedAcc tupleGenerator(MAX_NOTE_HASHES_PER_TX, fr, seed + 0x120, Fr.zero), tupleGenerator(MAX_NULLIFIERS_PER_TX, fr, seed + 0x200, Fr.zero), tupleGenerator(MAX_L2_TO_L1_MSGS_PER_TX, makeScopedL2ToL1Message, seed + 0x600, ScopedL2ToL1Message.empty), - tupleGenerator(MAX_NOTE_ENCRYPTED_LOGS_PER_TX, makeLogHash, seed + 0x700, LogHash.empty), - tupleGenerator(MAX_ENCRYPTED_LOGS_PER_TX, makeScopedLogHash, seed + 0x800, ScopedLogHash.empty), + tupleGenerator(MAX_PRIVATE_LOGS_PER_TX, makePrivateLog, seed + 0x700, PrivateLog.empty), tupleGenerator(MAX_UNENCRYPTED_LOGS_PER_TX, makeScopedLogHash, seed + 0x900, ScopedLogHash.empty), // unencrypted logs tupleGenerator(MAX_CONTRACT_CLASS_LOGS_PER_TX, makeScopedLogHash, seed + 0xa00, ScopedLogHash.empty), // contract class logs - fr(seed + 0xb00), // note_encrypted_log_preimages_length - fr(seed + 0xc00), // encrypted_log_preimages_length fr(seed + 0xd00), // unencrypted_log_preimages_length fr(seed + 0xe00), // contract_class_log_preimages_length tupleGenerator(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, makePublicDataWrite, seed + 0xd00, PublicDataWrite.empty), @@ -330,8 +326,7 @@ export function makePrivateToPublicAccumulatedData(seed = 1) { makeTuple(MAX_NOTE_HASHES_PER_TX, fr, seed), makeTuple(MAX_NULLIFIERS_PER_TX, fr, seed + 0x100), makeTuple(MAX_L2_TO_L1_MSGS_PER_TX, makeScopedL2ToL1Message, seed + 0x200), - makeTuple(MAX_NOTE_ENCRYPTED_LOGS_PER_TX, makeLogHash, seed + 0x700), - makeTuple(MAX_ENCRYPTED_LOGS_PER_TX, makeScopedLogHash, seed + 0x800), + makeTuple(MAX_PRIVATE_LOGS_PER_TX, makePrivateLog, seed + 0x700), makeTuple(MAX_CONTRACT_CLASS_LOGS_PER_TX, makeScopedLogHash, seed + 0x900), makeTuple(MAX_ENQUEUED_CALLS_PER_TX, makePublicCallRequest, seed + 0x500), ); @@ -571,11 +566,10 @@ export function makePrivateCircuitPublicInputs(seed = 0): PrivateCircuitPublicIn publicCallRequests: makeTuple(MAX_ENQUEUED_CALLS_PER_CALL, makeCountedPublicCallRequest, seed + 0x700), publicTeardownCallRequest: makePublicCallRequest(seed + 0x800), l2ToL1Msgs: makeTuple(MAX_L2_TO_L1_MSGS_PER_CALL, makeL2ToL1Message, seed + 0x800), + privateLogs: makeTuple(MAX_PRIVATE_LOGS_PER_CALL, makePrivateLogData, seed + 0x875), + contractClassLogsHashes: makeTuple(MAX_CONTRACT_CLASS_LOGS_PER_TX, makeLogHash, seed + 0xa00), startSideEffectCounter: fr(seed + 0x849), endSideEffectCounter: fr(seed + 0x850), - noteEncryptedLogsHashes: makeTuple(MAX_NOTE_ENCRYPTED_LOGS_PER_CALL, makeNoteLogHash, seed + 0x875), - encryptedLogsHashes: makeTuple(MAX_ENCRYPTED_LOGS_PER_CALL, makeEncryptedLogHash, seed + 0x900), - contractClassLogsHashes: makeTuple(MAX_CONTRACT_CLASS_LOGS_PER_TX, makeLogHash, seed + 0xa00), historicalHeader: makeHeader(seed + 0xd00, undefined), txContext: makeTxContext(seed + 0x1400), isFeePayer: false, diff --git a/yarn-project/circuits.js/src/tests/fixtures.ts b/yarn-project/circuits.js/src/tests/fixtures.ts index 280c4240bb5..a771830b5b5 100644 --- a/yarn-project/circuits.js/src/tests/fixtures.ts +++ b/yarn-project/circuits.js/src/tests/fixtures.ts @@ -20,34 +20,6 @@ export function getTestContractArtifact(): ContractArtifact { return loadContractArtifact(content); } -// Copied from the test 'registers a new contract class' in end-to-end/src/e2e_deploy_contract.test.ts -export function getSampleContractClassRegisteredEventPayload(): Buffer { - const path = getPathToFixture('ContractClassRegisteredEventData.hex'); - return Buffer.from(readFileSync(path).toString(), 'hex'); -} - -// This is generated with code like this: -// const tx = await StatefulTestContract.deploy(wallet, owner, owner, 42).send({ universalDeploy: true }).wait(); -// const logs = await pxe.getUnencryptedLogs({ txHash: tx.txHash }); -// const logData = logs.logs[0].log.data; -// writeTestData('yarn-project/circuits.js/fixtures/ContractInstanceDeployedEventData.hex', logData); -export function getSampleContractInstanceDeployedEventPayload(): Buffer { - const path = getPathToFixture('ContractInstanceDeployedEventData.hex'); - return Buffer.from(readFileSync(path).toString(), 'hex'); -} - -// Generated from end-to-end/src/e2e_deploy_contract.test.ts with AZTEC_GENERATE_TEST_DATA -export function getSamplePrivateFunctionBroadcastedEventPayload(): Buffer { - const path = getPathToFixture('PrivateFunctionBroadcastedEventData.hex'); - return Buffer.from(readFileSync(path).toString(), 'hex'); -} - -// Generated from end-to-end/src/e2e_deploy_contract.test.ts with AZTEC_GENERATE_TEST_DATA -export function getSampleUnconstrainedFunctionBroadcastedEventPayload(): Buffer { - const path = getPathToFixture('UnconstrainedFunctionBroadcastedEventData.hex'); - return Buffer.from(readFileSync(path).toString(), 'hex'); -} - export function getPathToFixture(name: string) { return resolve(dirname(fileURLToPath(import.meta.url)), `../../fixtures/${name}`); } diff --git a/yarn-project/cli/src/utils/inspect.ts b/yarn-project/cli/src/utils/inspect.ts index 4423b9bc882..80c87f4c79d 100644 --- a/yarn-project/cli/src/utils/inspect.ts +++ b/yarn-project/cli/src/utils/inspect.ts @@ -39,7 +39,7 @@ export async function inspectTx( log: LogFn, opts: { includeBlockInfo?: boolean; artifactMap?: ArtifactMap } = {}, ) { - const [receipt, effectsInBlock, notes] = await Promise.all([ + const [receipt, effectsInBlock, incomingNotes] = await Promise.all([ pxe.getTxReceipt(txHash), pxe.getTxEffect(txHash), pxe.getIncomingNotes({ txHash, status: NoteStatus.ACTIVE_OR_NULLIFIED }), @@ -85,15 +85,15 @@ export async function inspectTx( } // Created notes - const noteEncryptedLogsCount = effects.noteEncryptedLogs.unrollLogs().length; - if (noteEncryptedLogsCount > 0) { + const notes = effects.noteHashes; + if (notes.length > 0) { log(' Created notes:'); - const notVisibleNotes = noteEncryptedLogsCount - notes.length; - if (notVisibleNotes > 0) { - log(` ${notVisibleNotes} notes not visible in the PXE`); - } - for (const note of notes) { - inspectNote(note, artifactMap, log); + log(` Total: ${notes.length}. Incoming: ${incomingNotes.length}.`); + if (incomingNotes.length) { + log(' Incoming notes:'); + for (const note of incomingNotes) { + inspectNote(note, artifactMap, log); + } } } diff --git a/yarn-project/end-to-end/src/e2e_2_pxes.test.ts b/yarn-project/end-to-end/src/e2e_2_pxes.test.ts index c95e16b9d7a..d3dded0788d 100644 --- a/yarn-project/end-to-end/src/e2e_2_pxes.test.ts +++ b/yarn-project/end-to-end/src/e2e_2_pxes.test.ts @@ -57,7 +57,8 @@ describe('e2e_2_pxes', () => { await teardownA(); }); - it('transfers funds from user A to B via PXE A followed by transfer from B to A via PXE B', async () => { + // TODO #10296 + it.skip('transfers funds from user A to B via PXE A followed by transfer from B to A via PXE B', async () => { const initialBalance = 987n; const transferAmount1 = 654n; const transferAmount2 = 323n; diff --git a/yarn-project/end-to-end/src/e2e_block_building.test.ts b/yarn-project/end-to-end/src/e2e_block_building.test.ts index 41a27b70a92..4989a66d0a9 100644 --- a/yarn-project/end-to-end/src/e2e_block_building.test.ts +++ b/yarn-project/end-to-end/src/e2e_block_building.test.ts @@ -8,6 +8,7 @@ import { type DebugLogger, Fq, Fr, + L1EventPayload, L1NotePayload, type PXE, TxStatus, @@ -18,7 +19,7 @@ import { } from '@aztec/aztec.js'; import { getL1ContractsConfigEnvVars } from '@aztec/ethereum'; import { times } from '@aztec/foundation/collection'; -import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto'; +import { poseidon2Hash } from '@aztec/foundation/crypto'; import { StatefulTestContract, StatefulTestContractArtifact } from '@aztec/noir-contracts.js'; import { TestContract } from '@aztec/noir-contracts.js/Test'; import { TokenContract } from '@aztec/noir-contracts.js/Token'; @@ -299,8 +300,8 @@ describe('e2e_block_building', () => { // compare logs expect(rct.status).toEqual('success'); - const noteValues = tx.noteEncryptedLogs.unrollLogs().map(l => { - const notePayload = L1NotePayload.decryptAsIncoming(l.data, thisWallet.getEncryptionSecret()); + const noteValues = tx.data.getNonEmptyPrivateLogs().map(log => { + const notePayload = L1NotePayload.decryptAsIncoming(log, thisWallet.getEncryptionSecret()); // In this test we care only about the privately delivered values return notePayload?.privateNoteValues[0]; }); @@ -319,8 +320,10 @@ describe('e2e_block_building', () => { const outgoingViewer = thisWallet.getAddress(); // call test contract + const values = [new Fr(5), new Fr(4), new Fr(3), new Fr(2), new Fr(1)]; + const nestedValues = [new Fr(0), new Fr(0), new Fr(0), new Fr(0), new Fr(0)]; const action = testContract.methods.emit_array_as_encrypted_log( - [5, 4, 3, 2, 1], + values, thisWallet.getAddress(), outgoingViewer, true, @@ -330,19 +333,20 @@ describe('e2e_block_building', () => { // compare logs expect(rct.status).toEqual('success'); - const encryptedLogs = tx.encryptedLogs.unrollLogs(); - expect(encryptedLogs[0].maskedContractAddress).toEqual( - poseidon2HashWithSeparator([testContract.address, new Fr(5)], 0), - ); - expect(encryptedLogs[1].maskedContractAddress).toEqual( - poseidon2HashWithSeparator([testContract.address, new Fr(5)], 0), - ); - // Setting randomness = 0 in app means 'do not mask the address' - expect(encryptedLogs[2].maskedContractAddress).toEqual(testContract.address.toField()); + const privateLogs = tx.data.getNonEmptyPrivateLogs(); + expect(privateLogs.length).toBe(3); + + // The first two logs are encrypted. + const event0 = L1EventPayload.decryptAsIncoming(privateLogs[0], thisWallet.getEncryptionSecret())!; + expect(event0.event.items).toEqual(values); + + const event1 = L1EventPayload.decryptAsIncoming(privateLogs[1], thisWallet.getEncryptionSecret())!; + expect(event1.event.items).toEqual(nestedValues); - // TODO(1139 | 6408): We currently encrypted generic event logs the same way as notes, so the below - // will likely not be useful when complete. - // const decryptedLogs = encryptedLogs.map(l => TaggedNote.decryptAsIncoming(l.data, keys.masterIncomingViewingSecretKey)); + // The last log is not encrypted. + // The first field is the first value and is siloed with contract address by the kernel circuit. + const expectedFirstField = poseidon2Hash([testContract.address, values[0]]); + expect(privateLogs[2].fields.slice(0, 5)).toEqual([expectedFirstField, ...values.slice(1)]); }, 60_000); }); diff --git a/yarn-project/end-to-end/src/e2e_deploy_contract/contract_class_registration.test.ts b/yarn-project/end-to-end/src/e2e_deploy_contract/contract_class_registration.test.ts index 46161491706..f74795170f2 100644 --- a/yarn-project/end-to-end/src/e2e_deploy_contract/contract_class_registration.test.ts +++ b/yarn-project/end-to-end/src/e2e_deploy_contract/contract_class_registration.test.ts @@ -71,6 +71,12 @@ describe('e2e_deploy_contract contract class registration', () => { }); it('registers the contract class on the node', async () => { + // TODO(#10007) Enable this. + // const logs = await aztecNode.getContractClassLogs({ txHash: registrationTxReceipt.txHash }); + // expect(logs.logs.length).toEqual(1); + // const logData = logs.logs[0].log.data; + // writeTestData('yarn-project/protocol-contracts/fixtures/ContractClassRegisteredEventData.hex', logData); + const registeredClass = await aztecNode.getContractClass(contractClass.id); expect(registeredClass).toBeDefined(); expect(registeredClass!.artifactHash.toString()).toEqual(contractClass.artifactHash.toString()); @@ -92,7 +98,7 @@ describe('e2e_deploy_contract contract class registration', () => { const tx = await (await broadcastPrivateFunction(wallet, artifact, selector)).send().wait(); const logs = await pxe.getContractClassLogs({ txHash: tx.txHash }); const logData = logs.logs[0].log.data; - writeTestData('yarn-project/circuits.js/fixtures/PrivateFunctionBroadcastedEventData.hex', logData); + writeTestData('yarn-project/protocol-contracts/fixtures/PrivateFunctionBroadcastedEventData.hex', logData); const fetchedClass = await aztecNode.getContractClass(contractClass.id); const fetchedFunction = fetchedClass!.privateFunctions[0]!; @@ -106,7 +112,7 @@ describe('e2e_deploy_contract contract class registration', () => { const tx = await (await broadcastUnconstrainedFunction(wallet, artifact, selector)).send().wait(); const logs = await pxe.getContractClassLogs({ txHash: tx.txHash }); const logData = logs.logs[0].log.data; - writeTestData('yarn-project/circuits.js/fixtures/UnconstrainedFunctionBroadcastedEventData.hex', logData); + writeTestData('yarn-project/protocol-contracts/fixtures/UnconstrainedFunctionBroadcastedEventData.hex', logData); const fetchedClass = await aztecNode.getContractClass(contractClass.id); const fetchedFunction = fetchedClass!.unconstrainedFunctions[0]!; @@ -163,6 +169,15 @@ describe('e2e_deploy_contract contract class registration', () => { }); it('stores contract instance in the aztec node', async () => { + // Contract instance deployed event is emitted via private logs. + const block = await aztecNode.getBlockNumber(); + const logs = await aztecNode.getPrivateLogs(block, 1); + expect(logs.length).toBe(1); + writeTestData( + 'yarn-project/protocol-contracts/fixtures/ContractInstanceDeployedEventData.hex', + logs[0].toBuffer(), + ); + const deployed = await aztecNode.getContract(instance.address); expect(deployed).toBeDefined(); expect(deployed!.address).toEqual(instance.address); diff --git a/yarn-project/end-to-end/src/e2e_event_logs.test.ts b/yarn-project/end-to-end/src/e2e_event_logs.test.ts index 162d53d6eb0..bfecaead50e 100644 --- a/yarn-project/end-to-end/src/e2e_event_logs.test.ts +++ b/yarn-project/end-to-end/src/e2e_event_logs.test.ts @@ -38,23 +38,18 @@ describe('Logs', () => { describe('functionality around emitting an encrypted log', () => { it('emits multiple events as encrypted logs and decodes them one manually', async () => { - const randomness = makeTuple(2, Fr.random); const preimage = makeTuple(4, Fr.random); - const tx = await testLogContract.methods - .emit_encrypted_events(wallets[1].getAddress(), randomness, preimage) - .send() - .wait(); + const tx = await testLogContract.methods.emit_encrypted_events(wallets[1].getAddress(), preimage).send().wait(); const txEffect = await node.getTxEffect(tx.txHash); - const encryptedLogs = txEffect!.data.encryptedLogs.unrollLogs(); - expect(encryptedLogs.length).toBe(3); + const privateLogs = txEffect!.data.privateLogs; + expect(privateLogs.length).toBe(3); - const decryptedEvent0 = L1EventPayload.decryptAsIncoming(encryptedLogs[0], wallets[0].getEncryptionSecret())!; + const decryptedEvent0 = L1EventPayload.decryptAsIncoming(privateLogs[0], wallets[0].getEncryptionSecret())!; expect(decryptedEvent0.contractAddress).toStrictEqual(testLogContract.address); - expect(decryptedEvent0.randomness).toStrictEqual(randomness[0]); expect(decryptedEvent0.eventTypeId).toStrictEqual(EventSelector.fromSignature('ExampleEvent0(Field,Field)')); // We decode our event into the event type @@ -65,7 +60,7 @@ describe('Logs', () => { expect(event0?.value0).toStrictEqual(preimage[0].toBigInt()); expect(event0?.value1).toStrictEqual(preimage[1].toBigInt()); - const decryptedEvent1 = L1EventPayload.decryptAsIncoming(encryptedLogs[2], wallets[0].getEncryptionSecret())!; + const decryptedEvent1 = L1EventPayload.decryptAsIncoming(privateLogs[2], wallets[0].getEncryptionSecret())!; const event1Metadata = new EventMetadata(TestLogContract.events.ExampleEvent1); @@ -77,7 +72,6 @@ describe('Logs', () => { expect(badEvent0).toBe(undefined); expect(decryptedEvent1.contractAddress).toStrictEqual(testLogContract.address); - expect(decryptedEvent1.randomness).toStrictEqual(randomness[1]); expect(decryptedEvent1.eventTypeId).toStrictEqual(EventSelector.fromSignature('ExampleEvent1((Field),u8)')); // We expect the fields to have been populated correctly @@ -91,54 +85,44 @@ describe('Logs', () => { }); it('emits multiple events as encrypted logs and decodes them', async () => { - const randomness = makeTuple(5, makeTuple.bind(undefined, 2, Fr.random)) as Tuple, 5>; - const preimage = makeTuple(5, makeTuple.bind(undefined, 4, Fr.random)) as Tuple, 5>; + const preimages = makeTuple(5, makeTuple.bind(undefined, 4, Fr.random)) as Tuple, 5>; - let i = 0; - const firstTx = await testLogContract.methods - .emit_encrypted_events(wallets[1].getAddress(), randomness[i], preimage[i]) - .send() - .wait(); - await Promise.all( - [...new Array(3)].map(() => - testLogContract.methods - .emit_encrypted_events(wallets[1].getAddress(), randomness[++i], preimage[i]) - .send() - .wait(), + const txs = await Promise.all( + preimages.map(preimage => + testLogContract.methods.emit_encrypted_events(wallets[1].getAddress(), preimage).send().wait(), ), ); - const lastTx = await testLogContract.methods - .emit_encrypted_events(wallets[1].getAddress(), randomness[++i], preimage[i]) - .send() - .wait(); + const firstBlockNumber = Math.min(...txs.map(tx => tx.blockNumber!)); + const lastBlockNumber = Math.max(...txs.map(tx => tx.blockNumber!)); + const numBlocks = lastBlockNumber - firstBlockNumber + 1; // We get all the events we can decrypt with either our incoming or outgoing viewing keys const collectedEvent0s = await wallets[0].getEncryptedEvents( TestLogContract.events.ExampleEvent0, - firstTx.blockNumber!, - lastTx.blockNumber! - firstTx.blockNumber! + 1, + firstBlockNumber, + numBlocks, ); const collectedEvent0sWithIncoming = await wallets[0].getEncryptedEvents( TestLogContract.events.ExampleEvent0, - firstTx.blockNumber!, - lastTx.blockNumber! - firstTx.blockNumber! + 1, + firstBlockNumber, + numBlocks, // This function can be called specifying the viewing public keys associated with the encrypted event. [wallets[0].getCompleteAddress().publicKeys.masterIncomingViewingPublicKey], ); const collectedEvent0sWithOutgoing = await wallets[0].getEncryptedEvents( TestLogContract.events.ExampleEvent0, - firstTx.blockNumber!, - lastTx.blockNumber! - firstTx.blockNumber! + 1, + firstBlockNumber, + numBlocks, [wallets[0].getCompleteAddress().publicKeys.masterOutgoingViewingPublicKey], ); const collectedEvent1s = await wallets[0].getEncryptedEvents( TestLogContract.events.ExampleEvent1, - firstTx.blockNumber!, - lastTx.blockNumber! - firstTx.blockNumber! + 1, + firstBlockNumber, + numBlocks, [wallets[0].getCompleteAddress().publicKeys.masterIncomingViewingPublicKey], ); @@ -149,8 +133,8 @@ describe('Logs', () => { const emptyEvent1s = await wallets[0].getEncryptedEvents( TestLogContract.events.ExampleEvent1, - firstTx.blockNumber!, - lastTx.blockNumber! - firstTx.blockNumber! + 1, + firstBlockNumber, + numBlocks, [wallets[0].getCompleteAddress().publicKeys.masterOutgoingViewingPublicKey], ); @@ -158,13 +142,13 @@ describe('Logs', () => { const exampleEvent0Sort = (a: ExampleEvent0, b: ExampleEvent0) => (a.value0 > b.value0 ? 1 : -1); expect(collectedEvent0sWithIncoming.sort(exampleEvent0Sort)).toStrictEqual( - preimage + preimages .map(preimage => ({ value0: preimage[0].toBigInt(), value1: preimage[1].toBigInt() })) .sort(exampleEvent0Sort), ); expect(collectedEvent0sWithOutgoing.sort(exampleEvent0Sort)).toStrictEqual( - preimage + preimages .map(preimage => ({ value0: preimage[0].toBigInt(), value1: preimage[1].toBigInt() })) .sort(exampleEvent0Sort), ); @@ -175,7 +159,7 @@ describe('Logs', () => { const exampleEvent1Sort = (a: ExampleEvent1, b: ExampleEvent1) => (a.value2 > b.value2 ? 1 : -1); expect(collectedEvent1s.sort(exampleEvent1Sort)).toStrictEqual( - preimage + preimages .map(preimage => ({ value2: new AztecAddress(preimage[2]), // We get the last byte here because value3 is of type u8 diff --git a/yarn-project/end-to-end/src/e2e_multiple_accounts_1_enc_key.test.ts b/yarn-project/end-to-end/src/e2e_multiple_accounts_1_enc_key.test.ts index a2cce349b9c..ff22b574df3 100644 --- a/yarn-project/end-to-end/src/e2e_multiple_accounts_1_enc_key.test.ts +++ b/yarn-project/end-to-end/src/e2e_multiple_accounts_1_enc_key.test.ts @@ -1,6 +1,5 @@ import { getSchnorrAccount } from '@aztec/accounts/schnorr'; import { - type AztecNode, type CompleteAddress, type DebugLogger, Fr, @@ -12,10 +11,9 @@ import { import { TokenContract } from '@aztec/noir-contracts.js/Token'; import { deployToken, expectTokenBalance } from './fixtures/token_utils.js'; -import { expectsNumOfNoteEncryptedLogsInTheLastBlockToBe, setup } from './fixtures/utils.js'; +import { setup } from './fixtures/utils.js'; describe('e2e_multiple_accounts_1_enc_key', () => { - let aztecNode: AztecNode | undefined; let pxe: PXE; const wallets: Wallet[] = []; const accounts: CompleteAddress[] = []; @@ -28,7 +26,7 @@ describe('e2e_multiple_accounts_1_enc_key', () => { const numAccounts = 3; beforeEach(async () => { - ({ teardown, aztecNode, pxe, logger } = await setup(0)); + ({ teardown, pxe, logger } = await setup(0)); const encryptionPrivateKey = Fr.random(); @@ -74,8 +72,6 @@ describe('e2e_multiple_accounts_1_enc_key', () => { await expectTokenBalance(wallets[i], token, wallets[i].getAddress(), expectedBalances[i], logger); } - await expectsNumOfNoteEncryptedLogsInTheLastBlockToBe(aztecNode, 2); - logger.info(`Transfer ${transferAmount} from ${sender} to ${receiver} successful`); }; diff --git a/yarn-project/end-to-end/src/e2e_pending_note_hashes_contract.test.ts b/yarn-project/end-to-end/src/e2e_pending_note_hashes_contract.test.ts index fa9230fa294..a2f6022d7ff 100644 --- a/yarn-project/end-to-end/src/e2e_pending_note_hashes_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_pending_note_hashes_contract.test.ts @@ -7,7 +7,6 @@ import { } from '@aztec/circuits.js'; import { PendingNoteHashesContract } from '@aztec/noir-contracts.js/PendingNoteHashes'; -import { EncryptedNoteTxL2Logs } from '../../circuit-types/src/logs/tx_l2_logs.js'; import { setup } from './fixtures/utils.js'; describe('e2e_pending_note_hashes_contract', () => { @@ -61,14 +60,8 @@ describe('e2e_pending_note_hashes_contract', () => { const blockNum = await aztecNode.getBlockNumber(); const block = (await aztecNode.getBlocks(blockNum, 1))[0]; - const logArray = block.body.txEffects.flatMap(txEffect => txEffect.noteEncryptedLogs); - - for (let l = 0; l < exceptFirstFew + 1; l++) { - expect(logArray[l]).not.toEqual(EncryptedNoteTxL2Logs.empty()); - } - for (let l = exceptFirstFew + 1; l < logArray.length; l++) { - expect(logArray[l]).toEqual(EncryptedNoteTxL2Logs.empty()); - } + const privateLogs = block.body.txEffects.flatMap(txEffect => txEffect.privateLogs); + expect(privateLogs.length).toBe(exceptFirstFew); }; const deployContract = async () => { diff --git a/yarn-project/end-to-end/src/e2e_synching.test.ts b/yarn-project/end-to-end/src/e2e_synching.test.ts index 9f15525f094..99670517bff 100644 --- a/yarn-project/end-to-end/src/e2e_synching.test.ts +++ b/yarn-project/end-to-end/src/e2e_synching.test.ts @@ -46,7 +46,7 @@ import { sleep, } from '@aztec/aztec.js'; // eslint-disable-next-line no-restricted-imports -import { L2Block, LogType, tryStop } from '@aztec/circuit-types'; +import { L2Block, tryStop } from '@aztec/circuit-types'; import { type AztecAddress } from '@aztec/circuits.js'; import { getL1ContractsConfigEnvVars } from '@aztec/ethereum'; import { Timer } from '@aztec/foundation/timer'; @@ -513,9 +513,10 @@ describe('e2e_synching', () => { }); expect(await archiver.getTxEffect(txHash)).not.toBeUndefined; - [LogType.NOTEENCRYPTED, LogType.ENCRYPTED, LogType.UNENCRYPTED].forEach(async t => { - expect(await archiver.getLogs(blockTip.number, 1, t)).not.toEqual([]); - }); + expect(await archiver.getPrivateLogs(blockTip.number, 1)).not.toEqual([]); + expect( + await archiver.getUnencryptedLogs({ fromBlock: blockTip.number, toBlock: blockTip.number + 1 }), + ).not.toEqual([]); await rollup.write.prune(); @@ -537,9 +538,10 @@ describe('e2e_synching', () => { ); expect(await archiver.getTxEffect(txHash)).toBeUndefined; - [LogType.NOTEENCRYPTED, LogType.ENCRYPTED, LogType.UNENCRYPTED].forEach(async t => { - expect(await archiver.getLogs(blockTip.number, 1, t)).toEqual([]); - }); + expect(await archiver.getPrivateLogs(blockTip.number, 1)).toEqual([]); + expect( + await archiver.getUnencryptedLogs({ fromBlock: blockTip.number, toBlock: blockTip.number + 1 }), + ).toEqual([]); // Check world state reverted as well expect(await worldState.getLatestBlockNumber()).toEqual(Number(assumeProvenThrough)); diff --git a/yarn-project/end-to-end/src/fixtures/utils.ts b/yarn-project/end-to-end/src/fixtures/utils.ts index 8fded19aa9a..2ff469f815f 100644 --- a/yarn-project/end-to-end/src/fixtures/utils.ts +++ b/yarn-project/end-to-end/src/fixtures/utils.ts @@ -12,9 +12,7 @@ import { type ContractMethod, type DebugLogger, type DeployL1Contracts, - EncryptedNoteL2BlockL2Logs, EthCheatCodes, - LogType, NoFeePaymentMethod, type PXE, type SentTx, @@ -551,26 +549,6 @@ export function getLogger() { return createDebugLogger('aztec:' + describeBlockName); } -/** - * Checks the number of encrypted logs in the last block is as expected. - * @param aztecNode - The instance of aztec node for retrieving the logs. - * @param numEncryptedLogs - The number of expected logs. - */ -export const expectsNumOfNoteEncryptedLogsInTheLastBlockToBe = async ( - aztecNode: AztecNode | undefined, - numEncryptedLogs: number, -) => { - if (!aztecNode) { - // An api for retrieving encrypted logs does not exist on the PXE Service so we have to use the node - // This means we can't perform this check if there is no node - return; - } - const l2BlockNum = await aztecNode.getBlockNumber(); - const encryptedLogs = await aztecNode.getLogs(l2BlockNum, 1, LogType.NOTEENCRYPTED); - const unrolledLogs = EncryptedNoteL2BlockL2Logs.unrollLogs(encryptedLogs); - expect(unrolledLogs.length).toBe(numEncryptedLogs); -}; - /** * Checks that the last block contains the given expected unencrypted log messages. * @param tx - An instance of SentTx for which to retrieve the logs. diff --git a/yarn-project/noir-protocol-circuits-types/src/scripts/generate_private_kernel_reset_data.ts b/yarn-project/noir-protocol-circuits-types/src/scripts/generate_private_kernel_reset_data.ts index d6d5b118b9c..f415b887b72 100644 --- a/yarn-project/noir-protocol-circuits-types/src/scripts/generate_private_kernel_reset_data.ts +++ b/yarn-project/noir-protocol-circuits-types/src/scripts/generate_private_kernel_reset_data.ts @@ -1,10 +1,10 @@ import { - MAX_ENCRYPTED_LOGS_PER_TX, MAX_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NOTE_HASHES_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIERS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, + MAX_PRIVATE_LOGS_PER_TX, PRIVATE_KERNEL_RESET_INDEX, type PrivateKernelResetDimensionsConfig, VK_TREE_HEIGHT, @@ -28,7 +28,7 @@ const maxDimensions = [ MAX_NULLIFIERS_PER_TX, MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, - MAX_ENCRYPTED_LOGS_PER_TX, + MAX_PRIVATE_LOGS_PER_TX, ]; function generateImports() { diff --git a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts index f21c013e30e..77ec114a2a8 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -21,7 +21,6 @@ import { CountedPublicCallRequest, type EmptyBlockRootRollupInputs, type EmptyNestedData, - EncryptedLogHash, EthAddress, FeeRecipient, Fr, @@ -41,16 +40,15 @@ import { L2ToL1Message, LogHash, MAX_CONTRACT_CLASS_LOGS_PER_TX, - MAX_ENCRYPTED_LOGS_PER_TX, MAX_ENQUEUED_CALLS_PER_TX, MAX_KEY_VALIDATION_REQUESTS_PER_TX, MAX_L2_TO_L1_MSGS_PER_TX, - MAX_NOTE_ENCRYPTED_LOGS_PER_TX, MAX_NOTE_HASHES_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIERS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, + MAX_PRIVATE_LOGS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX, MaxBlockNumber, @@ -62,7 +60,6 @@ import { NUM_BYTES_PER_SHA256, NoteHash, type NoteHashReadRequestHints, - NoteLogHash, Nullifier, type NullifierLeafPreimage, type NullifierReadRequestHints, @@ -87,6 +84,8 @@ import { type PrivateKernelEmptyInputs, type PrivateKernelResetHints, PrivateKernelTailCircuitPublicInputs, + PrivateLog, + PrivateLogData, type PrivateToAvmAccumulatedData, type PrivateToAvmAccumulatedDataArrayLengths, PrivateToPublicAccumulatedData, @@ -111,12 +110,12 @@ import { type RootParityInputs, type RootRollupInputs, RootRollupPublicInputs, - ScopedEncryptedLogHash, ScopedKeyValidationRequestAndGenerator, ScopedL2ToL1Message, ScopedLogHash, ScopedNoteHash, ScopedNullifier, + ScopedPrivateLogData, ScopedReadRequest, type SettledReadHint, StateReference, @@ -150,7 +149,6 @@ import type { Counted as CountedPublicCallRequestNoir, EmptyBlockRootRollupInputs as EmptyBlockRootRollupInputsNoir, EmptyNestedCircuitPublicInputs as EmptyNestedDataNoir, - EncryptedLogHash as EncryptedLogHashNoir, FeeRecipient as FeeRecipientNoir, Field, FixedLengthArray, @@ -179,7 +177,6 @@ import type { NoteHash as NoteHashNoir, NoteHashReadRequestHints as NoteHashReadRequestHintsNoir, NoteHashSettledReadHint as NoteHashSettledReadHintNoir, - NoteLogHash as NoteLogHashNoir, NullifierLeafPreimage as NullifierLeafPreimageNoir, Nullifier as NullifierNoir, NullifierReadRequestHints as NullifierReadRequestHintsNoir, @@ -201,6 +198,8 @@ import type { PrivateKernelDataWithoutPublicInputs as PrivateKernelDataWithoutPublicInputsNoir, PrivateKernelEmptyPrivateInputs as PrivateKernelEmptyPrivateInputsNoir, PrivateKernelResetHints as PrivateKernelResetHintsNoir, + PrivateLogData as PrivateLogDataNoir, + Log as PrivateLogNoir, PrivateToAvmAccumulatedDataArrayLengths as PrivateToAvmAccumulatedDataArrayLengthsNoir, PrivateToAvmAccumulatedData as PrivateToAvmAccumulatedDataNoir, PrivateToPublicAccumulatedData as PrivateToPublicAccumulatedDataNoir, @@ -222,12 +221,12 @@ import type { RootRollupInputs as RootRollupInputsNoir, RootRollupParityInput as RootRollupParityInputNoir, RootRollupPublicInputs as RootRollupPublicInputsNoir, - ScopedEncryptedLogHash as ScopedEncryptedLogHashNoir, ScopedKeyValidationRequestAndGenerator as ScopedKeyValidationRequestAndGeneratorNoir, ScopedL2ToL1Message as ScopedL2ToL1MessageNoir, ScopedLogHash as ScopedLogHashNoir, ScopedNoteHash as ScopedNoteHashNoir, ScopedNullifier as ScopedNullifierNoir, + Scoped as ScopedPrivateLogDataNoir, ScopedReadRequest as ScopedReadRequestNoir, StateReference as StateReferenceNoir, TransientDataIndexHint as TransientDataIndexHintNoir, @@ -608,29 +607,43 @@ function mapScopedNullifierFromNoir(nullifier: ScopedNullifierNoir) { ); } -/** - * Maps a LogHash to a noir LogHash. - * @param logHash - The LogHash. - * @returns The noir log hash. - */ -export function mapLogHashToNoir(logHash: LogHash): LogHashNoir { +function mapPrivateLogToNoir(log: PrivateLog): PrivateLogNoir { return { - value: mapFieldToNoir(logHash.value), - counter: mapNumberToNoir(logHash.counter), - length: mapFieldToNoir(logHash.length), + fields: mapTuple(log.fields, mapFieldToNoir), }; } -/** - * Maps a noir LogHash to a LogHash. - * @param logHash - The noir LogHash. - * @returns The TS log hash. - */ -export function mapLogHashFromNoir(logHash: LogHashNoir): LogHash { - return new LogHash( - mapFieldFromNoir(logHash.value), - mapNumberFromNoir(logHash.counter), - mapFieldFromNoir(logHash.length), +function mapPrivateLogFromNoir(log: PrivateLogNoir) { + return new PrivateLog(mapTupleFromNoir(log.fields, log.fields.length, mapFieldFromNoir)); +} + +function mapPrivateLogDataToNoir(data: PrivateLogData): PrivateLogDataNoir { + return { + log: mapPrivateLogToNoir(data.log), + note_hash_counter: mapNumberToNoir(data.noteHashCounter), + counter: mapNumberToNoir(data.counter), + }; +} + +function mapPrivateLogDataFromNoir(data: PrivateLogDataNoir) { + return new PrivateLogData( + mapPrivateLogFromNoir(data.log), + mapNumberFromNoir(data.note_hash_counter), + mapNumberFromNoir(data.counter), + ); +} + +function mapScopedPrivateLogDataToNoir(data: ScopedPrivateLogData): ScopedPrivateLogDataNoir { + return { + inner: mapPrivateLogDataToNoir(data.inner), + contract_address: mapAztecAddressToNoir(data.contractAddress), + }; +} + +function mapScopedPrivateLogDataFromNoir(data: ScopedPrivateLogDataNoir) { + return new ScopedPrivateLogData( + mapPrivateLogDataFromNoir(data.inner), + mapAztecAddressFromNoir(data.contract_address), ); } @@ -639,12 +652,11 @@ export function mapLogHashFromNoir(logHash: LogHashNoir): LogHash { * @param logHash - The LogHash. * @returns The noir log hash. */ -export function mapEncryptedLogHashToNoir(logHash: EncryptedLogHash): EncryptedLogHashNoir { +function mapLogHashToNoir(logHash: LogHash): LogHashNoir { return { value: mapFieldToNoir(logHash.value), counter: mapNumberToNoir(logHash.counter), length: mapFieldToNoir(logHash.length), - randomness: mapFieldToNoir(logHash.randomness), }; } @@ -653,12 +665,11 @@ export function mapEncryptedLogHashToNoir(logHash: EncryptedLogHash): EncryptedL * @param logHash - The noir LogHash. * @returns The TS log hash. */ -export function mapEncryptedLogHashFromNoir(logHash: EncryptedLogHashNoir): EncryptedLogHash { - return new EncryptedLogHash( +function mapLogHashFromNoir(logHash: LogHashNoir): LogHash { + return new LogHash( mapFieldFromNoir(logHash.value), mapNumberFromNoir(logHash.counter), mapFieldFromNoir(logHash.length), - mapFieldFromNoir(logHash.randomness), ); } @@ -667,31 +678,7 @@ export function mapEncryptedLogHashFromNoir(logHash: EncryptedLogHashNoir): Encr * @param logHash - The ts LogHash. * @returns The noir log hash. */ -export function mapScopedEncryptedLogHashToNoir(scopedLogHash: ScopedEncryptedLogHash): ScopedEncryptedLogHashNoir { - return { - log_hash: mapEncryptedLogHashToNoir(scopedLogHash.logHash), - contract_address: mapAztecAddressToNoir(scopedLogHash.contractAddress), - }; -} - -/** - * Maps a noir ScopedLogHash to a ts ScopedLogHash. - * @param logHash - The noir LogHash. - * @returns The TS log hash. - */ -export function mapScopedEncryptedLogHashFromNoir(scopedLogHash: ScopedEncryptedLogHashNoir): ScopedEncryptedLogHash { - return new ScopedEncryptedLogHash( - mapEncryptedLogHashFromNoir(scopedLogHash.log_hash), - mapAztecAddressFromNoir(scopedLogHash.contract_address), - ); -} - -/** - * Maps a ts ScopedLogHash to a noir ScopedLogHash. - * @param logHash - The ts LogHash. - * @returns The noir log hash. - */ -export function mapScopedLogHashToNoir(scopedLogHash: ScopedLogHash): ScopedLogHashNoir { +function mapScopedLogHashToNoir(scopedLogHash: ScopedLogHash): ScopedLogHashNoir { return { log_hash: mapLogHashToNoir(scopedLogHash.logHash), contract_address: mapAztecAddressToNoir(scopedLogHash.contractAddress), @@ -703,47 +690,19 @@ export function mapScopedLogHashToNoir(scopedLogHash: ScopedLogHash): ScopedLogH * @param logHash - The noir LogHash. * @returns The TS log hash. */ -export function mapScopedLogHashFromNoir(scopedLogHash: ScopedLogHashNoir): ScopedLogHash { +function mapScopedLogHashFromNoir(scopedLogHash: ScopedLogHashNoir): ScopedLogHash { return new ScopedLogHash( mapLogHashFromNoir(scopedLogHash.log_hash), mapAztecAddressFromNoir(scopedLogHash.contract_address), ); } -/** - * Maps a LogHash to a noir LogHash. - * @param noteLogHash - The NoteLogHash. - * @returns The noir note log hash. - */ -export function mapNoteLogHashToNoir(noteLogHash: NoteLogHash): NoteLogHashNoir { - return { - value: mapFieldToNoir(noteLogHash.value), - counter: mapNumberToNoir(noteLogHash.counter), - length: mapFieldToNoir(noteLogHash.length), - note_hash_counter: mapNumberToNoir(noteLogHash.noteHashCounter), - }; -} - -/** - * Maps a noir LogHash to a LogHash. - * @param noteLogHash - The noir NoteLogHash. - * @returns The TS note log hash. - */ -export function mapNoteLogHashFromNoir(noteLogHash: NoteLogHashNoir): NoteLogHash { - return new NoteLogHash( - mapFieldFromNoir(noteLogHash.value), - mapNumberFromNoir(noteLogHash.counter), - mapFieldFromNoir(noteLogHash.length), - mapNumberFromNoir(noteLogHash.note_hash_counter), - ); -} - /** * Maps a ReadRequest to a noir ReadRequest. * @param readRequest - The read request. * @returns The noir ReadRequest. */ -export function mapReadRequestToNoir(readRequest: ReadRequest): ReadRequestNoir { +function mapReadRequestToNoir(readRequest: ReadRequest): ReadRequestNoir { return { value: mapFieldToNoir(readRequest.value), counter: mapNumberToNoir(readRequest.counter), @@ -755,7 +714,7 @@ export function mapReadRequestToNoir(readRequest: ReadRequest): ReadRequestNoir * @param readRequest - The noir ReadRequest. * @returns The TS ReadRequest. */ -export function mapReadRequestFromNoir(readRequest: ReadRequestNoir): ReadRequest { +function mapReadRequestFromNoir(readRequest: ReadRequestNoir): ReadRequest { return new ReadRequest(mapFieldFromNoir(readRequest.value), mapNumberFromNoir(readRequest.counter)); } @@ -895,11 +854,10 @@ export function mapPrivateCircuitPublicInputsToNoir( public_call_requests: mapTuple(privateCircuitPublicInputs.publicCallRequests, mapCountedPublicCallRequestToNoir), public_teardown_call_request: mapPublicCallRequestToNoir(privateCircuitPublicInputs.publicTeardownCallRequest), l2_to_l1_msgs: mapTuple(privateCircuitPublicInputs.l2ToL1Msgs, mapL2ToL1MessageToNoir), + private_logs: mapTuple(privateCircuitPublicInputs.privateLogs, mapPrivateLogDataToNoir), + contract_class_logs_hashes: mapTuple(privateCircuitPublicInputs.contractClassLogsHashes, mapLogHashToNoir), start_side_effect_counter: mapFieldToNoir(privateCircuitPublicInputs.startSideEffectCounter), end_side_effect_counter: mapFieldToNoir(privateCircuitPublicInputs.endSideEffectCounter), - note_encrypted_logs_hashes: mapTuple(privateCircuitPublicInputs.noteEncryptedLogsHashes, mapNoteLogHashToNoir), - encrypted_logs_hashes: mapTuple(privateCircuitPublicInputs.encryptedLogsHashes, mapEncryptedLogHashToNoir), - contract_class_logs_hashes: mapTuple(privateCircuitPublicInputs.contractClassLogsHashes, mapLogHashToNoir), historical_header: mapHeaderToNoir(privateCircuitPublicInputs.historicalHeader), tx_context: mapTxContextToNoir(privateCircuitPublicInputs.txContext), min_revertible_side_effect_counter: mapFieldToNoir(privateCircuitPublicInputs.minRevertibleSideEffectCounter), @@ -1126,16 +1084,7 @@ export function mapPrivateAccumulatedDataFromNoir( mapTupleFromNoir(privateAccumulatedData.note_hashes, MAX_NOTE_HASHES_PER_TX, mapScopedNoteHashFromNoir), mapTupleFromNoir(privateAccumulatedData.nullifiers, MAX_NULLIFIERS_PER_TX, mapScopedNullifierFromNoir), mapTupleFromNoir(privateAccumulatedData.l2_to_l1_msgs, MAX_L2_TO_L1_MSGS_PER_TX, mapScopedL2ToL1MessageFromNoir), - mapTupleFromNoir( - privateAccumulatedData.note_encrypted_logs_hashes, - MAX_NOTE_ENCRYPTED_LOGS_PER_TX, - mapNoteLogHashFromNoir, - ), - mapTupleFromNoir( - privateAccumulatedData.encrypted_logs_hashes, - MAX_ENCRYPTED_LOGS_PER_TX, - mapScopedEncryptedLogHashFromNoir, - ), + mapTupleFromNoir(privateAccumulatedData.private_logs, MAX_PRIVATE_LOGS_PER_TX, mapScopedPrivateLogDataFromNoir), mapTupleFromNoir( privateAccumulatedData.contract_class_logs_hashes, MAX_CONTRACT_CLASS_LOGS_PER_TX, @@ -1159,8 +1108,7 @@ export function mapPrivateAccumulatedDataToNoir(data: PrivateAccumulatedData): P note_hashes: mapTuple(data.noteHashes, mapScopedNoteHashToNoir), nullifiers: mapTuple(data.nullifiers, mapScopedNullifierToNoir), l2_to_l1_msgs: mapTuple(data.l2ToL1Msgs, mapScopedL2ToL1MessageToNoir), - note_encrypted_logs_hashes: mapTuple(data.noteEncryptedLogsHashes, mapNoteLogHashToNoir), - encrypted_logs_hashes: mapTuple(data.encryptedLogsHashes, mapScopedEncryptedLogHashToNoir), + private_logs: mapTuple(data.privateLogs, mapScopedPrivateLogDataToNoir), contract_class_logs_hashes: mapTuple(data.contractClassLogsHashes, mapScopedLogHashToNoir), public_call_requests: mapTuple(data.publicCallRequests, mapCountedPublicCallRequestToNoir), private_call_stack: mapTuple(data.privateCallStack, mapPrivateCallRequestToNoir), @@ -1213,8 +1161,7 @@ function mapPrivateToPublicAccumulatedDataFromNoir(data: PrivateToPublicAccumula mapTupleFromNoir(data.note_hashes, MAX_NOTE_HASHES_PER_TX, mapFieldFromNoir), mapTupleFromNoir(data.nullifiers, MAX_NULLIFIERS_PER_TX, mapFieldFromNoir), mapTupleFromNoir(data.l2_to_l1_msgs, MAX_L2_TO_L1_MSGS_PER_TX, mapScopedL2ToL1MessageFromNoir), - mapTupleFromNoir(data.note_encrypted_logs_hashes, MAX_NOTE_ENCRYPTED_LOGS_PER_TX, mapLogHashFromNoir), - mapTupleFromNoir(data.encrypted_logs_hashes, MAX_ENCRYPTED_LOGS_PER_TX, mapScopedLogHashFromNoir), + mapTupleFromNoir(data.private_logs, MAX_PRIVATE_LOGS_PER_TX, mapPrivateLogFromNoir), mapTupleFromNoir(data.contract_class_logs_hashes, MAX_CONTRACT_CLASS_LOGS_PER_TX, mapScopedLogHashFromNoir), mapTupleFromNoir(data.public_call_requests, MAX_ENQUEUED_CALLS_PER_TX, mapPublicCallRequestFromNoir), ); @@ -1227,8 +1174,7 @@ function mapPrivateToPublicAccumulatedDataToNoir( note_hashes: mapTuple(data.noteHashes, mapFieldToNoir), nullifiers: mapTuple(data.nullifiers, mapFieldToNoir), l2_to_l1_msgs: mapTuple(data.l2ToL1Msgs, mapScopedL2ToL1MessageToNoir), - note_encrypted_logs_hashes: mapTuple(data.noteEncryptedLogsHashes, mapLogHashToNoir), - encrypted_logs_hashes: mapTuple(data.encryptedLogsHashes, mapScopedLogHashToNoir), + private_logs: mapTuple(data.privateLogs, mapPrivateLogToNoir), contract_class_logs_hashes: mapTuple(data.contractClassLogsHashes, mapScopedLogHashToNoir), public_call_requests: mapTuple(data.publicCallRequests, mapPublicCallRequestToNoir), }; @@ -1267,23 +1213,12 @@ function mapAvmAccumulatedDataToNoir(data: AvmAccumulatedData): AvmAccumulatedDa * @param combinedAccumulatedData - The noir combined accumulated data. * @returns The parsed combined accumulated data. */ -export function mapCombinedAccumulatedDataFromNoir( - combinedAccumulatedData: CombinedAccumulatedDataNoir, -): CombinedAccumulatedData { +export function mapCombinedAccumulatedDataFromNoir(combinedAccumulatedData: CombinedAccumulatedDataNoir) { return new CombinedAccumulatedData( mapTupleFromNoir(combinedAccumulatedData.note_hashes, MAX_NOTE_HASHES_PER_TX, mapFieldFromNoir), mapTupleFromNoir(combinedAccumulatedData.nullifiers, MAX_NULLIFIERS_PER_TX, mapFieldFromNoir), mapTupleFromNoir(combinedAccumulatedData.l2_to_l1_msgs, MAX_L2_TO_L1_MSGS_PER_TX, mapScopedL2ToL1MessageFromNoir), - mapTupleFromNoir( - combinedAccumulatedData.note_encrypted_logs_hashes, - MAX_NOTE_ENCRYPTED_LOGS_PER_TX, - mapLogHashFromNoir, - ), - mapTupleFromNoir( - combinedAccumulatedData.encrypted_logs_hashes, - MAX_ENCRYPTED_LOGS_PER_TX, - mapScopedLogHashFromNoir, - ), + mapTupleFromNoir(combinedAccumulatedData.private_logs, MAX_PRIVATE_LOGS_PER_TX, mapPrivateLogFromNoir), mapTupleFromNoir( combinedAccumulatedData.unencrypted_logs_hashes, MAX_UNENCRYPTED_LOGS_PER_TX, @@ -1294,8 +1229,6 @@ export function mapCombinedAccumulatedDataFromNoir( MAX_CONTRACT_CLASS_LOGS_PER_TX, mapScopedLogHashFromNoir, ), - mapFieldFromNoir(combinedAccumulatedData.note_encrypted_log_preimages_length), - mapFieldFromNoir(combinedAccumulatedData.encrypted_log_preimages_length), mapFieldFromNoir(combinedAccumulatedData.unencrypted_log_preimages_length), mapFieldFromNoir(combinedAccumulatedData.contract_class_log_preimages_length), mapTupleFromNoir( @@ -1313,12 +1246,9 @@ export function mapCombinedAccumulatedDataToNoir( note_hashes: mapTuple(combinedAccumulatedData.noteHashes, mapFieldToNoir), nullifiers: mapTuple(combinedAccumulatedData.nullifiers, mapFieldToNoir), l2_to_l1_msgs: mapTuple(combinedAccumulatedData.l2ToL1Msgs, mapScopedL2ToL1MessageToNoir), - note_encrypted_logs_hashes: mapTuple(combinedAccumulatedData.noteEncryptedLogsHashes, mapLogHashToNoir), - encrypted_logs_hashes: mapTuple(combinedAccumulatedData.encryptedLogsHashes, mapScopedLogHashToNoir), + private_logs: mapTuple(combinedAccumulatedData.privateLogs, mapPrivateLogToNoir), unencrypted_logs_hashes: mapTuple(combinedAccumulatedData.unencryptedLogsHashes, mapScopedLogHashToNoir), contract_class_logs_hashes: mapTuple(combinedAccumulatedData.contractClassLogsHashes, mapScopedLogHashToNoir), - note_encrypted_log_preimages_length: mapFieldToNoir(combinedAccumulatedData.noteEncryptedLogPreimagesLength), - encrypted_log_preimages_length: mapFieldToNoir(combinedAccumulatedData.encryptedLogPreimagesLength), unencrypted_log_preimages_length: mapFieldToNoir(combinedAccumulatedData.unencryptedLogPreimagesLength), contract_class_log_preimages_length: mapFieldToNoir(combinedAccumulatedData.contractClassLogPreimagesLength), public_data_writes: mapTuple(combinedAccumulatedData.publicDataWrites, mapPublicDataWriteToNoir), diff --git a/yarn-project/circuits.js/fixtures/ContractClassRegisteredEventData.hex b/yarn-project/protocol-contracts/fixtures/ContractClassRegisteredEventData.hex similarity index 100% rename from yarn-project/circuits.js/fixtures/ContractClassRegisteredEventData.hex rename to yarn-project/protocol-contracts/fixtures/ContractClassRegisteredEventData.hex diff --git a/yarn-project/protocol-contracts/fixtures/ContractInstanceDeployedEventData.hex b/yarn-project/protocol-contracts/fixtures/ContractInstanceDeployedEventData.hex new file mode 100644 index 00000000000..38c65f2ae31 --- /dev/null +++ b/yarn-project/protocol-contracts/fixtures/ContractInstanceDeployedEventData.hex @@ -0,0 +1 @@ +2ec28b91a5f838506d6042915005ff55cf7a0a5f889a83b11faed33a31b486f20c5c6978e380c4e3940ab74770639260bcc75c93c3d0ae48ee4a241d555b094e000000000000000000000000000000000000000000000000000000000000000106f485aceb5c16470a993faa3fa40bb4d231b419d5930005d11b01e2b958561e2b78af6d543573f77372e53e66932714d68877b4bcbb18671e68a846795297e1261a942678edb850a955359c8dccb79ae8ab4bb54218212916a4df41cf99f54516c1fe3833b58824049ac650af267463c5143af92773cc9c1896bb021eceabd4215719102869d6ebf6639babeee6ead59c5d407e3940d0d6ac847fe7d446af95009815eee682568d5688081d08852c8c42b117b8ed50300f97784212dda2626a071726daedce34a9420c01d2c34d0214f444970d60e0c77c181f74176e1d3c5926ae3f275a1e7c07f857f3905a9fa07d028d1e5c7fb450b15d8dce81d16009740bb00659afc7e91dcf94a15fc739740b4d13a1dd9c440288a945eba8ca074e9a21c507a634f4c28b8f690cd6bcb7b2540ed28ee21cc2ee67049d9e3ed9e3108a024c78ef4a6cdc11fbd7cfb67da0c31f127cb476d6a974fc0cb76ef2f011edf80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file diff --git a/yarn-project/circuits.js/fixtures/PrivateFunctionBroadcastedEventData.hex b/yarn-project/protocol-contracts/fixtures/PrivateFunctionBroadcastedEventData.hex similarity index 100% rename from yarn-project/circuits.js/fixtures/PrivateFunctionBroadcastedEventData.hex rename to yarn-project/protocol-contracts/fixtures/PrivateFunctionBroadcastedEventData.hex diff --git a/yarn-project/circuits.js/fixtures/UnconstrainedFunctionBroadcastedEventData.hex b/yarn-project/protocol-contracts/fixtures/UnconstrainedFunctionBroadcastedEventData.hex similarity index 100% rename from yarn-project/circuits.js/fixtures/UnconstrainedFunctionBroadcastedEventData.hex rename to yarn-project/protocol-contracts/fixtures/UnconstrainedFunctionBroadcastedEventData.hex diff --git a/yarn-project/protocol-contracts/package.json b/yarn-project/protocol-contracts/package.json index be631e73100..0f7dbfa66e2 100644 --- a/yarn-project/protocol-contracts/package.json +++ b/yarn-project/protocol-contracts/package.json @@ -70,12 +70,14 @@ "@aztec/circuits.js": "workspace:^", "@aztec/foundation": "workspace:^", "@aztec/types": "workspace:^", + "lodash.chunk": "^4.2.0", "lodash.omit": "^4.5.0", "tslib": "^2.4.0" }, "devDependencies": { "@jest/globals": "^29.5.0", "@types/jest": "^29.5.0", + "@types/lodash.chunk": "^4.2.9", "@types/lodash.omit": "^4.5.9", "@types/node": "^18.7.23", "jest": "^29.5.0", diff --git a/yarn-project/circuits.js/src/contract/events/__snapshots__/private_function_broadcasted_event.test.ts.snap b/yarn-project/protocol-contracts/src/class-registerer/__snapshots__/private_function_broadcasted_event.test.ts.snap similarity index 100% rename from yarn-project/circuits.js/src/contract/events/__snapshots__/private_function_broadcasted_event.test.ts.snap rename to yarn-project/protocol-contracts/src/class-registerer/__snapshots__/private_function_broadcasted_event.test.ts.snap diff --git a/yarn-project/circuits.js/src/contract/events/__snapshots__/unconstrained_function_broadcasted_event.test.ts.snap b/yarn-project/protocol-contracts/src/class-registerer/__snapshots__/unconstrained_function_broadcasted_event.test.ts.snap similarity index 100% rename from yarn-project/circuits.js/src/contract/events/__snapshots__/unconstrained_function_broadcasted_event.test.ts.snap rename to yarn-project/protocol-contracts/src/class-registerer/__snapshots__/unconstrained_function_broadcasted_event.test.ts.snap diff --git a/yarn-project/circuits.js/src/contract/events/contract_class_registered_event.test.ts b/yarn-project/protocol-contracts/src/class-registerer/contract_class_registered_event.test.ts similarity index 71% rename from yarn-project/circuits.js/src/contract/events/contract_class_registered_event.test.ts rename to yarn-project/protocol-contracts/src/class-registerer/contract_class_registered_event.test.ts index 77d9e760fae..9a4bf4b0a1f 100644 --- a/yarn-project/circuits.js/src/contract/events/contract_class_registered_event.test.ts +++ b/yarn-project/protocol-contracts/src/class-registerer/contract_class_registered_event.test.ts @@ -1,11 +1,14 @@ -import { getSampleContractClassRegisteredEventPayload } from '../../tests/fixtures.js'; -import { computePublicBytecodeCommitment } from '../contract_class_id.js'; +import { computePublicBytecodeCommitment } from '@aztec/circuits.js'; + +import { getSampleContractClassRegisteredEventPayload } from '../tests/fixtures.js'; import { ContractClassRegisteredEvent } from './contract_class_registered_event.js'; describe('ContractClassRegisteredEvent', () => { it('parses an event as emitted by the ContractClassRegisterer', () => { - const data = getSampleContractClassRegisteredEventPayload(); - const event = ContractClassRegisteredEvent.fromLogData(data); + const log = getSampleContractClassRegisteredEventPayload(); + expect(ContractClassRegisteredEvent.isContractClassRegisteredEvent(log)).toBe(true); + + const event = ContractClassRegisteredEvent.fromLog(log); expect(event.contractClassId.toString()).toEqual( '0x1c9a43d08a1af21c35e4201262a49497a488b0686209370a70f2434af643b4f7', ); diff --git a/yarn-project/circuits.js/src/contract/events/contract_class_registered_event.ts b/yarn-project/protocol-contracts/src/class-registerer/contract_class_registered_event.ts similarity index 68% rename from yarn-project/circuits.js/src/contract/events/contract_class_registered_event.ts rename to yarn-project/protocol-contracts/src/class-registerer/contract_class_registered_event.ts index bc88b985759..b8c935dd948 100644 --- a/yarn-project/circuits.js/src/contract/events/contract_class_registered_event.ts +++ b/yarn-project/protocol-contracts/src/class-registerer/contract_class_registered_event.ts @@ -1,14 +1,17 @@ +import { + type ContractClassPublic, + PUBLIC_DISPATCH_SELECTOR, + type PublicFunction, + computeContractClassId, + computePublicBytecodeCommitment, +} from '@aztec/circuits.js'; import { FunctionSelector, bufferFromFields } from '@aztec/foundation/abi'; -import { type AztecAddress } from '@aztec/foundation/aztec-address'; -import { toBigIntBE } from '@aztec/foundation/bigint-buffer'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader } from '@aztec/foundation/serialize'; import chunk from 'lodash.chunk'; -import { PUBLIC_DISPATCH_SELECTOR, REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE } from '../../constants.gen.js'; -import { computeContractClassId, computePublicBytecodeCommitment } from '../contract_class_id.js'; -import { type ContractClassPublic, type PublicFunction } from '../interfaces/index.js'; +import { REGISTERER_CONTRACT_CLASS_REGISTERED_TAG } from '../protocol_contract_data.js'; /** Event emitted from the ContractClassRegisterer. */ export class ContractClassRegisteredEvent { @@ -21,22 +24,10 @@ export class ContractClassRegisteredEvent { ) {} static isContractClassRegisteredEvent(log: Buffer) { - return toBigIntBE(log.subarray(0, 32)) == REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE; + return log.subarray(0, 32).equals(REGISTERER_CONTRACT_CLASS_REGISTERED_TAG.toBuffer()); } - static fromLogs(logs: { contractAddress: AztecAddress; data: Buffer }[], registererContractAddress: AztecAddress) { - return logs - .filter(log => ContractClassRegisteredEvent.isContractClassRegisteredEvent(log.data)) - .filter(log => log.contractAddress.equals(registererContractAddress)) - .map(log => this.fromLogData(log.data)); - } - - static fromLogData(log: Buffer) { - if (!this.isContractClassRegisteredEvent(log)) { - throw new Error( - `Log data for ContractClassRegisteredEvent is not prefixed with magic value 0x${REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE}`, - ); - } + static fromLog(log: Buffer) { const reader = new BufferReader(log.subarray(32)); const contractClassId = reader.readObject(Fr); const version = reader.readObject(Fr).toNumber(); diff --git a/yarn-project/protocol-contracts/src/class-registerer/index.ts b/yarn-project/protocol-contracts/src/class-registerer/index.ts index 046e9951baa..b30844b28fa 100644 --- a/yarn-project/protocol-contracts/src/class-registerer/index.ts +++ b/yarn-project/protocol-contracts/src/class-registerer/index.ts @@ -1,5 +1,9 @@ import { type ProtocolContract, getCanonicalProtocolContract } from '../protocol_contract.js'; +export * from './contract_class_registered_event.js'; +export * from './private_function_broadcasted_event.js'; +export * from './unconstrained_function_broadcasted_event.js'; + /** Returns the canonical deployment of the class registerer contract. */ export function getCanonicalClassRegisterer(): ProtocolContract { return getCanonicalProtocolContract('ContractClassRegisterer'); diff --git a/yarn-project/circuits.js/src/contract/events/private_function_broadcasted_event.test.ts b/yarn-project/protocol-contracts/src/class-registerer/private_function_broadcasted_event.test.ts similarity index 64% rename from yarn-project/circuits.js/src/contract/events/private_function_broadcasted_event.test.ts rename to yarn-project/protocol-contracts/src/class-registerer/private_function_broadcasted_event.test.ts index 4b8c246db46..9dd2cdd9a8f 100644 --- a/yarn-project/circuits.js/src/contract/events/private_function_broadcasted_event.test.ts +++ b/yarn-project/protocol-contracts/src/class-registerer/private_function_broadcasted_event.test.ts @@ -1,13 +1,16 @@ import { setupCustomSnapshotSerializers } from '@aztec/foundation/testing'; -import { getSamplePrivateFunctionBroadcastedEventPayload } from '../../tests/fixtures.js'; +import { getSamplePrivateFunctionBroadcastedEventPayload } from '../tests/fixtures.js'; import { PrivateFunctionBroadcastedEvent } from './private_function_broadcasted_event.js'; describe('PrivateFunctionBroadcastedEvent', () => { beforeAll(() => setupCustomSnapshotSerializers(expect)); + it('parses an event as emitted by the ContractClassRegisterer', () => { - const data = getSamplePrivateFunctionBroadcastedEventPayload(); - const event = PrivateFunctionBroadcastedEvent.fromLogData(data); + const log = getSamplePrivateFunctionBroadcastedEventPayload(); + expect(PrivateFunctionBroadcastedEvent.isPrivateFunctionBroadcastedEvent(log)).toBe(true); + + const event = PrivateFunctionBroadcastedEvent.fromLog(log); expect(event).toMatchSnapshot(); }); }); diff --git a/yarn-project/circuits.js/src/contract/events/private_function_broadcasted_event.ts b/yarn-project/protocol-contracts/src/class-registerer/private_function_broadcasted_event.ts similarity index 80% rename from yarn-project/circuits.js/src/contract/events/private_function_broadcasted_event.ts rename to yarn-project/protocol-contracts/src/class-registerer/private_function_broadcasted_event.ts index 595a3b6dd9c..8a30be9c346 100644 --- a/yarn-project/circuits.js/src/contract/events/private_function_broadcasted_event.ts +++ b/yarn-project/protocol-contracts/src/class-registerer/private_function_broadcasted_event.ts @@ -1,20 +1,18 @@ +import { + ARTIFACT_FUNCTION_TREE_MAX_HEIGHT, + type ExecutablePrivateFunctionWithMembershipProof, + FUNCTION_TREE_HEIGHT, + MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS, + type PrivateFunction, + REGISTERER_PRIVATE_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS, +} from '@aztec/circuits.js'; import { FunctionSelector, bufferFromFields } from '@aztec/foundation/abi'; -import { type AztecAddress } from '@aztec/foundation/aztec-address'; -import { toBigIntBE } from '@aztec/foundation/bigint-buffer'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, type Tuple } from '@aztec/foundation/serialize'; import chunk from 'lodash.chunk'; -import { - ARTIFACT_FUNCTION_TREE_MAX_HEIGHT, - FUNCTION_TREE_HEIGHT, - MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS, - REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE, - REGISTERER_PRIVATE_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS, - REGISTERER_PRIVATE_FUNCTION_BROADCASTED_MAGIC_VALUE, -} from '../../constants.gen.js'; -import { type ExecutablePrivateFunctionWithMembershipProof, type PrivateFunction } from '../interfaces/index.js'; +import { REGISTERER_PRIVATE_FUNCTION_BROADCASTED_TAG } from '../protocol_contract_data.js'; /** Event emitted from the ContractClassRegisterer. */ export class PrivateFunctionBroadcastedEvent { @@ -30,23 +28,10 @@ export class PrivateFunctionBroadcastedEvent { ) {} static isPrivateFunctionBroadcastedEvent(log: Buffer) { - return toBigIntBE(log.subarray(0, 32)) == REGISTERER_PRIVATE_FUNCTION_BROADCASTED_MAGIC_VALUE; - } - - static fromLogs(logs: { contractAddress: AztecAddress; data: Buffer }[], registererContractAddress: AztecAddress) { - return logs - .filter(log => PrivateFunctionBroadcastedEvent.isPrivateFunctionBroadcastedEvent(log.data)) - .filter(log => log.contractAddress.equals(registererContractAddress)) - .map(log => this.fromLogData(log.data)); + return log.subarray(0, 32).equals(REGISTERER_PRIVATE_FUNCTION_BROADCASTED_TAG.toBuffer()); } - static fromLogData(log: Buffer) { - if (!this.isPrivateFunctionBroadcastedEvent(log)) { - throw new Error( - `Log data for PrivateFunctionBroadcastedEvent is not prefixed with magic value 0x${REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE}`, - ); - } - + static fromLog(log: Buffer) { const expectedLength = 32 * (MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS + diff --git a/yarn-project/circuits.js/src/contract/events/unconstrained_function_broadcasted_event.test.ts b/yarn-project/protocol-contracts/src/class-registerer/unconstrained_function_broadcasted_event.test.ts similarity index 82% rename from yarn-project/circuits.js/src/contract/events/unconstrained_function_broadcasted_event.test.ts rename to yarn-project/protocol-contracts/src/class-registerer/unconstrained_function_broadcasted_event.test.ts index 33cd679e0c5..db3ae210eab 100644 --- a/yarn-project/circuits.js/src/contract/events/unconstrained_function_broadcasted_event.test.ts +++ b/yarn-project/protocol-contracts/src/class-registerer/unconstrained_function_broadcasted_event.test.ts @@ -4,7 +4,7 @@ import { Fr } from '@aztec/foundation/fields'; import { type Tuple } from '@aztec/foundation/serialize'; import { setupCustomSnapshotSerializers } from '@aztec/foundation/testing'; -import { getSampleUnconstrainedFunctionBroadcastedEventPayload } from '../../tests/fixtures.js'; +import { getSampleUnconstrainedFunctionBroadcastedEventPayload } from '../tests/fixtures.js'; import { BroadcastedUnconstrainedFunction, UnconstrainedFunctionBroadcastedEvent, @@ -12,9 +12,12 @@ import { describe('UnconstrainedFunctionBroadcastedEvent', () => { beforeAll(() => setupCustomSnapshotSerializers(expect)); + it('parses an event as emitted by the ContractClassRegisterer', () => { - const data = getSampleUnconstrainedFunctionBroadcastedEventPayload(); - const event = UnconstrainedFunctionBroadcastedEvent.fromLogData(data); + const log = getSampleUnconstrainedFunctionBroadcastedEventPayload(); + expect(UnconstrainedFunctionBroadcastedEvent.isUnconstrainedFunctionBroadcastedEvent(log)).toBe(true); + + const event = UnconstrainedFunctionBroadcastedEvent.fromLog(log); expect(event).toMatchSnapshot(); }); diff --git a/yarn-project/circuits.js/src/contract/events/unconstrained_function_broadcasted_event.ts b/yarn-project/protocol-contracts/src/class-registerer/unconstrained_function_broadcasted_event.ts similarity index 79% rename from yarn-project/circuits.js/src/contract/events/unconstrained_function_broadcasted_event.ts rename to yarn-project/protocol-contracts/src/class-registerer/unconstrained_function_broadcasted_event.ts index 4948319bebf..0bc22385f07 100644 --- a/yarn-project/circuits.js/src/contract/events/unconstrained_function_broadcasted_event.ts +++ b/yarn-project/protocol-contracts/src/class-registerer/unconstrained_function_broadcasted_event.ts @@ -1,20 +1,18 @@ +import { + ARTIFACT_FUNCTION_TREE_MAX_HEIGHT, + MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS, + REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS, + type UnconstrainedFunction, + type UnconstrainedFunctionWithMembershipProof, +} from '@aztec/circuits.js'; import { FunctionSelector, bufferFromFields } from '@aztec/foundation/abi'; -import { type AztecAddress } from '@aztec/foundation/aztec-address'; -import { toBigIntBE } from '@aztec/foundation/bigint-buffer'; import { removeArrayPaddingEnd } from '@aztec/foundation/collection'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, type Tuple } from '@aztec/foundation/serialize'; import chunk from 'lodash.chunk'; -import { - ARTIFACT_FUNCTION_TREE_MAX_HEIGHT, - MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS, - REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE, - REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS, - REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE, -} from '../../constants.gen.js'; -import { type UnconstrainedFunction, type UnconstrainedFunctionWithMembershipProof } from '../interfaces/index.js'; +import { REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_TAG } from '../protocol_contract_data.js'; /** Event emitted from the ContractClassRegisterer. */ export class UnconstrainedFunctionBroadcastedEvent { @@ -28,23 +26,10 @@ export class UnconstrainedFunctionBroadcastedEvent { ) {} static isUnconstrainedFunctionBroadcastedEvent(log: Buffer) { - return toBigIntBE(log.subarray(0, 32)) == REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE; - } - - static fromLogs(logs: { contractAddress: AztecAddress; data: Buffer }[], registererContractAddress: AztecAddress) { - return logs - .filter(log => UnconstrainedFunctionBroadcastedEvent.isUnconstrainedFunctionBroadcastedEvent(log.data)) - .filter(log => log.contractAddress.equals(registererContractAddress)) - .map(log => this.fromLogData(log.data)); + return log.subarray(0, 32).equals(REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_TAG.toBuffer()); } - static fromLogData(log: Buffer) { - if (!this.isUnconstrainedFunctionBroadcastedEvent(log)) { - throw new Error( - `Log data for UnconstrainedFunctionBroadcastedEvent is not prefixed with magic value 0x${REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE}`, - ); - } - + static fromLog(log: Buffer) { const expectedLength = 32 * (MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS + diff --git a/yarn-project/protocol-contracts/src/index.ts b/yarn-project/protocol-contracts/src/index.ts index adb7745ebef..029032c827f 100644 --- a/yarn-project/protocol-contracts/src/index.ts +++ b/yarn-project/protocol-contracts/src/index.ts @@ -1,3 +1,8 @@ +export * from './auth-registry/index.js'; +export * from './class-registerer/index.js'; +export * from './fee-juice/index.js'; +export * from './instance-deployer/index.js'; +export * from './multi-call-entrypoint/index.js'; export * from './protocol_contract.js'; export * from './protocol_contract_data.js'; export * from './protocol_contract_tree.js'; diff --git a/yarn-project/protocol-contracts/src/instance-deployer/contract_instance_deployed_event.test.ts b/yarn-project/protocol-contracts/src/instance-deployer/contract_instance_deployed_event.test.ts new file mode 100644 index 00000000000..30a9744ec9f --- /dev/null +++ b/yarn-project/protocol-contracts/src/instance-deployer/contract_instance_deployed_event.test.ts @@ -0,0 +1,18 @@ +import { PrivateLog } from '@aztec/circuits.js'; + +import { getSampleContractInstanceDeployedEventPayload } from '../tests/fixtures.js'; +import { ContractInstanceDeployedEvent } from './contract_instance_deployed_event.js'; + +describe('ContractInstanceDeployedEvent', () => { + it('parses an event as emitted by the ClassInstanceDeployer', () => { + const data = getSampleContractInstanceDeployedEventPayload(); + const log = PrivateLog.fromBuffer(data); + expect(ContractInstanceDeployedEvent.isContractInstanceDeployedEvent(log)).toBe(true); + + const event = ContractInstanceDeployedEvent.fromLog(log); + expect(event.address.toString()).toEqual('0x0c5c6978e380c4e3940ab74770639260bcc75c93c3d0ae48ee4a241d555b094e'); + expect(event.contractClassId.toString()).toEqual( + '0x2b78af6d543573f77372e53e66932714d68877b4bcbb18671e68a846795297e1', + ); + }); +}); diff --git a/yarn-project/circuits.js/src/contract/events/contract_instance_deployed_event.ts b/yarn-project/protocol-contracts/src/instance-deployer/contract_instance_deployed_event.ts similarity index 53% rename from yarn-project/circuits.js/src/contract/events/contract_instance_deployed_event.ts rename to yarn-project/protocol-contracts/src/instance-deployer/contract_instance_deployed_event.ts index 9f58f13f059..500f87f82fd 100644 --- a/yarn-project/circuits.js/src/contract/events/contract_instance_deployed_event.ts +++ b/yarn-project/protocol-contracts/src/instance-deployer/contract_instance_deployed_event.ts @@ -1,11 +1,9 @@ +import { type ContractInstanceWithAddress, type PrivateLog, PublicKeys } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { toBigIntBE } from '@aztec/foundation/bigint-buffer'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader } from '@aztec/foundation/serialize'; -import { DEPLOYER_CONTRACT_ADDRESS, DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE } from '../../constants.gen.js'; -import { PublicKeys } from '../../types/public_keys.js'; -import { type ContractInstanceWithAddress } from '../interfaces/contract_instance.js'; +import { DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_TAG } from '../protocol_contract_data.js'; /** Event emitted from the ContractInstanceDeployer. */ export class ContractInstanceDeployedEvent { @@ -19,28 +17,13 @@ export class ContractInstanceDeployedEvent { public readonly deployer: AztecAddress, ) {} - static isContractInstanceDeployedEvent(log: Buffer) { - return toBigIntBE(log.subarray(0, 32)) == DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE; + static isContractInstanceDeployedEvent(log: PrivateLog) { + return log.fields[0].equals(DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_TAG); } - // We store the contract instance deployed event log in enc logs, contract_instance_deployer_contract/src/main.nr - static fromLogs(logs: { maskedContractAddress: Fr; data: Buffer }[]) { - return logs - .filter(log => ContractInstanceDeployedEvent.isContractInstanceDeployedEvent(log.data)) - .filter(log => - AztecAddress.fromField(log.maskedContractAddress).equals( - AztecAddress.fromBigInt(BigInt(DEPLOYER_CONTRACT_ADDRESS)), - ), - ) - .map(log => ContractInstanceDeployedEvent.fromLogData(log.data)); - } - - static fromLogData(log: Buffer) { - if (!this.isContractInstanceDeployedEvent(log)) { - const magicValue = DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE.toString(16); - throw new Error(`Log data for ContractInstanceDeployedEvent is not prefixed with magic value 0x${magicValue}`); - } - const reader = new BufferReader(log.subarray(32)); + static fromLog(log: PrivateLog) { + const bufferWithoutTag = log.toBuffer().subarray(32); + const reader = new BufferReader(bufferWithoutTag); const address = reader.readObject(AztecAddress); const version = reader.readObject(Fr).toNumber(); const salt = reader.readObject(Fr); diff --git a/yarn-project/protocol-contracts/src/instance-deployer/index.ts b/yarn-project/protocol-contracts/src/instance-deployer/index.ts index 600c06392c6..1253aeb915d 100644 --- a/yarn-project/protocol-contracts/src/instance-deployer/index.ts +++ b/yarn-project/protocol-contracts/src/instance-deployer/index.ts @@ -1,5 +1,7 @@ import { type ProtocolContract, getCanonicalProtocolContract } from '../protocol_contract.js'; +export * from './contract_instance_deployed_event.js'; + /** Returns the canonical deployment of the instance deployer contract. */ export function getCanonicalInstanceDeployer(): ProtocolContract { return getCanonicalProtocolContract('ContractInstanceDeployer'); diff --git a/yarn-project/protocol-contracts/src/scripts/generate_data.ts b/yarn-project/protocol-contracts/src/scripts/generate_data.ts index 6aefff993d4..eebd16860fe 100644 --- a/yarn-project/protocol-contracts/src/scripts/generate_data.ts +++ b/yarn-project/protocol-contracts/src/scripts/generate_data.ts @@ -2,13 +2,18 @@ import { AztecAddress, CANONICAL_AUTH_REGISTRY_ADDRESS, DEPLOYER_CONTRACT_ADDRESS, + DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE, FEE_JUICE_ADDRESS, Fr, MULTI_CALL_ENTRYPOINT_ADDRESS, REGISTERER_CONTRACT_ADDRESS, + REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE, + REGISTERER_PRIVATE_FUNCTION_BROADCASTED_MAGIC_VALUE, + REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE, ROUTER_ADDRESS, getContractInstanceFromDeployParams, } from '@aztec/circuits.js'; +import { poseidon2Hash } from '@aztec/foundation/crypto'; import { createConsoleLogger } from '@aztec/foundation/log'; import { loadContractArtifact } from '@aztec/types/abi'; import { type NoirCompiledContract } from '@aztec/types/noir'; @@ -144,6 +149,18 @@ function generateRoot(names: string[], leaves: Fr[]) { `; } +function generateLogTags() { + return ` + export const REGISTERER_CONTRACT_CLASS_REGISTERED_TAG = new Fr(${REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE}n); + export const REGISTERER_PRIVATE_FUNCTION_BROADCASTED_TAG = new Fr(${REGISTERER_PRIVATE_FUNCTION_BROADCASTED_MAGIC_VALUE}n); + export const REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_TAG = new Fr(${REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE}n); + export const DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_TAG = Fr.fromString('${poseidon2Hash([ + DEPLOYER_CONTRACT_ADDRESS, + DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE, + ])}'); + `; +} + async function generateOutputFile(names: string[], leaves: Fr[]) { const content = ` // GENERATED FILE - DO NOT EDIT. RUN \`yarn generate\` or \`yarn generate:data\` @@ -163,6 +180,8 @@ async function generateOutputFile(names: string[], leaves: Fr[]) { ${generateContractLeaves(names, leaves)} ${generateRoot(names, leaves)} + + ${generateLogTags()} `; await fs.writeFile(outputFilePath, content); } diff --git a/yarn-project/protocol-contracts/src/tests/fixtures.ts b/yarn-project/protocol-contracts/src/tests/fixtures.ts new file mode 100644 index 00000000000..9dab177e881 --- /dev/null +++ b/yarn-project/protocol-contracts/src/tests/fixtures.ts @@ -0,0 +1,31 @@ +import { readFileSync } from 'fs'; +import { dirname, resolve } from 'path'; +import { fileURLToPath } from 'url'; + +// Generated from end-to-end/src/e2e_deploy_contract/contract_class_registration.test.ts with AZTEC_GENERATE_TEST_DATA=1 +export function getSampleContractClassRegisteredEventPayload(): Buffer { + const path = getPathToFixture('ContractClassRegisteredEventData.hex'); + return Buffer.from(readFileSync(path).toString(), 'hex'); +} + +// Generated from end-to-end/src/e2e_deploy_contract/contract_class_registration.test.ts with AZTEC_GENERATE_TEST_DATA=1 +export function getSamplePrivateFunctionBroadcastedEventPayload(): Buffer { + const path = getPathToFixture('PrivateFunctionBroadcastedEventData.hex'); + return Buffer.from(readFileSync(path).toString(), 'hex'); +} + +// Generated from end-to-end/src/e2e_deploy_contract/contract_class_registration.test.ts with AZTEC_GENERATE_TEST_DATA=1 +export function getSampleUnconstrainedFunctionBroadcastedEventPayload(): Buffer { + const path = getPathToFixture('UnconstrainedFunctionBroadcastedEventData.hex'); + return Buffer.from(readFileSync(path).toString(), 'hex'); +} + +// Generated from end-to-end/src/e2e_deploy_contract/contract_class_registration.test.ts with AZTEC_GENERATE_TEST_DATA=1 +export function getSampleContractInstanceDeployedEventPayload(): Buffer { + const path = getPathToFixture('ContractInstanceDeployedEventData.hex'); + return Buffer.from(readFileSync(path).toString(), 'hex'); +} + +export function getPathToFixture(name: string) { + return resolve(dirname(fileURLToPath(import.meta.url)), `../../fixtures/${name}`); +} diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator.ts b/yarn-project/prover-client/src/orchestrator/orchestrator.ts index 85c71b7f8ba..fdf607298e2 100644 --- a/yarn-project/prover-client/src/orchestrator/orchestrator.ts +++ b/yarn-project/prover-client/src/orchestrator/orchestrator.ts @@ -602,13 +602,6 @@ export class ProvingOrchestrator implements EpochProver { provingState: BlockProvingState, ) { const txProvingState = new TxProvingState(tx, hints, treeSnapshots); - - const rejectReason = txProvingState.verifyStateOrReject(); - if (rejectReason) { - provingState.reject(rejectReason); - return; - } - const txIndex = provingState.addNewTx(txProvingState); this.enqueueTube(provingState, txIndex); if (txProvingState.requireAvmProof) { diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator_mixed_blocks.test.ts b/yarn-project/prover-client/src/orchestrator/orchestrator_mixed_blocks.test.ts index 9aa8a2e793e..e4ebaee303e 100644 --- a/yarn-project/prover-client/src/orchestrator/orchestrator_mixed_blocks.test.ts +++ b/yarn-project/prover-client/src/orchestrator/orchestrator_mixed_blocks.test.ts @@ -48,7 +48,7 @@ describe('prover/orchestrator/mixed-blocks', () => { }); it.each([2, 4, 5, 8] as const)('builds an L2 block with %i bloated txs', async (totalCount: number) => { - const txs = times(totalCount, (i: number) => makeBloatedProcessedTxWithVKRoot(context.actualDb, i)); + const txs = times(totalCount, (i: number) => makeBloatedProcessedTxWithVKRoot(context.actualDb, i + 1)); const l1ToL2Messages = range(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, 1 + 0x400).map(fr); diff --git a/yarn-project/prover-client/src/orchestrator/tx-proving-state.ts b/yarn-project/prover-client/src/orchestrator/tx-proving-state.ts index d3bcec2b7d5..311b4aa75a0 100644 --- a/yarn-project/prover-client/src/orchestrator/tx-proving-state.ts +++ b/yarn-project/prover-client/src/orchestrator/tx-proving-state.ts @@ -1,18 +1,10 @@ -import { - EncryptedNoteTxL2Logs, - EncryptedTxL2Logs, - type MerkleTreeId, - type ProcessedTx, - type ProofAndVerificationKey, - UnencryptedTxL2Logs, -} from '@aztec/circuit-types'; +import { type MerkleTreeId, type ProcessedTx, type ProofAndVerificationKey } from '@aztec/circuit-types'; import { type AVM_PROOF_LENGTH_IN_FIELDS, AVM_VK_INDEX, type AppendOnlyTreeSnapshot, AvmProofData, type BaseRollupHints, - Fr, PrivateBaseRollupHints, PrivateBaseRollupInputs, PrivateTubeData, @@ -112,53 +104,6 @@ export class TxProvingState { this.avm = avmProofAndVk; } - public verifyStateOrReject(): string | undefined { - const txEffect = this.processedTx.txEffect; - const fromPrivate = this.processedTx.data; - - const noteEncryptedLogsHashes = [ - fromPrivate.forRollup?.end.noteEncryptedLogsHashes || [], - fromPrivate.forPublic?.nonRevertibleAccumulatedData.noteEncryptedLogsHashes || [], - fromPrivate.forPublic?.revertibleAccumulatedData.noteEncryptedLogsHashes || [], - ].flat(); - const txNoteEncryptedLogsHash = EncryptedNoteTxL2Logs.hashNoteLogs( - noteEncryptedLogsHashes.filter(log => !log.isEmpty()).map(log => log.value.toBuffer()), - ); - if (!txNoteEncryptedLogsHash.equals(txEffect.noteEncryptedLogs.hash())) { - return `Note encrypted logs hash mismatch: ${Fr.fromBuffer(txNoteEncryptedLogsHash)} === ${Fr.fromBuffer( - txEffect.noteEncryptedLogs.hash(), - )}`; - } - - const encryptedLogsHashes = [ - fromPrivate.forRollup?.end.encryptedLogsHashes || [], - fromPrivate.forPublic?.nonRevertibleAccumulatedData.encryptedLogsHashes || [], - fromPrivate.forPublic?.revertibleAccumulatedData.encryptedLogsHashes || [], - ].flat(); - const txEncryptedLogsHash = EncryptedTxL2Logs.hashSiloedLogs( - encryptedLogsHashes.filter(log => !log.isEmpty()).map(log => log.getSiloedHash()), - ); - if (!txEncryptedLogsHash.equals(txEffect.encryptedLogs.hash())) { - // @todo This rejection messages is never seen. Never making it out to the logs - return `Encrypted logs hash mismatch: ${Fr.fromBuffer(txEncryptedLogsHash)} === ${Fr.fromBuffer( - txEffect.encryptedLogs.hash(), - )}`; - } - - const avmOutput = this.processedTx.avmProvingRequest?.inputs.output; - const unencryptedLogsHashes = avmOutput - ? avmOutput.accumulatedData.unencryptedLogsHashes - : fromPrivate.forRollup!.end.unencryptedLogsHashes; - const txUnencryptedLogsHash = UnencryptedTxL2Logs.hashSiloedLogs( - unencryptedLogsHashes.filter(log => !log.isEmpty()).map(log => log.getSiloedHash()), - ); - if (!txUnencryptedLogsHash.equals(txEffect.unencryptedLogs.hash())) { - return `Unencrypted logs hash mismatch: ${Fr.fromBuffer(txUnencryptedLogsHash)} === ${Fr.fromBuffer( - txEffect.unencryptedLogs.hash(), - )}`; - } - } - private getTubeVkData() { let vkIndex = TUBE_VK_INDEX; try { diff --git a/yarn-project/pxe/src/kernel_prover/hints/build_private_kernel_reset_private_inputs.ts b/yarn-project/pxe/src/kernel_prover/hints/build_private_kernel_reset_private_inputs.ts index ec6396e90f0..438506677df 100644 --- a/yarn-project/pxe/src/kernel_prover/hints/build_private_kernel_reset_private_inputs.ts +++ b/yarn-project/pxe/src/kernel_prover/hints/build_private_kernel_reset_private_inputs.ts @@ -131,7 +131,7 @@ export class PrivateKernelResetPrivateInputsBuilder { } else { // Siloing is only needed after processing all iterations. fns.push( - ...[() => this.needsSiloNoteHashes(), () => this.needsSiloNullifiers(), () => this.needsSiloLogHashes()], + ...[() => this.needsSiloNoteHashes(), () => this.needsSiloNullifiers(), () => this.needsSiloPrivateLogs()], ); // If there's no next iteration, reset is needed when any of the dimension has non empty data. // All the fns should to be executed so that data in all dimensions will be reset. @@ -447,24 +447,22 @@ export class PrivateKernelResetPrivateInputsBuilder { return numToSilo > 0; } - private needsSiloLogHashes() { + private needsSiloPrivateLogs() { if (this.numTransientData === undefined) { - throw new Error('`needsResetTransientData` must be run before `needsSiloLogHashes`.'); + throw new Error('`needsResetTransientData` must be run before `needsSiloPrivateLogs`.'); } - const numLogs = this.previousKernel.end.encryptedLogsHashes.filter(l => !l.logHash.randomness.isZero()).length; - const numToSilo = Math.max(0, numLogs - this.numTransientData); - // The reset circuit checks that capped_size must be greater than or equal to all non-empty logs. - // Since there is no current config with ENCRYPTED_LOG_SILOING_AMOUNT = 0 (only 1+), it defaults to 1, - // so the circuit fails when we have more than 1 log and require no siloing. - const numLogsNoSiloing = this.previousKernel.end.encryptedLogsHashes.filter( - l => !l.logHash.isEmpty() && l.logHash.randomness.isZero(), - ).length; - const cappedSize = !numToSilo && numLogsNoSiloing > 1 ? numLogsNoSiloing : numToSilo; - // NB: This is a little flimsy, and only works because we have either ENCRYPTED_LOG_SILOING_AMOUNT=1 or 8. - // e.g. if we have 2 logs that need siloing, and 2 that dont, then numLogs = ENCRYPTED_LOG_SILOING_AMOUNT = 2 - // This would fail because the circuit thinks that cappedSize = 2, but we have 4 logs. - this.requestedDimensions.ENCRYPTED_LOG_SILOING_AMOUNT = cappedSize; + const privateLogs = this.previousKernel.end.privateLogs; + const numLogs = privateLogs.filter(l => !l.contractAddress.isZero()).length; + + const noteHashes = this.previousKernel.end.noteHashes; + const squashedNoteHashCounters = this.transientDataIndexHints + .filter(h => h.noteHashIndex < noteHashes.length) + .map(h => noteHashes[h.noteHashIndex].counter); + const numSquashedLogs = privateLogs.filter(l => squashedNoteHashCounters.includes(l.inner.noteHashCounter)).length; + + const numToSilo = numLogs - numSquashedLogs; + this.requestedDimensions.PRIVATE_LOG_SILOING_AMOUNT = numToSilo; return numToSilo > 0; } diff --git a/yarn-project/pxe/src/kernel_prover/kernel_prover.test.ts b/yarn-project/pxe/src/kernel_prover/kernel_prover.test.ts index 25978d48da2..d7ae9401a9b 100644 --- a/yarn-project/pxe/src/kernel_prover/kernel_prover.test.ts +++ b/yarn-project/pxe/src/kernel_prover/kernel_prover.test.ts @@ -74,8 +74,6 @@ describe('Kernel Prover', () => { [], PublicExecutionRequest.empty(), [], - [], - [], ); }; diff --git a/yarn-project/pxe/src/pxe_service/pxe_service.ts b/yarn-project/pxe/src/pxe_service/pxe_service.ts index 9a41966a582..4a5ab7a7576 100644 --- a/yarn-project/pxe/src/pxe_service/pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/pxe_service.ts @@ -896,9 +896,7 @@ export class PXEService implements PXE { const blocks = await this.node.getBlocks(from, limit); const txEffects = blocks.flatMap(block => block.body.txEffects); - const encryptedTxLogs = txEffects.flatMap(txEffect => txEffect.encryptedLogs); - - const encryptedLogs = encryptedTxLogs.flatMap(encryptedTxLog => encryptedTxLog.unrollLogs()); + const privateLogs = txEffects.flatMap(txEffect => txEffect.privateLogs); const vsks = await Promise.all( vpks.map(async vpk => { @@ -919,10 +917,11 @@ export class PXEService implements PXE { }), ); - const visibleEvents = encryptedLogs.flatMap(encryptedLog => { + const visibleEvents = privateLogs.flatMap(log => { for (const sk of vsks) { - const decryptedEvent = - L1EventPayload.decryptAsIncoming(encryptedLog, sk) ?? L1EventPayload.decryptAsOutgoing(encryptedLog, sk); + // TODO: Verify that the first field of the log is the tag siloed with contract address. + // Or use tags to query logs, like we do with notes. + const decryptedEvent = L1EventPayload.decryptAsIncoming(log, sk) ?? L1EventPayload.decryptAsOutgoing(log, sk); if (decryptedEvent !== undefined) { return [decryptedEvent]; } diff --git a/yarn-project/pxe/src/simulator_oracle/index.ts b/yarn-project/pxe/src/simulator_oracle/index.ts index 00dfea9c56d..4a18b6bf758 100644 --- a/yarn-project/pxe/src/simulator_oracle/index.ts +++ b/yarn-project/pxe/src/simulator_oracle/index.ts @@ -22,6 +22,7 @@ import { IndexedTaggingSecret, type KeyValidationRequest, type L1_TO_L2_MSG_TREE_HEIGHT, + PrivateLog, computeAddressSecret, computeTaggingSecret, } from '@aztec/circuits.js'; @@ -373,7 +374,7 @@ export class SimulatorOracle implements DBOracle { do { const currentTags = [...new Array(INDEX_OFFSET)].map((_, i) => { const indexedAppTaggingSecret = new IndexedTaggingSecret(appTaggingSecret, currentIndex + i); - return indexedAppTaggingSecret.computeTag(recipient); + return indexedAppTaggingSecret.computeSiloedTag(recipient, contractAddress); }); previousEmptyBack = currentEmptyBack; @@ -466,7 +467,9 @@ export class SimulatorOracle implements DBOracle { while (currentTagggingSecrets.length > 0) { // 2. Compute tags using the secrets, recipient and index. Obtain logs for each tag (#9380) - const currentTags = currentTagggingSecrets.map(taggingSecret => taggingSecret.computeTag(recipient)); + const currentTags = currentTagggingSecrets.map(taggingSecret => + taggingSecret.computeSiloedTag(recipient, contractAddress), + ); const logsByTags = await this.aztecNode.getLogsByTags(currentTags); const newTaggingSecrets: IndexedTaggingSecret[] = []; logsByTags.forEach((logsByTag, logIndex) => { @@ -547,12 +550,12 @@ export class SimulatorOracle implements DBOracle { const txEffectsCache = new Map | undefined>(); for (const scopedLog of scopedLogs) { - const incomingNotePayload = L1NotePayload.decryptAsIncoming( - scopedLog.logData, - addressSecret, - scopedLog.isFromPublic, - ); - const outgoingNotePayload = L1NotePayload.decryptAsOutgoing(scopedLog.logData, ovskM, scopedLog.isFromPublic); + const incomingNotePayload = scopedLog.isFromPublic + ? L1NotePayload.decryptAsIncomingFromPublic(scopedLog.logData, addressSecret) + : L1NotePayload.decryptAsIncoming(PrivateLog.fromBuffer(scopedLog.logData), addressSecret); + const outgoingNotePayload = scopedLog.isFromPublic + ? L1NotePayload.decryptAsOutgoingFromPublic(scopedLog.logData, ovskM) + : L1NotePayload.decryptAsOutgoing(PrivateLog.fromBuffer(scopedLog.logData), ovskM); if (incomingNotePayload || outgoingNotePayload) { if (incomingNotePayload && outgoingNotePayload && !incomingNotePayload.equals(outgoingNotePayload)) { diff --git a/yarn-project/pxe/src/simulator_oracle/simulator_oracle.test.ts b/yarn-project/pxe/src/simulator_oracle/simulator_oracle.test.ts index 7dbb18cccf6..a9804de5eec 100644 --- a/yarn-project/pxe/src/simulator_oracle/simulator_oracle.test.ts +++ b/yarn-project/pxe/src/simulator_oracle/simulator_oracle.test.ts @@ -1,6 +1,5 @@ import { type AztecNode, - EncryptedL2NoteLog, EncryptedLogPayload, L1NotePayload, Note, @@ -76,10 +75,10 @@ class MockNoteRequest { } } - encrypt(): EncryptedL2NoteLog { + encrypt(): Buffer { const ephSk = GrumpkinScalar.random(); - const log = this.logPayload.encrypt(ephSk, this.recipient, this.ovKeys); - return new EncryptedL2NoteLog(log); + const log = this.logPayload.generatePayload(ephSk, this.recipient, this.ovKeys); + return log.toBuffer(); } get indexWithinNoteHashTree(): bigint { @@ -103,7 +102,7 @@ class MockNoteRequest { } } -function computeTagForIndex( +function computeSiloedTagForIndex( sender: { completeAddress: CompleteAddress; ivsk: Fq }, recipient: AztecAddress, contractAddress: AztecAddress, @@ -111,7 +110,8 @@ function computeTagForIndex( ) { const sharedSecret = computeTaggingSecret(sender.completeAddress, sender.ivsk, recipient); const siloedSecret = poseidon2Hash([sharedSecret.x, sharedSecret.y, contractAddress]); - return poseidon2Hash([siloedSecret, recipient, index]); + const tag = poseidon2Hash([siloedSecret, recipient, index]); + return poseidon2Hash([contractAddress, tag]); } describe('Simulator oracle', () => { @@ -153,7 +153,7 @@ describe('Simulator oracle', () => { // Add a random note from every address in the address book for our account with index senderOffset // Compute the tag as sender (knowledge of preaddress and ivsk) for (const sender of senders) { - const tag = computeTagForIndex(sender, recipient.address, contractAddress, senderOffset); + const tag = computeSiloedTagForIndex(sender, recipient.address, contractAddress, senderOffset); const blockNumber = 1; const randomNote = new MockNoteRequest( getRandomNoteLogPayload(tag, contractAddress), @@ -163,7 +163,7 @@ describe('Simulator oracle', () => { recipient.address, recipientOvKeys, ); - const log = new TxScopedL2Log(TxHash.random(), 0, blockNumber, false, randomNote.encrypt().data); + const log = new TxScopedL2Log(TxHash.random(), 0, blockNumber, false, randomNote.encrypt()); logs[tag.toString()] = [log]; } // Accumulated logs intended for recipient: NUM_SENDERS @@ -171,8 +171,10 @@ describe('Simulator oracle', () => { // Add a random note from the first sender in the address book, repeating the tag // Compute the tag as sender (knowledge of preaddress and ivsk) const firstSender = senders[0]; - const tag = computeTagForIndex(firstSender, recipient.address, contractAddress, senderOffset); - const log = new TxScopedL2Log(TxHash.random(), 1, 0, false, EncryptedL2NoteLog.random(tag).data); + const tag = computeSiloedTagForIndex(firstSender, recipient.address, contractAddress, senderOffset); + const payload = getRandomNoteLogPayload(tag, contractAddress); + const logData = payload.generatePayload(GrumpkinScalar.random(), recipient.address, recipientOvKeys).toBuffer(); + const log = new TxScopedL2Log(TxHash.random(), 1, 0, false, logData); logs[tag.toString()].push(log); // Accumulated logs intended for recipient: NUM_SENDERS + 1 @@ -180,7 +182,7 @@ describe('Simulator oracle', () => { // Compute the tag as sender (knowledge of preaddress and ivsk) for (let i = NUM_SENDERS / 2; i < NUM_SENDERS; i++) { const sender = senders[i]; - const tag = computeTagForIndex(sender, recipient.address, contractAddress, senderOffset + 1); + const tag = computeSiloedTagForIndex(sender, recipient.address, contractAddress, senderOffset + 1); const blockNumber = 2; const randomNote = new MockNoteRequest( getRandomNoteLogPayload(tag, contractAddress), @@ -190,7 +192,7 @@ describe('Simulator oracle', () => { recipient.address, recipientOvKeys, ); - const log = new TxScopedL2Log(TxHash.random(), 0, blockNumber, false, randomNote.encrypt().data); + const log = new TxScopedL2Log(TxHash.random(), 0, blockNumber, false, randomNote.encrypt()); logs[tag.toString()] = [log]; } // Accumulated logs intended for recipient: NUM_SENDERS + 1 + NUM_SENDERS / 2 @@ -201,7 +203,7 @@ describe('Simulator oracle', () => { const keys = deriveKeys(Fr.random()); const partialAddress = Fr.random(); const randomRecipient = computeAddress(keys.publicKeys, partialAddress); - const tag = computeTagForIndex(sender, randomRecipient, contractAddress, senderOffset); + const tag = computeSiloedTagForIndex(sender, randomRecipient, contractAddress, senderOffset); const blockNumber = 3; const randomNote = new MockNoteRequest( getRandomNoteLogPayload(tag, contractAddress), @@ -214,7 +216,7 @@ describe('Simulator oracle', () => { computeOvskApp(keys.masterOutgoingViewingSecretKey, contractAddress), ), ); - const log = new TxScopedL2Log(TxHash.random(), 0, blockNumber, false, randomNote.encrypt().data); + const log = new TxScopedL2Log(TxHash.random(), 0, blockNumber, false, randomNote.encrypt()); logs[tag.toString()] = [log]; } // Accumulated logs intended for recipient: NUM_SENDERS + 1 + NUM_SENDERS / 2 @@ -526,7 +528,7 @@ describe('Simulator oracle', () => { } const dataStartIndex = (request.blockNumber - 1) * NUM_NOTE_HASHES_PER_BLOCK + request.txIndex * MAX_NOTE_HASHES_PER_TX; - const taggedLog = new TxScopedL2Log(txHash, dataStartIndex, blockNumber, false, request.encrypt().data); + const taggedLog = new TxScopedL2Log(txHash, dataStartIndex, blockNumber, false, request.encrypt()); const note = request.snippetOfNoteDao.note; const noteHash = pedersenHash(note.items); txEffectsMap[txHash.toString()].noteHashes[request.noteHashIndex] = noteHash; diff --git a/yarn-project/simulator/src/acvm/oracle/oracle.ts b/yarn-project/simulator/src/acvm/oracle/oracle.ts index f52db4237b0..cdf274883f4 100644 --- a/yarn-project/simulator/src/acvm/oracle/oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/oracle.ts @@ -306,36 +306,6 @@ export class Oracle { return newValues.map(toACVMField); } - emitEncryptedEventLog( - [contractAddress]: ACVMField[], - [randomness]: ACVMField[], - encryptedEvent: ACVMField[], - [counter]: ACVMField[], - ): void { - // Convert each field to a number and then to a buffer (1 byte is stored in 1 field) - const processedInput = Buffer.from(encryptedEvent.map(fromACVMField).map(f => f.toNumber())); - this.typedOracle.emitEncryptedEventLog( - AztecAddress.fromString(contractAddress), - Fr.fromString(randomness), - processedInput, - +counter, - ); - } - - emitEncryptedNoteLog([noteHashCounter]: ACVMField[], encryptedNote: ACVMField[], [counter]: ACVMField[]): void { - // Convert each field to a number and then to a buffer (1 byte is stored in 1 field) - const processedInput = Buffer.from(encryptedNote.map(fromACVMField).map(f => f.toNumber())); - this.typedOracle.emitEncryptedNoteLog(+noteHashCounter, processedInput, +counter); - } - - emitUnencryptedLog([contractAddress]: ACVMField[], message: ACVMField[], [counter]: ACVMField[]): ACVMField { - const logPayload = Buffer.concat(message.map(fromACVMField).map(f => f.toBuffer())); - const log = new UnencryptedL2Log(AztecAddress.fromString(contractAddress), logPayload); - - this.typedOracle.emitUnencryptedLog(log, +counter); - return toACVMField(0); - } - emitContractClassLog([contractAddress]: ACVMField[], message: ACVMField[], [counter]: ACVMField[]): ACVMField { const logPayload = Buffer.concat(message.map(fromACVMField).map(f => f.toBuffer())); const log = new UnencryptedL2Log(AztecAddress.fromString(contractAddress), logPayload); diff --git a/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts index 541774c5979..197d235296a 100644 --- a/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts @@ -195,23 +195,6 @@ export abstract class TypedOracle { throw new OracleMethodNotAvailableError('storageWrite'); } - emitEncryptedEventLog( - _contractAddress: AztecAddress, - _randomness: Fr, - _encryptedEvent: Buffer, - _counter: number, - ): void { - throw new OracleMethodNotAvailableError('emitEncryptedEventLog'); - } - - emitEncryptedNoteLog(_noteHashCounter: number, _encryptedNote: Buffer, _counter: number): void { - throw new OracleMethodNotAvailableError('emitEncryptedNoteLog'); - } - - emitUnencryptedLog(_log: UnencryptedL2Log, _counter: number): void { - throw new OracleMethodNotAvailableError('emitUnencryptedLog'); - } - emitContractClassLog(_log: UnencryptedL2Log, _counter: number): Fr { throw new OracleMethodNotAvailableError('emitContractClassUnencryptedLog'); } diff --git a/yarn-project/simulator/src/avm/avm_simulator.test.ts b/yarn-project/simulator/src/avm/avm_simulator.test.ts index 72889ea63c1..06811af1557 100644 --- a/yarn-project/simulator/src/avm/avm_simulator.test.ts +++ b/yarn-project/simulator/src/avm/avm_simulator.test.ts @@ -1178,7 +1178,7 @@ describe('AVM simulator: transpiled Noir contracts', () => { const { preimage: lowLeafPreimage, index: lowLeafIndex, - alreadyPresent: leafAlreadyPresent, + update: leafAlreadyPresent, } = await ephemeralForest.getLeafOrLowLeafInfo( MerkleTreeId.PUBLIC_DATA_TREE, leafSlot0, @@ -1223,7 +1223,7 @@ describe('AVM simulator: transpiled Noir contracts', () => { const { preimage: lowLeafPreimage, index: lowLeafIndex, - alreadyPresent: leafAlreadyPresent, + update: leafAlreadyPresent, } = await ephemeralForest.getLeafOrLowLeafInfo( MerkleTreeId.PUBLIC_DATA_TREE, leafSlot0, @@ -1294,7 +1294,7 @@ describe('AVM simulator: transpiled Noir contracts', () => { const { preimage: lowLeafPreimage, index: lowLeafIndex, - alreadyPresent: leafAlreadyPresent, + update: leafAlreadyPresent, } = await ephemeralForest.getLeafOrLowLeafInfo( MerkleTreeId.PUBLIC_DATA_TREE, leafSlot0, diff --git a/yarn-project/simulator/src/avm/avm_tree.test.ts b/yarn-project/simulator/src/avm/avm_tree.test.ts index 47f88232828..aa0ab6bc07b 100644 --- a/yarn-project/simulator/src/avm/avm_tree.test.ts +++ b/yarn-project/simulator/src/avm/avm_tree.test.ts @@ -1,15 +1,15 @@ import { + type BatchInsertionResult, type IndexedTreeId, MerkleTreeId, type MerkleTreeWriteOperations, - type SequentialInsertionResult, } from '@aztec/circuit-types'; import { NOTE_HASH_TREE_HEIGHT, NULLIFIER_SUBTREE_HEIGHT, - NULLIFIER_TREE_HEIGHT, + type NULLIFIER_TREE_HEIGHT, type NullifierLeafPreimage, - PUBLIC_DATA_TREE_HEIGHT, + type PUBLIC_DATA_TREE_HEIGHT, PublicDataTreeLeaf, type PublicDataTreeLeafPreimage, } from '@aztec/circuits.js'; @@ -18,16 +18,11 @@ import { Fr } from '@aztec/foundation/fields'; import { type IndexedTreeLeafPreimage } from '@aztec/foundation/trees'; import { openTmpStore } from '@aztec/kv-store/utils'; import { NoopTelemetryClient } from '@aztec/telemetry-client/noop'; -import { MerkleTrees, NativeWorldStateService } from '@aztec/world-state'; +import { MerkleTrees } from '@aztec/world-state'; -import { - AvmEphemeralForest, - EphemeralAvmTree, - type IndexedInsertResult, - type IndexedUpsertResult, -} from './avm_tree.js'; +import { AvmEphemeralForest, EphemeralAvmTree, type IndexedInsertionResult } from './avm_tree.js'; -let mainState: MerkleTreeWriteOperations; +let worldStateTrees: MerkleTrees; let copyState: MerkleTreeWriteOperations; // Up to 64 dummy note hashes let noteHashes: Fr[]; @@ -42,9 +37,8 @@ let getSiblingIndex = 21n; // Helper to check the equality of the insertion results (low witness, insertion path) const checkEqualityOfInsertionResults = ( - containerResults: IndexedUpsertResult[] | IndexedInsertResult[], - wsResults: SequentialInsertionResult[], - treeHeight: number, + containerResults: IndexedInsertionResult[], + wsResults: BatchInsertionResult[], ) => { if (containerResults.length !== wsResults.length) { throw new Error('Results length mismatch'); @@ -55,41 +49,40 @@ const checkEqualityOfInsertionResults = ( expect(containerResult.lowWitness.siblingPath).toEqual(wsResult.lowLeavesWitnessData![0].siblingPath.toFields()); expect(containerResult.lowWitness.index).toEqual(wsResult.lowLeavesWitnessData![0].index); expect(containerResult.lowWitness.preimage).toEqual(wsResult.lowLeavesWitnessData![0].leafPreimage); - if ('update' in containerResult && containerResult.update) { - expect(Array(treeHeight).fill(Fr.ZERO)).toEqual(wsResult.insertionWitnessData[0].siblingPath.toFields()); - } else { - expect(containerResult.insertionPath).toEqual(wsResult.insertionWitnessData[0].siblingPath.toFields()); - } + expect(containerResult.insertionPath).toEqual(wsResult.newSubtreeSiblingPath.toFields()); } }; const getWorldStateRoot = async (treeId: MerkleTreeId) => { - return (await mainState.getTreeInfo(treeId)).root; + return (await worldStateTrees.getTreeInfo(treeId, /*includeUncommitted=*/ true)).root; }; const getWorldStateSiblingPath = (treeId: MerkleTreeId, index: bigint) => { - return mainState.getSiblingPath(treeId, index); + return worldStateTrees.getSiblingPath(treeId, index, /*includeUncommitted=*/ true); }; const publicDataInsertWorldState = ( slot: Fr, value: Fr, -): Promise> => { - return mainState.sequentialInsert(MerkleTreeId.PUBLIC_DATA_TREE, [new PublicDataTreeLeaf(slot, value).toBuffer()]); +): Promise> => { + return worldStateTrees.batchInsert( + MerkleTreeId.PUBLIC_DATA_TREE, + [new PublicDataTreeLeaf(slot, value).toBuffer()], + 0, + ); }; const nullifierInsertWorldState = ( nullifier: Fr, -): Promise> => { - return mainState.sequentialInsert(MerkleTreeId.NULLIFIER_TREE, [nullifier.toBuffer()]); +): Promise> => { + return worldStateTrees.batchInsert(MerkleTreeId.NULLIFIER_TREE, [nullifier.toBuffer()], 0); }; // Set up some recurring state for the tests beforeEach(async () => { - const worldState = await NativeWorldStateService.tmp(); - - mainState = await worldState.fork(); - copyState = await worldState.fork(); + const store = openTmpStore(true); + worldStateTrees = await MerkleTrees.new(store, new NoopTelemetryClient()); + copyState = await worldStateTrees.fork(); noteHashes = Array.from({ length: 64 }, (_, i) => new Fr(i)); // We do + 128 since the first 128 leaves are already filled in the indexed trees (nullifier, public data) @@ -132,7 +125,7 @@ describe('Simple Note Hash Consistency', () => { for (const noteHash of noteHashes) { treeContainer.appendNoteHash(noteHash); } - await mainState.appendLeaves(treeId, noteHashes); + await worldStateTrees.appendLeaves(treeId, noteHashes); // Check that the roots are consistent const wsRoot = await getWorldStateRoot(treeId); @@ -159,7 +152,7 @@ describe('Simple Note Hash Consistency', () => { } // Build a worldstateDB with all the note hashes - await mainState.appendLeaves(treeId, preInserted.concat(postInserted)); + await worldStateTrees.appendLeaves(treeId, preInserted.concat(postInserted)); // Check that the roots are consistent const wsRoot = await getWorldStateRoot(treeId); @@ -181,8 +174,8 @@ describe('Simple Note Hash Consistency', () => { describe('Simple Public Data Consistency', () => { const treeId = MerkleTreeId.PUBLIC_DATA_TREE as IndexedTreeId; - let containerInsertionResults: IndexedUpsertResult[] = []; - let worldStateInsertionResults: SequentialInsertionResult[] = []; + let containerInsertionResults: IndexedInsertionResult[] = []; + let worldStateInsertionResults: BatchInsertionResult[] = []; // We need to zero out between tests afterEach(() => { @@ -206,7 +199,7 @@ describe('Simple Public Data Consistency', () => { expect(computedRoot.toBuffer()).toEqual(wsRoot); // Check that all the accumulated insertion results match - checkEqualityOfInsertionResults(containerInsertionResults, worldStateInsertionResults, PUBLIC_DATA_TREE_HEIGHT); + checkEqualityOfInsertionResults(containerInsertionResults, worldStateInsertionResults); }); it('Should fork a prefilled tree and check consistency', async () => { @@ -274,14 +267,14 @@ describe('Simple Public Data Consistency', () => { expect(computedRoot.toBuffer()).toEqual(wsRoot); // Check the insertion results match - checkEqualityOfInsertionResults(containerInsertionResults, worldStateInsertionResults, PUBLIC_DATA_TREE_HEIGHT); + checkEqualityOfInsertionResults(containerInsertionResults, worldStateInsertionResults); }); }); describe('Simple Nullifier Consistency', () => { const treeId = MerkleTreeId.NULLIFIER_TREE as IndexedTreeId; - let containerInsertionResults: IndexedInsertResult[] = []; - let worldStateInsertionResults: SequentialInsertionResult[] = []; + let containerInsertionResults: IndexedInsertionResult[] = []; + let worldStateInsertionResults: BatchInsertionResult[] = []; // We need to zero out between tests afterEach(() => { @@ -304,7 +297,7 @@ describe('Simple Nullifier Consistency', () => { expect(computedRoot.toBuffer()).toEqual(wsRoot); // Check that all the accumulated insertion results match - checkEqualityOfInsertionResults(containerInsertionResults, worldStateInsertionResults, NULLIFIER_TREE_HEIGHT); + checkEqualityOfInsertionResults(containerInsertionResults, worldStateInsertionResults); // Check a sibling path from a random index is consistent const wsSiblingPath = await getWorldStateSiblingPath(treeId, getSiblingIndex); @@ -332,11 +325,7 @@ describe('Simple Nullifier Consistency', () => { expect(computedRoot.toBuffer()).toEqual(wsRoot); // Check insertion results - note we can only compare against the post-insertion results - checkEqualityOfInsertionResults( - containerInsertionResults, - worldStateInsertionResults.slice(preInsertIndex), - NULLIFIER_TREE_HEIGHT, - ); + checkEqualityOfInsertionResults(containerInsertionResults, worldStateInsertionResults.slice(preInsertIndex)); }); it('Should check that the insertion paths resolve to the root', async () => { @@ -377,7 +366,7 @@ describe('Simple Nullifier Consistency', () => { // Update low nullifier const newLowNullifier = containerInsert.lowWitness.preimage; newLowNullifier.nextIndex = containerInsert.leafIndex; - newLowNullifier.nextNullifier = containerInsert.element.nullifier; + newLowNullifier.nextNullifier = containerInsert.newOrElementToUpdate.element.nullifier; // Compute new root const updatedRoot = calcRootFromPath( containerInsert.lowWitness.siblingPath, @@ -392,7 +381,7 @@ describe('Simple Nullifier Consistency', () => { // Step 4 const finalRoot = calcRootFromPath( containerInsert.insertionPath, - treeContainer.hashPreimage(containerInsert.element), + treeContainer.hashPreimage(containerInsert.newOrElementToUpdate.element), containerInsert.leafIndex, ); expect(finalRoot.toBuffer()).toEqual(rootAfter); @@ -421,7 +410,7 @@ describe('Big Random Avm Ephemeral Container Test', () => { // Insert values ino merkleTrees // Note Hash - await mainState.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, noteHashes.slice(0, ENTRY_COUNT)); + await worldStateTrees.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, noteHashes.slice(0, ENTRY_COUNT)); // Everything else for (let i = 0; i < ENTRY_COUNT; i++) { await nullifierInsertWorldState(indexedHashes[i]); @@ -488,7 +477,7 @@ describe('Checking forking and merging', () => { it('Fork-Rollback-Fork-Merge should be consistent', async () => { // To store results - const wsInsertionResults: SequentialInsertionResult[] = []; + const wsInsertionResults: BatchInsertionResult[] = []; const containerInsertionResults = []; const treeContainer = await AvmEphemeralForest.create(copyState); @@ -517,7 +506,7 @@ describe('Checking forking and merging', () => { expect(containerRoot.toBuffer()).toEqual(wsRoot); // Check that all the accumulated insertion results - checkEqualityOfInsertionResults(containerInsertionResults, wsInsertionResults, PUBLIC_DATA_TREE_HEIGHT); + checkEqualityOfInsertionResults(containerInsertionResults, wsInsertionResults); }); }); @@ -565,7 +554,7 @@ describe('Batch Insertion', () => { const treeContainer = await AvmEphemeralForest.create(copyState); await treeContainer.appendNullifier(indexedHashes[0]); await treeContainer.appendNullifier(indexedHashes[1]); - await mainState.batchInsert( + await worldStateTrees.batchInsert( MerkleTreeId.NULLIFIER_TREE, [indexedHashes[0].toBuffer(), indexedHashes[1].toBuffer()], NULLIFIER_SUBTREE_HEIGHT, diff --git a/yarn-project/simulator/src/avm/avm_tree.ts b/yarn-project/simulator/src/avm/avm_tree.ts index f9cc70f745e..86c4b160d7d 100644 --- a/yarn-project/simulator/src/avm/avm_tree.ts +++ b/yarn-project/simulator/src/avm/avm_tree.ts @@ -17,14 +17,7 @@ import cloneDeep from 'lodash.clonedeep'; type PreimageWitness = { preimage: T; index: bigint; -}; - -/** - * The result of fetching a leaf from an indexed tree. Contains the preimage and wether the leaf was already present - * or it's a low leaf. - */ -type GetLeafResult = PreimageWitness & { - alreadyPresent: boolean; + update: boolean; }; /** @@ -36,30 +29,16 @@ type LeafWitness = PreimageWitness & { }; /** - * The result of an update in an indexed merkle tree (no new leaf inserted) - */ -type IndexedUpdateResult = { - element: T; - lowWitness: LeafWitness; -}; - -/** - * The result of an insertion in an indexed merkle tree. + * The result of an indexed insertion in an indexed merkle tree. * This will be used to hint the circuit */ -export type IndexedInsertResult = IndexedUpdateResult & { +export type IndexedInsertionResult = { leafIndex: bigint; insertionPath: Fr[]; + newOrElementToUpdate: { update: boolean; element: T }; + lowWitness: LeafWitness; }; -/** - * The result of an indexed upsert in an indexed merkle tree. - * This will be used to hint the circuit - */ -export type IndexedUpsertResult = - | (IndexedUpdateResult & { update: true }) - | (IndexedInsertResult & { update: false }); - /****************************************************/ /****** The AvmEphemeralForest Class ****************/ /****************************************************/ @@ -165,7 +144,7 @@ export class AvmEphemeralForest { * @param newValue - The value to be written or updated to * @returns The insertion result which contains the insertion path, low leaf and the new leaf index */ - async writePublicStorage(slot: Fr, newValue: Fr): Promise> { + async writePublicStorage(slot: Fr, newValue: Fr): Promise> { // This only works for the public data tree const treeId = MerkleTreeId.PUBLIC_DATA_TREE; const tree = this.treeMap.get(treeId)!; @@ -173,12 +152,12 @@ export class AvmEphemeralForest { typeof treeId, PublicDataTreeLeafPreimage >(treeId, slot); - const { preimage, index: lowLeafIndex, alreadyPresent: update } = leafOrLowLeafInfo; - const siblingPath = await this.getSiblingPath(treeId, lowLeafIndex); + const { preimage, index, update } = leafOrLowLeafInfo; + const siblingPath = await this.getSiblingPath(treeId, index); if (pathAbsentInEphemeralTree) { // Since we have never seen this before - we should insert it into our tree as it is about to be updated. - this.treeMap.get(treeId)!.insertSiblingPath(lowLeafIndex, siblingPath); + this.treeMap.get(treeId)!.insertSiblingPath(index, siblingPath); } if (update) { @@ -186,18 +165,29 @@ export class AvmEphemeralForest { const existingPublicDataSiblingPath = siblingPath; updatedPreimage.value = newValue; - tree.updateLeaf(this.hashPreimage(updatedPreimage), lowLeafIndex); - this.setIndexedUpdates(treeId, lowLeafIndex, updatedPreimage); - this._updateSortedKeys(treeId, [updatedPreimage.slot], [lowLeafIndex]); + // It is really unintuitive that by updating, we are also appending a Zero Leaf to the tree + // Additionally, this leaf preimage does not seem to factor into further appends + const emptyLeaf = new PublicDataTreeLeafPreimage(Fr.ZERO, Fr.ZERO, Fr.ZERO, 0n); + const insertionIndex = tree.leafCount; + tree.updateLeaf(this.hashPreimage(updatedPreimage), index); + tree.appendLeaf(Fr.ZERO); + this.setIndexedUpdates(treeId, index, updatedPreimage); + this.setIndexedUpdates(treeId, insertionIndex, emptyLeaf); + const insertionPath = tree.getSiblingPath(insertionIndex)!; + + // Even though we append an empty leaf into the tree as a part of update - it doesnt seem to impact future inserts... + this._updateSortedKeys(treeId, [updatedPreimage.slot], [index]); return { - element: updatedPreimage, + leafIndex: insertionIndex, + insertionPath, + newOrElementToUpdate: { update: true, element: updatedPreimage }, lowWitness: { preimage: preimage, - index: lowLeafIndex, + index: index, + update: true, siblingPath: existingPublicDataSiblingPath, }, - update: true, }; } // We are writing to a new slot, so our preimage is a lowNullifier @@ -212,22 +202,22 @@ export class AvmEphemeralForest { new Fr(preimage.getNextKey()), preimage.getNextIndex(), ); - const insertionPath = this.appendIndexedTree(treeId, lowLeafIndex, updatedLowLeaf, newPublicDataLeaf); + const insertionPath = this.appendIndexedTree(treeId, index, updatedLowLeaf, newPublicDataLeaf); // Even though the low leaf key is not updated, we still need to update the sorted keys in case we have // not seen the low leaf before - this._updateSortedKeys(treeId, [newPublicDataLeaf.slot, updatedLowLeaf.slot], [insertionIndex, lowLeafIndex]); + this._updateSortedKeys(treeId, [newPublicDataLeaf.slot, updatedLowLeaf.slot], [insertionIndex, index]); return { - element: newPublicDataLeaf, + leafIndex: insertionIndex, + insertionPath: insertionPath, + newOrElementToUpdate: { update: false, element: newPublicDataLeaf }, lowWitness: { preimage, - index: lowLeafIndex, + index: index, + update: false, siblingPath, }, - update: false, - leafIndex: insertionIndex, - insertionPath: insertionPath, }; } @@ -257,14 +247,14 @@ export class AvmEphemeralForest { * @param value - The nullifier to be appended * @returns The insertion result which contains the insertion path, low leaf and the new leaf index */ - async appendNullifier(nullifier: Fr): Promise> { + async appendNullifier(nullifier: Fr): Promise> { const treeId = MerkleTreeId.NULLIFIER_TREE; const tree = this.treeMap.get(treeId)!; const [leafOrLowLeafInfo, pathAbsentInEphemeralTree] = await this._getLeafOrLowLeafInfo< typeof treeId, NullifierLeafPreimage >(treeId, nullifier); - const { preimage, index, alreadyPresent } = leafOrLowLeafInfo; + const { preimage, index, update } = leafOrLowLeafInfo; const siblingPath = await this.getSiblingPath(treeId, index); if (pathAbsentInEphemeralTree) { @@ -272,7 +262,7 @@ export class AvmEphemeralForest { this.treeMap.get(treeId)!.insertSiblingPath(index, siblingPath); } - assert(!alreadyPresent, 'Nullifier already exists in the tree. Cannot update a nullifier!'); + assert(!update, 'Nullifier already exists in the tree. Cannot update a nullifier!'); // We are writing a new entry const insertionIndex = tree.leafCount; @@ -292,14 +282,15 @@ export class AvmEphemeralForest { ); return { - element: newNullifierLeaf, + leafIndex: insertionIndex, + insertionPath: insertionPath, + newOrElementToUpdate: { update: false, element: newNullifierLeaf }, lowWitness: { preimage, index, + update, siblingPath, }, - leafIndex: insertionIndex, - insertionPath: insertionPath, }; } @@ -369,7 +360,7 @@ export class AvmEphemeralForest { async getLeafOrLowLeafInfo( treeId: ID, key: Fr, - ): Promise> { + ): Promise> { const [leafOrLowLeafInfo, _] = await this._getLeafOrLowLeafInfo(treeId, key); return leafOrLowLeafInfo; } @@ -382,14 +373,14 @@ export class AvmEphemeralForest { * @param key - The key for which we are look up the leaf or low leaf for. * @param T - The type of the preimage (PublicData or Nullifier) * @returns [ - * getLeafResult - The leaf or low leaf info (preimage & leaf index), + * preimageWitness - The leaf or low leaf info (preimage & leaf index), * pathAbsentInEphemeralTree - whether its sibling path is absent in the ephemeral tree (useful during insertions) * ] */ async _getLeafOrLowLeafInfo( treeId: ID, key: Fr, - ): Promise<[GetLeafResult, /*pathAbsentInEphemeralTree=*/ boolean]> { + ): Promise<[PreimageWitness, /*pathAbsentInEphemeralTree=*/ boolean]> { const bigIntKey = key.toBigInt(); // In this function, "min" refers to the leaf with the // largest key <= the specified key in the indexedUpdates. @@ -401,7 +392,7 @@ export class AvmEphemeralForest { if (minIndexedLeafIndex === -1n) { // No leaf is present in the indexed updates that is <= the key, // so retrieve the leaf or low leaf from the underlying DB. - const leafOrLowLeafPreimage: GetLeafResult = await this._getLeafOrLowLeafWitnessInExternalDb( + const leafOrLowLeafPreimage: PreimageWitness = await this._getLeafOrLowLeafWitnessInExternalDb( treeId, bigIntKey, ); @@ -411,7 +402,7 @@ export class AvmEphemeralForest { const minPreimage: T = this.getIndexedUpdate(treeId, minIndexedLeafIndex); if (minPreimage.getKey() === bigIntKey) { // the index found is an exact match, no need to search further - const leafInfo = { preimage: minPreimage, index: minIndexedLeafIndex, alreadyPresent: true }; + const leafInfo = { preimage: minPreimage, index: minIndexedLeafIndex, update: true }; return [leafInfo, /*pathAbsentInEphemeralTree=*/ false]; } else { // We are starting with the leaf with largest key <= the specified key @@ -462,7 +453,7 @@ export class AvmEphemeralForest { private async _getLeafOrLowLeafWitnessInExternalDb( treeId: ID, key: bigint, - ): Promise> { + ): Promise> { // "key" is siloed slot (leafSlot) or siloed nullifier const previousValueIndex = await this.treeDb.getPreviousValueIndex(treeId, key); assert( @@ -477,7 +468,7 @@ export class AvmEphemeralForest { `${MerkleTreeId[treeId]} low leaf preimage should never be undefined (even if target leaf does not exist)`, ); - return { preimage: leafPreimage as T, index: leafIndex, alreadyPresent }; + return { preimage: leafPreimage as T, index: leafIndex, update: alreadyPresent }; } /** @@ -490,7 +481,7 @@ export class AvmEphemeralForest { * @param minIndex - The index of the leaf with the largest key <= the specified key. * @param T - The type of the preimage (PublicData or Nullifier) * @returns [ - * GetLeafResult | undefined - The leaf or low leaf info (preimage & leaf index), + * preimageWitness | undefined - The leaf or low leaf info (preimage & leaf index), * pathAbsentInEphemeralTree - whether its sibling path is absent in the ephemeral tree (useful during insertions) * ] * @@ -506,10 +497,10 @@ export class AvmEphemeralForest { key: bigint, minPreimage: T, minIndex: bigint, - ): Promise<[GetLeafResult | undefined, /*pathAbsentInEphemeralTree=*/ boolean]> { + ): Promise<[PreimageWitness | undefined, /*pathAbsentInEphemeralTree=*/ boolean]> { let found = false; let curr = minPreimage as T; - let result: GetLeafResult | undefined = undefined; + let result: PreimageWitness | undefined = undefined; // Temp to avoid infinite loops - the limit is the number of leaves we may have to read const LIMIT = 2n ** BigInt(getTreeHeight(treeId)) - 1n; let counter = 0n; @@ -520,11 +511,11 @@ export class AvmEphemeralForest { if (curr.getKey() === bigIntKey) { // We found an exact match - therefore this is an update found = true; - result = { preimage: curr, index: lowPublicDataIndex, alreadyPresent: true }; + result = { preimage: curr, index: lowPublicDataIndex, update: true }; } else if (curr.getKey() < bigIntKey && (curr.getNextIndex() === 0n || curr.getNextKey() > bigIntKey)) { // We found it via sandwich or max condition, this is a low nullifier found = true; - result = { preimage: curr, index: lowPublicDataIndex, alreadyPresent: false }; + result = { preimage: curr, index: lowPublicDataIndex, update: false }; } // Update the the values for the next iteration else { diff --git a/yarn-project/simulator/src/avm/journal/journal.ts b/yarn-project/simulator/src/avm/journal/journal.ts index 63dbf59f09e..9a3ffa5273a 100644 --- a/yarn-project/simulator/src/avm/journal/journal.ts +++ b/yarn-project/simulator/src/avm/journal/journal.ts @@ -163,12 +163,8 @@ export class AvmPersistableStateManager { const lowLeafIndex = lowLeafInfo.index; const lowLeafPath = lowLeafInfo.siblingPath; - const newLeafPreimage = result.element as PublicDataTreeLeafPreimage; - let insertionPath; - - if (!result.update) { - insertionPath = result.insertionPath; - } + const insertionPath = result.insertionPath; + const newLeafPreimage = result.newOrElementToUpdate.element as PublicDataTreeLeafPreimage; this.trace.tracePublicStorageWrite( contractAddress, @@ -204,7 +200,7 @@ export class AvmPersistableStateManager { const { preimage, index: leafIndex, - alreadyPresent, + update: exists, } = await this.merkleTrees.getLeafOrLowLeafInfo(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot); // The index and preimage here is either the low leaf or the leaf itself (depending on the value of update flag) // In either case, we just want the sibling path to this leaf - it's up to the avm to distinguish if it's a low leaf or not @@ -216,7 +212,7 @@ export class AvmPersistableStateManager { ); this.log.debug(`leafPreimage.slot: ${leafPreimage.slot}, leafPreimage.value: ${leafPreimage.value}`); - if (!alreadyPresent) { + if (!exists) { // Sanity check that the leaf slot is skipped by low leaf when it doesn't exist assert( leafPreimage.slot.toBigInt() < leafSlot.toBigInt() && @@ -312,15 +308,12 @@ export class AvmPersistableStateManager { const { preimage, index: leafIndex, - alreadyPresent, + update, } = await this.merkleTrees.getLeafOrLowLeafInfo(MerkleTreeId.NULLIFIER_TREE, siloedNullifier); const leafPreimage = preimage as NullifierLeafPreimage; const leafPath = await this.merkleTrees.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, leafIndex); - assert( - alreadyPresent == exists, - 'WorldStateDB contains nullifier leaf, but merkle tree does not.... This is a bug!', - ); + assert(update == exists, 'WorldStateDB contains nullifier leaf, but merkle tree does not.... This is a bug!'); if (exists) { this.log.debug(`Siloed nullifier ${siloedNullifier} exists at leafIndex=${leafIndex}`); @@ -362,11 +355,11 @@ export class AvmPersistableStateManager { // Maybe overkill, but we should check if the nullifier is already present in the tree before attempting to insert // It might be better to catch the error from the insert operation // Trace all nullifier creations, even duplicate insertions that fail - const { preimage, index, alreadyPresent } = await this.merkleTrees.getLeafOrLowLeafInfo( + const { preimage, index, update } = await this.merkleTrees.getLeafOrLowLeafInfo( MerkleTreeId.NULLIFIER_TREE, siloedNullifier, ); - if (alreadyPresent) { + if (update) { this.log.verbose(`Siloed nullifier ${siloedNullifier} already present in tree at index ${index}!`); // If the nullifier is already present, we should not insert it again // instead we provide the direct membership path @@ -374,7 +367,7 @@ export class AvmPersistableStateManager { // This just becomes a nullifier read hint this.trace.traceNullifierCheck( siloedNullifier, - /*exists=*/ alreadyPresent, + /*exists=*/ update, preimage as NullifierLeafPreimage, new Fr(index), path, diff --git a/yarn-project/simulator/src/client/client_execution_context.ts b/yarn-project/simulator/src/client/client_execution_context.ts index c933b4caeba..0d7b8d4a122 100644 --- a/yarn-project/simulator/src/client/client_execution_context.ts +++ b/yarn-project/simulator/src/client/client_execution_context.ts @@ -1,11 +1,8 @@ import { type AuthWitness, type AztecNode, - CountedLog, - CountedNoteLog, + CountedContractClassLog, CountedPublicExecutionRequest, - EncryptedL2Log, - EncryptedL2NoteLog, Note, NoteAndSlot, type NoteStatus, @@ -25,7 +22,6 @@ import { import { computeUniqueNoteHash, siloNoteHash } from '@aztec/circuits.js/hash'; import { type FunctionAbi, type FunctionArtifact, type NoteSelector, countArgumentsSize } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; import { applyStringFormatting, createDebugLogger } from '@aztec/foundation/log'; @@ -60,9 +56,7 @@ export class ClientExecutionContext extends ViewDataOracle { */ private noteHashLeafIndexMap: Map = new Map(); private noteHashNullifierCounterMap: Map = new Map(); - private noteEncryptedLogs: CountedNoteLog[] = []; - private encryptedLogs: CountedLog[] = []; - private contractClassLogs: CountedLog[] = []; + private contractClassLogs: CountedContractClassLog[] = []; private nestedExecutions: PrivateExecutionResult[] = []; private enqueuedPublicFunctionCalls: CountedPublicExecutionRequest[] = []; private publicTeardownFunctionCall: PublicExecutionRequest = PublicExecutionRequest.empty(); @@ -136,20 +130,6 @@ export class ClientExecutionContext extends ViewDataOracle { return this.noteHashNullifierCounterMap; } - /** - * Return the note encrypted logs emitted during this execution. - */ - public getNoteEncryptedLogs() { - return this.noteEncryptedLogs; - } - - /** - * Return the encrypted logs emitted during this execution. - */ - public getEncryptedLogs() { - return this.encryptedLogs; - } - /** * Return the contract class logs emitted during this execution. */ @@ -326,49 +306,15 @@ export class ClientExecutionContext extends ViewDataOracle { return Promise.resolve(); } - /** - * Emit encrypted data - * @param contractAddress - The contract emitting the encrypted event. - * @param randomness - A value used to mask the contract address we are siloing with. - * @param encryptedEvent - The encrypted event data. - * @param counter - The effects counter. - */ - public override emitEncryptedEventLog( - contractAddress: AztecAddress, - randomness: Fr, - encryptedEvent: Buffer, - counter: number, - ) { - // In some cases, we actually want to reveal the contract address we are siloing with: - // e.g. 'handshaking' contract w/ known address - // An app providing randomness = 0 signals to not mask the address. - const maskedContractAddress = randomness.isZero() - ? contractAddress.toField() - : poseidon2HashWithSeparator([contractAddress, randomness], 0); - const encryptedLog = new CountedLog(new EncryptedL2Log(encryptedEvent, maskedContractAddress), counter); - this.encryptedLogs.push(encryptedLog); - } - - /** - * Emit encrypted note data - * @param noteHashCounter - The note hash counter. - * @param encryptedNote - The encrypted note data. - * @param counter - The log counter. - */ - public override emitEncryptedNoteLog(noteHashCounter: number, encryptedNote: Buffer, counter: number) { - const encryptedLog = new CountedNoteLog(new EncryptedL2NoteLog(encryptedNote), counter, noteHashCounter); - this.noteEncryptedLogs.push(encryptedLog); - } - /** * Emit a contract class unencrypted log. - * This fn exists separately from emitUnencryptedLog because sha hashing the preimage + * This fn exists because sha hashing the preimage * is too large to compile (16,200 fields, 518,400 bytes) => the oracle hashes it. * See private_context.nr * @param log - The unencrypted log to be emitted. */ public override emitContractClassLog(log: UnencryptedL2Log, counter: number) { - this.contractClassLogs.push(new CountedLog(log, counter)); + this.contractClassLogs.push(new CountedContractClassLog(log, counter)); const text = log.toHumanReadable(); this.log.verbose( `Emitted log from ContractClassRegisterer: "${text.length > 100 ? text.slice(0, 100) + '...' : text}"`, @@ -381,7 +327,7 @@ export class ClientExecutionContext extends ViewDataOracle { childExecutionResult.publicInputs.noteHashes.some(item => !item.isEmpty()) || childExecutionResult.publicInputs.nullifiers.some(item => !item.isEmpty()) || childExecutionResult.publicInputs.l2ToL1Msgs.some(item => !item.isEmpty()) || - childExecutionResult.publicInputs.encryptedLogsHashes.some(item => !item.isEmpty()) || + childExecutionResult.publicInputs.privateLogs.some(item => !item.isEmpty()) || childExecutionResult.publicInputs.contractClassLogsHashes.some(item => !item.isEmpty()) ) { throw new Error(`Static call cannot update the state, emit L2->L1 messages or generate logs`); diff --git a/yarn-project/simulator/src/client/private_execution.test.ts b/yarn-project/simulator/src/client/private_execution.test.ts index 3b3b7a039e5..815f48c36bb 100644 --- a/yarn-project/simulator/src/client/private_execution.test.ts +++ b/yarn-project/simulator/src/client/private_execution.test.ts @@ -1,15 +1,12 @@ import { type AztecNode, CountedPublicExecutionRequest, - EncryptedNoteFunctionL2Logs, type L1ToL2Message, type L2BlockNumber, Note, PackedValues, - type PrivateExecutionResult, PublicExecutionRequest, TxExecutionRequest, - collectSortedEncryptedLogs, } from '@aztec/circuit-types'; import { AppendOnlyTreeSnapshot, @@ -186,11 +183,6 @@ describe('Private Execution test suite', () => { return trees[name]; }; - const getEncryptedNoteSerializedLength = (result: PrivateExecutionResult) => { - const fnLogs = new EncryptedNoteFunctionL2Logs(result.noteEncryptedLogs.map(l => l.log)); - return fnLogs.getKernelLength(); - }; - beforeAll(() => { logger = createDebugLogger('aztec:test:private_execution'); @@ -288,21 +280,8 @@ describe('Private Execution test suite', () => { const args = [times(5, () => Fr.random()), owner, outgoingViewer, false]; const result = await runSimulator({ artifact, msgSender: owner, args }); - const newEncryptedLogs = getNonEmptyItems(result.publicInputs.encryptedLogsHashes); - expect(newEncryptedLogs).toHaveLength(1); - const functionLogs = collectSortedEncryptedLogs(result); - expect(functionLogs.logs).toHaveLength(1); - - const [encryptedLog] = newEncryptedLogs; - expect(encryptedLog.value).toEqual(Fr.fromBuffer(functionLogs.logs[0].hash())); - expect(encryptedLog.length).toEqual(new Fr(functionLogs.getKernelLength())); - // 5 is hardcoded in the test contract - expect(encryptedLog.randomness).toEqual(new Fr(5)); - const expectedMaskedAddress = poseidon2HashWithSeparator( - [result.publicInputs.callContext.contractAddress, new Fr(5)], - 0, - ); - expect(expectedMaskedAddress).toEqual(functionLogs.logs[0].maskedContractAddress); + const privateLogs = getNonEmptyItems(result.publicInputs.privateLogs); + expect(privateLogs).toHaveLength(1); }); }); @@ -368,13 +347,8 @@ describe('Private Execution test suite', () => { await acirSimulator.computeNoteHash(contractAddress, newNote.storageSlot, newNote.noteTypeId, newNote.note), ); - const newEncryptedLogs = getNonEmptyItems(result.publicInputs.noteEncryptedLogsHashes); - expect(newEncryptedLogs).toHaveLength(1); - - const [encryptedLog] = newEncryptedLogs; - expect(encryptedLog.noteHashCounter).toEqual(noteHashes[0].counter); - expect(encryptedLog.value).toEqual(Fr.fromBuffer(result.noteEncryptedLogs[0].log.hash())); - expect(encryptedLog.length).toEqual(new Fr(getEncryptedNoteSerializedLength(result))); + const privateLogs = getNonEmptyItems(result.publicInputs.privateLogs); + expect(privateLogs).toHaveLength(1); }); it('should run the create_note function', async () => { @@ -393,13 +367,8 @@ describe('Private Execution test suite', () => { await acirSimulator.computeNoteHash(contractAddress, newNote.storageSlot, newNote.noteTypeId, newNote.note), ); - const newEncryptedLogs = getNonEmptyItems(result.publicInputs.noteEncryptedLogsHashes); - expect(newEncryptedLogs).toHaveLength(1); - - const [encryptedLog] = newEncryptedLogs; - expect(encryptedLog.noteHashCounter).toEqual(noteHashes[0].counter); - expect(encryptedLog.value).toEqual(Fr.fromBuffer(result.noteEncryptedLogs[0].log.hash())); - expect(encryptedLog.length).toEqual(new Fr(getEncryptedNoteSerializedLength(result))); + const privateLogs = getNonEmptyItems(result.publicInputs.privateLogs); + expect(privateLogs).toHaveLength(1); }); it('should run the destroy_and_create function', async () => { @@ -458,17 +427,8 @@ describe('Private Execution test suite', () => { expect(recipientNote.note.items[0]).toEqual(new Fr(amountToTransfer)); expect(changeNote.note.items[0]).toEqual(new Fr(40n)); - const newEncryptedLogs = getNonEmptyItems(result.publicInputs.noteEncryptedLogsHashes); - expect(newEncryptedLogs).toHaveLength(2); - - const [encryptedChangeLog, encryptedRecipientLog] = newEncryptedLogs; - expect(encryptedChangeLog.value).toEqual(Fr.fromBuffer(result.noteEncryptedLogs[0].log.hash())); - expect(encryptedChangeLog.noteHashCounter).toEqual(changeNoteHash.counter); - expect(encryptedRecipientLog.value).toEqual(Fr.fromBuffer(result.noteEncryptedLogs[1].log.hash())); - expect(encryptedRecipientLog.noteHashCounter).toEqual(recipientNoteHash.counter); - expect(encryptedChangeLog.length.add(encryptedRecipientLog.length)).toEqual( - new Fr(getEncryptedNoteSerializedLength(result)), - ); + const privateLogs = getNonEmptyItems(result.publicInputs.privateLogs); + expect(privateLogs).toHaveLength(2); const readRequests = getNonEmptyItems(result.publicInputs.noteHashReadRequests).map(r => r.value); expect(readRequests).toHaveLength(consumedNotes.length); @@ -510,16 +470,8 @@ describe('Private Execution test suite', () => { expect(recipientNote.note.items[0]).toEqual(new Fr(amountToTransfer)); expect(changeNote.note.items[0]).toEqual(new Fr(balance - amountToTransfer)); - const newEncryptedLogs = getNonEmptyItems(result.publicInputs.noteEncryptedLogsHashes); - expect(newEncryptedLogs).toHaveLength(2); - const [encryptedChangeLog, encryptedRecipientLog] = newEncryptedLogs; - expect(encryptedChangeLog.value).toEqual(Fr.fromBuffer(result.noteEncryptedLogs[0].log.hash())); - expect(encryptedChangeLog.noteHashCounter).toEqual(result.publicInputs.noteHashes[0].counter); - expect(encryptedRecipientLog.value).toEqual(Fr.fromBuffer(result.noteEncryptedLogs[1].log.hash())); - expect(encryptedRecipientLog.noteHashCounter).toEqual(result.publicInputs.noteHashes[1].counter); - expect(encryptedChangeLog.length.add(encryptedRecipientLog.length)).toEqual( - new Fr(getEncryptedNoteSerializedLength(result)), - ); + const privateLogs = getNonEmptyItems(result.publicInputs.privateLogs); + expect(privateLogs).toHaveLength(2); }); }); @@ -963,13 +915,8 @@ describe('Private Execution test suite', () => { ); expect(noteHashFromCall).toEqual(derivedNoteHash); - const newEncryptedLogs = getNonEmptyItems(result.publicInputs.noteEncryptedLogsHashes); - expect(newEncryptedLogs).toHaveLength(1); - - const [encryptedLog] = newEncryptedLogs; - expect(encryptedLog.noteHashCounter).toEqual(noteHashesFromCall[0].counter); - expect(encryptedLog.noteHashCounter).toEqual(result.noteEncryptedLogs[0].noteHashCounter); - expect(encryptedLog.value).toEqual(Fr.fromBuffer(result.noteEncryptedLogs[0].log.hash())); + const privateLogs = getNonEmptyItems(result.publicInputs.privateLogs); + expect(privateLogs).toHaveLength(1); // read request should match a note hash for pending notes (there is no nonce, so can't compute "unique" hash) const readRequest = getNonEmptyItems(result.publicInputs.noteHashReadRequests)[0]; @@ -1047,13 +994,8 @@ describe('Private Execution test suite', () => { ); expect(noteHashes[0].value).toEqual(derivedNoteHash); - const newEncryptedLogs = getNonEmptyItems(execInsert.publicInputs.noteEncryptedLogsHashes); - expect(newEncryptedLogs).toHaveLength(1); - - const [encryptedLog] = newEncryptedLogs; - expect(encryptedLog.noteHashCounter).toEqual(noteHashes[0].counter); - expect(encryptedLog.noteHashCounter).toEqual(execInsert.noteEncryptedLogs[0].noteHashCounter); - expect(encryptedLog.value).toEqual(Fr.fromBuffer(execInsert.noteEncryptedLogs[0].log.hash())); + const privateLogs = getNonEmptyItems(execInsert.publicInputs.privateLogs); + expect(privateLogs).toHaveLength(1); // read request should match a note hash for pending notes (there is no nonce, so can't compute "unique" hash) const readRequest = execGetThenNullify.publicInputs.noteHashReadRequests[0]; diff --git a/yarn-project/simulator/src/client/private_execution.ts b/yarn-project/simulator/src/client/private_execution.ts index 2e71194575f..ed25d5bf4c0 100644 --- a/yarn-project/simulator/src/client/private_execution.ts +++ b/yarn-project/simulator/src/client/private_execution.ts @@ -59,8 +59,6 @@ export async function executePrivateFunction( appCircuitName: functionName, } satisfies CircuitWitnessGenerationStats); - const noteEncryptedLogs = context.getNoteEncryptedLogs(); - const encryptedLogs = context.getEncryptedLogs(); const contractClassLogs = context.getContractClassLogs(); const rawReturnValues = await context.unpackReturns(publicInputs.returnsHash); @@ -86,8 +84,6 @@ export async function executePrivateFunction( nestedExecutions, enqueuedPublicFunctionCalls, publicTeardownFunctionCall, - noteEncryptedLogs, - encryptedLogs, contractClassLogs, ); } diff --git a/yarn-project/simulator/src/public/public_db_sources.ts b/yarn-project/simulator/src/public/public_db_sources.ts index 2984835828b..27177b3b919 100644 --- a/yarn-project/simulator/src/public/public_db_sources.ts +++ b/yarn-project/simulator/src/public/public_db_sources.ts @@ -9,9 +9,7 @@ import { type PublicDBAccessStats } from '@aztec/circuit-types/stats'; import { type AztecAddress, type ContractClassPublic, - ContractClassRegisteredEvent, type ContractDataSource, - ContractInstanceDeployedEvent, type ContractInstanceWithAddress, Fr, type FunctionSelector, @@ -24,7 +22,7 @@ import { import { computeL1ToL2MessageNullifier, computePublicDataTreeLeafSlot } from '@aztec/circuits.js/hash'; import { createDebugLogger } from '@aztec/foundation/log'; import { Timer } from '@aztec/foundation/timer'; -import { ProtocolContractAddress } from '@aztec/protocol-contracts'; +import { ContractClassRegisteredEvent, ContractInstanceDeployedEvent } from '@aztec/protocol-contracts'; import { type CommitmentsDB, MessageLoadOracleInputs, @@ -51,13 +49,20 @@ export class ContractsDataSourcePublicDB implements PublicContractsDB { public addNewContracts(tx: Tx): Promise { // Extract contract class and instance data from logs and add to cache for this block const logs = tx.contractClassLogs.unrollLogs(); - ContractClassRegisteredEvent.fromLogs(logs, ProtocolContractAddress.ContractClassRegisterer).forEach(e => { - this.log.debug(`Adding class ${e.contractClassId.toString()} to public execution contract cache`); - this.classCache.set(e.contractClassId.toString(), e.toContractClassPublic()); - }); - // We store the contract instance deployed event log in enc logs, contract_instance_deployer_contract/src/main.nr - const encLogs = tx.encryptedLogs.unrollLogs(); - ContractInstanceDeployedEvent.fromLogs(encLogs).forEach(e => { + logs + .filter(log => ContractClassRegisteredEvent.isContractClassRegisteredEvent(log.data)) + .forEach(log => { + const event = ContractClassRegisteredEvent.fromLog(log.data); + this.log.debug(`Adding class ${event.contractClassId.toString()} to public execution contract cache`); + this.classCache.set(event.contractClassId.toString(), event.toContractClassPublic()); + }); + + // We store the contract instance deployed event log in private logs, contract_instance_deployer_contract/src/main.nr + const contractInstanceEvents = tx.data + .getNonEmptyPrivateLogs() + .filter(log => ContractInstanceDeployedEvent.isContractInstanceDeployedEvent(log)) + .map(ContractInstanceDeployedEvent.fromLog); + contractInstanceEvents.forEach(e => { this.log.debug( `Adding instance ${e.address.toString()} with class ${e.contractClassId.toString()} to public execution contract cache`, ); @@ -76,12 +81,20 @@ export class ContractsDataSourcePublicDB implements PublicContractsDB { // Let's say we have two txs adding the same contract on the same block. If the 2nd one reverts, // wouldn't that accidentally remove the contract added on the first one? const logs = tx.contractClassLogs.unrollLogs(); - ContractClassRegisteredEvent.fromLogs(logs, ProtocolContractAddress.ContractClassRegisterer).forEach(e => - this.classCache.delete(e.contractClassId.toString()), - ); - // We store the contract instance deployed event log in enc logs, contract_instance_deployer_contract/src/main.nr - const encLogs = tx.encryptedLogs.unrollLogs(); - ContractInstanceDeployedEvent.fromLogs(encLogs).forEach(e => this.instanceCache.delete(e.address.toString())); + logs + .filter(log => ContractClassRegisteredEvent.isContractClassRegisteredEvent(log.data)) + .forEach(log => { + const event = ContractClassRegisteredEvent.fromLog(log.data); + this.classCache.delete(event.contractClassId.toString()); + }); + + // We store the contract instance deployed event log in private logs, contract_instance_deployer_contract/src/main.nr + const contractInstanceEvents = tx.data + .getNonEmptyPrivateLogs() + .filter(log => ContractInstanceDeployedEvent.isContractInstanceDeployedEvent(log)) + .map(ContractInstanceDeployedEvent.fromLog); + contractInstanceEvents.forEach(e => this.instanceCache.delete(e.address.toString())); + return Promise.resolve(); } diff --git a/yarn-project/simulator/src/public/public_processor.ts b/yarn-project/simulator/src/public/public_processor.ts index 23e33b9ee2f..d6ba69c8302 100644 --- a/yarn-project/simulator/src/public/public_processor.ts +++ b/yarn-project/simulator/src/public/public_processor.ts @@ -13,7 +13,6 @@ import { } from '@aztec/circuit-types'; import { type AztecAddress, - ContractClassRegisteredEvent, type ContractDataSource, Fr, type GlobalVariables, @@ -26,7 +25,7 @@ import { import { padArrayEnd } from '@aztec/foundation/collection'; import { createDebugLogger } from '@aztec/foundation/log'; import { Timer } from '@aztec/foundation/timer'; -import { ProtocolContractAddress } from '@aztec/protocol-contracts'; +import { ContractClassRegisteredEvent, ProtocolContractAddress } from '@aztec/protocol-contracts'; import { Attributes, type TelemetryClient, type Tracer, trackSpan } from '@aztec/telemetry-client'; import { computeFeePayerBalanceLeafSlot, computeFeePayerBalanceStorageSlot } from './fee_payment.js'; @@ -275,10 +274,10 @@ export class PublicProcessor { }); this.metrics.recordClassRegistration( - ...ContractClassRegisteredEvent.fromLogs( - tx.contractClassLogs.unrollLogs(), - ProtocolContractAddress.ContractClassRegisterer, - ), + ...tx.contractClassLogs + .unrollLogs() + .filter(log => ContractClassRegisteredEvent.isContractClassRegisteredEvent(log.data)) + .map(log => ContractClassRegisteredEvent.fromLog(log.data)), ); const phaseCount = processedPhases.length; diff --git a/yarn-project/simulator/src/public/public_processor_metrics.ts b/yarn-project/simulator/src/public/public_processor_metrics.ts index ff54a7d152d..ccc1ee9daad 100644 --- a/yarn-project/simulator/src/public/public_processor_metrics.ts +++ b/yarn-project/simulator/src/public/public_processor_metrics.ts @@ -1,5 +1,5 @@ import { type TxExecutionPhase } from '@aztec/circuit-types'; -import { type ContractClassRegisteredEvent } from '@aztec/circuits.js'; +import { type ContractClassRegisteredEvent } from '@aztec/protocol-contracts'; import { Attributes, type Histogram, diff --git a/yarn-project/txe/src/oracle/txe_oracle.ts b/yarn-project/txe/src/oracle/txe_oracle.ts index 670bf6b1b77..e9c6d1c01c9 100644 --- a/yarn-project/txe/src/oracle/txe_oracle.ts +++ b/yarn-project/txe/src/oracle/txe_oracle.ts @@ -1,6 +1,5 @@ import { AuthWitness, - type EncryptedL2NoteLog, MerkleTreeId, Note, type NoteStatus, @@ -95,8 +94,6 @@ export class TXE implements TypedOracle { private version: Fr = Fr.ONE; private chainId: Fr = Fr.ONE; - private logsByTags = new Map(); - constructor( private logger: Logger, private trees: MerkleTrees, @@ -509,21 +506,6 @@ export class TXE implements TypedOracle { return publicDataWrites.map(write => write.value); } - emitEncryptedLog(_contractAddress: AztecAddress, _randomness: Fr, _encryptedNote: Buffer, counter: number): void { - this.sideEffectCounter = counter + 1; - return; - } - - emitEncryptedNoteLog(_noteHashCounter: number, _encryptedNote: Buffer, counter: number): void { - this.sideEffectCounter = counter + 1; - return; - } - - emitUnencryptedLog(_log: UnencryptedL2Log, counter: number): void { - this.sideEffectCounter = counter + 1; - return; - } - emitContractClassLog(_log: UnencryptedL2Log, _counter: number): Fr { throw new Error('Method not implemented.'); } @@ -762,16 +744,6 @@ export class TXE implements TypedOracle { this.logger.verbose(`debug_log ${applyStringFormatting(message, fields)}`); } - emitEncryptedEventLog( - _contractAddress: AztecAddress, - _randomness: Fr, - _encryptedEvent: Buffer, - counter: number, - ): void { - this.sideEffectCounter = counter + 1; - return; - } - async incrementAppTaggingSecretIndexAsSender(sender: AztecAddress, recipient: AztecAddress): Promise { const appSecret = await this.#calculateTaggingSecret(this.contractAddress, sender, recipient); const [index] = await this.txeDatabase.getTaggingSecretsIndexesAsSender([appSecret]); diff --git a/yarn-project/txe/src/txe_service/txe_service.ts b/yarn-project/txe/src/txe_service/txe_service.ts index 5c7cb4d6c60..1fdaee4d635 100644 --- a/yarn-project/txe/src/txe_service/txe_service.ts +++ b/yarn-project/txe/src/txe_service/txe_service.ts @@ -459,30 +459,6 @@ export class TXEService { return toForeignCallResult([toArray(keyValidationRequest.toFields())]); } - emitEncryptedLog( - _contractAddress: ForeignCallSingle, - _randomness: ForeignCallSingle, - _encryptedLog: ForeignCallSingle, - _counter: ForeignCallSingle, - ) { - // TODO(#8811): Implement - return toForeignCallResult([]); - } - - emitEncryptedNoteLog( - _noteHashCounter: ForeignCallSingle, - _encryptedNote: ForeignCallArray, - _counter: ForeignCallSingle, - ) { - // TODO(#8811): Implement - return toForeignCallResult([]); - } - - emitEncryptedEventLog(_contractAddress: AztecAddress, _randomness: Fr, _encryptedEvent: Buffer, _counter: number) { - // TODO(#8811): Implement - return toForeignCallResult([]); - } - async callPrivateFunction( targetContractAddress: ForeignCallSingle, functionSelector: ForeignCallSingle, @@ -595,11 +571,6 @@ export class TXEService { return toForeignCallResult([toArray(witness)]); } - emitUnencryptedLog(_contractAddress: ForeignCallSingle, _message: ForeignCallArray, _counter: ForeignCallSingle) { - // TODO(#8811): Implement - return toForeignCallResult([]); - } - async getAppTaggingSecretAsSender(sender: ForeignCallSingle, recipient: ForeignCallSingle) { const secret = await this.typedOracle.getAppTaggingSecretAsSender( AztecAddress.fromField(fromSingle(sender)), diff --git a/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.test.ts b/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.test.ts index 08023782278..a8840645fc9 100644 --- a/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.test.ts +++ b/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.test.ts @@ -89,7 +89,7 @@ describe('ServerWorldStateSynchronizer', () => { const pushBlocks = async (from: number, to: number) => { await server.handleBlockStreamEvent({ type: 'blocks-added', - blocks: times(to - from + 1, i => L2Block.random(i + from, 4, 2, 3, 2, 1, inHash)), + blocks: times(to - from + 1, i => L2Block.random(i + from, 4, 3, 1, inHash)), }); server.latest.number = to; }; diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index f12b77c3c63..cea030422b8 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -416,11 +416,9 @@ __metadata: "@aztec/types": "workspace:^" "@jest/globals": ^29.5.0 "@types/jest": ^29.5.0 - "@types/lodash.chunk": ^4.2.7 "@types/node": ^18.7.23 eslint: ^8.35.0 jest: ^29.5.0 - lodash.chunk: ^4.2.0 prettier: ^2.8.4 ts-node: ^10.9.1 tslib: ^2.4.0 @@ -959,10 +957,12 @@ __metadata: "@aztec/types": "workspace:^" "@jest/globals": ^29.5.0 "@types/jest": ^29.5.0 + "@types/lodash.chunk": ^4.2.9 "@types/lodash.omit": ^4.5.9 "@types/node": ^18.7.23 jest: ^29.5.0 jest-mock-extended: ^3.0.3 + lodash.chunk: ^4.2.0 lodash.omit: ^4.5.0 ts-loader: ^9.4.4 ts-node: ^10.9.1