diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index 0e095c7335c..2fff232d55a 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 = 64; 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 = 1476; 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 = 2084; + uint256 internal constant PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 2898; + uint256 internal constant PRIVATE_TO_PUBLIC_ACCUMULATED_DATA_LENGTH = 1476; 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 = 2997; + uint256 internal constant KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1532; 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 = 36864; 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..63cb16fbf83 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"0014a1509239adce426ae94248ef0db28299cd8694dfb0b515498b508d794eb8"; } } 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..27af49fca3c 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": "0x04a62f6cd634f15dc4f6f448b1c3add589a71ab829a019d5e8c8c3d7b87a45e9", + "blockHash": "0x17c125a56cdcdfa66d75c4856167512e05caa58fca0e74709c9c0c65c17c3579", "body": "0x00000000", - "txsEffectsHash": "0x002dcd61493c9a7f3ce4605573ee657e6ced4a3dd10bfb216f44a796b3d585c9", + "txsEffectsHash": "0x00dec8a17682b92c34894c7a164a7cb1138217b531b8ee34ed7169f2261a2113", "decodedHeader": { "contentCommitment": { "inHash": "0x00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c", "outHash": "0x00f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb", "numTxs": 2, - "txsEffectsHash": "0x002dcd61493c9a7f3ce4605573ee657e6ced4a3dd10bfb216f44a796b3d585c9" + "txsEffectsHash": "0x00dec8a17682b92c34894c7a164a7cb1138217b531b8ee34ed7169f2261a2113" }, "globalVariables": { "blockNumber": 1, "slotNumber": "0x0000000000000000000000000000000000000000000000000000000000000012", "chainId": 31337, - "timestamp": 1732579818, + "timestamp": 1732722455, "version": 1, - "coinbase": "0xbebcbac2f24abc01241a668cca41d0659589499e", - "feeRecipient": "0x1fb24139a0110fb00ebdcf0b6667bdd95c82ede876a1d34fb8cef074eae1db2c", + "coinbase": "0xcb481cb0dab10d427667aa7f967ebaa5b4d3a9dd", + "feeRecipient": "0x21d0bbacc6d29b0dbbcf30a87b386e044df6a2c58142e2affdefc5e3c4802d7c", "gasFees": { "feePerDaGas": 0, - "feePerL2Gas": 54153599320 + "feePerL2Gas": 54153582330 } }, "totalFees": "0x0000000000000000000000000000000000000000000000000000000000000000", @@ -59,8 +59,8 @@ } } }, - "header": "0x0237797d6a2c04d20d4fa06b74482bd970ccd51a43d9b05b57e9b91fa1ae1cae000000010000000000000000000000000000000000000000000000000000000000000002002dcd61493c9a7f3ce4605573ee657e6ced4a3dd10bfb216f44a796b3d585c900089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c00f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb2e33ee2008411c04b99c24b313513d097a0d21a5040b6193d1f978b8226892d6000000101fd848aa69e1633722fe249a5b7f53b094f1c9cef9f5c694b073fd1cc5850dfb000000800c499b373a1f0fe1b510a63563546d2d39e206895056a5af0143c5f30d6390730000010023c08a6b1297210c5e24c76b9a936250a1ce2721576c26ea797c7ec35f9e46a9000000800000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000674511eabebcbac2f24abc01241a668cca41d0659589499e1fb24139a0110fb00ebdcf0b6667bdd95c82ede876a1d34fb8cef074eae1db2c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c9bce595800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x00f5efb7d5e53918275f835f7103b62acc1d37c11bbf27e0482680f107fc01d4", + "header": "0x0237797d6a2c04d20d4fa06b74482bd970ccd51a43d9b05b57e9b91fa1ae1cae00000001000000000000000000000000000000000000000000000000000000000000000200dec8a17682b92c34894c7a164a7cb1138217b531b8ee34ed7169f2261a211300089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c00f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb2e33ee2008411c04b99c24b313513d097a0d21a5040b6193d1f978b8226892d6000000101fd848aa69e1633722fe249a5b7f53b094f1c9cef9f5c694b073fd1cc5850dfb000000800c499b373a1f0fe1b510a63563546d2d39e206895056a5af0143c5f30d6390730000010023c08a6b1297210c5e24c76b9a936250a1ce2721576c26ea797c7ec35f9e46a9000000800000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000067473f17cb481cb0dab10d427667aa7f967ebaa5b4d3a9dd21d0bbacc6d29b0dbbcf30a87b386e044df6a2c58142e2affdefc5e3c4802d7c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c9bce16fa00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x00e98bcbe4ef4803f5366a490065d8736e4bcbe93bf762e5bda83301e1a40a51", "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..1fb4048755c 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": "0x0d41c23f368f0de16ec6a28314d74dfdc9ca334524673e7534b0436696305729", + "blockHash": "0x1af3332127715ac6ed09f8e47835c2e400d84e4b778bf28376a4893ae89b5cfe", "body": "0x00000000", - "txsEffectsHash": "0x002dcd61493c9a7f3ce4605573ee657e6ced4a3dd10bfb216f44a796b3d585c9", + "txsEffectsHash": "0x00dec8a17682b92c34894c7a164a7cb1138217b531b8ee34ed7169f2261a2113", "decodedHeader": { "contentCommitment": { "inHash": "0x00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c", "outHash": "0x00f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb", "numTxs": 2, - "txsEffectsHash": "0x002dcd61493c9a7f3ce4605573ee657e6ced4a3dd10bfb216f44a796b3d585c9" + "txsEffectsHash": "0x00dec8a17682b92c34894c7a164a7cb1138217b531b8ee34ed7169f2261a2113" }, "globalVariables": { "blockNumber": 2, "slotNumber": "0x0000000000000000000000000000000000000000000000000000000000000013", "chainId": 31337, - "timestamp": 1732579842, + "timestamp": 1732722479, "version": 1, - "coinbase": "0xbebcbac2f24abc01241a668cca41d0659589499e", - "feeRecipient": "0x1fb24139a0110fb00ebdcf0b6667bdd95c82ede876a1d34fb8cef074eae1db2c", + "coinbase": "0xcb481cb0dab10d427667aa7f967ebaa5b4d3a9dd", + "feeRecipient": "0x21d0bbacc6d29b0dbbcf30a87b386e044df6a2c58142e2affdefc5e3c4802d7c", "gasFees": { "feePerDaGas": 0, - "feePerL2Gas": 54153599320 + "feePerL2Gas": 54153582330 } }, "totalFees": "0x0000000000000000000000000000000000000000000000000000000000000000", "totalManaUsed": "0x0000000000000000000000000000000000000000000000000000000000000000", "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x14cc4063ccae0d809992631edee86e43cd48aa4465598e54e05f4c91fc7cf9dc" + "root": "0x04a62f6cd634f15dc4f6f448b1c3add589a71ab829a019d5e8c8c3d7b87a45e9" }, "stateReference": { "l1ToL2MessageTree": { @@ -59,8 +59,8 @@ } } }, - "header": "0x14cc4063ccae0d809992631edee86e43cd48aa4465598e54e05f4c91fc7cf9dc000000020000000000000000000000000000000000000000000000000000000000000002002dcd61493c9a7f3ce4605573ee657e6ced4a3dd10bfb216f44a796b3d585c900089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c00f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb2e33ee2008411c04b99c24b313513d097a0d21a5040b6193d1f978b8226892d6000000201fd848aa69e1633722fe249a5b7f53b094f1c9cef9f5c694b073fd1cc5850dfb000001000c499b373a1f0fe1b510a63563546d2d39e206895056a5af0143c5f30d6390730000018023c08a6b1297210c5e24c76b9a936250a1ce2721576c26ea797c7ec35f9e46a9000000800000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000067451202bebcbac2f24abc01241a668cca41d0659589499e1fb24139a0110fb00ebdcf0b6667bdd95c82ede876a1d34fb8cef074eae1db2c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c9bce595800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x004cab0bf8cace3c6a6b2506f12a17d5f1ccaf63db14d8f6e67b3fea6d34fc3d", + "header": "0x04a62f6cd634f15dc4f6f448b1c3add589a71ab829a019d5e8c8c3d7b87a45e900000002000000000000000000000000000000000000000000000000000000000000000200dec8a17682b92c34894c7a164a7cb1138217b531b8ee34ed7169f2261a211300089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c00f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb2e33ee2008411c04b99c24b313513d097a0d21a5040b6193d1f978b8226892d6000000201fd848aa69e1633722fe249a5b7f53b094f1c9cef9f5c694b073fd1cc5850dfb000001000c499b373a1f0fe1b510a63563546d2d39e206895056a5af0143c5f30d6390730000018023c08a6b1297210c5e24c76b9a936250a1ce2721576c26ea797c7ec35f9e46a9000000800000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000067473f2fcb481cb0dab10d427667aa7f967ebaa5b4d3a9dd21d0bbacc6d29b0dbbcf30a87b386e044df6a2c58142e2affdefc5e3c4802d7c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c9bce16fa00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x003704e1233da38de17971fbfcbaaf82e0ef35739e0bbcf6f1588284286f7929", "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..56ab00473be 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": "0x28449b938250ecc926d7bd4c05f4b84ae07dfe7e90a62abf27b7d241bcd6de23", + "blockHash": "0x23402596e083daff10da9f2a8d963a59fff04f3229797b89b4fa0e65f4cde036", + "body": "0x00000004000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000041000000000000000000000000000000000000000000000000000000000000004100100000000000000000000000000000000000000000000000000000000000410020000000000000000000000000000000000000000000000000000000000041003000000000000000000000000000000000000000000000000000000000004100400000000000000000000000000000000000000000000000000000000000410050000000000000000000000000000000000000000000000000000000000041006000000000000000000000000000000000000000000000000000000000004100700000000000000000000000000000000000000000000000000000000000410080000000000000000000000000000000000000000000000000000000000041009000000000000000000000000000000000000000000000000000000000004100a000000000000000000000000000000000000000000000000000000000004100b000000000000000000000000000000000000000000000000000000000004100c000000000000000000000000000000000000000000000000000000000004100d000000000000000000000000000000000000000000000000000000000004100e000000000000000000000000000000000000000000000000000000000004100f0000000000000000000000000000000000000000000000000000000000041010000000000000000000000000000000000000000000000000000000000004101100000000000000000000000000000000000000000000000000000000000410120000000000000000000000000000000000000000000000000000000000041013000000000000000000000000000000000000000000000000000000000004101400000000000000000000000000000000000000000000000000000000000410150000000000000000000000000000000000000000000000000000000000041016000000000000000000000000000000000000000000000000000000000004101700000000000000000000000000000000000000000000000000000000000410180000000000000000000000000000000000000000000000000000000000041019000000000000000000000000000000000000000000000000000000000004101a000000000000000000000000000000000000000000000000000000000004101b000000000000000000000000000000000000000000000000000000000004101c000000000000000000000000000000000000000000000000000000000004101d000000000000000000000000000000000000000000000000000000000004101e000000000000000000000000000000000000000000000000000000000004101f0000000000000000000000000000000000000000000000000000000000041020000000000000000000000000000000000000000000000000000000000004102100000000000000000000000000000000000000000000000000000000000410220000000000000000000000000000000000000000000000000000000000041023000000000000000000000000000000000000000000000000000000000004102400000000000000000000000000000000000000000000000000000000000410250000000000000000000000000000000000000000000000000000000000041026000000000000000000000000000000000000000000000000000000000004102700000000000000000000000000000000000000000000000000000000000410280000000000000000000000000000000000000000000000000000000000041029000000000000000000000000000000000000000000000000000000000004102a000000000000000000000000000000000000000000000000000000000004102b000000000000000000000000000000000000000000000000000000000004102c000000000000000000000000000000000000000000000000000000000004102d000000000000000000000000000000000000000000000000000000000004102e000000000000000000000000000000000000000000000000000000000004102f0000000000000000000000000000000000000000000000000000000000041030000000000000000000000000000000000000000000000000000000000004103100000000000000000000000000000000000000000000000000000000000410320000000000000000000000000000000000000000000000000000000000041033000000000000000000000000000000000000000000000000000000000004103400000000000000000000000000000000000000000000000000000000000410350000000000000000000000000000000000000000000000000000000000041036000000000000000000000000000000000000000000000000000000000004103700000000000000000000000000000000000000000000000000000000000410380000000000000000000000000000000000000000000000000000000000041039000000000000000000000000000000000000000000000000000000000004103a000000000000000000000000000000000000000000000000000000000004103b000000000000000000000000000000000000000000000000000000000004103c000000000000000000000000000000000000000000000000000000000004103d000000000000000000000000000000000000000000000000000000000004103e000000000000000000000000000000000000000000000000000000000004103f4000000000000000000000000000000000000000000000000000000000000400010000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004110100000000000000000000000000000000000000000000000000000000000411020000000000000000000000000000000000000000000000000000000000041103000000000000000000000000000000000000000000000000000000000004110400000000000000000000000000000000000000000000000000000000000411050000000000000000000000000000000000000000000000000000000000041106000000000000000000000000000000000000000000000000000000000004110700000000000000000000000000000000000000000000000000000000000411080000000000000000000000000000000000000000000000000000000000041109000000000000000000000000000000000000000000000000000000000004110a000000000000000000000000000000000000000000000000000000000004110b000000000000000000000000000000000000000000000000000000000004110c000000000000000000000000000000000000000000000000000000000004110d000000000000000000000000000000000000000000000000000000000004110e000000000000000000000000000000000000000000000000000000000004110f0000000000000000000000000000000000000000000000000000000000041110000000000000000000000000000000000000000000000000000000000004111100000000000000000000000000000000000000000000000000000000000411120000000000000000000000000000000000000000000000000000000000041113000000000000000000000000000000000000000000000000000000000004111400000000000000000000000000000000000000000000000000000000000411150000000000000000000000000000000000000000000000000000000000041116000000000000000000000000000000000000000000000000000000000004111700000000000000000000000000000000000000000000000000000000000411180000000000000000000000000000000000000000000000000000000000041119000000000000000000000000000000000000000000000000000000000004111a000000000000000000000000000000000000000000000000000000000004111b000000000000000000000000000000000000000000000000000000000004111c000000000000000000000000000000000000000000000000000000000004111d000000000000000000000000000000000000000000000000000000000004111e000000000000000000000000000000000000000000000000000000000004111f0000000000000000000000000000000000000000000000000000000000041120000000000000000000000000000000000000000000000000000000000004112100000000000000000000000000000000000000000000000000000000000411220000000000000000000000000000000000000000000000000000000000041123000000000000000000000000000000000000000000000000000000000004112400000000000000000000000000000000000000000000000000000000000411250000000000000000000000000000000000000000000000000000000000041126000000000000000000000000000000000000000000000000000000000004112700000000000000000000000000000000000000000000000000000000000411280000000000000000000000000000000000000000000000000000000000041129000000000000000000000000000000000000000000000000000000000004112a000000000000000000000000000000000000000000000000000000000004112b000000000000000000000000000000000000000000000000000000000004112c000000000000000000000000000000000000000000000000000000000004112d000000000000000000000000000000000000000000000000000000000004112e000000000000000000000000000000000000000000000000000000000004112f0000000000000000000000000000000000000000000000000000000000041130000000000000000000000000000000000000000000000000000000000004113100000000000000000000000000000000000000000000000000000000000411320000000000000000000000000000000000000000000000000000000000041133000000000000000000000000000000000000000000000000000000000004113400000000000000000000000000000000000000000000000000000000000411350000000000000000000000000000000000000000000000000000000000041136000000000000000000000000000000000000000000000000000000000004113700000000000000000000000000000000000000000000000000000000000411380000000000000000000000000000000000000000000000000000000000041139000000000000000000000000000000000000000000000000000000000004113a000000000000000000000000000000000000000000000000000000000004113b000000000000000000000000000000000000000000000000000000000004113c000000000000000000000000000000000000000000000000000000000004113d000000000000000000000000000000000000000000000000000000000004113e080097a6ec570e9b8e257647c9c74c5ad3edc57ca5ef6ae44d80b3c30d1d99b9b300ce48ec41d1edde0066fab553a456ae2f380d14fa8f956af1fb0217513a598900619ff12eaf97f63aa2a2311de3b6571a7b880a5247cb33b6a74787bf3f9bd5007854a2fad4e1801c6404394bf3d37ab08c135ea38a1974242e39a21273685f000f55796e72957a819e68a22e8602d73c3ba3718a5a4bd92b80b0aa444b182a00788b6e9874fb040ee679a7fae257190099a605229b948334e54a57739535d4004f1658ee3c1a91627e5d72f5a731f0796299df82ab41e72c88eee0c82fa85e003ee802add96628c693ed71afa9908138ba5a6fbf0a5f29a9c74e4e42aba6713f0000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000000000000000000000000000000004200a0000000000000000000000000000000000000000000000000000000000042001000000000000000000000000000000000000000000000000000000000004200b0000000000000000000000000000000000000000000000000000000000042002000000000000000000000000000000000000000000000000000000000004200c0000000000000000000000000000000000000000000000000000000000042003000000000000000000000000000000000000000000000000000000000004200d0000000000000000000000000000000000000000000000000000000000042004000000000000000000000000000000000000000000000000000000000004200e0000000000000000000000000000000000000000000000000000000000042005000000000000000000000000000000000000000000000000000000000004200f00000000000000000000000000000000000000000000000000000000000420060000000000000000000000000000000000000000000000000000000000042010000000000000000000000000000000000000000000000000000000000004200700000000000000000000000000000000000000000000000000000000000420110000000000000000000000000000000000000000000000000000000000042008000000000000000000000000000000000000000000000000000000000004201200000000000000000000000000000000000000000000000000000000000420090000000000000000000000000000000000000000000000000000000000042013000000000000000000000000000000000000000000000000000000000004200a0000000000000000000000000000000000000000000000000000000000042014000000000000000000000000000000000000000000000000000000000004200b0000000000000000000000000000000000000000000000000000000000042015000000000000000000000000000000000000000000000000000000000004200c0000000000000000000000000000000000000000000000000000000000042016000000000000000000000000000000000000000000000000000000000004200d0000000000000000000000000000000000000000000000000000000000042017000000000000000000000000000000000000000000000000000000000004200e0000000000000000000000000000000000000000000000000000000000042018000000000000000000000000000000000000000000000000000000000004200f00000000000000000000000000000000000000000000000000000000000420190000000000000000000000000000000000000000000000000000000000042010000000000000000000000000000000000000000000000000000000000004201a0000000000000000000000000000000000000000000000000000000000042011000000000000000000000000000000000000000000000000000000000004201b0000000000000000000000000000000000000000000000000000000000042012000000000000000000000000000000000000000000000000000000000004201c0000000000000000000000000000000000000000000000000000000000042013000000000000000000000000000000000000000000000000000000000004201d0000000000000000000000000000000000000000000000000000000000042014000000000000000000000000000000000000000000000000000000000004201e0000000000000000000000000000000000000000000000000000000000042015000000000000000000000000000000000000000000000000000000000004201f00000000000000000000000000000000000000000000000000000000000420160000000000000000000000000000000000000000000000000000000000042020000000000000000000000000000000000000000000000000000000000004201700000000000000000000000000000000000000000000000000000000000420210000000000000000000000000000000000000000000000000000000000042018000000000000000000000000000000000000000000000000000000000004202200000000000000000000000000000000000000000000000000000000000420190000000000000000000000000000000000000000000000000000000000042023000000000000000000000000000000000000000000000000000000000004201a0000000000000000000000000000000000000000000000000000000000042024000000000000000000000000000000000000000000000000000000000004201b0000000000000000000000000000000000000000000000000000000000042025000000000000000000000000000000000000000000000000000000000004201c0000000000000000000000000000000000000000000000000000000000042026000000000000000000000000000000000000000000000000000000000004201d0000000000000000000000000000000000000000000000000000000000042027000000000000000000000000000000000000000000000000000000000004201e0000000000000000000000000000000000000000000000000000000000042028000000000000000000000000000000000000000000000000000000000004201f00000000000000000000000000000000000000000000000000000000000420290000000000000000000000000000000000000000000000000000000000042020000000000000000000000000000000000000000000000000000000000004202a0000000000000000000000000000000000000000000000000000000000042021000000000000000000000000000000000000000000000000000000000004202b0000000000000000000000000000000000000000000000000000000000042022000000000000000000000000000000000000000000000000000000000004202c0000000000000000000000000000000000000000000000000000000000042023000000000000000000000000000000000000000000000000000000000004202d0000000000000000000000000000000000000000000000000000000000042024000000000000000000000000000000000000000000000000000000000004202e0000000000000000000000000000000000000000000000000000000000042025000000000000000000000000000000000000000000000000000000000004202f00000000000000000000000000000000000000000000000000000000000420260000000000000000000000000000000000000000000000000000000000042030000000000000000000000000000000000000000000000000000000000004202700000000000000000000000000000000000000000000000000000000000420310000000000000000000000000000000000000000000000000000000000042028000000000000000000000000000000000000000000000000000000000004203200000000000000000000000000000000000000000000000000000000000420290000000000000000000000000000000000000000000000000000000000042033000000000000000000000000000000000000000000000000000000000004202a0000000000000000000000000000000000000000000000000000000000042034000000000000000000000000000000000000000000000000000000000004202b0000000000000000000000000000000000000000000000000000000000042035000000000000000000000000000000000000000000000000000000000004202c0000000000000000000000000000000000000000000000000000000000042036000000000000000000000000000000000000000000000000000000000004202d0000000000000000000000000000000000000000000000000000000000042037000000000000000000000000000000000000000000000000000000000004202e0000000000000000000000000000000000000000000000000000000000042038000000000000000000000000000000000000000000000000000000000004202f00000000000000000000000000000000000000000000000000000000000420390000000000000000000000000000000000000000000000000000000000042030000000000000000000000000000000000000000000000000000000000004203a0000000000000000000000000000000000000000000000000000000000042031000000000000000000000000000000000000000000000000000000000004203b0000000000000000000000000000000000000000000000000000000000042032000000000000000000000000000000000000000000000000000000000004203c0000000000000000000000000000000000000000000000000000000000042033000000000000000000000000000000000000000000000000000000000004203d0000000000000000000000000000000000000000000000000000000000042034000000000000000000000000000000000000000000000000000000000004203e0000000000000000000000000000000000000000000000000000000000042035000000000000000000000000000000000000000000000000000000000004203f00000000000000000000000000000000000000000000000000000000000420360000000000000000000000000000000000000000000000000000000000042040000000000000000000000000000000000000000000000000000000000004203700000000000000000000000000000000000000000000000000000000000420410000000000000000000000000000000000000000000000000000000000042038000000000000000000000000000000000000000000000000000000000004204200000000000000000000000000000000000000000000000000000000000420390000000000000000000000000000000000000000000000000000000000042043000000000000000000000000000000000000000000000000000000000004203a0000000000000000000000000000000000000000000000000000000000042044000000000000000000000000000000000000000000000000000000000004203b0000000000000000000000000000000000000000000000000000000000042045000000000000000000000000000000000000000000000000000000000004203c0000000000000000000000000000000000000000000000000000000000042046000000000000000000000000000000000000000000000000000000000004203d0000000000000000000000000000000000000000000000000000000000042047000000000000000000000000000000000000000000000000000000000004203e0000000000000000000000000000000000000000000000000000000000042048400000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004170100000000000000000000000000000000000000000000000000000000000417020000000000000000000000000000000000000000000000000000000000041703000000000000000000000000000000000000000000000000000000000004170400000000000000000000000000000000000000000000000000000000000417050000000000000000000000000000000000000000000000000000000000041706000000000000000000000000000000000000000000000000000000000004170700000000000000000000000000000000000000000000000000000000000417080000000000000000000000000000000000000000000000000000000000041709000000000000000000000000000000000000000000000000000000000004170a000000000000000000000000000000000000000000000000000000000004170b000000000000000000000000000000000000000000000000000000000004170c000000000000000000000000000000000000000000000000000000000004170d000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f00000000000000000000000000000000000000000000000000000000000417100000000000000000000000000000000000000000000000000000000000041711000000000000000000000000000000000000000000000000000000000004170100000000000000000000000000000000000000000000000000000000000417020000000000000000000000000000000000000000000000000000000000041703000000000000000000000000000000000000000000000000000000000004170400000000000000000000000000000000000000000000000000000000000417050000000000000000000000000000000000000000000000000000000000041706000000000000000000000000000000000000000000000000000000000004170700000000000000000000000000000000000000000000000000000000000417080000000000000000000000000000000000000000000000000000000000041709000000000000000000000000000000000000000000000000000000000004170a000000000000000000000000000000000000000000000000000000000004170b000000000000000000000000000000000000000000000000000000000004170c000000000000000000000000000000000000000000000000000000000004170d000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f00000000000000000000000000000000000000000000000000000000000417100000000000000000000000000000000000000000000000000000000000041711000000000000000000000000000000000000000000000000000000000004171200000000000000000000000000000000000000000000000000000000000417020000000000000000000000000000000000000000000000000000000000041703000000000000000000000000000000000000000000000000000000000004170400000000000000000000000000000000000000000000000000000000000417050000000000000000000000000000000000000000000000000000000000041706000000000000000000000000000000000000000000000000000000000004170700000000000000000000000000000000000000000000000000000000000417080000000000000000000000000000000000000000000000000000000000041709000000000000000000000000000000000000000000000000000000000004170a000000000000000000000000000000000000000000000000000000000004170b000000000000000000000000000000000000000000000000000000000004170c000000000000000000000000000000000000000000000000000000000004170d000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f00000000000000000000000000000000000000000000000000000000000417100000000000000000000000000000000000000000000000000000000000041711000000000000000000000000000000000000000000000000000000000004171200000000000000000000000000000000000000000000000000000000000417130000000000000000000000000000000000000000000000000000000000041703000000000000000000000000000000000000000000000000000000000004170400000000000000000000000000000000000000000000000000000000000417050000000000000000000000000000000000000000000000000000000000041706000000000000000000000000000000000000000000000000000000000004170700000000000000000000000000000000000000000000000000000000000417080000000000000000000000000000000000000000000000000000000000041709000000000000000000000000000000000000000000000000000000000004170a000000000000000000000000000000000000000000000000000000000004170b000000000000000000000000000000000000000000000000000000000004170c000000000000000000000000000000000000000000000000000000000004170d000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f00000000000000000000000000000000000000000000000000000000000417100000000000000000000000000000000000000000000000000000000000041711000000000000000000000000000000000000000000000000000000000004171200000000000000000000000000000000000000000000000000000000000417130000000000000000000000000000000000000000000000000000000000041714000000000000000000000000000000000000000000000000000000000004170400000000000000000000000000000000000000000000000000000000000417050000000000000000000000000000000000000000000000000000000000041706000000000000000000000000000000000000000000000000000000000004170700000000000000000000000000000000000000000000000000000000000417080000000000000000000000000000000000000000000000000000000000041709000000000000000000000000000000000000000000000000000000000004170a000000000000000000000000000000000000000000000000000000000004170b000000000000000000000000000000000000000000000000000000000004170c000000000000000000000000000000000000000000000000000000000004170d000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f00000000000000000000000000000000000000000000000000000000000417100000000000000000000000000000000000000000000000000000000000041711000000000000000000000000000000000000000000000000000000000004171200000000000000000000000000000000000000000000000000000000000417130000000000000000000000000000000000000000000000000000000000041714000000000000000000000000000000000000000000000000000000000004171500000000000000000000000000000000000000000000000000000000000417050000000000000000000000000000000000000000000000000000000000041706000000000000000000000000000000000000000000000000000000000004170700000000000000000000000000000000000000000000000000000000000417080000000000000000000000000000000000000000000000000000000000041709000000000000000000000000000000000000000000000000000000000004170a000000000000000000000000000000000000000000000000000000000004170b000000000000000000000000000000000000000000000000000000000004170c000000000000000000000000000000000000000000000000000000000004170d000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f00000000000000000000000000000000000000000000000000000000000417100000000000000000000000000000000000000000000000000000000000041711000000000000000000000000000000000000000000000000000000000004171200000000000000000000000000000000000000000000000000000000000417130000000000000000000000000000000000000000000000000000000000041714000000000000000000000000000000000000000000000000000000000004171500000000000000000000000000000000000000000000000000000000000417160000000000000000000000000000000000000000000000000000000000041706000000000000000000000000000000000000000000000000000000000004170700000000000000000000000000000000000000000000000000000000000417080000000000000000000000000000000000000000000000000000000000041709000000000000000000000000000000000000000000000000000000000004170a000000000000000000000000000000000000000000000000000000000004170b000000000000000000000000000000000000000000000000000000000004170c000000000000000000000000000000000000000000000000000000000004170d000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f00000000000000000000000000000000000000000000000000000000000417100000000000000000000000000000000000000000000000000000000000041711000000000000000000000000000000000000000000000000000000000004171200000000000000000000000000000000000000000000000000000000000417130000000000000000000000000000000000000000000000000000000000041714000000000000000000000000000000000000000000000000000000000004171500000000000000000000000000000000000000000000000000000000000417160000000000000000000000000000000000000000000000000000000000041717000000000000000000000000000000000000000000000000000000000004170700000000000000000000000000000000000000000000000000000000000417080000000000000000000000000000000000000000000000000000000000041709000000000000000000000000000000000000000000000000000000000004170a000000000000000000000000000000000000000000000000000000000004170b000000000000000000000000000000000000000000000000000000000004170c000000000000000000000000000000000000000000000000000000000004170d000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f00000000000000000000000000000000000000000000000000000000000417100000000000000000000000000000000000000000000000000000000000041711000000000000000000000000000000000000000000000000000000000004171200000000000000000000000000000000000000000000000000000000000417130000000000000000000000000000000000000000000000000000000000041714000000000000000000000000000000000000000000000000000000000004171500000000000000000000000000000000000000000000000000000000000417160000000000000000000000000000000000000000000000000000000000041717000000000000000000000000000000000000000000000000000000000004171800000000000000000000000000000000000000000000000000000000000417080000000000000000000000000000000000000000000000000000000000041709000000000000000000000000000000000000000000000000000000000004170a000000000000000000000000000000000000000000000000000000000004170b000000000000000000000000000000000000000000000000000000000004170c000000000000000000000000000000000000000000000000000000000004170d000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f00000000000000000000000000000000000000000000000000000000000417100000000000000000000000000000000000000000000000000000000000041711000000000000000000000000000000000000000000000000000000000004171200000000000000000000000000000000000000000000000000000000000417130000000000000000000000000000000000000000000000000000000000041714000000000000000000000000000000000000000000000000000000000004171500000000000000000000000000000000000000000000000000000000000417160000000000000000000000000000000000000000000000000000000000041717000000000000000000000000000000000000000000000000000000000004171800000000000000000000000000000000000000000000000000000000000417190000000000000000000000000000000000000000000000000000000000041709000000000000000000000000000000000000000000000000000000000004170a000000000000000000000000000000000000000000000000000000000004170b000000000000000000000000000000000000000000000000000000000004170c000000000000000000000000000000000000000000000000000000000004170d000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f0000000000000000000000000000000000000000000000000000000000041710000000000000000000000000000000000000000000000000000000000004171100000000000000000000000000000000000000000000000000000000000417120000000000000000000000000000000000000000000000000000000000041713000000000000000000000000000000000000000000000000000000000004171400000000000000000000000000000000000000000000000000000000000417150000000000000000000000000000000000000000000000000000000000041716000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004170a000000000000000000000000000000000000000000000000000000000004170b000000000000000000000000000000000000000000000000000000000004170c000000000000000000000000000000000000000000000000000000000004170d000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f0000000000000000000000000000000000000000000000000000000000041710000000000000000000000000000000000000000000000000000000000004171100000000000000000000000000000000000000000000000000000000000417120000000000000000000000000000000000000000000000000000000000041713000000000000000000000000000000000000000000000000000000000004171400000000000000000000000000000000000000000000000000000000000417150000000000000000000000000000000000000000000000000000000000041716000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004170b000000000000000000000000000000000000000000000000000000000004170c000000000000000000000000000000000000000000000000000000000004170d000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f0000000000000000000000000000000000000000000000000000000000041710000000000000000000000000000000000000000000000000000000000004171100000000000000000000000000000000000000000000000000000000000417120000000000000000000000000000000000000000000000000000000000041713000000000000000000000000000000000000000000000000000000000004171400000000000000000000000000000000000000000000000000000000000417150000000000000000000000000000000000000000000000000000000000041716000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004170c000000000000000000000000000000000000000000000000000000000004170d000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f0000000000000000000000000000000000000000000000000000000000041710000000000000000000000000000000000000000000000000000000000004171100000000000000000000000000000000000000000000000000000000000417120000000000000000000000000000000000000000000000000000000000041713000000000000000000000000000000000000000000000000000000000004171400000000000000000000000000000000000000000000000000000000000417150000000000000000000000000000000000000000000000000000000000041716000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004170d000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f0000000000000000000000000000000000000000000000000000000000041710000000000000000000000000000000000000000000000000000000000004171100000000000000000000000000000000000000000000000000000000000417120000000000000000000000000000000000000000000000000000000000041713000000000000000000000000000000000000000000000000000000000004171400000000000000000000000000000000000000000000000000000000000417150000000000000000000000000000000000000000000000000000000000041716000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004170e000000000000000000000000000000000000000000000000000000000004170f0000000000000000000000000000000000000000000000000000000000041710000000000000000000000000000000000000000000000000000000000004171100000000000000000000000000000000000000000000000000000000000417120000000000000000000000000000000000000000000000000000000000041713000000000000000000000000000000000000000000000000000000000004171400000000000000000000000000000000000000000000000000000000000417150000000000000000000000000000000000000000000000000000000000041716000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f000000000000000000000000000000000000000000000000000000000004170f0000000000000000000000000000000000000000000000000000000000041710000000000000000000000000000000000000000000000000000000000004171100000000000000000000000000000000000000000000000000000000000417120000000000000000000000000000000000000000000000000000000000041713000000000000000000000000000000000000000000000000000000000004171400000000000000000000000000000000000000000000000000000000000417150000000000000000000000000000000000000000000000000000000000041716000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f00000000000000000000000000000000000000000000000000000000000417200000000000000000000000000000000000000000000000000000000000041710000000000000000000000000000000000000000000000000000000000004171100000000000000000000000000000000000000000000000000000000000417120000000000000000000000000000000000000000000000000000000000041713000000000000000000000000000000000000000000000000000000000004171400000000000000000000000000000000000000000000000000000000000417150000000000000000000000000000000000000000000000000000000000041716000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f00000000000000000000000000000000000000000000000000000000000417200000000000000000000000000000000000000000000000000000000000041721000000000000000000000000000000000000000000000000000000000004171100000000000000000000000000000000000000000000000000000000000417120000000000000000000000000000000000000000000000000000000000041713000000000000000000000000000000000000000000000000000000000004171400000000000000000000000000000000000000000000000000000000000417150000000000000000000000000000000000000000000000000000000000041716000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f00000000000000000000000000000000000000000000000000000000000417200000000000000000000000000000000000000000000000000000000000041721000000000000000000000000000000000000000000000000000000000004172200000000000000000000000000000000000000000000000000000000000417120000000000000000000000000000000000000000000000000000000000041713000000000000000000000000000000000000000000000000000000000004171400000000000000000000000000000000000000000000000000000000000417150000000000000000000000000000000000000000000000000000000000041716000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f00000000000000000000000000000000000000000000000000000000000417200000000000000000000000000000000000000000000000000000000000041721000000000000000000000000000000000000000000000000000000000004172200000000000000000000000000000000000000000000000000000000000417230000000000000000000000000000000000000000000000000000000000041713000000000000000000000000000000000000000000000000000000000004171400000000000000000000000000000000000000000000000000000000000417150000000000000000000000000000000000000000000000000000000000041716000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f00000000000000000000000000000000000000000000000000000000000417200000000000000000000000000000000000000000000000000000000000041721000000000000000000000000000000000000000000000000000000000004172200000000000000000000000000000000000000000000000000000000000417230000000000000000000000000000000000000000000000000000000000041724000000000000000000000000000000000000000000000000000000000004171400000000000000000000000000000000000000000000000000000000000417150000000000000000000000000000000000000000000000000000000000041716000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f00000000000000000000000000000000000000000000000000000000000417200000000000000000000000000000000000000000000000000000000000041721000000000000000000000000000000000000000000000000000000000004172200000000000000000000000000000000000000000000000000000000000417230000000000000000000000000000000000000000000000000000000000041724000000000000000000000000000000000000000000000000000000000004172500000000000000000000000000000000000000000000000000000000000417150000000000000000000000000000000000000000000000000000000000041716000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f00000000000000000000000000000000000000000000000000000000000417200000000000000000000000000000000000000000000000000000000000041721000000000000000000000000000000000000000000000000000000000004172200000000000000000000000000000000000000000000000000000000000417230000000000000000000000000000000000000000000000000000000000041724000000000000000000000000000000000000000000000000000000000004172500000000000000000000000000000000000000000000000000000000000417260000000000000000000000000000000000000000000000000000000000041716000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f00000000000000000000000000000000000000000000000000000000000417200000000000000000000000000000000000000000000000000000000000041721000000000000000000000000000000000000000000000000000000000004172200000000000000000000000000000000000000000000000000000000000417230000000000000000000000000000000000000000000000000000000000041724000000000000000000000000000000000000000000000000000000000004172500000000000000000000000000000000000000000000000000000000000417260000000000000000000000000000000000000000000000000000000000041727000000000000000000000000000000000000000000000000000000000004171700000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f00000000000000000000000000000000000000000000000000000000000417200000000000000000000000000000000000000000000000000000000000041721000000000000000000000000000000000000000000000000000000000004172200000000000000000000000000000000000000000000000000000000000417230000000000000000000000000000000000000000000000000000000000041724000000000000000000000000000000000000000000000000000000000004172500000000000000000000000000000000000000000000000000000000000417260000000000000000000000000000000000000000000000000000000000041727000000000000000000000000000000000000000000000000000000000004172800000000000000000000000000000000000000000000000000000000000417180000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f00000000000000000000000000000000000000000000000000000000000417200000000000000000000000000000000000000000000000000000000000041721000000000000000000000000000000000000000000000000000000000004172200000000000000000000000000000000000000000000000000000000000417230000000000000000000000000000000000000000000000000000000000041724000000000000000000000000000000000000000000000000000000000004172500000000000000000000000000000000000000000000000000000000000417260000000000000000000000000000000000000000000000000000000000041727000000000000000000000000000000000000000000000000000000000004172800000000000000000000000000000000000000000000000000000000000417290000000000000000000000000000000000000000000000000000000000041719000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f0000000000000000000000000000000000000000000000000000000000041720000000000000000000000000000000000000000000000000000000000004172100000000000000000000000000000000000000000000000000000000000417220000000000000000000000000000000000000000000000000000000000041723000000000000000000000000000000000000000000000000000000000004172400000000000000000000000000000000000000000000000000000000000417250000000000000000000000000000000000000000000000000000000000041726000000000000000000000000000000000000000000000000000000000004172700000000000000000000000000000000000000000000000000000000000417280000000000000000000000000000000000000000000000000000000000041729000000000000000000000000000000000000000000000000000000000004172a000000000000000000000000000000000000000000000000000000000004171a000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f0000000000000000000000000000000000000000000000000000000000041720000000000000000000000000000000000000000000000000000000000004172100000000000000000000000000000000000000000000000000000000000417220000000000000000000000000000000000000000000000000000000000041723000000000000000000000000000000000000000000000000000000000004172400000000000000000000000000000000000000000000000000000000000417250000000000000000000000000000000000000000000000000000000000041726000000000000000000000000000000000000000000000000000000000004172700000000000000000000000000000000000000000000000000000000000417280000000000000000000000000000000000000000000000000000000000041729000000000000000000000000000000000000000000000000000000000004172a000000000000000000000000000000000000000000000000000000000004172b000000000000000000000000000000000000000000000000000000000004171b000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f0000000000000000000000000000000000000000000000000000000000041720000000000000000000000000000000000000000000000000000000000004172100000000000000000000000000000000000000000000000000000000000417220000000000000000000000000000000000000000000000000000000000041723000000000000000000000000000000000000000000000000000000000004172400000000000000000000000000000000000000000000000000000000000417250000000000000000000000000000000000000000000000000000000000041726000000000000000000000000000000000000000000000000000000000004172700000000000000000000000000000000000000000000000000000000000417280000000000000000000000000000000000000000000000000000000000041729000000000000000000000000000000000000000000000000000000000004172a000000000000000000000000000000000000000000000000000000000004172b000000000000000000000000000000000000000000000000000000000004172c000000000000000000000000000000000000000000000000000000000004171c000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f0000000000000000000000000000000000000000000000000000000000041720000000000000000000000000000000000000000000000000000000000004172100000000000000000000000000000000000000000000000000000000000417220000000000000000000000000000000000000000000000000000000000041723000000000000000000000000000000000000000000000000000000000004172400000000000000000000000000000000000000000000000000000000000417250000000000000000000000000000000000000000000000000000000000041726000000000000000000000000000000000000000000000000000000000004172700000000000000000000000000000000000000000000000000000000000417280000000000000000000000000000000000000000000000000000000000041729000000000000000000000000000000000000000000000000000000000004172a000000000000000000000000000000000000000000000000000000000004172b000000000000000000000000000000000000000000000000000000000004172c000000000000000000000000000000000000000000000000000000000004172d000000000000000000000000000000000000000000000000000000000004171d000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f0000000000000000000000000000000000000000000000000000000000041720000000000000000000000000000000000000000000000000000000000004172100000000000000000000000000000000000000000000000000000000000417220000000000000000000000000000000000000000000000000000000000041723000000000000000000000000000000000000000000000000000000000004172400000000000000000000000000000000000000000000000000000000000417250000000000000000000000000000000000000000000000000000000000041726000000000000000000000000000000000000000000000000000000000004172700000000000000000000000000000000000000000000000000000000000417280000000000000000000000000000000000000000000000000000000000041729000000000000000000000000000000000000000000000000000000000004172a000000000000000000000000000000000000000000000000000000000004172b000000000000000000000000000000000000000000000000000000000004172c000000000000000000000000000000000000000000000000000000000004172d000000000000000000000000000000000000000000000000000000000004172e000000000000000000000000000000000000000000000000000000000004171e000000000000000000000000000000000000000000000000000000000004171f0000000000000000000000000000000000000000000000000000000000041720000000000000000000000000000000000000000000000000000000000004172100000000000000000000000000000000000000000000000000000000000417220000000000000000000000000000000000000000000000000000000000041723000000000000000000000000000000000000000000000000000000000004172400000000000000000000000000000000000000000000000000000000000417250000000000000000000000000000000000000000000000000000000000041726000000000000000000000000000000000000000000000000000000000004172700000000000000000000000000000000000000000000000000000000000417280000000000000000000000000000000000000000000000000000000000041729000000000000000000000000000000000000000000000000000000000004172a000000000000000000000000000000000000000000000000000000000004172b000000000000000000000000000000000000000000000000000000000004172c000000000000000000000000000000000000000000000000000000000004172d000000000000000000000000000000000000000000000000000000000004172e000000000000000000000000000000000000000000000000000000000004172f000000000000000000000000000000000000000000000000000000000004171f0000000000000000000000000000000000000000000000000000000000041720000000000000000000000000000000000000000000000000000000000004172100000000000000000000000000000000000000000000000000000000000417220000000000000000000000000000000000000000000000000000000000041723000000000000000000000000000000000000000000000000000000000004172400000000000000000000000000000000000000000000000000000000000417250000000000000000000000000000000000000000000000000000000000041726000000000000000000000000000000000000000000000000000000000004172700000000000000000000000000000000000000000000000000000000000417280000000000000000000000000000000000000000000000000000000000041729000000000000000000000000000000000000000000000000000000000004172a000000000000000000000000000000000000000000000000000000000004172b000000000000000000000000000000000000000000000000000000000004172c000000000000000000000000000000000000000000000000000000000004172d000000000000000000000000000000000000000000000000000000000004172e000000000000000000000000000000000000000000000000000000000004172f00000000000000000000000000000000000000000000000000000000000417300000000000000000000000000000000000000000000000000000000000041720000000000000000000000000000000000000000000000000000000000004172100000000000000000000000000000000000000000000000000000000000417220000000000000000000000000000000000000000000000000000000000041723000000000000000000000000000000000000000000000000000000000004172400000000000000000000000000000000000000000000000000000000000417250000000000000000000000000000000000000000000000000000000000041726000000000000000000000000000000000000000000000000000000000004172700000000000000000000000000000000000000000000000000000000000417280000000000000000000000000000000000000000000000000000000000041729000000000000000000000000000000000000000000000000000000000004172a000000000000000000000000000000000000000000000000000000000004172b000000000000000000000000000000000000000000000000000000000004172c000000000000000000000000000000000000000000000000000000000004172d000000000000000000000000000000000000000000000000000000000004172e000000000000000000000000000000000000000000000000000000000004172f00000000000000000000000000000000000000000000000000000000000417300000000000000000000000000000000000000000000000000000000000041731000000000000000000000000000000000000000000000000000000000004172100000000000000000000000000000000000000000000000000000000000417220000000000000000000000000000000000000000000000000000000000041723000000000000000000000000000000000000000000000000000000000004172400000000000000000000000000000000000000000000000000000000000417250000000000000000000000000000000000000000000000000000000000041726000000000000000000000000000000000000000000000000000000000004172700000000000000000000000000000000000000000000000000000000000417280000000000000000000000000000000000000000000000000000000000041729000000000000000000000000000000000000000000000000000000000004172a000000000000000000000000000000000000000000000000000000000004172b000000000000000000000000000000000000000000000000000000000004172c000000000000000000000000000000000000000000000000000000000004172d000000000000000000000000000000000000000000000000000000000004172e000000000000000000000000000000000000000000000000000000000004172f00000000000000000000000000000000000000000000000000000000000417300000000000000000000000000000000000000000000000000000000000041731000000000000000000000000000000000000000000000000000000000004173200000000000000000000000000000000000000000000000000000000000417220000000000000000000000000000000000000000000000000000000000041723000000000000000000000000000000000000000000000000000000000004172400000000000000000000000000000000000000000000000000000000000417250000000000000000000000000000000000000000000000000000000000041726000000000000000000000000000000000000000000000000000000000004172700000000000000000000000000000000000000000000000000000000000417280000000000000000000000000000000000000000000000000000000000041729000000000000000000000000000000000000000000000000000000000004172a000000000000000000000000000000000000000000000000000000000004172b000000000000000000000000000000000000000000000000000000000004172c000000000000000000000000000000000000000000000000000000000004172d000000000000000000000000000000000000000000000000000000000004172e000000000000000000000000000000000000000000000000000000000004172f00000000000000000000000000000000000000000000000000000000000417300000000000000000000000000000000000000000000000000000000000041731000000000000000000000000000000000000000000000000000000000004173200000000000000000000000000000000000000000000000000000000000417330000000000000000000000000000000000000000000000000000000000041723000000000000000000000000000000000000000000000000000000000004172400000000000000000000000000000000000000000000000000000000000417250000000000000000000000000000000000000000000000000000000000041726000000000000000000000000000000000000000000000000000000000004172700000000000000000000000000000000000000000000000000000000000417280000000000000000000000000000000000000000000000000000000000041729000000000000000000000000000000000000000000000000000000000004172a000000000000000000000000000000000000000000000000000000000004172b000000000000000000000000000000000000000000000000000000000004172c000000000000000000000000000000000000000000000000000000000004172d000000000000000000000000000000000000000000000000000000000004172e000000000000000000000000000000000000000000000000000000000004172f00000000000000000000000000000000000000000000000000000000000417300000000000000000000000000000000000000000000000000000000000041731000000000000000000000000000000000000000000000000000000000004173200000000000000000000000000000000000000000000000000000000000417330000000000000000000000000000000000000000000000000000000000041734000000000000000000000000000000000000000000000000000000000004172400000000000000000000000000000000000000000000000000000000000417250000000000000000000000000000000000000000000000000000000000041726000000000000000000000000000000000000000000000000000000000004172700000000000000000000000000000000000000000000000000000000000417280000000000000000000000000000000000000000000000000000000000041729000000000000000000000000000000000000000000000000000000000004172a000000000000000000000000000000000000000000000000000000000004172b000000000000000000000000000000000000000000000000000000000004172c000000000000000000000000000000000000000000000000000000000004172d000000000000000000000000000000000000000000000000000000000004172e000000000000000000000000000000000000000000000000000000000004172f00000000000000000000000000000000000000000000000000000000000417300000000000000000000000000000000000000000000000000000000000041731000000000000000000000000000000000000000000000000000000000004173200000000000000000000000000000000000000000000000000000000000417330000000000000000000000000000000000000000000000000000000000041734000000000000000000000000000000000000000000000000000000000004173500000000000000000000000000000000000000000000000000000000000417250000000000000000000000000000000000000000000000000000000000041726000000000000000000000000000000000000000000000000000000000004172700000000000000000000000000000000000000000000000000000000000417280000000000000000000000000000000000000000000000000000000000041729000000000000000000000000000000000000000000000000000000000004172a000000000000000000000000000000000000000000000000000000000004172b000000000000000000000000000000000000000000000000000000000004172c000000000000000000000000000000000000000000000000000000000004172d000000000000000000000000000000000000000000000000000000000004172e000000000000000000000000000000000000000000000000000000000004172f00000000000000000000000000000000000000000000000000000000000417300000000000000000000000000000000000000000000000000000000000041731000000000000000000000000000000000000000000000000000000000004173200000000000000000000000000000000000000000000000000000000000417330000000000000000000000000000000000000000000000000000000000041734000000000000000000000000000000000000000000000000000000000004173500000000000000000000000000000000000000000000000000000000000417360000000000000000000000000000000000000000000000000000000000041726000000000000000000000000000000000000000000000000000000000004172700000000000000000000000000000000000000000000000000000000000417280000000000000000000000000000000000000000000000000000000000041729000000000000000000000000000000000000000000000000000000000004172a000000000000000000000000000000000000000000000000000000000004172b000000000000000000000000000000000000000000000000000000000004172c000000000000000000000000000000000000000000000000000000000004172d000000000000000000000000000000000000000000000000000000000004172e000000000000000000000000000000000000000000000000000000000004172f00000000000000000000000000000000000000000000000000000000000417300000000000000000000000000000000000000000000000000000000000041731000000000000000000000000000000000000000000000000000000000004173200000000000000000000000000000000000000000000000000000000000417330000000000000000000000000000000000000000000000000000000000041734000000000000000000000000000000000000000000000000000000000004173500000000000000000000000000000000000000000000000000000000000417360000000000000000000000000000000000000000000000000000000000041737000000000000000000000000000000000000000000000000000000000004172700000000000000000000000000000000000000000000000000000000000417280000000000000000000000000000000000000000000000000000000000041729000000000000000000000000000000000000000000000000000000000004172a000000000000000000000000000000000000000000000000000000000004172b000000000000000000000000000000000000000000000000000000000004172c000000000000000000000000000000000000000000000000000000000004172d000000000000000000000000000000000000000000000000000000000004172e000000000000000000000000000000000000000000000000000000000004172f00000000000000000000000000000000000000000000000000000000000417300000000000000000000000000000000000000000000000000000000000041731000000000000000000000000000000000000000000000000000000000004173200000000000000000000000000000000000000000000000000000000000417330000000000000000000000000000000000000000000000000000000000041734000000000000000000000000000000000000000000000000000000000004173500000000000000000000000000000000000000000000000000000000000417360000000000000000000000000000000000000000000000000000000000041737000000000000000000000000000000000000000000000000000000000004173800000000000000000000000000000000000000000000000000000000000417280000000000000000000000000000000000000000000000000000000000041729000000000000000000000000000000000000000000000000000000000004172a000000000000000000000000000000000000000000000000000000000004172b000000000000000000000000000000000000000000000000000000000004172c000000000000000000000000000000000000000000000000000000000004172d000000000000000000000000000000000000000000000000000000000004172e000000000000000000000000000000000000000000000000000000000004172f00000000000000000000000000000000000000000000000000000000000417300000000000000000000000000000000000000000000000000000000000041731000000000000000000000000000000000000000000000000000000000004173200000000000000000000000000000000000000000000000000000000000417330000000000000000000000000000000000000000000000000000000000041734000000000000000000000000000000000000000000000000000000000004173500000000000000000000000000000000000000000000000000000000000417360000000000000000000000000000000000000000000000000000000000041737000000000000000000000000000000000000000000000000000000000004173800000000000000000000000000000000000000000000000000000000000417390000000000000000000000000000000000000000000000000000000000041729000000000000000000000000000000000000000000000000000000000004172a000000000000000000000000000000000000000000000000000000000004172b000000000000000000000000000000000000000000000000000000000004172c000000000000000000000000000000000000000000000000000000000004172d000000000000000000000000000000000000000000000000000000000004172e000000000000000000000000000000000000000000000000000000000004172f0000000000000000000000000000000000000000000000000000000000041730000000000000000000000000000000000000000000000000000000000004173100000000000000000000000000000000000000000000000000000000000417320000000000000000000000000000000000000000000000000000000000041733000000000000000000000000000000000000000000000000000000000004173400000000000000000000000000000000000000000000000000000000000417350000000000000000000000000000000000000000000000000000000000041736000000000000000000000000000000000000000000000000000000000004173700000000000000000000000000000000000000000000000000000000000417380000000000000000000000000000000000000000000000000000000000041739000000000000000000000000000000000000000000000000000000000004173a000000000000000000000000000000000000000000000000000000000004172a000000000000000000000000000000000000000000000000000000000004172b000000000000000000000000000000000000000000000000000000000004172c000000000000000000000000000000000000000000000000000000000004172d000000000000000000000000000000000000000000000000000000000004172e000000000000000000000000000000000000000000000000000000000004172f0000000000000000000000000000000000000000000000000000000000041730000000000000000000000000000000000000000000000000000000000004173100000000000000000000000000000000000000000000000000000000000417320000000000000000000000000000000000000000000000000000000000041733000000000000000000000000000000000000000000000000000000000004173400000000000000000000000000000000000000000000000000000000000417350000000000000000000000000000000000000000000000000000000000041736000000000000000000000000000000000000000000000000000000000004173700000000000000000000000000000000000000000000000000000000000417380000000000000000000000000000000000000000000000000000000000041739000000000000000000000000000000000000000000000000000000000004173a000000000000000000000000000000000000000000000000000000000004173b000000000000000000000000000000000000000000000000000000000004172b000000000000000000000000000000000000000000000000000000000004172c000000000000000000000000000000000000000000000000000000000004172d000000000000000000000000000000000000000000000000000000000004172e000000000000000000000000000000000000000000000000000000000004172f0000000000000000000000000000000000000000000000000000000000041730000000000000000000000000000000000000000000000000000000000004173100000000000000000000000000000000000000000000000000000000000417320000000000000000000000000000000000000000000000000000000000041733000000000000000000000000000000000000000000000000000000000004173400000000000000000000000000000000000000000000000000000000000417350000000000000000000000000000000000000000000000000000000000041736000000000000000000000000000000000000000000000000000000000004173700000000000000000000000000000000000000000000000000000000000417380000000000000000000000000000000000000000000000000000000000041739000000000000000000000000000000000000000000000000000000000004173a000000000000000000000000000000000000000000000000000000000004173b000000000000000000000000000000000000000000000000000000000004173c000000000000000000000000000000000000000000000000000000000004172c000000000000000000000000000000000000000000000000000000000004172d000000000000000000000000000000000000000000000000000000000004172e000000000000000000000000000000000000000000000000000000000004172f0000000000000000000000000000000000000000000000000000000000041730000000000000000000000000000000000000000000000000000000000004173100000000000000000000000000000000000000000000000000000000000417320000000000000000000000000000000000000000000000000000000000041733000000000000000000000000000000000000000000000000000000000004173400000000000000000000000000000000000000000000000000000000000417350000000000000000000000000000000000000000000000000000000000041736000000000000000000000000000000000000000000000000000000000004173700000000000000000000000000000000000000000000000000000000000417380000000000000000000000000000000000000000000000000000000000041739000000000000000000000000000000000000000000000000000000000004173a000000000000000000000000000000000000000000000000000000000004173b000000000000000000000000000000000000000000000000000000000004173c000000000000000000000000000000000000000000000000000000000004173d000000000000000000000000000000000000000000000000000000000004172d000000000000000000000000000000000000000000000000000000000004172e000000000000000000000000000000000000000000000000000000000004172f0000000000000000000000000000000000000000000000000000000000041730000000000000000000000000000000000000000000000000000000000004173100000000000000000000000000000000000000000000000000000000000417320000000000000000000000000000000000000000000000000000000000041733000000000000000000000000000000000000000000000000000000000004173400000000000000000000000000000000000000000000000000000000000417350000000000000000000000000000000000000000000000000000000000041736000000000000000000000000000000000000000000000000000000000004173700000000000000000000000000000000000000000000000000000000000417380000000000000000000000000000000000000000000000000000000000041739000000000000000000000000000000000000000000000000000000000004173a000000000000000000000000000000000000000000000000000000000004173b000000000000000000000000000000000000000000000000000000000004173c000000000000000000000000000000000000000000000000000000000004173d000000000000000000000000000000000000000000000000000000000004173e000000000000000000000000000000000000000000000000000000000004172e000000000000000000000000000000000000000000000000000000000004172f0000000000000000000000000000000000000000000000000000000000041730000000000000000000000000000000000000000000000000000000000004173100000000000000000000000000000000000000000000000000000000000417320000000000000000000000000000000000000000000000000000000000041733000000000000000000000000000000000000000000000000000000000004173400000000000000000000000000000000000000000000000000000000000417350000000000000000000000000000000000000000000000000000000000041736000000000000000000000000000000000000000000000000000000000004173700000000000000000000000000000000000000000000000000000000000417380000000000000000000000000000000000000000000000000000000000041739000000000000000000000000000000000000000000000000000000000004173a000000000000000000000000000000000000000000000000000000000004173b000000000000000000000000000000000000000000000000000000000004173c000000000000000000000000000000000000000000000000000000000004173d000000000000000000000000000000000000000000000000000000000004173e000000000000000000000000000000000000000000000000000000000004173f000000000000000000000000000000000000000000000000000000000004172f0000000000000000000000000000000000000000000000000000000000041730000000000000000000000000000000000000000000000000000000000004173100000000000000000000000000000000000000000000000000000000000417320000000000000000000000000000000000000000000000000000000000041733000000000000000000000000000000000000000000000000000000000004173400000000000000000000000000000000000000000000000000000000000417350000000000000000000000000000000000000000000000000000000000041736000000000000000000000000000000000000000000000000000000000004173700000000000000000000000000000000000000000000000000000000000417380000000000000000000000000000000000000000000000000000000000041739000000000000000000000000000000000000000000000000000000000004173a000000000000000000000000000000000000000000000000000000000004173b000000000000000000000000000000000000000000000000000000000004173c000000000000000000000000000000000000000000000000000000000004173d000000000000000000000000000000000000000000000000000000000004173e000000000000000000000000000000000000000000000000000000000004173f00000000000000000000000000000000000000000000000000000000000417400000000000000000000000000000000000000000000000000000000000041730000000000000000000000000000000000000000000000000000000000004173100000000000000000000000000000000000000000000000000000000000417320000000000000000000000000000000000000000000000000000000000041733000000000000000000000000000000000000000000000000000000000004173400000000000000000000000000000000000000000000000000000000000417350000000000000000000000000000000000000000000000000000000000041736000000000000000000000000000000000000000000000000000000000004173700000000000000000000000000000000000000000000000000000000000417380000000000000000000000000000000000000000000000000000000000041739000000000000000000000000000000000000000000000000000000000004173a000000000000000000000000000000000000000000000000000000000004173b000000000000000000000000000000000000000000000000000000000004173c000000000000000000000000000000000000000000000000000000000004173d000000000000000000000000000000000000000000000000000000000004173e000000000000000000000000000000000000000000000000000000000004173f00000000000000000000000000000000000000000000000000000000000417400000000000000000000000000000000000000000000000000000000000041741000000000000000000000000000000000000000000000000000000000004173100000000000000000000000000000000000000000000000000000000000417320000000000000000000000000000000000000000000000000000000000041733000000000000000000000000000000000000000000000000000000000004173400000000000000000000000000000000000000000000000000000000000417350000000000000000000000000000000000000000000000000000000000041736000000000000000000000000000000000000000000000000000000000004173700000000000000000000000000000000000000000000000000000000000417380000000000000000000000000000000000000000000000000000000000041739000000000000000000000000000000000000000000000000000000000004173a000000000000000000000000000000000000000000000000000000000004173b000000000000000000000000000000000000000000000000000000000004173c000000000000000000000000000000000000000000000000000000000004173d000000000000000000000000000000000000000000000000000000000004173e000000000000000000000000000000000000000000000000000000000004173f00000000000000000000000000000000000000000000000000000000000417400000000000000000000000000000000000000000000000000000000000041741000000000000000000000000000000000000000000000000000000000004174200000000000000000000000000000000000000000000000000000000000417320000000000000000000000000000000000000000000000000000000000041733000000000000000000000000000000000000000000000000000000000004173400000000000000000000000000000000000000000000000000000000000417350000000000000000000000000000000000000000000000000000000000041736000000000000000000000000000000000000000000000000000000000004173700000000000000000000000000000000000000000000000000000000000417380000000000000000000000000000000000000000000000000000000000041739000000000000000000000000000000000000000000000000000000000004173a000000000000000000000000000000000000000000000000000000000004173b000000000000000000000000000000000000000000000000000000000004173c000000000000000000000000000000000000000000000000000000000004173d000000000000000000000000000000000000000000000000000000000004173e000000000000000000000000000000000000000000000000000000000004173f00000000000000000000000000000000000000000000000000000000000417400000000000000000000000000000000000000000000000000000000000041741000000000000000000000000000000000000000000000000000000000004174200000000000000000000000000000000000000000000000000000000000417430000000000000000000000000000000000000000000000000000000000041733000000000000000000000000000000000000000000000000000000000004173400000000000000000000000000000000000000000000000000000000000417350000000000000000000000000000000000000000000000000000000000041736000000000000000000000000000000000000000000000000000000000004173700000000000000000000000000000000000000000000000000000000000417380000000000000000000000000000000000000000000000000000000000041739000000000000000000000000000000000000000000000000000000000004173a000000000000000000000000000000000000000000000000000000000004173b000000000000000000000000000000000000000000000000000000000004173c000000000000000000000000000000000000000000000000000000000004173d000000000000000000000000000000000000000000000000000000000004173e000000000000000000000000000000000000000000000000000000000004173f00000000000000000000000000000000000000000000000000000000000417400000000000000000000000000000000000000000000000000000000000041741000000000000000000000000000000000000000000000000000000000004174200000000000000000000000000000000000000000000000000000000000417430000000000000000000000000000000000000000000000000000000000041744000000000000000000000000000000000000000000000000000000000004173400000000000000000000000000000000000000000000000000000000000417350000000000000000000000000000000000000000000000000000000000041736000000000000000000000000000000000000000000000000000000000004173700000000000000000000000000000000000000000000000000000000000417380000000000000000000000000000000000000000000000000000000000041739000000000000000000000000000000000000000000000000000000000004173a000000000000000000000000000000000000000000000000000000000004173b000000000000000000000000000000000000000000000000000000000004173c000000000000000000000000000000000000000000000000000000000004173d000000000000000000000000000000000000000000000000000000000004173e000000000000000000000000000000000000000000000000000000000004173f00000000000000000000000000000000000000000000000000000000000417400000000000000000000000000000000000000000000000000000000000041741000000000000000000000000000000000000000000000000000000000004174200000000000000000000000000000000000000000000000000000000000417430000000000000000000000000000000000000000000000000000000000041744000000000000000000000000000000000000000000000000000000000004174500000000000000000000000000000000000000000000000000000000000417350000000000000000000000000000000000000000000000000000000000041736000000000000000000000000000000000000000000000000000000000004173700000000000000000000000000000000000000000000000000000000000417380000000000000000000000000000000000000000000000000000000000041739000000000000000000000000000000000000000000000000000000000004173a000000000000000000000000000000000000000000000000000000000004173b000000000000000000000000000000000000000000000000000000000004173c000000000000000000000000000000000000000000000000000000000004173d000000000000000000000000000000000000000000000000000000000004173e000000000000000000000000000000000000000000000000000000000004173f00000000000000000000000000000000000000000000000000000000000417400000000000000000000000000000000000000000000000000000000000041741000000000000000000000000000000000000000000000000000000000004174200000000000000000000000000000000000000000000000000000000000417430000000000000000000000000000000000000000000000000000000000041744000000000000000000000000000000000000000000000000000000000004174500000000000000000000000000000000000000000000000000000000000417460000000000000000000000000000000000000000000000000000000000041736000000000000000000000000000000000000000000000000000000000004173700000000000000000000000000000000000000000000000000000000000417380000000000000000000000000000000000000000000000000000000000041739000000000000000000000000000000000000000000000000000000000004173a000000000000000000000000000000000000000000000000000000000004173b000000000000000000000000000000000000000000000000000000000004173c000000000000000000000000000000000000000000000000000000000004173d000000000000000000000000000000000000000000000000000000000004173e000000000000000000000000000000000000000000000000000000000004173f00000000000000000000000000000000000000000000000000000000000417400000000000000000000000000000000000000000000000000000000000041741000000000000000000000000000000000000000000000000000000000004174200000000000000000000000000000000000000000000000000000000000417430000000000000000000000000000000000000000000000000000000000041744000000000000000000000000000000000000000000000000000000000004174500000000000000000000000000000000000000000000000000000000000417460000000000000000000000000000000000000000000000000000000000041747000000000000000000000000000000000000000000000000000000000004173700000000000000000000000000000000000000000000000000000000000417380000000000000000000000000000000000000000000000000000000000041739000000000000000000000000000000000000000000000000000000000004173a000000000000000000000000000000000000000000000000000000000004173b000000000000000000000000000000000000000000000000000000000004173c000000000000000000000000000000000000000000000000000000000004173d000000000000000000000000000000000000000000000000000000000004173e000000000000000000000000000000000000000000000000000000000004173f00000000000000000000000000000000000000000000000000000000000417400000000000000000000000000000000000000000000000000000000000041741000000000000000000000000000000000000000000000000000000000004174200000000000000000000000000000000000000000000000000000000000417430000000000000000000000000000000000000000000000000000000000041744000000000000000000000000000000000000000000000000000000000004174500000000000000000000000000000000000000000000000000000000000417460000000000000000000000000000000000000000000000000000000000041747000000000000000000000000000000000000000000000000000000000004174800000000000000000000000000000000000000000000000000000000000417380000000000000000000000000000000000000000000000000000000000041739000000000000000000000000000000000000000000000000000000000004173a000000000000000000000000000000000000000000000000000000000004173b000000000000000000000000000000000000000000000000000000000004173c000000000000000000000000000000000000000000000000000000000004173d000000000000000000000000000000000000000000000000000000000004173e000000000000000000000000000000000000000000000000000000000004173f00000000000000000000000000000000000000000000000000000000000417400000000000000000000000000000000000000000000000000000000000041741000000000000000000000000000000000000000000000000000000000004174200000000000000000000000000000000000000000000000000000000000417430000000000000000000000000000000000000000000000000000000000041744000000000000000000000000000000000000000000000000000000000004174500000000000000000000000000000000000000000000000000000000000417460000000000000000000000000000000000000000000000000000000000041747000000000000000000000000000000000000000000000000000000000004174800000000000000000000000000000000000000000000000000000000000417490000000000000000000000000000000000000000000000000000000000041739000000000000000000000000000000000000000000000000000000000004173a000000000000000000000000000000000000000000000000000000000004173b000000000000000000000000000000000000000000000000000000000004173c000000000000000000000000000000000000000000000000000000000004173d000000000000000000000000000000000000000000000000000000000004173e000000000000000000000000000000000000000000000000000000000004173f0000000000000000000000000000000000000000000000000000000000041740000000000000000000000000000000000000000000000000000000000004174100000000000000000000000000000000000000000000000000000000000417420000000000000000000000000000000000000000000000000000000000041743000000000000000000000000000000000000000000000000000000000004174400000000000000000000000000000000000000000000000000000000000417450000000000000000000000000000000000000000000000000000000000041746000000000000000000000000000000000000000000000000000000000004174700000000000000000000000000000000000000000000000000000000000417480000000000000000000000000000000000000000000000000000000000041749000000000000000000000000000000000000000000000000000000000004174a000000000000000000000000000000000000000000000000000000000004173a000000000000000000000000000000000000000000000000000000000004173b000000000000000000000000000000000000000000000000000000000004173c000000000000000000000000000000000000000000000000000000000004173d000000000000000000000000000000000000000000000000000000000004173e000000000000000000000000000000000000000000000000000000000004173f0000000000000000000000000000000000000000000000000000000000041740000000000000000000000000000000000000000000000000000000000004174100000000000000000000000000000000000000000000000000000000000417420000000000000000000000000000000000000000000000000000000000041743000000000000000000000000000000000000000000000000000000000004174400000000000000000000000000000000000000000000000000000000000417450000000000000000000000000000000000000000000000000000000000041746000000000000000000000000000000000000000000000000000000000004174700000000000000000000000000000000000000000000000000000000000417480000000000000000000000000000000000000000000000000000000000041749000000000000000000000000000000000000000000000000000000000004174a000000000000000000000000000000000000000000000000000000000004174b000000000000000000000000000000000000000000000000000000000004173b000000000000000000000000000000000000000000000000000000000004173c000000000000000000000000000000000000000000000000000000000004173d000000000000000000000000000000000000000000000000000000000004173e000000000000000000000000000000000000000000000000000000000004173f0000000000000000000000000000000000000000000000000000000000041740000000000000000000000000000000000000000000000000000000000004174100000000000000000000000000000000000000000000000000000000000417420000000000000000000000000000000000000000000000000000000000041743000000000000000000000000000000000000000000000000000000000004174400000000000000000000000000000000000000000000000000000000000417450000000000000000000000000000000000000000000000000000000000041746000000000000000000000000000000000000000000000000000000000004174700000000000000000000000000000000000000000000000000000000000417480000000000000000000000000000000000000000000000000000000000041749000000000000000000000000000000000000000000000000000000000004174a000000000000000000000000000000000000000000000000000000000004174b000000000000000000000000000000000000000000000000000000000004174c000000000000000000000000000000000000000000000000000000000004173c000000000000000000000000000000000000000000000000000000000004173d000000000000000000000000000000000000000000000000000000000004173e000000000000000000000000000000000000000000000000000000000004173f0000000000000000000000000000000000000000000000000000000000041740000000000000000000000000000000000000000000000000000000000004174100000000000000000000000000000000000000000000000000000000000417420000000000000000000000000000000000000000000000000000000000041743000000000000000000000000000000000000000000000000000000000004174400000000000000000000000000000000000000000000000000000000000417450000000000000000000000000000000000000000000000000000000000041746000000000000000000000000000000000000000000000000000000000004174700000000000000000000000000000000000000000000000000000000000417480000000000000000000000000000000000000000000000000000000000041749000000000000000000000000000000000000000000000000000000000004174a000000000000000000000000000000000000000000000000000000000004174b000000000000000000000000000000000000000000000000000000000004174c000000000000000000000000000000000000000000000000000000000004174d000000000000000000000000000000000000000000000000000000000004173d000000000000000000000000000000000000000000000000000000000004173e000000000000000000000000000000000000000000000000000000000004173f0000000000000000000000000000000000000000000000000000000000041740000000000000000000000000000000000000000000000000000000000004174100000000000000000000000000000000000000000000000000000000000417420000000000000000000000000000000000000000000000000000000000041743000000000000000000000000000000000000000000000000000000000004174400000000000000000000000000000000000000000000000000000000000417450000000000000000000000000000000000000000000000000000000000041746000000000000000000000000000000000000000000000000000000000004174700000000000000000000000000000000000000000000000000000000000417480000000000000000000000000000000000000000000000000000000000041749000000000000000000000000000000000000000000000000000000000004174a000000000000000000000000000000000000000000000000000000000004174b000000000000000000000000000000000000000000000000000000000004174c000000000000000000000000000000000000000000000000000000000004174d000000000000000000000000000000000000000000000000000000000004174e000000000000000000000000000000000000000000000000000000000004173e000000000000000000000000000000000000000000000000000000000004173f0000000000000000000000000000000000000000000000000000000000041740000000000000000000000000000000000000000000000000000000000004174100000000000000000000000000000000000000000000000000000000000417420000000000000000000000000000000000000000000000000000000000041743000000000000000000000000000000000000000000000000000000000004174400000000000000000000000000000000000000000000000000000000000417450000000000000000000000000000000000000000000000000000000000041746000000000000000000000000000000000000000000000000000000000004174700000000000000000000000000000000000000000000000000000000000417480000000000000000000000000000000000000000000000000000000000041749000000000000000000000000000000000000000000000000000000000004174a000000000000000000000000000000000000000000000000000000000004174b000000000000000000000000000000000000000000000000000000000004174c000000000000000000000000000000000000000000000000000000000004174d000000000000000000000000000000000000000000000000000000000004174e000000000000000000000000000000000000000000000000000000000004174f000000000000000000000000000000000000000000000000000000000004173f0000000000000000000000000000000000000000000000000000000000041740000000000000000000000000000000000000000000000000000000000004174100000000000000000000000000000000000000000000000000000000000417420000000000000000000000000000000000000000000000000000000000041743000000000000000000000000000000000000000000000000000000000004174400000000000000000000000000000000000000000000000000000000000417450000000000000000000000000000000000000000000000000000000000041746000000000000000000000000000000000000000000000000000000000004174700000000000000000000000000000000000000000000000000000000000417480000000000000000000000000000000000000000000000000000000000041749000000000000000000000000000000000000000000000000000000000004174a000000000000000000000000000000000000000000000000000000000004174b000000000000000000000000000000000000000000000000000000000004174c000000000000000000000000000000000000000000000000000000000004174d000000000000000000000000000000000000000000000000000000000004174e000000000000000000000000000000000000000000000000000000000004174f0000000000000000000000000000000000000000000000000000000000041750000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000081000000000000000000000000000000000000000000000000000000000000008100100000000000000000000000000000000000000000000000000000000000810020000000000000000000000000000000000000000000000000000000000081003000000000000000000000000000000000000000000000000000000000008100400000000000000000000000000000000000000000000000000000000000810050000000000000000000000000000000000000000000000000000000000081006000000000000000000000000000000000000000000000000000000000008100700000000000000000000000000000000000000000000000000000000000810080000000000000000000000000000000000000000000000000000000000081009000000000000000000000000000000000000000000000000000000000008100a000000000000000000000000000000000000000000000000000000000008100b000000000000000000000000000000000000000000000000000000000008100c000000000000000000000000000000000000000000000000000000000008100d000000000000000000000000000000000000000000000000000000000008100e000000000000000000000000000000000000000000000000000000000008100f0000000000000000000000000000000000000000000000000000000000081010000000000000000000000000000000000000000000000000000000000008101100000000000000000000000000000000000000000000000000000000000810120000000000000000000000000000000000000000000000000000000000081013000000000000000000000000000000000000000000000000000000000008101400000000000000000000000000000000000000000000000000000000000810150000000000000000000000000000000000000000000000000000000000081016000000000000000000000000000000000000000000000000000000000008101700000000000000000000000000000000000000000000000000000000000810180000000000000000000000000000000000000000000000000000000000081019000000000000000000000000000000000000000000000000000000000008101a000000000000000000000000000000000000000000000000000000000008101b000000000000000000000000000000000000000000000000000000000008101c000000000000000000000000000000000000000000000000000000000008101d000000000000000000000000000000000000000000000000000000000008101e000000000000000000000000000000000000000000000000000000000008101f0000000000000000000000000000000000000000000000000000000000081020000000000000000000000000000000000000000000000000000000000008102100000000000000000000000000000000000000000000000000000000000810220000000000000000000000000000000000000000000000000000000000081023000000000000000000000000000000000000000000000000000000000008102400000000000000000000000000000000000000000000000000000000000810250000000000000000000000000000000000000000000000000000000000081026000000000000000000000000000000000000000000000000000000000008102700000000000000000000000000000000000000000000000000000000000810280000000000000000000000000000000000000000000000000000000000081029000000000000000000000000000000000000000000000000000000000008102a000000000000000000000000000000000000000000000000000000000008102b000000000000000000000000000000000000000000000000000000000008102c000000000000000000000000000000000000000000000000000000000008102d000000000000000000000000000000000000000000000000000000000008102e000000000000000000000000000000000000000000000000000000000008102f0000000000000000000000000000000000000000000000000000000000081030000000000000000000000000000000000000000000000000000000000008103100000000000000000000000000000000000000000000000000000000000810320000000000000000000000000000000000000000000000000000000000081033000000000000000000000000000000000000000000000000000000000008103400000000000000000000000000000000000000000000000000000000000810350000000000000000000000000000000000000000000000000000000000081036000000000000000000000000000000000000000000000000000000000008103700000000000000000000000000000000000000000000000000000000000810380000000000000000000000000000000000000000000000000000000000081039000000000000000000000000000000000000000000000000000000000008103a000000000000000000000000000000000000000000000000000000000008103b000000000000000000000000000000000000000000000000000000000008103c000000000000000000000000000000000000000000000000000000000008103d000000000000000000000000000000000000000000000000000000000008103e000000000000000000000000000000000000000000000000000000000008103f4000000000000000000000000000000000000000000000000000000000000800010000000000000000000000000000000000000000000000000000000000081100000000000000000000000000000000000000000000000000000000000008110100000000000000000000000000000000000000000000000000000000000811020000000000000000000000000000000000000000000000000000000000081103000000000000000000000000000000000000000000000000000000000008110400000000000000000000000000000000000000000000000000000000000811050000000000000000000000000000000000000000000000000000000000081106000000000000000000000000000000000000000000000000000000000008110700000000000000000000000000000000000000000000000000000000000811080000000000000000000000000000000000000000000000000000000000081109000000000000000000000000000000000000000000000000000000000008110a000000000000000000000000000000000000000000000000000000000008110b000000000000000000000000000000000000000000000000000000000008110c000000000000000000000000000000000000000000000000000000000008110d000000000000000000000000000000000000000000000000000000000008110e000000000000000000000000000000000000000000000000000000000008110f0000000000000000000000000000000000000000000000000000000000081110000000000000000000000000000000000000000000000000000000000008111100000000000000000000000000000000000000000000000000000000000811120000000000000000000000000000000000000000000000000000000000081113000000000000000000000000000000000000000000000000000000000008111400000000000000000000000000000000000000000000000000000000000811150000000000000000000000000000000000000000000000000000000000081116000000000000000000000000000000000000000000000000000000000008111700000000000000000000000000000000000000000000000000000000000811180000000000000000000000000000000000000000000000000000000000081119000000000000000000000000000000000000000000000000000000000008111a000000000000000000000000000000000000000000000000000000000008111b000000000000000000000000000000000000000000000000000000000008111c000000000000000000000000000000000000000000000000000000000008111d000000000000000000000000000000000000000000000000000000000008111e000000000000000000000000000000000000000000000000000000000008111f0000000000000000000000000000000000000000000000000000000000081120000000000000000000000000000000000000000000000000000000000008112100000000000000000000000000000000000000000000000000000000000811220000000000000000000000000000000000000000000000000000000000081123000000000000000000000000000000000000000000000000000000000008112400000000000000000000000000000000000000000000000000000000000811250000000000000000000000000000000000000000000000000000000000081126000000000000000000000000000000000000000000000000000000000008112700000000000000000000000000000000000000000000000000000000000811280000000000000000000000000000000000000000000000000000000000081129000000000000000000000000000000000000000000000000000000000008112a000000000000000000000000000000000000000000000000000000000008112b000000000000000000000000000000000000000000000000000000000008112c000000000000000000000000000000000000000000000000000000000008112d000000000000000000000000000000000000000000000000000000000008112e000000000000000000000000000000000000000000000000000000000008112f0000000000000000000000000000000000000000000000000000000000081130000000000000000000000000000000000000000000000000000000000008113100000000000000000000000000000000000000000000000000000000000811320000000000000000000000000000000000000000000000000000000000081133000000000000000000000000000000000000000000000000000000000008113400000000000000000000000000000000000000000000000000000000000811350000000000000000000000000000000000000000000000000000000000081136000000000000000000000000000000000000000000000000000000000008113700000000000000000000000000000000000000000000000000000000000811380000000000000000000000000000000000000000000000000000000000081139000000000000000000000000000000000000000000000000000000000008113a000000000000000000000000000000000000000000000000000000000008113b000000000000000000000000000000000000000000000000000000000008113c000000000000000000000000000000000000000000000000000000000008113d000000000000000000000000000000000000000000000000000000000008113e08003c0472260790b0bdfb8ae4dc4d437e7686b73643f2198970d84e1059a5f13500bfd46275a318e438726ff2765ae154b63ab8a0daebcbed668a5f58a0e63dc1007906b9418dc758c6b4f8454c69baa48b7889b6b511d707abe8e2cb8f7c397300aeb60c4d65a44f122e58bf9565dfe2024b3ae654d5cf2e47ecb035d53c927000bf82e8cda20345f37bbb1de3932172324b57f0b98be483392697b168e3bba8000fb4bbad884ef30edf68e45a6cf2733fcf50310c69d7c1432b29af2c0aa8040023e1622d27fee3b4a40ab975ae0eb2e31619ef3dc76eb858f7fddb6a056131004689cd7007daf98dd3218b839b8e6a29f957154347b391fdb376bd0b344be23f0000000000000000000000000000000000000000000000000000000000082000000000000000000000000000000000000000000000000000000000000008200a0000000000000000000000000000000000000000000000000000000000082001000000000000000000000000000000000000000000000000000000000008200b0000000000000000000000000000000000000000000000000000000000082002000000000000000000000000000000000000000000000000000000000008200c0000000000000000000000000000000000000000000000000000000000082003000000000000000000000000000000000000000000000000000000000008200d0000000000000000000000000000000000000000000000000000000000082004000000000000000000000000000000000000000000000000000000000008200e0000000000000000000000000000000000000000000000000000000000082005000000000000000000000000000000000000000000000000000000000008200f00000000000000000000000000000000000000000000000000000000000820060000000000000000000000000000000000000000000000000000000000082010000000000000000000000000000000000000000000000000000000000008200700000000000000000000000000000000000000000000000000000000000820110000000000000000000000000000000000000000000000000000000000082008000000000000000000000000000000000000000000000000000000000008201200000000000000000000000000000000000000000000000000000000000820090000000000000000000000000000000000000000000000000000000000082013000000000000000000000000000000000000000000000000000000000008200a0000000000000000000000000000000000000000000000000000000000082014000000000000000000000000000000000000000000000000000000000008200b0000000000000000000000000000000000000000000000000000000000082015000000000000000000000000000000000000000000000000000000000008200c0000000000000000000000000000000000000000000000000000000000082016000000000000000000000000000000000000000000000000000000000008200d0000000000000000000000000000000000000000000000000000000000082017000000000000000000000000000000000000000000000000000000000008200e0000000000000000000000000000000000000000000000000000000000082018000000000000000000000000000000000000000000000000000000000008200f00000000000000000000000000000000000000000000000000000000000820190000000000000000000000000000000000000000000000000000000000082010000000000000000000000000000000000000000000000000000000000008201a0000000000000000000000000000000000000000000000000000000000082011000000000000000000000000000000000000000000000000000000000008201b0000000000000000000000000000000000000000000000000000000000082012000000000000000000000000000000000000000000000000000000000008201c0000000000000000000000000000000000000000000000000000000000082013000000000000000000000000000000000000000000000000000000000008201d0000000000000000000000000000000000000000000000000000000000082014000000000000000000000000000000000000000000000000000000000008201e0000000000000000000000000000000000000000000000000000000000082015000000000000000000000000000000000000000000000000000000000008201f00000000000000000000000000000000000000000000000000000000000820160000000000000000000000000000000000000000000000000000000000082020000000000000000000000000000000000000000000000000000000000008201700000000000000000000000000000000000000000000000000000000000820210000000000000000000000000000000000000000000000000000000000082018000000000000000000000000000000000000000000000000000000000008202200000000000000000000000000000000000000000000000000000000000820190000000000000000000000000000000000000000000000000000000000082023000000000000000000000000000000000000000000000000000000000008201a0000000000000000000000000000000000000000000000000000000000082024000000000000000000000000000000000000000000000000000000000008201b0000000000000000000000000000000000000000000000000000000000082025000000000000000000000000000000000000000000000000000000000008201c0000000000000000000000000000000000000000000000000000000000082026000000000000000000000000000000000000000000000000000000000008201d0000000000000000000000000000000000000000000000000000000000082027000000000000000000000000000000000000000000000000000000000008201e0000000000000000000000000000000000000000000000000000000000082028000000000000000000000000000000000000000000000000000000000008201f00000000000000000000000000000000000000000000000000000000000820290000000000000000000000000000000000000000000000000000000000082020000000000000000000000000000000000000000000000000000000000008202a0000000000000000000000000000000000000000000000000000000000082021000000000000000000000000000000000000000000000000000000000008202b0000000000000000000000000000000000000000000000000000000000082022000000000000000000000000000000000000000000000000000000000008202c0000000000000000000000000000000000000000000000000000000000082023000000000000000000000000000000000000000000000000000000000008202d0000000000000000000000000000000000000000000000000000000000082024000000000000000000000000000000000000000000000000000000000008202e0000000000000000000000000000000000000000000000000000000000082025000000000000000000000000000000000000000000000000000000000008202f00000000000000000000000000000000000000000000000000000000000820260000000000000000000000000000000000000000000000000000000000082030000000000000000000000000000000000000000000000000000000000008202700000000000000000000000000000000000000000000000000000000000820310000000000000000000000000000000000000000000000000000000000082028000000000000000000000000000000000000000000000000000000000008203200000000000000000000000000000000000000000000000000000000000820290000000000000000000000000000000000000000000000000000000000082033000000000000000000000000000000000000000000000000000000000008202a0000000000000000000000000000000000000000000000000000000000082034000000000000000000000000000000000000000000000000000000000008202b0000000000000000000000000000000000000000000000000000000000082035000000000000000000000000000000000000000000000000000000000008202c0000000000000000000000000000000000000000000000000000000000082036000000000000000000000000000000000000000000000000000000000008202d0000000000000000000000000000000000000000000000000000000000082037000000000000000000000000000000000000000000000000000000000008202e0000000000000000000000000000000000000000000000000000000000082038000000000000000000000000000000000000000000000000000000000008202f00000000000000000000000000000000000000000000000000000000000820390000000000000000000000000000000000000000000000000000000000082030000000000000000000000000000000000000000000000000000000000008203a0000000000000000000000000000000000000000000000000000000000082031000000000000000000000000000000000000000000000000000000000008203b0000000000000000000000000000000000000000000000000000000000082032000000000000000000000000000000000000000000000000000000000008203c0000000000000000000000000000000000000000000000000000000000082033000000000000000000000000000000000000000000000000000000000008203d0000000000000000000000000000000000000000000000000000000000082034000000000000000000000000000000000000000000000000000000000008203e0000000000000000000000000000000000000000000000000000000000082035000000000000000000000000000000000000000000000000000000000008203f00000000000000000000000000000000000000000000000000000000000820360000000000000000000000000000000000000000000000000000000000082040000000000000000000000000000000000000000000000000000000000008203700000000000000000000000000000000000000000000000000000000000820410000000000000000000000000000000000000000000000000000000000082038000000000000000000000000000000000000000000000000000000000008204200000000000000000000000000000000000000000000000000000000000820390000000000000000000000000000000000000000000000000000000000082043000000000000000000000000000000000000000000000000000000000008203a0000000000000000000000000000000000000000000000000000000000082044000000000000000000000000000000000000000000000000000000000008203b0000000000000000000000000000000000000000000000000000000000082045000000000000000000000000000000000000000000000000000000000008203c0000000000000000000000000000000000000000000000000000000000082046000000000000000000000000000000000000000000000000000000000008203d0000000000000000000000000000000000000000000000000000000000082047000000000000000000000000000000000000000000000000000000000008203e0000000000000000000000000000000000000000000000000000000000082048400000000000000000000000000000000000000000000000000000000000081700000000000000000000000000000000000000000000000000000000000008170100000000000000000000000000000000000000000000000000000000000817020000000000000000000000000000000000000000000000000000000000081703000000000000000000000000000000000000000000000000000000000008170400000000000000000000000000000000000000000000000000000000000817050000000000000000000000000000000000000000000000000000000000081706000000000000000000000000000000000000000000000000000000000008170700000000000000000000000000000000000000000000000000000000000817080000000000000000000000000000000000000000000000000000000000081709000000000000000000000000000000000000000000000000000000000008170a000000000000000000000000000000000000000000000000000000000008170b000000000000000000000000000000000000000000000000000000000008170c000000000000000000000000000000000000000000000000000000000008170d000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f00000000000000000000000000000000000000000000000000000000000817100000000000000000000000000000000000000000000000000000000000081711000000000000000000000000000000000000000000000000000000000008170100000000000000000000000000000000000000000000000000000000000817020000000000000000000000000000000000000000000000000000000000081703000000000000000000000000000000000000000000000000000000000008170400000000000000000000000000000000000000000000000000000000000817050000000000000000000000000000000000000000000000000000000000081706000000000000000000000000000000000000000000000000000000000008170700000000000000000000000000000000000000000000000000000000000817080000000000000000000000000000000000000000000000000000000000081709000000000000000000000000000000000000000000000000000000000008170a000000000000000000000000000000000000000000000000000000000008170b000000000000000000000000000000000000000000000000000000000008170c000000000000000000000000000000000000000000000000000000000008170d000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f00000000000000000000000000000000000000000000000000000000000817100000000000000000000000000000000000000000000000000000000000081711000000000000000000000000000000000000000000000000000000000008171200000000000000000000000000000000000000000000000000000000000817020000000000000000000000000000000000000000000000000000000000081703000000000000000000000000000000000000000000000000000000000008170400000000000000000000000000000000000000000000000000000000000817050000000000000000000000000000000000000000000000000000000000081706000000000000000000000000000000000000000000000000000000000008170700000000000000000000000000000000000000000000000000000000000817080000000000000000000000000000000000000000000000000000000000081709000000000000000000000000000000000000000000000000000000000008170a000000000000000000000000000000000000000000000000000000000008170b000000000000000000000000000000000000000000000000000000000008170c000000000000000000000000000000000000000000000000000000000008170d000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f00000000000000000000000000000000000000000000000000000000000817100000000000000000000000000000000000000000000000000000000000081711000000000000000000000000000000000000000000000000000000000008171200000000000000000000000000000000000000000000000000000000000817130000000000000000000000000000000000000000000000000000000000081703000000000000000000000000000000000000000000000000000000000008170400000000000000000000000000000000000000000000000000000000000817050000000000000000000000000000000000000000000000000000000000081706000000000000000000000000000000000000000000000000000000000008170700000000000000000000000000000000000000000000000000000000000817080000000000000000000000000000000000000000000000000000000000081709000000000000000000000000000000000000000000000000000000000008170a000000000000000000000000000000000000000000000000000000000008170b000000000000000000000000000000000000000000000000000000000008170c000000000000000000000000000000000000000000000000000000000008170d000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f00000000000000000000000000000000000000000000000000000000000817100000000000000000000000000000000000000000000000000000000000081711000000000000000000000000000000000000000000000000000000000008171200000000000000000000000000000000000000000000000000000000000817130000000000000000000000000000000000000000000000000000000000081714000000000000000000000000000000000000000000000000000000000008170400000000000000000000000000000000000000000000000000000000000817050000000000000000000000000000000000000000000000000000000000081706000000000000000000000000000000000000000000000000000000000008170700000000000000000000000000000000000000000000000000000000000817080000000000000000000000000000000000000000000000000000000000081709000000000000000000000000000000000000000000000000000000000008170a000000000000000000000000000000000000000000000000000000000008170b000000000000000000000000000000000000000000000000000000000008170c000000000000000000000000000000000000000000000000000000000008170d000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f00000000000000000000000000000000000000000000000000000000000817100000000000000000000000000000000000000000000000000000000000081711000000000000000000000000000000000000000000000000000000000008171200000000000000000000000000000000000000000000000000000000000817130000000000000000000000000000000000000000000000000000000000081714000000000000000000000000000000000000000000000000000000000008171500000000000000000000000000000000000000000000000000000000000817050000000000000000000000000000000000000000000000000000000000081706000000000000000000000000000000000000000000000000000000000008170700000000000000000000000000000000000000000000000000000000000817080000000000000000000000000000000000000000000000000000000000081709000000000000000000000000000000000000000000000000000000000008170a000000000000000000000000000000000000000000000000000000000008170b000000000000000000000000000000000000000000000000000000000008170c000000000000000000000000000000000000000000000000000000000008170d000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f00000000000000000000000000000000000000000000000000000000000817100000000000000000000000000000000000000000000000000000000000081711000000000000000000000000000000000000000000000000000000000008171200000000000000000000000000000000000000000000000000000000000817130000000000000000000000000000000000000000000000000000000000081714000000000000000000000000000000000000000000000000000000000008171500000000000000000000000000000000000000000000000000000000000817160000000000000000000000000000000000000000000000000000000000081706000000000000000000000000000000000000000000000000000000000008170700000000000000000000000000000000000000000000000000000000000817080000000000000000000000000000000000000000000000000000000000081709000000000000000000000000000000000000000000000000000000000008170a000000000000000000000000000000000000000000000000000000000008170b000000000000000000000000000000000000000000000000000000000008170c000000000000000000000000000000000000000000000000000000000008170d000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f00000000000000000000000000000000000000000000000000000000000817100000000000000000000000000000000000000000000000000000000000081711000000000000000000000000000000000000000000000000000000000008171200000000000000000000000000000000000000000000000000000000000817130000000000000000000000000000000000000000000000000000000000081714000000000000000000000000000000000000000000000000000000000008171500000000000000000000000000000000000000000000000000000000000817160000000000000000000000000000000000000000000000000000000000081717000000000000000000000000000000000000000000000000000000000008170700000000000000000000000000000000000000000000000000000000000817080000000000000000000000000000000000000000000000000000000000081709000000000000000000000000000000000000000000000000000000000008170a000000000000000000000000000000000000000000000000000000000008170b000000000000000000000000000000000000000000000000000000000008170c000000000000000000000000000000000000000000000000000000000008170d000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f00000000000000000000000000000000000000000000000000000000000817100000000000000000000000000000000000000000000000000000000000081711000000000000000000000000000000000000000000000000000000000008171200000000000000000000000000000000000000000000000000000000000817130000000000000000000000000000000000000000000000000000000000081714000000000000000000000000000000000000000000000000000000000008171500000000000000000000000000000000000000000000000000000000000817160000000000000000000000000000000000000000000000000000000000081717000000000000000000000000000000000000000000000000000000000008171800000000000000000000000000000000000000000000000000000000000817080000000000000000000000000000000000000000000000000000000000081709000000000000000000000000000000000000000000000000000000000008170a000000000000000000000000000000000000000000000000000000000008170b000000000000000000000000000000000000000000000000000000000008170c000000000000000000000000000000000000000000000000000000000008170d000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f00000000000000000000000000000000000000000000000000000000000817100000000000000000000000000000000000000000000000000000000000081711000000000000000000000000000000000000000000000000000000000008171200000000000000000000000000000000000000000000000000000000000817130000000000000000000000000000000000000000000000000000000000081714000000000000000000000000000000000000000000000000000000000008171500000000000000000000000000000000000000000000000000000000000817160000000000000000000000000000000000000000000000000000000000081717000000000000000000000000000000000000000000000000000000000008171800000000000000000000000000000000000000000000000000000000000817190000000000000000000000000000000000000000000000000000000000081709000000000000000000000000000000000000000000000000000000000008170a000000000000000000000000000000000000000000000000000000000008170b000000000000000000000000000000000000000000000000000000000008170c000000000000000000000000000000000000000000000000000000000008170d000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f0000000000000000000000000000000000000000000000000000000000081710000000000000000000000000000000000000000000000000000000000008171100000000000000000000000000000000000000000000000000000000000817120000000000000000000000000000000000000000000000000000000000081713000000000000000000000000000000000000000000000000000000000008171400000000000000000000000000000000000000000000000000000000000817150000000000000000000000000000000000000000000000000000000000081716000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008170a000000000000000000000000000000000000000000000000000000000008170b000000000000000000000000000000000000000000000000000000000008170c000000000000000000000000000000000000000000000000000000000008170d000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f0000000000000000000000000000000000000000000000000000000000081710000000000000000000000000000000000000000000000000000000000008171100000000000000000000000000000000000000000000000000000000000817120000000000000000000000000000000000000000000000000000000000081713000000000000000000000000000000000000000000000000000000000008171400000000000000000000000000000000000000000000000000000000000817150000000000000000000000000000000000000000000000000000000000081716000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008170b000000000000000000000000000000000000000000000000000000000008170c000000000000000000000000000000000000000000000000000000000008170d000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f0000000000000000000000000000000000000000000000000000000000081710000000000000000000000000000000000000000000000000000000000008171100000000000000000000000000000000000000000000000000000000000817120000000000000000000000000000000000000000000000000000000000081713000000000000000000000000000000000000000000000000000000000008171400000000000000000000000000000000000000000000000000000000000817150000000000000000000000000000000000000000000000000000000000081716000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008170c000000000000000000000000000000000000000000000000000000000008170d000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f0000000000000000000000000000000000000000000000000000000000081710000000000000000000000000000000000000000000000000000000000008171100000000000000000000000000000000000000000000000000000000000817120000000000000000000000000000000000000000000000000000000000081713000000000000000000000000000000000000000000000000000000000008171400000000000000000000000000000000000000000000000000000000000817150000000000000000000000000000000000000000000000000000000000081716000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008170d000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f0000000000000000000000000000000000000000000000000000000000081710000000000000000000000000000000000000000000000000000000000008171100000000000000000000000000000000000000000000000000000000000817120000000000000000000000000000000000000000000000000000000000081713000000000000000000000000000000000000000000000000000000000008171400000000000000000000000000000000000000000000000000000000000817150000000000000000000000000000000000000000000000000000000000081716000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008170e000000000000000000000000000000000000000000000000000000000008170f0000000000000000000000000000000000000000000000000000000000081710000000000000000000000000000000000000000000000000000000000008171100000000000000000000000000000000000000000000000000000000000817120000000000000000000000000000000000000000000000000000000000081713000000000000000000000000000000000000000000000000000000000008171400000000000000000000000000000000000000000000000000000000000817150000000000000000000000000000000000000000000000000000000000081716000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f000000000000000000000000000000000000000000000000000000000008170f0000000000000000000000000000000000000000000000000000000000081710000000000000000000000000000000000000000000000000000000000008171100000000000000000000000000000000000000000000000000000000000817120000000000000000000000000000000000000000000000000000000000081713000000000000000000000000000000000000000000000000000000000008171400000000000000000000000000000000000000000000000000000000000817150000000000000000000000000000000000000000000000000000000000081716000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f00000000000000000000000000000000000000000000000000000000000817200000000000000000000000000000000000000000000000000000000000081710000000000000000000000000000000000000000000000000000000000008171100000000000000000000000000000000000000000000000000000000000817120000000000000000000000000000000000000000000000000000000000081713000000000000000000000000000000000000000000000000000000000008171400000000000000000000000000000000000000000000000000000000000817150000000000000000000000000000000000000000000000000000000000081716000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f00000000000000000000000000000000000000000000000000000000000817200000000000000000000000000000000000000000000000000000000000081721000000000000000000000000000000000000000000000000000000000008171100000000000000000000000000000000000000000000000000000000000817120000000000000000000000000000000000000000000000000000000000081713000000000000000000000000000000000000000000000000000000000008171400000000000000000000000000000000000000000000000000000000000817150000000000000000000000000000000000000000000000000000000000081716000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f00000000000000000000000000000000000000000000000000000000000817200000000000000000000000000000000000000000000000000000000000081721000000000000000000000000000000000000000000000000000000000008172200000000000000000000000000000000000000000000000000000000000817120000000000000000000000000000000000000000000000000000000000081713000000000000000000000000000000000000000000000000000000000008171400000000000000000000000000000000000000000000000000000000000817150000000000000000000000000000000000000000000000000000000000081716000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f00000000000000000000000000000000000000000000000000000000000817200000000000000000000000000000000000000000000000000000000000081721000000000000000000000000000000000000000000000000000000000008172200000000000000000000000000000000000000000000000000000000000817230000000000000000000000000000000000000000000000000000000000081713000000000000000000000000000000000000000000000000000000000008171400000000000000000000000000000000000000000000000000000000000817150000000000000000000000000000000000000000000000000000000000081716000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f00000000000000000000000000000000000000000000000000000000000817200000000000000000000000000000000000000000000000000000000000081721000000000000000000000000000000000000000000000000000000000008172200000000000000000000000000000000000000000000000000000000000817230000000000000000000000000000000000000000000000000000000000081724000000000000000000000000000000000000000000000000000000000008171400000000000000000000000000000000000000000000000000000000000817150000000000000000000000000000000000000000000000000000000000081716000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f00000000000000000000000000000000000000000000000000000000000817200000000000000000000000000000000000000000000000000000000000081721000000000000000000000000000000000000000000000000000000000008172200000000000000000000000000000000000000000000000000000000000817230000000000000000000000000000000000000000000000000000000000081724000000000000000000000000000000000000000000000000000000000008172500000000000000000000000000000000000000000000000000000000000817150000000000000000000000000000000000000000000000000000000000081716000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f00000000000000000000000000000000000000000000000000000000000817200000000000000000000000000000000000000000000000000000000000081721000000000000000000000000000000000000000000000000000000000008172200000000000000000000000000000000000000000000000000000000000817230000000000000000000000000000000000000000000000000000000000081724000000000000000000000000000000000000000000000000000000000008172500000000000000000000000000000000000000000000000000000000000817260000000000000000000000000000000000000000000000000000000000081716000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f00000000000000000000000000000000000000000000000000000000000817200000000000000000000000000000000000000000000000000000000000081721000000000000000000000000000000000000000000000000000000000008172200000000000000000000000000000000000000000000000000000000000817230000000000000000000000000000000000000000000000000000000000081724000000000000000000000000000000000000000000000000000000000008172500000000000000000000000000000000000000000000000000000000000817260000000000000000000000000000000000000000000000000000000000081727000000000000000000000000000000000000000000000000000000000008171700000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f00000000000000000000000000000000000000000000000000000000000817200000000000000000000000000000000000000000000000000000000000081721000000000000000000000000000000000000000000000000000000000008172200000000000000000000000000000000000000000000000000000000000817230000000000000000000000000000000000000000000000000000000000081724000000000000000000000000000000000000000000000000000000000008172500000000000000000000000000000000000000000000000000000000000817260000000000000000000000000000000000000000000000000000000000081727000000000000000000000000000000000000000000000000000000000008172800000000000000000000000000000000000000000000000000000000000817180000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f00000000000000000000000000000000000000000000000000000000000817200000000000000000000000000000000000000000000000000000000000081721000000000000000000000000000000000000000000000000000000000008172200000000000000000000000000000000000000000000000000000000000817230000000000000000000000000000000000000000000000000000000000081724000000000000000000000000000000000000000000000000000000000008172500000000000000000000000000000000000000000000000000000000000817260000000000000000000000000000000000000000000000000000000000081727000000000000000000000000000000000000000000000000000000000008172800000000000000000000000000000000000000000000000000000000000817290000000000000000000000000000000000000000000000000000000000081719000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f0000000000000000000000000000000000000000000000000000000000081720000000000000000000000000000000000000000000000000000000000008172100000000000000000000000000000000000000000000000000000000000817220000000000000000000000000000000000000000000000000000000000081723000000000000000000000000000000000000000000000000000000000008172400000000000000000000000000000000000000000000000000000000000817250000000000000000000000000000000000000000000000000000000000081726000000000000000000000000000000000000000000000000000000000008172700000000000000000000000000000000000000000000000000000000000817280000000000000000000000000000000000000000000000000000000000081729000000000000000000000000000000000000000000000000000000000008172a000000000000000000000000000000000000000000000000000000000008171a000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f0000000000000000000000000000000000000000000000000000000000081720000000000000000000000000000000000000000000000000000000000008172100000000000000000000000000000000000000000000000000000000000817220000000000000000000000000000000000000000000000000000000000081723000000000000000000000000000000000000000000000000000000000008172400000000000000000000000000000000000000000000000000000000000817250000000000000000000000000000000000000000000000000000000000081726000000000000000000000000000000000000000000000000000000000008172700000000000000000000000000000000000000000000000000000000000817280000000000000000000000000000000000000000000000000000000000081729000000000000000000000000000000000000000000000000000000000008172a000000000000000000000000000000000000000000000000000000000008172b000000000000000000000000000000000000000000000000000000000008171b000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f0000000000000000000000000000000000000000000000000000000000081720000000000000000000000000000000000000000000000000000000000008172100000000000000000000000000000000000000000000000000000000000817220000000000000000000000000000000000000000000000000000000000081723000000000000000000000000000000000000000000000000000000000008172400000000000000000000000000000000000000000000000000000000000817250000000000000000000000000000000000000000000000000000000000081726000000000000000000000000000000000000000000000000000000000008172700000000000000000000000000000000000000000000000000000000000817280000000000000000000000000000000000000000000000000000000000081729000000000000000000000000000000000000000000000000000000000008172a000000000000000000000000000000000000000000000000000000000008172b000000000000000000000000000000000000000000000000000000000008172c000000000000000000000000000000000000000000000000000000000008171c000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f0000000000000000000000000000000000000000000000000000000000081720000000000000000000000000000000000000000000000000000000000008172100000000000000000000000000000000000000000000000000000000000817220000000000000000000000000000000000000000000000000000000000081723000000000000000000000000000000000000000000000000000000000008172400000000000000000000000000000000000000000000000000000000000817250000000000000000000000000000000000000000000000000000000000081726000000000000000000000000000000000000000000000000000000000008172700000000000000000000000000000000000000000000000000000000000817280000000000000000000000000000000000000000000000000000000000081729000000000000000000000000000000000000000000000000000000000008172a000000000000000000000000000000000000000000000000000000000008172b000000000000000000000000000000000000000000000000000000000008172c000000000000000000000000000000000000000000000000000000000008172d000000000000000000000000000000000000000000000000000000000008171d000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f0000000000000000000000000000000000000000000000000000000000081720000000000000000000000000000000000000000000000000000000000008172100000000000000000000000000000000000000000000000000000000000817220000000000000000000000000000000000000000000000000000000000081723000000000000000000000000000000000000000000000000000000000008172400000000000000000000000000000000000000000000000000000000000817250000000000000000000000000000000000000000000000000000000000081726000000000000000000000000000000000000000000000000000000000008172700000000000000000000000000000000000000000000000000000000000817280000000000000000000000000000000000000000000000000000000000081729000000000000000000000000000000000000000000000000000000000008172a000000000000000000000000000000000000000000000000000000000008172b000000000000000000000000000000000000000000000000000000000008172c000000000000000000000000000000000000000000000000000000000008172d000000000000000000000000000000000000000000000000000000000008172e000000000000000000000000000000000000000000000000000000000008171e000000000000000000000000000000000000000000000000000000000008171f0000000000000000000000000000000000000000000000000000000000081720000000000000000000000000000000000000000000000000000000000008172100000000000000000000000000000000000000000000000000000000000817220000000000000000000000000000000000000000000000000000000000081723000000000000000000000000000000000000000000000000000000000008172400000000000000000000000000000000000000000000000000000000000817250000000000000000000000000000000000000000000000000000000000081726000000000000000000000000000000000000000000000000000000000008172700000000000000000000000000000000000000000000000000000000000817280000000000000000000000000000000000000000000000000000000000081729000000000000000000000000000000000000000000000000000000000008172a000000000000000000000000000000000000000000000000000000000008172b000000000000000000000000000000000000000000000000000000000008172c000000000000000000000000000000000000000000000000000000000008172d000000000000000000000000000000000000000000000000000000000008172e000000000000000000000000000000000000000000000000000000000008172f000000000000000000000000000000000000000000000000000000000008171f0000000000000000000000000000000000000000000000000000000000081720000000000000000000000000000000000000000000000000000000000008172100000000000000000000000000000000000000000000000000000000000817220000000000000000000000000000000000000000000000000000000000081723000000000000000000000000000000000000000000000000000000000008172400000000000000000000000000000000000000000000000000000000000817250000000000000000000000000000000000000000000000000000000000081726000000000000000000000000000000000000000000000000000000000008172700000000000000000000000000000000000000000000000000000000000817280000000000000000000000000000000000000000000000000000000000081729000000000000000000000000000000000000000000000000000000000008172a000000000000000000000000000000000000000000000000000000000008172b000000000000000000000000000000000000000000000000000000000008172c000000000000000000000000000000000000000000000000000000000008172d000000000000000000000000000000000000000000000000000000000008172e000000000000000000000000000000000000000000000000000000000008172f00000000000000000000000000000000000000000000000000000000000817300000000000000000000000000000000000000000000000000000000000081720000000000000000000000000000000000000000000000000000000000008172100000000000000000000000000000000000000000000000000000000000817220000000000000000000000000000000000000000000000000000000000081723000000000000000000000000000000000000000000000000000000000008172400000000000000000000000000000000000000000000000000000000000817250000000000000000000000000000000000000000000000000000000000081726000000000000000000000000000000000000000000000000000000000008172700000000000000000000000000000000000000000000000000000000000817280000000000000000000000000000000000000000000000000000000000081729000000000000000000000000000000000000000000000000000000000008172a000000000000000000000000000000000000000000000000000000000008172b000000000000000000000000000000000000000000000000000000000008172c000000000000000000000000000000000000000000000000000000000008172d000000000000000000000000000000000000000000000000000000000008172e000000000000000000000000000000000000000000000000000000000008172f00000000000000000000000000000000000000000000000000000000000817300000000000000000000000000000000000000000000000000000000000081731000000000000000000000000000000000000000000000000000000000008172100000000000000000000000000000000000000000000000000000000000817220000000000000000000000000000000000000000000000000000000000081723000000000000000000000000000000000000000000000000000000000008172400000000000000000000000000000000000000000000000000000000000817250000000000000000000000000000000000000000000000000000000000081726000000000000000000000000000000000000000000000000000000000008172700000000000000000000000000000000000000000000000000000000000817280000000000000000000000000000000000000000000000000000000000081729000000000000000000000000000000000000000000000000000000000008172a000000000000000000000000000000000000000000000000000000000008172b000000000000000000000000000000000000000000000000000000000008172c000000000000000000000000000000000000000000000000000000000008172d000000000000000000000000000000000000000000000000000000000008172e000000000000000000000000000000000000000000000000000000000008172f00000000000000000000000000000000000000000000000000000000000817300000000000000000000000000000000000000000000000000000000000081731000000000000000000000000000000000000000000000000000000000008173200000000000000000000000000000000000000000000000000000000000817220000000000000000000000000000000000000000000000000000000000081723000000000000000000000000000000000000000000000000000000000008172400000000000000000000000000000000000000000000000000000000000817250000000000000000000000000000000000000000000000000000000000081726000000000000000000000000000000000000000000000000000000000008172700000000000000000000000000000000000000000000000000000000000817280000000000000000000000000000000000000000000000000000000000081729000000000000000000000000000000000000000000000000000000000008172a000000000000000000000000000000000000000000000000000000000008172b000000000000000000000000000000000000000000000000000000000008172c000000000000000000000000000000000000000000000000000000000008172d000000000000000000000000000000000000000000000000000000000008172e000000000000000000000000000000000000000000000000000000000008172f00000000000000000000000000000000000000000000000000000000000817300000000000000000000000000000000000000000000000000000000000081731000000000000000000000000000000000000000000000000000000000008173200000000000000000000000000000000000000000000000000000000000817330000000000000000000000000000000000000000000000000000000000081723000000000000000000000000000000000000000000000000000000000008172400000000000000000000000000000000000000000000000000000000000817250000000000000000000000000000000000000000000000000000000000081726000000000000000000000000000000000000000000000000000000000008172700000000000000000000000000000000000000000000000000000000000817280000000000000000000000000000000000000000000000000000000000081729000000000000000000000000000000000000000000000000000000000008172a000000000000000000000000000000000000000000000000000000000008172b000000000000000000000000000000000000000000000000000000000008172c000000000000000000000000000000000000000000000000000000000008172d000000000000000000000000000000000000000000000000000000000008172e000000000000000000000000000000000000000000000000000000000008172f00000000000000000000000000000000000000000000000000000000000817300000000000000000000000000000000000000000000000000000000000081731000000000000000000000000000000000000000000000000000000000008173200000000000000000000000000000000000000000000000000000000000817330000000000000000000000000000000000000000000000000000000000081734000000000000000000000000000000000000000000000000000000000008172400000000000000000000000000000000000000000000000000000000000817250000000000000000000000000000000000000000000000000000000000081726000000000000000000000000000000000000000000000000000000000008172700000000000000000000000000000000000000000000000000000000000817280000000000000000000000000000000000000000000000000000000000081729000000000000000000000000000000000000000000000000000000000008172a000000000000000000000000000000000000000000000000000000000008172b000000000000000000000000000000000000000000000000000000000008172c000000000000000000000000000000000000000000000000000000000008172d000000000000000000000000000000000000000000000000000000000008172e000000000000000000000000000000000000000000000000000000000008172f00000000000000000000000000000000000000000000000000000000000817300000000000000000000000000000000000000000000000000000000000081731000000000000000000000000000000000000000000000000000000000008173200000000000000000000000000000000000000000000000000000000000817330000000000000000000000000000000000000000000000000000000000081734000000000000000000000000000000000000000000000000000000000008173500000000000000000000000000000000000000000000000000000000000817250000000000000000000000000000000000000000000000000000000000081726000000000000000000000000000000000000000000000000000000000008172700000000000000000000000000000000000000000000000000000000000817280000000000000000000000000000000000000000000000000000000000081729000000000000000000000000000000000000000000000000000000000008172a000000000000000000000000000000000000000000000000000000000008172b000000000000000000000000000000000000000000000000000000000008172c000000000000000000000000000000000000000000000000000000000008172d000000000000000000000000000000000000000000000000000000000008172e000000000000000000000000000000000000000000000000000000000008172f00000000000000000000000000000000000000000000000000000000000817300000000000000000000000000000000000000000000000000000000000081731000000000000000000000000000000000000000000000000000000000008173200000000000000000000000000000000000000000000000000000000000817330000000000000000000000000000000000000000000000000000000000081734000000000000000000000000000000000000000000000000000000000008173500000000000000000000000000000000000000000000000000000000000817360000000000000000000000000000000000000000000000000000000000081726000000000000000000000000000000000000000000000000000000000008172700000000000000000000000000000000000000000000000000000000000817280000000000000000000000000000000000000000000000000000000000081729000000000000000000000000000000000000000000000000000000000008172a000000000000000000000000000000000000000000000000000000000008172b000000000000000000000000000000000000000000000000000000000008172c000000000000000000000000000000000000000000000000000000000008172d000000000000000000000000000000000000000000000000000000000008172e000000000000000000000000000000000000000000000000000000000008172f00000000000000000000000000000000000000000000000000000000000817300000000000000000000000000000000000000000000000000000000000081731000000000000000000000000000000000000000000000000000000000008173200000000000000000000000000000000000000000000000000000000000817330000000000000000000000000000000000000000000000000000000000081734000000000000000000000000000000000000000000000000000000000008173500000000000000000000000000000000000000000000000000000000000817360000000000000000000000000000000000000000000000000000000000081737000000000000000000000000000000000000000000000000000000000008172700000000000000000000000000000000000000000000000000000000000817280000000000000000000000000000000000000000000000000000000000081729000000000000000000000000000000000000000000000000000000000008172a000000000000000000000000000000000000000000000000000000000008172b000000000000000000000000000000000000000000000000000000000008172c000000000000000000000000000000000000000000000000000000000008172d000000000000000000000000000000000000000000000000000000000008172e000000000000000000000000000000000000000000000000000000000008172f00000000000000000000000000000000000000000000000000000000000817300000000000000000000000000000000000000000000000000000000000081731000000000000000000000000000000000000000000000000000000000008173200000000000000000000000000000000000000000000000000000000000817330000000000000000000000000000000000000000000000000000000000081734000000000000000000000000000000000000000000000000000000000008173500000000000000000000000000000000000000000000000000000000000817360000000000000000000000000000000000000000000000000000000000081737000000000000000000000000000000000000000000000000000000000008173800000000000000000000000000000000000000000000000000000000000817280000000000000000000000000000000000000000000000000000000000081729000000000000000000000000000000000000000000000000000000000008172a000000000000000000000000000000000000000000000000000000000008172b000000000000000000000000000000000000000000000000000000000008172c000000000000000000000000000000000000000000000000000000000008172d000000000000000000000000000000000000000000000000000000000008172e000000000000000000000000000000000000000000000000000000000008172f00000000000000000000000000000000000000000000000000000000000817300000000000000000000000000000000000000000000000000000000000081731000000000000000000000000000000000000000000000000000000000008173200000000000000000000000000000000000000000000000000000000000817330000000000000000000000000000000000000000000000000000000000081734000000000000000000000000000000000000000000000000000000000008173500000000000000000000000000000000000000000000000000000000000817360000000000000000000000000000000000000000000000000000000000081737000000000000000000000000000000000000000000000000000000000008173800000000000000000000000000000000000000000000000000000000000817390000000000000000000000000000000000000000000000000000000000081729000000000000000000000000000000000000000000000000000000000008172a000000000000000000000000000000000000000000000000000000000008172b000000000000000000000000000000000000000000000000000000000008172c000000000000000000000000000000000000000000000000000000000008172d000000000000000000000000000000000000000000000000000000000008172e000000000000000000000000000000000000000000000000000000000008172f0000000000000000000000000000000000000000000000000000000000081730000000000000000000000000000000000000000000000000000000000008173100000000000000000000000000000000000000000000000000000000000817320000000000000000000000000000000000000000000000000000000000081733000000000000000000000000000000000000000000000000000000000008173400000000000000000000000000000000000000000000000000000000000817350000000000000000000000000000000000000000000000000000000000081736000000000000000000000000000000000000000000000000000000000008173700000000000000000000000000000000000000000000000000000000000817380000000000000000000000000000000000000000000000000000000000081739000000000000000000000000000000000000000000000000000000000008173a000000000000000000000000000000000000000000000000000000000008172a000000000000000000000000000000000000000000000000000000000008172b000000000000000000000000000000000000000000000000000000000008172c000000000000000000000000000000000000000000000000000000000008172d000000000000000000000000000000000000000000000000000000000008172e000000000000000000000000000000000000000000000000000000000008172f0000000000000000000000000000000000000000000000000000000000081730000000000000000000000000000000000000000000000000000000000008173100000000000000000000000000000000000000000000000000000000000817320000000000000000000000000000000000000000000000000000000000081733000000000000000000000000000000000000000000000000000000000008173400000000000000000000000000000000000000000000000000000000000817350000000000000000000000000000000000000000000000000000000000081736000000000000000000000000000000000000000000000000000000000008173700000000000000000000000000000000000000000000000000000000000817380000000000000000000000000000000000000000000000000000000000081739000000000000000000000000000000000000000000000000000000000008173a000000000000000000000000000000000000000000000000000000000008173b000000000000000000000000000000000000000000000000000000000008172b000000000000000000000000000000000000000000000000000000000008172c000000000000000000000000000000000000000000000000000000000008172d000000000000000000000000000000000000000000000000000000000008172e000000000000000000000000000000000000000000000000000000000008172f0000000000000000000000000000000000000000000000000000000000081730000000000000000000000000000000000000000000000000000000000008173100000000000000000000000000000000000000000000000000000000000817320000000000000000000000000000000000000000000000000000000000081733000000000000000000000000000000000000000000000000000000000008173400000000000000000000000000000000000000000000000000000000000817350000000000000000000000000000000000000000000000000000000000081736000000000000000000000000000000000000000000000000000000000008173700000000000000000000000000000000000000000000000000000000000817380000000000000000000000000000000000000000000000000000000000081739000000000000000000000000000000000000000000000000000000000008173a000000000000000000000000000000000000000000000000000000000008173b000000000000000000000000000000000000000000000000000000000008173c000000000000000000000000000000000000000000000000000000000008172c000000000000000000000000000000000000000000000000000000000008172d000000000000000000000000000000000000000000000000000000000008172e000000000000000000000000000000000000000000000000000000000008172f0000000000000000000000000000000000000000000000000000000000081730000000000000000000000000000000000000000000000000000000000008173100000000000000000000000000000000000000000000000000000000000817320000000000000000000000000000000000000000000000000000000000081733000000000000000000000000000000000000000000000000000000000008173400000000000000000000000000000000000000000000000000000000000817350000000000000000000000000000000000000000000000000000000000081736000000000000000000000000000000000000000000000000000000000008173700000000000000000000000000000000000000000000000000000000000817380000000000000000000000000000000000000000000000000000000000081739000000000000000000000000000000000000000000000000000000000008173a000000000000000000000000000000000000000000000000000000000008173b000000000000000000000000000000000000000000000000000000000008173c000000000000000000000000000000000000000000000000000000000008173d000000000000000000000000000000000000000000000000000000000008172d000000000000000000000000000000000000000000000000000000000008172e000000000000000000000000000000000000000000000000000000000008172f0000000000000000000000000000000000000000000000000000000000081730000000000000000000000000000000000000000000000000000000000008173100000000000000000000000000000000000000000000000000000000000817320000000000000000000000000000000000000000000000000000000000081733000000000000000000000000000000000000000000000000000000000008173400000000000000000000000000000000000000000000000000000000000817350000000000000000000000000000000000000000000000000000000000081736000000000000000000000000000000000000000000000000000000000008173700000000000000000000000000000000000000000000000000000000000817380000000000000000000000000000000000000000000000000000000000081739000000000000000000000000000000000000000000000000000000000008173a000000000000000000000000000000000000000000000000000000000008173b000000000000000000000000000000000000000000000000000000000008173c000000000000000000000000000000000000000000000000000000000008173d000000000000000000000000000000000000000000000000000000000008173e000000000000000000000000000000000000000000000000000000000008172e000000000000000000000000000000000000000000000000000000000008172f0000000000000000000000000000000000000000000000000000000000081730000000000000000000000000000000000000000000000000000000000008173100000000000000000000000000000000000000000000000000000000000817320000000000000000000000000000000000000000000000000000000000081733000000000000000000000000000000000000000000000000000000000008173400000000000000000000000000000000000000000000000000000000000817350000000000000000000000000000000000000000000000000000000000081736000000000000000000000000000000000000000000000000000000000008173700000000000000000000000000000000000000000000000000000000000817380000000000000000000000000000000000000000000000000000000000081739000000000000000000000000000000000000000000000000000000000008173a000000000000000000000000000000000000000000000000000000000008173b000000000000000000000000000000000000000000000000000000000008173c000000000000000000000000000000000000000000000000000000000008173d000000000000000000000000000000000000000000000000000000000008173e000000000000000000000000000000000000000000000000000000000008173f000000000000000000000000000000000000000000000000000000000008172f0000000000000000000000000000000000000000000000000000000000081730000000000000000000000000000000000000000000000000000000000008173100000000000000000000000000000000000000000000000000000000000817320000000000000000000000000000000000000000000000000000000000081733000000000000000000000000000000000000000000000000000000000008173400000000000000000000000000000000000000000000000000000000000817350000000000000000000000000000000000000000000000000000000000081736000000000000000000000000000000000000000000000000000000000008173700000000000000000000000000000000000000000000000000000000000817380000000000000000000000000000000000000000000000000000000000081739000000000000000000000000000000000000000000000000000000000008173a000000000000000000000000000000000000000000000000000000000008173b000000000000000000000000000000000000000000000000000000000008173c000000000000000000000000000000000000000000000000000000000008173d000000000000000000000000000000000000000000000000000000000008173e000000000000000000000000000000000000000000000000000000000008173f00000000000000000000000000000000000000000000000000000000000817400000000000000000000000000000000000000000000000000000000000081730000000000000000000000000000000000000000000000000000000000008173100000000000000000000000000000000000000000000000000000000000817320000000000000000000000000000000000000000000000000000000000081733000000000000000000000000000000000000000000000000000000000008173400000000000000000000000000000000000000000000000000000000000817350000000000000000000000000000000000000000000000000000000000081736000000000000000000000000000000000000000000000000000000000008173700000000000000000000000000000000000000000000000000000000000817380000000000000000000000000000000000000000000000000000000000081739000000000000000000000000000000000000000000000000000000000008173a000000000000000000000000000000000000000000000000000000000008173b000000000000000000000000000000000000000000000000000000000008173c000000000000000000000000000000000000000000000000000000000008173d000000000000000000000000000000000000000000000000000000000008173e000000000000000000000000000000000000000000000000000000000008173f00000000000000000000000000000000000000000000000000000000000817400000000000000000000000000000000000000000000000000000000000081741000000000000000000000000000000000000000000000000000000000008173100000000000000000000000000000000000000000000000000000000000817320000000000000000000000000000000000000000000000000000000000081733000000000000000000000000000000000000000000000000000000000008173400000000000000000000000000000000000000000000000000000000000817350000000000000000000000000000000000000000000000000000000000081736000000000000000000000000000000000000000000000000000000000008173700000000000000000000000000000000000000000000000000000000000817380000000000000000000000000000000000000000000000000000000000081739000000000000000000000000000000000000000000000000000000000008173a000000000000000000000000000000000000000000000000000000000008173b000000000000000000000000000000000000000000000000000000000008173c000000000000000000000000000000000000000000000000000000000008173d000000000000000000000000000000000000000000000000000000000008173e000000000000000000000000000000000000000000000000000000000008173f00000000000000000000000000000000000000000000000000000000000817400000000000000000000000000000000000000000000000000000000000081741000000000000000000000000000000000000000000000000000000000008174200000000000000000000000000000000000000000000000000000000000817320000000000000000000000000000000000000000000000000000000000081733000000000000000000000000000000000000000000000000000000000008173400000000000000000000000000000000000000000000000000000000000817350000000000000000000000000000000000000000000000000000000000081736000000000000000000000000000000000000000000000000000000000008173700000000000000000000000000000000000000000000000000000000000817380000000000000000000000000000000000000000000000000000000000081739000000000000000000000000000000000000000000000000000000000008173a000000000000000000000000000000000000000000000000000000000008173b000000000000000000000000000000000000000000000000000000000008173c000000000000000000000000000000000000000000000000000000000008173d000000000000000000000000000000000000000000000000000000000008173e000000000000000000000000000000000000000000000000000000000008173f00000000000000000000000000000000000000000000000000000000000817400000000000000000000000000000000000000000000000000000000000081741000000000000000000000000000000000000000000000000000000000008174200000000000000000000000000000000000000000000000000000000000817430000000000000000000000000000000000000000000000000000000000081733000000000000000000000000000000000000000000000000000000000008173400000000000000000000000000000000000000000000000000000000000817350000000000000000000000000000000000000000000000000000000000081736000000000000000000000000000000000000000000000000000000000008173700000000000000000000000000000000000000000000000000000000000817380000000000000000000000000000000000000000000000000000000000081739000000000000000000000000000000000000000000000000000000000008173a000000000000000000000000000000000000000000000000000000000008173b000000000000000000000000000000000000000000000000000000000008173c000000000000000000000000000000000000000000000000000000000008173d000000000000000000000000000000000000000000000000000000000008173e000000000000000000000000000000000000000000000000000000000008173f00000000000000000000000000000000000000000000000000000000000817400000000000000000000000000000000000000000000000000000000000081741000000000000000000000000000000000000000000000000000000000008174200000000000000000000000000000000000000000000000000000000000817430000000000000000000000000000000000000000000000000000000000081744000000000000000000000000000000000000000000000000000000000008173400000000000000000000000000000000000000000000000000000000000817350000000000000000000000000000000000000000000000000000000000081736000000000000000000000000000000000000000000000000000000000008173700000000000000000000000000000000000000000000000000000000000817380000000000000000000000000000000000000000000000000000000000081739000000000000000000000000000000000000000000000000000000000008173a000000000000000000000000000000000000000000000000000000000008173b000000000000000000000000000000000000000000000000000000000008173c000000000000000000000000000000000000000000000000000000000008173d000000000000000000000000000000000000000000000000000000000008173e000000000000000000000000000000000000000000000000000000000008173f00000000000000000000000000000000000000000000000000000000000817400000000000000000000000000000000000000000000000000000000000081741000000000000000000000000000000000000000000000000000000000008174200000000000000000000000000000000000000000000000000000000000817430000000000000000000000000000000000000000000000000000000000081744000000000000000000000000000000000000000000000000000000000008174500000000000000000000000000000000000000000000000000000000000817350000000000000000000000000000000000000000000000000000000000081736000000000000000000000000000000000000000000000000000000000008173700000000000000000000000000000000000000000000000000000000000817380000000000000000000000000000000000000000000000000000000000081739000000000000000000000000000000000000000000000000000000000008173a000000000000000000000000000000000000000000000000000000000008173b000000000000000000000000000000000000000000000000000000000008173c000000000000000000000000000000000000000000000000000000000008173d000000000000000000000000000000000000000000000000000000000008173e000000000000000000000000000000000000000000000000000000000008173f00000000000000000000000000000000000000000000000000000000000817400000000000000000000000000000000000000000000000000000000000081741000000000000000000000000000000000000000000000000000000000008174200000000000000000000000000000000000000000000000000000000000817430000000000000000000000000000000000000000000000000000000000081744000000000000000000000000000000000000000000000000000000000008174500000000000000000000000000000000000000000000000000000000000817460000000000000000000000000000000000000000000000000000000000081736000000000000000000000000000000000000000000000000000000000008173700000000000000000000000000000000000000000000000000000000000817380000000000000000000000000000000000000000000000000000000000081739000000000000000000000000000000000000000000000000000000000008173a000000000000000000000000000000000000000000000000000000000008173b000000000000000000000000000000000000000000000000000000000008173c000000000000000000000000000000000000000000000000000000000008173d000000000000000000000000000000000000000000000000000000000008173e000000000000000000000000000000000000000000000000000000000008173f00000000000000000000000000000000000000000000000000000000000817400000000000000000000000000000000000000000000000000000000000081741000000000000000000000000000000000000000000000000000000000008174200000000000000000000000000000000000000000000000000000000000817430000000000000000000000000000000000000000000000000000000000081744000000000000000000000000000000000000000000000000000000000008174500000000000000000000000000000000000000000000000000000000000817460000000000000000000000000000000000000000000000000000000000081747000000000000000000000000000000000000000000000000000000000008173700000000000000000000000000000000000000000000000000000000000817380000000000000000000000000000000000000000000000000000000000081739000000000000000000000000000000000000000000000000000000000008173a000000000000000000000000000000000000000000000000000000000008173b000000000000000000000000000000000000000000000000000000000008173c000000000000000000000000000000000000000000000000000000000008173d000000000000000000000000000000000000000000000000000000000008173e000000000000000000000000000000000000000000000000000000000008173f00000000000000000000000000000000000000000000000000000000000817400000000000000000000000000000000000000000000000000000000000081741000000000000000000000000000000000000000000000000000000000008174200000000000000000000000000000000000000000000000000000000000817430000000000000000000000000000000000000000000000000000000000081744000000000000000000000000000000000000000000000000000000000008174500000000000000000000000000000000000000000000000000000000000817460000000000000000000000000000000000000000000000000000000000081747000000000000000000000000000000000000000000000000000000000008174800000000000000000000000000000000000000000000000000000000000817380000000000000000000000000000000000000000000000000000000000081739000000000000000000000000000000000000000000000000000000000008173a000000000000000000000000000000000000000000000000000000000008173b000000000000000000000000000000000000000000000000000000000008173c000000000000000000000000000000000000000000000000000000000008173d000000000000000000000000000000000000000000000000000000000008173e000000000000000000000000000000000000000000000000000000000008173f00000000000000000000000000000000000000000000000000000000000817400000000000000000000000000000000000000000000000000000000000081741000000000000000000000000000000000000000000000000000000000008174200000000000000000000000000000000000000000000000000000000000817430000000000000000000000000000000000000000000000000000000000081744000000000000000000000000000000000000000000000000000000000008174500000000000000000000000000000000000000000000000000000000000817460000000000000000000000000000000000000000000000000000000000081747000000000000000000000000000000000000000000000000000000000008174800000000000000000000000000000000000000000000000000000000000817490000000000000000000000000000000000000000000000000000000000081739000000000000000000000000000000000000000000000000000000000008173a000000000000000000000000000000000000000000000000000000000008173b000000000000000000000000000000000000000000000000000000000008173c000000000000000000000000000000000000000000000000000000000008173d000000000000000000000000000000000000000000000000000000000008173e000000000000000000000000000000000000000000000000000000000008173f0000000000000000000000000000000000000000000000000000000000081740000000000000000000000000000000000000000000000000000000000008174100000000000000000000000000000000000000000000000000000000000817420000000000000000000000000000000000000000000000000000000000081743000000000000000000000000000000000000000000000000000000000008174400000000000000000000000000000000000000000000000000000000000817450000000000000000000000000000000000000000000000000000000000081746000000000000000000000000000000000000000000000000000000000008174700000000000000000000000000000000000000000000000000000000000817480000000000000000000000000000000000000000000000000000000000081749000000000000000000000000000000000000000000000000000000000008174a000000000000000000000000000000000000000000000000000000000008173a000000000000000000000000000000000000000000000000000000000008173b000000000000000000000000000000000000000000000000000000000008173c000000000000000000000000000000000000000000000000000000000008173d000000000000000000000000000000000000000000000000000000000008173e000000000000000000000000000000000000000000000000000000000008173f0000000000000000000000000000000000000000000000000000000000081740000000000000000000000000000000000000000000000000000000000008174100000000000000000000000000000000000000000000000000000000000817420000000000000000000000000000000000000000000000000000000000081743000000000000000000000000000000000000000000000000000000000008174400000000000000000000000000000000000000000000000000000000000817450000000000000000000000000000000000000000000000000000000000081746000000000000000000000000000000000000000000000000000000000008174700000000000000000000000000000000000000000000000000000000000817480000000000000000000000000000000000000000000000000000000000081749000000000000000000000000000000000000000000000000000000000008174a000000000000000000000000000000000000000000000000000000000008174b000000000000000000000000000000000000000000000000000000000008173b000000000000000000000000000000000000000000000000000000000008173c000000000000000000000000000000000000000000000000000000000008173d000000000000000000000000000000000000000000000000000000000008173e000000000000000000000000000000000000000000000000000000000008173f0000000000000000000000000000000000000000000000000000000000081740000000000000000000000000000000000000000000000000000000000008174100000000000000000000000000000000000000000000000000000000000817420000000000000000000000000000000000000000000000000000000000081743000000000000000000000000000000000000000000000000000000000008174400000000000000000000000000000000000000000000000000000000000817450000000000000000000000000000000000000000000000000000000000081746000000000000000000000000000000000000000000000000000000000008174700000000000000000000000000000000000000000000000000000000000817480000000000000000000000000000000000000000000000000000000000081749000000000000000000000000000000000000000000000000000000000008174a000000000000000000000000000000000000000000000000000000000008174b000000000000000000000000000000000000000000000000000000000008174c000000000000000000000000000000000000000000000000000000000008173c000000000000000000000000000000000000000000000000000000000008173d000000000000000000000000000000000000000000000000000000000008173e000000000000000000000000000000000000000000000000000000000008173f0000000000000000000000000000000000000000000000000000000000081740000000000000000000000000000000000000000000000000000000000008174100000000000000000000000000000000000000000000000000000000000817420000000000000000000000000000000000000000000000000000000000081743000000000000000000000000000000000000000000000000000000000008174400000000000000000000000000000000000000000000000000000000000817450000000000000000000000000000000000000000000000000000000000081746000000000000000000000000000000000000000000000000000000000008174700000000000000000000000000000000000000000000000000000000000817480000000000000000000000000000000000000000000000000000000000081749000000000000000000000000000000000000000000000000000000000008174a000000000000000000000000000000000000000000000000000000000008174b000000000000000000000000000000000000000000000000000000000008174c000000000000000000000000000000000000000000000000000000000008174d000000000000000000000000000000000000000000000000000000000008173d000000000000000000000000000000000000000000000000000000000008173e000000000000000000000000000000000000000000000000000000000008173f0000000000000000000000000000000000000000000000000000000000081740000000000000000000000000000000000000000000000000000000000008174100000000000000000000000000000000000000000000000000000000000817420000000000000000000000000000000000000000000000000000000000081743000000000000000000000000000000000000000000000000000000000008174400000000000000000000000000000000000000000000000000000000000817450000000000000000000000000000000000000000000000000000000000081746000000000000000000000000000000000000000000000000000000000008174700000000000000000000000000000000000000000000000000000000000817480000000000000000000000000000000000000000000000000000000000081749000000000000000000000000000000000000000000000000000000000008174a000000000000000000000000000000000000000000000000000000000008174b000000000000000000000000000000000000000000000000000000000008174c000000000000000000000000000000000000000000000000000000000008174d000000000000000000000000000000000000000000000000000000000008174e000000000000000000000000000000000000000000000000000000000008173e000000000000000000000000000000000000000000000000000000000008173f0000000000000000000000000000000000000000000000000000000000081740000000000000000000000000000000000000000000000000000000000008174100000000000000000000000000000000000000000000000000000000000817420000000000000000000000000000000000000000000000000000000000081743000000000000000000000000000000000000000000000000000000000008174400000000000000000000000000000000000000000000000000000000000817450000000000000000000000000000000000000000000000000000000000081746000000000000000000000000000000000000000000000000000000000008174700000000000000000000000000000000000000000000000000000000000817480000000000000000000000000000000000000000000000000000000000081749000000000000000000000000000000000000000000000000000000000008174a000000000000000000000000000000000000000000000000000000000008174b000000000000000000000000000000000000000000000000000000000008174c000000000000000000000000000000000000000000000000000000000008174d000000000000000000000000000000000000000000000000000000000008174e000000000000000000000000000000000000000000000000000000000008174f000000000000000000000000000000000000000000000000000000000008173f0000000000000000000000000000000000000000000000000000000000081740000000000000000000000000000000000000000000000000000000000008174100000000000000000000000000000000000000000000000000000000000817420000000000000000000000000000000000000000000000000000000000081743000000000000000000000000000000000000000000000000000000000008174400000000000000000000000000000000000000000000000000000000000817450000000000000000000000000000000000000000000000000000000000081746000000000000000000000000000000000000000000000000000000000008174700000000000000000000000000000000000000000000000000000000000817480000000000000000000000000000000000000000000000000000000000081749000000000000000000000000000000000000000000000000000000000008174a000000000000000000000000000000000000000000000000000000000008174b000000000000000000000000000000000000000000000000000000000008174c000000000000000000000000000000000000000000000000000000000008174d000000000000000000000000000000000000000000000000000000000008174e000000000000000000000000000000000000000000000000000000000008174f00000000000000000000000000000000000000000000000000000000000817500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000c100000000000000000000000000000000000000000000000000000000000000c100100000000000000000000000000000000000000000000000000000000000c100200000000000000000000000000000000000000000000000000000000000c100300000000000000000000000000000000000000000000000000000000000c100400000000000000000000000000000000000000000000000000000000000c100500000000000000000000000000000000000000000000000000000000000c100600000000000000000000000000000000000000000000000000000000000c100700000000000000000000000000000000000000000000000000000000000c100800000000000000000000000000000000000000000000000000000000000c100900000000000000000000000000000000000000000000000000000000000c100a00000000000000000000000000000000000000000000000000000000000c100b00000000000000000000000000000000000000000000000000000000000c100c00000000000000000000000000000000000000000000000000000000000c100d00000000000000000000000000000000000000000000000000000000000c100e00000000000000000000000000000000000000000000000000000000000c100f00000000000000000000000000000000000000000000000000000000000c101000000000000000000000000000000000000000000000000000000000000c101100000000000000000000000000000000000000000000000000000000000c101200000000000000000000000000000000000000000000000000000000000c101300000000000000000000000000000000000000000000000000000000000c101400000000000000000000000000000000000000000000000000000000000c101500000000000000000000000000000000000000000000000000000000000c101600000000000000000000000000000000000000000000000000000000000c101700000000000000000000000000000000000000000000000000000000000c101800000000000000000000000000000000000000000000000000000000000c101900000000000000000000000000000000000000000000000000000000000c101a00000000000000000000000000000000000000000000000000000000000c101b00000000000000000000000000000000000000000000000000000000000c101c00000000000000000000000000000000000000000000000000000000000c101d00000000000000000000000000000000000000000000000000000000000c101e00000000000000000000000000000000000000000000000000000000000c101f00000000000000000000000000000000000000000000000000000000000c102000000000000000000000000000000000000000000000000000000000000c102100000000000000000000000000000000000000000000000000000000000c102200000000000000000000000000000000000000000000000000000000000c102300000000000000000000000000000000000000000000000000000000000c102400000000000000000000000000000000000000000000000000000000000c102500000000000000000000000000000000000000000000000000000000000c102600000000000000000000000000000000000000000000000000000000000c102700000000000000000000000000000000000000000000000000000000000c102800000000000000000000000000000000000000000000000000000000000c102900000000000000000000000000000000000000000000000000000000000c102a00000000000000000000000000000000000000000000000000000000000c102b00000000000000000000000000000000000000000000000000000000000c102c00000000000000000000000000000000000000000000000000000000000c102d00000000000000000000000000000000000000000000000000000000000c102e00000000000000000000000000000000000000000000000000000000000c102f00000000000000000000000000000000000000000000000000000000000c103000000000000000000000000000000000000000000000000000000000000c103100000000000000000000000000000000000000000000000000000000000c103200000000000000000000000000000000000000000000000000000000000c103300000000000000000000000000000000000000000000000000000000000c103400000000000000000000000000000000000000000000000000000000000c103500000000000000000000000000000000000000000000000000000000000c103600000000000000000000000000000000000000000000000000000000000c103700000000000000000000000000000000000000000000000000000000000c103800000000000000000000000000000000000000000000000000000000000c103900000000000000000000000000000000000000000000000000000000000c103a00000000000000000000000000000000000000000000000000000000000c103b00000000000000000000000000000000000000000000000000000000000c103c00000000000000000000000000000000000000000000000000000000000c103d00000000000000000000000000000000000000000000000000000000000c103e00000000000000000000000000000000000000000000000000000000000c103f4000000000000000000000000000000000000000000000000000000000000c000100000000000000000000000000000000000000000000000000000000000c110000000000000000000000000000000000000000000000000000000000000c110100000000000000000000000000000000000000000000000000000000000c110200000000000000000000000000000000000000000000000000000000000c110300000000000000000000000000000000000000000000000000000000000c110400000000000000000000000000000000000000000000000000000000000c110500000000000000000000000000000000000000000000000000000000000c110600000000000000000000000000000000000000000000000000000000000c110700000000000000000000000000000000000000000000000000000000000c110800000000000000000000000000000000000000000000000000000000000c110900000000000000000000000000000000000000000000000000000000000c110a00000000000000000000000000000000000000000000000000000000000c110b00000000000000000000000000000000000000000000000000000000000c110c00000000000000000000000000000000000000000000000000000000000c110d00000000000000000000000000000000000000000000000000000000000c110e00000000000000000000000000000000000000000000000000000000000c110f00000000000000000000000000000000000000000000000000000000000c111000000000000000000000000000000000000000000000000000000000000c111100000000000000000000000000000000000000000000000000000000000c111200000000000000000000000000000000000000000000000000000000000c111300000000000000000000000000000000000000000000000000000000000c111400000000000000000000000000000000000000000000000000000000000c111500000000000000000000000000000000000000000000000000000000000c111600000000000000000000000000000000000000000000000000000000000c111700000000000000000000000000000000000000000000000000000000000c111800000000000000000000000000000000000000000000000000000000000c111900000000000000000000000000000000000000000000000000000000000c111a00000000000000000000000000000000000000000000000000000000000c111b00000000000000000000000000000000000000000000000000000000000c111c00000000000000000000000000000000000000000000000000000000000c111d00000000000000000000000000000000000000000000000000000000000c111e00000000000000000000000000000000000000000000000000000000000c111f00000000000000000000000000000000000000000000000000000000000c112000000000000000000000000000000000000000000000000000000000000c112100000000000000000000000000000000000000000000000000000000000c112200000000000000000000000000000000000000000000000000000000000c112300000000000000000000000000000000000000000000000000000000000c112400000000000000000000000000000000000000000000000000000000000c112500000000000000000000000000000000000000000000000000000000000c112600000000000000000000000000000000000000000000000000000000000c112700000000000000000000000000000000000000000000000000000000000c112800000000000000000000000000000000000000000000000000000000000c112900000000000000000000000000000000000000000000000000000000000c112a00000000000000000000000000000000000000000000000000000000000c112b00000000000000000000000000000000000000000000000000000000000c112c00000000000000000000000000000000000000000000000000000000000c112d00000000000000000000000000000000000000000000000000000000000c112e00000000000000000000000000000000000000000000000000000000000c112f00000000000000000000000000000000000000000000000000000000000c113000000000000000000000000000000000000000000000000000000000000c113100000000000000000000000000000000000000000000000000000000000c113200000000000000000000000000000000000000000000000000000000000c113300000000000000000000000000000000000000000000000000000000000c113400000000000000000000000000000000000000000000000000000000000c113500000000000000000000000000000000000000000000000000000000000c113600000000000000000000000000000000000000000000000000000000000c113700000000000000000000000000000000000000000000000000000000000c113800000000000000000000000000000000000000000000000000000000000c113900000000000000000000000000000000000000000000000000000000000c113a00000000000000000000000000000000000000000000000000000000000c113b00000000000000000000000000000000000000000000000000000000000c113c00000000000000000000000000000000000000000000000000000000000c113d00000000000000000000000000000000000000000000000000000000000c113e0800f8029be42ec3f25204907ca981fb71e5b357093eb5db10fc01ca98a4e4154c0030e13d351a5bf1d5a040e82a163ca57017f39162693f85c571e441e36d702d00a550ae0f39f977d9473d6de1be3232fc68ed0c4a601d53542148695102cfc9005580bc65e4bff9c8fffa64db02c0fa6af14d9d26fd962f4c5904cbd3ddec2500758c4a0d43dfec788b2f580877c4f473adec8f168ea24424f2600e4eb4916f00342602bf90d10f8ca8e582a894dcc4c02bb89fe458532e0c632b53bae54b4d00ca43ab78ab834337e9964d84a0674c9adabdca140539c5a6bc96e0ba9a51f6004ffbfd91be292a7c6a0e255e50caa156ac2d628b40ad2128c4ab63a92d8a1c3f00000000000000000000000000000000000000000000000000000000000c200000000000000000000000000000000000000000000000000000000000000c200a00000000000000000000000000000000000000000000000000000000000c200100000000000000000000000000000000000000000000000000000000000c200b00000000000000000000000000000000000000000000000000000000000c200200000000000000000000000000000000000000000000000000000000000c200c00000000000000000000000000000000000000000000000000000000000c200300000000000000000000000000000000000000000000000000000000000c200d00000000000000000000000000000000000000000000000000000000000c200400000000000000000000000000000000000000000000000000000000000c200e00000000000000000000000000000000000000000000000000000000000c200500000000000000000000000000000000000000000000000000000000000c200f00000000000000000000000000000000000000000000000000000000000c200600000000000000000000000000000000000000000000000000000000000c201000000000000000000000000000000000000000000000000000000000000c200700000000000000000000000000000000000000000000000000000000000c201100000000000000000000000000000000000000000000000000000000000c200800000000000000000000000000000000000000000000000000000000000c201200000000000000000000000000000000000000000000000000000000000c200900000000000000000000000000000000000000000000000000000000000c201300000000000000000000000000000000000000000000000000000000000c200a00000000000000000000000000000000000000000000000000000000000c201400000000000000000000000000000000000000000000000000000000000c200b00000000000000000000000000000000000000000000000000000000000c201500000000000000000000000000000000000000000000000000000000000c200c00000000000000000000000000000000000000000000000000000000000c201600000000000000000000000000000000000000000000000000000000000c200d00000000000000000000000000000000000000000000000000000000000c201700000000000000000000000000000000000000000000000000000000000c200e00000000000000000000000000000000000000000000000000000000000c201800000000000000000000000000000000000000000000000000000000000c200f00000000000000000000000000000000000000000000000000000000000c201900000000000000000000000000000000000000000000000000000000000c201000000000000000000000000000000000000000000000000000000000000c201a00000000000000000000000000000000000000000000000000000000000c201100000000000000000000000000000000000000000000000000000000000c201b00000000000000000000000000000000000000000000000000000000000c201200000000000000000000000000000000000000000000000000000000000c201c00000000000000000000000000000000000000000000000000000000000c201300000000000000000000000000000000000000000000000000000000000c201d00000000000000000000000000000000000000000000000000000000000c201400000000000000000000000000000000000000000000000000000000000c201e00000000000000000000000000000000000000000000000000000000000c201500000000000000000000000000000000000000000000000000000000000c201f00000000000000000000000000000000000000000000000000000000000c201600000000000000000000000000000000000000000000000000000000000c202000000000000000000000000000000000000000000000000000000000000c201700000000000000000000000000000000000000000000000000000000000c202100000000000000000000000000000000000000000000000000000000000c201800000000000000000000000000000000000000000000000000000000000c202200000000000000000000000000000000000000000000000000000000000c201900000000000000000000000000000000000000000000000000000000000c202300000000000000000000000000000000000000000000000000000000000c201a00000000000000000000000000000000000000000000000000000000000c202400000000000000000000000000000000000000000000000000000000000c201b00000000000000000000000000000000000000000000000000000000000c202500000000000000000000000000000000000000000000000000000000000c201c00000000000000000000000000000000000000000000000000000000000c202600000000000000000000000000000000000000000000000000000000000c201d00000000000000000000000000000000000000000000000000000000000c202700000000000000000000000000000000000000000000000000000000000c201e00000000000000000000000000000000000000000000000000000000000c202800000000000000000000000000000000000000000000000000000000000c201f00000000000000000000000000000000000000000000000000000000000c202900000000000000000000000000000000000000000000000000000000000c202000000000000000000000000000000000000000000000000000000000000c202a00000000000000000000000000000000000000000000000000000000000c202100000000000000000000000000000000000000000000000000000000000c202b00000000000000000000000000000000000000000000000000000000000c202200000000000000000000000000000000000000000000000000000000000c202c00000000000000000000000000000000000000000000000000000000000c202300000000000000000000000000000000000000000000000000000000000c202d00000000000000000000000000000000000000000000000000000000000c202400000000000000000000000000000000000000000000000000000000000c202e00000000000000000000000000000000000000000000000000000000000c202500000000000000000000000000000000000000000000000000000000000c202f00000000000000000000000000000000000000000000000000000000000c202600000000000000000000000000000000000000000000000000000000000c203000000000000000000000000000000000000000000000000000000000000c202700000000000000000000000000000000000000000000000000000000000c203100000000000000000000000000000000000000000000000000000000000c202800000000000000000000000000000000000000000000000000000000000c203200000000000000000000000000000000000000000000000000000000000c202900000000000000000000000000000000000000000000000000000000000c203300000000000000000000000000000000000000000000000000000000000c202a00000000000000000000000000000000000000000000000000000000000c203400000000000000000000000000000000000000000000000000000000000c202b00000000000000000000000000000000000000000000000000000000000c203500000000000000000000000000000000000000000000000000000000000c202c00000000000000000000000000000000000000000000000000000000000c203600000000000000000000000000000000000000000000000000000000000c202d00000000000000000000000000000000000000000000000000000000000c203700000000000000000000000000000000000000000000000000000000000c202e00000000000000000000000000000000000000000000000000000000000c203800000000000000000000000000000000000000000000000000000000000c202f00000000000000000000000000000000000000000000000000000000000c203900000000000000000000000000000000000000000000000000000000000c203000000000000000000000000000000000000000000000000000000000000c203a00000000000000000000000000000000000000000000000000000000000c203100000000000000000000000000000000000000000000000000000000000c203b00000000000000000000000000000000000000000000000000000000000c203200000000000000000000000000000000000000000000000000000000000c203c00000000000000000000000000000000000000000000000000000000000c203300000000000000000000000000000000000000000000000000000000000c203d00000000000000000000000000000000000000000000000000000000000c203400000000000000000000000000000000000000000000000000000000000c203e00000000000000000000000000000000000000000000000000000000000c203500000000000000000000000000000000000000000000000000000000000c203f00000000000000000000000000000000000000000000000000000000000c203600000000000000000000000000000000000000000000000000000000000c204000000000000000000000000000000000000000000000000000000000000c203700000000000000000000000000000000000000000000000000000000000c204100000000000000000000000000000000000000000000000000000000000c203800000000000000000000000000000000000000000000000000000000000c204200000000000000000000000000000000000000000000000000000000000c203900000000000000000000000000000000000000000000000000000000000c204300000000000000000000000000000000000000000000000000000000000c203a00000000000000000000000000000000000000000000000000000000000c204400000000000000000000000000000000000000000000000000000000000c203b00000000000000000000000000000000000000000000000000000000000c204500000000000000000000000000000000000000000000000000000000000c203c00000000000000000000000000000000000000000000000000000000000c204600000000000000000000000000000000000000000000000000000000000c203d00000000000000000000000000000000000000000000000000000000000c204700000000000000000000000000000000000000000000000000000000000c203e00000000000000000000000000000000000000000000000000000000000c20484000000000000000000000000000000000000000000000000000000000000c170000000000000000000000000000000000000000000000000000000000000c170100000000000000000000000000000000000000000000000000000000000c170200000000000000000000000000000000000000000000000000000000000c170300000000000000000000000000000000000000000000000000000000000c170400000000000000000000000000000000000000000000000000000000000c170500000000000000000000000000000000000000000000000000000000000c170600000000000000000000000000000000000000000000000000000000000c170700000000000000000000000000000000000000000000000000000000000c170800000000000000000000000000000000000000000000000000000000000c170900000000000000000000000000000000000000000000000000000000000c170a00000000000000000000000000000000000000000000000000000000000c170b00000000000000000000000000000000000000000000000000000000000c170c00000000000000000000000000000000000000000000000000000000000c170d00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c170100000000000000000000000000000000000000000000000000000000000c170200000000000000000000000000000000000000000000000000000000000c170300000000000000000000000000000000000000000000000000000000000c170400000000000000000000000000000000000000000000000000000000000c170500000000000000000000000000000000000000000000000000000000000c170600000000000000000000000000000000000000000000000000000000000c170700000000000000000000000000000000000000000000000000000000000c170800000000000000000000000000000000000000000000000000000000000c170900000000000000000000000000000000000000000000000000000000000c170a00000000000000000000000000000000000000000000000000000000000c170b00000000000000000000000000000000000000000000000000000000000c170c00000000000000000000000000000000000000000000000000000000000c170d00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c170200000000000000000000000000000000000000000000000000000000000c170300000000000000000000000000000000000000000000000000000000000c170400000000000000000000000000000000000000000000000000000000000c170500000000000000000000000000000000000000000000000000000000000c170600000000000000000000000000000000000000000000000000000000000c170700000000000000000000000000000000000000000000000000000000000c170800000000000000000000000000000000000000000000000000000000000c170900000000000000000000000000000000000000000000000000000000000c170a00000000000000000000000000000000000000000000000000000000000c170b00000000000000000000000000000000000000000000000000000000000c170c00000000000000000000000000000000000000000000000000000000000c170d00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c170300000000000000000000000000000000000000000000000000000000000c170400000000000000000000000000000000000000000000000000000000000c170500000000000000000000000000000000000000000000000000000000000c170600000000000000000000000000000000000000000000000000000000000c170700000000000000000000000000000000000000000000000000000000000c170800000000000000000000000000000000000000000000000000000000000c170900000000000000000000000000000000000000000000000000000000000c170a00000000000000000000000000000000000000000000000000000000000c170b00000000000000000000000000000000000000000000000000000000000c170c00000000000000000000000000000000000000000000000000000000000c170d00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c170400000000000000000000000000000000000000000000000000000000000c170500000000000000000000000000000000000000000000000000000000000c170600000000000000000000000000000000000000000000000000000000000c170700000000000000000000000000000000000000000000000000000000000c170800000000000000000000000000000000000000000000000000000000000c170900000000000000000000000000000000000000000000000000000000000c170a00000000000000000000000000000000000000000000000000000000000c170b00000000000000000000000000000000000000000000000000000000000c170c00000000000000000000000000000000000000000000000000000000000c170d00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c170500000000000000000000000000000000000000000000000000000000000c170600000000000000000000000000000000000000000000000000000000000c170700000000000000000000000000000000000000000000000000000000000c170800000000000000000000000000000000000000000000000000000000000c170900000000000000000000000000000000000000000000000000000000000c170a00000000000000000000000000000000000000000000000000000000000c170b00000000000000000000000000000000000000000000000000000000000c170c00000000000000000000000000000000000000000000000000000000000c170d00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c170600000000000000000000000000000000000000000000000000000000000c170700000000000000000000000000000000000000000000000000000000000c170800000000000000000000000000000000000000000000000000000000000c170900000000000000000000000000000000000000000000000000000000000c170a00000000000000000000000000000000000000000000000000000000000c170b00000000000000000000000000000000000000000000000000000000000c170c00000000000000000000000000000000000000000000000000000000000c170d00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c170700000000000000000000000000000000000000000000000000000000000c170800000000000000000000000000000000000000000000000000000000000c170900000000000000000000000000000000000000000000000000000000000c170a00000000000000000000000000000000000000000000000000000000000c170b00000000000000000000000000000000000000000000000000000000000c170c00000000000000000000000000000000000000000000000000000000000c170d00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c170800000000000000000000000000000000000000000000000000000000000c170900000000000000000000000000000000000000000000000000000000000c170a00000000000000000000000000000000000000000000000000000000000c170b00000000000000000000000000000000000000000000000000000000000c170c00000000000000000000000000000000000000000000000000000000000c170d00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c170900000000000000000000000000000000000000000000000000000000000c170a00000000000000000000000000000000000000000000000000000000000c170b00000000000000000000000000000000000000000000000000000000000c170c00000000000000000000000000000000000000000000000000000000000c170d00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c170a00000000000000000000000000000000000000000000000000000000000c170b00000000000000000000000000000000000000000000000000000000000c170c00000000000000000000000000000000000000000000000000000000000c170d00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c170b00000000000000000000000000000000000000000000000000000000000c170c00000000000000000000000000000000000000000000000000000000000c170d00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c170c00000000000000000000000000000000000000000000000000000000000c170d00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c170d00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c170e00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c170f00000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c171000000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c171100000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c171200000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c171300000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c171400000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c171500000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c171600000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c172700000000000000000000000000000000000000000000000000000000000c171700000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c172700000000000000000000000000000000000000000000000000000000000c172800000000000000000000000000000000000000000000000000000000000c171800000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c172700000000000000000000000000000000000000000000000000000000000c172800000000000000000000000000000000000000000000000000000000000c172900000000000000000000000000000000000000000000000000000000000c171900000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c172700000000000000000000000000000000000000000000000000000000000c172800000000000000000000000000000000000000000000000000000000000c172900000000000000000000000000000000000000000000000000000000000c172a00000000000000000000000000000000000000000000000000000000000c171a00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c172700000000000000000000000000000000000000000000000000000000000c172800000000000000000000000000000000000000000000000000000000000c172900000000000000000000000000000000000000000000000000000000000c172a00000000000000000000000000000000000000000000000000000000000c172b00000000000000000000000000000000000000000000000000000000000c171b00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c172700000000000000000000000000000000000000000000000000000000000c172800000000000000000000000000000000000000000000000000000000000c172900000000000000000000000000000000000000000000000000000000000c172a00000000000000000000000000000000000000000000000000000000000c172b00000000000000000000000000000000000000000000000000000000000c172c00000000000000000000000000000000000000000000000000000000000c171c00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c172700000000000000000000000000000000000000000000000000000000000c172800000000000000000000000000000000000000000000000000000000000c172900000000000000000000000000000000000000000000000000000000000c172a00000000000000000000000000000000000000000000000000000000000c172b00000000000000000000000000000000000000000000000000000000000c172c00000000000000000000000000000000000000000000000000000000000c172d00000000000000000000000000000000000000000000000000000000000c171d00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c172700000000000000000000000000000000000000000000000000000000000c172800000000000000000000000000000000000000000000000000000000000c172900000000000000000000000000000000000000000000000000000000000c172a00000000000000000000000000000000000000000000000000000000000c172b00000000000000000000000000000000000000000000000000000000000c172c00000000000000000000000000000000000000000000000000000000000c172d00000000000000000000000000000000000000000000000000000000000c172e00000000000000000000000000000000000000000000000000000000000c171e00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c172700000000000000000000000000000000000000000000000000000000000c172800000000000000000000000000000000000000000000000000000000000c172900000000000000000000000000000000000000000000000000000000000c172a00000000000000000000000000000000000000000000000000000000000c172b00000000000000000000000000000000000000000000000000000000000c172c00000000000000000000000000000000000000000000000000000000000c172d00000000000000000000000000000000000000000000000000000000000c172e00000000000000000000000000000000000000000000000000000000000c172f00000000000000000000000000000000000000000000000000000000000c171f00000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c172700000000000000000000000000000000000000000000000000000000000c172800000000000000000000000000000000000000000000000000000000000c172900000000000000000000000000000000000000000000000000000000000c172a00000000000000000000000000000000000000000000000000000000000c172b00000000000000000000000000000000000000000000000000000000000c172c00000000000000000000000000000000000000000000000000000000000c172d00000000000000000000000000000000000000000000000000000000000c172e00000000000000000000000000000000000000000000000000000000000c172f00000000000000000000000000000000000000000000000000000000000c173000000000000000000000000000000000000000000000000000000000000c172000000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c172700000000000000000000000000000000000000000000000000000000000c172800000000000000000000000000000000000000000000000000000000000c172900000000000000000000000000000000000000000000000000000000000c172a00000000000000000000000000000000000000000000000000000000000c172b00000000000000000000000000000000000000000000000000000000000c172c00000000000000000000000000000000000000000000000000000000000c172d00000000000000000000000000000000000000000000000000000000000c172e00000000000000000000000000000000000000000000000000000000000c172f00000000000000000000000000000000000000000000000000000000000c173000000000000000000000000000000000000000000000000000000000000c173100000000000000000000000000000000000000000000000000000000000c172100000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c172700000000000000000000000000000000000000000000000000000000000c172800000000000000000000000000000000000000000000000000000000000c172900000000000000000000000000000000000000000000000000000000000c172a00000000000000000000000000000000000000000000000000000000000c172b00000000000000000000000000000000000000000000000000000000000c172c00000000000000000000000000000000000000000000000000000000000c172d00000000000000000000000000000000000000000000000000000000000c172e00000000000000000000000000000000000000000000000000000000000c172f00000000000000000000000000000000000000000000000000000000000c173000000000000000000000000000000000000000000000000000000000000c173100000000000000000000000000000000000000000000000000000000000c173200000000000000000000000000000000000000000000000000000000000c172200000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c172700000000000000000000000000000000000000000000000000000000000c172800000000000000000000000000000000000000000000000000000000000c172900000000000000000000000000000000000000000000000000000000000c172a00000000000000000000000000000000000000000000000000000000000c172b00000000000000000000000000000000000000000000000000000000000c172c00000000000000000000000000000000000000000000000000000000000c172d00000000000000000000000000000000000000000000000000000000000c172e00000000000000000000000000000000000000000000000000000000000c172f00000000000000000000000000000000000000000000000000000000000c173000000000000000000000000000000000000000000000000000000000000c173100000000000000000000000000000000000000000000000000000000000c173200000000000000000000000000000000000000000000000000000000000c173300000000000000000000000000000000000000000000000000000000000c172300000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c172700000000000000000000000000000000000000000000000000000000000c172800000000000000000000000000000000000000000000000000000000000c172900000000000000000000000000000000000000000000000000000000000c172a00000000000000000000000000000000000000000000000000000000000c172b00000000000000000000000000000000000000000000000000000000000c172c00000000000000000000000000000000000000000000000000000000000c172d00000000000000000000000000000000000000000000000000000000000c172e00000000000000000000000000000000000000000000000000000000000c172f00000000000000000000000000000000000000000000000000000000000c173000000000000000000000000000000000000000000000000000000000000c173100000000000000000000000000000000000000000000000000000000000c173200000000000000000000000000000000000000000000000000000000000c173300000000000000000000000000000000000000000000000000000000000c173400000000000000000000000000000000000000000000000000000000000c172400000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c172700000000000000000000000000000000000000000000000000000000000c172800000000000000000000000000000000000000000000000000000000000c172900000000000000000000000000000000000000000000000000000000000c172a00000000000000000000000000000000000000000000000000000000000c172b00000000000000000000000000000000000000000000000000000000000c172c00000000000000000000000000000000000000000000000000000000000c172d00000000000000000000000000000000000000000000000000000000000c172e00000000000000000000000000000000000000000000000000000000000c172f00000000000000000000000000000000000000000000000000000000000c173000000000000000000000000000000000000000000000000000000000000c173100000000000000000000000000000000000000000000000000000000000c173200000000000000000000000000000000000000000000000000000000000c173300000000000000000000000000000000000000000000000000000000000c173400000000000000000000000000000000000000000000000000000000000c173500000000000000000000000000000000000000000000000000000000000c172500000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c172700000000000000000000000000000000000000000000000000000000000c172800000000000000000000000000000000000000000000000000000000000c172900000000000000000000000000000000000000000000000000000000000c172a00000000000000000000000000000000000000000000000000000000000c172b00000000000000000000000000000000000000000000000000000000000c172c00000000000000000000000000000000000000000000000000000000000c172d00000000000000000000000000000000000000000000000000000000000c172e00000000000000000000000000000000000000000000000000000000000c172f00000000000000000000000000000000000000000000000000000000000c173000000000000000000000000000000000000000000000000000000000000c173100000000000000000000000000000000000000000000000000000000000c173200000000000000000000000000000000000000000000000000000000000c173300000000000000000000000000000000000000000000000000000000000c173400000000000000000000000000000000000000000000000000000000000c173500000000000000000000000000000000000000000000000000000000000c173600000000000000000000000000000000000000000000000000000000000c172600000000000000000000000000000000000000000000000000000000000c172700000000000000000000000000000000000000000000000000000000000c172800000000000000000000000000000000000000000000000000000000000c172900000000000000000000000000000000000000000000000000000000000c172a00000000000000000000000000000000000000000000000000000000000c172b00000000000000000000000000000000000000000000000000000000000c172c00000000000000000000000000000000000000000000000000000000000c172d00000000000000000000000000000000000000000000000000000000000c172e00000000000000000000000000000000000000000000000000000000000c172f00000000000000000000000000000000000000000000000000000000000c173000000000000000000000000000000000000000000000000000000000000c173100000000000000000000000000000000000000000000000000000000000c173200000000000000000000000000000000000000000000000000000000000c173300000000000000000000000000000000000000000000000000000000000c173400000000000000000000000000000000000000000000000000000000000c173500000000000000000000000000000000000000000000000000000000000c173600000000000000000000000000000000000000000000000000000000000c173700000000000000000000000000000000000000000000000000000000000c172700000000000000000000000000000000000000000000000000000000000c172800000000000000000000000000000000000000000000000000000000000c172900000000000000000000000000000000000000000000000000000000000c172a00000000000000000000000000000000000000000000000000000000000c172b00000000000000000000000000000000000000000000000000000000000c172c00000000000000000000000000000000000000000000000000000000000c172d00000000000000000000000000000000000000000000000000000000000c172e00000000000000000000000000000000000000000000000000000000000c172f00000000000000000000000000000000000000000000000000000000000c173000000000000000000000000000000000000000000000000000000000000c173100000000000000000000000000000000000000000000000000000000000c173200000000000000000000000000000000000000000000000000000000000c173300000000000000000000000000000000000000000000000000000000000c173400000000000000000000000000000000000000000000000000000000000c173500000000000000000000000000000000000000000000000000000000000c173600000000000000000000000000000000000000000000000000000000000c173700000000000000000000000000000000000000000000000000000000000c173800000000000000000000000000000000000000000000000000000000000c172800000000000000000000000000000000000000000000000000000000000c172900000000000000000000000000000000000000000000000000000000000c172a00000000000000000000000000000000000000000000000000000000000c172b00000000000000000000000000000000000000000000000000000000000c172c00000000000000000000000000000000000000000000000000000000000c172d00000000000000000000000000000000000000000000000000000000000c172e00000000000000000000000000000000000000000000000000000000000c172f00000000000000000000000000000000000000000000000000000000000c173000000000000000000000000000000000000000000000000000000000000c173100000000000000000000000000000000000000000000000000000000000c173200000000000000000000000000000000000000000000000000000000000c173300000000000000000000000000000000000000000000000000000000000c173400000000000000000000000000000000000000000000000000000000000c173500000000000000000000000000000000000000000000000000000000000c173600000000000000000000000000000000000000000000000000000000000c173700000000000000000000000000000000000000000000000000000000000c173800000000000000000000000000000000000000000000000000000000000c173900000000000000000000000000000000000000000000000000000000000c172900000000000000000000000000000000000000000000000000000000000c172a00000000000000000000000000000000000000000000000000000000000c172b00000000000000000000000000000000000000000000000000000000000c172c00000000000000000000000000000000000000000000000000000000000c172d00000000000000000000000000000000000000000000000000000000000c172e00000000000000000000000000000000000000000000000000000000000c172f00000000000000000000000000000000000000000000000000000000000c173000000000000000000000000000000000000000000000000000000000000c173100000000000000000000000000000000000000000000000000000000000c173200000000000000000000000000000000000000000000000000000000000c173300000000000000000000000000000000000000000000000000000000000c173400000000000000000000000000000000000000000000000000000000000c173500000000000000000000000000000000000000000000000000000000000c173600000000000000000000000000000000000000000000000000000000000c173700000000000000000000000000000000000000000000000000000000000c173800000000000000000000000000000000000000000000000000000000000c173900000000000000000000000000000000000000000000000000000000000c173a00000000000000000000000000000000000000000000000000000000000c172a00000000000000000000000000000000000000000000000000000000000c172b00000000000000000000000000000000000000000000000000000000000c172c00000000000000000000000000000000000000000000000000000000000c172d00000000000000000000000000000000000000000000000000000000000c172e00000000000000000000000000000000000000000000000000000000000c172f00000000000000000000000000000000000000000000000000000000000c173000000000000000000000000000000000000000000000000000000000000c173100000000000000000000000000000000000000000000000000000000000c173200000000000000000000000000000000000000000000000000000000000c173300000000000000000000000000000000000000000000000000000000000c173400000000000000000000000000000000000000000000000000000000000c173500000000000000000000000000000000000000000000000000000000000c173600000000000000000000000000000000000000000000000000000000000c173700000000000000000000000000000000000000000000000000000000000c173800000000000000000000000000000000000000000000000000000000000c173900000000000000000000000000000000000000000000000000000000000c173a00000000000000000000000000000000000000000000000000000000000c173b00000000000000000000000000000000000000000000000000000000000c172b00000000000000000000000000000000000000000000000000000000000c172c00000000000000000000000000000000000000000000000000000000000c172d00000000000000000000000000000000000000000000000000000000000c172e00000000000000000000000000000000000000000000000000000000000c172f00000000000000000000000000000000000000000000000000000000000c173000000000000000000000000000000000000000000000000000000000000c173100000000000000000000000000000000000000000000000000000000000c173200000000000000000000000000000000000000000000000000000000000c173300000000000000000000000000000000000000000000000000000000000c173400000000000000000000000000000000000000000000000000000000000c173500000000000000000000000000000000000000000000000000000000000c173600000000000000000000000000000000000000000000000000000000000c173700000000000000000000000000000000000000000000000000000000000c173800000000000000000000000000000000000000000000000000000000000c173900000000000000000000000000000000000000000000000000000000000c173a00000000000000000000000000000000000000000000000000000000000c173b00000000000000000000000000000000000000000000000000000000000c173c00000000000000000000000000000000000000000000000000000000000c172c00000000000000000000000000000000000000000000000000000000000c172d00000000000000000000000000000000000000000000000000000000000c172e00000000000000000000000000000000000000000000000000000000000c172f00000000000000000000000000000000000000000000000000000000000c173000000000000000000000000000000000000000000000000000000000000c173100000000000000000000000000000000000000000000000000000000000c173200000000000000000000000000000000000000000000000000000000000c173300000000000000000000000000000000000000000000000000000000000c173400000000000000000000000000000000000000000000000000000000000c173500000000000000000000000000000000000000000000000000000000000c173600000000000000000000000000000000000000000000000000000000000c173700000000000000000000000000000000000000000000000000000000000c173800000000000000000000000000000000000000000000000000000000000c173900000000000000000000000000000000000000000000000000000000000c173a00000000000000000000000000000000000000000000000000000000000c173b00000000000000000000000000000000000000000000000000000000000c173c00000000000000000000000000000000000000000000000000000000000c173d00000000000000000000000000000000000000000000000000000000000c172d00000000000000000000000000000000000000000000000000000000000c172e00000000000000000000000000000000000000000000000000000000000c172f00000000000000000000000000000000000000000000000000000000000c173000000000000000000000000000000000000000000000000000000000000c173100000000000000000000000000000000000000000000000000000000000c173200000000000000000000000000000000000000000000000000000000000c173300000000000000000000000000000000000000000000000000000000000c173400000000000000000000000000000000000000000000000000000000000c173500000000000000000000000000000000000000000000000000000000000c173600000000000000000000000000000000000000000000000000000000000c173700000000000000000000000000000000000000000000000000000000000c173800000000000000000000000000000000000000000000000000000000000c173900000000000000000000000000000000000000000000000000000000000c173a00000000000000000000000000000000000000000000000000000000000c173b00000000000000000000000000000000000000000000000000000000000c173c00000000000000000000000000000000000000000000000000000000000c173d00000000000000000000000000000000000000000000000000000000000c173e00000000000000000000000000000000000000000000000000000000000c172e00000000000000000000000000000000000000000000000000000000000c172f00000000000000000000000000000000000000000000000000000000000c173000000000000000000000000000000000000000000000000000000000000c173100000000000000000000000000000000000000000000000000000000000c173200000000000000000000000000000000000000000000000000000000000c173300000000000000000000000000000000000000000000000000000000000c173400000000000000000000000000000000000000000000000000000000000c173500000000000000000000000000000000000000000000000000000000000c173600000000000000000000000000000000000000000000000000000000000c173700000000000000000000000000000000000000000000000000000000000c173800000000000000000000000000000000000000000000000000000000000c173900000000000000000000000000000000000000000000000000000000000c173a00000000000000000000000000000000000000000000000000000000000c173b00000000000000000000000000000000000000000000000000000000000c173c00000000000000000000000000000000000000000000000000000000000c173d00000000000000000000000000000000000000000000000000000000000c173e00000000000000000000000000000000000000000000000000000000000c173f00000000000000000000000000000000000000000000000000000000000c172f00000000000000000000000000000000000000000000000000000000000c173000000000000000000000000000000000000000000000000000000000000c173100000000000000000000000000000000000000000000000000000000000c173200000000000000000000000000000000000000000000000000000000000c173300000000000000000000000000000000000000000000000000000000000c173400000000000000000000000000000000000000000000000000000000000c173500000000000000000000000000000000000000000000000000000000000c173600000000000000000000000000000000000000000000000000000000000c173700000000000000000000000000000000000000000000000000000000000c173800000000000000000000000000000000000000000000000000000000000c173900000000000000000000000000000000000000000000000000000000000c173a00000000000000000000000000000000000000000000000000000000000c173b00000000000000000000000000000000000000000000000000000000000c173c00000000000000000000000000000000000000000000000000000000000c173d00000000000000000000000000000000000000000000000000000000000c173e00000000000000000000000000000000000000000000000000000000000c173f00000000000000000000000000000000000000000000000000000000000c174000000000000000000000000000000000000000000000000000000000000c173000000000000000000000000000000000000000000000000000000000000c173100000000000000000000000000000000000000000000000000000000000c173200000000000000000000000000000000000000000000000000000000000c173300000000000000000000000000000000000000000000000000000000000c173400000000000000000000000000000000000000000000000000000000000c173500000000000000000000000000000000000000000000000000000000000c173600000000000000000000000000000000000000000000000000000000000c173700000000000000000000000000000000000000000000000000000000000c173800000000000000000000000000000000000000000000000000000000000c173900000000000000000000000000000000000000000000000000000000000c173a00000000000000000000000000000000000000000000000000000000000c173b00000000000000000000000000000000000000000000000000000000000c173c00000000000000000000000000000000000000000000000000000000000c173d00000000000000000000000000000000000000000000000000000000000c173e00000000000000000000000000000000000000000000000000000000000c173f00000000000000000000000000000000000000000000000000000000000c174000000000000000000000000000000000000000000000000000000000000c174100000000000000000000000000000000000000000000000000000000000c173100000000000000000000000000000000000000000000000000000000000c173200000000000000000000000000000000000000000000000000000000000c173300000000000000000000000000000000000000000000000000000000000c173400000000000000000000000000000000000000000000000000000000000c173500000000000000000000000000000000000000000000000000000000000c173600000000000000000000000000000000000000000000000000000000000c173700000000000000000000000000000000000000000000000000000000000c173800000000000000000000000000000000000000000000000000000000000c173900000000000000000000000000000000000000000000000000000000000c173a00000000000000000000000000000000000000000000000000000000000c173b00000000000000000000000000000000000000000000000000000000000c173c00000000000000000000000000000000000000000000000000000000000c173d00000000000000000000000000000000000000000000000000000000000c173e00000000000000000000000000000000000000000000000000000000000c173f00000000000000000000000000000000000000000000000000000000000c174000000000000000000000000000000000000000000000000000000000000c174100000000000000000000000000000000000000000000000000000000000c174200000000000000000000000000000000000000000000000000000000000c173200000000000000000000000000000000000000000000000000000000000c173300000000000000000000000000000000000000000000000000000000000c173400000000000000000000000000000000000000000000000000000000000c173500000000000000000000000000000000000000000000000000000000000c173600000000000000000000000000000000000000000000000000000000000c173700000000000000000000000000000000000000000000000000000000000c173800000000000000000000000000000000000000000000000000000000000c173900000000000000000000000000000000000000000000000000000000000c173a00000000000000000000000000000000000000000000000000000000000c173b00000000000000000000000000000000000000000000000000000000000c173c00000000000000000000000000000000000000000000000000000000000c173d00000000000000000000000000000000000000000000000000000000000c173e00000000000000000000000000000000000000000000000000000000000c173f00000000000000000000000000000000000000000000000000000000000c174000000000000000000000000000000000000000000000000000000000000c174100000000000000000000000000000000000000000000000000000000000c174200000000000000000000000000000000000000000000000000000000000c174300000000000000000000000000000000000000000000000000000000000c173300000000000000000000000000000000000000000000000000000000000c173400000000000000000000000000000000000000000000000000000000000c173500000000000000000000000000000000000000000000000000000000000c173600000000000000000000000000000000000000000000000000000000000c173700000000000000000000000000000000000000000000000000000000000c173800000000000000000000000000000000000000000000000000000000000c173900000000000000000000000000000000000000000000000000000000000c173a00000000000000000000000000000000000000000000000000000000000c173b00000000000000000000000000000000000000000000000000000000000c173c00000000000000000000000000000000000000000000000000000000000c173d00000000000000000000000000000000000000000000000000000000000c173e00000000000000000000000000000000000000000000000000000000000c173f00000000000000000000000000000000000000000000000000000000000c174000000000000000000000000000000000000000000000000000000000000c174100000000000000000000000000000000000000000000000000000000000c174200000000000000000000000000000000000000000000000000000000000c174300000000000000000000000000000000000000000000000000000000000c174400000000000000000000000000000000000000000000000000000000000c173400000000000000000000000000000000000000000000000000000000000c173500000000000000000000000000000000000000000000000000000000000c173600000000000000000000000000000000000000000000000000000000000c173700000000000000000000000000000000000000000000000000000000000c173800000000000000000000000000000000000000000000000000000000000c173900000000000000000000000000000000000000000000000000000000000c173a00000000000000000000000000000000000000000000000000000000000c173b00000000000000000000000000000000000000000000000000000000000c173c00000000000000000000000000000000000000000000000000000000000c173d00000000000000000000000000000000000000000000000000000000000c173e00000000000000000000000000000000000000000000000000000000000c173f00000000000000000000000000000000000000000000000000000000000c174000000000000000000000000000000000000000000000000000000000000c174100000000000000000000000000000000000000000000000000000000000c174200000000000000000000000000000000000000000000000000000000000c174300000000000000000000000000000000000000000000000000000000000c174400000000000000000000000000000000000000000000000000000000000c174500000000000000000000000000000000000000000000000000000000000c173500000000000000000000000000000000000000000000000000000000000c173600000000000000000000000000000000000000000000000000000000000c173700000000000000000000000000000000000000000000000000000000000c173800000000000000000000000000000000000000000000000000000000000c173900000000000000000000000000000000000000000000000000000000000c173a00000000000000000000000000000000000000000000000000000000000c173b00000000000000000000000000000000000000000000000000000000000c173c00000000000000000000000000000000000000000000000000000000000c173d00000000000000000000000000000000000000000000000000000000000c173e00000000000000000000000000000000000000000000000000000000000c173f00000000000000000000000000000000000000000000000000000000000c174000000000000000000000000000000000000000000000000000000000000c174100000000000000000000000000000000000000000000000000000000000c174200000000000000000000000000000000000000000000000000000000000c174300000000000000000000000000000000000000000000000000000000000c174400000000000000000000000000000000000000000000000000000000000c174500000000000000000000000000000000000000000000000000000000000c174600000000000000000000000000000000000000000000000000000000000c173600000000000000000000000000000000000000000000000000000000000c173700000000000000000000000000000000000000000000000000000000000c173800000000000000000000000000000000000000000000000000000000000c173900000000000000000000000000000000000000000000000000000000000c173a00000000000000000000000000000000000000000000000000000000000c173b00000000000000000000000000000000000000000000000000000000000c173c00000000000000000000000000000000000000000000000000000000000c173d00000000000000000000000000000000000000000000000000000000000c173e00000000000000000000000000000000000000000000000000000000000c173f00000000000000000000000000000000000000000000000000000000000c174000000000000000000000000000000000000000000000000000000000000c174100000000000000000000000000000000000000000000000000000000000c174200000000000000000000000000000000000000000000000000000000000c174300000000000000000000000000000000000000000000000000000000000c174400000000000000000000000000000000000000000000000000000000000c174500000000000000000000000000000000000000000000000000000000000c174600000000000000000000000000000000000000000000000000000000000c174700000000000000000000000000000000000000000000000000000000000c173700000000000000000000000000000000000000000000000000000000000c173800000000000000000000000000000000000000000000000000000000000c173900000000000000000000000000000000000000000000000000000000000c173a00000000000000000000000000000000000000000000000000000000000c173b00000000000000000000000000000000000000000000000000000000000c173c00000000000000000000000000000000000000000000000000000000000c173d00000000000000000000000000000000000000000000000000000000000c173e00000000000000000000000000000000000000000000000000000000000c173f00000000000000000000000000000000000000000000000000000000000c174000000000000000000000000000000000000000000000000000000000000c174100000000000000000000000000000000000000000000000000000000000c174200000000000000000000000000000000000000000000000000000000000c174300000000000000000000000000000000000000000000000000000000000c174400000000000000000000000000000000000000000000000000000000000c174500000000000000000000000000000000000000000000000000000000000c174600000000000000000000000000000000000000000000000000000000000c174700000000000000000000000000000000000000000000000000000000000c174800000000000000000000000000000000000000000000000000000000000c173800000000000000000000000000000000000000000000000000000000000c173900000000000000000000000000000000000000000000000000000000000c173a00000000000000000000000000000000000000000000000000000000000c173b00000000000000000000000000000000000000000000000000000000000c173c00000000000000000000000000000000000000000000000000000000000c173d00000000000000000000000000000000000000000000000000000000000c173e00000000000000000000000000000000000000000000000000000000000c173f00000000000000000000000000000000000000000000000000000000000c174000000000000000000000000000000000000000000000000000000000000c174100000000000000000000000000000000000000000000000000000000000c174200000000000000000000000000000000000000000000000000000000000c174300000000000000000000000000000000000000000000000000000000000c174400000000000000000000000000000000000000000000000000000000000c174500000000000000000000000000000000000000000000000000000000000c174600000000000000000000000000000000000000000000000000000000000c174700000000000000000000000000000000000000000000000000000000000c174800000000000000000000000000000000000000000000000000000000000c174900000000000000000000000000000000000000000000000000000000000c173900000000000000000000000000000000000000000000000000000000000c173a00000000000000000000000000000000000000000000000000000000000c173b00000000000000000000000000000000000000000000000000000000000c173c00000000000000000000000000000000000000000000000000000000000c173d00000000000000000000000000000000000000000000000000000000000c173e00000000000000000000000000000000000000000000000000000000000c173f00000000000000000000000000000000000000000000000000000000000c174000000000000000000000000000000000000000000000000000000000000c174100000000000000000000000000000000000000000000000000000000000c174200000000000000000000000000000000000000000000000000000000000c174300000000000000000000000000000000000000000000000000000000000c174400000000000000000000000000000000000000000000000000000000000c174500000000000000000000000000000000000000000000000000000000000c174600000000000000000000000000000000000000000000000000000000000c174700000000000000000000000000000000000000000000000000000000000c174800000000000000000000000000000000000000000000000000000000000c174900000000000000000000000000000000000000000000000000000000000c174a00000000000000000000000000000000000000000000000000000000000c173a00000000000000000000000000000000000000000000000000000000000c173b00000000000000000000000000000000000000000000000000000000000c173c00000000000000000000000000000000000000000000000000000000000c173d00000000000000000000000000000000000000000000000000000000000c173e00000000000000000000000000000000000000000000000000000000000c173f00000000000000000000000000000000000000000000000000000000000c174000000000000000000000000000000000000000000000000000000000000c174100000000000000000000000000000000000000000000000000000000000c174200000000000000000000000000000000000000000000000000000000000c174300000000000000000000000000000000000000000000000000000000000c174400000000000000000000000000000000000000000000000000000000000c174500000000000000000000000000000000000000000000000000000000000c174600000000000000000000000000000000000000000000000000000000000c174700000000000000000000000000000000000000000000000000000000000c174800000000000000000000000000000000000000000000000000000000000c174900000000000000000000000000000000000000000000000000000000000c174a00000000000000000000000000000000000000000000000000000000000c174b00000000000000000000000000000000000000000000000000000000000c173b00000000000000000000000000000000000000000000000000000000000c173c00000000000000000000000000000000000000000000000000000000000c173d00000000000000000000000000000000000000000000000000000000000c173e00000000000000000000000000000000000000000000000000000000000c173f00000000000000000000000000000000000000000000000000000000000c174000000000000000000000000000000000000000000000000000000000000c174100000000000000000000000000000000000000000000000000000000000c174200000000000000000000000000000000000000000000000000000000000c174300000000000000000000000000000000000000000000000000000000000c174400000000000000000000000000000000000000000000000000000000000c174500000000000000000000000000000000000000000000000000000000000c174600000000000000000000000000000000000000000000000000000000000c174700000000000000000000000000000000000000000000000000000000000c174800000000000000000000000000000000000000000000000000000000000c174900000000000000000000000000000000000000000000000000000000000c174a00000000000000000000000000000000000000000000000000000000000c174b00000000000000000000000000000000000000000000000000000000000c174c00000000000000000000000000000000000000000000000000000000000c173c00000000000000000000000000000000000000000000000000000000000c173d00000000000000000000000000000000000000000000000000000000000c173e00000000000000000000000000000000000000000000000000000000000c173f00000000000000000000000000000000000000000000000000000000000c174000000000000000000000000000000000000000000000000000000000000c174100000000000000000000000000000000000000000000000000000000000c174200000000000000000000000000000000000000000000000000000000000c174300000000000000000000000000000000000000000000000000000000000c174400000000000000000000000000000000000000000000000000000000000c174500000000000000000000000000000000000000000000000000000000000c174600000000000000000000000000000000000000000000000000000000000c174700000000000000000000000000000000000000000000000000000000000c174800000000000000000000000000000000000000000000000000000000000c174900000000000000000000000000000000000000000000000000000000000c174a00000000000000000000000000000000000000000000000000000000000c174b00000000000000000000000000000000000000000000000000000000000c174c00000000000000000000000000000000000000000000000000000000000c174d00000000000000000000000000000000000000000000000000000000000c173d00000000000000000000000000000000000000000000000000000000000c173e00000000000000000000000000000000000000000000000000000000000c173f00000000000000000000000000000000000000000000000000000000000c174000000000000000000000000000000000000000000000000000000000000c174100000000000000000000000000000000000000000000000000000000000c174200000000000000000000000000000000000000000000000000000000000c174300000000000000000000000000000000000000000000000000000000000c174400000000000000000000000000000000000000000000000000000000000c174500000000000000000000000000000000000000000000000000000000000c174600000000000000000000000000000000000000000000000000000000000c174700000000000000000000000000000000000000000000000000000000000c174800000000000000000000000000000000000000000000000000000000000c174900000000000000000000000000000000000000000000000000000000000c174a00000000000000000000000000000000000000000000000000000000000c174b00000000000000000000000000000000000000000000000000000000000c174c00000000000000000000000000000000000000000000000000000000000c174d00000000000000000000000000000000000000000000000000000000000c174e00000000000000000000000000000000000000000000000000000000000c173e00000000000000000000000000000000000000000000000000000000000c173f00000000000000000000000000000000000000000000000000000000000c174000000000000000000000000000000000000000000000000000000000000c174100000000000000000000000000000000000000000000000000000000000c174200000000000000000000000000000000000000000000000000000000000c174300000000000000000000000000000000000000000000000000000000000c174400000000000000000000000000000000000000000000000000000000000c174500000000000000000000000000000000000000000000000000000000000c174600000000000000000000000000000000000000000000000000000000000c174700000000000000000000000000000000000000000000000000000000000c174800000000000000000000000000000000000000000000000000000000000c174900000000000000000000000000000000000000000000000000000000000c174a00000000000000000000000000000000000000000000000000000000000c174b00000000000000000000000000000000000000000000000000000000000c174c00000000000000000000000000000000000000000000000000000000000c174d00000000000000000000000000000000000000000000000000000000000c174e00000000000000000000000000000000000000000000000000000000000c174f00000000000000000000000000000000000000000000000000000000000c173f00000000000000000000000000000000000000000000000000000000000c174000000000000000000000000000000000000000000000000000000000000c174100000000000000000000000000000000000000000000000000000000000c174200000000000000000000000000000000000000000000000000000000000c174300000000000000000000000000000000000000000000000000000000000c174400000000000000000000000000000000000000000000000000000000000c174500000000000000000000000000000000000000000000000000000000000c174600000000000000000000000000000000000000000000000000000000000c174700000000000000000000000000000000000000000000000000000000000c174800000000000000000000000000000000000000000000000000000000000c174900000000000000000000000000000000000000000000000000000000000c174a00000000000000000000000000000000000000000000000000000000000c174b00000000000000000000000000000000000000000000000000000000000c174c00000000000000000000000000000000000000000000000000000000000c174d00000000000000000000000000000000000000000000000000000000000c174e00000000000000000000000000000000000000000000000000000000000c174f00000000000000000000000000000000000000000000000000000000000c1750000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000101000000000000000000000000000000000000000000000000000000000000010100100000000000000000000000000000000000000000000000000000000001010020000000000000000000000000000000000000000000000000000000000101003000000000000000000000000000000000000000000000000000000000010100400000000000000000000000000000000000000000000000000000000001010050000000000000000000000000000000000000000000000000000000000101006000000000000000000000000000000000000000000000000000000000010100700000000000000000000000000000000000000000000000000000000001010080000000000000000000000000000000000000000000000000000000000101009000000000000000000000000000000000000000000000000000000000010100a000000000000000000000000000000000000000000000000000000000010100b000000000000000000000000000000000000000000000000000000000010100c000000000000000000000000000000000000000000000000000000000010100d000000000000000000000000000000000000000000000000000000000010100e000000000000000000000000000000000000000000000000000000000010100f0000000000000000000000000000000000000000000000000000000000101010000000000000000000000000000000000000000000000000000000000010101100000000000000000000000000000000000000000000000000000000001010120000000000000000000000000000000000000000000000000000000000101013000000000000000000000000000000000000000000000000000000000010101400000000000000000000000000000000000000000000000000000000001010150000000000000000000000000000000000000000000000000000000000101016000000000000000000000000000000000000000000000000000000000010101700000000000000000000000000000000000000000000000000000000001010180000000000000000000000000000000000000000000000000000000000101019000000000000000000000000000000000000000000000000000000000010101a000000000000000000000000000000000000000000000000000000000010101b000000000000000000000000000000000000000000000000000000000010101c000000000000000000000000000000000000000000000000000000000010101d000000000000000000000000000000000000000000000000000000000010101e000000000000000000000000000000000000000000000000000000000010101f0000000000000000000000000000000000000000000000000000000000101020000000000000000000000000000000000000000000000000000000000010102100000000000000000000000000000000000000000000000000000000001010220000000000000000000000000000000000000000000000000000000000101023000000000000000000000000000000000000000000000000000000000010102400000000000000000000000000000000000000000000000000000000001010250000000000000000000000000000000000000000000000000000000000101026000000000000000000000000000000000000000000000000000000000010102700000000000000000000000000000000000000000000000000000000001010280000000000000000000000000000000000000000000000000000000000101029000000000000000000000000000000000000000000000000000000000010102a000000000000000000000000000000000000000000000000000000000010102b000000000000000000000000000000000000000000000000000000000010102c000000000000000000000000000000000000000000000000000000000010102d000000000000000000000000000000000000000000000000000000000010102e000000000000000000000000000000000000000000000000000000000010102f0000000000000000000000000000000000000000000000000000000000101030000000000000000000000000000000000000000000000000000000000010103100000000000000000000000000000000000000000000000000000000001010320000000000000000000000000000000000000000000000000000000000101033000000000000000000000000000000000000000000000000000000000010103400000000000000000000000000000000000000000000000000000000001010350000000000000000000000000000000000000000000000000000000000101036000000000000000000000000000000000000000000000000000000000010103700000000000000000000000000000000000000000000000000000000001010380000000000000000000000000000000000000000000000000000000000101039000000000000000000000000000000000000000000000000000000000010103a000000000000000000000000000000000000000000000000000000000010103b000000000000000000000000000000000000000000000000000000000010103c000000000000000000000000000000000000000000000000000000000010103d000000000000000000000000000000000000000000000000000000000010103e000000000000000000000000000000000000000000000000000000000010103f4000000000000000000000000000000000000000000000000000000000001000010000000000000000000000000000000000000000000000000000000000101100000000000000000000000000000000000000000000000000000000000010110100000000000000000000000000000000000000000000000000000000001011020000000000000000000000000000000000000000000000000000000000101103000000000000000000000000000000000000000000000000000000000010110400000000000000000000000000000000000000000000000000000000001011050000000000000000000000000000000000000000000000000000000000101106000000000000000000000000000000000000000000000000000000000010110700000000000000000000000000000000000000000000000000000000001011080000000000000000000000000000000000000000000000000000000000101109000000000000000000000000000000000000000000000000000000000010110a000000000000000000000000000000000000000000000000000000000010110b000000000000000000000000000000000000000000000000000000000010110c000000000000000000000000000000000000000000000000000000000010110d000000000000000000000000000000000000000000000000000000000010110e000000000000000000000000000000000000000000000000000000000010110f0000000000000000000000000000000000000000000000000000000000101110000000000000000000000000000000000000000000000000000000000010111100000000000000000000000000000000000000000000000000000000001011120000000000000000000000000000000000000000000000000000000000101113000000000000000000000000000000000000000000000000000000000010111400000000000000000000000000000000000000000000000000000000001011150000000000000000000000000000000000000000000000000000000000101116000000000000000000000000000000000000000000000000000000000010111700000000000000000000000000000000000000000000000000000000001011180000000000000000000000000000000000000000000000000000000000101119000000000000000000000000000000000000000000000000000000000010111a000000000000000000000000000000000000000000000000000000000010111b000000000000000000000000000000000000000000000000000000000010111c000000000000000000000000000000000000000000000000000000000010111d000000000000000000000000000000000000000000000000000000000010111e000000000000000000000000000000000000000000000000000000000010111f0000000000000000000000000000000000000000000000000000000000101120000000000000000000000000000000000000000000000000000000000010112100000000000000000000000000000000000000000000000000000000001011220000000000000000000000000000000000000000000000000000000000101123000000000000000000000000000000000000000000000000000000000010112400000000000000000000000000000000000000000000000000000000001011250000000000000000000000000000000000000000000000000000000000101126000000000000000000000000000000000000000000000000000000000010112700000000000000000000000000000000000000000000000000000000001011280000000000000000000000000000000000000000000000000000000000101129000000000000000000000000000000000000000000000000000000000010112a000000000000000000000000000000000000000000000000000000000010112b000000000000000000000000000000000000000000000000000000000010112c000000000000000000000000000000000000000000000000000000000010112d000000000000000000000000000000000000000000000000000000000010112e000000000000000000000000000000000000000000000000000000000010112f0000000000000000000000000000000000000000000000000000000000101130000000000000000000000000000000000000000000000000000000000010113100000000000000000000000000000000000000000000000000000000001011320000000000000000000000000000000000000000000000000000000000101133000000000000000000000000000000000000000000000000000000000010113400000000000000000000000000000000000000000000000000000000001011350000000000000000000000000000000000000000000000000000000000101136000000000000000000000000000000000000000000000000000000000010113700000000000000000000000000000000000000000000000000000000001011380000000000000000000000000000000000000000000000000000000000101139000000000000000000000000000000000000000000000000000000000010113a000000000000000000000000000000000000000000000000000000000010113b000000000000000000000000000000000000000000000000000000000010113c000000000000000000000000000000000000000000000000000000000010113d000000000000000000000000000000000000000000000000000000000010113e080099145b6c0d32753835121f8b271186d01236948a4622ce78a98347fcfc98390085277a27c6acbd5ffc4c19cd65fc30056999e9bec36998f753132db0ff8e2300f3cf77a7261759ebd5f4149f6ad56746f4499cfcd4adf27a1d373f77da64d5009bc6e0e994a23cde8c95b90c1acc1b4a480c6599d1df2c3f9f6e76f3d1aff200d7a1c4a2700dacaaf07f1f0ff33837bdbabcf0b9ace17efabe0761708c4bb900dbeb8e96d14f21e57d5786b6d6ae7e5ddb1bb35935c0fb246d4bdbca62e02c00fbf12b5e0df6223b801088798e4e04d2a92ffe9a11639b7f0ce314e3412a8000d796e0724de03b796ba77069fcd6cf921e566f3aed15eb3e77258add74e9ff3f0000000000000000000000000000000000000000000000000000000000102000000000000000000000000000000000000000000000000000000000000010200a0000000000000000000000000000000000000000000000000000000000102001000000000000000000000000000000000000000000000000000000000010200b0000000000000000000000000000000000000000000000000000000000102002000000000000000000000000000000000000000000000000000000000010200c0000000000000000000000000000000000000000000000000000000000102003000000000000000000000000000000000000000000000000000000000010200d0000000000000000000000000000000000000000000000000000000000102004000000000000000000000000000000000000000000000000000000000010200e0000000000000000000000000000000000000000000000000000000000102005000000000000000000000000000000000000000000000000000000000010200f00000000000000000000000000000000000000000000000000000000001020060000000000000000000000000000000000000000000000000000000000102010000000000000000000000000000000000000000000000000000000000010200700000000000000000000000000000000000000000000000000000000001020110000000000000000000000000000000000000000000000000000000000102008000000000000000000000000000000000000000000000000000000000010201200000000000000000000000000000000000000000000000000000000001020090000000000000000000000000000000000000000000000000000000000102013000000000000000000000000000000000000000000000000000000000010200a0000000000000000000000000000000000000000000000000000000000102014000000000000000000000000000000000000000000000000000000000010200b0000000000000000000000000000000000000000000000000000000000102015000000000000000000000000000000000000000000000000000000000010200c0000000000000000000000000000000000000000000000000000000000102016000000000000000000000000000000000000000000000000000000000010200d0000000000000000000000000000000000000000000000000000000000102017000000000000000000000000000000000000000000000000000000000010200e0000000000000000000000000000000000000000000000000000000000102018000000000000000000000000000000000000000000000000000000000010200f00000000000000000000000000000000000000000000000000000000001020190000000000000000000000000000000000000000000000000000000000102010000000000000000000000000000000000000000000000000000000000010201a0000000000000000000000000000000000000000000000000000000000102011000000000000000000000000000000000000000000000000000000000010201b0000000000000000000000000000000000000000000000000000000000102012000000000000000000000000000000000000000000000000000000000010201c0000000000000000000000000000000000000000000000000000000000102013000000000000000000000000000000000000000000000000000000000010201d0000000000000000000000000000000000000000000000000000000000102014000000000000000000000000000000000000000000000000000000000010201e0000000000000000000000000000000000000000000000000000000000102015000000000000000000000000000000000000000000000000000000000010201f00000000000000000000000000000000000000000000000000000000001020160000000000000000000000000000000000000000000000000000000000102020000000000000000000000000000000000000000000000000000000000010201700000000000000000000000000000000000000000000000000000000001020210000000000000000000000000000000000000000000000000000000000102018000000000000000000000000000000000000000000000000000000000010202200000000000000000000000000000000000000000000000000000000001020190000000000000000000000000000000000000000000000000000000000102023000000000000000000000000000000000000000000000000000000000010201a0000000000000000000000000000000000000000000000000000000000102024000000000000000000000000000000000000000000000000000000000010201b0000000000000000000000000000000000000000000000000000000000102025000000000000000000000000000000000000000000000000000000000010201c0000000000000000000000000000000000000000000000000000000000102026000000000000000000000000000000000000000000000000000000000010201d0000000000000000000000000000000000000000000000000000000000102027000000000000000000000000000000000000000000000000000000000010201e0000000000000000000000000000000000000000000000000000000000102028000000000000000000000000000000000000000000000000000000000010201f00000000000000000000000000000000000000000000000000000000001020290000000000000000000000000000000000000000000000000000000000102020000000000000000000000000000000000000000000000000000000000010202a0000000000000000000000000000000000000000000000000000000000102021000000000000000000000000000000000000000000000000000000000010202b0000000000000000000000000000000000000000000000000000000000102022000000000000000000000000000000000000000000000000000000000010202c0000000000000000000000000000000000000000000000000000000000102023000000000000000000000000000000000000000000000000000000000010202d0000000000000000000000000000000000000000000000000000000000102024000000000000000000000000000000000000000000000000000000000010202e0000000000000000000000000000000000000000000000000000000000102025000000000000000000000000000000000000000000000000000000000010202f00000000000000000000000000000000000000000000000000000000001020260000000000000000000000000000000000000000000000000000000000102030000000000000000000000000000000000000000000000000000000000010202700000000000000000000000000000000000000000000000000000000001020310000000000000000000000000000000000000000000000000000000000102028000000000000000000000000000000000000000000000000000000000010203200000000000000000000000000000000000000000000000000000000001020290000000000000000000000000000000000000000000000000000000000102033000000000000000000000000000000000000000000000000000000000010202a0000000000000000000000000000000000000000000000000000000000102034000000000000000000000000000000000000000000000000000000000010202b0000000000000000000000000000000000000000000000000000000000102035000000000000000000000000000000000000000000000000000000000010202c0000000000000000000000000000000000000000000000000000000000102036000000000000000000000000000000000000000000000000000000000010202d0000000000000000000000000000000000000000000000000000000000102037000000000000000000000000000000000000000000000000000000000010202e0000000000000000000000000000000000000000000000000000000000102038000000000000000000000000000000000000000000000000000000000010202f00000000000000000000000000000000000000000000000000000000001020390000000000000000000000000000000000000000000000000000000000102030000000000000000000000000000000000000000000000000000000000010203a0000000000000000000000000000000000000000000000000000000000102031000000000000000000000000000000000000000000000000000000000010203b0000000000000000000000000000000000000000000000000000000000102032000000000000000000000000000000000000000000000000000000000010203c0000000000000000000000000000000000000000000000000000000000102033000000000000000000000000000000000000000000000000000000000010203d0000000000000000000000000000000000000000000000000000000000102034000000000000000000000000000000000000000000000000000000000010203e0000000000000000000000000000000000000000000000000000000000102035000000000000000000000000000000000000000000000000000000000010203f00000000000000000000000000000000000000000000000000000000001020360000000000000000000000000000000000000000000000000000000000102040000000000000000000000000000000000000000000000000000000000010203700000000000000000000000000000000000000000000000000000000001020410000000000000000000000000000000000000000000000000000000000102038000000000000000000000000000000000000000000000000000000000010204200000000000000000000000000000000000000000000000000000000001020390000000000000000000000000000000000000000000000000000000000102043000000000000000000000000000000000000000000000000000000000010203a0000000000000000000000000000000000000000000000000000000000102044000000000000000000000000000000000000000000000000000000000010203b0000000000000000000000000000000000000000000000000000000000102045000000000000000000000000000000000000000000000000000000000010203c0000000000000000000000000000000000000000000000000000000000102046000000000000000000000000000000000000000000000000000000000010203d0000000000000000000000000000000000000000000000000000000000102047000000000000000000000000000000000000000000000000000000000010203e0000000000000000000000000000000000000000000000000000000000102048400000000000000000000000000000000000000000000000000000000000101700000000000000000000000000000000000000000000000000000000000010170100000000000000000000000000000000000000000000000000000000001017020000000000000000000000000000000000000000000000000000000000101703000000000000000000000000000000000000000000000000000000000010170400000000000000000000000000000000000000000000000000000000001017050000000000000000000000000000000000000000000000000000000000101706000000000000000000000000000000000000000000000000000000000010170700000000000000000000000000000000000000000000000000000000001017080000000000000000000000000000000000000000000000000000000000101709000000000000000000000000000000000000000000000000000000000010170a000000000000000000000000000000000000000000000000000000000010170b000000000000000000000000000000000000000000000000000000000010170c000000000000000000000000000000000000000000000000000000000010170d000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f00000000000000000000000000000000000000000000000000000000001017100000000000000000000000000000000000000000000000000000000000101711000000000000000000000000000000000000000000000000000000000010170100000000000000000000000000000000000000000000000000000000001017020000000000000000000000000000000000000000000000000000000000101703000000000000000000000000000000000000000000000000000000000010170400000000000000000000000000000000000000000000000000000000001017050000000000000000000000000000000000000000000000000000000000101706000000000000000000000000000000000000000000000000000000000010170700000000000000000000000000000000000000000000000000000000001017080000000000000000000000000000000000000000000000000000000000101709000000000000000000000000000000000000000000000000000000000010170a000000000000000000000000000000000000000000000000000000000010170b000000000000000000000000000000000000000000000000000000000010170c000000000000000000000000000000000000000000000000000000000010170d000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f00000000000000000000000000000000000000000000000000000000001017100000000000000000000000000000000000000000000000000000000000101711000000000000000000000000000000000000000000000000000000000010171200000000000000000000000000000000000000000000000000000000001017020000000000000000000000000000000000000000000000000000000000101703000000000000000000000000000000000000000000000000000000000010170400000000000000000000000000000000000000000000000000000000001017050000000000000000000000000000000000000000000000000000000000101706000000000000000000000000000000000000000000000000000000000010170700000000000000000000000000000000000000000000000000000000001017080000000000000000000000000000000000000000000000000000000000101709000000000000000000000000000000000000000000000000000000000010170a000000000000000000000000000000000000000000000000000000000010170b000000000000000000000000000000000000000000000000000000000010170c000000000000000000000000000000000000000000000000000000000010170d000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f00000000000000000000000000000000000000000000000000000000001017100000000000000000000000000000000000000000000000000000000000101711000000000000000000000000000000000000000000000000000000000010171200000000000000000000000000000000000000000000000000000000001017130000000000000000000000000000000000000000000000000000000000101703000000000000000000000000000000000000000000000000000000000010170400000000000000000000000000000000000000000000000000000000001017050000000000000000000000000000000000000000000000000000000000101706000000000000000000000000000000000000000000000000000000000010170700000000000000000000000000000000000000000000000000000000001017080000000000000000000000000000000000000000000000000000000000101709000000000000000000000000000000000000000000000000000000000010170a000000000000000000000000000000000000000000000000000000000010170b000000000000000000000000000000000000000000000000000000000010170c000000000000000000000000000000000000000000000000000000000010170d000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f00000000000000000000000000000000000000000000000000000000001017100000000000000000000000000000000000000000000000000000000000101711000000000000000000000000000000000000000000000000000000000010171200000000000000000000000000000000000000000000000000000000001017130000000000000000000000000000000000000000000000000000000000101714000000000000000000000000000000000000000000000000000000000010170400000000000000000000000000000000000000000000000000000000001017050000000000000000000000000000000000000000000000000000000000101706000000000000000000000000000000000000000000000000000000000010170700000000000000000000000000000000000000000000000000000000001017080000000000000000000000000000000000000000000000000000000000101709000000000000000000000000000000000000000000000000000000000010170a000000000000000000000000000000000000000000000000000000000010170b000000000000000000000000000000000000000000000000000000000010170c000000000000000000000000000000000000000000000000000000000010170d000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f00000000000000000000000000000000000000000000000000000000001017100000000000000000000000000000000000000000000000000000000000101711000000000000000000000000000000000000000000000000000000000010171200000000000000000000000000000000000000000000000000000000001017130000000000000000000000000000000000000000000000000000000000101714000000000000000000000000000000000000000000000000000000000010171500000000000000000000000000000000000000000000000000000000001017050000000000000000000000000000000000000000000000000000000000101706000000000000000000000000000000000000000000000000000000000010170700000000000000000000000000000000000000000000000000000000001017080000000000000000000000000000000000000000000000000000000000101709000000000000000000000000000000000000000000000000000000000010170a000000000000000000000000000000000000000000000000000000000010170b000000000000000000000000000000000000000000000000000000000010170c000000000000000000000000000000000000000000000000000000000010170d000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f00000000000000000000000000000000000000000000000000000000001017100000000000000000000000000000000000000000000000000000000000101711000000000000000000000000000000000000000000000000000000000010171200000000000000000000000000000000000000000000000000000000001017130000000000000000000000000000000000000000000000000000000000101714000000000000000000000000000000000000000000000000000000000010171500000000000000000000000000000000000000000000000000000000001017160000000000000000000000000000000000000000000000000000000000101706000000000000000000000000000000000000000000000000000000000010170700000000000000000000000000000000000000000000000000000000001017080000000000000000000000000000000000000000000000000000000000101709000000000000000000000000000000000000000000000000000000000010170a000000000000000000000000000000000000000000000000000000000010170b000000000000000000000000000000000000000000000000000000000010170c000000000000000000000000000000000000000000000000000000000010170d000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f00000000000000000000000000000000000000000000000000000000001017100000000000000000000000000000000000000000000000000000000000101711000000000000000000000000000000000000000000000000000000000010171200000000000000000000000000000000000000000000000000000000001017130000000000000000000000000000000000000000000000000000000000101714000000000000000000000000000000000000000000000000000000000010171500000000000000000000000000000000000000000000000000000000001017160000000000000000000000000000000000000000000000000000000000101717000000000000000000000000000000000000000000000000000000000010170700000000000000000000000000000000000000000000000000000000001017080000000000000000000000000000000000000000000000000000000000101709000000000000000000000000000000000000000000000000000000000010170a000000000000000000000000000000000000000000000000000000000010170b000000000000000000000000000000000000000000000000000000000010170c000000000000000000000000000000000000000000000000000000000010170d000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f00000000000000000000000000000000000000000000000000000000001017100000000000000000000000000000000000000000000000000000000000101711000000000000000000000000000000000000000000000000000000000010171200000000000000000000000000000000000000000000000000000000001017130000000000000000000000000000000000000000000000000000000000101714000000000000000000000000000000000000000000000000000000000010171500000000000000000000000000000000000000000000000000000000001017160000000000000000000000000000000000000000000000000000000000101717000000000000000000000000000000000000000000000000000000000010171800000000000000000000000000000000000000000000000000000000001017080000000000000000000000000000000000000000000000000000000000101709000000000000000000000000000000000000000000000000000000000010170a000000000000000000000000000000000000000000000000000000000010170b000000000000000000000000000000000000000000000000000000000010170c000000000000000000000000000000000000000000000000000000000010170d000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f00000000000000000000000000000000000000000000000000000000001017100000000000000000000000000000000000000000000000000000000000101711000000000000000000000000000000000000000000000000000000000010171200000000000000000000000000000000000000000000000000000000001017130000000000000000000000000000000000000000000000000000000000101714000000000000000000000000000000000000000000000000000000000010171500000000000000000000000000000000000000000000000000000000001017160000000000000000000000000000000000000000000000000000000000101717000000000000000000000000000000000000000000000000000000000010171800000000000000000000000000000000000000000000000000000000001017190000000000000000000000000000000000000000000000000000000000101709000000000000000000000000000000000000000000000000000000000010170a000000000000000000000000000000000000000000000000000000000010170b000000000000000000000000000000000000000000000000000000000010170c000000000000000000000000000000000000000000000000000000000010170d000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f0000000000000000000000000000000000000000000000000000000000101710000000000000000000000000000000000000000000000000000000000010171100000000000000000000000000000000000000000000000000000000001017120000000000000000000000000000000000000000000000000000000000101713000000000000000000000000000000000000000000000000000000000010171400000000000000000000000000000000000000000000000000000000001017150000000000000000000000000000000000000000000000000000000000101716000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010170a000000000000000000000000000000000000000000000000000000000010170b000000000000000000000000000000000000000000000000000000000010170c000000000000000000000000000000000000000000000000000000000010170d000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f0000000000000000000000000000000000000000000000000000000000101710000000000000000000000000000000000000000000000000000000000010171100000000000000000000000000000000000000000000000000000000001017120000000000000000000000000000000000000000000000000000000000101713000000000000000000000000000000000000000000000000000000000010171400000000000000000000000000000000000000000000000000000000001017150000000000000000000000000000000000000000000000000000000000101716000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010170b000000000000000000000000000000000000000000000000000000000010170c000000000000000000000000000000000000000000000000000000000010170d000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f0000000000000000000000000000000000000000000000000000000000101710000000000000000000000000000000000000000000000000000000000010171100000000000000000000000000000000000000000000000000000000001017120000000000000000000000000000000000000000000000000000000000101713000000000000000000000000000000000000000000000000000000000010171400000000000000000000000000000000000000000000000000000000001017150000000000000000000000000000000000000000000000000000000000101716000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010170c000000000000000000000000000000000000000000000000000000000010170d000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f0000000000000000000000000000000000000000000000000000000000101710000000000000000000000000000000000000000000000000000000000010171100000000000000000000000000000000000000000000000000000000001017120000000000000000000000000000000000000000000000000000000000101713000000000000000000000000000000000000000000000000000000000010171400000000000000000000000000000000000000000000000000000000001017150000000000000000000000000000000000000000000000000000000000101716000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010170d000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f0000000000000000000000000000000000000000000000000000000000101710000000000000000000000000000000000000000000000000000000000010171100000000000000000000000000000000000000000000000000000000001017120000000000000000000000000000000000000000000000000000000000101713000000000000000000000000000000000000000000000000000000000010171400000000000000000000000000000000000000000000000000000000001017150000000000000000000000000000000000000000000000000000000000101716000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010170e000000000000000000000000000000000000000000000000000000000010170f0000000000000000000000000000000000000000000000000000000000101710000000000000000000000000000000000000000000000000000000000010171100000000000000000000000000000000000000000000000000000000001017120000000000000000000000000000000000000000000000000000000000101713000000000000000000000000000000000000000000000000000000000010171400000000000000000000000000000000000000000000000000000000001017150000000000000000000000000000000000000000000000000000000000101716000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f000000000000000000000000000000000000000000000000000000000010170f0000000000000000000000000000000000000000000000000000000000101710000000000000000000000000000000000000000000000000000000000010171100000000000000000000000000000000000000000000000000000000001017120000000000000000000000000000000000000000000000000000000000101713000000000000000000000000000000000000000000000000000000000010171400000000000000000000000000000000000000000000000000000000001017150000000000000000000000000000000000000000000000000000000000101716000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f00000000000000000000000000000000000000000000000000000000001017200000000000000000000000000000000000000000000000000000000000101710000000000000000000000000000000000000000000000000000000000010171100000000000000000000000000000000000000000000000000000000001017120000000000000000000000000000000000000000000000000000000000101713000000000000000000000000000000000000000000000000000000000010171400000000000000000000000000000000000000000000000000000000001017150000000000000000000000000000000000000000000000000000000000101716000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f00000000000000000000000000000000000000000000000000000000001017200000000000000000000000000000000000000000000000000000000000101721000000000000000000000000000000000000000000000000000000000010171100000000000000000000000000000000000000000000000000000000001017120000000000000000000000000000000000000000000000000000000000101713000000000000000000000000000000000000000000000000000000000010171400000000000000000000000000000000000000000000000000000000001017150000000000000000000000000000000000000000000000000000000000101716000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f00000000000000000000000000000000000000000000000000000000001017200000000000000000000000000000000000000000000000000000000000101721000000000000000000000000000000000000000000000000000000000010172200000000000000000000000000000000000000000000000000000000001017120000000000000000000000000000000000000000000000000000000000101713000000000000000000000000000000000000000000000000000000000010171400000000000000000000000000000000000000000000000000000000001017150000000000000000000000000000000000000000000000000000000000101716000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f00000000000000000000000000000000000000000000000000000000001017200000000000000000000000000000000000000000000000000000000000101721000000000000000000000000000000000000000000000000000000000010172200000000000000000000000000000000000000000000000000000000001017230000000000000000000000000000000000000000000000000000000000101713000000000000000000000000000000000000000000000000000000000010171400000000000000000000000000000000000000000000000000000000001017150000000000000000000000000000000000000000000000000000000000101716000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f00000000000000000000000000000000000000000000000000000000001017200000000000000000000000000000000000000000000000000000000000101721000000000000000000000000000000000000000000000000000000000010172200000000000000000000000000000000000000000000000000000000001017230000000000000000000000000000000000000000000000000000000000101724000000000000000000000000000000000000000000000000000000000010171400000000000000000000000000000000000000000000000000000000001017150000000000000000000000000000000000000000000000000000000000101716000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f00000000000000000000000000000000000000000000000000000000001017200000000000000000000000000000000000000000000000000000000000101721000000000000000000000000000000000000000000000000000000000010172200000000000000000000000000000000000000000000000000000000001017230000000000000000000000000000000000000000000000000000000000101724000000000000000000000000000000000000000000000000000000000010172500000000000000000000000000000000000000000000000000000000001017150000000000000000000000000000000000000000000000000000000000101716000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f00000000000000000000000000000000000000000000000000000000001017200000000000000000000000000000000000000000000000000000000000101721000000000000000000000000000000000000000000000000000000000010172200000000000000000000000000000000000000000000000000000000001017230000000000000000000000000000000000000000000000000000000000101724000000000000000000000000000000000000000000000000000000000010172500000000000000000000000000000000000000000000000000000000001017260000000000000000000000000000000000000000000000000000000000101716000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f00000000000000000000000000000000000000000000000000000000001017200000000000000000000000000000000000000000000000000000000000101721000000000000000000000000000000000000000000000000000000000010172200000000000000000000000000000000000000000000000000000000001017230000000000000000000000000000000000000000000000000000000000101724000000000000000000000000000000000000000000000000000000000010172500000000000000000000000000000000000000000000000000000000001017260000000000000000000000000000000000000000000000000000000000101727000000000000000000000000000000000000000000000000000000000010171700000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f00000000000000000000000000000000000000000000000000000000001017200000000000000000000000000000000000000000000000000000000000101721000000000000000000000000000000000000000000000000000000000010172200000000000000000000000000000000000000000000000000000000001017230000000000000000000000000000000000000000000000000000000000101724000000000000000000000000000000000000000000000000000000000010172500000000000000000000000000000000000000000000000000000000001017260000000000000000000000000000000000000000000000000000000000101727000000000000000000000000000000000000000000000000000000000010172800000000000000000000000000000000000000000000000000000000001017180000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f00000000000000000000000000000000000000000000000000000000001017200000000000000000000000000000000000000000000000000000000000101721000000000000000000000000000000000000000000000000000000000010172200000000000000000000000000000000000000000000000000000000001017230000000000000000000000000000000000000000000000000000000000101724000000000000000000000000000000000000000000000000000000000010172500000000000000000000000000000000000000000000000000000000001017260000000000000000000000000000000000000000000000000000000000101727000000000000000000000000000000000000000000000000000000000010172800000000000000000000000000000000000000000000000000000000001017290000000000000000000000000000000000000000000000000000000000101719000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f0000000000000000000000000000000000000000000000000000000000101720000000000000000000000000000000000000000000000000000000000010172100000000000000000000000000000000000000000000000000000000001017220000000000000000000000000000000000000000000000000000000000101723000000000000000000000000000000000000000000000000000000000010172400000000000000000000000000000000000000000000000000000000001017250000000000000000000000000000000000000000000000000000000000101726000000000000000000000000000000000000000000000000000000000010172700000000000000000000000000000000000000000000000000000000001017280000000000000000000000000000000000000000000000000000000000101729000000000000000000000000000000000000000000000000000000000010172a000000000000000000000000000000000000000000000000000000000010171a000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f0000000000000000000000000000000000000000000000000000000000101720000000000000000000000000000000000000000000000000000000000010172100000000000000000000000000000000000000000000000000000000001017220000000000000000000000000000000000000000000000000000000000101723000000000000000000000000000000000000000000000000000000000010172400000000000000000000000000000000000000000000000000000000001017250000000000000000000000000000000000000000000000000000000000101726000000000000000000000000000000000000000000000000000000000010172700000000000000000000000000000000000000000000000000000000001017280000000000000000000000000000000000000000000000000000000000101729000000000000000000000000000000000000000000000000000000000010172a000000000000000000000000000000000000000000000000000000000010172b000000000000000000000000000000000000000000000000000000000010171b000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f0000000000000000000000000000000000000000000000000000000000101720000000000000000000000000000000000000000000000000000000000010172100000000000000000000000000000000000000000000000000000000001017220000000000000000000000000000000000000000000000000000000000101723000000000000000000000000000000000000000000000000000000000010172400000000000000000000000000000000000000000000000000000000001017250000000000000000000000000000000000000000000000000000000000101726000000000000000000000000000000000000000000000000000000000010172700000000000000000000000000000000000000000000000000000000001017280000000000000000000000000000000000000000000000000000000000101729000000000000000000000000000000000000000000000000000000000010172a000000000000000000000000000000000000000000000000000000000010172b000000000000000000000000000000000000000000000000000000000010172c000000000000000000000000000000000000000000000000000000000010171c000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f0000000000000000000000000000000000000000000000000000000000101720000000000000000000000000000000000000000000000000000000000010172100000000000000000000000000000000000000000000000000000000001017220000000000000000000000000000000000000000000000000000000000101723000000000000000000000000000000000000000000000000000000000010172400000000000000000000000000000000000000000000000000000000001017250000000000000000000000000000000000000000000000000000000000101726000000000000000000000000000000000000000000000000000000000010172700000000000000000000000000000000000000000000000000000000001017280000000000000000000000000000000000000000000000000000000000101729000000000000000000000000000000000000000000000000000000000010172a000000000000000000000000000000000000000000000000000000000010172b000000000000000000000000000000000000000000000000000000000010172c000000000000000000000000000000000000000000000000000000000010172d000000000000000000000000000000000000000000000000000000000010171d000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f0000000000000000000000000000000000000000000000000000000000101720000000000000000000000000000000000000000000000000000000000010172100000000000000000000000000000000000000000000000000000000001017220000000000000000000000000000000000000000000000000000000000101723000000000000000000000000000000000000000000000000000000000010172400000000000000000000000000000000000000000000000000000000001017250000000000000000000000000000000000000000000000000000000000101726000000000000000000000000000000000000000000000000000000000010172700000000000000000000000000000000000000000000000000000000001017280000000000000000000000000000000000000000000000000000000000101729000000000000000000000000000000000000000000000000000000000010172a000000000000000000000000000000000000000000000000000000000010172b000000000000000000000000000000000000000000000000000000000010172c000000000000000000000000000000000000000000000000000000000010172d000000000000000000000000000000000000000000000000000000000010172e000000000000000000000000000000000000000000000000000000000010171e000000000000000000000000000000000000000000000000000000000010171f0000000000000000000000000000000000000000000000000000000000101720000000000000000000000000000000000000000000000000000000000010172100000000000000000000000000000000000000000000000000000000001017220000000000000000000000000000000000000000000000000000000000101723000000000000000000000000000000000000000000000000000000000010172400000000000000000000000000000000000000000000000000000000001017250000000000000000000000000000000000000000000000000000000000101726000000000000000000000000000000000000000000000000000000000010172700000000000000000000000000000000000000000000000000000000001017280000000000000000000000000000000000000000000000000000000000101729000000000000000000000000000000000000000000000000000000000010172a000000000000000000000000000000000000000000000000000000000010172b000000000000000000000000000000000000000000000000000000000010172c000000000000000000000000000000000000000000000000000000000010172d000000000000000000000000000000000000000000000000000000000010172e000000000000000000000000000000000000000000000000000000000010172f000000000000000000000000000000000000000000000000000000000010171f0000000000000000000000000000000000000000000000000000000000101720000000000000000000000000000000000000000000000000000000000010172100000000000000000000000000000000000000000000000000000000001017220000000000000000000000000000000000000000000000000000000000101723000000000000000000000000000000000000000000000000000000000010172400000000000000000000000000000000000000000000000000000000001017250000000000000000000000000000000000000000000000000000000000101726000000000000000000000000000000000000000000000000000000000010172700000000000000000000000000000000000000000000000000000000001017280000000000000000000000000000000000000000000000000000000000101729000000000000000000000000000000000000000000000000000000000010172a000000000000000000000000000000000000000000000000000000000010172b000000000000000000000000000000000000000000000000000000000010172c000000000000000000000000000000000000000000000000000000000010172d000000000000000000000000000000000000000000000000000000000010172e000000000000000000000000000000000000000000000000000000000010172f00000000000000000000000000000000000000000000000000000000001017300000000000000000000000000000000000000000000000000000000000101720000000000000000000000000000000000000000000000000000000000010172100000000000000000000000000000000000000000000000000000000001017220000000000000000000000000000000000000000000000000000000000101723000000000000000000000000000000000000000000000000000000000010172400000000000000000000000000000000000000000000000000000000001017250000000000000000000000000000000000000000000000000000000000101726000000000000000000000000000000000000000000000000000000000010172700000000000000000000000000000000000000000000000000000000001017280000000000000000000000000000000000000000000000000000000000101729000000000000000000000000000000000000000000000000000000000010172a000000000000000000000000000000000000000000000000000000000010172b000000000000000000000000000000000000000000000000000000000010172c000000000000000000000000000000000000000000000000000000000010172d000000000000000000000000000000000000000000000000000000000010172e000000000000000000000000000000000000000000000000000000000010172f00000000000000000000000000000000000000000000000000000000001017300000000000000000000000000000000000000000000000000000000000101731000000000000000000000000000000000000000000000000000000000010172100000000000000000000000000000000000000000000000000000000001017220000000000000000000000000000000000000000000000000000000000101723000000000000000000000000000000000000000000000000000000000010172400000000000000000000000000000000000000000000000000000000001017250000000000000000000000000000000000000000000000000000000000101726000000000000000000000000000000000000000000000000000000000010172700000000000000000000000000000000000000000000000000000000001017280000000000000000000000000000000000000000000000000000000000101729000000000000000000000000000000000000000000000000000000000010172a000000000000000000000000000000000000000000000000000000000010172b000000000000000000000000000000000000000000000000000000000010172c000000000000000000000000000000000000000000000000000000000010172d000000000000000000000000000000000000000000000000000000000010172e000000000000000000000000000000000000000000000000000000000010172f00000000000000000000000000000000000000000000000000000000001017300000000000000000000000000000000000000000000000000000000000101731000000000000000000000000000000000000000000000000000000000010173200000000000000000000000000000000000000000000000000000000001017220000000000000000000000000000000000000000000000000000000000101723000000000000000000000000000000000000000000000000000000000010172400000000000000000000000000000000000000000000000000000000001017250000000000000000000000000000000000000000000000000000000000101726000000000000000000000000000000000000000000000000000000000010172700000000000000000000000000000000000000000000000000000000001017280000000000000000000000000000000000000000000000000000000000101729000000000000000000000000000000000000000000000000000000000010172a000000000000000000000000000000000000000000000000000000000010172b000000000000000000000000000000000000000000000000000000000010172c000000000000000000000000000000000000000000000000000000000010172d000000000000000000000000000000000000000000000000000000000010172e000000000000000000000000000000000000000000000000000000000010172f00000000000000000000000000000000000000000000000000000000001017300000000000000000000000000000000000000000000000000000000000101731000000000000000000000000000000000000000000000000000000000010173200000000000000000000000000000000000000000000000000000000001017330000000000000000000000000000000000000000000000000000000000101723000000000000000000000000000000000000000000000000000000000010172400000000000000000000000000000000000000000000000000000000001017250000000000000000000000000000000000000000000000000000000000101726000000000000000000000000000000000000000000000000000000000010172700000000000000000000000000000000000000000000000000000000001017280000000000000000000000000000000000000000000000000000000000101729000000000000000000000000000000000000000000000000000000000010172a000000000000000000000000000000000000000000000000000000000010172b000000000000000000000000000000000000000000000000000000000010172c000000000000000000000000000000000000000000000000000000000010172d000000000000000000000000000000000000000000000000000000000010172e000000000000000000000000000000000000000000000000000000000010172f00000000000000000000000000000000000000000000000000000000001017300000000000000000000000000000000000000000000000000000000000101731000000000000000000000000000000000000000000000000000000000010173200000000000000000000000000000000000000000000000000000000001017330000000000000000000000000000000000000000000000000000000000101734000000000000000000000000000000000000000000000000000000000010172400000000000000000000000000000000000000000000000000000000001017250000000000000000000000000000000000000000000000000000000000101726000000000000000000000000000000000000000000000000000000000010172700000000000000000000000000000000000000000000000000000000001017280000000000000000000000000000000000000000000000000000000000101729000000000000000000000000000000000000000000000000000000000010172a000000000000000000000000000000000000000000000000000000000010172b000000000000000000000000000000000000000000000000000000000010172c000000000000000000000000000000000000000000000000000000000010172d000000000000000000000000000000000000000000000000000000000010172e000000000000000000000000000000000000000000000000000000000010172f00000000000000000000000000000000000000000000000000000000001017300000000000000000000000000000000000000000000000000000000000101731000000000000000000000000000000000000000000000000000000000010173200000000000000000000000000000000000000000000000000000000001017330000000000000000000000000000000000000000000000000000000000101734000000000000000000000000000000000000000000000000000000000010173500000000000000000000000000000000000000000000000000000000001017250000000000000000000000000000000000000000000000000000000000101726000000000000000000000000000000000000000000000000000000000010172700000000000000000000000000000000000000000000000000000000001017280000000000000000000000000000000000000000000000000000000000101729000000000000000000000000000000000000000000000000000000000010172a000000000000000000000000000000000000000000000000000000000010172b000000000000000000000000000000000000000000000000000000000010172c000000000000000000000000000000000000000000000000000000000010172d000000000000000000000000000000000000000000000000000000000010172e000000000000000000000000000000000000000000000000000000000010172f00000000000000000000000000000000000000000000000000000000001017300000000000000000000000000000000000000000000000000000000000101731000000000000000000000000000000000000000000000000000000000010173200000000000000000000000000000000000000000000000000000000001017330000000000000000000000000000000000000000000000000000000000101734000000000000000000000000000000000000000000000000000000000010173500000000000000000000000000000000000000000000000000000000001017360000000000000000000000000000000000000000000000000000000000101726000000000000000000000000000000000000000000000000000000000010172700000000000000000000000000000000000000000000000000000000001017280000000000000000000000000000000000000000000000000000000000101729000000000000000000000000000000000000000000000000000000000010172a000000000000000000000000000000000000000000000000000000000010172b000000000000000000000000000000000000000000000000000000000010172c000000000000000000000000000000000000000000000000000000000010172d000000000000000000000000000000000000000000000000000000000010172e000000000000000000000000000000000000000000000000000000000010172f00000000000000000000000000000000000000000000000000000000001017300000000000000000000000000000000000000000000000000000000000101731000000000000000000000000000000000000000000000000000000000010173200000000000000000000000000000000000000000000000000000000001017330000000000000000000000000000000000000000000000000000000000101734000000000000000000000000000000000000000000000000000000000010173500000000000000000000000000000000000000000000000000000000001017360000000000000000000000000000000000000000000000000000000000101737000000000000000000000000000000000000000000000000000000000010172700000000000000000000000000000000000000000000000000000000001017280000000000000000000000000000000000000000000000000000000000101729000000000000000000000000000000000000000000000000000000000010172a000000000000000000000000000000000000000000000000000000000010172b000000000000000000000000000000000000000000000000000000000010172c000000000000000000000000000000000000000000000000000000000010172d000000000000000000000000000000000000000000000000000000000010172e000000000000000000000000000000000000000000000000000000000010172f00000000000000000000000000000000000000000000000000000000001017300000000000000000000000000000000000000000000000000000000000101731000000000000000000000000000000000000000000000000000000000010173200000000000000000000000000000000000000000000000000000000001017330000000000000000000000000000000000000000000000000000000000101734000000000000000000000000000000000000000000000000000000000010173500000000000000000000000000000000000000000000000000000000001017360000000000000000000000000000000000000000000000000000000000101737000000000000000000000000000000000000000000000000000000000010173800000000000000000000000000000000000000000000000000000000001017280000000000000000000000000000000000000000000000000000000000101729000000000000000000000000000000000000000000000000000000000010172a000000000000000000000000000000000000000000000000000000000010172b000000000000000000000000000000000000000000000000000000000010172c000000000000000000000000000000000000000000000000000000000010172d000000000000000000000000000000000000000000000000000000000010172e000000000000000000000000000000000000000000000000000000000010172f00000000000000000000000000000000000000000000000000000000001017300000000000000000000000000000000000000000000000000000000000101731000000000000000000000000000000000000000000000000000000000010173200000000000000000000000000000000000000000000000000000000001017330000000000000000000000000000000000000000000000000000000000101734000000000000000000000000000000000000000000000000000000000010173500000000000000000000000000000000000000000000000000000000001017360000000000000000000000000000000000000000000000000000000000101737000000000000000000000000000000000000000000000000000000000010173800000000000000000000000000000000000000000000000000000000001017390000000000000000000000000000000000000000000000000000000000101729000000000000000000000000000000000000000000000000000000000010172a000000000000000000000000000000000000000000000000000000000010172b000000000000000000000000000000000000000000000000000000000010172c000000000000000000000000000000000000000000000000000000000010172d000000000000000000000000000000000000000000000000000000000010172e000000000000000000000000000000000000000000000000000000000010172f0000000000000000000000000000000000000000000000000000000000101730000000000000000000000000000000000000000000000000000000000010173100000000000000000000000000000000000000000000000000000000001017320000000000000000000000000000000000000000000000000000000000101733000000000000000000000000000000000000000000000000000000000010173400000000000000000000000000000000000000000000000000000000001017350000000000000000000000000000000000000000000000000000000000101736000000000000000000000000000000000000000000000000000000000010173700000000000000000000000000000000000000000000000000000000001017380000000000000000000000000000000000000000000000000000000000101739000000000000000000000000000000000000000000000000000000000010173a000000000000000000000000000000000000000000000000000000000010172a000000000000000000000000000000000000000000000000000000000010172b000000000000000000000000000000000000000000000000000000000010172c000000000000000000000000000000000000000000000000000000000010172d000000000000000000000000000000000000000000000000000000000010172e000000000000000000000000000000000000000000000000000000000010172f0000000000000000000000000000000000000000000000000000000000101730000000000000000000000000000000000000000000000000000000000010173100000000000000000000000000000000000000000000000000000000001017320000000000000000000000000000000000000000000000000000000000101733000000000000000000000000000000000000000000000000000000000010173400000000000000000000000000000000000000000000000000000000001017350000000000000000000000000000000000000000000000000000000000101736000000000000000000000000000000000000000000000000000000000010173700000000000000000000000000000000000000000000000000000000001017380000000000000000000000000000000000000000000000000000000000101739000000000000000000000000000000000000000000000000000000000010173a000000000000000000000000000000000000000000000000000000000010173b000000000000000000000000000000000000000000000000000000000010172b000000000000000000000000000000000000000000000000000000000010172c000000000000000000000000000000000000000000000000000000000010172d000000000000000000000000000000000000000000000000000000000010172e000000000000000000000000000000000000000000000000000000000010172f0000000000000000000000000000000000000000000000000000000000101730000000000000000000000000000000000000000000000000000000000010173100000000000000000000000000000000000000000000000000000000001017320000000000000000000000000000000000000000000000000000000000101733000000000000000000000000000000000000000000000000000000000010173400000000000000000000000000000000000000000000000000000000001017350000000000000000000000000000000000000000000000000000000000101736000000000000000000000000000000000000000000000000000000000010173700000000000000000000000000000000000000000000000000000000001017380000000000000000000000000000000000000000000000000000000000101739000000000000000000000000000000000000000000000000000000000010173a000000000000000000000000000000000000000000000000000000000010173b000000000000000000000000000000000000000000000000000000000010173c000000000000000000000000000000000000000000000000000000000010172c000000000000000000000000000000000000000000000000000000000010172d000000000000000000000000000000000000000000000000000000000010172e000000000000000000000000000000000000000000000000000000000010172f0000000000000000000000000000000000000000000000000000000000101730000000000000000000000000000000000000000000000000000000000010173100000000000000000000000000000000000000000000000000000000001017320000000000000000000000000000000000000000000000000000000000101733000000000000000000000000000000000000000000000000000000000010173400000000000000000000000000000000000000000000000000000000001017350000000000000000000000000000000000000000000000000000000000101736000000000000000000000000000000000000000000000000000000000010173700000000000000000000000000000000000000000000000000000000001017380000000000000000000000000000000000000000000000000000000000101739000000000000000000000000000000000000000000000000000000000010173a000000000000000000000000000000000000000000000000000000000010173b000000000000000000000000000000000000000000000000000000000010173c000000000000000000000000000000000000000000000000000000000010173d000000000000000000000000000000000000000000000000000000000010172d000000000000000000000000000000000000000000000000000000000010172e000000000000000000000000000000000000000000000000000000000010172f0000000000000000000000000000000000000000000000000000000000101730000000000000000000000000000000000000000000000000000000000010173100000000000000000000000000000000000000000000000000000000001017320000000000000000000000000000000000000000000000000000000000101733000000000000000000000000000000000000000000000000000000000010173400000000000000000000000000000000000000000000000000000000001017350000000000000000000000000000000000000000000000000000000000101736000000000000000000000000000000000000000000000000000000000010173700000000000000000000000000000000000000000000000000000000001017380000000000000000000000000000000000000000000000000000000000101739000000000000000000000000000000000000000000000000000000000010173a000000000000000000000000000000000000000000000000000000000010173b000000000000000000000000000000000000000000000000000000000010173c000000000000000000000000000000000000000000000000000000000010173d000000000000000000000000000000000000000000000000000000000010173e000000000000000000000000000000000000000000000000000000000010172e000000000000000000000000000000000000000000000000000000000010172f0000000000000000000000000000000000000000000000000000000000101730000000000000000000000000000000000000000000000000000000000010173100000000000000000000000000000000000000000000000000000000001017320000000000000000000000000000000000000000000000000000000000101733000000000000000000000000000000000000000000000000000000000010173400000000000000000000000000000000000000000000000000000000001017350000000000000000000000000000000000000000000000000000000000101736000000000000000000000000000000000000000000000000000000000010173700000000000000000000000000000000000000000000000000000000001017380000000000000000000000000000000000000000000000000000000000101739000000000000000000000000000000000000000000000000000000000010173a000000000000000000000000000000000000000000000000000000000010173b000000000000000000000000000000000000000000000000000000000010173c000000000000000000000000000000000000000000000000000000000010173d000000000000000000000000000000000000000000000000000000000010173e000000000000000000000000000000000000000000000000000000000010173f000000000000000000000000000000000000000000000000000000000010172f0000000000000000000000000000000000000000000000000000000000101730000000000000000000000000000000000000000000000000000000000010173100000000000000000000000000000000000000000000000000000000001017320000000000000000000000000000000000000000000000000000000000101733000000000000000000000000000000000000000000000000000000000010173400000000000000000000000000000000000000000000000000000000001017350000000000000000000000000000000000000000000000000000000000101736000000000000000000000000000000000000000000000000000000000010173700000000000000000000000000000000000000000000000000000000001017380000000000000000000000000000000000000000000000000000000000101739000000000000000000000000000000000000000000000000000000000010173a000000000000000000000000000000000000000000000000000000000010173b000000000000000000000000000000000000000000000000000000000010173c000000000000000000000000000000000000000000000000000000000010173d000000000000000000000000000000000000000000000000000000000010173e000000000000000000000000000000000000000000000000000000000010173f00000000000000000000000000000000000000000000000000000000001017400000000000000000000000000000000000000000000000000000000000101730000000000000000000000000000000000000000000000000000000000010173100000000000000000000000000000000000000000000000000000000001017320000000000000000000000000000000000000000000000000000000000101733000000000000000000000000000000000000000000000000000000000010173400000000000000000000000000000000000000000000000000000000001017350000000000000000000000000000000000000000000000000000000000101736000000000000000000000000000000000000000000000000000000000010173700000000000000000000000000000000000000000000000000000000001017380000000000000000000000000000000000000000000000000000000000101739000000000000000000000000000000000000000000000000000000000010173a000000000000000000000000000000000000000000000000000000000010173b000000000000000000000000000000000000000000000000000000000010173c000000000000000000000000000000000000000000000000000000000010173d000000000000000000000000000000000000000000000000000000000010173e000000000000000000000000000000000000000000000000000000000010173f00000000000000000000000000000000000000000000000000000000001017400000000000000000000000000000000000000000000000000000000000101741000000000000000000000000000000000000000000000000000000000010173100000000000000000000000000000000000000000000000000000000001017320000000000000000000000000000000000000000000000000000000000101733000000000000000000000000000000000000000000000000000000000010173400000000000000000000000000000000000000000000000000000000001017350000000000000000000000000000000000000000000000000000000000101736000000000000000000000000000000000000000000000000000000000010173700000000000000000000000000000000000000000000000000000000001017380000000000000000000000000000000000000000000000000000000000101739000000000000000000000000000000000000000000000000000000000010173a000000000000000000000000000000000000000000000000000000000010173b000000000000000000000000000000000000000000000000000000000010173c000000000000000000000000000000000000000000000000000000000010173d000000000000000000000000000000000000000000000000000000000010173e000000000000000000000000000000000000000000000000000000000010173f00000000000000000000000000000000000000000000000000000000001017400000000000000000000000000000000000000000000000000000000000101741000000000000000000000000000000000000000000000000000000000010174200000000000000000000000000000000000000000000000000000000001017320000000000000000000000000000000000000000000000000000000000101733000000000000000000000000000000000000000000000000000000000010173400000000000000000000000000000000000000000000000000000000001017350000000000000000000000000000000000000000000000000000000000101736000000000000000000000000000000000000000000000000000000000010173700000000000000000000000000000000000000000000000000000000001017380000000000000000000000000000000000000000000000000000000000101739000000000000000000000000000000000000000000000000000000000010173a000000000000000000000000000000000000000000000000000000000010173b000000000000000000000000000000000000000000000000000000000010173c000000000000000000000000000000000000000000000000000000000010173d000000000000000000000000000000000000000000000000000000000010173e000000000000000000000000000000000000000000000000000000000010173f00000000000000000000000000000000000000000000000000000000001017400000000000000000000000000000000000000000000000000000000000101741000000000000000000000000000000000000000000000000000000000010174200000000000000000000000000000000000000000000000000000000001017430000000000000000000000000000000000000000000000000000000000101733000000000000000000000000000000000000000000000000000000000010173400000000000000000000000000000000000000000000000000000000001017350000000000000000000000000000000000000000000000000000000000101736000000000000000000000000000000000000000000000000000000000010173700000000000000000000000000000000000000000000000000000000001017380000000000000000000000000000000000000000000000000000000000101739000000000000000000000000000000000000000000000000000000000010173a000000000000000000000000000000000000000000000000000000000010173b000000000000000000000000000000000000000000000000000000000010173c000000000000000000000000000000000000000000000000000000000010173d000000000000000000000000000000000000000000000000000000000010173e000000000000000000000000000000000000000000000000000000000010173f00000000000000000000000000000000000000000000000000000000001017400000000000000000000000000000000000000000000000000000000000101741000000000000000000000000000000000000000000000000000000000010174200000000000000000000000000000000000000000000000000000000001017430000000000000000000000000000000000000000000000000000000000101744000000000000000000000000000000000000000000000000000000000010173400000000000000000000000000000000000000000000000000000000001017350000000000000000000000000000000000000000000000000000000000101736000000000000000000000000000000000000000000000000000000000010173700000000000000000000000000000000000000000000000000000000001017380000000000000000000000000000000000000000000000000000000000101739000000000000000000000000000000000000000000000000000000000010173a000000000000000000000000000000000000000000000000000000000010173b000000000000000000000000000000000000000000000000000000000010173c000000000000000000000000000000000000000000000000000000000010173d000000000000000000000000000000000000000000000000000000000010173e000000000000000000000000000000000000000000000000000000000010173f00000000000000000000000000000000000000000000000000000000001017400000000000000000000000000000000000000000000000000000000000101741000000000000000000000000000000000000000000000000000000000010174200000000000000000000000000000000000000000000000000000000001017430000000000000000000000000000000000000000000000000000000000101744000000000000000000000000000000000000000000000000000000000010174500000000000000000000000000000000000000000000000000000000001017350000000000000000000000000000000000000000000000000000000000101736000000000000000000000000000000000000000000000000000000000010173700000000000000000000000000000000000000000000000000000000001017380000000000000000000000000000000000000000000000000000000000101739000000000000000000000000000000000000000000000000000000000010173a000000000000000000000000000000000000000000000000000000000010173b000000000000000000000000000000000000000000000000000000000010173c000000000000000000000000000000000000000000000000000000000010173d000000000000000000000000000000000000000000000000000000000010173e000000000000000000000000000000000000000000000000000000000010173f00000000000000000000000000000000000000000000000000000000001017400000000000000000000000000000000000000000000000000000000000101741000000000000000000000000000000000000000000000000000000000010174200000000000000000000000000000000000000000000000000000000001017430000000000000000000000000000000000000000000000000000000000101744000000000000000000000000000000000000000000000000000000000010174500000000000000000000000000000000000000000000000000000000001017460000000000000000000000000000000000000000000000000000000000101736000000000000000000000000000000000000000000000000000000000010173700000000000000000000000000000000000000000000000000000000001017380000000000000000000000000000000000000000000000000000000000101739000000000000000000000000000000000000000000000000000000000010173a000000000000000000000000000000000000000000000000000000000010173b000000000000000000000000000000000000000000000000000000000010173c000000000000000000000000000000000000000000000000000000000010173d000000000000000000000000000000000000000000000000000000000010173e000000000000000000000000000000000000000000000000000000000010173f00000000000000000000000000000000000000000000000000000000001017400000000000000000000000000000000000000000000000000000000000101741000000000000000000000000000000000000000000000000000000000010174200000000000000000000000000000000000000000000000000000000001017430000000000000000000000000000000000000000000000000000000000101744000000000000000000000000000000000000000000000000000000000010174500000000000000000000000000000000000000000000000000000000001017460000000000000000000000000000000000000000000000000000000000101747000000000000000000000000000000000000000000000000000000000010173700000000000000000000000000000000000000000000000000000000001017380000000000000000000000000000000000000000000000000000000000101739000000000000000000000000000000000000000000000000000000000010173a000000000000000000000000000000000000000000000000000000000010173b000000000000000000000000000000000000000000000000000000000010173c000000000000000000000000000000000000000000000000000000000010173d000000000000000000000000000000000000000000000000000000000010173e000000000000000000000000000000000000000000000000000000000010173f00000000000000000000000000000000000000000000000000000000001017400000000000000000000000000000000000000000000000000000000000101741000000000000000000000000000000000000000000000000000000000010174200000000000000000000000000000000000000000000000000000000001017430000000000000000000000000000000000000000000000000000000000101744000000000000000000000000000000000000000000000000000000000010174500000000000000000000000000000000000000000000000000000000001017460000000000000000000000000000000000000000000000000000000000101747000000000000000000000000000000000000000000000000000000000010174800000000000000000000000000000000000000000000000000000000001017380000000000000000000000000000000000000000000000000000000000101739000000000000000000000000000000000000000000000000000000000010173a000000000000000000000000000000000000000000000000000000000010173b000000000000000000000000000000000000000000000000000000000010173c000000000000000000000000000000000000000000000000000000000010173d000000000000000000000000000000000000000000000000000000000010173e000000000000000000000000000000000000000000000000000000000010173f00000000000000000000000000000000000000000000000000000000001017400000000000000000000000000000000000000000000000000000000000101741000000000000000000000000000000000000000000000000000000000010174200000000000000000000000000000000000000000000000000000000001017430000000000000000000000000000000000000000000000000000000000101744000000000000000000000000000000000000000000000000000000000010174500000000000000000000000000000000000000000000000000000000001017460000000000000000000000000000000000000000000000000000000000101747000000000000000000000000000000000000000000000000000000000010174800000000000000000000000000000000000000000000000000000000001017490000000000000000000000000000000000000000000000000000000000101739000000000000000000000000000000000000000000000000000000000010173a000000000000000000000000000000000000000000000000000000000010173b000000000000000000000000000000000000000000000000000000000010173c000000000000000000000000000000000000000000000000000000000010173d000000000000000000000000000000000000000000000000000000000010173e000000000000000000000000000000000000000000000000000000000010173f0000000000000000000000000000000000000000000000000000000000101740000000000000000000000000000000000000000000000000000000000010174100000000000000000000000000000000000000000000000000000000001017420000000000000000000000000000000000000000000000000000000000101743000000000000000000000000000000000000000000000000000000000010174400000000000000000000000000000000000000000000000000000000001017450000000000000000000000000000000000000000000000000000000000101746000000000000000000000000000000000000000000000000000000000010174700000000000000000000000000000000000000000000000000000000001017480000000000000000000000000000000000000000000000000000000000101749000000000000000000000000000000000000000000000000000000000010174a000000000000000000000000000000000000000000000000000000000010173a000000000000000000000000000000000000000000000000000000000010173b000000000000000000000000000000000000000000000000000000000010173c000000000000000000000000000000000000000000000000000000000010173d000000000000000000000000000000000000000000000000000000000010173e000000000000000000000000000000000000000000000000000000000010173f0000000000000000000000000000000000000000000000000000000000101740000000000000000000000000000000000000000000000000000000000010174100000000000000000000000000000000000000000000000000000000001017420000000000000000000000000000000000000000000000000000000000101743000000000000000000000000000000000000000000000000000000000010174400000000000000000000000000000000000000000000000000000000001017450000000000000000000000000000000000000000000000000000000000101746000000000000000000000000000000000000000000000000000000000010174700000000000000000000000000000000000000000000000000000000001017480000000000000000000000000000000000000000000000000000000000101749000000000000000000000000000000000000000000000000000000000010174a000000000000000000000000000000000000000000000000000000000010174b000000000000000000000000000000000000000000000000000000000010173b000000000000000000000000000000000000000000000000000000000010173c000000000000000000000000000000000000000000000000000000000010173d000000000000000000000000000000000000000000000000000000000010173e000000000000000000000000000000000000000000000000000000000010173f0000000000000000000000000000000000000000000000000000000000101740000000000000000000000000000000000000000000000000000000000010174100000000000000000000000000000000000000000000000000000000001017420000000000000000000000000000000000000000000000000000000000101743000000000000000000000000000000000000000000000000000000000010174400000000000000000000000000000000000000000000000000000000001017450000000000000000000000000000000000000000000000000000000000101746000000000000000000000000000000000000000000000000000000000010174700000000000000000000000000000000000000000000000000000000001017480000000000000000000000000000000000000000000000000000000000101749000000000000000000000000000000000000000000000000000000000010174a000000000000000000000000000000000000000000000000000000000010174b000000000000000000000000000000000000000000000000000000000010174c000000000000000000000000000000000000000000000000000000000010173c000000000000000000000000000000000000000000000000000000000010173d000000000000000000000000000000000000000000000000000000000010173e000000000000000000000000000000000000000000000000000000000010173f0000000000000000000000000000000000000000000000000000000000101740000000000000000000000000000000000000000000000000000000000010174100000000000000000000000000000000000000000000000000000000001017420000000000000000000000000000000000000000000000000000000000101743000000000000000000000000000000000000000000000000000000000010174400000000000000000000000000000000000000000000000000000000001017450000000000000000000000000000000000000000000000000000000000101746000000000000000000000000000000000000000000000000000000000010174700000000000000000000000000000000000000000000000000000000001017480000000000000000000000000000000000000000000000000000000000101749000000000000000000000000000000000000000000000000000000000010174a000000000000000000000000000000000000000000000000000000000010174b000000000000000000000000000000000000000000000000000000000010174c000000000000000000000000000000000000000000000000000000000010174d000000000000000000000000000000000000000000000000000000000010173d000000000000000000000000000000000000000000000000000000000010173e000000000000000000000000000000000000000000000000000000000010173f0000000000000000000000000000000000000000000000000000000000101740000000000000000000000000000000000000000000000000000000000010174100000000000000000000000000000000000000000000000000000000001017420000000000000000000000000000000000000000000000000000000000101743000000000000000000000000000000000000000000000000000000000010174400000000000000000000000000000000000000000000000000000000001017450000000000000000000000000000000000000000000000000000000000101746000000000000000000000000000000000000000000000000000000000010174700000000000000000000000000000000000000000000000000000000001017480000000000000000000000000000000000000000000000000000000000101749000000000000000000000000000000000000000000000000000000000010174a000000000000000000000000000000000000000000000000000000000010174b000000000000000000000000000000000000000000000000000000000010174c000000000000000000000000000000000000000000000000000000000010174d000000000000000000000000000000000000000000000000000000000010174e000000000000000000000000000000000000000000000000000000000010173e000000000000000000000000000000000000000000000000000000000010173f0000000000000000000000000000000000000000000000000000000000101740000000000000000000000000000000000000000000000000000000000010174100000000000000000000000000000000000000000000000000000000001017420000000000000000000000000000000000000000000000000000000000101743000000000000000000000000000000000000000000000000000000000010174400000000000000000000000000000000000000000000000000000000001017450000000000000000000000000000000000000000000000000000000000101746000000000000000000000000000000000000000000000000000000000010174700000000000000000000000000000000000000000000000000000000001017480000000000000000000000000000000000000000000000000000000000101749000000000000000000000000000000000000000000000000000000000010174a000000000000000000000000000000000000000000000000000000000010174b000000000000000000000000000000000000000000000000000000000010174c000000000000000000000000000000000000000000000000000000000010174d000000000000000000000000000000000000000000000000000000000010174e000000000000000000000000000000000000000000000000000000000010174f000000000000000000000000000000000000000000000000000000000010173f0000000000000000000000000000000000000000000000000000000000101740000000000000000000000000000000000000000000000000000000000010174100000000000000000000000000000000000000000000000000000000001017420000000000000000000000000000000000000000000000000000000000101743000000000000000000000000000000000000000000000000000000000010174400000000000000000000000000000000000000000000000000000000001017450000000000000000000000000000000000000000000000000000000000101746000000000000000000000000000000000000000000000000000000000010174700000000000000000000000000000000000000000000000000000000001017480000000000000000000000000000000000000000000000000000000000101749000000000000000000000000000000000000000000000000000000000010174a000000000000000000000000000000000000000000000000000000000010174b000000000000000000000000000000000000000000000000000000000010174c000000000000000000000000000000000000000000000000000000000010174d000000000000000000000000000000000000000000000000000000000010174e000000000000000000000000000000000000000000000000000000000010174f0000000000000000000000000000000000000000000000000000000000101750000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "txsEffectsHash": "0x009692d598a8a032778fc919537fc2a424d296da353b5f19f58907ce5b43cd12", "decodedHeader": { "contentCommitment": { "inHash": "0x00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c", "outHash": "0x000ca4a4610ad22c97c9161cedcf01faa3619f1b85457f1627d09627b71903a6", "numTxs": 4, - "txsEffectsHash": "0x00db66b36b24ebccb7543a74620018056cad2f0b08eaf251ad00362551f0a2d0" + "txsEffectsHash": "0x009692d598a8a032778fc919537fc2a424d296da353b5f19f58907ce5b43cd12" }, "globalVariables": { "blockNumber": 1, "slotNumber": "0x000000000000000000000000000000000000000000000000000000000000001a", "chainId": 31337, - "timestamp": 1732579038, + "timestamp": 1732721663, "version": 1, - "coinbase": "0x7bf63a9118e60cc630c4faa654223f715d4bd20e", - "feeRecipient": "0x2f2bacf41d88061f8a9e9234dfb8f6cdf5287e15eeeb4a6af5b0691d846bad5d", + "coinbase": "0xa2339f6422bf5c06403c4c1f6fb825374381084e", + "feeRecipient": "0x247bc3f73704c8273a70221a140b44e69ecf4c55822a83d360f35f82c17b099e", "gasFees": { "feePerDaGas": 0, - "feePerL2Gas": 54166854910 + "feePerL2Gas": 54155637780 } }, "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": "0x0237797d6a2c04d20d4fa06b74482bd970ccd51a43d9b05b57e9b91fa1ae1cae000000010000000000000000000000000000000000000000000000000000000000000004009692d598a8a032778fc919537fc2a424d296da353b5f19f58907ce5b43cd1200089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c000ca4a4610ad22c97c9161cedcf01faa3619f1b85457f1627d09627b71903a62e33ee2008411c04b99c24b313513d097a0d21a5040b6193d1f978b8226892d60000001000553ea03210e12bf95ed15f0105108f39db784d318cfe9b52cba413618711ce000001000627376bc9d9804095498d2fe262c2dceeb5ecfc696966496eaee65f1798fed50000018020a27b2839a892ce7ac7c3a76b625388d4efdd4d736f29f86d41bb32d4bc73cf0000017c0000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000067473bffa2339f6422bf5c06403c4c1f6fb825374381084e247bc3f73704c8273a70221a140b44e69ecf4c55822a83d360f35f82c17b099e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c9bed741400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x008d7601b88126ea33b5ea56a8c46de563efb2f10c8d482ac2129f14bd13b5e7", "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..25ffca3359e 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": "0x0e84a79a8805b387f272053cfb08f5a104c8ce38f9be7b547893a0519928e47d", + "blockHash": "0x1ab336412243906cd153af575a0f4e75327a7084a880b2743098c92298c82ae3", + "body": "0x00000004000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000141000000000000000000000000000000000000000000000000000000000000014100100000000000000000000000000000000000000000000000000000000001410020000000000000000000000000000000000000000000000000000000000141003000000000000000000000000000000000000000000000000000000000014100400000000000000000000000000000000000000000000000000000000001410050000000000000000000000000000000000000000000000000000000000141006000000000000000000000000000000000000000000000000000000000014100700000000000000000000000000000000000000000000000000000000001410080000000000000000000000000000000000000000000000000000000000141009000000000000000000000000000000000000000000000000000000000014100a000000000000000000000000000000000000000000000000000000000014100b000000000000000000000000000000000000000000000000000000000014100c000000000000000000000000000000000000000000000000000000000014100d000000000000000000000000000000000000000000000000000000000014100e000000000000000000000000000000000000000000000000000000000014100f0000000000000000000000000000000000000000000000000000000000141010000000000000000000000000000000000000000000000000000000000014101100000000000000000000000000000000000000000000000000000000001410120000000000000000000000000000000000000000000000000000000000141013000000000000000000000000000000000000000000000000000000000014101400000000000000000000000000000000000000000000000000000000001410150000000000000000000000000000000000000000000000000000000000141016000000000000000000000000000000000000000000000000000000000014101700000000000000000000000000000000000000000000000000000000001410180000000000000000000000000000000000000000000000000000000000141019000000000000000000000000000000000000000000000000000000000014101a000000000000000000000000000000000000000000000000000000000014101b000000000000000000000000000000000000000000000000000000000014101c000000000000000000000000000000000000000000000000000000000014101d000000000000000000000000000000000000000000000000000000000014101e000000000000000000000000000000000000000000000000000000000014101f0000000000000000000000000000000000000000000000000000000000141020000000000000000000000000000000000000000000000000000000000014102100000000000000000000000000000000000000000000000000000000001410220000000000000000000000000000000000000000000000000000000000141023000000000000000000000000000000000000000000000000000000000014102400000000000000000000000000000000000000000000000000000000001410250000000000000000000000000000000000000000000000000000000000141026000000000000000000000000000000000000000000000000000000000014102700000000000000000000000000000000000000000000000000000000001410280000000000000000000000000000000000000000000000000000000000141029000000000000000000000000000000000000000000000000000000000014102a000000000000000000000000000000000000000000000000000000000014102b000000000000000000000000000000000000000000000000000000000014102c000000000000000000000000000000000000000000000000000000000014102d000000000000000000000000000000000000000000000000000000000014102e000000000000000000000000000000000000000000000000000000000014102f0000000000000000000000000000000000000000000000000000000000141030000000000000000000000000000000000000000000000000000000000014103100000000000000000000000000000000000000000000000000000000001410320000000000000000000000000000000000000000000000000000000000141033000000000000000000000000000000000000000000000000000000000014103400000000000000000000000000000000000000000000000000000000001410350000000000000000000000000000000000000000000000000000000000141036000000000000000000000000000000000000000000000000000000000014103700000000000000000000000000000000000000000000000000000000001410380000000000000000000000000000000000000000000000000000000000141039000000000000000000000000000000000000000000000000000000000014103a000000000000000000000000000000000000000000000000000000000014103b000000000000000000000000000000000000000000000000000000000014103c000000000000000000000000000000000000000000000000000000000014103d000000000000000000000000000000000000000000000000000000000014103e000000000000000000000000000000000000000000000000000000000014103f4000000000000000000000000000000000000000000000000000000000001400010000000000000000000000000000000000000000000000000000000000141100000000000000000000000000000000000000000000000000000000000014110100000000000000000000000000000000000000000000000000000000001411020000000000000000000000000000000000000000000000000000000000141103000000000000000000000000000000000000000000000000000000000014110400000000000000000000000000000000000000000000000000000000001411050000000000000000000000000000000000000000000000000000000000141106000000000000000000000000000000000000000000000000000000000014110700000000000000000000000000000000000000000000000000000000001411080000000000000000000000000000000000000000000000000000000000141109000000000000000000000000000000000000000000000000000000000014110a000000000000000000000000000000000000000000000000000000000014110b000000000000000000000000000000000000000000000000000000000014110c000000000000000000000000000000000000000000000000000000000014110d000000000000000000000000000000000000000000000000000000000014110e000000000000000000000000000000000000000000000000000000000014110f0000000000000000000000000000000000000000000000000000000000141110000000000000000000000000000000000000000000000000000000000014111100000000000000000000000000000000000000000000000000000000001411120000000000000000000000000000000000000000000000000000000000141113000000000000000000000000000000000000000000000000000000000014111400000000000000000000000000000000000000000000000000000000001411150000000000000000000000000000000000000000000000000000000000141116000000000000000000000000000000000000000000000000000000000014111700000000000000000000000000000000000000000000000000000000001411180000000000000000000000000000000000000000000000000000000000141119000000000000000000000000000000000000000000000000000000000014111a000000000000000000000000000000000000000000000000000000000014111b000000000000000000000000000000000000000000000000000000000014111c000000000000000000000000000000000000000000000000000000000014111d000000000000000000000000000000000000000000000000000000000014111e000000000000000000000000000000000000000000000000000000000014111f0000000000000000000000000000000000000000000000000000000000141120000000000000000000000000000000000000000000000000000000000014112100000000000000000000000000000000000000000000000000000000001411220000000000000000000000000000000000000000000000000000000000141123000000000000000000000000000000000000000000000000000000000014112400000000000000000000000000000000000000000000000000000000001411250000000000000000000000000000000000000000000000000000000000141126000000000000000000000000000000000000000000000000000000000014112700000000000000000000000000000000000000000000000000000000001411280000000000000000000000000000000000000000000000000000000000141129000000000000000000000000000000000000000000000000000000000014112a000000000000000000000000000000000000000000000000000000000014112b000000000000000000000000000000000000000000000000000000000014112c000000000000000000000000000000000000000000000000000000000014112d000000000000000000000000000000000000000000000000000000000014112e000000000000000000000000000000000000000000000000000000000014112f0000000000000000000000000000000000000000000000000000000000141130000000000000000000000000000000000000000000000000000000000014113100000000000000000000000000000000000000000000000000000000001411320000000000000000000000000000000000000000000000000000000000141133000000000000000000000000000000000000000000000000000000000014113400000000000000000000000000000000000000000000000000000000001411350000000000000000000000000000000000000000000000000000000000141136000000000000000000000000000000000000000000000000000000000014113700000000000000000000000000000000000000000000000000000000001411380000000000000000000000000000000000000000000000000000000000141139000000000000000000000000000000000000000000000000000000000014113a000000000000000000000000000000000000000000000000000000000014113b000000000000000000000000000000000000000000000000000000000014113c000000000000000000000000000000000000000000000000000000000014113d000000000000000000000000000000000000000000000000000000000014113e08005c015113cb57d67dd6c0febd596819ac0298b6a23fc80aba17d445d540059a00f20b7d1308051fe7b68031a7c336b0b4b56738928b6510133aff1b818d5a9a0063eec1883a4f95f4933f9275e850d84b3d035f5061ed986c437a07331fd30e00d3a32d6bbc4fd843686fd0c5e118a73b847529977dca5b9e0e81f6604f22ca00c2f4f5133d9194d41e853e5e951e16690babce8461f25342c0bad20f2aa1e3000a6bf4739e7eb387913d955dc2e8f14f8cce27696b9d2e128b6acefafb80ee005763f7e0648f958b559677622a648f318fc79ebc0cb539170d49c26456e69200302e2b8a92cda941e9af8761b89899a58a587656d9710594e1d865b16522993f0000000000000000000000000000000000000000000000000000000000142000000000000000000000000000000000000000000000000000000000000014200a0000000000000000000000000000000000000000000000000000000000142001000000000000000000000000000000000000000000000000000000000014200b0000000000000000000000000000000000000000000000000000000000142002000000000000000000000000000000000000000000000000000000000014200c0000000000000000000000000000000000000000000000000000000000142003000000000000000000000000000000000000000000000000000000000014200d0000000000000000000000000000000000000000000000000000000000142004000000000000000000000000000000000000000000000000000000000014200e0000000000000000000000000000000000000000000000000000000000142005000000000000000000000000000000000000000000000000000000000014200f00000000000000000000000000000000000000000000000000000000001420060000000000000000000000000000000000000000000000000000000000142010000000000000000000000000000000000000000000000000000000000014200700000000000000000000000000000000000000000000000000000000001420110000000000000000000000000000000000000000000000000000000000142008000000000000000000000000000000000000000000000000000000000014201200000000000000000000000000000000000000000000000000000000001420090000000000000000000000000000000000000000000000000000000000142013000000000000000000000000000000000000000000000000000000000014200a0000000000000000000000000000000000000000000000000000000000142014000000000000000000000000000000000000000000000000000000000014200b0000000000000000000000000000000000000000000000000000000000142015000000000000000000000000000000000000000000000000000000000014200c0000000000000000000000000000000000000000000000000000000000142016000000000000000000000000000000000000000000000000000000000014200d0000000000000000000000000000000000000000000000000000000000142017000000000000000000000000000000000000000000000000000000000014200e0000000000000000000000000000000000000000000000000000000000142018000000000000000000000000000000000000000000000000000000000014200f00000000000000000000000000000000000000000000000000000000001420190000000000000000000000000000000000000000000000000000000000142010000000000000000000000000000000000000000000000000000000000014201a0000000000000000000000000000000000000000000000000000000000142011000000000000000000000000000000000000000000000000000000000014201b0000000000000000000000000000000000000000000000000000000000142012000000000000000000000000000000000000000000000000000000000014201c0000000000000000000000000000000000000000000000000000000000142013000000000000000000000000000000000000000000000000000000000014201d0000000000000000000000000000000000000000000000000000000000142014000000000000000000000000000000000000000000000000000000000014201e0000000000000000000000000000000000000000000000000000000000142015000000000000000000000000000000000000000000000000000000000014201f00000000000000000000000000000000000000000000000000000000001420160000000000000000000000000000000000000000000000000000000000142020000000000000000000000000000000000000000000000000000000000014201700000000000000000000000000000000000000000000000000000000001420210000000000000000000000000000000000000000000000000000000000142018000000000000000000000000000000000000000000000000000000000014202200000000000000000000000000000000000000000000000000000000001420190000000000000000000000000000000000000000000000000000000000142023000000000000000000000000000000000000000000000000000000000014201a0000000000000000000000000000000000000000000000000000000000142024000000000000000000000000000000000000000000000000000000000014201b0000000000000000000000000000000000000000000000000000000000142025000000000000000000000000000000000000000000000000000000000014201c0000000000000000000000000000000000000000000000000000000000142026000000000000000000000000000000000000000000000000000000000014201d0000000000000000000000000000000000000000000000000000000000142027000000000000000000000000000000000000000000000000000000000014201e0000000000000000000000000000000000000000000000000000000000142028000000000000000000000000000000000000000000000000000000000014201f00000000000000000000000000000000000000000000000000000000001420290000000000000000000000000000000000000000000000000000000000142020000000000000000000000000000000000000000000000000000000000014202a0000000000000000000000000000000000000000000000000000000000142021000000000000000000000000000000000000000000000000000000000014202b0000000000000000000000000000000000000000000000000000000000142022000000000000000000000000000000000000000000000000000000000014202c0000000000000000000000000000000000000000000000000000000000142023000000000000000000000000000000000000000000000000000000000014202d0000000000000000000000000000000000000000000000000000000000142024000000000000000000000000000000000000000000000000000000000014202e0000000000000000000000000000000000000000000000000000000000142025000000000000000000000000000000000000000000000000000000000014202f00000000000000000000000000000000000000000000000000000000001420260000000000000000000000000000000000000000000000000000000000142030000000000000000000000000000000000000000000000000000000000014202700000000000000000000000000000000000000000000000000000000001420310000000000000000000000000000000000000000000000000000000000142028000000000000000000000000000000000000000000000000000000000014203200000000000000000000000000000000000000000000000000000000001420290000000000000000000000000000000000000000000000000000000000142033000000000000000000000000000000000000000000000000000000000014202a0000000000000000000000000000000000000000000000000000000000142034000000000000000000000000000000000000000000000000000000000014202b0000000000000000000000000000000000000000000000000000000000142035000000000000000000000000000000000000000000000000000000000014202c0000000000000000000000000000000000000000000000000000000000142036000000000000000000000000000000000000000000000000000000000014202d0000000000000000000000000000000000000000000000000000000000142037000000000000000000000000000000000000000000000000000000000014202e0000000000000000000000000000000000000000000000000000000000142038000000000000000000000000000000000000000000000000000000000014202f00000000000000000000000000000000000000000000000000000000001420390000000000000000000000000000000000000000000000000000000000142030000000000000000000000000000000000000000000000000000000000014203a0000000000000000000000000000000000000000000000000000000000142031000000000000000000000000000000000000000000000000000000000014203b0000000000000000000000000000000000000000000000000000000000142032000000000000000000000000000000000000000000000000000000000014203c0000000000000000000000000000000000000000000000000000000000142033000000000000000000000000000000000000000000000000000000000014203d0000000000000000000000000000000000000000000000000000000000142034000000000000000000000000000000000000000000000000000000000014203e0000000000000000000000000000000000000000000000000000000000142035000000000000000000000000000000000000000000000000000000000014203f00000000000000000000000000000000000000000000000000000000001420360000000000000000000000000000000000000000000000000000000000142040000000000000000000000000000000000000000000000000000000000014203700000000000000000000000000000000000000000000000000000000001420410000000000000000000000000000000000000000000000000000000000142038000000000000000000000000000000000000000000000000000000000014204200000000000000000000000000000000000000000000000000000000001420390000000000000000000000000000000000000000000000000000000000142043000000000000000000000000000000000000000000000000000000000014203a0000000000000000000000000000000000000000000000000000000000142044000000000000000000000000000000000000000000000000000000000014203b0000000000000000000000000000000000000000000000000000000000142045000000000000000000000000000000000000000000000000000000000014203c0000000000000000000000000000000000000000000000000000000000142046000000000000000000000000000000000000000000000000000000000014203d0000000000000000000000000000000000000000000000000000000000142047000000000000000000000000000000000000000000000000000000000014203e0000000000000000000000000000000000000000000000000000000000142048400000000000000000000000000000000000000000000000000000000000141700000000000000000000000000000000000000000000000000000000000014170100000000000000000000000000000000000000000000000000000000001417020000000000000000000000000000000000000000000000000000000000141703000000000000000000000000000000000000000000000000000000000014170400000000000000000000000000000000000000000000000000000000001417050000000000000000000000000000000000000000000000000000000000141706000000000000000000000000000000000000000000000000000000000014170700000000000000000000000000000000000000000000000000000000001417080000000000000000000000000000000000000000000000000000000000141709000000000000000000000000000000000000000000000000000000000014170a000000000000000000000000000000000000000000000000000000000014170b000000000000000000000000000000000000000000000000000000000014170c000000000000000000000000000000000000000000000000000000000014170d000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f00000000000000000000000000000000000000000000000000000000001417100000000000000000000000000000000000000000000000000000000000141711000000000000000000000000000000000000000000000000000000000014170100000000000000000000000000000000000000000000000000000000001417020000000000000000000000000000000000000000000000000000000000141703000000000000000000000000000000000000000000000000000000000014170400000000000000000000000000000000000000000000000000000000001417050000000000000000000000000000000000000000000000000000000000141706000000000000000000000000000000000000000000000000000000000014170700000000000000000000000000000000000000000000000000000000001417080000000000000000000000000000000000000000000000000000000000141709000000000000000000000000000000000000000000000000000000000014170a000000000000000000000000000000000000000000000000000000000014170b000000000000000000000000000000000000000000000000000000000014170c000000000000000000000000000000000000000000000000000000000014170d000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f00000000000000000000000000000000000000000000000000000000001417100000000000000000000000000000000000000000000000000000000000141711000000000000000000000000000000000000000000000000000000000014171200000000000000000000000000000000000000000000000000000000001417020000000000000000000000000000000000000000000000000000000000141703000000000000000000000000000000000000000000000000000000000014170400000000000000000000000000000000000000000000000000000000001417050000000000000000000000000000000000000000000000000000000000141706000000000000000000000000000000000000000000000000000000000014170700000000000000000000000000000000000000000000000000000000001417080000000000000000000000000000000000000000000000000000000000141709000000000000000000000000000000000000000000000000000000000014170a000000000000000000000000000000000000000000000000000000000014170b000000000000000000000000000000000000000000000000000000000014170c000000000000000000000000000000000000000000000000000000000014170d000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f00000000000000000000000000000000000000000000000000000000001417100000000000000000000000000000000000000000000000000000000000141711000000000000000000000000000000000000000000000000000000000014171200000000000000000000000000000000000000000000000000000000001417130000000000000000000000000000000000000000000000000000000000141703000000000000000000000000000000000000000000000000000000000014170400000000000000000000000000000000000000000000000000000000001417050000000000000000000000000000000000000000000000000000000000141706000000000000000000000000000000000000000000000000000000000014170700000000000000000000000000000000000000000000000000000000001417080000000000000000000000000000000000000000000000000000000000141709000000000000000000000000000000000000000000000000000000000014170a000000000000000000000000000000000000000000000000000000000014170b000000000000000000000000000000000000000000000000000000000014170c000000000000000000000000000000000000000000000000000000000014170d000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f00000000000000000000000000000000000000000000000000000000001417100000000000000000000000000000000000000000000000000000000000141711000000000000000000000000000000000000000000000000000000000014171200000000000000000000000000000000000000000000000000000000001417130000000000000000000000000000000000000000000000000000000000141714000000000000000000000000000000000000000000000000000000000014170400000000000000000000000000000000000000000000000000000000001417050000000000000000000000000000000000000000000000000000000000141706000000000000000000000000000000000000000000000000000000000014170700000000000000000000000000000000000000000000000000000000001417080000000000000000000000000000000000000000000000000000000000141709000000000000000000000000000000000000000000000000000000000014170a000000000000000000000000000000000000000000000000000000000014170b000000000000000000000000000000000000000000000000000000000014170c000000000000000000000000000000000000000000000000000000000014170d000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f00000000000000000000000000000000000000000000000000000000001417100000000000000000000000000000000000000000000000000000000000141711000000000000000000000000000000000000000000000000000000000014171200000000000000000000000000000000000000000000000000000000001417130000000000000000000000000000000000000000000000000000000000141714000000000000000000000000000000000000000000000000000000000014171500000000000000000000000000000000000000000000000000000000001417050000000000000000000000000000000000000000000000000000000000141706000000000000000000000000000000000000000000000000000000000014170700000000000000000000000000000000000000000000000000000000001417080000000000000000000000000000000000000000000000000000000000141709000000000000000000000000000000000000000000000000000000000014170a000000000000000000000000000000000000000000000000000000000014170b000000000000000000000000000000000000000000000000000000000014170c000000000000000000000000000000000000000000000000000000000014170d000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f00000000000000000000000000000000000000000000000000000000001417100000000000000000000000000000000000000000000000000000000000141711000000000000000000000000000000000000000000000000000000000014171200000000000000000000000000000000000000000000000000000000001417130000000000000000000000000000000000000000000000000000000000141714000000000000000000000000000000000000000000000000000000000014171500000000000000000000000000000000000000000000000000000000001417160000000000000000000000000000000000000000000000000000000000141706000000000000000000000000000000000000000000000000000000000014170700000000000000000000000000000000000000000000000000000000001417080000000000000000000000000000000000000000000000000000000000141709000000000000000000000000000000000000000000000000000000000014170a000000000000000000000000000000000000000000000000000000000014170b000000000000000000000000000000000000000000000000000000000014170c000000000000000000000000000000000000000000000000000000000014170d000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f00000000000000000000000000000000000000000000000000000000001417100000000000000000000000000000000000000000000000000000000000141711000000000000000000000000000000000000000000000000000000000014171200000000000000000000000000000000000000000000000000000000001417130000000000000000000000000000000000000000000000000000000000141714000000000000000000000000000000000000000000000000000000000014171500000000000000000000000000000000000000000000000000000000001417160000000000000000000000000000000000000000000000000000000000141717000000000000000000000000000000000000000000000000000000000014170700000000000000000000000000000000000000000000000000000000001417080000000000000000000000000000000000000000000000000000000000141709000000000000000000000000000000000000000000000000000000000014170a000000000000000000000000000000000000000000000000000000000014170b000000000000000000000000000000000000000000000000000000000014170c000000000000000000000000000000000000000000000000000000000014170d000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f00000000000000000000000000000000000000000000000000000000001417100000000000000000000000000000000000000000000000000000000000141711000000000000000000000000000000000000000000000000000000000014171200000000000000000000000000000000000000000000000000000000001417130000000000000000000000000000000000000000000000000000000000141714000000000000000000000000000000000000000000000000000000000014171500000000000000000000000000000000000000000000000000000000001417160000000000000000000000000000000000000000000000000000000000141717000000000000000000000000000000000000000000000000000000000014171800000000000000000000000000000000000000000000000000000000001417080000000000000000000000000000000000000000000000000000000000141709000000000000000000000000000000000000000000000000000000000014170a000000000000000000000000000000000000000000000000000000000014170b000000000000000000000000000000000000000000000000000000000014170c000000000000000000000000000000000000000000000000000000000014170d000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f00000000000000000000000000000000000000000000000000000000001417100000000000000000000000000000000000000000000000000000000000141711000000000000000000000000000000000000000000000000000000000014171200000000000000000000000000000000000000000000000000000000001417130000000000000000000000000000000000000000000000000000000000141714000000000000000000000000000000000000000000000000000000000014171500000000000000000000000000000000000000000000000000000000001417160000000000000000000000000000000000000000000000000000000000141717000000000000000000000000000000000000000000000000000000000014171800000000000000000000000000000000000000000000000000000000001417190000000000000000000000000000000000000000000000000000000000141709000000000000000000000000000000000000000000000000000000000014170a000000000000000000000000000000000000000000000000000000000014170b000000000000000000000000000000000000000000000000000000000014170c000000000000000000000000000000000000000000000000000000000014170d000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f0000000000000000000000000000000000000000000000000000000000141710000000000000000000000000000000000000000000000000000000000014171100000000000000000000000000000000000000000000000000000000001417120000000000000000000000000000000000000000000000000000000000141713000000000000000000000000000000000000000000000000000000000014171400000000000000000000000000000000000000000000000000000000001417150000000000000000000000000000000000000000000000000000000000141716000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014170a000000000000000000000000000000000000000000000000000000000014170b000000000000000000000000000000000000000000000000000000000014170c000000000000000000000000000000000000000000000000000000000014170d000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f0000000000000000000000000000000000000000000000000000000000141710000000000000000000000000000000000000000000000000000000000014171100000000000000000000000000000000000000000000000000000000001417120000000000000000000000000000000000000000000000000000000000141713000000000000000000000000000000000000000000000000000000000014171400000000000000000000000000000000000000000000000000000000001417150000000000000000000000000000000000000000000000000000000000141716000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014170b000000000000000000000000000000000000000000000000000000000014170c000000000000000000000000000000000000000000000000000000000014170d000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f0000000000000000000000000000000000000000000000000000000000141710000000000000000000000000000000000000000000000000000000000014171100000000000000000000000000000000000000000000000000000000001417120000000000000000000000000000000000000000000000000000000000141713000000000000000000000000000000000000000000000000000000000014171400000000000000000000000000000000000000000000000000000000001417150000000000000000000000000000000000000000000000000000000000141716000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014170c000000000000000000000000000000000000000000000000000000000014170d000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f0000000000000000000000000000000000000000000000000000000000141710000000000000000000000000000000000000000000000000000000000014171100000000000000000000000000000000000000000000000000000000001417120000000000000000000000000000000000000000000000000000000000141713000000000000000000000000000000000000000000000000000000000014171400000000000000000000000000000000000000000000000000000000001417150000000000000000000000000000000000000000000000000000000000141716000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014170d000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f0000000000000000000000000000000000000000000000000000000000141710000000000000000000000000000000000000000000000000000000000014171100000000000000000000000000000000000000000000000000000000001417120000000000000000000000000000000000000000000000000000000000141713000000000000000000000000000000000000000000000000000000000014171400000000000000000000000000000000000000000000000000000000001417150000000000000000000000000000000000000000000000000000000000141716000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014170e000000000000000000000000000000000000000000000000000000000014170f0000000000000000000000000000000000000000000000000000000000141710000000000000000000000000000000000000000000000000000000000014171100000000000000000000000000000000000000000000000000000000001417120000000000000000000000000000000000000000000000000000000000141713000000000000000000000000000000000000000000000000000000000014171400000000000000000000000000000000000000000000000000000000001417150000000000000000000000000000000000000000000000000000000000141716000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f000000000000000000000000000000000000000000000000000000000014170f0000000000000000000000000000000000000000000000000000000000141710000000000000000000000000000000000000000000000000000000000014171100000000000000000000000000000000000000000000000000000000001417120000000000000000000000000000000000000000000000000000000000141713000000000000000000000000000000000000000000000000000000000014171400000000000000000000000000000000000000000000000000000000001417150000000000000000000000000000000000000000000000000000000000141716000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f00000000000000000000000000000000000000000000000000000000001417200000000000000000000000000000000000000000000000000000000000141710000000000000000000000000000000000000000000000000000000000014171100000000000000000000000000000000000000000000000000000000001417120000000000000000000000000000000000000000000000000000000000141713000000000000000000000000000000000000000000000000000000000014171400000000000000000000000000000000000000000000000000000000001417150000000000000000000000000000000000000000000000000000000000141716000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f00000000000000000000000000000000000000000000000000000000001417200000000000000000000000000000000000000000000000000000000000141721000000000000000000000000000000000000000000000000000000000014171100000000000000000000000000000000000000000000000000000000001417120000000000000000000000000000000000000000000000000000000000141713000000000000000000000000000000000000000000000000000000000014171400000000000000000000000000000000000000000000000000000000001417150000000000000000000000000000000000000000000000000000000000141716000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f00000000000000000000000000000000000000000000000000000000001417200000000000000000000000000000000000000000000000000000000000141721000000000000000000000000000000000000000000000000000000000014172200000000000000000000000000000000000000000000000000000000001417120000000000000000000000000000000000000000000000000000000000141713000000000000000000000000000000000000000000000000000000000014171400000000000000000000000000000000000000000000000000000000001417150000000000000000000000000000000000000000000000000000000000141716000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f00000000000000000000000000000000000000000000000000000000001417200000000000000000000000000000000000000000000000000000000000141721000000000000000000000000000000000000000000000000000000000014172200000000000000000000000000000000000000000000000000000000001417230000000000000000000000000000000000000000000000000000000000141713000000000000000000000000000000000000000000000000000000000014171400000000000000000000000000000000000000000000000000000000001417150000000000000000000000000000000000000000000000000000000000141716000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f00000000000000000000000000000000000000000000000000000000001417200000000000000000000000000000000000000000000000000000000000141721000000000000000000000000000000000000000000000000000000000014172200000000000000000000000000000000000000000000000000000000001417230000000000000000000000000000000000000000000000000000000000141724000000000000000000000000000000000000000000000000000000000014171400000000000000000000000000000000000000000000000000000000001417150000000000000000000000000000000000000000000000000000000000141716000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f00000000000000000000000000000000000000000000000000000000001417200000000000000000000000000000000000000000000000000000000000141721000000000000000000000000000000000000000000000000000000000014172200000000000000000000000000000000000000000000000000000000001417230000000000000000000000000000000000000000000000000000000000141724000000000000000000000000000000000000000000000000000000000014172500000000000000000000000000000000000000000000000000000000001417150000000000000000000000000000000000000000000000000000000000141716000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f00000000000000000000000000000000000000000000000000000000001417200000000000000000000000000000000000000000000000000000000000141721000000000000000000000000000000000000000000000000000000000014172200000000000000000000000000000000000000000000000000000000001417230000000000000000000000000000000000000000000000000000000000141724000000000000000000000000000000000000000000000000000000000014172500000000000000000000000000000000000000000000000000000000001417260000000000000000000000000000000000000000000000000000000000141716000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f00000000000000000000000000000000000000000000000000000000001417200000000000000000000000000000000000000000000000000000000000141721000000000000000000000000000000000000000000000000000000000014172200000000000000000000000000000000000000000000000000000000001417230000000000000000000000000000000000000000000000000000000000141724000000000000000000000000000000000000000000000000000000000014172500000000000000000000000000000000000000000000000000000000001417260000000000000000000000000000000000000000000000000000000000141727000000000000000000000000000000000000000000000000000000000014171700000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f00000000000000000000000000000000000000000000000000000000001417200000000000000000000000000000000000000000000000000000000000141721000000000000000000000000000000000000000000000000000000000014172200000000000000000000000000000000000000000000000000000000001417230000000000000000000000000000000000000000000000000000000000141724000000000000000000000000000000000000000000000000000000000014172500000000000000000000000000000000000000000000000000000000001417260000000000000000000000000000000000000000000000000000000000141727000000000000000000000000000000000000000000000000000000000014172800000000000000000000000000000000000000000000000000000000001417180000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f00000000000000000000000000000000000000000000000000000000001417200000000000000000000000000000000000000000000000000000000000141721000000000000000000000000000000000000000000000000000000000014172200000000000000000000000000000000000000000000000000000000001417230000000000000000000000000000000000000000000000000000000000141724000000000000000000000000000000000000000000000000000000000014172500000000000000000000000000000000000000000000000000000000001417260000000000000000000000000000000000000000000000000000000000141727000000000000000000000000000000000000000000000000000000000014172800000000000000000000000000000000000000000000000000000000001417290000000000000000000000000000000000000000000000000000000000141719000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f0000000000000000000000000000000000000000000000000000000000141720000000000000000000000000000000000000000000000000000000000014172100000000000000000000000000000000000000000000000000000000001417220000000000000000000000000000000000000000000000000000000000141723000000000000000000000000000000000000000000000000000000000014172400000000000000000000000000000000000000000000000000000000001417250000000000000000000000000000000000000000000000000000000000141726000000000000000000000000000000000000000000000000000000000014172700000000000000000000000000000000000000000000000000000000001417280000000000000000000000000000000000000000000000000000000000141729000000000000000000000000000000000000000000000000000000000014172a000000000000000000000000000000000000000000000000000000000014171a000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f0000000000000000000000000000000000000000000000000000000000141720000000000000000000000000000000000000000000000000000000000014172100000000000000000000000000000000000000000000000000000000001417220000000000000000000000000000000000000000000000000000000000141723000000000000000000000000000000000000000000000000000000000014172400000000000000000000000000000000000000000000000000000000001417250000000000000000000000000000000000000000000000000000000000141726000000000000000000000000000000000000000000000000000000000014172700000000000000000000000000000000000000000000000000000000001417280000000000000000000000000000000000000000000000000000000000141729000000000000000000000000000000000000000000000000000000000014172a000000000000000000000000000000000000000000000000000000000014172b000000000000000000000000000000000000000000000000000000000014171b000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f0000000000000000000000000000000000000000000000000000000000141720000000000000000000000000000000000000000000000000000000000014172100000000000000000000000000000000000000000000000000000000001417220000000000000000000000000000000000000000000000000000000000141723000000000000000000000000000000000000000000000000000000000014172400000000000000000000000000000000000000000000000000000000001417250000000000000000000000000000000000000000000000000000000000141726000000000000000000000000000000000000000000000000000000000014172700000000000000000000000000000000000000000000000000000000001417280000000000000000000000000000000000000000000000000000000000141729000000000000000000000000000000000000000000000000000000000014172a000000000000000000000000000000000000000000000000000000000014172b000000000000000000000000000000000000000000000000000000000014172c000000000000000000000000000000000000000000000000000000000014171c000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f0000000000000000000000000000000000000000000000000000000000141720000000000000000000000000000000000000000000000000000000000014172100000000000000000000000000000000000000000000000000000000001417220000000000000000000000000000000000000000000000000000000000141723000000000000000000000000000000000000000000000000000000000014172400000000000000000000000000000000000000000000000000000000001417250000000000000000000000000000000000000000000000000000000000141726000000000000000000000000000000000000000000000000000000000014172700000000000000000000000000000000000000000000000000000000001417280000000000000000000000000000000000000000000000000000000000141729000000000000000000000000000000000000000000000000000000000014172a000000000000000000000000000000000000000000000000000000000014172b000000000000000000000000000000000000000000000000000000000014172c000000000000000000000000000000000000000000000000000000000014172d000000000000000000000000000000000000000000000000000000000014171d000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f0000000000000000000000000000000000000000000000000000000000141720000000000000000000000000000000000000000000000000000000000014172100000000000000000000000000000000000000000000000000000000001417220000000000000000000000000000000000000000000000000000000000141723000000000000000000000000000000000000000000000000000000000014172400000000000000000000000000000000000000000000000000000000001417250000000000000000000000000000000000000000000000000000000000141726000000000000000000000000000000000000000000000000000000000014172700000000000000000000000000000000000000000000000000000000001417280000000000000000000000000000000000000000000000000000000000141729000000000000000000000000000000000000000000000000000000000014172a000000000000000000000000000000000000000000000000000000000014172b000000000000000000000000000000000000000000000000000000000014172c000000000000000000000000000000000000000000000000000000000014172d000000000000000000000000000000000000000000000000000000000014172e000000000000000000000000000000000000000000000000000000000014171e000000000000000000000000000000000000000000000000000000000014171f0000000000000000000000000000000000000000000000000000000000141720000000000000000000000000000000000000000000000000000000000014172100000000000000000000000000000000000000000000000000000000001417220000000000000000000000000000000000000000000000000000000000141723000000000000000000000000000000000000000000000000000000000014172400000000000000000000000000000000000000000000000000000000001417250000000000000000000000000000000000000000000000000000000000141726000000000000000000000000000000000000000000000000000000000014172700000000000000000000000000000000000000000000000000000000001417280000000000000000000000000000000000000000000000000000000000141729000000000000000000000000000000000000000000000000000000000014172a000000000000000000000000000000000000000000000000000000000014172b000000000000000000000000000000000000000000000000000000000014172c000000000000000000000000000000000000000000000000000000000014172d000000000000000000000000000000000000000000000000000000000014172e000000000000000000000000000000000000000000000000000000000014172f000000000000000000000000000000000000000000000000000000000014171f0000000000000000000000000000000000000000000000000000000000141720000000000000000000000000000000000000000000000000000000000014172100000000000000000000000000000000000000000000000000000000001417220000000000000000000000000000000000000000000000000000000000141723000000000000000000000000000000000000000000000000000000000014172400000000000000000000000000000000000000000000000000000000001417250000000000000000000000000000000000000000000000000000000000141726000000000000000000000000000000000000000000000000000000000014172700000000000000000000000000000000000000000000000000000000001417280000000000000000000000000000000000000000000000000000000000141729000000000000000000000000000000000000000000000000000000000014172a000000000000000000000000000000000000000000000000000000000014172b000000000000000000000000000000000000000000000000000000000014172c000000000000000000000000000000000000000000000000000000000014172d000000000000000000000000000000000000000000000000000000000014172e000000000000000000000000000000000000000000000000000000000014172f00000000000000000000000000000000000000000000000000000000001417300000000000000000000000000000000000000000000000000000000000141720000000000000000000000000000000000000000000000000000000000014172100000000000000000000000000000000000000000000000000000000001417220000000000000000000000000000000000000000000000000000000000141723000000000000000000000000000000000000000000000000000000000014172400000000000000000000000000000000000000000000000000000000001417250000000000000000000000000000000000000000000000000000000000141726000000000000000000000000000000000000000000000000000000000014172700000000000000000000000000000000000000000000000000000000001417280000000000000000000000000000000000000000000000000000000000141729000000000000000000000000000000000000000000000000000000000014172a000000000000000000000000000000000000000000000000000000000014172b000000000000000000000000000000000000000000000000000000000014172c000000000000000000000000000000000000000000000000000000000014172d000000000000000000000000000000000000000000000000000000000014172e000000000000000000000000000000000000000000000000000000000014172f00000000000000000000000000000000000000000000000000000000001417300000000000000000000000000000000000000000000000000000000000141731000000000000000000000000000000000000000000000000000000000014172100000000000000000000000000000000000000000000000000000000001417220000000000000000000000000000000000000000000000000000000000141723000000000000000000000000000000000000000000000000000000000014172400000000000000000000000000000000000000000000000000000000001417250000000000000000000000000000000000000000000000000000000000141726000000000000000000000000000000000000000000000000000000000014172700000000000000000000000000000000000000000000000000000000001417280000000000000000000000000000000000000000000000000000000000141729000000000000000000000000000000000000000000000000000000000014172a000000000000000000000000000000000000000000000000000000000014172b000000000000000000000000000000000000000000000000000000000014172c000000000000000000000000000000000000000000000000000000000014172d000000000000000000000000000000000000000000000000000000000014172e000000000000000000000000000000000000000000000000000000000014172f00000000000000000000000000000000000000000000000000000000001417300000000000000000000000000000000000000000000000000000000000141731000000000000000000000000000000000000000000000000000000000014173200000000000000000000000000000000000000000000000000000000001417220000000000000000000000000000000000000000000000000000000000141723000000000000000000000000000000000000000000000000000000000014172400000000000000000000000000000000000000000000000000000000001417250000000000000000000000000000000000000000000000000000000000141726000000000000000000000000000000000000000000000000000000000014172700000000000000000000000000000000000000000000000000000000001417280000000000000000000000000000000000000000000000000000000000141729000000000000000000000000000000000000000000000000000000000014172a000000000000000000000000000000000000000000000000000000000014172b000000000000000000000000000000000000000000000000000000000014172c000000000000000000000000000000000000000000000000000000000014172d000000000000000000000000000000000000000000000000000000000014172e000000000000000000000000000000000000000000000000000000000014172f00000000000000000000000000000000000000000000000000000000001417300000000000000000000000000000000000000000000000000000000000141731000000000000000000000000000000000000000000000000000000000014173200000000000000000000000000000000000000000000000000000000001417330000000000000000000000000000000000000000000000000000000000141723000000000000000000000000000000000000000000000000000000000014172400000000000000000000000000000000000000000000000000000000001417250000000000000000000000000000000000000000000000000000000000141726000000000000000000000000000000000000000000000000000000000014172700000000000000000000000000000000000000000000000000000000001417280000000000000000000000000000000000000000000000000000000000141729000000000000000000000000000000000000000000000000000000000014172a000000000000000000000000000000000000000000000000000000000014172b000000000000000000000000000000000000000000000000000000000014172c000000000000000000000000000000000000000000000000000000000014172d000000000000000000000000000000000000000000000000000000000014172e000000000000000000000000000000000000000000000000000000000014172f00000000000000000000000000000000000000000000000000000000001417300000000000000000000000000000000000000000000000000000000000141731000000000000000000000000000000000000000000000000000000000014173200000000000000000000000000000000000000000000000000000000001417330000000000000000000000000000000000000000000000000000000000141734000000000000000000000000000000000000000000000000000000000014172400000000000000000000000000000000000000000000000000000000001417250000000000000000000000000000000000000000000000000000000000141726000000000000000000000000000000000000000000000000000000000014172700000000000000000000000000000000000000000000000000000000001417280000000000000000000000000000000000000000000000000000000000141729000000000000000000000000000000000000000000000000000000000014172a000000000000000000000000000000000000000000000000000000000014172b000000000000000000000000000000000000000000000000000000000014172c000000000000000000000000000000000000000000000000000000000014172d000000000000000000000000000000000000000000000000000000000014172e000000000000000000000000000000000000000000000000000000000014172f00000000000000000000000000000000000000000000000000000000001417300000000000000000000000000000000000000000000000000000000000141731000000000000000000000000000000000000000000000000000000000014173200000000000000000000000000000000000000000000000000000000001417330000000000000000000000000000000000000000000000000000000000141734000000000000000000000000000000000000000000000000000000000014173500000000000000000000000000000000000000000000000000000000001417250000000000000000000000000000000000000000000000000000000000141726000000000000000000000000000000000000000000000000000000000014172700000000000000000000000000000000000000000000000000000000001417280000000000000000000000000000000000000000000000000000000000141729000000000000000000000000000000000000000000000000000000000014172a000000000000000000000000000000000000000000000000000000000014172b000000000000000000000000000000000000000000000000000000000014172c000000000000000000000000000000000000000000000000000000000014172d000000000000000000000000000000000000000000000000000000000014172e000000000000000000000000000000000000000000000000000000000014172f00000000000000000000000000000000000000000000000000000000001417300000000000000000000000000000000000000000000000000000000000141731000000000000000000000000000000000000000000000000000000000014173200000000000000000000000000000000000000000000000000000000001417330000000000000000000000000000000000000000000000000000000000141734000000000000000000000000000000000000000000000000000000000014173500000000000000000000000000000000000000000000000000000000001417360000000000000000000000000000000000000000000000000000000000141726000000000000000000000000000000000000000000000000000000000014172700000000000000000000000000000000000000000000000000000000001417280000000000000000000000000000000000000000000000000000000000141729000000000000000000000000000000000000000000000000000000000014172a000000000000000000000000000000000000000000000000000000000014172b000000000000000000000000000000000000000000000000000000000014172c000000000000000000000000000000000000000000000000000000000014172d000000000000000000000000000000000000000000000000000000000014172e000000000000000000000000000000000000000000000000000000000014172f00000000000000000000000000000000000000000000000000000000001417300000000000000000000000000000000000000000000000000000000000141731000000000000000000000000000000000000000000000000000000000014173200000000000000000000000000000000000000000000000000000000001417330000000000000000000000000000000000000000000000000000000000141734000000000000000000000000000000000000000000000000000000000014173500000000000000000000000000000000000000000000000000000000001417360000000000000000000000000000000000000000000000000000000000141737000000000000000000000000000000000000000000000000000000000014172700000000000000000000000000000000000000000000000000000000001417280000000000000000000000000000000000000000000000000000000000141729000000000000000000000000000000000000000000000000000000000014172a000000000000000000000000000000000000000000000000000000000014172b000000000000000000000000000000000000000000000000000000000014172c000000000000000000000000000000000000000000000000000000000014172d000000000000000000000000000000000000000000000000000000000014172e000000000000000000000000000000000000000000000000000000000014172f00000000000000000000000000000000000000000000000000000000001417300000000000000000000000000000000000000000000000000000000000141731000000000000000000000000000000000000000000000000000000000014173200000000000000000000000000000000000000000000000000000000001417330000000000000000000000000000000000000000000000000000000000141734000000000000000000000000000000000000000000000000000000000014173500000000000000000000000000000000000000000000000000000000001417360000000000000000000000000000000000000000000000000000000000141737000000000000000000000000000000000000000000000000000000000014173800000000000000000000000000000000000000000000000000000000001417280000000000000000000000000000000000000000000000000000000000141729000000000000000000000000000000000000000000000000000000000014172a000000000000000000000000000000000000000000000000000000000014172b000000000000000000000000000000000000000000000000000000000014172c000000000000000000000000000000000000000000000000000000000014172d000000000000000000000000000000000000000000000000000000000014172e000000000000000000000000000000000000000000000000000000000014172f00000000000000000000000000000000000000000000000000000000001417300000000000000000000000000000000000000000000000000000000000141731000000000000000000000000000000000000000000000000000000000014173200000000000000000000000000000000000000000000000000000000001417330000000000000000000000000000000000000000000000000000000000141734000000000000000000000000000000000000000000000000000000000014173500000000000000000000000000000000000000000000000000000000001417360000000000000000000000000000000000000000000000000000000000141737000000000000000000000000000000000000000000000000000000000014173800000000000000000000000000000000000000000000000000000000001417390000000000000000000000000000000000000000000000000000000000141729000000000000000000000000000000000000000000000000000000000014172a000000000000000000000000000000000000000000000000000000000014172b000000000000000000000000000000000000000000000000000000000014172c000000000000000000000000000000000000000000000000000000000014172d000000000000000000000000000000000000000000000000000000000014172e000000000000000000000000000000000000000000000000000000000014172f0000000000000000000000000000000000000000000000000000000000141730000000000000000000000000000000000000000000000000000000000014173100000000000000000000000000000000000000000000000000000000001417320000000000000000000000000000000000000000000000000000000000141733000000000000000000000000000000000000000000000000000000000014173400000000000000000000000000000000000000000000000000000000001417350000000000000000000000000000000000000000000000000000000000141736000000000000000000000000000000000000000000000000000000000014173700000000000000000000000000000000000000000000000000000000001417380000000000000000000000000000000000000000000000000000000000141739000000000000000000000000000000000000000000000000000000000014173a000000000000000000000000000000000000000000000000000000000014172a000000000000000000000000000000000000000000000000000000000014172b000000000000000000000000000000000000000000000000000000000014172c000000000000000000000000000000000000000000000000000000000014172d000000000000000000000000000000000000000000000000000000000014172e000000000000000000000000000000000000000000000000000000000014172f0000000000000000000000000000000000000000000000000000000000141730000000000000000000000000000000000000000000000000000000000014173100000000000000000000000000000000000000000000000000000000001417320000000000000000000000000000000000000000000000000000000000141733000000000000000000000000000000000000000000000000000000000014173400000000000000000000000000000000000000000000000000000000001417350000000000000000000000000000000000000000000000000000000000141736000000000000000000000000000000000000000000000000000000000014173700000000000000000000000000000000000000000000000000000000001417380000000000000000000000000000000000000000000000000000000000141739000000000000000000000000000000000000000000000000000000000014173a000000000000000000000000000000000000000000000000000000000014173b000000000000000000000000000000000000000000000000000000000014172b000000000000000000000000000000000000000000000000000000000014172c000000000000000000000000000000000000000000000000000000000014172d000000000000000000000000000000000000000000000000000000000014172e000000000000000000000000000000000000000000000000000000000014172f0000000000000000000000000000000000000000000000000000000000141730000000000000000000000000000000000000000000000000000000000014173100000000000000000000000000000000000000000000000000000000001417320000000000000000000000000000000000000000000000000000000000141733000000000000000000000000000000000000000000000000000000000014173400000000000000000000000000000000000000000000000000000000001417350000000000000000000000000000000000000000000000000000000000141736000000000000000000000000000000000000000000000000000000000014173700000000000000000000000000000000000000000000000000000000001417380000000000000000000000000000000000000000000000000000000000141739000000000000000000000000000000000000000000000000000000000014173a000000000000000000000000000000000000000000000000000000000014173b000000000000000000000000000000000000000000000000000000000014173c000000000000000000000000000000000000000000000000000000000014172c000000000000000000000000000000000000000000000000000000000014172d000000000000000000000000000000000000000000000000000000000014172e000000000000000000000000000000000000000000000000000000000014172f0000000000000000000000000000000000000000000000000000000000141730000000000000000000000000000000000000000000000000000000000014173100000000000000000000000000000000000000000000000000000000001417320000000000000000000000000000000000000000000000000000000000141733000000000000000000000000000000000000000000000000000000000014173400000000000000000000000000000000000000000000000000000000001417350000000000000000000000000000000000000000000000000000000000141736000000000000000000000000000000000000000000000000000000000014173700000000000000000000000000000000000000000000000000000000001417380000000000000000000000000000000000000000000000000000000000141739000000000000000000000000000000000000000000000000000000000014173a000000000000000000000000000000000000000000000000000000000014173b000000000000000000000000000000000000000000000000000000000014173c000000000000000000000000000000000000000000000000000000000014173d000000000000000000000000000000000000000000000000000000000014172d000000000000000000000000000000000000000000000000000000000014172e000000000000000000000000000000000000000000000000000000000014172f0000000000000000000000000000000000000000000000000000000000141730000000000000000000000000000000000000000000000000000000000014173100000000000000000000000000000000000000000000000000000000001417320000000000000000000000000000000000000000000000000000000000141733000000000000000000000000000000000000000000000000000000000014173400000000000000000000000000000000000000000000000000000000001417350000000000000000000000000000000000000000000000000000000000141736000000000000000000000000000000000000000000000000000000000014173700000000000000000000000000000000000000000000000000000000001417380000000000000000000000000000000000000000000000000000000000141739000000000000000000000000000000000000000000000000000000000014173a000000000000000000000000000000000000000000000000000000000014173b000000000000000000000000000000000000000000000000000000000014173c000000000000000000000000000000000000000000000000000000000014173d000000000000000000000000000000000000000000000000000000000014173e000000000000000000000000000000000000000000000000000000000014172e000000000000000000000000000000000000000000000000000000000014172f0000000000000000000000000000000000000000000000000000000000141730000000000000000000000000000000000000000000000000000000000014173100000000000000000000000000000000000000000000000000000000001417320000000000000000000000000000000000000000000000000000000000141733000000000000000000000000000000000000000000000000000000000014173400000000000000000000000000000000000000000000000000000000001417350000000000000000000000000000000000000000000000000000000000141736000000000000000000000000000000000000000000000000000000000014173700000000000000000000000000000000000000000000000000000000001417380000000000000000000000000000000000000000000000000000000000141739000000000000000000000000000000000000000000000000000000000014173a000000000000000000000000000000000000000000000000000000000014173b000000000000000000000000000000000000000000000000000000000014173c000000000000000000000000000000000000000000000000000000000014173d000000000000000000000000000000000000000000000000000000000014173e000000000000000000000000000000000000000000000000000000000014173f000000000000000000000000000000000000000000000000000000000014172f0000000000000000000000000000000000000000000000000000000000141730000000000000000000000000000000000000000000000000000000000014173100000000000000000000000000000000000000000000000000000000001417320000000000000000000000000000000000000000000000000000000000141733000000000000000000000000000000000000000000000000000000000014173400000000000000000000000000000000000000000000000000000000001417350000000000000000000000000000000000000000000000000000000000141736000000000000000000000000000000000000000000000000000000000014173700000000000000000000000000000000000000000000000000000000001417380000000000000000000000000000000000000000000000000000000000141739000000000000000000000000000000000000000000000000000000000014173a000000000000000000000000000000000000000000000000000000000014173b000000000000000000000000000000000000000000000000000000000014173c000000000000000000000000000000000000000000000000000000000014173d000000000000000000000000000000000000000000000000000000000014173e000000000000000000000000000000000000000000000000000000000014173f00000000000000000000000000000000000000000000000000000000001417400000000000000000000000000000000000000000000000000000000000141730000000000000000000000000000000000000000000000000000000000014173100000000000000000000000000000000000000000000000000000000001417320000000000000000000000000000000000000000000000000000000000141733000000000000000000000000000000000000000000000000000000000014173400000000000000000000000000000000000000000000000000000000001417350000000000000000000000000000000000000000000000000000000000141736000000000000000000000000000000000000000000000000000000000014173700000000000000000000000000000000000000000000000000000000001417380000000000000000000000000000000000000000000000000000000000141739000000000000000000000000000000000000000000000000000000000014173a000000000000000000000000000000000000000000000000000000000014173b000000000000000000000000000000000000000000000000000000000014173c000000000000000000000000000000000000000000000000000000000014173d000000000000000000000000000000000000000000000000000000000014173e000000000000000000000000000000000000000000000000000000000014173f00000000000000000000000000000000000000000000000000000000001417400000000000000000000000000000000000000000000000000000000000141741000000000000000000000000000000000000000000000000000000000014173100000000000000000000000000000000000000000000000000000000001417320000000000000000000000000000000000000000000000000000000000141733000000000000000000000000000000000000000000000000000000000014173400000000000000000000000000000000000000000000000000000000001417350000000000000000000000000000000000000000000000000000000000141736000000000000000000000000000000000000000000000000000000000014173700000000000000000000000000000000000000000000000000000000001417380000000000000000000000000000000000000000000000000000000000141739000000000000000000000000000000000000000000000000000000000014173a000000000000000000000000000000000000000000000000000000000014173b000000000000000000000000000000000000000000000000000000000014173c000000000000000000000000000000000000000000000000000000000014173d000000000000000000000000000000000000000000000000000000000014173e000000000000000000000000000000000000000000000000000000000014173f00000000000000000000000000000000000000000000000000000000001417400000000000000000000000000000000000000000000000000000000000141741000000000000000000000000000000000000000000000000000000000014174200000000000000000000000000000000000000000000000000000000001417320000000000000000000000000000000000000000000000000000000000141733000000000000000000000000000000000000000000000000000000000014173400000000000000000000000000000000000000000000000000000000001417350000000000000000000000000000000000000000000000000000000000141736000000000000000000000000000000000000000000000000000000000014173700000000000000000000000000000000000000000000000000000000001417380000000000000000000000000000000000000000000000000000000000141739000000000000000000000000000000000000000000000000000000000014173a000000000000000000000000000000000000000000000000000000000014173b000000000000000000000000000000000000000000000000000000000014173c000000000000000000000000000000000000000000000000000000000014173d000000000000000000000000000000000000000000000000000000000014173e000000000000000000000000000000000000000000000000000000000014173f00000000000000000000000000000000000000000000000000000000001417400000000000000000000000000000000000000000000000000000000000141741000000000000000000000000000000000000000000000000000000000014174200000000000000000000000000000000000000000000000000000000001417430000000000000000000000000000000000000000000000000000000000141733000000000000000000000000000000000000000000000000000000000014173400000000000000000000000000000000000000000000000000000000001417350000000000000000000000000000000000000000000000000000000000141736000000000000000000000000000000000000000000000000000000000014173700000000000000000000000000000000000000000000000000000000001417380000000000000000000000000000000000000000000000000000000000141739000000000000000000000000000000000000000000000000000000000014173a000000000000000000000000000000000000000000000000000000000014173b000000000000000000000000000000000000000000000000000000000014173c000000000000000000000000000000000000000000000000000000000014173d000000000000000000000000000000000000000000000000000000000014173e000000000000000000000000000000000000000000000000000000000014173f00000000000000000000000000000000000000000000000000000000001417400000000000000000000000000000000000000000000000000000000000141741000000000000000000000000000000000000000000000000000000000014174200000000000000000000000000000000000000000000000000000000001417430000000000000000000000000000000000000000000000000000000000141744000000000000000000000000000000000000000000000000000000000014173400000000000000000000000000000000000000000000000000000000001417350000000000000000000000000000000000000000000000000000000000141736000000000000000000000000000000000000000000000000000000000014173700000000000000000000000000000000000000000000000000000000001417380000000000000000000000000000000000000000000000000000000000141739000000000000000000000000000000000000000000000000000000000014173a000000000000000000000000000000000000000000000000000000000014173b000000000000000000000000000000000000000000000000000000000014173c000000000000000000000000000000000000000000000000000000000014173d000000000000000000000000000000000000000000000000000000000014173e000000000000000000000000000000000000000000000000000000000014173f00000000000000000000000000000000000000000000000000000000001417400000000000000000000000000000000000000000000000000000000000141741000000000000000000000000000000000000000000000000000000000014174200000000000000000000000000000000000000000000000000000000001417430000000000000000000000000000000000000000000000000000000000141744000000000000000000000000000000000000000000000000000000000014174500000000000000000000000000000000000000000000000000000000001417350000000000000000000000000000000000000000000000000000000000141736000000000000000000000000000000000000000000000000000000000014173700000000000000000000000000000000000000000000000000000000001417380000000000000000000000000000000000000000000000000000000000141739000000000000000000000000000000000000000000000000000000000014173a000000000000000000000000000000000000000000000000000000000014173b000000000000000000000000000000000000000000000000000000000014173c000000000000000000000000000000000000000000000000000000000014173d000000000000000000000000000000000000000000000000000000000014173e000000000000000000000000000000000000000000000000000000000014173f00000000000000000000000000000000000000000000000000000000001417400000000000000000000000000000000000000000000000000000000000141741000000000000000000000000000000000000000000000000000000000014174200000000000000000000000000000000000000000000000000000000001417430000000000000000000000000000000000000000000000000000000000141744000000000000000000000000000000000000000000000000000000000014174500000000000000000000000000000000000000000000000000000000001417460000000000000000000000000000000000000000000000000000000000141736000000000000000000000000000000000000000000000000000000000014173700000000000000000000000000000000000000000000000000000000001417380000000000000000000000000000000000000000000000000000000000141739000000000000000000000000000000000000000000000000000000000014173a000000000000000000000000000000000000000000000000000000000014173b000000000000000000000000000000000000000000000000000000000014173c000000000000000000000000000000000000000000000000000000000014173d000000000000000000000000000000000000000000000000000000000014173e000000000000000000000000000000000000000000000000000000000014173f00000000000000000000000000000000000000000000000000000000001417400000000000000000000000000000000000000000000000000000000000141741000000000000000000000000000000000000000000000000000000000014174200000000000000000000000000000000000000000000000000000000001417430000000000000000000000000000000000000000000000000000000000141744000000000000000000000000000000000000000000000000000000000014174500000000000000000000000000000000000000000000000000000000001417460000000000000000000000000000000000000000000000000000000000141747000000000000000000000000000000000000000000000000000000000014173700000000000000000000000000000000000000000000000000000000001417380000000000000000000000000000000000000000000000000000000000141739000000000000000000000000000000000000000000000000000000000014173a000000000000000000000000000000000000000000000000000000000014173b000000000000000000000000000000000000000000000000000000000014173c000000000000000000000000000000000000000000000000000000000014173d000000000000000000000000000000000000000000000000000000000014173e000000000000000000000000000000000000000000000000000000000014173f00000000000000000000000000000000000000000000000000000000001417400000000000000000000000000000000000000000000000000000000000141741000000000000000000000000000000000000000000000000000000000014174200000000000000000000000000000000000000000000000000000000001417430000000000000000000000000000000000000000000000000000000000141744000000000000000000000000000000000000000000000000000000000014174500000000000000000000000000000000000000000000000000000000001417460000000000000000000000000000000000000000000000000000000000141747000000000000000000000000000000000000000000000000000000000014174800000000000000000000000000000000000000000000000000000000001417380000000000000000000000000000000000000000000000000000000000141739000000000000000000000000000000000000000000000000000000000014173a000000000000000000000000000000000000000000000000000000000014173b000000000000000000000000000000000000000000000000000000000014173c000000000000000000000000000000000000000000000000000000000014173d000000000000000000000000000000000000000000000000000000000014173e000000000000000000000000000000000000000000000000000000000014173f00000000000000000000000000000000000000000000000000000000001417400000000000000000000000000000000000000000000000000000000000141741000000000000000000000000000000000000000000000000000000000014174200000000000000000000000000000000000000000000000000000000001417430000000000000000000000000000000000000000000000000000000000141744000000000000000000000000000000000000000000000000000000000014174500000000000000000000000000000000000000000000000000000000001417460000000000000000000000000000000000000000000000000000000000141747000000000000000000000000000000000000000000000000000000000014174800000000000000000000000000000000000000000000000000000000001417490000000000000000000000000000000000000000000000000000000000141739000000000000000000000000000000000000000000000000000000000014173a000000000000000000000000000000000000000000000000000000000014173b000000000000000000000000000000000000000000000000000000000014173c000000000000000000000000000000000000000000000000000000000014173d000000000000000000000000000000000000000000000000000000000014173e000000000000000000000000000000000000000000000000000000000014173f0000000000000000000000000000000000000000000000000000000000141740000000000000000000000000000000000000000000000000000000000014174100000000000000000000000000000000000000000000000000000000001417420000000000000000000000000000000000000000000000000000000000141743000000000000000000000000000000000000000000000000000000000014174400000000000000000000000000000000000000000000000000000000001417450000000000000000000000000000000000000000000000000000000000141746000000000000000000000000000000000000000000000000000000000014174700000000000000000000000000000000000000000000000000000000001417480000000000000000000000000000000000000000000000000000000000141749000000000000000000000000000000000000000000000000000000000014174a000000000000000000000000000000000000000000000000000000000014173a000000000000000000000000000000000000000000000000000000000014173b000000000000000000000000000000000000000000000000000000000014173c000000000000000000000000000000000000000000000000000000000014173d000000000000000000000000000000000000000000000000000000000014173e000000000000000000000000000000000000000000000000000000000014173f0000000000000000000000000000000000000000000000000000000000141740000000000000000000000000000000000000000000000000000000000014174100000000000000000000000000000000000000000000000000000000001417420000000000000000000000000000000000000000000000000000000000141743000000000000000000000000000000000000000000000000000000000014174400000000000000000000000000000000000000000000000000000000001417450000000000000000000000000000000000000000000000000000000000141746000000000000000000000000000000000000000000000000000000000014174700000000000000000000000000000000000000000000000000000000001417480000000000000000000000000000000000000000000000000000000000141749000000000000000000000000000000000000000000000000000000000014174a000000000000000000000000000000000000000000000000000000000014174b000000000000000000000000000000000000000000000000000000000014173b000000000000000000000000000000000000000000000000000000000014173c000000000000000000000000000000000000000000000000000000000014173d000000000000000000000000000000000000000000000000000000000014173e000000000000000000000000000000000000000000000000000000000014173f0000000000000000000000000000000000000000000000000000000000141740000000000000000000000000000000000000000000000000000000000014174100000000000000000000000000000000000000000000000000000000001417420000000000000000000000000000000000000000000000000000000000141743000000000000000000000000000000000000000000000000000000000014174400000000000000000000000000000000000000000000000000000000001417450000000000000000000000000000000000000000000000000000000000141746000000000000000000000000000000000000000000000000000000000014174700000000000000000000000000000000000000000000000000000000001417480000000000000000000000000000000000000000000000000000000000141749000000000000000000000000000000000000000000000000000000000014174a000000000000000000000000000000000000000000000000000000000014174b000000000000000000000000000000000000000000000000000000000014174c000000000000000000000000000000000000000000000000000000000014173c000000000000000000000000000000000000000000000000000000000014173d000000000000000000000000000000000000000000000000000000000014173e000000000000000000000000000000000000000000000000000000000014173f0000000000000000000000000000000000000000000000000000000000141740000000000000000000000000000000000000000000000000000000000014174100000000000000000000000000000000000000000000000000000000001417420000000000000000000000000000000000000000000000000000000000141743000000000000000000000000000000000000000000000000000000000014174400000000000000000000000000000000000000000000000000000000001417450000000000000000000000000000000000000000000000000000000000141746000000000000000000000000000000000000000000000000000000000014174700000000000000000000000000000000000000000000000000000000001417480000000000000000000000000000000000000000000000000000000000141749000000000000000000000000000000000000000000000000000000000014174a000000000000000000000000000000000000000000000000000000000014174b000000000000000000000000000000000000000000000000000000000014174c000000000000000000000000000000000000000000000000000000000014174d000000000000000000000000000000000000000000000000000000000014173d000000000000000000000000000000000000000000000000000000000014173e000000000000000000000000000000000000000000000000000000000014173f0000000000000000000000000000000000000000000000000000000000141740000000000000000000000000000000000000000000000000000000000014174100000000000000000000000000000000000000000000000000000000001417420000000000000000000000000000000000000000000000000000000000141743000000000000000000000000000000000000000000000000000000000014174400000000000000000000000000000000000000000000000000000000001417450000000000000000000000000000000000000000000000000000000000141746000000000000000000000000000000000000000000000000000000000014174700000000000000000000000000000000000000000000000000000000001417480000000000000000000000000000000000000000000000000000000000141749000000000000000000000000000000000000000000000000000000000014174a000000000000000000000000000000000000000000000000000000000014174b000000000000000000000000000000000000000000000000000000000014174c000000000000000000000000000000000000000000000000000000000014174d000000000000000000000000000000000000000000000000000000000014174e000000000000000000000000000000000000000000000000000000000014173e000000000000000000000000000000000000000000000000000000000014173f0000000000000000000000000000000000000000000000000000000000141740000000000000000000000000000000000000000000000000000000000014174100000000000000000000000000000000000000000000000000000000001417420000000000000000000000000000000000000000000000000000000000141743000000000000000000000000000000000000000000000000000000000014174400000000000000000000000000000000000000000000000000000000001417450000000000000000000000000000000000000000000000000000000000141746000000000000000000000000000000000000000000000000000000000014174700000000000000000000000000000000000000000000000000000000001417480000000000000000000000000000000000000000000000000000000000141749000000000000000000000000000000000000000000000000000000000014174a000000000000000000000000000000000000000000000000000000000014174b000000000000000000000000000000000000000000000000000000000014174c000000000000000000000000000000000000000000000000000000000014174d000000000000000000000000000000000000000000000000000000000014174e000000000000000000000000000000000000000000000000000000000014174f000000000000000000000000000000000000000000000000000000000014173f0000000000000000000000000000000000000000000000000000000000141740000000000000000000000000000000000000000000000000000000000014174100000000000000000000000000000000000000000000000000000000001417420000000000000000000000000000000000000000000000000000000000141743000000000000000000000000000000000000000000000000000000000014174400000000000000000000000000000000000000000000000000000000001417450000000000000000000000000000000000000000000000000000000000141746000000000000000000000000000000000000000000000000000000000014174700000000000000000000000000000000000000000000000000000000001417480000000000000000000000000000000000000000000000000000000000141749000000000000000000000000000000000000000000000000000000000014174a000000000000000000000000000000000000000000000000000000000014174b000000000000000000000000000000000000000000000000000000000014174c000000000000000000000000000000000000000000000000000000000014174d000000000000000000000000000000000000000000000000000000000014174e000000000000000000000000000000000000000000000000000000000014174f0000000000000000000000000000000000000000000000000000000000141750000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000181000000000000000000000000000000000000000000000000000000000000018100100000000000000000000000000000000000000000000000000000000001810020000000000000000000000000000000000000000000000000000000000181003000000000000000000000000000000000000000000000000000000000018100400000000000000000000000000000000000000000000000000000000001810050000000000000000000000000000000000000000000000000000000000181006000000000000000000000000000000000000000000000000000000000018100700000000000000000000000000000000000000000000000000000000001810080000000000000000000000000000000000000000000000000000000000181009000000000000000000000000000000000000000000000000000000000018100a000000000000000000000000000000000000000000000000000000000018100b000000000000000000000000000000000000000000000000000000000018100c000000000000000000000000000000000000000000000000000000000018100d000000000000000000000000000000000000000000000000000000000018100e000000000000000000000000000000000000000000000000000000000018100f0000000000000000000000000000000000000000000000000000000000181010000000000000000000000000000000000000000000000000000000000018101100000000000000000000000000000000000000000000000000000000001810120000000000000000000000000000000000000000000000000000000000181013000000000000000000000000000000000000000000000000000000000018101400000000000000000000000000000000000000000000000000000000001810150000000000000000000000000000000000000000000000000000000000181016000000000000000000000000000000000000000000000000000000000018101700000000000000000000000000000000000000000000000000000000001810180000000000000000000000000000000000000000000000000000000000181019000000000000000000000000000000000000000000000000000000000018101a000000000000000000000000000000000000000000000000000000000018101b000000000000000000000000000000000000000000000000000000000018101c000000000000000000000000000000000000000000000000000000000018101d000000000000000000000000000000000000000000000000000000000018101e000000000000000000000000000000000000000000000000000000000018101f0000000000000000000000000000000000000000000000000000000000181020000000000000000000000000000000000000000000000000000000000018102100000000000000000000000000000000000000000000000000000000001810220000000000000000000000000000000000000000000000000000000000181023000000000000000000000000000000000000000000000000000000000018102400000000000000000000000000000000000000000000000000000000001810250000000000000000000000000000000000000000000000000000000000181026000000000000000000000000000000000000000000000000000000000018102700000000000000000000000000000000000000000000000000000000001810280000000000000000000000000000000000000000000000000000000000181029000000000000000000000000000000000000000000000000000000000018102a000000000000000000000000000000000000000000000000000000000018102b000000000000000000000000000000000000000000000000000000000018102c000000000000000000000000000000000000000000000000000000000018102d000000000000000000000000000000000000000000000000000000000018102e000000000000000000000000000000000000000000000000000000000018102f0000000000000000000000000000000000000000000000000000000000181030000000000000000000000000000000000000000000000000000000000018103100000000000000000000000000000000000000000000000000000000001810320000000000000000000000000000000000000000000000000000000000181033000000000000000000000000000000000000000000000000000000000018103400000000000000000000000000000000000000000000000000000000001810350000000000000000000000000000000000000000000000000000000000181036000000000000000000000000000000000000000000000000000000000018103700000000000000000000000000000000000000000000000000000000001810380000000000000000000000000000000000000000000000000000000000181039000000000000000000000000000000000000000000000000000000000018103a000000000000000000000000000000000000000000000000000000000018103b000000000000000000000000000000000000000000000000000000000018103c000000000000000000000000000000000000000000000000000000000018103d000000000000000000000000000000000000000000000000000000000018103e000000000000000000000000000000000000000000000000000000000018103f4000000000000000000000000000000000000000000000000000000000001800010000000000000000000000000000000000000000000000000000000000181100000000000000000000000000000000000000000000000000000000000018110100000000000000000000000000000000000000000000000000000000001811020000000000000000000000000000000000000000000000000000000000181103000000000000000000000000000000000000000000000000000000000018110400000000000000000000000000000000000000000000000000000000001811050000000000000000000000000000000000000000000000000000000000181106000000000000000000000000000000000000000000000000000000000018110700000000000000000000000000000000000000000000000000000000001811080000000000000000000000000000000000000000000000000000000000181109000000000000000000000000000000000000000000000000000000000018110a000000000000000000000000000000000000000000000000000000000018110b000000000000000000000000000000000000000000000000000000000018110c000000000000000000000000000000000000000000000000000000000018110d000000000000000000000000000000000000000000000000000000000018110e000000000000000000000000000000000000000000000000000000000018110f0000000000000000000000000000000000000000000000000000000000181110000000000000000000000000000000000000000000000000000000000018111100000000000000000000000000000000000000000000000000000000001811120000000000000000000000000000000000000000000000000000000000181113000000000000000000000000000000000000000000000000000000000018111400000000000000000000000000000000000000000000000000000000001811150000000000000000000000000000000000000000000000000000000000181116000000000000000000000000000000000000000000000000000000000018111700000000000000000000000000000000000000000000000000000000001811180000000000000000000000000000000000000000000000000000000000181119000000000000000000000000000000000000000000000000000000000018111a000000000000000000000000000000000000000000000000000000000018111b000000000000000000000000000000000000000000000000000000000018111c000000000000000000000000000000000000000000000000000000000018111d000000000000000000000000000000000000000000000000000000000018111e000000000000000000000000000000000000000000000000000000000018111f0000000000000000000000000000000000000000000000000000000000181120000000000000000000000000000000000000000000000000000000000018112100000000000000000000000000000000000000000000000000000000001811220000000000000000000000000000000000000000000000000000000000181123000000000000000000000000000000000000000000000000000000000018112400000000000000000000000000000000000000000000000000000000001811250000000000000000000000000000000000000000000000000000000000181126000000000000000000000000000000000000000000000000000000000018112700000000000000000000000000000000000000000000000000000000001811280000000000000000000000000000000000000000000000000000000000181129000000000000000000000000000000000000000000000000000000000018112a000000000000000000000000000000000000000000000000000000000018112b000000000000000000000000000000000000000000000000000000000018112c000000000000000000000000000000000000000000000000000000000018112d000000000000000000000000000000000000000000000000000000000018112e000000000000000000000000000000000000000000000000000000000018112f0000000000000000000000000000000000000000000000000000000000181130000000000000000000000000000000000000000000000000000000000018113100000000000000000000000000000000000000000000000000000000001811320000000000000000000000000000000000000000000000000000000000181133000000000000000000000000000000000000000000000000000000000018113400000000000000000000000000000000000000000000000000000000001811350000000000000000000000000000000000000000000000000000000000181136000000000000000000000000000000000000000000000000000000000018113700000000000000000000000000000000000000000000000000000000001811380000000000000000000000000000000000000000000000000000000000181139000000000000000000000000000000000000000000000000000000000018113a000000000000000000000000000000000000000000000000000000000018113b000000000000000000000000000000000000000000000000000000000018113c000000000000000000000000000000000000000000000000000000000018113d000000000000000000000000000000000000000000000000000000000018113e0800f872eb9653f03af10f331da1361fa1524d3cd958cb72dacea1d424f19df3af00ffc548a17cd6ba1f2d228f30e4ddb19ecc46ad3b609977d52bb0f49e1206410032f8058bd779c520eabae2743b02ec4f71670428506fcceb2d4b69f26fb11800c0283e15fbf74ffa4eafb984030394f3c2ea6733cc0eacb0431a9475eff28f00b7f55314bfd9d441c1c624e241908228fe4da3d3a0a7fbd56814e1c8cd5d3e00f430f33a786675271736fd728c7bf7428b8c24ac948d7faf76ddb8783a496c0048fc235ead8d4b9d44929662a6384074fc4e5076bec5b7deb34f612393684300fd9b61cb1ad9b4b28f58399906e73933e3cccee8fc98a393f0eedb95b13ee63f0000000000000000000000000000000000000000000000000000000000182000000000000000000000000000000000000000000000000000000000000018200a0000000000000000000000000000000000000000000000000000000000182001000000000000000000000000000000000000000000000000000000000018200b0000000000000000000000000000000000000000000000000000000000182002000000000000000000000000000000000000000000000000000000000018200c0000000000000000000000000000000000000000000000000000000000182003000000000000000000000000000000000000000000000000000000000018200d0000000000000000000000000000000000000000000000000000000000182004000000000000000000000000000000000000000000000000000000000018200e0000000000000000000000000000000000000000000000000000000000182005000000000000000000000000000000000000000000000000000000000018200f00000000000000000000000000000000000000000000000000000000001820060000000000000000000000000000000000000000000000000000000000182010000000000000000000000000000000000000000000000000000000000018200700000000000000000000000000000000000000000000000000000000001820110000000000000000000000000000000000000000000000000000000000182008000000000000000000000000000000000000000000000000000000000018201200000000000000000000000000000000000000000000000000000000001820090000000000000000000000000000000000000000000000000000000000182013000000000000000000000000000000000000000000000000000000000018200a0000000000000000000000000000000000000000000000000000000000182014000000000000000000000000000000000000000000000000000000000018200b0000000000000000000000000000000000000000000000000000000000182015000000000000000000000000000000000000000000000000000000000018200c0000000000000000000000000000000000000000000000000000000000182016000000000000000000000000000000000000000000000000000000000018200d0000000000000000000000000000000000000000000000000000000000182017000000000000000000000000000000000000000000000000000000000018200e0000000000000000000000000000000000000000000000000000000000182018000000000000000000000000000000000000000000000000000000000018200f00000000000000000000000000000000000000000000000000000000001820190000000000000000000000000000000000000000000000000000000000182010000000000000000000000000000000000000000000000000000000000018201a0000000000000000000000000000000000000000000000000000000000182011000000000000000000000000000000000000000000000000000000000018201b0000000000000000000000000000000000000000000000000000000000182012000000000000000000000000000000000000000000000000000000000018201c0000000000000000000000000000000000000000000000000000000000182013000000000000000000000000000000000000000000000000000000000018201d0000000000000000000000000000000000000000000000000000000000182014000000000000000000000000000000000000000000000000000000000018201e0000000000000000000000000000000000000000000000000000000000182015000000000000000000000000000000000000000000000000000000000018201f00000000000000000000000000000000000000000000000000000000001820160000000000000000000000000000000000000000000000000000000000182020000000000000000000000000000000000000000000000000000000000018201700000000000000000000000000000000000000000000000000000000001820210000000000000000000000000000000000000000000000000000000000182018000000000000000000000000000000000000000000000000000000000018202200000000000000000000000000000000000000000000000000000000001820190000000000000000000000000000000000000000000000000000000000182023000000000000000000000000000000000000000000000000000000000018201a0000000000000000000000000000000000000000000000000000000000182024000000000000000000000000000000000000000000000000000000000018201b0000000000000000000000000000000000000000000000000000000000182025000000000000000000000000000000000000000000000000000000000018201c0000000000000000000000000000000000000000000000000000000000182026000000000000000000000000000000000000000000000000000000000018201d0000000000000000000000000000000000000000000000000000000000182027000000000000000000000000000000000000000000000000000000000018201e0000000000000000000000000000000000000000000000000000000000182028000000000000000000000000000000000000000000000000000000000018201f00000000000000000000000000000000000000000000000000000000001820290000000000000000000000000000000000000000000000000000000000182020000000000000000000000000000000000000000000000000000000000018202a0000000000000000000000000000000000000000000000000000000000182021000000000000000000000000000000000000000000000000000000000018202b0000000000000000000000000000000000000000000000000000000000182022000000000000000000000000000000000000000000000000000000000018202c0000000000000000000000000000000000000000000000000000000000182023000000000000000000000000000000000000000000000000000000000018202d0000000000000000000000000000000000000000000000000000000000182024000000000000000000000000000000000000000000000000000000000018202e0000000000000000000000000000000000000000000000000000000000182025000000000000000000000000000000000000000000000000000000000018202f00000000000000000000000000000000000000000000000000000000001820260000000000000000000000000000000000000000000000000000000000182030000000000000000000000000000000000000000000000000000000000018202700000000000000000000000000000000000000000000000000000000001820310000000000000000000000000000000000000000000000000000000000182028000000000000000000000000000000000000000000000000000000000018203200000000000000000000000000000000000000000000000000000000001820290000000000000000000000000000000000000000000000000000000000182033000000000000000000000000000000000000000000000000000000000018202a0000000000000000000000000000000000000000000000000000000000182034000000000000000000000000000000000000000000000000000000000018202b0000000000000000000000000000000000000000000000000000000000182035000000000000000000000000000000000000000000000000000000000018202c0000000000000000000000000000000000000000000000000000000000182036000000000000000000000000000000000000000000000000000000000018202d0000000000000000000000000000000000000000000000000000000000182037000000000000000000000000000000000000000000000000000000000018202e0000000000000000000000000000000000000000000000000000000000182038000000000000000000000000000000000000000000000000000000000018202f00000000000000000000000000000000000000000000000000000000001820390000000000000000000000000000000000000000000000000000000000182030000000000000000000000000000000000000000000000000000000000018203a0000000000000000000000000000000000000000000000000000000000182031000000000000000000000000000000000000000000000000000000000018203b0000000000000000000000000000000000000000000000000000000000182032000000000000000000000000000000000000000000000000000000000018203c0000000000000000000000000000000000000000000000000000000000182033000000000000000000000000000000000000000000000000000000000018203d0000000000000000000000000000000000000000000000000000000000182034000000000000000000000000000000000000000000000000000000000018203e0000000000000000000000000000000000000000000000000000000000182035000000000000000000000000000000000000000000000000000000000018203f00000000000000000000000000000000000000000000000000000000001820360000000000000000000000000000000000000000000000000000000000182040000000000000000000000000000000000000000000000000000000000018203700000000000000000000000000000000000000000000000000000000001820410000000000000000000000000000000000000000000000000000000000182038000000000000000000000000000000000000000000000000000000000018204200000000000000000000000000000000000000000000000000000000001820390000000000000000000000000000000000000000000000000000000000182043000000000000000000000000000000000000000000000000000000000018203a0000000000000000000000000000000000000000000000000000000000182044000000000000000000000000000000000000000000000000000000000018203b0000000000000000000000000000000000000000000000000000000000182045000000000000000000000000000000000000000000000000000000000018203c0000000000000000000000000000000000000000000000000000000000182046000000000000000000000000000000000000000000000000000000000018203d0000000000000000000000000000000000000000000000000000000000182047000000000000000000000000000000000000000000000000000000000018203e0000000000000000000000000000000000000000000000000000000000182048400000000000000000000000000000000000000000000000000000000000181700000000000000000000000000000000000000000000000000000000000018170100000000000000000000000000000000000000000000000000000000001817020000000000000000000000000000000000000000000000000000000000181703000000000000000000000000000000000000000000000000000000000018170400000000000000000000000000000000000000000000000000000000001817050000000000000000000000000000000000000000000000000000000000181706000000000000000000000000000000000000000000000000000000000018170700000000000000000000000000000000000000000000000000000000001817080000000000000000000000000000000000000000000000000000000000181709000000000000000000000000000000000000000000000000000000000018170a000000000000000000000000000000000000000000000000000000000018170b000000000000000000000000000000000000000000000000000000000018170c000000000000000000000000000000000000000000000000000000000018170d000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f00000000000000000000000000000000000000000000000000000000001817100000000000000000000000000000000000000000000000000000000000181711000000000000000000000000000000000000000000000000000000000018170100000000000000000000000000000000000000000000000000000000001817020000000000000000000000000000000000000000000000000000000000181703000000000000000000000000000000000000000000000000000000000018170400000000000000000000000000000000000000000000000000000000001817050000000000000000000000000000000000000000000000000000000000181706000000000000000000000000000000000000000000000000000000000018170700000000000000000000000000000000000000000000000000000000001817080000000000000000000000000000000000000000000000000000000000181709000000000000000000000000000000000000000000000000000000000018170a000000000000000000000000000000000000000000000000000000000018170b000000000000000000000000000000000000000000000000000000000018170c000000000000000000000000000000000000000000000000000000000018170d000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f00000000000000000000000000000000000000000000000000000000001817100000000000000000000000000000000000000000000000000000000000181711000000000000000000000000000000000000000000000000000000000018171200000000000000000000000000000000000000000000000000000000001817020000000000000000000000000000000000000000000000000000000000181703000000000000000000000000000000000000000000000000000000000018170400000000000000000000000000000000000000000000000000000000001817050000000000000000000000000000000000000000000000000000000000181706000000000000000000000000000000000000000000000000000000000018170700000000000000000000000000000000000000000000000000000000001817080000000000000000000000000000000000000000000000000000000000181709000000000000000000000000000000000000000000000000000000000018170a000000000000000000000000000000000000000000000000000000000018170b000000000000000000000000000000000000000000000000000000000018170c000000000000000000000000000000000000000000000000000000000018170d000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f00000000000000000000000000000000000000000000000000000000001817100000000000000000000000000000000000000000000000000000000000181711000000000000000000000000000000000000000000000000000000000018171200000000000000000000000000000000000000000000000000000000001817130000000000000000000000000000000000000000000000000000000000181703000000000000000000000000000000000000000000000000000000000018170400000000000000000000000000000000000000000000000000000000001817050000000000000000000000000000000000000000000000000000000000181706000000000000000000000000000000000000000000000000000000000018170700000000000000000000000000000000000000000000000000000000001817080000000000000000000000000000000000000000000000000000000000181709000000000000000000000000000000000000000000000000000000000018170a000000000000000000000000000000000000000000000000000000000018170b000000000000000000000000000000000000000000000000000000000018170c000000000000000000000000000000000000000000000000000000000018170d000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f00000000000000000000000000000000000000000000000000000000001817100000000000000000000000000000000000000000000000000000000000181711000000000000000000000000000000000000000000000000000000000018171200000000000000000000000000000000000000000000000000000000001817130000000000000000000000000000000000000000000000000000000000181714000000000000000000000000000000000000000000000000000000000018170400000000000000000000000000000000000000000000000000000000001817050000000000000000000000000000000000000000000000000000000000181706000000000000000000000000000000000000000000000000000000000018170700000000000000000000000000000000000000000000000000000000001817080000000000000000000000000000000000000000000000000000000000181709000000000000000000000000000000000000000000000000000000000018170a000000000000000000000000000000000000000000000000000000000018170b000000000000000000000000000000000000000000000000000000000018170c000000000000000000000000000000000000000000000000000000000018170d000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f00000000000000000000000000000000000000000000000000000000001817100000000000000000000000000000000000000000000000000000000000181711000000000000000000000000000000000000000000000000000000000018171200000000000000000000000000000000000000000000000000000000001817130000000000000000000000000000000000000000000000000000000000181714000000000000000000000000000000000000000000000000000000000018171500000000000000000000000000000000000000000000000000000000001817050000000000000000000000000000000000000000000000000000000000181706000000000000000000000000000000000000000000000000000000000018170700000000000000000000000000000000000000000000000000000000001817080000000000000000000000000000000000000000000000000000000000181709000000000000000000000000000000000000000000000000000000000018170a000000000000000000000000000000000000000000000000000000000018170b000000000000000000000000000000000000000000000000000000000018170c000000000000000000000000000000000000000000000000000000000018170d000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f00000000000000000000000000000000000000000000000000000000001817100000000000000000000000000000000000000000000000000000000000181711000000000000000000000000000000000000000000000000000000000018171200000000000000000000000000000000000000000000000000000000001817130000000000000000000000000000000000000000000000000000000000181714000000000000000000000000000000000000000000000000000000000018171500000000000000000000000000000000000000000000000000000000001817160000000000000000000000000000000000000000000000000000000000181706000000000000000000000000000000000000000000000000000000000018170700000000000000000000000000000000000000000000000000000000001817080000000000000000000000000000000000000000000000000000000000181709000000000000000000000000000000000000000000000000000000000018170a000000000000000000000000000000000000000000000000000000000018170b000000000000000000000000000000000000000000000000000000000018170c000000000000000000000000000000000000000000000000000000000018170d000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f00000000000000000000000000000000000000000000000000000000001817100000000000000000000000000000000000000000000000000000000000181711000000000000000000000000000000000000000000000000000000000018171200000000000000000000000000000000000000000000000000000000001817130000000000000000000000000000000000000000000000000000000000181714000000000000000000000000000000000000000000000000000000000018171500000000000000000000000000000000000000000000000000000000001817160000000000000000000000000000000000000000000000000000000000181717000000000000000000000000000000000000000000000000000000000018170700000000000000000000000000000000000000000000000000000000001817080000000000000000000000000000000000000000000000000000000000181709000000000000000000000000000000000000000000000000000000000018170a000000000000000000000000000000000000000000000000000000000018170b000000000000000000000000000000000000000000000000000000000018170c000000000000000000000000000000000000000000000000000000000018170d000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f00000000000000000000000000000000000000000000000000000000001817100000000000000000000000000000000000000000000000000000000000181711000000000000000000000000000000000000000000000000000000000018171200000000000000000000000000000000000000000000000000000000001817130000000000000000000000000000000000000000000000000000000000181714000000000000000000000000000000000000000000000000000000000018171500000000000000000000000000000000000000000000000000000000001817160000000000000000000000000000000000000000000000000000000000181717000000000000000000000000000000000000000000000000000000000018171800000000000000000000000000000000000000000000000000000000001817080000000000000000000000000000000000000000000000000000000000181709000000000000000000000000000000000000000000000000000000000018170a000000000000000000000000000000000000000000000000000000000018170b000000000000000000000000000000000000000000000000000000000018170c000000000000000000000000000000000000000000000000000000000018170d000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f00000000000000000000000000000000000000000000000000000000001817100000000000000000000000000000000000000000000000000000000000181711000000000000000000000000000000000000000000000000000000000018171200000000000000000000000000000000000000000000000000000000001817130000000000000000000000000000000000000000000000000000000000181714000000000000000000000000000000000000000000000000000000000018171500000000000000000000000000000000000000000000000000000000001817160000000000000000000000000000000000000000000000000000000000181717000000000000000000000000000000000000000000000000000000000018171800000000000000000000000000000000000000000000000000000000001817190000000000000000000000000000000000000000000000000000000000181709000000000000000000000000000000000000000000000000000000000018170a000000000000000000000000000000000000000000000000000000000018170b000000000000000000000000000000000000000000000000000000000018170c000000000000000000000000000000000000000000000000000000000018170d000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f0000000000000000000000000000000000000000000000000000000000181710000000000000000000000000000000000000000000000000000000000018171100000000000000000000000000000000000000000000000000000000001817120000000000000000000000000000000000000000000000000000000000181713000000000000000000000000000000000000000000000000000000000018171400000000000000000000000000000000000000000000000000000000001817150000000000000000000000000000000000000000000000000000000000181716000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018170a000000000000000000000000000000000000000000000000000000000018170b000000000000000000000000000000000000000000000000000000000018170c000000000000000000000000000000000000000000000000000000000018170d000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f0000000000000000000000000000000000000000000000000000000000181710000000000000000000000000000000000000000000000000000000000018171100000000000000000000000000000000000000000000000000000000001817120000000000000000000000000000000000000000000000000000000000181713000000000000000000000000000000000000000000000000000000000018171400000000000000000000000000000000000000000000000000000000001817150000000000000000000000000000000000000000000000000000000000181716000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018170b000000000000000000000000000000000000000000000000000000000018170c000000000000000000000000000000000000000000000000000000000018170d000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f0000000000000000000000000000000000000000000000000000000000181710000000000000000000000000000000000000000000000000000000000018171100000000000000000000000000000000000000000000000000000000001817120000000000000000000000000000000000000000000000000000000000181713000000000000000000000000000000000000000000000000000000000018171400000000000000000000000000000000000000000000000000000000001817150000000000000000000000000000000000000000000000000000000000181716000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018170c000000000000000000000000000000000000000000000000000000000018170d000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f0000000000000000000000000000000000000000000000000000000000181710000000000000000000000000000000000000000000000000000000000018171100000000000000000000000000000000000000000000000000000000001817120000000000000000000000000000000000000000000000000000000000181713000000000000000000000000000000000000000000000000000000000018171400000000000000000000000000000000000000000000000000000000001817150000000000000000000000000000000000000000000000000000000000181716000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018170d000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f0000000000000000000000000000000000000000000000000000000000181710000000000000000000000000000000000000000000000000000000000018171100000000000000000000000000000000000000000000000000000000001817120000000000000000000000000000000000000000000000000000000000181713000000000000000000000000000000000000000000000000000000000018171400000000000000000000000000000000000000000000000000000000001817150000000000000000000000000000000000000000000000000000000000181716000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018170e000000000000000000000000000000000000000000000000000000000018170f0000000000000000000000000000000000000000000000000000000000181710000000000000000000000000000000000000000000000000000000000018171100000000000000000000000000000000000000000000000000000000001817120000000000000000000000000000000000000000000000000000000000181713000000000000000000000000000000000000000000000000000000000018171400000000000000000000000000000000000000000000000000000000001817150000000000000000000000000000000000000000000000000000000000181716000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f000000000000000000000000000000000000000000000000000000000018170f0000000000000000000000000000000000000000000000000000000000181710000000000000000000000000000000000000000000000000000000000018171100000000000000000000000000000000000000000000000000000000001817120000000000000000000000000000000000000000000000000000000000181713000000000000000000000000000000000000000000000000000000000018171400000000000000000000000000000000000000000000000000000000001817150000000000000000000000000000000000000000000000000000000000181716000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f00000000000000000000000000000000000000000000000000000000001817200000000000000000000000000000000000000000000000000000000000181710000000000000000000000000000000000000000000000000000000000018171100000000000000000000000000000000000000000000000000000000001817120000000000000000000000000000000000000000000000000000000000181713000000000000000000000000000000000000000000000000000000000018171400000000000000000000000000000000000000000000000000000000001817150000000000000000000000000000000000000000000000000000000000181716000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f00000000000000000000000000000000000000000000000000000000001817200000000000000000000000000000000000000000000000000000000000181721000000000000000000000000000000000000000000000000000000000018171100000000000000000000000000000000000000000000000000000000001817120000000000000000000000000000000000000000000000000000000000181713000000000000000000000000000000000000000000000000000000000018171400000000000000000000000000000000000000000000000000000000001817150000000000000000000000000000000000000000000000000000000000181716000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f00000000000000000000000000000000000000000000000000000000001817200000000000000000000000000000000000000000000000000000000000181721000000000000000000000000000000000000000000000000000000000018172200000000000000000000000000000000000000000000000000000000001817120000000000000000000000000000000000000000000000000000000000181713000000000000000000000000000000000000000000000000000000000018171400000000000000000000000000000000000000000000000000000000001817150000000000000000000000000000000000000000000000000000000000181716000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f00000000000000000000000000000000000000000000000000000000001817200000000000000000000000000000000000000000000000000000000000181721000000000000000000000000000000000000000000000000000000000018172200000000000000000000000000000000000000000000000000000000001817230000000000000000000000000000000000000000000000000000000000181713000000000000000000000000000000000000000000000000000000000018171400000000000000000000000000000000000000000000000000000000001817150000000000000000000000000000000000000000000000000000000000181716000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f00000000000000000000000000000000000000000000000000000000001817200000000000000000000000000000000000000000000000000000000000181721000000000000000000000000000000000000000000000000000000000018172200000000000000000000000000000000000000000000000000000000001817230000000000000000000000000000000000000000000000000000000000181724000000000000000000000000000000000000000000000000000000000018171400000000000000000000000000000000000000000000000000000000001817150000000000000000000000000000000000000000000000000000000000181716000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f00000000000000000000000000000000000000000000000000000000001817200000000000000000000000000000000000000000000000000000000000181721000000000000000000000000000000000000000000000000000000000018172200000000000000000000000000000000000000000000000000000000001817230000000000000000000000000000000000000000000000000000000000181724000000000000000000000000000000000000000000000000000000000018172500000000000000000000000000000000000000000000000000000000001817150000000000000000000000000000000000000000000000000000000000181716000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f00000000000000000000000000000000000000000000000000000000001817200000000000000000000000000000000000000000000000000000000000181721000000000000000000000000000000000000000000000000000000000018172200000000000000000000000000000000000000000000000000000000001817230000000000000000000000000000000000000000000000000000000000181724000000000000000000000000000000000000000000000000000000000018172500000000000000000000000000000000000000000000000000000000001817260000000000000000000000000000000000000000000000000000000000181716000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f00000000000000000000000000000000000000000000000000000000001817200000000000000000000000000000000000000000000000000000000000181721000000000000000000000000000000000000000000000000000000000018172200000000000000000000000000000000000000000000000000000000001817230000000000000000000000000000000000000000000000000000000000181724000000000000000000000000000000000000000000000000000000000018172500000000000000000000000000000000000000000000000000000000001817260000000000000000000000000000000000000000000000000000000000181727000000000000000000000000000000000000000000000000000000000018171700000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f00000000000000000000000000000000000000000000000000000000001817200000000000000000000000000000000000000000000000000000000000181721000000000000000000000000000000000000000000000000000000000018172200000000000000000000000000000000000000000000000000000000001817230000000000000000000000000000000000000000000000000000000000181724000000000000000000000000000000000000000000000000000000000018172500000000000000000000000000000000000000000000000000000000001817260000000000000000000000000000000000000000000000000000000000181727000000000000000000000000000000000000000000000000000000000018172800000000000000000000000000000000000000000000000000000000001817180000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f00000000000000000000000000000000000000000000000000000000001817200000000000000000000000000000000000000000000000000000000000181721000000000000000000000000000000000000000000000000000000000018172200000000000000000000000000000000000000000000000000000000001817230000000000000000000000000000000000000000000000000000000000181724000000000000000000000000000000000000000000000000000000000018172500000000000000000000000000000000000000000000000000000000001817260000000000000000000000000000000000000000000000000000000000181727000000000000000000000000000000000000000000000000000000000018172800000000000000000000000000000000000000000000000000000000001817290000000000000000000000000000000000000000000000000000000000181719000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f0000000000000000000000000000000000000000000000000000000000181720000000000000000000000000000000000000000000000000000000000018172100000000000000000000000000000000000000000000000000000000001817220000000000000000000000000000000000000000000000000000000000181723000000000000000000000000000000000000000000000000000000000018172400000000000000000000000000000000000000000000000000000000001817250000000000000000000000000000000000000000000000000000000000181726000000000000000000000000000000000000000000000000000000000018172700000000000000000000000000000000000000000000000000000000001817280000000000000000000000000000000000000000000000000000000000181729000000000000000000000000000000000000000000000000000000000018172a000000000000000000000000000000000000000000000000000000000018171a000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f0000000000000000000000000000000000000000000000000000000000181720000000000000000000000000000000000000000000000000000000000018172100000000000000000000000000000000000000000000000000000000001817220000000000000000000000000000000000000000000000000000000000181723000000000000000000000000000000000000000000000000000000000018172400000000000000000000000000000000000000000000000000000000001817250000000000000000000000000000000000000000000000000000000000181726000000000000000000000000000000000000000000000000000000000018172700000000000000000000000000000000000000000000000000000000001817280000000000000000000000000000000000000000000000000000000000181729000000000000000000000000000000000000000000000000000000000018172a000000000000000000000000000000000000000000000000000000000018172b000000000000000000000000000000000000000000000000000000000018171b000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f0000000000000000000000000000000000000000000000000000000000181720000000000000000000000000000000000000000000000000000000000018172100000000000000000000000000000000000000000000000000000000001817220000000000000000000000000000000000000000000000000000000000181723000000000000000000000000000000000000000000000000000000000018172400000000000000000000000000000000000000000000000000000000001817250000000000000000000000000000000000000000000000000000000000181726000000000000000000000000000000000000000000000000000000000018172700000000000000000000000000000000000000000000000000000000001817280000000000000000000000000000000000000000000000000000000000181729000000000000000000000000000000000000000000000000000000000018172a000000000000000000000000000000000000000000000000000000000018172b000000000000000000000000000000000000000000000000000000000018172c000000000000000000000000000000000000000000000000000000000018171c000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f0000000000000000000000000000000000000000000000000000000000181720000000000000000000000000000000000000000000000000000000000018172100000000000000000000000000000000000000000000000000000000001817220000000000000000000000000000000000000000000000000000000000181723000000000000000000000000000000000000000000000000000000000018172400000000000000000000000000000000000000000000000000000000001817250000000000000000000000000000000000000000000000000000000000181726000000000000000000000000000000000000000000000000000000000018172700000000000000000000000000000000000000000000000000000000001817280000000000000000000000000000000000000000000000000000000000181729000000000000000000000000000000000000000000000000000000000018172a000000000000000000000000000000000000000000000000000000000018172b000000000000000000000000000000000000000000000000000000000018172c000000000000000000000000000000000000000000000000000000000018172d000000000000000000000000000000000000000000000000000000000018171d000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f0000000000000000000000000000000000000000000000000000000000181720000000000000000000000000000000000000000000000000000000000018172100000000000000000000000000000000000000000000000000000000001817220000000000000000000000000000000000000000000000000000000000181723000000000000000000000000000000000000000000000000000000000018172400000000000000000000000000000000000000000000000000000000001817250000000000000000000000000000000000000000000000000000000000181726000000000000000000000000000000000000000000000000000000000018172700000000000000000000000000000000000000000000000000000000001817280000000000000000000000000000000000000000000000000000000000181729000000000000000000000000000000000000000000000000000000000018172a000000000000000000000000000000000000000000000000000000000018172b000000000000000000000000000000000000000000000000000000000018172c000000000000000000000000000000000000000000000000000000000018172d000000000000000000000000000000000000000000000000000000000018172e000000000000000000000000000000000000000000000000000000000018171e000000000000000000000000000000000000000000000000000000000018171f0000000000000000000000000000000000000000000000000000000000181720000000000000000000000000000000000000000000000000000000000018172100000000000000000000000000000000000000000000000000000000001817220000000000000000000000000000000000000000000000000000000000181723000000000000000000000000000000000000000000000000000000000018172400000000000000000000000000000000000000000000000000000000001817250000000000000000000000000000000000000000000000000000000000181726000000000000000000000000000000000000000000000000000000000018172700000000000000000000000000000000000000000000000000000000001817280000000000000000000000000000000000000000000000000000000000181729000000000000000000000000000000000000000000000000000000000018172a000000000000000000000000000000000000000000000000000000000018172b000000000000000000000000000000000000000000000000000000000018172c000000000000000000000000000000000000000000000000000000000018172d000000000000000000000000000000000000000000000000000000000018172e000000000000000000000000000000000000000000000000000000000018172f000000000000000000000000000000000000000000000000000000000018171f0000000000000000000000000000000000000000000000000000000000181720000000000000000000000000000000000000000000000000000000000018172100000000000000000000000000000000000000000000000000000000001817220000000000000000000000000000000000000000000000000000000000181723000000000000000000000000000000000000000000000000000000000018172400000000000000000000000000000000000000000000000000000000001817250000000000000000000000000000000000000000000000000000000000181726000000000000000000000000000000000000000000000000000000000018172700000000000000000000000000000000000000000000000000000000001817280000000000000000000000000000000000000000000000000000000000181729000000000000000000000000000000000000000000000000000000000018172a000000000000000000000000000000000000000000000000000000000018172b000000000000000000000000000000000000000000000000000000000018172c000000000000000000000000000000000000000000000000000000000018172d000000000000000000000000000000000000000000000000000000000018172e000000000000000000000000000000000000000000000000000000000018172f00000000000000000000000000000000000000000000000000000000001817300000000000000000000000000000000000000000000000000000000000181720000000000000000000000000000000000000000000000000000000000018172100000000000000000000000000000000000000000000000000000000001817220000000000000000000000000000000000000000000000000000000000181723000000000000000000000000000000000000000000000000000000000018172400000000000000000000000000000000000000000000000000000000001817250000000000000000000000000000000000000000000000000000000000181726000000000000000000000000000000000000000000000000000000000018172700000000000000000000000000000000000000000000000000000000001817280000000000000000000000000000000000000000000000000000000000181729000000000000000000000000000000000000000000000000000000000018172a000000000000000000000000000000000000000000000000000000000018172b000000000000000000000000000000000000000000000000000000000018172c000000000000000000000000000000000000000000000000000000000018172d000000000000000000000000000000000000000000000000000000000018172e000000000000000000000000000000000000000000000000000000000018172f00000000000000000000000000000000000000000000000000000000001817300000000000000000000000000000000000000000000000000000000000181731000000000000000000000000000000000000000000000000000000000018172100000000000000000000000000000000000000000000000000000000001817220000000000000000000000000000000000000000000000000000000000181723000000000000000000000000000000000000000000000000000000000018172400000000000000000000000000000000000000000000000000000000001817250000000000000000000000000000000000000000000000000000000000181726000000000000000000000000000000000000000000000000000000000018172700000000000000000000000000000000000000000000000000000000001817280000000000000000000000000000000000000000000000000000000000181729000000000000000000000000000000000000000000000000000000000018172a000000000000000000000000000000000000000000000000000000000018172b000000000000000000000000000000000000000000000000000000000018172c000000000000000000000000000000000000000000000000000000000018172d000000000000000000000000000000000000000000000000000000000018172e000000000000000000000000000000000000000000000000000000000018172f00000000000000000000000000000000000000000000000000000000001817300000000000000000000000000000000000000000000000000000000000181731000000000000000000000000000000000000000000000000000000000018173200000000000000000000000000000000000000000000000000000000001817220000000000000000000000000000000000000000000000000000000000181723000000000000000000000000000000000000000000000000000000000018172400000000000000000000000000000000000000000000000000000000001817250000000000000000000000000000000000000000000000000000000000181726000000000000000000000000000000000000000000000000000000000018172700000000000000000000000000000000000000000000000000000000001817280000000000000000000000000000000000000000000000000000000000181729000000000000000000000000000000000000000000000000000000000018172a000000000000000000000000000000000000000000000000000000000018172b000000000000000000000000000000000000000000000000000000000018172c000000000000000000000000000000000000000000000000000000000018172d000000000000000000000000000000000000000000000000000000000018172e000000000000000000000000000000000000000000000000000000000018172f00000000000000000000000000000000000000000000000000000000001817300000000000000000000000000000000000000000000000000000000000181731000000000000000000000000000000000000000000000000000000000018173200000000000000000000000000000000000000000000000000000000001817330000000000000000000000000000000000000000000000000000000000181723000000000000000000000000000000000000000000000000000000000018172400000000000000000000000000000000000000000000000000000000001817250000000000000000000000000000000000000000000000000000000000181726000000000000000000000000000000000000000000000000000000000018172700000000000000000000000000000000000000000000000000000000001817280000000000000000000000000000000000000000000000000000000000181729000000000000000000000000000000000000000000000000000000000018172a000000000000000000000000000000000000000000000000000000000018172b000000000000000000000000000000000000000000000000000000000018172c000000000000000000000000000000000000000000000000000000000018172d000000000000000000000000000000000000000000000000000000000018172e000000000000000000000000000000000000000000000000000000000018172f00000000000000000000000000000000000000000000000000000000001817300000000000000000000000000000000000000000000000000000000000181731000000000000000000000000000000000000000000000000000000000018173200000000000000000000000000000000000000000000000000000000001817330000000000000000000000000000000000000000000000000000000000181734000000000000000000000000000000000000000000000000000000000018172400000000000000000000000000000000000000000000000000000000001817250000000000000000000000000000000000000000000000000000000000181726000000000000000000000000000000000000000000000000000000000018172700000000000000000000000000000000000000000000000000000000001817280000000000000000000000000000000000000000000000000000000000181729000000000000000000000000000000000000000000000000000000000018172a000000000000000000000000000000000000000000000000000000000018172b000000000000000000000000000000000000000000000000000000000018172c000000000000000000000000000000000000000000000000000000000018172d000000000000000000000000000000000000000000000000000000000018172e000000000000000000000000000000000000000000000000000000000018172f00000000000000000000000000000000000000000000000000000000001817300000000000000000000000000000000000000000000000000000000000181731000000000000000000000000000000000000000000000000000000000018173200000000000000000000000000000000000000000000000000000000001817330000000000000000000000000000000000000000000000000000000000181734000000000000000000000000000000000000000000000000000000000018173500000000000000000000000000000000000000000000000000000000001817250000000000000000000000000000000000000000000000000000000000181726000000000000000000000000000000000000000000000000000000000018172700000000000000000000000000000000000000000000000000000000001817280000000000000000000000000000000000000000000000000000000000181729000000000000000000000000000000000000000000000000000000000018172a000000000000000000000000000000000000000000000000000000000018172b000000000000000000000000000000000000000000000000000000000018172c000000000000000000000000000000000000000000000000000000000018172d000000000000000000000000000000000000000000000000000000000018172e000000000000000000000000000000000000000000000000000000000018172f00000000000000000000000000000000000000000000000000000000001817300000000000000000000000000000000000000000000000000000000000181731000000000000000000000000000000000000000000000000000000000018173200000000000000000000000000000000000000000000000000000000001817330000000000000000000000000000000000000000000000000000000000181734000000000000000000000000000000000000000000000000000000000018173500000000000000000000000000000000000000000000000000000000001817360000000000000000000000000000000000000000000000000000000000181726000000000000000000000000000000000000000000000000000000000018172700000000000000000000000000000000000000000000000000000000001817280000000000000000000000000000000000000000000000000000000000181729000000000000000000000000000000000000000000000000000000000018172a000000000000000000000000000000000000000000000000000000000018172b000000000000000000000000000000000000000000000000000000000018172c000000000000000000000000000000000000000000000000000000000018172d000000000000000000000000000000000000000000000000000000000018172e000000000000000000000000000000000000000000000000000000000018172f00000000000000000000000000000000000000000000000000000000001817300000000000000000000000000000000000000000000000000000000000181731000000000000000000000000000000000000000000000000000000000018173200000000000000000000000000000000000000000000000000000000001817330000000000000000000000000000000000000000000000000000000000181734000000000000000000000000000000000000000000000000000000000018173500000000000000000000000000000000000000000000000000000000001817360000000000000000000000000000000000000000000000000000000000181737000000000000000000000000000000000000000000000000000000000018172700000000000000000000000000000000000000000000000000000000001817280000000000000000000000000000000000000000000000000000000000181729000000000000000000000000000000000000000000000000000000000018172a000000000000000000000000000000000000000000000000000000000018172b000000000000000000000000000000000000000000000000000000000018172c000000000000000000000000000000000000000000000000000000000018172d000000000000000000000000000000000000000000000000000000000018172e000000000000000000000000000000000000000000000000000000000018172f00000000000000000000000000000000000000000000000000000000001817300000000000000000000000000000000000000000000000000000000000181731000000000000000000000000000000000000000000000000000000000018173200000000000000000000000000000000000000000000000000000000001817330000000000000000000000000000000000000000000000000000000000181734000000000000000000000000000000000000000000000000000000000018173500000000000000000000000000000000000000000000000000000000001817360000000000000000000000000000000000000000000000000000000000181737000000000000000000000000000000000000000000000000000000000018173800000000000000000000000000000000000000000000000000000000001817280000000000000000000000000000000000000000000000000000000000181729000000000000000000000000000000000000000000000000000000000018172a000000000000000000000000000000000000000000000000000000000018172b000000000000000000000000000000000000000000000000000000000018172c000000000000000000000000000000000000000000000000000000000018172d000000000000000000000000000000000000000000000000000000000018172e000000000000000000000000000000000000000000000000000000000018172f00000000000000000000000000000000000000000000000000000000001817300000000000000000000000000000000000000000000000000000000000181731000000000000000000000000000000000000000000000000000000000018173200000000000000000000000000000000000000000000000000000000001817330000000000000000000000000000000000000000000000000000000000181734000000000000000000000000000000000000000000000000000000000018173500000000000000000000000000000000000000000000000000000000001817360000000000000000000000000000000000000000000000000000000000181737000000000000000000000000000000000000000000000000000000000018173800000000000000000000000000000000000000000000000000000000001817390000000000000000000000000000000000000000000000000000000000181729000000000000000000000000000000000000000000000000000000000018172a000000000000000000000000000000000000000000000000000000000018172b000000000000000000000000000000000000000000000000000000000018172c000000000000000000000000000000000000000000000000000000000018172d000000000000000000000000000000000000000000000000000000000018172e000000000000000000000000000000000000000000000000000000000018172f0000000000000000000000000000000000000000000000000000000000181730000000000000000000000000000000000000000000000000000000000018173100000000000000000000000000000000000000000000000000000000001817320000000000000000000000000000000000000000000000000000000000181733000000000000000000000000000000000000000000000000000000000018173400000000000000000000000000000000000000000000000000000000001817350000000000000000000000000000000000000000000000000000000000181736000000000000000000000000000000000000000000000000000000000018173700000000000000000000000000000000000000000000000000000000001817380000000000000000000000000000000000000000000000000000000000181739000000000000000000000000000000000000000000000000000000000018173a000000000000000000000000000000000000000000000000000000000018172a000000000000000000000000000000000000000000000000000000000018172b000000000000000000000000000000000000000000000000000000000018172c000000000000000000000000000000000000000000000000000000000018172d000000000000000000000000000000000000000000000000000000000018172e000000000000000000000000000000000000000000000000000000000018172f0000000000000000000000000000000000000000000000000000000000181730000000000000000000000000000000000000000000000000000000000018173100000000000000000000000000000000000000000000000000000000001817320000000000000000000000000000000000000000000000000000000000181733000000000000000000000000000000000000000000000000000000000018173400000000000000000000000000000000000000000000000000000000001817350000000000000000000000000000000000000000000000000000000000181736000000000000000000000000000000000000000000000000000000000018173700000000000000000000000000000000000000000000000000000000001817380000000000000000000000000000000000000000000000000000000000181739000000000000000000000000000000000000000000000000000000000018173a000000000000000000000000000000000000000000000000000000000018173b000000000000000000000000000000000000000000000000000000000018172b000000000000000000000000000000000000000000000000000000000018172c000000000000000000000000000000000000000000000000000000000018172d000000000000000000000000000000000000000000000000000000000018172e000000000000000000000000000000000000000000000000000000000018172f0000000000000000000000000000000000000000000000000000000000181730000000000000000000000000000000000000000000000000000000000018173100000000000000000000000000000000000000000000000000000000001817320000000000000000000000000000000000000000000000000000000000181733000000000000000000000000000000000000000000000000000000000018173400000000000000000000000000000000000000000000000000000000001817350000000000000000000000000000000000000000000000000000000000181736000000000000000000000000000000000000000000000000000000000018173700000000000000000000000000000000000000000000000000000000001817380000000000000000000000000000000000000000000000000000000000181739000000000000000000000000000000000000000000000000000000000018173a000000000000000000000000000000000000000000000000000000000018173b000000000000000000000000000000000000000000000000000000000018173c000000000000000000000000000000000000000000000000000000000018172c000000000000000000000000000000000000000000000000000000000018172d000000000000000000000000000000000000000000000000000000000018172e000000000000000000000000000000000000000000000000000000000018172f0000000000000000000000000000000000000000000000000000000000181730000000000000000000000000000000000000000000000000000000000018173100000000000000000000000000000000000000000000000000000000001817320000000000000000000000000000000000000000000000000000000000181733000000000000000000000000000000000000000000000000000000000018173400000000000000000000000000000000000000000000000000000000001817350000000000000000000000000000000000000000000000000000000000181736000000000000000000000000000000000000000000000000000000000018173700000000000000000000000000000000000000000000000000000000001817380000000000000000000000000000000000000000000000000000000000181739000000000000000000000000000000000000000000000000000000000018173a000000000000000000000000000000000000000000000000000000000018173b000000000000000000000000000000000000000000000000000000000018173c000000000000000000000000000000000000000000000000000000000018173d000000000000000000000000000000000000000000000000000000000018172d000000000000000000000000000000000000000000000000000000000018172e000000000000000000000000000000000000000000000000000000000018172f0000000000000000000000000000000000000000000000000000000000181730000000000000000000000000000000000000000000000000000000000018173100000000000000000000000000000000000000000000000000000000001817320000000000000000000000000000000000000000000000000000000000181733000000000000000000000000000000000000000000000000000000000018173400000000000000000000000000000000000000000000000000000000001817350000000000000000000000000000000000000000000000000000000000181736000000000000000000000000000000000000000000000000000000000018173700000000000000000000000000000000000000000000000000000000001817380000000000000000000000000000000000000000000000000000000000181739000000000000000000000000000000000000000000000000000000000018173a000000000000000000000000000000000000000000000000000000000018173b000000000000000000000000000000000000000000000000000000000018173c000000000000000000000000000000000000000000000000000000000018173d000000000000000000000000000000000000000000000000000000000018173e000000000000000000000000000000000000000000000000000000000018172e000000000000000000000000000000000000000000000000000000000018172f0000000000000000000000000000000000000000000000000000000000181730000000000000000000000000000000000000000000000000000000000018173100000000000000000000000000000000000000000000000000000000001817320000000000000000000000000000000000000000000000000000000000181733000000000000000000000000000000000000000000000000000000000018173400000000000000000000000000000000000000000000000000000000001817350000000000000000000000000000000000000000000000000000000000181736000000000000000000000000000000000000000000000000000000000018173700000000000000000000000000000000000000000000000000000000001817380000000000000000000000000000000000000000000000000000000000181739000000000000000000000000000000000000000000000000000000000018173a000000000000000000000000000000000000000000000000000000000018173b000000000000000000000000000000000000000000000000000000000018173c000000000000000000000000000000000000000000000000000000000018173d000000000000000000000000000000000000000000000000000000000018173e000000000000000000000000000000000000000000000000000000000018173f000000000000000000000000000000000000000000000000000000000018172f0000000000000000000000000000000000000000000000000000000000181730000000000000000000000000000000000000000000000000000000000018173100000000000000000000000000000000000000000000000000000000001817320000000000000000000000000000000000000000000000000000000000181733000000000000000000000000000000000000000000000000000000000018173400000000000000000000000000000000000000000000000000000000001817350000000000000000000000000000000000000000000000000000000000181736000000000000000000000000000000000000000000000000000000000018173700000000000000000000000000000000000000000000000000000000001817380000000000000000000000000000000000000000000000000000000000181739000000000000000000000000000000000000000000000000000000000018173a000000000000000000000000000000000000000000000000000000000018173b000000000000000000000000000000000000000000000000000000000018173c000000000000000000000000000000000000000000000000000000000018173d000000000000000000000000000000000000000000000000000000000018173e000000000000000000000000000000000000000000000000000000000018173f00000000000000000000000000000000000000000000000000000000001817400000000000000000000000000000000000000000000000000000000000181730000000000000000000000000000000000000000000000000000000000018173100000000000000000000000000000000000000000000000000000000001817320000000000000000000000000000000000000000000000000000000000181733000000000000000000000000000000000000000000000000000000000018173400000000000000000000000000000000000000000000000000000000001817350000000000000000000000000000000000000000000000000000000000181736000000000000000000000000000000000000000000000000000000000018173700000000000000000000000000000000000000000000000000000000001817380000000000000000000000000000000000000000000000000000000000181739000000000000000000000000000000000000000000000000000000000018173a000000000000000000000000000000000000000000000000000000000018173b000000000000000000000000000000000000000000000000000000000018173c000000000000000000000000000000000000000000000000000000000018173d000000000000000000000000000000000000000000000000000000000018173e000000000000000000000000000000000000000000000000000000000018173f00000000000000000000000000000000000000000000000000000000001817400000000000000000000000000000000000000000000000000000000000181741000000000000000000000000000000000000000000000000000000000018173100000000000000000000000000000000000000000000000000000000001817320000000000000000000000000000000000000000000000000000000000181733000000000000000000000000000000000000000000000000000000000018173400000000000000000000000000000000000000000000000000000000001817350000000000000000000000000000000000000000000000000000000000181736000000000000000000000000000000000000000000000000000000000018173700000000000000000000000000000000000000000000000000000000001817380000000000000000000000000000000000000000000000000000000000181739000000000000000000000000000000000000000000000000000000000018173a000000000000000000000000000000000000000000000000000000000018173b000000000000000000000000000000000000000000000000000000000018173c000000000000000000000000000000000000000000000000000000000018173d000000000000000000000000000000000000000000000000000000000018173e000000000000000000000000000000000000000000000000000000000018173f00000000000000000000000000000000000000000000000000000000001817400000000000000000000000000000000000000000000000000000000000181741000000000000000000000000000000000000000000000000000000000018174200000000000000000000000000000000000000000000000000000000001817320000000000000000000000000000000000000000000000000000000000181733000000000000000000000000000000000000000000000000000000000018173400000000000000000000000000000000000000000000000000000000001817350000000000000000000000000000000000000000000000000000000000181736000000000000000000000000000000000000000000000000000000000018173700000000000000000000000000000000000000000000000000000000001817380000000000000000000000000000000000000000000000000000000000181739000000000000000000000000000000000000000000000000000000000018173a000000000000000000000000000000000000000000000000000000000018173b000000000000000000000000000000000000000000000000000000000018173c000000000000000000000000000000000000000000000000000000000018173d000000000000000000000000000000000000000000000000000000000018173e000000000000000000000000000000000000000000000000000000000018173f00000000000000000000000000000000000000000000000000000000001817400000000000000000000000000000000000000000000000000000000000181741000000000000000000000000000000000000000000000000000000000018174200000000000000000000000000000000000000000000000000000000001817430000000000000000000000000000000000000000000000000000000000181733000000000000000000000000000000000000000000000000000000000018173400000000000000000000000000000000000000000000000000000000001817350000000000000000000000000000000000000000000000000000000000181736000000000000000000000000000000000000000000000000000000000018173700000000000000000000000000000000000000000000000000000000001817380000000000000000000000000000000000000000000000000000000000181739000000000000000000000000000000000000000000000000000000000018173a000000000000000000000000000000000000000000000000000000000018173b000000000000000000000000000000000000000000000000000000000018173c000000000000000000000000000000000000000000000000000000000018173d000000000000000000000000000000000000000000000000000000000018173e000000000000000000000000000000000000000000000000000000000018173f00000000000000000000000000000000000000000000000000000000001817400000000000000000000000000000000000000000000000000000000000181741000000000000000000000000000000000000000000000000000000000018174200000000000000000000000000000000000000000000000000000000001817430000000000000000000000000000000000000000000000000000000000181744000000000000000000000000000000000000000000000000000000000018173400000000000000000000000000000000000000000000000000000000001817350000000000000000000000000000000000000000000000000000000000181736000000000000000000000000000000000000000000000000000000000018173700000000000000000000000000000000000000000000000000000000001817380000000000000000000000000000000000000000000000000000000000181739000000000000000000000000000000000000000000000000000000000018173a000000000000000000000000000000000000000000000000000000000018173b000000000000000000000000000000000000000000000000000000000018173c000000000000000000000000000000000000000000000000000000000018173d000000000000000000000000000000000000000000000000000000000018173e000000000000000000000000000000000000000000000000000000000018173f00000000000000000000000000000000000000000000000000000000001817400000000000000000000000000000000000000000000000000000000000181741000000000000000000000000000000000000000000000000000000000018174200000000000000000000000000000000000000000000000000000000001817430000000000000000000000000000000000000000000000000000000000181744000000000000000000000000000000000000000000000000000000000018174500000000000000000000000000000000000000000000000000000000001817350000000000000000000000000000000000000000000000000000000000181736000000000000000000000000000000000000000000000000000000000018173700000000000000000000000000000000000000000000000000000000001817380000000000000000000000000000000000000000000000000000000000181739000000000000000000000000000000000000000000000000000000000018173a000000000000000000000000000000000000000000000000000000000018173b000000000000000000000000000000000000000000000000000000000018173c000000000000000000000000000000000000000000000000000000000018173d000000000000000000000000000000000000000000000000000000000018173e000000000000000000000000000000000000000000000000000000000018173f00000000000000000000000000000000000000000000000000000000001817400000000000000000000000000000000000000000000000000000000000181741000000000000000000000000000000000000000000000000000000000018174200000000000000000000000000000000000000000000000000000000001817430000000000000000000000000000000000000000000000000000000000181744000000000000000000000000000000000000000000000000000000000018174500000000000000000000000000000000000000000000000000000000001817460000000000000000000000000000000000000000000000000000000000181736000000000000000000000000000000000000000000000000000000000018173700000000000000000000000000000000000000000000000000000000001817380000000000000000000000000000000000000000000000000000000000181739000000000000000000000000000000000000000000000000000000000018173a000000000000000000000000000000000000000000000000000000000018173b000000000000000000000000000000000000000000000000000000000018173c000000000000000000000000000000000000000000000000000000000018173d000000000000000000000000000000000000000000000000000000000018173e000000000000000000000000000000000000000000000000000000000018173f00000000000000000000000000000000000000000000000000000000001817400000000000000000000000000000000000000000000000000000000000181741000000000000000000000000000000000000000000000000000000000018174200000000000000000000000000000000000000000000000000000000001817430000000000000000000000000000000000000000000000000000000000181744000000000000000000000000000000000000000000000000000000000018174500000000000000000000000000000000000000000000000000000000001817460000000000000000000000000000000000000000000000000000000000181747000000000000000000000000000000000000000000000000000000000018173700000000000000000000000000000000000000000000000000000000001817380000000000000000000000000000000000000000000000000000000000181739000000000000000000000000000000000000000000000000000000000018173a000000000000000000000000000000000000000000000000000000000018173b000000000000000000000000000000000000000000000000000000000018173c000000000000000000000000000000000000000000000000000000000018173d000000000000000000000000000000000000000000000000000000000018173e000000000000000000000000000000000000000000000000000000000018173f00000000000000000000000000000000000000000000000000000000001817400000000000000000000000000000000000000000000000000000000000181741000000000000000000000000000000000000000000000000000000000018174200000000000000000000000000000000000000000000000000000000001817430000000000000000000000000000000000000000000000000000000000181744000000000000000000000000000000000000000000000000000000000018174500000000000000000000000000000000000000000000000000000000001817460000000000000000000000000000000000000000000000000000000000181747000000000000000000000000000000000000000000000000000000000018174800000000000000000000000000000000000000000000000000000000001817380000000000000000000000000000000000000000000000000000000000181739000000000000000000000000000000000000000000000000000000000018173a000000000000000000000000000000000000000000000000000000000018173b000000000000000000000000000000000000000000000000000000000018173c000000000000000000000000000000000000000000000000000000000018173d000000000000000000000000000000000000000000000000000000000018173e000000000000000000000000000000000000000000000000000000000018173f00000000000000000000000000000000000000000000000000000000001817400000000000000000000000000000000000000000000000000000000000181741000000000000000000000000000000000000000000000000000000000018174200000000000000000000000000000000000000000000000000000000001817430000000000000000000000000000000000000000000000000000000000181744000000000000000000000000000000000000000000000000000000000018174500000000000000000000000000000000000000000000000000000000001817460000000000000000000000000000000000000000000000000000000000181747000000000000000000000000000000000000000000000000000000000018174800000000000000000000000000000000000000000000000000000000001817490000000000000000000000000000000000000000000000000000000000181739000000000000000000000000000000000000000000000000000000000018173a000000000000000000000000000000000000000000000000000000000018173b000000000000000000000000000000000000000000000000000000000018173c000000000000000000000000000000000000000000000000000000000018173d000000000000000000000000000000000000000000000000000000000018173e000000000000000000000000000000000000000000000000000000000018173f0000000000000000000000000000000000000000000000000000000000181740000000000000000000000000000000000000000000000000000000000018174100000000000000000000000000000000000000000000000000000000001817420000000000000000000000000000000000000000000000000000000000181743000000000000000000000000000000000000000000000000000000000018174400000000000000000000000000000000000000000000000000000000001817450000000000000000000000000000000000000000000000000000000000181746000000000000000000000000000000000000000000000000000000000018174700000000000000000000000000000000000000000000000000000000001817480000000000000000000000000000000000000000000000000000000000181749000000000000000000000000000000000000000000000000000000000018174a000000000000000000000000000000000000000000000000000000000018173a000000000000000000000000000000000000000000000000000000000018173b000000000000000000000000000000000000000000000000000000000018173c000000000000000000000000000000000000000000000000000000000018173d000000000000000000000000000000000000000000000000000000000018173e000000000000000000000000000000000000000000000000000000000018173f0000000000000000000000000000000000000000000000000000000000181740000000000000000000000000000000000000000000000000000000000018174100000000000000000000000000000000000000000000000000000000001817420000000000000000000000000000000000000000000000000000000000181743000000000000000000000000000000000000000000000000000000000018174400000000000000000000000000000000000000000000000000000000001817450000000000000000000000000000000000000000000000000000000000181746000000000000000000000000000000000000000000000000000000000018174700000000000000000000000000000000000000000000000000000000001817480000000000000000000000000000000000000000000000000000000000181749000000000000000000000000000000000000000000000000000000000018174a000000000000000000000000000000000000000000000000000000000018174b000000000000000000000000000000000000000000000000000000000018173b000000000000000000000000000000000000000000000000000000000018173c000000000000000000000000000000000000000000000000000000000018173d000000000000000000000000000000000000000000000000000000000018173e000000000000000000000000000000000000000000000000000000000018173f0000000000000000000000000000000000000000000000000000000000181740000000000000000000000000000000000000000000000000000000000018174100000000000000000000000000000000000000000000000000000000001817420000000000000000000000000000000000000000000000000000000000181743000000000000000000000000000000000000000000000000000000000018174400000000000000000000000000000000000000000000000000000000001817450000000000000000000000000000000000000000000000000000000000181746000000000000000000000000000000000000000000000000000000000018174700000000000000000000000000000000000000000000000000000000001817480000000000000000000000000000000000000000000000000000000000181749000000000000000000000000000000000000000000000000000000000018174a000000000000000000000000000000000000000000000000000000000018174b000000000000000000000000000000000000000000000000000000000018174c000000000000000000000000000000000000000000000000000000000018173c000000000000000000000000000000000000000000000000000000000018173d000000000000000000000000000000000000000000000000000000000018173e000000000000000000000000000000000000000000000000000000000018173f0000000000000000000000000000000000000000000000000000000000181740000000000000000000000000000000000000000000000000000000000018174100000000000000000000000000000000000000000000000000000000001817420000000000000000000000000000000000000000000000000000000000181743000000000000000000000000000000000000000000000000000000000018174400000000000000000000000000000000000000000000000000000000001817450000000000000000000000000000000000000000000000000000000000181746000000000000000000000000000000000000000000000000000000000018174700000000000000000000000000000000000000000000000000000000001817480000000000000000000000000000000000000000000000000000000000181749000000000000000000000000000000000000000000000000000000000018174a000000000000000000000000000000000000000000000000000000000018174b000000000000000000000000000000000000000000000000000000000018174c000000000000000000000000000000000000000000000000000000000018174d000000000000000000000000000000000000000000000000000000000018173d000000000000000000000000000000000000000000000000000000000018173e000000000000000000000000000000000000000000000000000000000018173f0000000000000000000000000000000000000000000000000000000000181740000000000000000000000000000000000000000000000000000000000018174100000000000000000000000000000000000000000000000000000000001817420000000000000000000000000000000000000000000000000000000000181743000000000000000000000000000000000000000000000000000000000018174400000000000000000000000000000000000000000000000000000000001817450000000000000000000000000000000000000000000000000000000000181746000000000000000000000000000000000000000000000000000000000018174700000000000000000000000000000000000000000000000000000000001817480000000000000000000000000000000000000000000000000000000000181749000000000000000000000000000000000000000000000000000000000018174a000000000000000000000000000000000000000000000000000000000018174b000000000000000000000000000000000000000000000000000000000018174c000000000000000000000000000000000000000000000000000000000018174d000000000000000000000000000000000000000000000000000000000018174e000000000000000000000000000000000000000000000000000000000018173e000000000000000000000000000000000000000000000000000000000018173f0000000000000000000000000000000000000000000000000000000000181740000000000000000000000000000000000000000000000000000000000018174100000000000000000000000000000000000000000000000000000000001817420000000000000000000000000000000000000000000000000000000000181743000000000000000000000000000000000000000000000000000000000018174400000000000000000000000000000000000000000000000000000000001817450000000000000000000000000000000000000000000000000000000000181746000000000000000000000000000000000000000000000000000000000018174700000000000000000000000000000000000000000000000000000000001817480000000000000000000000000000000000000000000000000000000000181749000000000000000000000000000000000000000000000000000000000018174a000000000000000000000000000000000000000000000000000000000018174b000000000000000000000000000000000000000000000000000000000018174c000000000000000000000000000000000000000000000000000000000018174d000000000000000000000000000000000000000000000000000000000018174e000000000000000000000000000000000000000000000000000000000018174f000000000000000000000000000000000000000000000000000000000018173f0000000000000000000000000000000000000000000000000000000000181740000000000000000000000000000000000000000000000000000000000018174100000000000000000000000000000000000000000000000000000000001817420000000000000000000000000000000000000000000000000000000000181743000000000000000000000000000000000000000000000000000000000018174400000000000000000000000000000000000000000000000000000000001817450000000000000000000000000000000000000000000000000000000000181746000000000000000000000000000000000000000000000000000000000018174700000000000000000000000000000000000000000000000000000000001817480000000000000000000000000000000000000000000000000000000000181749000000000000000000000000000000000000000000000000000000000018174a000000000000000000000000000000000000000000000000000000000018174b000000000000000000000000000000000000000000000000000000000018174c000000000000000000000000000000000000000000000000000000000018174d000000000000000000000000000000000000000000000000000000000018174e000000000000000000000000000000000000000000000000000000000018174f00000000000000000000000000000000000000000000000000000000001817500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c100100000000000000000000000000000000000000000000000000000000001c100200000000000000000000000000000000000000000000000000000000001c100300000000000000000000000000000000000000000000000000000000001c100400000000000000000000000000000000000000000000000000000000001c100500000000000000000000000000000000000000000000000000000000001c100600000000000000000000000000000000000000000000000000000000001c100700000000000000000000000000000000000000000000000000000000001c100800000000000000000000000000000000000000000000000000000000001c100900000000000000000000000000000000000000000000000000000000001c100a00000000000000000000000000000000000000000000000000000000001c100b00000000000000000000000000000000000000000000000000000000001c100c00000000000000000000000000000000000000000000000000000000001c100d00000000000000000000000000000000000000000000000000000000001c100e00000000000000000000000000000000000000000000000000000000001c100f00000000000000000000000000000000000000000000000000000000001c101000000000000000000000000000000000000000000000000000000000001c101100000000000000000000000000000000000000000000000000000000001c101200000000000000000000000000000000000000000000000000000000001c101300000000000000000000000000000000000000000000000000000000001c101400000000000000000000000000000000000000000000000000000000001c101500000000000000000000000000000000000000000000000000000000001c101600000000000000000000000000000000000000000000000000000000001c101700000000000000000000000000000000000000000000000000000000001c101800000000000000000000000000000000000000000000000000000000001c101900000000000000000000000000000000000000000000000000000000001c101a00000000000000000000000000000000000000000000000000000000001c101b00000000000000000000000000000000000000000000000000000000001c101c00000000000000000000000000000000000000000000000000000000001c101d00000000000000000000000000000000000000000000000000000000001c101e00000000000000000000000000000000000000000000000000000000001c101f00000000000000000000000000000000000000000000000000000000001c102000000000000000000000000000000000000000000000000000000000001c102100000000000000000000000000000000000000000000000000000000001c102200000000000000000000000000000000000000000000000000000000001c102300000000000000000000000000000000000000000000000000000000001c102400000000000000000000000000000000000000000000000000000000001c102500000000000000000000000000000000000000000000000000000000001c102600000000000000000000000000000000000000000000000000000000001c102700000000000000000000000000000000000000000000000000000000001c102800000000000000000000000000000000000000000000000000000000001c102900000000000000000000000000000000000000000000000000000000001c102a00000000000000000000000000000000000000000000000000000000001c102b00000000000000000000000000000000000000000000000000000000001c102c00000000000000000000000000000000000000000000000000000000001c102d00000000000000000000000000000000000000000000000000000000001c102e00000000000000000000000000000000000000000000000000000000001c102f00000000000000000000000000000000000000000000000000000000001c103000000000000000000000000000000000000000000000000000000000001c103100000000000000000000000000000000000000000000000000000000001c103200000000000000000000000000000000000000000000000000000000001c103300000000000000000000000000000000000000000000000000000000001c103400000000000000000000000000000000000000000000000000000000001c103500000000000000000000000000000000000000000000000000000000001c103600000000000000000000000000000000000000000000000000000000001c103700000000000000000000000000000000000000000000000000000000001c103800000000000000000000000000000000000000000000000000000000001c103900000000000000000000000000000000000000000000000000000000001c103a00000000000000000000000000000000000000000000000000000000001c103b00000000000000000000000000000000000000000000000000000000001c103c00000000000000000000000000000000000000000000000000000000001c103d00000000000000000000000000000000000000000000000000000000001c103e00000000000000000000000000000000000000000000000000000000001c103f4000000000000000000000000000000000000000000000000000000000001c000100000000000000000000000000000000000000000000000000000000001c110000000000000000000000000000000000000000000000000000000000001c110100000000000000000000000000000000000000000000000000000000001c110200000000000000000000000000000000000000000000000000000000001c110300000000000000000000000000000000000000000000000000000000001c110400000000000000000000000000000000000000000000000000000000001c110500000000000000000000000000000000000000000000000000000000001c110600000000000000000000000000000000000000000000000000000000001c110700000000000000000000000000000000000000000000000000000000001c110800000000000000000000000000000000000000000000000000000000001c110900000000000000000000000000000000000000000000000000000000001c110a00000000000000000000000000000000000000000000000000000000001c110b00000000000000000000000000000000000000000000000000000000001c110c00000000000000000000000000000000000000000000000000000000001c110d00000000000000000000000000000000000000000000000000000000001c110e00000000000000000000000000000000000000000000000000000000001c110f00000000000000000000000000000000000000000000000000000000001c111000000000000000000000000000000000000000000000000000000000001c111100000000000000000000000000000000000000000000000000000000001c111200000000000000000000000000000000000000000000000000000000001c111300000000000000000000000000000000000000000000000000000000001c111400000000000000000000000000000000000000000000000000000000001c111500000000000000000000000000000000000000000000000000000000001c111600000000000000000000000000000000000000000000000000000000001c111700000000000000000000000000000000000000000000000000000000001c111800000000000000000000000000000000000000000000000000000000001c111900000000000000000000000000000000000000000000000000000000001c111a00000000000000000000000000000000000000000000000000000000001c111b00000000000000000000000000000000000000000000000000000000001c111c00000000000000000000000000000000000000000000000000000000001c111d00000000000000000000000000000000000000000000000000000000001c111e00000000000000000000000000000000000000000000000000000000001c111f00000000000000000000000000000000000000000000000000000000001c112000000000000000000000000000000000000000000000000000000000001c112100000000000000000000000000000000000000000000000000000000001c112200000000000000000000000000000000000000000000000000000000001c112300000000000000000000000000000000000000000000000000000000001c112400000000000000000000000000000000000000000000000000000000001c112500000000000000000000000000000000000000000000000000000000001c112600000000000000000000000000000000000000000000000000000000001c112700000000000000000000000000000000000000000000000000000000001c112800000000000000000000000000000000000000000000000000000000001c112900000000000000000000000000000000000000000000000000000000001c112a00000000000000000000000000000000000000000000000000000000001c112b00000000000000000000000000000000000000000000000000000000001c112c00000000000000000000000000000000000000000000000000000000001c112d00000000000000000000000000000000000000000000000000000000001c112e00000000000000000000000000000000000000000000000000000000001c112f00000000000000000000000000000000000000000000000000000000001c113000000000000000000000000000000000000000000000000000000000001c113100000000000000000000000000000000000000000000000000000000001c113200000000000000000000000000000000000000000000000000000000001c113300000000000000000000000000000000000000000000000000000000001c113400000000000000000000000000000000000000000000000000000000001c113500000000000000000000000000000000000000000000000000000000001c113600000000000000000000000000000000000000000000000000000000001c113700000000000000000000000000000000000000000000000000000000001c113800000000000000000000000000000000000000000000000000000000001c113900000000000000000000000000000000000000000000000000000000001c113a00000000000000000000000000000000000000000000000000000000001c113b00000000000000000000000000000000000000000000000000000000001c113c00000000000000000000000000000000000000000000000000000000001c113d00000000000000000000000000000000000000000000000000000000001c113e08006838aa99533bea0d4204cad17cb3c147e99c2f9089e54a4289d54733eeada2002ab314bd11ace2494a3fb0970d276da39f0fe7da19c9a2438b9c7c334d32470071703d79d8425a7eca52006df6a8f9728508a83639e3e1c2ebae2b853a087c00c9501ac04a78ac5413c9131b08708064ed2c2515b8893f12c2d1cda15a44f100a0955f93e109778d26f9e5b0d46e45c539e59b0941517bfa888eb2d7d2d8a6005adc3be9406cc5f102c6adb44746e8529a256e2396353a8659344cc3e914c4007a5fe572cf6af804f472dabf095c5eb6b30efc5fd627ad3245a8ef0f3f578c003dcaa91dfc9fdad7ba8da68a48fc662dfc0a995cbb0c1bc62099c8257d240d3f00000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c200a00000000000000000000000000000000000000000000000000000000001c200100000000000000000000000000000000000000000000000000000000001c200b00000000000000000000000000000000000000000000000000000000001c200200000000000000000000000000000000000000000000000000000000001c200c00000000000000000000000000000000000000000000000000000000001c200300000000000000000000000000000000000000000000000000000000001c200d00000000000000000000000000000000000000000000000000000000001c200400000000000000000000000000000000000000000000000000000000001c200e00000000000000000000000000000000000000000000000000000000001c200500000000000000000000000000000000000000000000000000000000001c200f00000000000000000000000000000000000000000000000000000000001c200600000000000000000000000000000000000000000000000000000000001c201000000000000000000000000000000000000000000000000000000000001c200700000000000000000000000000000000000000000000000000000000001c201100000000000000000000000000000000000000000000000000000000001c200800000000000000000000000000000000000000000000000000000000001c201200000000000000000000000000000000000000000000000000000000001c200900000000000000000000000000000000000000000000000000000000001c201300000000000000000000000000000000000000000000000000000000001c200a00000000000000000000000000000000000000000000000000000000001c201400000000000000000000000000000000000000000000000000000000001c200b00000000000000000000000000000000000000000000000000000000001c201500000000000000000000000000000000000000000000000000000000001c200c00000000000000000000000000000000000000000000000000000000001c201600000000000000000000000000000000000000000000000000000000001c200d00000000000000000000000000000000000000000000000000000000001c201700000000000000000000000000000000000000000000000000000000001c200e00000000000000000000000000000000000000000000000000000000001c201800000000000000000000000000000000000000000000000000000000001c200f00000000000000000000000000000000000000000000000000000000001c201900000000000000000000000000000000000000000000000000000000001c201000000000000000000000000000000000000000000000000000000000001c201a00000000000000000000000000000000000000000000000000000000001c201100000000000000000000000000000000000000000000000000000000001c201b00000000000000000000000000000000000000000000000000000000001c201200000000000000000000000000000000000000000000000000000000001c201c00000000000000000000000000000000000000000000000000000000001c201300000000000000000000000000000000000000000000000000000000001c201d00000000000000000000000000000000000000000000000000000000001c201400000000000000000000000000000000000000000000000000000000001c201e00000000000000000000000000000000000000000000000000000000001c201500000000000000000000000000000000000000000000000000000000001c201f00000000000000000000000000000000000000000000000000000000001c201600000000000000000000000000000000000000000000000000000000001c202000000000000000000000000000000000000000000000000000000000001c201700000000000000000000000000000000000000000000000000000000001c202100000000000000000000000000000000000000000000000000000000001c201800000000000000000000000000000000000000000000000000000000001c202200000000000000000000000000000000000000000000000000000000001c201900000000000000000000000000000000000000000000000000000000001c202300000000000000000000000000000000000000000000000000000000001c201a00000000000000000000000000000000000000000000000000000000001c202400000000000000000000000000000000000000000000000000000000001c201b00000000000000000000000000000000000000000000000000000000001c202500000000000000000000000000000000000000000000000000000000001c201c00000000000000000000000000000000000000000000000000000000001c202600000000000000000000000000000000000000000000000000000000001c201d00000000000000000000000000000000000000000000000000000000001c202700000000000000000000000000000000000000000000000000000000001c201e00000000000000000000000000000000000000000000000000000000001c202800000000000000000000000000000000000000000000000000000000001c201f00000000000000000000000000000000000000000000000000000000001c202900000000000000000000000000000000000000000000000000000000001c202000000000000000000000000000000000000000000000000000000000001c202a00000000000000000000000000000000000000000000000000000000001c202100000000000000000000000000000000000000000000000000000000001c202b00000000000000000000000000000000000000000000000000000000001c202200000000000000000000000000000000000000000000000000000000001c202c00000000000000000000000000000000000000000000000000000000001c202300000000000000000000000000000000000000000000000000000000001c202d00000000000000000000000000000000000000000000000000000000001c202400000000000000000000000000000000000000000000000000000000001c202e00000000000000000000000000000000000000000000000000000000001c202500000000000000000000000000000000000000000000000000000000001c202f00000000000000000000000000000000000000000000000000000000001c202600000000000000000000000000000000000000000000000000000000001c203000000000000000000000000000000000000000000000000000000000001c202700000000000000000000000000000000000000000000000000000000001c203100000000000000000000000000000000000000000000000000000000001c202800000000000000000000000000000000000000000000000000000000001c203200000000000000000000000000000000000000000000000000000000001c202900000000000000000000000000000000000000000000000000000000001c203300000000000000000000000000000000000000000000000000000000001c202a00000000000000000000000000000000000000000000000000000000001c203400000000000000000000000000000000000000000000000000000000001c202b00000000000000000000000000000000000000000000000000000000001c203500000000000000000000000000000000000000000000000000000000001c202c00000000000000000000000000000000000000000000000000000000001c203600000000000000000000000000000000000000000000000000000000001c202d00000000000000000000000000000000000000000000000000000000001c203700000000000000000000000000000000000000000000000000000000001c202e00000000000000000000000000000000000000000000000000000000001c203800000000000000000000000000000000000000000000000000000000001c202f00000000000000000000000000000000000000000000000000000000001c203900000000000000000000000000000000000000000000000000000000001c203000000000000000000000000000000000000000000000000000000000001c203a00000000000000000000000000000000000000000000000000000000001c203100000000000000000000000000000000000000000000000000000000001c203b00000000000000000000000000000000000000000000000000000000001c203200000000000000000000000000000000000000000000000000000000001c203c00000000000000000000000000000000000000000000000000000000001c203300000000000000000000000000000000000000000000000000000000001c203d00000000000000000000000000000000000000000000000000000000001c203400000000000000000000000000000000000000000000000000000000001c203e00000000000000000000000000000000000000000000000000000000001c203500000000000000000000000000000000000000000000000000000000001c203f00000000000000000000000000000000000000000000000000000000001c203600000000000000000000000000000000000000000000000000000000001c204000000000000000000000000000000000000000000000000000000000001c203700000000000000000000000000000000000000000000000000000000001c204100000000000000000000000000000000000000000000000000000000001c203800000000000000000000000000000000000000000000000000000000001c204200000000000000000000000000000000000000000000000000000000001c203900000000000000000000000000000000000000000000000000000000001c204300000000000000000000000000000000000000000000000000000000001c203a00000000000000000000000000000000000000000000000000000000001c204400000000000000000000000000000000000000000000000000000000001c203b00000000000000000000000000000000000000000000000000000000001c204500000000000000000000000000000000000000000000000000000000001c203c00000000000000000000000000000000000000000000000000000000001c204600000000000000000000000000000000000000000000000000000000001c203d00000000000000000000000000000000000000000000000000000000001c204700000000000000000000000000000000000000000000000000000000001c203e00000000000000000000000000000000000000000000000000000000001c20484000000000000000000000000000000000000000000000000000000000001c170000000000000000000000000000000000000000000000000000000000001c170100000000000000000000000000000000000000000000000000000000001c170200000000000000000000000000000000000000000000000000000000001c170300000000000000000000000000000000000000000000000000000000001c170400000000000000000000000000000000000000000000000000000000001c170500000000000000000000000000000000000000000000000000000000001c170600000000000000000000000000000000000000000000000000000000001c170700000000000000000000000000000000000000000000000000000000001c170800000000000000000000000000000000000000000000000000000000001c170900000000000000000000000000000000000000000000000000000000001c170a00000000000000000000000000000000000000000000000000000000001c170b00000000000000000000000000000000000000000000000000000000001c170c00000000000000000000000000000000000000000000000000000000001c170d00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c170100000000000000000000000000000000000000000000000000000000001c170200000000000000000000000000000000000000000000000000000000001c170300000000000000000000000000000000000000000000000000000000001c170400000000000000000000000000000000000000000000000000000000001c170500000000000000000000000000000000000000000000000000000000001c170600000000000000000000000000000000000000000000000000000000001c170700000000000000000000000000000000000000000000000000000000001c170800000000000000000000000000000000000000000000000000000000001c170900000000000000000000000000000000000000000000000000000000001c170a00000000000000000000000000000000000000000000000000000000001c170b00000000000000000000000000000000000000000000000000000000001c170c00000000000000000000000000000000000000000000000000000000001c170d00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c170200000000000000000000000000000000000000000000000000000000001c170300000000000000000000000000000000000000000000000000000000001c170400000000000000000000000000000000000000000000000000000000001c170500000000000000000000000000000000000000000000000000000000001c170600000000000000000000000000000000000000000000000000000000001c170700000000000000000000000000000000000000000000000000000000001c170800000000000000000000000000000000000000000000000000000000001c170900000000000000000000000000000000000000000000000000000000001c170a00000000000000000000000000000000000000000000000000000000001c170b00000000000000000000000000000000000000000000000000000000001c170c00000000000000000000000000000000000000000000000000000000001c170d00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c170300000000000000000000000000000000000000000000000000000000001c170400000000000000000000000000000000000000000000000000000000001c170500000000000000000000000000000000000000000000000000000000001c170600000000000000000000000000000000000000000000000000000000001c170700000000000000000000000000000000000000000000000000000000001c170800000000000000000000000000000000000000000000000000000000001c170900000000000000000000000000000000000000000000000000000000001c170a00000000000000000000000000000000000000000000000000000000001c170b00000000000000000000000000000000000000000000000000000000001c170c00000000000000000000000000000000000000000000000000000000001c170d00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c170400000000000000000000000000000000000000000000000000000000001c170500000000000000000000000000000000000000000000000000000000001c170600000000000000000000000000000000000000000000000000000000001c170700000000000000000000000000000000000000000000000000000000001c170800000000000000000000000000000000000000000000000000000000001c170900000000000000000000000000000000000000000000000000000000001c170a00000000000000000000000000000000000000000000000000000000001c170b00000000000000000000000000000000000000000000000000000000001c170c00000000000000000000000000000000000000000000000000000000001c170d00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c170500000000000000000000000000000000000000000000000000000000001c170600000000000000000000000000000000000000000000000000000000001c170700000000000000000000000000000000000000000000000000000000001c170800000000000000000000000000000000000000000000000000000000001c170900000000000000000000000000000000000000000000000000000000001c170a00000000000000000000000000000000000000000000000000000000001c170b00000000000000000000000000000000000000000000000000000000001c170c00000000000000000000000000000000000000000000000000000000001c170d00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c170600000000000000000000000000000000000000000000000000000000001c170700000000000000000000000000000000000000000000000000000000001c170800000000000000000000000000000000000000000000000000000000001c170900000000000000000000000000000000000000000000000000000000001c170a00000000000000000000000000000000000000000000000000000000001c170b00000000000000000000000000000000000000000000000000000000001c170c00000000000000000000000000000000000000000000000000000000001c170d00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c170700000000000000000000000000000000000000000000000000000000001c170800000000000000000000000000000000000000000000000000000000001c170900000000000000000000000000000000000000000000000000000000001c170a00000000000000000000000000000000000000000000000000000000001c170b00000000000000000000000000000000000000000000000000000000001c170c00000000000000000000000000000000000000000000000000000000001c170d00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c170800000000000000000000000000000000000000000000000000000000001c170900000000000000000000000000000000000000000000000000000000001c170a00000000000000000000000000000000000000000000000000000000001c170b00000000000000000000000000000000000000000000000000000000001c170c00000000000000000000000000000000000000000000000000000000001c170d00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c170900000000000000000000000000000000000000000000000000000000001c170a00000000000000000000000000000000000000000000000000000000001c170b00000000000000000000000000000000000000000000000000000000001c170c00000000000000000000000000000000000000000000000000000000001c170d00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c170a00000000000000000000000000000000000000000000000000000000001c170b00000000000000000000000000000000000000000000000000000000001c170c00000000000000000000000000000000000000000000000000000000001c170d00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c170b00000000000000000000000000000000000000000000000000000000001c170c00000000000000000000000000000000000000000000000000000000001c170d00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c170c00000000000000000000000000000000000000000000000000000000001c170d00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c170d00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c170e00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c170f00000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c171000000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c171100000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c171200000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c171300000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c171400000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c171500000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c171600000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c172700000000000000000000000000000000000000000000000000000000001c171700000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c172700000000000000000000000000000000000000000000000000000000001c172800000000000000000000000000000000000000000000000000000000001c171800000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c172700000000000000000000000000000000000000000000000000000000001c172800000000000000000000000000000000000000000000000000000000001c172900000000000000000000000000000000000000000000000000000000001c171900000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c172700000000000000000000000000000000000000000000000000000000001c172800000000000000000000000000000000000000000000000000000000001c172900000000000000000000000000000000000000000000000000000000001c172a00000000000000000000000000000000000000000000000000000000001c171a00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c172700000000000000000000000000000000000000000000000000000000001c172800000000000000000000000000000000000000000000000000000000001c172900000000000000000000000000000000000000000000000000000000001c172a00000000000000000000000000000000000000000000000000000000001c172b00000000000000000000000000000000000000000000000000000000001c171b00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c172700000000000000000000000000000000000000000000000000000000001c172800000000000000000000000000000000000000000000000000000000001c172900000000000000000000000000000000000000000000000000000000001c172a00000000000000000000000000000000000000000000000000000000001c172b00000000000000000000000000000000000000000000000000000000001c172c00000000000000000000000000000000000000000000000000000000001c171c00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c172700000000000000000000000000000000000000000000000000000000001c172800000000000000000000000000000000000000000000000000000000001c172900000000000000000000000000000000000000000000000000000000001c172a00000000000000000000000000000000000000000000000000000000001c172b00000000000000000000000000000000000000000000000000000000001c172c00000000000000000000000000000000000000000000000000000000001c172d00000000000000000000000000000000000000000000000000000000001c171d00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c172700000000000000000000000000000000000000000000000000000000001c172800000000000000000000000000000000000000000000000000000000001c172900000000000000000000000000000000000000000000000000000000001c172a00000000000000000000000000000000000000000000000000000000001c172b00000000000000000000000000000000000000000000000000000000001c172c00000000000000000000000000000000000000000000000000000000001c172d00000000000000000000000000000000000000000000000000000000001c172e00000000000000000000000000000000000000000000000000000000001c171e00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c172700000000000000000000000000000000000000000000000000000000001c172800000000000000000000000000000000000000000000000000000000001c172900000000000000000000000000000000000000000000000000000000001c172a00000000000000000000000000000000000000000000000000000000001c172b00000000000000000000000000000000000000000000000000000000001c172c00000000000000000000000000000000000000000000000000000000001c172d00000000000000000000000000000000000000000000000000000000001c172e00000000000000000000000000000000000000000000000000000000001c172f00000000000000000000000000000000000000000000000000000000001c171f00000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c172700000000000000000000000000000000000000000000000000000000001c172800000000000000000000000000000000000000000000000000000000001c172900000000000000000000000000000000000000000000000000000000001c172a00000000000000000000000000000000000000000000000000000000001c172b00000000000000000000000000000000000000000000000000000000001c172c00000000000000000000000000000000000000000000000000000000001c172d00000000000000000000000000000000000000000000000000000000001c172e00000000000000000000000000000000000000000000000000000000001c172f00000000000000000000000000000000000000000000000000000000001c173000000000000000000000000000000000000000000000000000000000001c172000000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c172700000000000000000000000000000000000000000000000000000000001c172800000000000000000000000000000000000000000000000000000000001c172900000000000000000000000000000000000000000000000000000000001c172a00000000000000000000000000000000000000000000000000000000001c172b00000000000000000000000000000000000000000000000000000000001c172c00000000000000000000000000000000000000000000000000000000001c172d00000000000000000000000000000000000000000000000000000000001c172e00000000000000000000000000000000000000000000000000000000001c172f00000000000000000000000000000000000000000000000000000000001c173000000000000000000000000000000000000000000000000000000000001c173100000000000000000000000000000000000000000000000000000000001c172100000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c172700000000000000000000000000000000000000000000000000000000001c172800000000000000000000000000000000000000000000000000000000001c172900000000000000000000000000000000000000000000000000000000001c172a00000000000000000000000000000000000000000000000000000000001c172b00000000000000000000000000000000000000000000000000000000001c172c00000000000000000000000000000000000000000000000000000000001c172d00000000000000000000000000000000000000000000000000000000001c172e00000000000000000000000000000000000000000000000000000000001c172f00000000000000000000000000000000000000000000000000000000001c173000000000000000000000000000000000000000000000000000000000001c173100000000000000000000000000000000000000000000000000000000001c173200000000000000000000000000000000000000000000000000000000001c172200000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c172700000000000000000000000000000000000000000000000000000000001c172800000000000000000000000000000000000000000000000000000000001c172900000000000000000000000000000000000000000000000000000000001c172a00000000000000000000000000000000000000000000000000000000001c172b00000000000000000000000000000000000000000000000000000000001c172c00000000000000000000000000000000000000000000000000000000001c172d00000000000000000000000000000000000000000000000000000000001c172e00000000000000000000000000000000000000000000000000000000001c172f00000000000000000000000000000000000000000000000000000000001c173000000000000000000000000000000000000000000000000000000000001c173100000000000000000000000000000000000000000000000000000000001c173200000000000000000000000000000000000000000000000000000000001c173300000000000000000000000000000000000000000000000000000000001c172300000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c172700000000000000000000000000000000000000000000000000000000001c172800000000000000000000000000000000000000000000000000000000001c172900000000000000000000000000000000000000000000000000000000001c172a00000000000000000000000000000000000000000000000000000000001c172b00000000000000000000000000000000000000000000000000000000001c172c00000000000000000000000000000000000000000000000000000000001c172d00000000000000000000000000000000000000000000000000000000001c172e00000000000000000000000000000000000000000000000000000000001c172f00000000000000000000000000000000000000000000000000000000001c173000000000000000000000000000000000000000000000000000000000001c173100000000000000000000000000000000000000000000000000000000001c173200000000000000000000000000000000000000000000000000000000001c173300000000000000000000000000000000000000000000000000000000001c173400000000000000000000000000000000000000000000000000000000001c172400000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c172700000000000000000000000000000000000000000000000000000000001c172800000000000000000000000000000000000000000000000000000000001c172900000000000000000000000000000000000000000000000000000000001c172a00000000000000000000000000000000000000000000000000000000001c172b00000000000000000000000000000000000000000000000000000000001c172c00000000000000000000000000000000000000000000000000000000001c172d00000000000000000000000000000000000000000000000000000000001c172e00000000000000000000000000000000000000000000000000000000001c172f00000000000000000000000000000000000000000000000000000000001c173000000000000000000000000000000000000000000000000000000000001c173100000000000000000000000000000000000000000000000000000000001c173200000000000000000000000000000000000000000000000000000000001c173300000000000000000000000000000000000000000000000000000000001c173400000000000000000000000000000000000000000000000000000000001c173500000000000000000000000000000000000000000000000000000000001c172500000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c172700000000000000000000000000000000000000000000000000000000001c172800000000000000000000000000000000000000000000000000000000001c172900000000000000000000000000000000000000000000000000000000001c172a00000000000000000000000000000000000000000000000000000000001c172b00000000000000000000000000000000000000000000000000000000001c172c00000000000000000000000000000000000000000000000000000000001c172d00000000000000000000000000000000000000000000000000000000001c172e00000000000000000000000000000000000000000000000000000000001c172f00000000000000000000000000000000000000000000000000000000001c173000000000000000000000000000000000000000000000000000000000001c173100000000000000000000000000000000000000000000000000000000001c173200000000000000000000000000000000000000000000000000000000001c173300000000000000000000000000000000000000000000000000000000001c173400000000000000000000000000000000000000000000000000000000001c173500000000000000000000000000000000000000000000000000000000001c173600000000000000000000000000000000000000000000000000000000001c172600000000000000000000000000000000000000000000000000000000001c172700000000000000000000000000000000000000000000000000000000001c172800000000000000000000000000000000000000000000000000000000001c172900000000000000000000000000000000000000000000000000000000001c172a00000000000000000000000000000000000000000000000000000000001c172b00000000000000000000000000000000000000000000000000000000001c172c00000000000000000000000000000000000000000000000000000000001c172d00000000000000000000000000000000000000000000000000000000001c172e00000000000000000000000000000000000000000000000000000000001c172f00000000000000000000000000000000000000000000000000000000001c173000000000000000000000000000000000000000000000000000000000001c173100000000000000000000000000000000000000000000000000000000001c173200000000000000000000000000000000000000000000000000000000001c173300000000000000000000000000000000000000000000000000000000001c173400000000000000000000000000000000000000000000000000000000001c173500000000000000000000000000000000000000000000000000000000001c173600000000000000000000000000000000000000000000000000000000001c173700000000000000000000000000000000000000000000000000000000001c172700000000000000000000000000000000000000000000000000000000001c172800000000000000000000000000000000000000000000000000000000001c172900000000000000000000000000000000000000000000000000000000001c172a00000000000000000000000000000000000000000000000000000000001c172b00000000000000000000000000000000000000000000000000000000001c172c00000000000000000000000000000000000000000000000000000000001c172d00000000000000000000000000000000000000000000000000000000001c172e00000000000000000000000000000000000000000000000000000000001c172f00000000000000000000000000000000000000000000000000000000001c173000000000000000000000000000000000000000000000000000000000001c173100000000000000000000000000000000000000000000000000000000001c173200000000000000000000000000000000000000000000000000000000001c173300000000000000000000000000000000000000000000000000000000001c173400000000000000000000000000000000000000000000000000000000001c173500000000000000000000000000000000000000000000000000000000001c173600000000000000000000000000000000000000000000000000000000001c173700000000000000000000000000000000000000000000000000000000001c173800000000000000000000000000000000000000000000000000000000001c172800000000000000000000000000000000000000000000000000000000001c172900000000000000000000000000000000000000000000000000000000001c172a00000000000000000000000000000000000000000000000000000000001c172b00000000000000000000000000000000000000000000000000000000001c172c00000000000000000000000000000000000000000000000000000000001c172d00000000000000000000000000000000000000000000000000000000001c172e00000000000000000000000000000000000000000000000000000000001c172f00000000000000000000000000000000000000000000000000000000001c173000000000000000000000000000000000000000000000000000000000001c173100000000000000000000000000000000000000000000000000000000001c173200000000000000000000000000000000000000000000000000000000001c173300000000000000000000000000000000000000000000000000000000001c173400000000000000000000000000000000000000000000000000000000001c173500000000000000000000000000000000000000000000000000000000001c173600000000000000000000000000000000000000000000000000000000001c173700000000000000000000000000000000000000000000000000000000001c173800000000000000000000000000000000000000000000000000000000001c173900000000000000000000000000000000000000000000000000000000001c172900000000000000000000000000000000000000000000000000000000001c172a00000000000000000000000000000000000000000000000000000000001c172b00000000000000000000000000000000000000000000000000000000001c172c00000000000000000000000000000000000000000000000000000000001c172d00000000000000000000000000000000000000000000000000000000001c172e00000000000000000000000000000000000000000000000000000000001c172f00000000000000000000000000000000000000000000000000000000001c173000000000000000000000000000000000000000000000000000000000001c173100000000000000000000000000000000000000000000000000000000001c173200000000000000000000000000000000000000000000000000000000001c173300000000000000000000000000000000000000000000000000000000001c173400000000000000000000000000000000000000000000000000000000001c173500000000000000000000000000000000000000000000000000000000001c173600000000000000000000000000000000000000000000000000000000001c173700000000000000000000000000000000000000000000000000000000001c173800000000000000000000000000000000000000000000000000000000001c173900000000000000000000000000000000000000000000000000000000001c173a00000000000000000000000000000000000000000000000000000000001c172a00000000000000000000000000000000000000000000000000000000001c172b00000000000000000000000000000000000000000000000000000000001c172c00000000000000000000000000000000000000000000000000000000001c172d00000000000000000000000000000000000000000000000000000000001c172e00000000000000000000000000000000000000000000000000000000001c172f00000000000000000000000000000000000000000000000000000000001c173000000000000000000000000000000000000000000000000000000000001c173100000000000000000000000000000000000000000000000000000000001c173200000000000000000000000000000000000000000000000000000000001c173300000000000000000000000000000000000000000000000000000000001c173400000000000000000000000000000000000000000000000000000000001c173500000000000000000000000000000000000000000000000000000000001c173600000000000000000000000000000000000000000000000000000000001c173700000000000000000000000000000000000000000000000000000000001c173800000000000000000000000000000000000000000000000000000000001c173900000000000000000000000000000000000000000000000000000000001c173a00000000000000000000000000000000000000000000000000000000001c173b00000000000000000000000000000000000000000000000000000000001c172b00000000000000000000000000000000000000000000000000000000001c172c00000000000000000000000000000000000000000000000000000000001c172d00000000000000000000000000000000000000000000000000000000001c172e00000000000000000000000000000000000000000000000000000000001c172f00000000000000000000000000000000000000000000000000000000001c173000000000000000000000000000000000000000000000000000000000001c173100000000000000000000000000000000000000000000000000000000001c173200000000000000000000000000000000000000000000000000000000001c173300000000000000000000000000000000000000000000000000000000001c173400000000000000000000000000000000000000000000000000000000001c173500000000000000000000000000000000000000000000000000000000001c173600000000000000000000000000000000000000000000000000000000001c173700000000000000000000000000000000000000000000000000000000001c173800000000000000000000000000000000000000000000000000000000001c173900000000000000000000000000000000000000000000000000000000001c173a00000000000000000000000000000000000000000000000000000000001c173b00000000000000000000000000000000000000000000000000000000001c173c00000000000000000000000000000000000000000000000000000000001c172c00000000000000000000000000000000000000000000000000000000001c172d00000000000000000000000000000000000000000000000000000000001c172e00000000000000000000000000000000000000000000000000000000001c172f00000000000000000000000000000000000000000000000000000000001c173000000000000000000000000000000000000000000000000000000000001c173100000000000000000000000000000000000000000000000000000000001c173200000000000000000000000000000000000000000000000000000000001c173300000000000000000000000000000000000000000000000000000000001c173400000000000000000000000000000000000000000000000000000000001c173500000000000000000000000000000000000000000000000000000000001c173600000000000000000000000000000000000000000000000000000000001c173700000000000000000000000000000000000000000000000000000000001c173800000000000000000000000000000000000000000000000000000000001c173900000000000000000000000000000000000000000000000000000000001c173a00000000000000000000000000000000000000000000000000000000001c173b00000000000000000000000000000000000000000000000000000000001c173c00000000000000000000000000000000000000000000000000000000001c173d00000000000000000000000000000000000000000000000000000000001c172d00000000000000000000000000000000000000000000000000000000001c172e00000000000000000000000000000000000000000000000000000000001c172f00000000000000000000000000000000000000000000000000000000001c173000000000000000000000000000000000000000000000000000000000001c173100000000000000000000000000000000000000000000000000000000001c173200000000000000000000000000000000000000000000000000000000001c173300000000000000000000000000000000000000000000000000000000001c173400000000000000000000000000000000000000000000000000000000001c173500000000000000000000000000000000000000000000000000000000001c173600000000000000000000000000000000000000000000000000000000001c173700000000000000000000000000000000000000000000000000000000001c173800000000000000000000000000000000000000000000000000000000001c173900000000000000000000000000000000000000000000000000000000001c173a00000000000000000000000000000000000000000000000000000000001c173b00000000000000000000000000000000000000000000000000000000001c173c00000000000000000000000000000000000000000000000000000000001c173d00000000000000000000000000000000000000000000000000000000001c173e00000000000000000000000000000000000000000000000000000000001c172e00000000000000000000000000000000000000000000000000000000001c172f00000000000000000000000000000000000000000000000000000000001c173000000000000000000000000000000000000000000000000000000000001c173100000000000000000000000000000000000000000000000000000000001c173200000000000000000000000000000000000000000000000000000000001c173300000000000000000000000000000000000000000000000000000000001c173400000000000000000000000000000000000000000000000000000000001c173500000000000000000000000000000000000000000000000000000000001c173600000000000000000000000000000000000000000000000000000000001c173700000000000000000000000000000000000000000000000000000000001c173800000000000000000000000000000000000000000000000000000000001c173900000000000000000000000000000000000000000000000000000000001c173a00000000000000000000000000000000000000000000000000000000001c173b00000000000000000000000000000000000000000000000000000000001c173c00000000000000000000000000000000000000000000000000000000001c173d00000000000000000000000000000000000000000000000000000000001c173e00000000000000000000000000000000000000000000000000000000001c173f00000000000000000000000000000000000000000000000000000000001c172f00000000000000000000000000000000000000000000000000000000001c173000000000000000000000000000000000000000000000000000000000001c173100000000000000000000000000000000000000000000000000000000001c173200000000000000000000000000000000000000000000000000000000001c173300000000000000000000000000000000000000000000000000000000001c173400000000000000000000000000000000000000000000000000000000001c173500000000000000000000000000000000000000000000000000000000001c173600000000000000000000000000000000000000000000000000000000001c173700000000000000000000000000000000000000000000000000000000001c173800000000000000000000000000000000000000000000000000000000001c173900000000000000000000000000000000000000000000000000000000001c173a00000000000000000000000000000000000000000000000000000000001c173b00000000000000000000000000000000000000000000000000000000001c173c00000000000000000000000000000000000000000000000000000000001c173d00000000000000000000000000000000000000000000000000000000001c173e00000000000000000000000000000000000000000000000000000000001c173f00000000000000000000000000000000000000000000000000000000001c174000000000000000000000000000000000000000000000000000000000001c173000000000000000000000000000000000000000000000000000000000001c173100000000000000000000000000000000000000000000000000000000001c173200000000000000000000000000000000000000000000000000000000001c173300000000000000000000000000000000000000000000000000000000001c173400000000000000000000000000000000000000000000000000000000001c173500000000000000000000000000000000000000000000000000000000001c173600000000000000000000000000000000000000000000000000000000001c173700000000000000000000000000000000000000000000000000000000001c173800000000000000000000000000000000000000000000000000000000001c173900000000000000000000000000000000000000000000000000000000001c173a00000000000000000000000000000000000000000000000000000000001c173b00000000000000000000000000000000000000000000000000000000001c173c00000000000000000000000000000000000000000000000000000000001c173d00000000000000000000000000000000000000000000000000000000001c173e00000000000000000000000000000000000000000000000000000000001c173f00000000000000000000000000000000000000000000000000000000001c174000000000000000000000000000000000000000000000000000000000001c174100000000000000000000000000000000000000000000000000000000001c173100000000000000000000000000000000000000000000000000000000001c173200000000000000000000000000000000000000000000000000000000001c173300000000000000000000000000000000000000000000000000000000001c173400000000000000000000000000000000000000000000000000000000001c173500000000000000000000000000000000000000000000000000000000001c173600000000000000000000000000000000000000000000000000000000001c173700000000000000000000000000000000000000000000000000000000001c173800000000000000000000000000000000000000000000000000000000001c173900000000000000000000000000000000000000000000000000000000001c173a00000000000000000000000000000000000000000000000000000000001c173b00000000000000000000000000000000000000000000000000000000001c173c00000000000000000000000000000000000000000000000000000000001c173d00000000000000000000000000000000000000000000000000000000001c173e00000000000000000000000000000000000000000000000000000000001c173f00000000000000000000000000000000000000000000000000000000001c174000000000000000000000000000000000000000000000000000000000001c174100000000000000000000000000000000000000000000000000000000001c174200000000000000000000000000000000000000000000000000000000001c173200000000000000000000000000000000000000000000000000000000001c173300000000000000000000000000000000000000000000000000000000001c173400000000000000000000000000000000000000000000000000000000001c173500000000000000000000000000000000000000000000000000000000001c173600000000000000000000000000000000000000000000000000000000001c173700000000000000000000000000000000000000000000000000000000001c173800000000000000000000000000000000000000000000000000000000001c173900000000000000000000000000000000000000000000000000000000001c173a00000000000000000000000000000000000000000000000000000000001c173b00000000000000000000000000000000000000000000000000000000001c173c00000000000000000000000000000000000000000000000000000000001c173d00000000000000000000000000000000000000000000000000000000001c173e00000000000000000000000000000000000000000000000000000000001c173f00000000000000000000000000000000000000000000000000000000001c174000000000000000000000000000000000000000000000000000000000001c174100000000000000000000000000000000000000000000000000000000001c174200000000000000000000000000000000000000000000000000000000001c174300000000000000000000000000000000000000000000000000000000001c173300000000000000000000000000000000000000000000000000000000001c173400000000000000000000000000000000000000000000000000000000001c173500000000000000000000000000000000000000000000000000000000001c173600000000000000000000000000000000000000000000000000000000001c173700000000000000000000000000000000000000000000000000000000001c173800000000000000000000000000000000000000000000000000000000001c173900000000000000000000000000000000000000000000000000000000001c173a00000000000000000000000000000000000000000000000000000000001c173b00000000000000000000000000000000000000000000000000000000001c173c00000000000000000000000000000000000000000000000000000000001c173d00000000000000000000000000000000000000000000000000000000001c173e00000000000000000000000000000000000000000000000000000000001c173f00000000000000000000000000000000000000000000000000000000001c174000000000000000000000000000000000000000000000000000000000001c174100000000000000000000000000000000000000000000000000000000001c174200000000000000000000000000000000000000000000000000000000001c174300000000000000000000000000000000000000000000000000000000001c174400000000000000000000000000000000000000000000000000000000001c173400000000000000000000000000000000000000000000000000000000001c173500000000000000000000000000000000000000000000000000000000001c173600000000000000000000000000000000000000000000000000000000001c173700000000000000000000000000000000000000000000000000000000001c173800000000000000000000000000000000000000000000000000000000001c173900000000000000000000000000000000000000000000000000000000001c173a00000000000000000000000000000000000000000000000000000000001c173b00000000000000000000000000000000000000000000000000000000001c173c00000000000000000000000000000000000000000000000000000000001c173d00000000000000000000000000000000000000000000000000000000001c173e00000000000000000000000000000000000000000000000000000000001c173f00000000000000000000000000000000000000000000000000000000001c174000000000000000000000000000000000000000000000000000000000001c174100000000000000000000000000000000000000000000000000000000001c174200000000000000000000000000000000000000000000000000000000001c174300000000000000000000000000000000000000000000000000000000001c174400000000000000000000000000000000000000000000000000000000001c174500000000000000000000000000000000000000000000000000000000001c173500000000000000000000000000000000000000000000000000000000001c173600000000000000000000000000000000000000000000000000000000001c173700000000000000000000000000000000000000000000000000000000001c173800000000000000000000000000000000000000000000000000000000001c173900000000000000000000000000000000000000000000000000000000001c173a00000000000000000000000000000000000000000000000000000000001c173b00000000000000000000000000000000000000000000000000000000001c173c00000000000000000000000000000000000000000000000000000000001c173d00000000000000000000000000000000000000000000000000000000001c173e00000000000000000000000000000000000000000000000000000000001c173f00000000000000000000000000000000000000000000000000000000001c174000000000000000000000000000000000000000000000000000000000001c174100000000000000000000000000000000000000000000000000000000001c174200000000000000000000000000000000000000000000000000000000001c174300000000000000000000000000000000000000000000000000000000001c174400000000000000000000000000000000000000000000000000000000001c174500000000000000000000000000000000000000000000000000000000001c174600000000000000000000000000000000000000000000000000000000001c173600000000000000000000000000000000000000000000000000000000001c173700000000000000000000000000000000000000000000000000000000001c173800000000000000000000000000000000000000000000000000000000001c173900000000000000000000000000000000000000000000000000000000001c173a00000000000000000000000000000000000000000000000000000000001c173b00000000000000000000000000000000000000000000000000000000001c173c00000000000000000000000000000000000000000000000000000000001c173d00000000000000000000000000000000000000000000000000000000001c173e00000000000000000000000000000000000000000000000000000000001c173f00000000000000000000000000000000000000000000000000000000001c174000000000000000000000000000000000000000000000000000000000001c174100000000000000000000000000000000000000000000000000000000001c174200000000000000000000000000000000000000000000000000000000001c174300000000000000000000000000000000000000000000000000000000001c174400000000000000000000000000000000000000000000000000000000001c174500000000000000000000000000000000000000000000000000000000001c174600000000000000000000000000000000000000000000000000000000001c174700000000000000000000000000000000000000000000000000000000001c173700000000000000000000000000000000000000000000000000000000001c173800000000000000000000000000000000000000000000000000000000001c173900000000000000000000000000000000000000000000000000000000001c173a00000000000000000000000000000000000000000000000000000000001c173b00000000000000000000000000000000000000000000000000000000001c173c00000000000000000000000000000000000000000000000000000000001c173d00000000000000000000000000000000000000000000000000000000001c173e00000000000000000000000000000000000000000000000000000000001c173f00000000000000000000000000000000000000000000000000000000001c174000000000000000000000000000000000000000000000000000000000001c174100000000000000000000000000000000000000000000000000000000001c174200000000000000000000000000000000000000000000000000000000001c174300000000000000000000000000000000000000000000000000000000001c174400000000000000000000000000000000000000000000000000000000001c174500000000000000000000000000000000000000000000000000000000001c174600000000000000000000000000000000000000000000000000000000001c174700000000000000000000000000000000000000000000000000000000001c174800000000000000000000000000000000000000000000000000000000001c173800000000000000000000000000000000000000000000000000000000001c173900000000000000000000000000000000000000000000000000000000001c173a00000000000000000000000000000000000000000000000000000000001c173b00000000000000000000000000000000000000000000000000000000001c173c00000000000000000000000000000000000000000000000000000000001c173d00000000000000000000000000000000000000000000000000000000001c173e00000000000000000000000000000000000000000000000000000000001c173f00000000000000000000000000000000000000000000000000000000001c174000000000000000000000000000000000000000000000000000000000001c174100000000000000000000000000000000000000000000000000000000001c174200000000000000000000000000000000000000000000000000000000001c174300000000000000000000000000000000000000000000000000000000001c174400000000000000000000000000000000000000000000000000000000001c174500000000000000000000000000000000000000000000000000000000001c174600000000000000000000000000000000000000000000000000000000001c174700000000000000000000000000000000000000000000000000000000001c174800000000000000000000000000000000000000000000000000000000001c174900000000000000000000000000000000000000000000000000000000001c173900000000000000000000000000000000000000000000000000000000001c173a00000000000000000000000000000000000000000000000000000000001c173b00000000000000000000000000000000000000000000000000000000001c173c00000000000000000000000000000000000000000000000000000000001c173d00000000000000000000000000000000000000000000000000000000001c173e00000000000000000000000000000000000000000000000000000000001c173f00000000000000000000000000000000000000000000000000000000001c174000000000000000000000000000000000000000000000000000000000001c174100000000000000000000000000000000000000000000000000000000001c174200000000000000000000000000000000000000000000000000000000001c174300000000000000000000000000000000000000000000000000000000001c174400000000000000000000000000000000000000000000000000000000001c174500000000000000000000000000000000000000000000000000000000001c174600000000000000000000000000000000000000000000000000000000001c174700000000000000000000000000000000000000000000000000000000001c174800000000000000000000000000000000000000000000000000000000001c174900000000000000000000000000000000000000000000000000000000001c174a00000000000000000000000000000000000000000000000000000000001c173a00000000000000000000000000000000000000000000000000000000001c173b00000000000000000000000000000000000000000000000000000000001c173c00000000000000000000000000000000000000000000000000000000001c173d00000000000000000000000000000000000000000000000000000000001c173e00000000000000000000000000000000000000000000000000000000001c173f00000000000000000000000000000000000000000000000000000000001c174000000000000000000000000000000000000000000000000000000000001c174100000000000000000000000000000000000000000000000000000000001c174200000000000000000000000000000000000000000000000000000000001c174300000000000000000000000000000000000000000000000000000000001c174400000000000000000000000000000000000000000000000000000000001c174500000000000000000000000000000000000000000000000000000000001c174600000000000000000000000000000000000000000000000000000000001c174700000000000000000000000000000000000000000000000000000000001c174800000000000000000000000000000000000000000000000000000000001c174900000000000000000000000000000000000000000000000000000000001c174a00000000000000000000000000000000000000000000000000000000001c174b00000000000000000000000000000000000000000000000000000000001c173b00000000000000000000000000000000000000000000000000000000001c173c00000000000000000000000000000000000000000000000000000000001c173d00000000000000000000000000000000000000000000000000000000001c173e00000000000000000000000000000000000000000000000000000000001c173f00000000000000000000000000000000000000000000000000000000001c174000000000000000000000000000000000000000000000000000000000001c174100000000000000000000000000000000000000000000000000000000001c174200000000000000000000000000000000000000000000000000000000001c174300000000000000000000000000000000000000000000000000000000001c174400000000000000000000000000000000000000000000000000000000001c174500000000000000000000000000000000000000000000000000000000001c174600000000000000000000000000000000000000000000000000000000001c174700000000000000000000000000000000000000000000000000000000001c174800000000000000000000000000000000000000000000000000000000001c174900000000000000000000000000000000000000000000000000000000001c174a00000000000000000000000000000000000000000000000000000000001c174b00000000000000000000000000000000000000000000000000000000001c174c00000000000000000000000000000000000000000000000000000000001c173c00000000000000000000000000000000000000000000000000000000001c173d00000000000000000000000000000000000000000000000000000000001c173e00000000000000000000000000000000000000000000000000000000001c173f00000000000000000000000000000000000000000000000000000000001c174000000000000000000000000000000000000000000000000000000000001c174100000000000000000000000000000000000000000000000000000000001c174200000000000000000000000000000000000000000000000000000000001c174300000000000000000000000000000000000000000000000000000000001c174400000000000000000000000000000000000000000000000000000000001c174500000000000000000000000000000000000000000000000000000000001c174600000000000000000000000000000000000000000000000000000000001c174700000000000000000000000000000000000000000000000000000000001c174800000000000000000000000000000000000000000000000000000000001c174900000000000000000000000000000000000000000000000000000000001c174a00000000000000000000000000000000000000000000000000000000001c174b00000000000000000000000000000000000000000000000000000000001c174c00000000000000000000000000000000000000000000000000000000001c174d00000000000000000000000000000000000000000000000000000000001c173d00000000000000000000000000000000000000000000000000000000001c173e00000000000000000000000000000000000000000000000000000000001c173f00000000000000000000000000000000000000000000000000000000001c174000000000000000000000000000000000000000000000000000000000001c174100000000000000000000000000000000000000000000000000000000001c174200000000000000000000000000000000000000000000000000000000001c174300000000000000000000000000000000000000000000000000000000001c174400000000000000000000000000000000000000000000000000000000001c174500000000000000000000000000000000000000000000000000000000001c174600000000000000000000000000000000000000000000000000000000001c174700000000000000000000000000000000000000000000000000000000001c174800000000000000000000000000000000000000000000000000000000001c174900000000000000000000000000000000000000000000000000000000001c174a00000000000000000000000000000000000000000000000000000000001c174b00000000000000000000000000000000000000000000000000000000001c174c00000000000000000000000000000000000000000000000000000000001c174d00000000000000000000000000000000000000000000000000000000001c174e00000000000000000000000000000000000000000000000000000000001c173e00000000000000000000000000000000000000000000000000000000001c173f00000000000000000000000000000000000000000000000000000000001c174000000000000000000000000000000000000000000000000000000000001c174100000000000000000000000000000000000000000000000000000000001c174200000000000000000000000000000000000000000000000000000000001c174300000000000000000000000000000000000000000000000000000000001c174400000000000000000000000000000000000000000000000000000000001c174500000000000000000000000000000000000000000000000000000000001c174600000000000000000000000000000000000000000000000000000000001c174700000000000000000000000000000000000000000000000000000000001c174800000000000000000000000000000000000000000000000000000000001c174900000000000000000000000000000000000000000000000000000000001c174a00000000000000000000000000000000000000000000000000000000001c174b00000000000000000000000000000000000000000000000000000000001c174c00000000000000000000000000000000000000000000000000000000001c174d00000000000000000000000000000000000000000000000000000000001c174e00000000000000000000000000000000000000000000000000000000001c174f00000000000000000000000000000000000000000000000000000000001c173f00000000000000000000000000000000000000000000000000000000001c174000000000000000000000000000000000000000000000000000000000001c174100000000000000000000000000000000000000000000000000000000001c174200000000000000000000000000000000000000000000000000000000001c174300000000000000000000000000000000000000000000000000000000001c174400000000000000000000000000000000000000000000000000000000001c174500000000000000000000000000000000000000000000000000000000001c174600000000000000000000000000000000000000000000000000000000001c174700000000000000000000000000000000000000000000000000000000001c174800000000000000000000000000000000000000000000000000000000001c174900000000000000000000000000000000000000000000000000000000001c174a00000000000000000000000000000000000000000000000000000000001c174b00000000000000000000000000000000000000000000000000000000001c174c00000000000000000000000000000000000000000000000000000000001c174d00000000000000000000000000000000000000000000000000000000001c174e00000000000000000000000000000000000000000000000000000000001c174f00000000000000000000000000000000000000000000000000000000001c1750000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000201000000000000000000000000000000000000000000000000000000000000020100100000000000000000000000000000000000000000000000000000000002010020000000000000000000000000000000000000000000000000000000000201003000000000000000000000000000000000000000000000000000000000020100400000000000000000000000000000000000000000000000000000000002010050000000000000000000000000000000000000000000000000000000000201006000000000000000000000000000000000000000000000000000000000020100700000000000000000000000000000000000000000000000000000000002010080000000000000000000000000000000000000000000000000000000000201009000000000000000000000000000000000000000000000000000000000020100a000000000000000000000000000000000000000000000000000000000020100b000000000000000000000000000000000000000000000000000000000020100c000000000000000000000000000000000000000000000000000000000020100d000000000000000000000000000000000000000000000000000000000020100e000000000000000000000000000000000000000000000000000000000020100f0000000000000000000000000000000000000000000000000000000000201010000000000000000000000000000000000000000000000000000000000020101100000000000000000000000000000000000000000000000000000000002010120000000000000000000000000000000000000000000000000000000000201013000000000000000000000000000000000000000000000000000000000020101400000000000000000000000000000000000000000000000000000000002010150000000000000000000000000000000000000000000000000000000000201016000000000000000000000000000000000000000000000000000000000020101700000000000000000000000000000000000000000000000000000000002010180000000000000000000000000000000000000000000000000000000000201019000000000000000000000000000000000000000000000000000000000020101a000000000000000000000000000000000000000000000000000000000020101b000000000000000000000000000000000000000000000000000000000020101c000000000000000000000000000000000000000000000000000000000020101d000000000000000000000000000000000000000000000000000000000020101e000000000000000000000000000000000000000000000000000000000020101f0000000000000000000000000000000000000000000000000000000000201020000000000000000000000000000000000000000000000000000000000020102100000000000000000000000000000000000000000000000000000000002010220000000000000000000000000000000000000000000000000000000000201023000000000000000000000000000000000000000000000000000000000020102400000000000000000000000000000000000000000000000000000000002010250000000000000000000000000000000000000000000000000000000000201026000000000000000000000000000000000000000000000000000000000020102700000000000000000000000000000000000000000000000000000000002010280000000000000000000000000000000000000000000000000000000000201029000000000000000000000000000000000000000000000000000000000020102a000000000000000000000000000000000000000000000000000000000020102b000000000000000000000000000000000000000000000000000000000020102c000000000000000000000000000000000000000000000000000000000020102d000000000000000000000000000000000000000000000000000000000020102e000000000000000000000000000000000000000000000000000000000020102f0000000000000000000000000000000000000000000000000000000000201030000000000000000000000000000000000000000000000000000000000020103100000000000000000000000000000000000000000000000000000000002010320000000000000000000000000000000000000000000000000000000000201033000000000000000000000000000000000000000000000000000000000020103400000000000000000000000000000000000000000000000000000000002010350000000000000000000000000000000000000000000000000000000000201036000000000000000000000000000000000000000000000000000000000020103700000000000000000000000000000000000000000000000000000000002010380000000000000000000000000000000000000000000000000000000000201039000000000000000000000000000000000000000000000000000000000020103a000000000000000000000000000000000000000000000000000000000020103b000000000000000000000000000000000000000000000000000000000020103c000000000000000000000000000000000000000000000000000000000020103d000000000000000000000000000000000000000000000000000000000020103e000000000000000000000000000000000000000000000000000000000020103f4000000000000000000000000000000000000000000000000000000000002000010000000000000000000000000000000000000000000000000000000000201100000000000000000000000000000000000000000000000000000000000020110100000000000000000000000000000000000000000000000000000000002011020000000000000000000000000000000000000000000000000000000000201103000000000000000000000000000000000000000000000000000000000020110400000000000000000000000000000000000000000000000000000000002011050000000000000000000000000000000000000000000000000000000000201106000000000000000000000000000000000000000000000000000000000020110700000000000000000000000000000000000000000000000000000000002011080000000000000000000000000000000000000000000000000000000000201109000000000000000000000000000000000000000000000000000000000020110a000000000000000000000000000000000000000000000000000000000020110b000000000000000000000000000000000000000000000000000000000020110c000000000000000000000000000000000000000000000000000000000020110d000000000000000000000000000000000000000000000000000000000020110e000000000000000000000000000000000000000000000000000000000020110f0000000000000000000000000000000000000000000000000000000000201110000000000000000000000000000000000000000000000000000000000020111100000000000000000000000000000000000000000000000000000000002011120000000000000000000000000000000000000000000000000000000000201113000000000000000000000000000000000000000000000000000000000020111400000000000000000000000000000000000000000000000000000000002011150000000000000000000000000000000000000000000000000000000000201116000000000000000000000000000000000000000000000000000000000020111700000000000000000000000000000000000000000000000000000000002011180000000000000000000000000000000000000000000000000000000000201119000000000000000000000000000000000000000000000000000000000020111a000000000000000000000000000000000000000000000000000000000020111b000000000000000000000000000000000000000000000000000000000020111c000000000000000000000000000000000000000000000000000000000020111d000000000000000000000000000000000000000000000000000000000020111e000000000000000000000000000000000000000000000000000000000020111f0000000000000000000000000000000000000000000000000000000000201120000000000000000000000000000000000000000000000000000000000020112100000000000000000000000000000000000000000000000000000000002011220000000000000000000000000000000000000000000000000000000000201123000000000000000000000000000000000000000000000000000000000020112400000000000000000000000000000000000000000000000000000000002011250000000000000000000000000000000000000000000000000000000000201126000000000000000000000000000000000000000000000000000000000020112700000000000000000000000000000000000000000000000000000000002011280000000000000000000000000000000000000000000000000000000000201129000000000000000000000000000000000000000000000000000000000020112a000000000000000000000000000000000000000000000000000000000020112b000000000000000000000000000000000000000000000000000000000020112c000000000000000000000000000000000000000000000000000000000020112d000000000000000000000000000000000000000000000000000000000020112e000000000000000000000000000000000000000000000000000000000020112f0000000000000000000000000000000000000000000000000000000000201130000000000000000000000000000000000000000000000000000000000020113100000000000000000000000000000000000000000000000000000000002011320000000000000000000000000000000000000000000000000000000000201133000000000000000000000000000000000000000000000000000000000020113400000000000000000000000000000000000000000000000000000000002011350000000000000000000000000000000000000000000000000000000000201136000000000000000000000000000000000000000000000000000000000020113700000000000000000000000000000000000000000000000000000000002011380000000000000000000000000000000000000000000000000000000000201139000000000000000000000000000000000000000000000000000000000020113a000000000000000000000000000000000000000000000000000000000020113b000000000000000000000000000000000000000000000000000000000020113c000000000000000000000000000000000000000000000000000000000020113d000000000000000000000000000000000000000000000000000000000020113e0800e9805e8a4faa87fc419af08a6d956f18976c46ea694bbd4cf6946e6d02033200e0925a6b172b4b01bb76eb1d3f7dd2ced118bca70d223a6d61afa1b75915ae00383590492d2f99a0283d1de57015b4b6b0759a8023af2c68fb4929dee2f303007ed57100dd77e2b6405f780503ef61b7b53e13f344b6e6a6eff3e3c13de0d0001ab1b0c348c46184dbc86ff79f248e7da1b09d3f9c6a986e98fe45389f060d0023d134bc68d7efa25e255001069827dc0bee766c08c988d6300071ed27fe6c0031cbb780b07f632cbaf767dc80608cc0a8e1d1df3ecd6f5d8bc0ca6703e4f4002c7dc9e731fc5f6456b2a70b4e636ac17d5e0cd36d3a591116a9e124f735863f0000000000000000000000000000000000000000000000000000000000202000000000000000000000000000000000000000000000000000000000000020200a0000000000000000000000000000000000000000000000000000000000202001000000000000000000000000000000000000000000000000000000000020200b0000000000000000000000000000000000000000000000000000000000202002000000000000000000000000000000000000000000000000000000000020200c0000000000000000000000000000000000000000000000000000000000202003000000000000000000000000000000000000000000000000000000000020200d0000000000000000000000000000000000000000000000000000000000202004000000000000000000000000000000000000000000000000000000000020200e0000000000000000000000000000000000000000000000000000000000202005000000000000000000000000000000000000000000000000000000000020200f00000000000000000000000000000000000000000000000000000000002020060000000000000000000000000000000000000000000000000000000000202010000000000000000000000000000000000000000000000000000000000020200700000000000000000000000000000000000000000000000000000000002020110000000000000000000000000000000000000000000000000000000000202008000000000000000000000000000000000000000000000000000000000020201200000000000000000000000000000000000000000000000000000000002020090000000000000000000000000000000000000000000000000000000000202013000000000000000000000000000000000000000000000000000000000020200a0000000000000000000000000000000000000000000000000000000000202014000000000000000000000000000000000000000000000000000000000020200b0000000000000000000000000000000000000000000000000000000000202015000000000000000000000000000000000000000000000000000000000020200c0000000000000000000000000000000000000000000000000000000000202016000000000000000000000000000000000000000000000000000000000020200d0000000000000000000000000000000000000000000000000000000000202017000000000000000000000000000000000000000000000000000000000020200e0000000000000000000000000000000000000000000000000000000000202018000000000000000000000000000000000000000000000000000000000020200f00000000000000000000000000000000000000000000000000000000002020190000000000000000000000000000000000000000000000000000000000202010000000000000000000000000000000000000000000000000000000000020201a0000000000000000000000000000000000000000000000000000000000202011000000000000000000000000000000000000000000000000000000000020201b0000000000000000000000000000000000000000000000000000000000202012000000000000000000000000000000000000000000000000000000000020201c0000000000000000000000000000000000000000000000000000000000202013000000000000000000000000000000000000000000000000000000000020201d0000000000000000000000000000000000000000000000000000000000202014000000000000000000000000000000000000000000000000000000000020201e0000000000000000000000000000000000000000000000000000000000202015000000000000000000000000000000000000000000000000000000000020201f00000000000000000000000000000000000000000000000000000000002020160000000000000000000000000000000000000000000000000000000000202020000000000000000000000000000000000000000000000000000000000020201700000000000000000000000000000000000000000000000000000000002020210000000000000000000000000000000000000000000000000000000000202018000000000000000000000000000000000000000000000000000000000020202200000000000000000000000000000000000000000000000000000000002020190000000000000000000000000000000000000000000000000000000000202023000000000000000000000000000000000000000000000000000000000020201a0000000000000000000000000000000000000000000000000000000000202024000000000000000000000000000000000000000000000000000000000020201b0000000000000000000000000000000000000000000000000000000000202025000000000000000000000000000000000000000000000000000000000020201c0000000000000000000000000000000000000000000000000000000000202026000000000000000000000000000000000000000000000000000000000020201d0000000000000000000000000000000000000000000000000000000000202027000000000000000000000000000000000000000000000000000000000020201e0000000000000000000000000000000000000000000000000000000000202028000000000000000000000000000000000000000000000000000000000020201f00000000000000000000000000000000000000000000000000000000002020290000000000000000000000000000000000000000000000000000000000202020000000000000000000000000000000000000000000000000000000000020202a0000000000000000000000000000000000000000000000000000000000202021000000000000000000000000000000000000000000000000000000000020202b0000000000000000000000000000000000000000000000000000000000202022000000000000000000000000000000000000000000000000000000000020202c0000000000000000000000000000000000000000000000000000000000202023000000000000000000000000000000000000000000000000000000000020202d0000000000000000000000000000000000000000000000000000000000202024000000000000000000000000000000000000000000000000000000000020202e0000000000000000000000000000000000000000000000000000000000202025000000000000000000000000000000000000000000000000000000000020202f00000000000000000000000000000000000000000000000000000000002020260000000000000000000000000000000000000000000000000000000000202030000000000000000000000000000000000000000000000000000000000020202700000000000000000000000000000000000000000000000000000000002020310000000000000000000000000000000000000000000000000000000000202028000000000000000000000000000000000000000000000000000000000020203200000000000000000000000000000000000000000000000000000000002020290000000000000000000000000000000000000000000000000000000000202033000000000000000000000000000000000000000000000000000000000020202a0000000000000000000000000000000000000000000000000000000000202034000000000000000000000000000000000000000000000000000000000020202b0000000000000000000000000000000000000000000000000000000000202035000000000000000000000000000000000000000000000000000000000020202c0000000000000000000000000000000000000000000000000000000000202036000000000000000000000000000000000000000000000000000000000020202d0000000000000000000000000000000000000000000000000000000000202037000000000000000000000000000000000000000000000000000000000020202e0000000000000000000000000000000000000000000000000000000000202038000000000000000000000000000000000000000000000000000000000020202f00000000000000000000000000000000000000000000000000000000002020390000000000000000000000000000000000000000000000000000000000202030000000000000000000000000000000000000000000000000000000000020203a0000000000000000000000000000000000000000000000000000000000202031000000000000000000000000000000000000000000000000000000000020203b0000000000000000000000000000000000000000000000000000000000202032000000000000000000000000000000000000000000000000000000000020203c0000000000000000000000000000000000000000000000000000000000202033000000000000000000000000000000000000000000000000000000000020203d0000000000000000000000000000000000000000000000000000000000202034000000000000000000000000000000000000000000000000000000000020203e0000000000000000000000000000000000000000000000000000000000202035000000000000000000000000000000000000000000000000000000000020203f00000000000000000000000000000000000000000000000000000000002020360000000000000000000000000000000000000000000000000000000000202040000000000000000000000000000000000000000000000000000000000020203700000000000000000000000000000000000000000000000000000000002020410000000000000000000000000000000000000000000000000000000000202038000000000000000000000000000000000000000000000000000000000020204200000000000000000000000000000000000000000000000000000000002020390000000000000000000000000000000000000000000000000000000000202043000000000000000000000000000000000000000000000000000000000020203a0000000000000000000000000000000000000000000000000000000000202044000000000000000000000000000000000000000000000000000000000020203b0000000000000000000000000000000000000000000000000000000000202045000000000000000000000000000000000000000000000000000000000020203c0000000000000000000000000000000000000000000000000000000000202046000000000000000000000000000000000000000000000000000000000020203d0000000000000000000000000000000000000000000000000000000000202047000000000000000000000000000000000000000000000000000000000020203e0000000000000000000000000000000000000000000000000000000000202048400000000000000000000000000000000000000000000000000000000000201700000000000000000000000000000000000000000000000000000000000020170100000000000000000000000000000000000000000000000000000000002017020000000000000000000000000000000000000000000000000000000000201703000000000000000000000000000000000000000000000000000000000020170400000000000000000000000000000000000000000000000000000000002017050000000000000000000000000000000000000000000000000000000000201706000000000000000000000000000000000000000000000000000000000020170700000000000000000000000000000000000000000000000000000000002017080000000000000000000000000000000000000000000000000000000000201709000000000000000000000000000000000000000000000000000000000020170a000000000000000000000000000000000000000000000000000000000020170b000000000000000000000000000000000000000000000000000000000020170c000000000000000000000000000000000000000000000000000000000020170d000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f00000000000000000000000000000000000000000000000000000000002017100000000000000000000000000000000000000000000000000000000000201711000000000000000000000000000000000000000000000000000000000020170100000000000000000000000000000000000000000000000000000000002017020000000000000000000000000000000000000000000000000000000000201703000000000000000000000000000000000000000000000000000000000020170400000000000000000000000000000000000000000000000000000000002017050000000000000000000000000000000000000000000000000000000000201706000000000000000000000000000000000000000000000000000000000020170700000000000000000000000000000000000000000000000000000000002017080000000000000000000000000000000000000000000000000000000000201709000000000000000000000000000000000000000000000000000000000020170a000000000000000000000000000000000000000000000000000000000020170b000000000000000000000000000000000000000000000000000000000020170c000000000000000000000000000000000000000000000000000000000020170d000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f00000000000000000000000000000000000000000000000000000000002017100000000000000000000000000000000000000000000000000000000000201711000000000000000000000000000000000000000000000000000000000020171200000000000000000000000000000000000000000000000000000000002017020000000000000000000000000000000000000000000000000000000000201703000000000000000000000000000000000000000000000000000000000020170400000000000000000000000000000000000000000000000000000000002017050000000000000000000000000000000000000000000000000000000000201706000000000000000000000000000000000000000000000000000000000020170700000000000000000000000000000000000000000000000000000000002017080000000000000000000000000000000000000000000000000000000000201709000000000000000000000000000000000000000000000000000000000020170a000000000000000000000000000000000000000000000000000000000020170b000000000000000000000000000000000000000000000000000000000020170c000000000000000000000000000000000000000000000000000000000020170d000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f00000000000000000000000000000000000000000000000000000000002017100000000000000000000000000000000000000000000000000000000000201711000000000000000000000000000000000000000000000000000000000020171200000000000000000000000000000000000000000000000000000000002017130000000000000000000000000000000000000000000000000000000000201703000000000000000000000000000000000000000000000000000000000020170400000000000000000000000000000000000000000000000000000000002017050000000000000000000000000000000000000000000000000000000000201706000000000000000000000000000000000000000000000000000000000020170700000000000000000000000000000000000000000000000000000000002017080000000000000000000000000000000000000000000000000000000000201709000000000000000000000000000000000000000000000000000000000020170a000000000000000000000000000000000000000000000000000000000020170b000000000000000000000000000000000000000000000000000000000020170c000000000000000000000000000000000000000000000000000000000020170d000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f00000000000000000000000000000000000000000000000000000000002017100000000000000000000000000000000000000000000000000000000000201711000000000000000000000000000000000000000000000000000000000020171200000000000000000000000000000000000000000000000000000000002017130000000000000000000000000000000000000000000000000000000000201714000000000000000000000000000000000000000000000000000000000020170400000000000000000000000000000000000000000000000000000000002017050000000000000000000000000000000000000000000000000000000000201706000000000000000000000000000000000000000000000000000000000020170700000000000000000000000000000000000000000000000000000000002017080000000000000000000000000000000000000000000000000000000000201709000000000000000000000000000000000000000000000000000000000020170a000000000000000000000000000000000000000000000000000000000020170b000000000000000000000000000000000000000000000000000000000020170c000000000000000000000000000000000000000000000000000000000020170d000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f00000000000000000000000000000000000000000000000000000000002017100000000000000000000000000000000000000000000000000000000000201711000000000000000000000000000000000000000000000000000000000020171200000000000000000000000000000000000000000000000000000000002017130000000000000000000000000000000000000000000000000000000000201714000000000000000000000000000000000000000000000000000000000020171500000000000000000000000000000000000000000000000000000000002017050000000000000000000000000000000000000000000000000000000000201706000000000000000000000000000000000000000000000000000000000020170700000000000000000000000000000000000000000000000000000000002017080000000000000000000000000000000000000000000000000000000000201709000000000000000000000000000000000000000000000000000000000020170a000000000000000000000000000000000000000000000000000000000020170b000000000000000000000000000000000000000000000000000000000020170c000000000000000000000000000000000000000000000000000000000020170d000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f00000000000000000000000000000000000000000000000000000000002017100000000000000000000000000000000000000000000000000000000000201711000000000000000000000000000000000000000000000000000000000020171200000000000000000000000000000000000000000000000000000000002017130000000000000000000000000000000000000000000000000000000000201714000000000000000000000000000000000000000000000000000000000020171500000000000000000000000000000000000000000000000000000000002017160000000000000000000000000000000000000000000000000000000000201706000000000000000000000000000000000000000000000000000000000020170700000000000000000000000000000000000000000000000000000000002017080000000000000000000000000000000000000000000000000000000000201709000000000000000000000000000000000000000000000000000000000020170a000000000000000000000000000000000000000000000000000000000020170b000000000000000000000000000000000000000000000000000000000020170c000000000000000000000000000000000000000000000000000000000020170d000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f00000000000000000000000000000000000000000000000000000000002017100000000000000000000000000000000000000000000000000000000000201711000000000000000000000000000000000000000000000000000000000020171200000000000000000000000000000000000000000000000000000000002017130000000000000000000000000000000000000000000000000000000000201714000000000000000000000000000000000000000000000000000000000020171500000000000000000000000000000000000000000000000000000000002017160000000000000000000000000000000000000000000000000000000000201717000000000000000000000000000000000000000000000000000000000020170700000000000000000000000000000000000000000000000000000000002017080000000000000000000000000000000000000000000000000000000000201709000000000000000000000000000000000000000000000000000000000020170a000000000000000000000000000000000000000000000000000000000020170b000000000000000000000000000000000000000000000000000000000020170c000000000000000000000000000000000000000000000000000000000020170d000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f00000000000000000000000000000000000000000000000000000000002017100000000000000000000000000000000000000000000000000000000000201711000000000000000000000000000000000000000000000000000000000020171200000000000000000000000000000000000000000000000000000000002017130000000000000000000000000000000000000000000000000000000000201714000000000000000000000000000000000000000000000000000000000020171500000000000000000000000000000000000000000000000000000000002017160000000000000000000000000000000000000000000000000000000000201717000000000000000000000000000000000000000000000000000000000020171800000000000000000000000000000000000000000000000000000000002017080000000000000000000000000000000000000000000000000000000000201709000000000000000000000000000000000000000000000000000000000020170a000000000000000000000000000000000000000000000000000000000020170b000000000000000000000000000000000000000000000000000000000020170c000000000000000000000000000000000000000000000000000000000020170d000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f00000000000000000000000000000000000000000000000000000000002017100000000000000000000000000000000000000000000000000000000000201711000000000000000000000000000000000000000000000000000000000020171200000000000000000000000000000000000000000000000000000000002017130000000000000000000000000000000000000000000000000000000000201714000000000000000000000000000000000000000000000000000000000020171500000000000000000000000000000000000000000000000000000000002017160000000000000000000000000000000000000000000000000000000000201717000000000000000000000000000000000000000000000000000000000020171800000000000000000000000000000000000000000000000000000000002017190000000000000000000000000000000000000000000000000000000000201709000000000000000000000000000000000000000000000000000000000020170a000000000000000000000000000000000000000000000000000000000020170b000000000000000000000000000000000000000000000000000000000020170c000000000000000000000000000000000000000000000000000000000020170d000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f0000000000000000000000000000000000000000000000000000000000201710000000000000000000000000000000000000000000000000000000000020171100000000000000000000000000000000000000000000000000000000002017120000000000000000000000000000000000000000000000000000000000201713000000000000000000000000000000000000000000000000000000000020171400000000000000000000000000000000000000000000000000000000002017150000000000000000000000000000000000000000000000000000000000201716000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020170a000000000000000000000000000000000000000000000000000000000020170b000000000000000000000000000000000000000000000000000000000020170c000000000000000000000000000000000000000000000000000000000020170d000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f0000000000000000000000000000000000000000000000000000000000201710000000000000000000000000000000000000000000000000000000000020171100000000000000000000000000000000000000000000000000000000002017120000000000000000000000000000000000000000000000000000000000201713000000000000000000000000000000000000000000000000000000000020171400000000000000000000000000000000000000000000000000000000002017150000000000000000000000000000000000000000000000000000000000201716000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020170b000000000000000000000000000000000000000000000000000000000020170c000000000000000000000000000000000000000000000000000000000020170d000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f0000000000000000000000000000000000000000000000000000000000201710000000000000000000000000000000000000000000000000000000000020171100000000000000000000000000000000000000000000000000000000002017120000000000000000000000000000000000000000000000000000000000201713000000000000000000000000000000000000000000000000000000000020171400000000000000000000000000000000000000000000000000000000002017150000000000000000000000000000000000000000000000000000000000201716000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020170c000000000000000000000000000000000000000000000000000000000020170d000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f0000000000000000000000000000000000000000000000000000000000201710000000000000000000000000000000000000000000000000000000000020171100000000000000000000000000000000000000000000000000000000002017120000000000000000000000000000000000000000000000000000000000201713000000000000000000000000000000000000000000000000000000000020171400000000000000000000000000000000000000000000000000000000002017150000000000000000000000000000000000000000000000000000000000201716000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020170d000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f0000000000000000000000000000000000000000000000000000000000201710000000000000000000000000000000000000000000000000000000000020171100000000000000000000000000000000000000000000000000000000002017120000000000000000000000000000000000000000000000000000000000201713000000000000000000000000000000000000000000000000000000000020171400000000000000000000000000000000000000000000000000000000002017150000000000000000000000000000000000000000000000000000000000201716000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020170e000000000000000000000000000000000000000000000000000000000020170f0000000000000000000000000000000000000000000000000000000000201710000000000000000000000000000000000000000000000000000000000020171100000000000000000000000000000000000000000000000000000000002017120000000000000000000000000000000000000000000000000000000000201713000000000000000000000000000000000000000000000000000000000020171400000000000000000000000000000000000000000000000000000000002017150000000000000000000000000000000000000000000000000000000000201716000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f000000000000000000000000000000000000000000000000000000000020170f0000000000000000000000000000000000000000000000000000000000201710000000000000000000000000000000000000000000000000000000000020171100000000000000000000000000000000000000000000000000000000002017120000000000000000000000000000000000000000000000000000000000201713000000000000000000000000000000000000000000000000000000000020171400000000000000000000000000000000000000000000000000000000002017150000000000000000000000000000000000000000000000000000000000201716000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f00000000000000000000000000000000000000000000000000000000002017200000000000000000000000000000000000000000000000000000000000201710000000000000000000000000000000000000000000000000000000000020171100000000000000000000000000000000000000000000000000000000002017120000000000000000000000000000000000000000000000000000000000201713000000000000000000000000000000000000000000000000000000000020171400000000000000000000000000000000000000000000000000000000002017150000000000000000000000000000000000000000000000000000000000201716000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f00000000000000000000000000000000000000000000000000000000002017200000000000000000000000000000000000000000000000000000000000201721000000000000000000000000000000000000000000000000000000000020171100000000000000000000000000000000000000000000000000000000002017120000000000000000000000000000000000000000000000000000000000201713000000000000000000000000000000000000000000000000000000000020171400000000000000000000000000000000000000000000000000000000002017150000000000000000000000000000000000000000000000000000000000201716000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f00000000000000000000000000000000000000000000000000000000002017200000000000000000000000000000000000000000000000000000000000201721000000000000000000000000000000000000000000000000000000000020172200000000000000000000000000000000000000000000000000000000002017120000000000000000000000000000000000000000000000000000000000201713000000000000000000000000000000000000000000000000000000000020171400000000000000000000000000000000000000000000000000000000002017150000000000000000000000000000000000000000000000000000000000201716000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f00000000000000000000000000000000000000000000000000000000002017200000000000000000000000000000000000000000000000000000000000201721000000000000000000000000000000000000000000000000000000000020172200000000000000000000000000000000000000000000000000000000002017230000000000000000000000000000000000000000000000000000000000201713000000000000000000000000000000000000000000000000000000000020171400000000000000000000000000000000000000000000000000000000002017150000000000000000000000000000000000000000000000000000000000201716000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f00000000000000000000000000000000000000000000000000000000002017200000000000000000000000000000000000000000000000000000000000201721000000000000000000000000000000000000000000000000000000000020172200000000000000000000000000000000000000000000000000000000002017230000000000000000000000000000000000000000000000000000000000201724000000000000000000000000000000000000000000000000000000000020171400000000000000000000000000000000000000000000000000000000002017150000000000000000000000000000000000000000000000000000000000201716000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f00000000000000000000000000000000000000000000000000000000002017200000000000000000000000000000000000000000000000000000000000201721000000000000000000000000000000000000000000000000000000000020172200000000000000000000000000000000000000000000000000000000002017230000000000000000000000000000000000000000000000000000000000201724000000000000000000000000000000000000000000000000000000000020172500000000000000000000000000000000000000000000000000000000002017150000000000000000000000000000000000000000000000000000000000201716000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f00000000000000000000000000000000000000000000000000000000002017200000000000000000000000000000000000000000000000000000000000201721000000000000000000000000000000000000000000000000000000000020172200000000000000000000000000000000000000000000000000000000002017230000000000000000000000000000000000000000000000000000000000201724000000000000000000000000000000000000000000000000000000000020172500000000000000000000000000000000000000000000000000000000002017260000000000000000000000000000000000000000000000000000000000201716000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f00000000000000000000000000000000000000000000000000000000002017200000000000000000000000000000000000000000000000000000000000201721000000000000000000000000000000000000000000000000000000000020172200000000000000000000000000000000000000000000000000000000002017230000000000000000000000000000000000000000000000000000000000201724000000000000000000000000000000000000000000000000000000000020172500000000000000000000000000000000000000000000000000000000002017260000000000000000000000000000000000000000000000000000000000201727000000000000000000000000000000000000000000000000000000000020171700000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f00000000000000000000000000000000000000000000000000000000002017200000000000000000000000000000000000000000000000000000000000201721000000000000000000000000000000000000000000000000000000000020172200000000000000000000000000000000000000000000000000000000002017230000000000000000000000000000000000000000000000000000000000201724000000000000000000000000000000000000000000000000000000000020172500000000000000000000000000000000000000000000000000000000002017260000000000000000000000000000000000000000000000000000000000201727000000000000000000000000000000000000000000000000000000000020172800000000000000000000000000000000000000000000000000000000002017180000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f00000000000000000000000000000000000000000000000000000000002017200000000000000000000000000000000000000000000000000000000000201721000000000000000000000000000000000000000000000000000000000020172200000000000000000000000000000000000000000000000000000000002017230000000000000000000000000000000000000000000000000000000000201724000000000000000000000000000000000000000000000000000000000020172500000000000000000000000000000000000000000000000000000000002017260000000000000000000000000000000000000000000000000000000000201727000000000000000000000000000000000000000000000000000000000020172800000000000000000000000000000000000000000000000000000000002017290000000000000000000000000000000000000000000000000000000000201719000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f0000000000000000000000000000000000000000000000000000000000201720000000000000000000000000000000000000000000000000000000000020172100000000000000000000000000000000000000000000000000000000002017220000000000000000000000000000000000000000000000000000000000201723000000000000000000000000000000000000000000000000000000000020172400000000000000000000000000000000000000000000000000000000002017250000000000000000000000000000000000000000000000000000000000201726000000000000000000000000000000000000000000000000000000000020172700000000000000000000000000000000000000000000000000000000002017280000000000000000000000000000000000000000000000000000000000201729000000000000000000000000000000000000000000000000000000000020172a000000000000000000000000000000000000000000000000000000000020171a000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f0000000000000000000000000000000000000000000000000000000000201720000000000000000000000000000000000000000000000000000000000020172100000000000000000000000000000000000000000000000000000000002017220000000000000000000000000000000000000000000000000000000000201723000000000000000000000000000000000000000000000000000000000020172400000000000000000000000000000000000000000000000000000000002017250000000000000000000000000000000000000000000000000000000000201726000000000000000000000000000000000000000000000000000000000020172700000000000000000000000000000000000000000000000000000000002017280000000000000000000000000000000000000000000000000000000000201729000000000000000000000000000000000000000000000000000000000020172a000000000000000000000000000000000000000000000000000000000020172b000000000000000000000000000000000000000000000000000000000020171b000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f0000000000000000000000000000000000000000000000000000000000201720000000000000000000000000000000000000000000000000000000000020172100000000000000000000000000000000000000000000000000000000002017220000000000000000000000000000000000000000000000000000000000201723000000000000000000000000000000000000000000000000000000000020172400000000000000000000000000000000000000000000000000000000002017250000000000000000000000000000000000000000000000000000000000201726000000000000000000000000000000000000000000000000000000000020172700000000000000000000000000000000000000000000000000000000002017280000000000000000000000000000000000000000000000000000000000201729000000000000000000000000000000000000000000000000000000000020172a000000000000000000000000000000000000000000000000000000000020172b000000000000000000000000000000000000000000000000000000000020172c000000000000000000000000000000000000000000000000000000000020171c000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f0000000000000000000000000000000000000000000000000000000000201720000000000000000000000000000000000000000000000000000000000020172100000000000000000000000000000000000000000000000000000000002017220000000000000000000000000000000000000000000000000000000000201723000000000000000000000000000000000000000000000000000000000020172400000000000000000000000000000000000000000000000000000000002017250000000000000000000000000000000000000000000000000000000000201726000000000000000000000000000000000000000000000000000000000020172700000000000000000000000000000000000000000000000000000000002017280000000000000000000000000000000000000000000000000000000000201729000000000000000000000000000000000000000000000000000000000020172a000000000000000000000000000000000000000000000000000000000020172b000000000000000000000000000000000000000000000000000000000020172c000000000000000000000000000000000000000000000000000000000020172d000000000000000000000000000000000000000000000000000000000020171d000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f0000000000000000000000000000000000000000000000000000000000201720000000000000000000000000000000000000000000000000000000000020172100000000000000000000000000000000000000000000000000000000002017220000000000000000000000000000000000000000000000000000000000201723000000000000000000000000000000000000000000000000000000000020172400000000000000000000000000000000000000000000000000000000002017250000000000000000000000000000000000000000000000000000000000201726000000000000000000000000000000000000000000000000000000000020172700000000000000000000000000000000000000000000000000000000002017280000000000000000000000000000000000000000000000000000000000201729000000000000000000000000000000000000000000000000000000000020172a000000000000000000000000000000000000000000000000000000000020172b000000000000000000000000000000000000000000000000000000000020172c000000000000000000000000000000000000000000000000000000000020172d000000000000000000000000000000000000000000000000000000000020172e000000000000000000000000000000000000000000000000000000000020171e000000000000000000000000000000000000000000000000000000000020171f0000000000000000000000000000000000000000000000000000000000201720000000000000000000000000000000000000000000000000000000000020172100000000000000000000000000000000000000000000000000000000002017220000000000000000000000000000000000000000000000000000000000201723000000000000000000000000000000000000000000000000000000000020172400000000000000000000000000000000000000000000000000000000002017250000000000000000000000000000000000000000000000000000000000201726000000000000000000000000000000000000000000000000000000000020172700000000000000000000000000000000000000000000000000000000002017280000000000000000000000000000000000000000000000000000000000201729000000000000000000000000000000000000000000000000000000000020172a000000000000000000000000000000000000000000000000000000000020172b000000000000000000000000000000000000000000000000000000000020172c000000000000000000000000000000000000000000000000000000000020172d000000000000000000000000000000000000000000000000000000000020172e000000000000000000000000000000000000000000000000000000000020172f000000000000000000000000000000000000000000000000000000000020171f0000000000000000000000000000000000000000000000000000000000201720000000000000000000000000000000000000000000000000000000000020172100000000000000000000000000000000000000000000000000000000002017220000000000000000000000000000000000000000000000000000000000201723000000000000000000000000000000000000000000000000000000000020172400000000000000000000000000000000000000000000000000000000002017250000000000000000000000000000000000000000000000000000000000201726000000000000000000000000000000000000000000000000000000000020172700000000000000000000000000000000000000000000000000000000002017280000000000000000000000000000000000000000000000000000000000201729000000000000000000000000000000000000000000000000000000000020172a000000000000000000000000000000000000000000000000000000000020172b000000000000000000000000000000000000000000000000000000000020172c000000000000000000000000000000000000000000000000000000000020172d000000000000000000000000000000000000000000000000000000000020172e000000000000000000000000000000000000000000000000000000000020172f00000000000000000000000000000000000000000000000000000000002017300000000000000000000000000000000000000000000000000000000000201720000000000000000000000000000000000000000000000000000000000020172100000000000000000000000000000000000000000000000000000000002017220000000000000000000000000000000000000000000000000000000000201723000000000000000000000000000000000000000000000000000000000020172400000000000000000000000000000000000000000000000000000000002017250000000000000000000000000000000000000000000000000000000000201726000000000000000000000000000000000000000000000000000000000020172700000000000000000000000000000000000000000000000000000000002017280000000000000000000000000000000000000000000000000000000000201729000000000000000000000000000000000000000000000000000000000020172a000000000000000000000000000000000000000000000000000000000020172b000000000000000000000000000000000000000000000000000000000020172c000000000000000000000000000000000000000000000000000000000020172d000000000000000000000000000000000000000000000000000000000020172e000000000000000000000000000000000000000000000000000000000020172f00000000000000000000000000000000000000000000000000000000002017300000000000000000000000000000000000000000000000000000000000201731000000000000000000000000000000000000000000000000000000000020172100000000000000000000000000000000000000000000000000000000002017220000000000000000000000000000000000000000000000000000000000201723000000000000000000000000000000000000000000000000000000000020172400000000000000000000000000000000000000000000000000000000002017250000000000000000000000000000000000000000000000000000000000201726000000000000000000000000000000000000000000000000000000000020172700000000000000000000000000000000000000000000000000000000002017280000000000000000000000000000000000000000000000000000000000201729000000000000000000000000000000000000000000000000000000000020172a000000000000000000000000000000000000000000000000000000000020172b000000000000000000000000000000000000000000000000000000000020172c000000000000000000000000000000000000000000000000000000000020172d000000000000000000000000000000000000000000000000000000000020172e000000000000000000000000000000000000000000000000000000000020172f00000000000000000000000000000000000000000000000000000000002017300000000000000000000000000000000000000000000000000000000000201731000000000000000000000000000000000000000000000000000000000020173200000000000000000000000000000000000000000000000000000000002017220000000000000000000000000000000000000000000000000000000000201723000000000000000000000000000000000000000000000000000000000020172400000000000000000000000000000000000000000000000000000000002017250000000000000000000000000000000000000000000000000000000000201726000000000000000000000000000000000000000000000000000000000020172700000000000000000000000000000000000000000000000000000000002017280000000000000000000000000000000000000000000000000000000000201729000000000000000000000000000000000000000000000000000000000020172a000000000000000000000000000000000000000000000000000000000020172b000000000000000000000000000000000000000000000000000000000020172c000000000000000000000000000000000000000000000000000000000020172d000000000000000000000000000000000000000000000000000000000020172e000000000000000000000000000000000000000000000000000000000020172f00000000000000000000000000000000000000000000000000000000002017300000000000000000000000000000000000000000000000000000000000201731000000000000000000000000000000000000000000000000000000000020173200000000000000000000000000000000000000000000000000000000002017330000000000000000000000000000000000000000000000000000000000201723000000000000000000000000000000000000000000000000000000000020172400000000000000000000000000000000000000000000000000000000002017250000000000000000000000000000000000000000000000000000000000201726000000000000000000000000000000000000000000000000000000000020172700000000000000000000000000000000000000000000000000000000002017280000000000000000000000000000000000000000000000000000000000201729000000000000000000000000000000000000000000000000000000000020172a000000000000000000000000000000000000000000000000000000000020172b000000000000000000000000000000000000000000000000000000000020172c000000000000000000000000000000000000000000000000000000000020172d000000000000000000000000000000000000000000000000000000000020172e000000000000000000000000000000000000000000000000000000000020172f00000000000000000000000000000000000000000000000000000000002017300000000000000000000000000000000000000000000000000000000000201731000000000000000000000000000000000000000000000000000000000020173200000000000000000000000000000000000000000000000000000000002017330000000000000000000000000000000000000000000000000000000000201734000000000000000000000000000000000000000000000000000000000020172400000000000000000000000000000000000000000000000000000000002017250000000000000000000000000000000000000000000000000000000000201726000000000000000000000000000000000000000000000000000000000020172700000000000000000000000000000000000000000000000000000000002017280000000000000000000000000000000000000000000000000000000000201729000000000000000000000000000000000000000000000000000000000020172a000000000000000000000000000000000000000000000000000000000020172b000000000000000000000000000000000000000000000000000000000020172c000000000000000000000000000000000000000000000000000000000020172d000000000000000000000000000000000000000000000000000000000020172e000000000000000000000000000000000000000000000000000000000020172f00000000000000000000000000000000000000000000000000000000002017300000000000000000000000000000000000000000000000000000000000201731000000000000000000000000000000000000000000000000000000000020173200000000000000000000000000000000000000000000000000000000002017330000000000000000000000000000000000000000000000000000000000201734000000000000000000000000000000000000000000000000000000000020173500000000000000000000000000000000000000000000000000000000002017250000000000000000000000000000000000000000000000000000000000201726000000000000000000000000000000000000000000000000000000000020172700000000000000000000000000000000000000000000000000000000002017280000000000000000000000000000000000000000000000000000000000201729000000000000000000000000000000000000000000000000000000000020172a000000000000000000000000000000000000000000000000000000000020172b000000000000000000000000000000000000000000000000000000000020172c000000000000000000000000000000000000000000000000000000000020172d000000000000000000000000000000000000000000000000000000000020172e000000000000000000000000000000000000000000000000000000000020172f00000000000000000000000000000000000000000000000000000000002017300000000000000000000000000000000000000000000000000000000000201731000000000000000000000000000000000000000000000000000000000020173200000000000000000000000000000000000000000000000000000000002017330000000000000000000000000000000000000000000000000000000000201734000000000000000000000000000000000000000000000000000000000020173500000000000000000000000000000000000000000000000000000000002017360000000000000000000000000000000000000000000000000000000000201726000000000000000000000000000000000000000000000000000000000020172700000000000000000000000000000000000000000000000000000000002017280000000000000000000000000000000000000000000000000000000000201729000000000000000000000000000000000000000000000000000000000020172a000000000000000000000000000000000000000000000000000000000020172b000000000000000000000000000000000000000000000000000000000020172c000000000000000000000000000000000000000000000000000000000020172d000000000000000000000000000000000000000000000000000000000020172e000000000000000000000000000000000000000000000000000000000020172f00000000000000000000000000000000000000000000000000000000002017300000000000000000000000000000000000000000000000000000000000201731000000000000000000000000000000000000000000000000000000000020173200000000000000000000000000000000000000000000000000000000002017330000000000000000000000000000000000000000000000000000000000201734000000000000000000000000000000000000000000000000000000000020173500000000000000000000000000000000000000000000000000000000002017360000000000000000000000000000000000000000000000000000000000201737000000000000000000000000000000000000000000000000000000000020172700000000000000000000000000000000000000000000000000000000002017280000000000000000000000000000000000000000000000000000000000201729000000000000000000000000000000000000000000000000000000000020172a000000000000000000000000000000000000000000000000000000000020172b000000000000000000000000000000000000000000000000000000000020172c000000000000000000000000000000000000000000000000000000000020172d000000000000000000000000000000000000000000000000000000000020172e000000000000000000000000000000000000000000000000000000000020172f00000000000000000000000000000000000000000000000000000000002017300000000000000000000000000000000000000000000000000000000000201731000000000000000000000000000000000000000000000000000000000020173200000000000000000000000000000000000000000000000000000000002017330000000000000000000000000000000000000000000000000000000000201734000000000000000000000000000000000000000000000000000000000020173500000000000000000000000000000000000000000000000000000000002017360000000000000000000000000000000000000000000000000000000000201737000000000000000000000000000000000000000000000000000000000020173800000000000000000000000000000000000000000000000000000000002017280000000000000000000000000000000000000000000000000000000000201729000000000000000000000000000000000000000000000000000000000020172a000000000000000000000000000000000000000000000000000000000020172b000000000000000000000000000000000000000000000000000000000020172c000000000000000000000000000000000000000000000000000000000020172d000000000000000000000000000000000000000000000000000000000020172e000000000000000000000000000000000000000000000000000000000020172f00000000000000000000000000000000000000000000000000000000002017300000000000000000000000000000000000000000000000000000000000201731000000000000000000000000000000000000000000000000000000000020173200000000000000000000000000000000000000000000000000000000002017330000000000000000000000000000000000000000000000000000000000201734000000000000000000000000000000000000000000000000000000000020173500000000000000000000000000000000000000000000000000000000002017360000000000000000000000000000000000000000000000000000000000201737000000000000000000000000000000000000000000000000000000000020173800000000000000000000000000000000000000000000000000000000002017390000000000000000000000000000000000000000000000000000000000201729000000000000000000000000000000000000000000000000000000000020172a000000000000000000000000000000000000000000000000000000000020172b000000000000000000000000000000000000000000000000000000000020172c000000000000000000000000000000000000000000000000000000000020172d000000000000000000000000000000000000000000000000000000000020172e000000000000000000000000000000000000000000000000000000000020172f0000000000000000000000000000000000000000000000000000000000201730000000000000000000000000000000000000000000000000000000000020173100000000000000000000000000000000000000000000000000000000002017320000000000000000000000000000000000000000000000000000000000201733000000000000000000000000000000000000000000000000000000000020173400000000000000000000000000000000000000000000000000000000002017350000000000000000000000000000000000000000000000000000000000201736000000000000000000000000000000000000000000000000000000000020173700000000000000000000000000000000000000000000000000000000002017380000000000000000000000000000000000000000000000000000000000201739000000000000000000000000000000000000000000000000000000000020173a000000000000000000000000000000000000000000000000000000000020172a000000000000000000000000000000000000000000000000000000000020172b000000000000000000000000000000000000000000000000000000000020172c000000000000000000000000000000000000000000000000000000000020172d000000000000000000000000000000000000000000000000000000000020172e000000000000000000000000000000000000000000000000000000000020172f0000000000000000000000000000000000000000000000000000000000201730000000000000000000000000000000000000000000000000000000000020173100000000000000000000000000000000000000000000000000000000002017320000000000000000000000000000000000000000000000000000000000201733000000000000000000000000000000000000000000000000000000000020173400000000000000000000000000000000000000000000000000000000002017350000000000000000000000000000000000000000000000000000000000201736000000000000000000000000000000000000000000000000000000000020173700000000000000000000000000000000000000000000000000000000002017380000000000000000000000000000000000000000000000000000000000201739000000000000000000000000000000000000000000000000000000000020173a000000000000000000000000000000000000000000000000000000000020173b000000000000000000000000000000000000000000000000000000000020172b000000000000000000000000000000000000000000000000000000000020172c000000000000000000000000000000000000000000000000000000000020172d000000000000000000000000000000000000000000000000000000000020172e000000000000000000000000000000000000000000000000000000000020172f0000000000000000000000000000000000000000000000000000000000201730000000000000000000000000000000000000000000000000000000000020173100000000000000000000000000000000000000000000000000000000002017320000000000000000000000000000000000000000000000000000000000201733000000000000000000000000000000000000000000000000000000000020173400000000000000000000000000000000000000000000000000000000002017350000000000000000000000000000000000000000000000000000000000201736000000000000000000000000000000000000000000000000000000000020173700000000000000000000000000000000000000000000000000000000002017380000000000000000000000000000000000000000000000000000000000201739000000000000000000000000000000000000000000000000000000000020173a000000000000000000000000000000000000000000000000000000000020173b000000000000000000000000000000000000000000000000000000000020173c000000000000000000000000000000000000000000000000000000000020172c000000000000000000000000000000000000000000000000000000000020172d000000000000000000000000000000000000000000000000000000000020172e000000000000000000000000000000000000000000000000000000000020172f0000000000000000000000000000000000000000000000000000000000201730000000000000000000000000000000000000000000000000000000000020173100000000000000000000000000000000000000000000000000000000002017320000000000000000000000000000000000000000000000000000000000201733000000000000000000000000000000000000000000000000000000000020173400000000000000000000000000000000000000000000000000000000002017350000000000000000000000000000000000000000000000000000000000201736000000000000000000000000000000000000000000000000000000000020173700000000000000000000000000000000000000000000000000000000002017380000000000000000000000000000000000000000000000000000000000201739000000000000000000000000000000000000000000000000000000000020173a000000000000000000000000000000000000000000000000000000000020173b000000000000000000000000000000000000000000000000000000000020173c000000000000000000000000000000000000000000000000000000000020173d000000000000000000000000000000000000000000000000000000000020172d000000000000000000000000000000000000000000000000000000000020172e000000000000000000000000000000000000000000000000000000000020172f0000000000000000000000000000000000000000000000000000000000201730000000000000000000000000000000000000000000000000000000000020173100000000000000000000000000000000000000000000000000000000002017320000000000000000000000000000000000000000000000000000000000201733000000000000000000000000000000000000000000000000000000000020173400000000000000000000000000000000000000000000000000000000002017350000000000000000000000000000000000000000000000000000000000201736000000000000000000000000000000000000000000000000000000000020173700000000000000000000000000000000000000000000000000000000002017380000000000000000000000000000000000000000000000000000000000201739000000000000000000000000000000000000000000000000000000000020173a000000000000000000000000000000000000000000000000000000000020173b000000000000000000000000000000000000000000000000000000000020173c000000000000000000000000000000000000000000000000000000000020173d000000000000000000000000000000000000000000000000000000000020173e000000000000000000000000000000000000000000000000000000000020172e000000000000000000000000000000000000000000000000000000000020172f0000000000000000000000000000000000000000000000000000000000201730000000000000000000000000000000000000000000000000000000000020173100000000000000000000000000000000000000000000000000000000002017320000000000000000000000000000000000000000000000000000000000201733000000000000000000000000000000000000000000000000000000000020173400000000000000000000000000000000000000000000000000000000002017350000000000000000000000000000000000000000000000000000000000201736000000000000000000000000000000000000000000000000000000000020173700000000000000000000000000000000000000000000000000000000002017380000000000000000000000000000000000000000000000000000000000201739000000000000000000000000000000000000000000000000000000000020173a000000000000000000000000000000000000000000000000000000000020173b000000000000000000000000000000000000000000000000000000000020173c000000000000000000000000000000000000000000000000000000000020173d000000000000000000000000000000000000000000000000000000000020173e000000000000000000000000000000000000000000000000000000000020173f000000000000000000000000000000000000000000000000000000000020172f0000000000000000000000000000000000000000000000000000000000201730000000000000000000000000000000000000000000000000000000000020173100000000000000000000000000000000000000000000000000000000002017320000000000000000000000000000000000000000000000000000000000201733000000000000000000000000000000000000000000000000000000000020173400000000000000000000000000000000000000000000000000000000002017350000000000000000000000000000000000000000000000000000000000201736000000000000000000000000000000000000000000000000000000000020173700000000000000000000000000000000000000000000000000000000002017380000000000000000000000000000000000000000000000000000000000201739000000000000000000000000000000000000000000000000000000000020173a000000000000000000000000000000000000000000000000000000000020173b000000000000000000000000000000000000000000000000000000000020173c000000000000000000000000000000000000000000000000000000000020173d000000000000000000000000000000000000000000000000000000000020173e000000000000000000000000000000000000000000000000000000000020173f00000000000000000000000000000000000000000000000000000000002017400000000000000000000000000000000000000000000000000000000000201730000000000000000000000000000000000000000000000000000000000020173100000000000000000000000000000000000000000000000000000000002017320000000000000000000000000000000000000000000000000000000000201733000000000000000000000000000000000000000000000000000000000020173400000000000000000000000000000000000000000000000000000000002017350000000000000000000000000000000000000000000000000000000000201736000000000000000000000000000000000000000000000000000000000020173700000000000000000000000000000000000000000000000000000000002017380000000000000000000000000000000000000000000000000000000000201739000000000000000000000000000000000000000000000000000000000020173a000000000000000000000000000000000000000000000000000000000020173b000000000000000000000000000000000000000000000000000000000020173c000000000000000000000000000000000000000000000000000000000020173d000000000000000000000000000000000000000000000000000000000020173e000000000000000000000000000000000000000000000000000000000020173f00000000000000000000000000000000000000000000000000000000002017400000000000000000000000000000000000000000000000000000000000201741000000000000000000000000000000000000000000000000000000000020173100000000000000000000000000000000000000000000000000000000002017320000000000000000000000000000000000000000000000000000000000201733000000000000000000000000000000000000000000000000000000000020173400000000000000000000000000000000000000000000000000000000002017350000000000000000000000000000000000000000000000000000000000201736000000000000000000000000000000000000000000000000000000000020173700000000000000000000000000000000000000000000000000000000002017380000000000000000000000000000000000000000000000000000000000201739000000000000000000000000000000000000000000000000000000000020173a000000000000000000000000000000000000000000000000000000000020173b000000000000000000000000000000000000000000000000000000000020173c000000000000000000000000000000000000000000000000000000000020173d000000000000000000000000000000000000000000000000000000000020173e000000000000000000000000000000000000000000000000000000000020173f00000000000000000000000000000000000000000000000000000000002017400000000000000000000000000000000000000000000000000000000000201741000000000000000000000000000000000000000000000000000000000020174200000000000000000000000000000000000000000000000000000000002017320000000000000000000000000000000000000000000000000000000000201733000000000000000000000000000000000000000000000000000000000020173400000000000000000000000000000000000000000000000000000000002017350000000000000000000000000000000000000000000000000000000000201736000000000000000000000000000000000000000000000000000000000020173700000000000000000000000000000000000000000000000000000000002017380000000000000000000000000000000000000000000000000000000000201739000000000000000000000000000000000000000000000000000000000020173a000000000000000000000000000000000000000000000000000000000020173b000000000000000000000000000000000000000000000000000000000020173c000000000000000000000000000000000000000000000000000000000020173d000000000000000000000000000000000000000000000000000000000020173e000000000000000000000000000000000000000000000000000000000020173f00000000000000000000000000000000000000000000000000000000002017400000000000000000000000000000000000000000000000000000000000201741000000000000000000000000000000000000000000000000000000000020174200000000000000000000000000000000000000000000000000000000002017430000000000000000000000000000000000000000000000000000000000201733000000000000000000000000000000000000000000000000000000000020173400000000000000000000000000000000000000000000000000000000002017350000000000000000000000000000000000000000000000000000000000201736000000000000000000000000000000000000000000000000000000000020173700000000000000000000000000000000000000000000000000000000002017380000000000000000000000000000000000000000000000000000000000201739000000000000000000000000000000000000000000000000000000000020173a000000000000000000000000000000000000000000000000000000000020173b000000000000000000000000000000000000000000000000000000000020173c000000000000000000000000000000000000000000000000000000000020173d000000000000000000000000000000000000000000000000000000000020173e000000000000000000000000000000000000000000000000000000000020173f00000000000000000000000000000000000000000000000000000000002017400000000000000000000000000000000000000000000000000000000000201741000000000000000000000000000000000000000000000000000000000020174200000000000000000000000000000000000000000000000000000000002017430000000000000000000000000000000000000000000000000000000000201744000000000000000000000000000000000000000000000000000000000020173400000000000000000000000000000000000000000000000000000000002017350000000000000000000000000000000000000000000000000000000000201736000000000000000000000000000000000000000000000000000000000020173700000000000000000000000000000000000000000000000000000000002017380000000000000000000000000000000000000000000000000000000000201739000000000000000000000000000000000000000000000000000000000020173a000000000000000000000000000000000000000000000000000000000020173b000000000000000000000000000000000000000000000000000000000020173c000000000000000000000000000000000000000000000000000000000020173d000000000000000000000000000000000000000000000000000000000020173e000000000000000000000000000000000000000000000000000000000020173f00000000000000000000000000000000000000000000000000000000002017400000000000000000000000000000000000000000000000000000000000201741000000000000000000000000000000000000000000000000000000000020174200000000000000000000000000000000000000000000000000000000002017430000000000000000000000000000000000000000000000000000000000201744000000000000000000000000000000000000000000000000000000000020174500000000000000000000000000000000000000000000000000000000002017350000000000000000000000000000000000000000000000000000000000201736000000000000000000000000000000000000000000000000000000000020173700000000000000000000000000000000000000000000000000000000002017380000000000000000000000000000000000000000000000000000000000201739000000000000000000000000000000000000000000000000000000000020173a000000000000000000000000000000000000000000000000000000000020173b000000000000000000000000000000000000000000000000000000000020173c000000000000000000000000000000000000000000000000000000000020173d000000000000000000000000000000000000000000000000000000000020173e000000000000000000000000000000000000000000000000000000000020173f00000000000000000000000000000000000000000000000000000000002017400000000000000000000000000000000000000000000000000000000000201741000000000000000000000000000000000000000000000000000000000020174200000000000000000000000000000000000000000000000000000000002017430000000000000000000000000000000000000000000000000000000000201744000000000000000000000000000000000000000000000000000000000020174500000000000000000000000000000000000000000000000000000000002017460000000000000000000000000000000000000000000000000000000000201736000000000000000000000000000000000000000000000000000000000020173700000000000000000000000000000000000000000000000000000000002017380000000000000000000000000000000000000000000000000000000000201739000000000000000000000000000000000000000000000000000000000020173a000000000000000000000000000000000000000000000000000000000020173b000000000000000000000000000000000000000000000000000000000020173c000000000000000000000000000000000000000000000000000000000020173d000000000000000000000000000000000000000000000000000000000020173e000000000000000000000000000000000000000000000000000000000020173f00000000000000000000000000000000000000000000000000000000002017400000000000000000000000000000000000000000000000000000000000201741000000000000000000000000000000000000000000000000000000000020174200000000000000000000000000000000000000000000000000000000002017430000000000000000000000000000000000000000000000000000000000201744000000000000000000000000000000000000000000000000000000000020174500000000000000000000000000000000000000000000000000000000002017460000000000000000000000000000000000000000000000000000000000201747000000000000000000000000000000000000000000000000000000000020173700000000000000000000000000000000000000000000000000000000002017380000000000000000000000000000000000000000000000000000000000201739000000000000000000000000000000000000000000000000000000000020173a000000000000000000000000000000000000000000000000000000000020173b000000000000000000000000000000000000000000000000000000000020173c000000000000000000000000000000000000000000000000000000000020173d000000000000000000000000000000000000000000000000000000000020173e000000000000000000000000000000000000000000000000000000000020173f00000000000000000000000000000000000000000000000000000000002017400000000000000000000000000000000000000000000000000000000000201741000000000000000000000000000000000000000000000000000000000020174200000000000000000000000000000000000000000000000000000000002017430000000000000000000000000000000000000000000000000000000000201744000000000000000000000000000000000000000000000000000000000020174500000000000000000000000000000000000000000000000000000000002017460000000000000000000000000000000000000000000000000000000000201747000000000000000000000000000000000000000000000000000000000020174800000000000000000000000000000000000000000000000000000000002017380000000000000000000000000000000000000000000000000000000000201739000000000000000000000000000000000000000000000000000000000020173a000000000000000000000000000000000000000000000000000000000020173b000000000000000000000000000000000000000000000000000000000020173c000000000000000000000000000000000000000000000000000000000020173d000000000000000000000000000000000000000000000000000000000020173e000000000000000000000000000000000000000000000000000000000020173f00000000000000000000000000000000000000000000000000000000002017400000000000000000000000000000000000000000000000000000000000201741000000000000000000000000000000000000000000000000000000000020174200000000000000000000000000000000000000000000000000000000002017430000000000000000000000000000000000000000000000000000000000201744000000000000000000000000000000000000000000000000000000000020174500000000000000000000000000000000000000000000000000000000002017460000000000000000000000000000000000000000000000000000000000201747000000000000000000000000000000000000000000000000000000000020174800000000000000000000000000000000000000000000000000000000002017490000000000000000000000000000000000000000000000000000000000201739000000000000000000000000000000000000000000000000000000000020173a000000000000000000000000000000000000000000000000000000000020173b000000000000000000000000000000000000000000000000000000000020173c000000000000000000000000000000000000000000000000000000000020173d000000000000000000000000000000000000000000000000000000000020173e000000000000000000000000000000000000000000000000000000000020173f0000000000000000000000000000000000000000000000000000000000201740000000000000000000000000000000000000000000000000000000000020174100000000000000000000000000000000000000000000000000000000002017420000000000000000000000000000000000000000000000000000000000201743000000000000000000000000000000000000000000000000000000000020174400000000000000000000000000000000000000000000000000000000002017450000000000000000000000000000000000000000000000000000000000201746000000000000000000000000000000000000000000000000000000000020174700000000000000000000000000000000000000000000000000000000002017480000000000000000000000000000000000000000000000000000000000201749000000000000000000000000000000000000000000000000000000000020174a000000000000000000000000000000000000000000000000000000000020173a000000000000000000000000000000000000000000000000000000000020173b000000000000000000000000000000000000000000000000000000000020173c000000000000000000000000000000000000000000000000000000000020173d000000000000000000000000000000000000000000000000000000000020173e000000000000000000000000000000000000000000000000000000000020173f0000000000000000000000000000000000000000000000000000000000201740000000000000000000000000000000000000000000000000000000000020174100000000000000000000000000000000000000000000000000000000002017420000000000000000000000000000000000000000000000000000000000201743000000000000000000000000000000000000000000000000000000000020174400000000000000000000000000000000000000000000000000000000002017450000000000000000000000000000000000000000000000000000000000201746000000000000000000000000000000000000000000000000000000000020174700000000000000000000000000000000000000000000000000000000002017480000000000000000000000000000000000000000000000000000000000201749000000000000000000000000000000000000000000000000000000000020174a000000000000000000000000000000000000000000000000000000000020174b000000000000000000000000000000000000000000000000000000000020173b000000000000000000000000000000000000000000000000000000000020173c000000000000000000000000000000000000000000000000000000000020173d000000000000000000000000000000000000000000000000000000000020173e000000000000000000000000000000000000000000000000000000000020173f0000000000000000000000000000000000000000000000000000000000201740000000000000000000000000000000000000000000000000000000000020174100000000000000000000000000000000000000000000000000000000002017420000000000000000000000000000000000000000000000000000000000201743000000000000000000000000000000000000000000000000000000000020174400000000000000000000000000000000000000000000000000000000002017450000000000000000000000000000000000000000000000000000000000201746000000000000000000000000000000000000000000000000000000000020174700000000000000000000000000000000000000000000000000000000002017480000000000000000000000000000000000000000000000000000000000201749000000000000000000000000000000000000000000000000000000000020174a000000000000000000000000000000000000000000000000000000000020174b000000000000000000000000000000000000000000000000000000000020174c000000000000000000000000000000000000000000000000000000000020173c000000000000000000000000000000000000000000000000000000000020173d000000000000000000000000000000000000000000000000000000000020173e000000000000000000000000000000000000000000000000000000000020173f0000000000000000000000000000000000000000000000000000000000201740000000000000000000000000000000000000000000000000000000000020174100000000000000000000000000000000000000000000000000000000002017420000000000000000000000000000000000000000000000000000000000201743000000000000000000000000000000000000000000000000000000000020174400000000000000000000000000000000000000000000000000000000002017450000000000000000000000000000000000000000000000000000000000201746000000000000000000000000000000000000000000000000000000000020174700000000000000000000000000000000000000000000000000000000002017480000000000000000000000000000000000000000000000000000000000201749000000000000000000000000000000000000000000000000000000000020174a000000000000000000000000000000000000000000000000000000000020174b000000000000000000000000000000000000000000000000000000000020174c000000000000000000000000000000000000000000000000000000000020174d000000000000000000000000000000000000000000000000000000000020173d000000000000000000000000000000000000000000000000000000000020173e000000000000000000000000000000000000000000000000000000000020173f0000000000000000000000000000000000000000000000000000000000201740000000000000000000000000000000000000000000000000000000000020174100000000000000000000000000000000000000000000000000000000002017420000000000000000000000000000000000000000000000000000000000201743000000000000000000000000000000000000000000000000000000000020174400000000000000000000000000000000000000000000000000000000002017450000000000000000000000000000000000000000000000000000000000201746000000000000000000000000000000000000000000000000000000000020174700000000000000000000000000000000000000000000000000000000002017480000000000000000000000000000000000000000000000000000000000201749000000000000000000000000000000000000000000000000000000000020174a000000000000000000000000000000000000000000000000000000000020174b000000000000000000000000000000000000000000000000000000000020174c000000000000000000000000000000000000000000000000000000000020174d000000000000000000000000000000000000000000000000000000000020174e000000000000000000000000000000000000000000000000000000000020173e000000000000000000000000000000000000000000000000000000000020173f0000000000000000000000000000000000000000000000000000000000201740000000000000000000000000000000000000000000000000000000000020174100000000000000000000000000000000000000000000000000000000002017420000000000000000000000000000000000000000000000000000000000201743000000000000000000000000000000000000000000000000000000000020174400000000000000000000000000000000000000000000000000000000002017450000000000000000000000000000000000000000000000000000000000201746000000000000000000000000000000000000000000000000000000000020174700000000000000000000000000000000000000000000000000000000002017480000000000000000000000000000000000000000000000000000000000201749000000000000000000000000000000000000000000000000000000000020174a000000000000000000000000000000000000000000000000000000000020174b000000000000000000000000000000000000000000000000000000000020174c000000000000000000000000000000000000000000000000000000000020174d000000000000000000000000000000000000000000000000000000000020174e000000000000000000000000000000000000000000000000000000000020174f000000000000000000000000000000000000000000000000000000000020173f0000000000000000000000000000000000000000000000000000000000201740000000000000000000000000000000000000000000000000000000000020174100000000000000000000000000000000000000000000000000000000002017420000000000000000000000000000000000000000000000000000000000201743000000000000000000000000000000000000000000000000000000000020174400000000000000000000000000000000000000000000000000000000002017450000000000000000000000000000000000000000000000000000000000201746000000000000000000000000000000000000000000000000000000000020174700000000000000000000000000000000000000000000000000000000002017480000000000000000000000000000000000000000000000000000000000201749000000000000000000000000000000000000000000000000000000000020174a000000000000000000000000000000000000000000000000000000000020174b000000000000000000000000000000000000000000000000000000000020174c000000000000000000000000000000000000000000000000000000000020174d000000000000000000000000000000000000000000000000000000000020174e000000000000000000000000000000000000000000000000000000000020174f0000000000000000000000000000000000000000000000000000000000201750000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "txsEffectsHash": "0x0099776e98800f70450a8e9810387d186700c7c1a85bf86347ba8032dd028edb", "decodedHeader": { "contentCommitment": { "inHash": "0x00e1371045bd7d2c3e1f19cba5f536f0e82042ba4bc257d4ba19c146215e8242", "outHash": "0x00a5c37986316b1f5f2df53fa9ddf4965f539e872f5e1374f28d225540faca26", "numTxs": 4, - "txsEffectsHash": "0x00e0afd1e2cddfe35e364bde6047d93fec56b54e7b925edc28b31546b645822d" + "txsEffectsHash": "0x0099776e98800f70450a8e9810387d186700c7c1a85bf86347ba8032dd028edb" }, "globalVariables": { "blockNumber": 2, "slotNumber": "0x0000000000000000000000000000000000000000000000000000000000000023", "chainId": 31337, - "timestamp": 1732579254, + "timestamp": 1732721879, "version": 1, - "coinbase": "0x7bf63a9118e60cc630c4faa654223f715d4bd20e", - "feeRecipient": "0x2f2bacf41d88061f8a9e9234dfb8f6cdf5287e15eeeb4a6af5b0691d846bad5d", + "coinbase": "0xa2339f6422bf5c06403c4c1f6fb825374381084e", + "feeRecipient": "0x247bc3f73704c8273a70221a140b44e69ecf4c55822a83d360f35f82c17b099e", "gasFees": { "feePerDaGas": 0, - "feePerL2Gas": 54154341830 + "feePerL2Gas": 54153697630 } }, "totalFees": "0x0000000000000000000000000000000000000000000000000000000000000000", "totalManaUsed": "0x0000000000000000000000000000000000000000000000000000000000000000", "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x0dd5f1f4c97e09c3d85323d27343341b245c49c5e7032c43c8b7c70d8b79629a" + "root": "0x28449b938250ecc926d7bd4c05f4b84ae07dfe7e90a62abf27b7d241bcd6de23" }, "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": "0x28449b938250ecc926d7bd4c05f4b84ae07dfe7e90a62abf27b7d241bcd6de230000000200000000000000000000000000000000000000000000000000000000000000040099776e98800f70450a8e9810387d186700c7c1a85bf86347ba8032dd028edb00e1371045bd7d2c3e1f19cba5f536f0e82042ba4bc257d4ba19c146215e824200a5c37986316b1f5f2df53fa9ddf4965f539e872f5e1374f28d225540faca26026efb6c2a517de2448119d0f1255757265dbec7cdd2952df929ede666e10944000000202494d2575971bca59a28ddc774d19136f4a294951ab67258c7e9c2d8f980592400000200137a2b2aa3dc64677f9670d964242d8fbf9fbabaa6b05e2c910eb0cb0f7cc3be000002800c5783f9fe3a18bb5abd12daca67d280f6b5dfef250b7433dc059ce0d868b319000002780000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000230000000000000000000000000000000000000000000000000000000067473cd7a2339f6422bf5c06403c4c1f6fb825374381084e247bc3f73704c8273a70221a140b44e69ecf4c55822a83d360f35f82c17b099e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c9bcfd95e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x00362a2cc5aaf7cfad99ca404d04d0b2286c08b75e1529612d1a95724de25aad", "numTxs": 4 } } \ No newline at end of file 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/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..783b40d1444 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 = 64; 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/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/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..65b119342e7 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, 64], "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, 64] ] } diff --git a/noir-projects/noir-protocol-circuits/scripts/generate_variants.js b/noir-projects/noir-protocol-circuits/scripts/generate_variants.js index 6625333516f..d288e21de49 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, 64], }; 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..a8d4a67b491 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(`"0014a1509239adce426ae94248ef0db28299cd8694dfb0b515498b508d794eb8"`); }); }); 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..6a1f65cb715 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 = 64; 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 = 1476; 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 = 2084; +export const PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 2898; +export const PRIVATE_TO_PUBLIC_ACCUMULATED_DATA_LENGTH = 1476; 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 = 2997; +export const KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1532; 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 = 36864; 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_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/ethereum/src/test/start_anvil.ts b/yarn-project/ethereum/src/test/start_anvil.ts index b8c287681b3..b487ede2181 100644 --- a/yarn-project/ethereum/src/test/start_anvil.ts +++ b/yarn-project/ethereum/src/test/start_anvil.ts @@ -22,6 +22,7 @@ export async function startAnvil(l1BlockTime?: number): Promise<{ anvil: Anvil; anvilBinary, port: ethereumHostPort, blockTime: l1BlockTime, + gasLimit: 60_000_000n, }); await anvil.start(); return anvil; 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/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