{"file_path":"contracts/state-transition/verifiers/EraVerifierPlonk.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.28;\n\nimport {IVerifier} from \"../chain-interfaces/IVerifier.sol\";\n\n/* solhint-disable max-line-length */\n/// @author Matter Labs\n/// @notice Modified version of the Permutations over Lagrange-bases for Oecumenical Noninteractive arguments of\n/// Knowledge (PLONK) verifier.\n/// Modifications have been made to optimize the proof system for ZK chain circuits.\n/// @dev Contract was generated from a verification key with a hash of 0xbaaa46d644f7034d609eea327e818bd9a93a3c0fdd60e887d233da8a35c4f8ae\n/// @dev It uses a custom memory layout inside the inline assembly block. Each reserved memory cell is declared in the\n/// constants below.\n/// @dev For a better understanding of the verifier algorithm please refer to the following papers:\n/// * Original Plonk Article: https://eprint.iacr.org/2019/953.pdf\n/// * Original LookUp Article: https://eprint.iacr.org/2020/315.pdf\n/// * Plonk for ZKsync v1.1: https://github.com/matter-labs/solidity_plonk_verifier/raw/recursive/bellman_vk_codegen_recursive/RecursivePlonkUnrolledForEthereum.pdf\n/// The notation used in the code is the same as in the papers.\n/* solhint-enable max-line-length */\ncontract EraVerifierPlonk is IVerifier {\n    /*//////////////////////////////////////////////////////////////\n                             Verification keys\n    //////////////////////////////////////////////////////////////*/\n\n    // Memory slots from 0x000 to 0x200 are reserved for intermediate computations and call to precompiles.\n\n    uint256 internal constant VK_GATE_SETUP_0_X_SLOT = 0x200 + 0x000;\n    uint256 internal constant VK_GATE_SETUP_0_Y_SLOT = 0x200 + 0x020;\n    uint256 internal constant VK_GATE_SETUP_1_X_SLOT = 0x200 + 0x040;\n    uint256 internal constant VK_GATE_SETUP_1_Y_SLOT = 0x200 + 0x060;\n    uint256 internal constant VK_GATE_SETUP_2_X_SLOT = 0x200 + 0x080;\n    uint256 internal constant VK_GATE_SETUP_2_Y_SLOT = 0x200 + 0x0a0;\n    uint256 internal constant VK_GATE_SETUP_3_X_SLOT = 0x200 + 0x0c0;\n    uint256 internal constant VK_GATE_SETUP_3_Y_SLOT = 0x200 + 0x0e0;\n    uint256 internal constant VK_GATE_SETUP_4_X_SLOT = 0x200 + 0x100;\n    uint256 internal constant VK_GATE_SETUP_4_Y_SLOT = 0x200 + 0x120;\n    uint256 internal constant VK_GATE_SETUP_5_X_SLOT = 0x200 + 0x140;\n    uint256 internal constant VK_GATE_SETUP_5_Y_SLOT = 0x200 + 0x160;\n    uint256 internal constant VK_GATE_SETUP_6_X_SLOT = 0x200 + 0x180;\n    uint256 internal constant VK_GATE_SETUP_6_Y_SLOT = 0x200 + 0x1a0;\n    uint256 internal constant VK_GATE_SETUP_7_X_SLOT = 0x200 + 0x1c0;\n    uint256 internal constant VK_GATE_SETUP_7_Y_SLOT = 0x200 + 0x1e0;\n\n    uint256 internal constant VK_GATE_SELECTORS_0_X_SLOT = 0x200 + 0x200;\n    uint256 internal constant VK_GATE_SELECTORS_0_Y_SLOT = 0x200 + 0x220;\n    uint256 internal constant VK_GATE_SELECTORS_1_X_SLOT = 0x200 + 0x240;\n    uint256 internal constant VK_GATE_SELECTORS_1_Y_SLOT = 0x200 + 0x260;\n\n    uint256 internal constant VK_PERMUTATION_0_X_SLOT = 0x200 + 0x280;\n    uint256 internal constant VK_PERMUTATION_0_Y_SLOT = 0x200 + 0x2a0;\n    uint256 internal constant VK_PERMUTATION_1_X_SLOT = 0x200 + 0x2c0;\n    uint256 internal constant VK_PERMUTATION_1_Y_SLOT = 0x200 + 0x2e0;\n    uint256 internal constant VK_PERMUTATION_2_X_SLOT = 0x200 + 0x300;\n    uint256 internal constant VK_PERMUTATION_2_Y_SLOT = 0x200 + 0x320;\n    uint256 internal constant VK_PERMUTATION_3_X_SLOT = 0x200 + 0x340;\n    uint256 internal constant VK_PERMUTATION_3_Y_SLOT = 0x200 + 0x360;\n\n    uint256 internal constant VK_LOOKUP_SELECTOR_X_SLOT = 0x200 + 0x380;\n    uint256 internal constant VK_LOOKUP_SELECTOR_Y_SLOT = 0x200 + 0x3a0;\n\n    uint256 internal constant VK_LOOKUP_TABLE_0_X_SLOT = 0x200 + 0x3c0;\n    uint256 internal constant VK_LOOKUP_TABLE_0_Y_SLOT = 0x200 + 0x3e0;\n    uint256 internal constant VK_LOOKUP_TABLE_1_X_SLOT = 0x200 + 0x400;\n    uint256 internal constant VK_LOOKUP_TABLE_1_Y_SLOT = 0x200 + 0x420;\n    uint256 internal constant VK_LOOKUP_TABLE_2_X_SLOT = 0x200 + 0x440;\n    uint256 internal constant VK_LOOKUP_TABLE_2_Y_SLOT = 0x200 + 0x460;\n    uint256 internal constant VK_LOOKUP_TABLE_3_X_SLOT = 0x200 + 0x480;\n    uint256 internal constant VK_LOOKUP_TABLE_3_Y_SLOT = 0x200 + 0x4a0;\n\n    uint256 internal constant VK_LOOKUP_TABLE_TYPE_X_SLOT = 0x200 + 0x4c0;\n    uint256 internal constant VK_LOOKUP_TABLE_TYPE_Y_SLOT = 0x200 + 0x4e0;\n\n    uint256 internal constant VK_RECURSIVE_FLAG_SLOT = 0x200 + 0x500;\n\n    /*//////////////////////////////////////////////////////////////\n                             Proof\n    //////////////////////////////////////////////////////////////*/\n\n    uint256 internal constant PROOF_PUBLIC_INPUT = 0x200 + 0x520 + 0x000;\n\n    uint256 internal constant PROOF_STATE_POLYS_0_X_SLOT = 0x200 + 0x520 + 0x020;\n    uint256 internal constant PROOF_STATE_POLYS_0_Y_SLOT = 0x200 + 0x520 + 0x040;\n    uint256 internal constant PROOF_STATE_POLYS_1_X_SLOT = 0x200 + 0x520 + 0x060;\n    uint256 internal constant PROOF_STATE_POLYS_1_Y_SLOT = 0x200 + 0x520 + 0x080;\n    uint256 internal constant PROOF_STATE_POLYS_2_X_SLOT = 0x200 + 0x520 + 0x0a0;\n    uint256 internal constant PROOF_STATE_POLYS_2_Y_SLOT = 0x200 + 0x520 + 0x0c0;\n    uint256 internal constant PROOF_STATE_POLYS_3_X_SLOT = 0x200 + 0x520 + 0x0e0;\n    uint256 internal constant PROOF_STATE_POLYS_3_Y_SLOT = 0x200 + 0x520 + 0x100;\n\n    uint256 internal constant PROOF_COPY_PERMUTATION_GRAND_PRODUCT_X_SLOT = 0x200 + 0x520 + 0x120;\n    uint256 internal constant PROOF_COPY_PERMUTATION_GRAND_PRODUCT_Y_SLOT = 0x200 + 0x520 + 0x140;\n\n    uint256 internal constant PROOF_LOOKUP_S_POLY_X_SLOT = 0x200 + 0x520 + 0x160;\n    uint256 internal constant PROOF_LOOKUP_S_POLY_Y_SLOT = 0x200 + 0x520 + 0x180;\n\n    uint256 internal constant PROOF_LOOKUP_GRAND_PRODUCT_X_SLOT = 0x200 + 0x520 + 0x1a0;\n    uint256 internal constant PROOF_LOOKUP_GRAND_PRODUCT_Y_SLOT = 0x200 + 0x520 + 0x1c0;\n\n    uint256 internal constant PROOF_QUOTIENT_POLY_PARTS_0_X_SLOT = 0x200 + 0x520 + 0x1e0;\n    uint256 internal constant PROOF_QUOTIENT_POLY_PARTS_0_Y_SLOT = 0x200 + 0x520 + 0x200;\n    uint256 internal constant PROOF_QUOTIENT_POLY_PARTS_1_X_SLOT = 0x200 + 0x520 + 0x220;\n    uint256 internal constant PROOF_QUOTIENT_POLY_PARTS_1_Y_SLOT = 0x200 + 0x520 + 0x240;\n    uint256 internal constant PROOF_QUOTIENT_POLY_PARTS_2_X_SLOT = 0x200 + 0x520 + 0x260;\n    uint256 internal constant PROOF_QUOTIENT_POLY_PARTS_2_Y_SLOT = 0x200 + 0x520 + 0x280;\n    uint256 internal constant PROOF_QUOTIENT_POLY_PARTS_3_X_SLOT = 0x200 + 0x520 + 0x2a0;\n    uint256 internal constant PROOF_QUOTIENT_POLY_PARTS_3_Y_SLOT = 0x200 + 0x520 + 0x2c0;\n\n    uint256 internal constant PROOF_STATE_POLYS_0_OPENING_AT_Z_SLOT = 0x200 + 0x520 + 0x2e0;\n    uint256 internal constant PROOF_STATE_POLYS_1_OPENING_AT_Z_SLOT = 0x200 + 0x520 + 0x300;\n    uint256 internal constant PROOF_STATE_POLYS_2_OPENING_AT_Z_SLOT = 0x200 + 0x520 + 0x320;\n    uint256 internal constant PROOF_STATE_POLYS_3_OPENING_AT_Z_SLOT = 0x200 + 0x520 + 0x340;\n\n    uint256 internal constant PROOF_STATE_POLYS_3_OPENING_AT_Z_OMEGA_SLOT = 0x200 + 0x520 + 0x360;\n    uint256 internal constant PROOF_GATE_SELECTORS_0_OPENING_AT_Z_SLOT = 0x200 + 0x520 + 0x380;\n\n    uint256 internal constant PROOF_COPY_PERMUTATION_POLYS_0_OPENING_AT_Z_SLOT = 0x200 + 0x520 + 0x3a0;\n    uint256 internal constant PROOF_COPY_PERMUTATION_POLYS_1_OPENING_AT_Z_SLOT = 0x200 + 0x520 + 0x3c0;\n    uint256 internal constant PROOF_COPY_PERMUTATION_POLYS_2_OPENING_AT_Z_SLOT = 0x200 + 0x520 + 0x3e0;\n\n    uint256 internal constant PROOF_COPY_PERMUTATION_GRAND_PRODUCT_OPENING_AT_Z_OMEGA_SLOT = 0x200 + 0x520 + 0x400;\n    uint256 internal constant PROOF_LOOKUP_S_POLY_OPENING_AT_Z_OMEGA_SLOT = 0x200 + 0x520 + 0x420;\n    uint256 internal constant PROOF_LOOKUP_GRAND_PRODUCT_OPENING_AT_Z_OMEGA_SLOT = 0x200 + 0x520 + 0x440;\n    uint256 internal constant PROOF_LOOKUP_T_POLY_OPENING_AT_Z_SLOT = 0x200 + 0x520 + 0x460;\n    uint256 internal constant PROOF_LOOKUP_T_POLY_OPENING_AT_Z_OMEGA_SLOT = 0x200 + 0x520 + 0x480;\n    uint256 internal constant PROOF_LOOKUP_SELECTOR_POLY_OPENING_AT_Z_SLOT = 0x200 + 0x520 + 0x4a0;\n    uint256 internal constant PROOF_LOOKUP_TABLE_TYPE_POLY_OPENING_AT_Z_SLOT = 0x200 + 0x520 + 0x4c0;\n    uint256 internal constant PROOF_QUOTIENT_POLY_OPENING_AT_Z_SLOT = 0x200 + 0x520 + 0x4e0;\n    uint256 internal constant PROOF_LINEARISATION_POLY_OPENING_AT_Z_SLOT = 0x200 + 0x520 + 0x500;\n\n    uint256 internal constant PROOF_OPENING_PROOF_AT_Z_X_SLOT = 0x200 + 0x520 + 0x520;\n    uint256 internal constant PROOF_OPENING_PROOF_AT_Z_Y_SLOT = 0x200 + 0x520 + 0x540;\n    uint256 internal constant PROOF_OPENING_PROOF_AT_Z_OMEGA_X_SLOT = 0x200 + 0x520 + 0x560;\n    uint256 internal constant PROOF_OPENING_PROOF_AT_Z_OMEGA_Y_SLOT = 0x200 + 0x520 + 0x580;\n\n    uint256 internal constant PROOF_RECURSIVE_PART_P1_X_SLOT = 0x200 + 0x520 + 0x5a0;\n    uint256 internal constant PROOF_RECURSIVE_PART_P1_Y_SLOT = 0x200 + 0x520 + 0x5c0;\n\n    uint256 internal constant PROOF_RECURSIVE_PART_P2_X_SLOT = 0x200 + 0x520 + 0x5e0;\n    uint256 internal constant PROOF_RECURSIVE_PART_P2_Y_SLOT = 0x200 + 0x520 + 0x600;\n\n    /*//////////////////////////////////////////////////////////////\n                             Transcript slot\n    //////////////////////////////////////////////////////////////*/\n\n    uint256 internal constant TRANSCRIPT_BEGIN_SLOT = 0x200 + 0x520 + 0x620 + 0x00;\n    uint256 internal constant TRANSCRIPT_DST_BYTE_SLOT = 0x200 + 0x520 + 0x620 + 0x03;\n    uint256 internal constant TRANSCRIPT_STATE_0_SLOT = 0x200 + 0x520 + 0x620 + 0x04;\n    uint256 internal constant TRANSCRIPT_STATE_1_SLOT = 0x200 + 0x520 + 0x620 + 0x24;\n    uint256 internal constant TRANSCRIPT_CHALLENGE_SLOT = 0x200 + 0x520 + 0x620 + 0x44;\n\n    /*//////////////////////////////////////////////////////////////\n                             Partial verifier state\n    //////////////////////////////////////////////////////////////*/\n\n    uint256 internal constant STATE_ALPHA_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x000;\n    uint256 internal constant STATE_BETA_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x020;\n    uint256 internal constant STATE_GAMMA_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x040;\n    uint256 internal constant STATE_POWER_OF_ALPHA_2_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x060;\n    uint256 internal constant STATE_POWER_OF_ALPHA_3_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x080;\n    uint256 internal constant STATE_POWER_OF_ALPHA_4_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x0a0;\n    uint256 internal constant STATE_POWER_OF_ALPHA_5_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x0c0;\n    uint256 internal constant STATE_POWER_OF_ALPHA_6_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x0e0;\n    uint256 internal constant STATE_POWER_OF_ALPHA_7_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x100;\n    uint256 internal constant STATE_POWER_OF_ALPHA_8_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x120;\n    uint256 internal constant STATE_ETA_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x140;\n    uint256 internal constant STATE_BETA_LOOKUP_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x160;\n    uint256 internal constant STATE_GAMMA_LOOKUP_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x180;\n    uint256 internal constant STATE_BETA_PLUS_ONE_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x1a0;\n    uint256 internal constant STATE_BETA_GAMMA_PLUS_GAMMA_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x1c0;\n    uint256 internal constant STATE_V_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x1e0;\n    uint256 internal constant STATE_U_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x200;\n    uint256 internal constant STATE_Z_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x220;\n    uint256 internal constant STATE_Z_MINUS_LAST_OMEGA_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x240;\n    uint256 internal constant STATE_L_0_AT_Z_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x260;\n    uint256 internal constant STATE_L_N_MINUS_ONE_AT_Z_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x280;\n    uint256 internal constant STATE_Z_IN_DOMAIN_SIZE = 0x200 + 0x520 + 0x620 + 0x80 + 0x2a0;\n\n    /*//////////////////////////////////////////////////////////////\n                             Queries\n    //////////////////////////////////////////////////////////////*/\n\n    uint256 internal constant QUERIES_BUFFER_POINT_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x2c0 + 0x00;\n\n    uint256 internal constant QUERIES_AT_Z_0_X_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x2c0 + 0x40;\n    uint256 internal constant QUERIES_AT_Z_0_Y_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x2c0 + 0x60;\n    uint256 internal constant QUERIES_AT_Z_1_X_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x2c0 + 0x80;\n    uint256 internal constant QUERIES_AT_Z_1_Y_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x2c0 + 0xa0;\n\n    uint256 internal constant QUERIES_T_POLY_AGGREGATED_X_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x2c0 + 0xc0;\n    uint256 internal constant QUERIES_T_POLY_AGGREGATED_Y_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x2c0 + 0xe0;\n\n    /*//////////////////////////////////////////////////////////////\n                             Aggregated commitment\n    //////////////////////////////////////////////////////////////*/\n\n    uint256 internal constant AGGREGATED_AT_Z_X_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x2c0 + 0x100 + 0x00;\n    uint256 internal constant AGGREGATED_AT_Z_Y_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x2c0 + 0x100 + 0x20;\n\n    uint256 internal constant AGGREGATED_AT_Z_OMEGA_X_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x2c0 + 0x100 + 0x40;\n    uint256 internal constant AGGREGATED_AT_Z_OMEGA_Y_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x2c0 + 0x100 + 0x60;\n\n    uint256 internal constant AGGREGATED_OPENING_AT_Z_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x2c0 + 0x100 + 0x80;\n    uint256 internal constant AGGREGATED_OPENING_AT_Z_OMEGA_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x2c0 + 0x100 + 0xa0;\n\n    /*//////////////////////////////////////////////////////////////\n                             Pairing data\n    //////////////////////////////////////////////////////////////*/\n\n    uint256 internal constant PAIRING_BUFFER_POINT_X_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x2c0 + 0x100 + 0xc0 + 0x00;\n    uint256 internal constant PAIRING_BUFFER_POINT_Y_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x2c0 + 0x100 + 0xc0 + 0x20;\n\n    uint256 internal constant PAIRING_PAIR_WITH_GENERATOR_X_SLOT =\n        0x200 + 0x520 + 0x620 + 0x80 + 0x2c0 + 0x100 + 0xc0 + 0x40;\n    uint256 internal constant PAIRING_PAIR_WITH_GENERATOR_Y_SLOT =\n        0x200 + 0x520 + 0x620 + 0x80 + 0x2c0 + 0x100 + 0xc0 + 0x60;\n\n    uint256 internal constant PAIRING_PAIR_WITH_X_X_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x2c0 + 0x100 + 0x100 + 0x80;\n    uint256 internal constant PAIRING_PAIR_WITH_X_Y_SLOT = 0x200 + 0x520 + 0x620 + 0x80 + 0x2c0 + 0x100 + 0x100 + 0xa0;\n\n    /*//////////////////////////////////////////////////////////////\n               Slots for scalar multiplication optimizations\n    //////////////////////////////////////////////////////////////*/\n\n    uint256 internal constant COPY_PERMUTATION_FIRST_AGGREGATED_COMMITMENT_COEFF =\n        0x200 + 0x520 + 0x620 + 0x80 + 0x2c0 + 0x100 + 0x100 + 0xc0;\n    uint256 internal constant LOOKUP_GRAND_PRODUCT_FIRST_AGGREGATED_COMMITMENT_COEFF =\n        0x200 + 0x520 + 0x620 + 0x80 + 0x2c0 + 0x100 + 0x100 + 0xe0;\n    uint256 internal constant LOOKUP_S_FIRST_AGGREGATED_COMMITMENT_COEFF =\n        0x200 + 0x520 + 0x620 + 0x80 + 0x2c0 + 0x100 + 0x100 + 0x100;\n\n    /*//////////////////////////////////////////////////////////////\n                             Constants\n    //////////////////////////////////////////////////////////////*/\n\n    uint256 internal constant OMEGA = 0x1951441010b2b95a6e47a6075066a50a036f5ba978c050f2821df86636c0facb;\n    uint256 internal constant DOMAIN_SIZE = 0x1000000; // 2^24\n    uint256 internal constant Q_MOD = 21888242871839275222246405745257275088696311157297823662689037894645226208583;\n    uint256 internal constant R_MOD = 21888242871839275222246405745257275088548364400416034343698204186575808495617;\n\n    /// @dev flip of 0xe000000000000000000000000000000000000000000000000000000000000000;\n    uint256 internal constant FR_MASK = 0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;\n\n    // non residues\n    uint256 internal constant NON_RESIDUES_0 = 0x05;\n    uint256 internal constant NON_RESIDUES_1 = 0x07;\n    uint256 internal constant NON_RESIDUES_2 = 0x0a;\n\n    // trusted setup g2 elements\n    uint256 internal constant G2_ELEMENTS_0_X1 = 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2;\n    uint256 internal constant G2_ELEMENTS_0_X2 = 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed;\n    uint256 internal constant G2_ELEMENTS_0_Y1 = 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b;\n    uint256 internal constant G2_ELEMENTS_0_Y2 = 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa;\n    uint256 internal constant G2_ELEMENTS_1_X1 = 0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1;\n    uint256 internal constant G2_ELEMENTS_1_X2 = 0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0;\n    uint256 internal constant G2_ELEMENTS_1_Y1 = 0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4;\n    uint256 internal constant G2_ELEMENTS_1_Y2 = 0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55;\n\n    /// @inheritdoc IVerifier\n    function verificationKeyHash() external pure returns (bytes32 vkHash) {\n        _loadVerificationKey();\n\n        assembly {\n            let start := VK_GATE_SETUP_0_X_SLOT\n            let end := VK_RECURSIVE_FLAG_SLOT\n            let length := add(sub(end, start), 0x20)\n\n            vkHash := keccak256(start, length)\n        }\n    }\n\n    /// @notice Load verification keys to memory in runtime.\n    /// @dev The constants are loaded into memory in a specific layout declared in the constants starting from\n    /// `VK_` prefix.\n    /// NOTE: Function may corrupt the memory state if some memory was used before this function was called.\n    /// The VK consists of commitments to setup polynomials:\n    /// [q_a], [q_b], [q_c], [q_d],                  - main gate setup commitments\n    /// [q_{d_next}], [q_ab], [q_ac], [q_const]      /\n    /// [main_gate_selector], [custom_gate_selector] - gate selectors commitments\n    /// [sigma_0], [sigma_1], [sigma_2], [sigma_3]   - permutation polynomials commitments\n    /// [lookup_selector]                            - lookup selector commitment\n    /// [col_0], [col_1], [col_2], [col_3]           - lookup columns commitments\n    /// [table_type]                                 - lookup table type commitment\n    function _loadVerificationKey() internal pure virtual {\n        assembly {\n            // gate setup commitments\n            mstore(VK_GATE_SETUP_0_X_SLOT, 0x0b4a9f5342e7afd12f0cf9e05570c9a093f0bd7cb7b78c81bf1544cb5da85b62)\n            mstore(VK_GATE_SETUP_0_Y_SLOT, 0x21eb82b2d4977e4c485af279bca5c883d086e4ea1ecd00920edf7d946a650995)\n            mstore(VK_GATE_SETUP_1_X_SLOT, 0x280e3c42287d88240208d3fd01cc10690f13a6d7da1fa42a4011ee9256ac104f)\n            mstore(VK_GATE_SETUP_1_Y_SLOT, 0x15dc080b2cb32132e40858645657e6b420eb468330fe66956cd03ba85bacaed4)\n            mstore(VK_GATE_SETUP_2_X_SLOT, 0x2069c413c319dd35062fa2baf6bdd6fa389f8dad854c60263d28eab3853a121c)\n            mstore(VK_GATE_SETUP_2_Y_SLOT, 0x01b890b5228208ffc081f6123071ec48d4df9be9e6621381f4a3c0b2fd4c40aa)\n            mstore(VK_GATE_SETUP_3_X_SLOT, 0x10f3e708f45ca2efdec8841e5269243fe198c0ee52800332cdce8667bc1dc969)\n            mstore(VK_GATE_SETUP_3_Y_SLOT, 0x2528663d1ef8e4f361da7b8731dad691ae589374ac614c1c5d1346f9e43fb5b6)\n            mstore(VK_GATE_SETUP_4_X_SLOT, 0x07c075fea3d01d8a8ea4118b3ba844f1780f3e4071dbb62a72f33a3c85a9071f)\n            mstore(VK_GATE_SETUP_4_Y_SLOT, 0x3036edf95d2870c750d7aa482c7b4c846bc1c2cbaca785d65ef0c19be2060c29)\n            mstore(VK_GATE_SETUP_5_X_SLOT, 0x302c28931968d9b0a7123b271164a047449bac619040613232e22cc826718123)\n            mstore(VK_GATE_SETUP_5_Y_SLOT, 0x1011a5c84cc8cc01327e01e0fab0816a62657f7ca662b39da403b27ed1fb32ae)\n            mstore(VK_GATE_SETUP_6_X_SLOT, 0x29f5372d67002cf1b03c4b90ba0892fb4067727e6e62556d3385f7ce080c6dbc)\n            mstore(VK_GATE_SETUP_6_Y_SLOT, 0x0a63248741589563e58fc34ea7ba84ac9bf4c8c8fed393c53fe76225e49f086a)\n            mstore(VK_GATE_SETUP_7_X_SLOT, 0x0439082913a1028f27fd9297e93291e707c66f203bc26904872dd3e17f354ab0)\n            mstore(VK_GATE_SETUP_7_Y_SLOT, 0x275078ab02afe9e191a023899a0d664819219a1a11a71df9bdc16deeb59357cd)\n\n            // gate selectors commitments\n            mstore(VK_GATE_SELECTORS_0_X_SLOT, 0x2b67cbcea5d975f37dafccfdacde7ae4676966cf346060b46d8c31895cd38a31)\n            mstore(VK_GATE_SELECTORS_0_Y_SLOT, 0x1df1d2b75d5e00c4cc9ed981167e1895a74ef9a21f2253aa350c195bd7af3f5f)\n            mstore(VK_GATE_SELECTORS_1_X_SLOT, 0x132e3968e05ce8a19671de377801c2255c018fbc07a81625fa7b4366e0c7374f)\n            mstore(VK_GATE_SELECTORS_1_Y_SLOT, 0x078307dbab33a8bf744787e3fd5edd7e5e183e8e8f6b11785bc01150c6e3c857)\n\n            // permutation commitments\n            mstore(VK_PERMUTATION_0_X_SLOT, 0x22a848812e5f1fd2574b256adea75f6b29ac39d6e164535e20441b7a92e6d720)\n            mstore(VK_PERMUTATION_0_Y_SLOT, 0x06073f25cf0516c9964f5c50daafb5237f6c1fa553a47f3469fb89257168c674)\n            mstore(VK_PERMUTATION_1_X_SLOT, 0x0c994cf1008a34dfac4e6cb410cacd3da3d5da38dfed7415be22d126a27348e8)\n            mstore(VK_PERMUTATION_1_Y_SLOT, 0x23ae45e176417d3ea51607c5a7640cbe2b3ff7fdf68ca435b61c86b88f0196ca)\n            mstore(VK_PERMUTATION_2_X_SLOT, 0x0e316b80565bacbb6e15df912e35ed2118659f623b55d24ed700944a85a47a55)\n            mstore(VK_PERMUTATION_2_Y_SLOT, 0x1e2be7f209a8e0f8d9994cbda5c7202e1dde2a04883f3055fa4b85be079d4baa)\n            mstore(VK_PERMUTATION_3_X_SLOT, 0x150fc6bea1e744b30d5b150e3be4e6d16ecc89de29eef2ffaaf7797cc7ceca2a)\n            mstore(VK_PERMUTATION_3_Y_SLOT, 0x2f0b5208404ab77741d24815423f45c8fe0757233433b3a41bc90b1b4fc9ff60)\n\n            // lookup tables commitments\n            mstore(VK_LOOKUP_TABLE_0_X_SLOT, 0x2c513ed74d9d57a5ec901e074032741036353a2c4513422e96e7b53b302d765b)\n            mstore(VK_LOOKUP_TABLE_0_Y_SLOT, 0x04dd964427e430f16004076d708c0cb21e225056cc1d57418cfbd3d472981468)\n            mstore(VK_LOOKUP_TABLE_1_X_SLOT, 0x1ea83e5e65c6f8068f4677e2911678cf329b28259642a32db1f14b8347828aac)\n            mstore(VK_LOOKUP_TABLE_1_Y_SLOT, 0x1d22bc884a2da4962a893ba8de13f57aaeb785ed52c5e686994839cab8f7475d)\n            mstore(VK_LOOKUP_TABLE_2_X_SLOT, 0x0b2e7212d0d9cff26d0bdf3d79b2cac029a25dfeb1cafdf49e2349d7db348d89)\n            mstore(VK_LOOKUP_TABLE_2_Y_SLOT, 0x1301f9b252419ea240eb67fda720ca0b16d92364027285f95e9b1349490fa283)\n            mstore(VK_LOOKUP_TABLE_3_X_SLOT, 0x02f7b99fdfa5b418548c2d777785820e02383cfc87e7085e280a375a358153bf)\n            mstore(VK_LOOKUP_TABLE_3_Y_SLOT, 0x09d004fe08dc4d19c382df36fad22ef676185663543703e6a4b40203e50fd8a6)\n\n            // lookup selector commitment\n            mstore(VK_LOOKUP_SELECTOR_X_SLOT, 0x2ac4721a65816699ae0aaad6c38ee4756fdecc3e9b6844f1b70cb4e35e841a4f)\n            mstore(VK_LOOKUP_SELECTOR_Y_SLOT, 0x03995224b6215f409c81c7155c0373fb14c58e1c08589894168da61111eb981b)\n\n            // table type commitment\n            mstore(VK_LOOKUP_TABLE_TYPE_X_SLOT, 0x155ac28b6e9ca210d38a17d7d71b20b0d539b503c7a5c9e222e3e11363cf200c)\n            mstore(VK_LOOKUP_TABLE_TYPE_Y_SLOT, 0x130de19edf9381111ec6d004656571a8da719e3057b3902b52e01d062e467240)\n\n            // flag for using recursive part\n            mstore(VK_RECURSIVE_FLAG_SLOT, 0)\n        }\n    }\n\n    /// @inheritdoc IVerifier\n    function verify(\n        uint256[] calldata, // _publicInputs\n        uint256[] calldata // _proof\n    ) public view virtual returns (bool) {\n        // No memory was accessed yet, so keys can be loaded into the right place and not corrupt any other memory.\n        _loadVerificationKey();\n\n        // Beginning of the big inline assembly block that makes all the verification work.\n        // Note: We use the custom memory layout, so the return value should be returned from the assembly, not\n        // Solidity code.\n        assembly {\n            /*//////////////////////////////////////////////////////////////\n                                    Utils\n            //////////////////////////////////////////////////////////////*/\n\n            /// @dev Reverts execution with a provided revert reason.\n            /// @param len The byte length of the error message string, which is expected to be no more than 32.\n            /// @param reason The 1-word revert reason string, encoded in ASCII.\n            function revertWithMessage(len, reason) {\n                // \"Error(string)\" signature: bytes32(bytes4(keccak256(\"Error(string)\")))\n                mstore(0x00, 0x08c379a000000000000000000000000000000000000000000000000000000000)\n                // Data offset\n                mstore(0x04, 0x0000000000000000000000000000000000000000000000000000000000000020)\n                // Length of revert string\n                mstore(0x24, len)\n                // Revert reason\n                mstore(0x44, reason)\n                // Revert\n                revert(0x00, 0x64)\n            }\n\n            /// @dev Performs modular exponentiation using the formula (value ^ power) mod R_MOD.\n            function modexp(value, power) -> res {\n                mstore(0x00, 0x20)\n                mstore(0x20, 0x20)\n                mstore(0x40, 0x20)\n                mstore(0x60, value)\n                mstore(0x80, power)\n                mstore(0xa0, R_MOD)\n                if iszero(staticcall(gas(), 5, 0, 0xc0, 0x00, 0x20)) {\n                    revertWithMessage(24, \"modexp precompile failed\")\n                }\n                res := mload(0x00)\n            }\n\n            /// @dev Performs a point multiplication operation and stores the result in a given memory destination.\n            function pointMulIntoDest(point, s, dest) {\n                mstore(0x00, mload(point))\n                mstore(0x20, mload(add(point, 0x20)))\n                mstore(0x40, s)\n                if iszero(staticcall(gas(), 7, 0, 0x60, dest, 0x40)) {\n                    revertWithMessage(30, \"pointMulIntoDest: ecMul failed\")\n                }\n            }\n\n            /// @dev Performs a point addition operation and stores the result in a given memory destination.\n            function pointAddIntoDest(p1, p2, dest) {\n                mstore(0x00, mload(p1))\n                mstore(0x20, mload(add(p1, 0x20)))\n                mstore(0x40, mload(p2))\n                mstore(0x60, mload(add(p2, 0x20)))\n                if iszero(staticcall(gas(), 6, 0x00, 0x80, dest, 0x40)) {\n                    revertWithMessage(30, \"pointAddIntoDest: ecAdd failed\")\n                }\n            }\n\n            /// @dev Performs a point subtraction operation and updates the first point with the result.\n            function pointSubAssign(p1, p2) {\n                mstore(0x00, mload(p1))\n                mstore(0x20, mload(add(p1, 0x20)))\n                mstore(0x40, mload(p2))\n                mstore(0x60, sub(Q_MOD, mload(add(p2, 0x20))))\n                if iszero(staticcall(gas(), 6, 0x00, 0x80, p1, 0x40)) {\n                    revertWithMessage(28, \"pointSubAssign: ecAdd failed\")\n                }\n            }\n\n            /// @dev Performs a point addition operation and updates the first point with the result.\n            function pointAddAssign(p1, p2) {\n                mstore(0x00, mload(p1))\n                mstore(0x20, mload(add(p1, 0x20)))\n                mstore(0x40, mload(p2))\n                mstore(0x60, mload(add(p2, 0x20)))\n                if iszero(staticcall(gas(), 6, 0x00, 0x80, p1, 0x40)) {\n                    revertWithMessage(28, \"pointAddAssign: ecAdd failed\")\n                }\n            }\n\n            /// @dev Performs a point multiplication operation and then adds the result to the destination point.\n            function pointMulAndAddIntoDest(point, s, dest) {\n                mstore(0x00, mload(point))\n                mstore(0x20, mload(add(point, 0x20)))\n                mstore(0x40, s)\n                let success := staticcall(gas(), 7, 0, 0x60, 0, 0x40)\n\n                mstore(0x40, mload(dest))\n                mstore(0x60, mload(add(dest, 0x20)))\n                success := and(success, staticcall(gas(), 6, 0x00, 0x80, dest, 0x40))\n\n                if iszero(success) {\n                    revertWithMessage(22, \"pointMulAndAddIntoDest\")\n                }\n            }\n\n            /// @dev Negates an elliptic curve point by changing the sign of the y-coordinate.\n            function pointNegate(point) {\n                let pY := mload(add(point, 0x20))\n                switch pY\n                case 0 {\n                    if mload(point) {\n                        revertWithMessage(26, \"pointNegate: invalid point\")\n                    }\n                }\n                default {\n                    mstore(add(point, 0x20), sub(Q_MOD, pY))\n                }\n            }\n\n            /*//////////////////////////////////////////////////////////////\n                                    Transcript helpers\n            //////////////////////////////////////////////////////////////*/\n\n            /// @dev Updates the transcript state with a new challenge value.\n            function updateTranscript(value) {\n                mstore8(TRANSCRIPT_DST_BYTE_SLOT, 0x00)\n                mstore(TRANSCRIPT_CHALLENGE_SLOT, value)\n                let newState0 := keccak256(TRANSCRIPT_BEGIN_SLOT, 0x64)\n                mstore8(TRANSCRIPT_DST_BYTE_SLOT, 0x01)\n                let newState1 := keccak256(TRANSCRIPT_BEGIN_SLOT, 0x64)\n                mstore(TRANSCRIPT_STATE_1_SLOT, newState1)\n                mstore(TRANSCRIPT_STATE_0_SLOT, newState0)\n            }\n\n            /// @dev Retrieves a transcript challenge.\n            function getTranscriptChallenge(numberOfChallenge) -> challenge {\n                mstore8(TRANSCRIPT_DST_BYTE_SLOT, 0x02)\n                mstore(TRANSCRIPT_CHALLENGE_SLOT, shl(224, numberOfChallenge))\n                challenge := and(keccak256(TRANSCRIPT_BEGIN_SLOT, 0x48), FR_MASK)\n            }\n\n            /*//////////////////////////////////////////////////////////////\n                                    1. Load Proof\n            //////////////////////////////////////////////////////////////*/\n\n            /// @dev This function loads a zk-SNARK proof, ensures it's properly formatted, and stores it in memory.\n            /// It ensures the number of inputs and the elliptic curve point's validity.\n            /// Note: It does NOT reject inputs that exceed these module sizes, but rather wraps them within the\n            /// module bounds.\n            /// The proof consists of:\n            /// 1. Public input: (1 field element from F_r)\n            ///\n            /// 2. Polynomial commitments (elliptic curve points over F_q):\n            ///     [a], [b], [c], [d]         - state polynomials commitments\n            ///     [z_perm]                   - copy-permutation grand product commitment\n            ///     [s]                        - polynomial for lookup argument commitment\n            ///     [z_lookup]                 - lookup grand product commitment\n            ///     [t_0], [t_1], [t_2], [t_3] - quotient polynomial parts commitments\n            ///     [W], [W']                  - proof openings commitments\n            ///\n            /// 3. Polynomial evaluations at z and z*omega (field elements from F_r):\n            ///     t(z)                                  - quotient polynomial opening\n            ///     a(z), b(z), c(z), d(z), d(z*omega)    - state polynomials openings\n            ///     main_gate_selector(z)                 - main gate selector opening\n            ///     sigma_0(z), sigma_1(z), sigma_2(z)    - permutation polynomials openings\n            ///     z_perm(z*omega)                       - copy-permutation grand product opening\n            ///     z_lookup(z*omega)                     - lookup grand product opening\n            ///     lookup_selector(z)                    - lookup selector opening\n            ///     s(x*omega), t(z*omega), table_type(z) - lookup argument polynomial openings\n            ///     r(z)                                  - linearisation polynomial opening\n            ///\n            /// 4. Recursive proof (0 or 2 elliptic curve points over F_q)\n            function loadProof() {\n                // 1. Load public input\n                let offset := calldataload(0x04)\n                let publicInputLengthInWords := calldataload(add(offset, 0x04))\n                let isValid := eq(publicInputLengthInWords, 1) // We expect only one public input\n                mstore(PROOF_PUBLIC_INPUT, and(calldataload(add(offset, 0x24)), FR_MASK))\n\n                // 2. Load the proof (except for the recursive part)\n                offset := calldataload(0x24)\n                let proofLengthInWords := calldataload(add(offset, 0x04))\n\n                // Check the proof length depending on whether the recursive part is present\n                let expectedProofLength\n                switch mload(VK_RECURSIVE_FLAG_SLOT)\n                case 0 {\n                    expectedProofLength := 44\n                }\n                default {\n                    expectedProofLength := 48\n                }\n                isValid := and(eq(proofLengthInWords, expectedProofLength), isValid)\n\n                // PROOF_STATE_POLYS_0\n                {\n                    let x := mod(calldataload(add(offset, 0x024)), Q_MOD)\n                    let y := mod(calldataload(add(offset, 0x044)), Q_MOD)\n                    let xx := mulmod(x, x, Q_MOD)\n                    isValid := and(eq(mulmod(y, y, Q_MOD), addmod(mulmod(x, xx, Q_MOD), 3, Q_MOD)), isValid)\n                    mstore(PROOF_STATE_POLYS_0_X_SLOT, x)\n                    mstore(PROOF_STATE_POLYS_0_Y_SLOT, y)\n                }\n                // PROOF_STATE_POLYS_1\n                {\n                    let x := mod(calldataload(add(offset, 0x064)), Q_MOD)\n                    let y := mod(calldataload(add(offset, 0x084)), Q_MOD)\n                    let xx := mulmod(x, x, Q_MOD)\n                    isValid := and(eq(mulmod(y, y, Q_MOD), addmod(mulmod(x, xx, Q_MOD), 3, Q_MOD)), isValid)\n                    mstore(PROOF_STATE_POLYS_1_X_SLOT, x)\n                    mstore(PROOF_STATE_POLYS_1_Y_SLOT, y)\n                }\n                // PROOF_STATE_POLYS_2\n                {\n                    let x := mod(calldataload(add(offset, 0x0a4)), Q_MOD)\n                    let y := mod(calldataload(add(offset, 0x0c4)), Q_MOD)\n                    let xx := mulmod(x, x, Q_MOD)\n                    isValid := and(eq(mulmod(y, y, Q_MOD), addmod(mulmod(x, xx, Q_MOD), 3, Q_MOD)), isValid)\n                    mstore(PROOF_STATE_POLYS_2_X_SLOT, x)\n                    mstore(PROOF_STATE_POLYS_2_Y_SLOT, y)\n                }\n                // PROOF_STATE_POLYS_3\n                {\n                    let x := mod(calldataload(add(offset, 0x0e4)), Q_MOD)\n                    let y := mod(calldataload(add(offset, 0x104)), Q_MOD)\n                    let xx := mulmod(x, x, Q_MOD)\n                    isValid := and(eq(mulmod(y, y, Q_MOD), addmod(mulmod(x, xx, Q_MOD), 3, Q_MOD)), isValid)\n                    mstore(PROOF_STATE_POLYS_3_X_SLOT, x)\n                    mstore(PROOF_STATE_POLYS_3_Y_SLOT, y)\n                }\n                // PROOF_COPY_PERMUTATION_GRAND_PRODUCT\n                {\n                    let x := mod(calldataload(add(offset, 0x124)), Q_MOD)\n                    let y := mod(calldataload(add(offset, 0x144)), Q_MOD)\n                    let xx := mulmod(x, x, Q_MOD)\n                    isValid := and(eq(mulmod(y, y, Q_MOD), addmod(mulmod(x, xx, Q_MOD), 3, Q_MOD)), isValid)\n                    mstore(PROOF_COPY_PERMUTATION_GRAND_PRODUCT_X_SLOT, x)\n                    mstore(PROOF_COPY_PERMUTATION_GRAND_PRODUCT_Y_SLOT, y)\n                }\n                // PROOF_LOOKUP_S_POLY\n                {\n                    let x := mod(calldataload(add(offset, 0x164)), Q_MOD)\n                    let y := mod(calldataload(add(offset, 0x184)), Q_MOD)\n                    let xx := mulmod(x, x, Q_MOD)\n                    isValid := and(eq(mulmod(y, y, Q_MOD), addmod(mulmod(x, xx, Q_MOD), 3, Q_MOD)), isValid)\n                    mstore(PROOF_LOOKUP_S_POLY_X_SLOT, x)\n                    mstore(PROOF_LOOKUP_S_POLY_Y_SLOT, y)\n                }\n                // PROOF_LOOKUP_GRAND_PRODUCT\n                {\n                    let x := mod(calldataload(add(offset, 0x1a4)), Q_MOD)\n                    let y := mod(calldataload(add(offset, 0x1c4)), Q_MOD)\n                    let xx := mulmod(x, x, Q_MOD)\n                    isValid := and(eq(mulmod(y, y, Q_MOD), addmod(mulmod(x, xx, Q_MOD), 3, Q_MOD)), isValid)\n                    mstore(PROOF_LOOKUP_GRAND_PRODUCT_X_SLOT, x)\n                    mstore(PROOF_LOOKUP_GRAND_PRODUCT_Y_SLOT, y)\n                }\n                // PROOF_QUOTIENT_POLY_PARTS_0\n                {\n                    let x := mod(calldataload(add(offset, 0x1e4)), Q_MOD)\n                    let y := mod(calldataload(add(offset, 0x204)), Q_MOD)\n                    let xx := mulmod(x, x, Q_MOD)\n                    isValid := and(eq(mulmod(y, y, Q_MOD), addmod(mulmod(x, xx, Q_MOD), 3, Q_MOD)), isValid)\n                    mstore(PROOF_QUOTIENT_POLY_PARTS_0_X_SLOT, x)\n                    mstore(PROOF_QUOTIENT_POLY_PARTS_0_Y_SLOT, y)\n                }\n                // PROOF_QUOTIENT_POLY_PARTS_1\n                {\n                    let x := mod(calldataload(add(offset, 0x224)), Q_MOD)\n                    let y := mod(calldataload(add(offset, 0x244)), Q_MOD)\n                    let xx := mulmod(x, x, Q_MOD)\n                    isValid := and(eq(mulmod(y, y, Q_MOD), addmod(mulmod(x, xx, Q_MOD), 3, Q_MOD)), isValid)\n                    mstore(PROOF_QUOTIENT_POLY_PARTS_1_X_SLOT, x)\n                    mstore(PROOF_QUOTIENT_POLY_PARTS_1_Y_SLOT, y)\n                }\n                // PROOF_QUOTIENT_POLY_PARTS_2\n                {\n                    let x := mod(calldataload(add(offset, 0x264)), Q_MOD)\n                    let y := mod(calldataload(add(offset, 0x284)), Q_MOD)\n                    let xx := mulmod(x, x, Q_MOD)\n                    isValid := and(eq(mulmod(y, y, Q_MOD), addmod(mulmod(x, xx, Q_MOD), 3, Q_MOD)), isValid)\n                    mstore(PROOF_QUOTIENT_POLY_PARTS_2_X_SLOT, x)\n                    mstore(PROOF_QUOTIENT_POLY_PARTS_2_Y_SLOT, y)\n                }\n                // PROOF_QUOTIENT_POLY_PARTS_3\n                {\n                    let x := mod(calldataload(add(offset, 0x2a4)), Q_MOD)\n                    let y := mod(calldataload(add(offset, 0x2c4)), Q_MOD)\n                    let xx := mulmod(x, x, Q_MOD)\n                    isValid := and(eq(mulmod(y, y, Q_MOD), addmod(mulmod(x, xx, Q_MOD), 3, Q_MOD)), isValid)\n                    mstore(PROOF_QUOTIENT_POLY_PARTS_3_X_SLOT, x)\n                    mstore(PROOF_QUOTIENT_POLY_PARTS_3_Y_SLOT, y)\n                }\n\n                mstore(PROOF_STATE_POLYS_0_OPENING_AT_Z_SLOT, mod(calldataload(add(offset, 0x2e4)), R_MOD))\n                mstore(PROOF_STATE_POLYS_1_OPENING_AT_Z_SLOT, mod(calldataload(add(offset, 0x304)), R_MOD))\n                mstore(PROOF_STATE_POLYS_2_OPENING_AT_Z_SLOT, mod(calldataload(add(offset, 0x324)), R_MOD))\n                mstore(PROOF_STATE_POLYS_3_OPENING_AT_Z_SLOT, mod(calldataload(add(offset, 0x344)), R_MOD))\n\n                mstore(PROOF_STATE_POLYS_3_OPENING_AT_Z_OMEGA_SLOT, mod(calldataload(add(offset, 0x364)), R_MOD))\n                mstore(PROOF_GATE_SELECTORS_0_OPENING_AT_Z_SLOT, mod(calldataload(add(offset, 0x384)), R_MOD))\n\n                mstore(PROOF_COPY_PERMUTATION_POLYS_0_OPENING_AT_Z_SLOT, mod(calldataload(add(offset, 0x3a4)), R_MOD))\n                mstore(PROOF_COPY_PERMUTATION_POLYS_1_OPENING_AT_Z_SLOT, mod(calldataload(add(offset, 0x3c4)), R_MOD))\n                mstore(PROOF_COPY_PERMUTATION_POLYS_2_OPENING_AT_Z_SLOT, mod(calldataload(add(offset, 0x3e4)), R_MOD))\n\n                mstore(\n                    PROOF_COPY_PERMUTATION_GRAND_PRODUCT_OPENING_AT_Z_OMEGA_SLOT,\n                    mod(calldataload(add(offset, 0x404)), R_MOD)\n                )\n                mstore(PROOF_LOOKUP_S_POLY_OPENING_AT_Z_OMEGA_SLOT, mod(calldataload(add(offset, 0x424)), R_MOD))\n                mstore(PROOF_LOOKUP_GRAND_PRODUCT_OPENING_AT_Z_OMEGA_SLOT, mod(calldataload(add(offset, 0x444)), R_MOD))\n                mstore(PROOF_LOOKUP_T_POLY_OPENING_AT_Z_SLOT, mod(calldataload(add(offset, 0x464)), R_MOD))\n                mstore(PROOF_LOOKUP_T_POLY_OPENING_AT_Z_OMEGA_SLOT, mod(calldataload(add(offset, 0x484)), R_MOD))\n                mstore(PROOF_LOOKUP_SELECTOR_POLY_OPENING_AT_Z_SLOT, mod(calldataload(add(offset, 0x4a4)), R_MOD))\n                mstore(PROOF_LOOKUP_TABLE_TYPE_POLY_OPENING_AT_Z_SLOT, mod(calldataload(add(offset, 0x4c4)), R_MOD))\n                mstore(PROOF_QUOTIENT_POLY_OPENING_AT_Z_SLOT, mod(calldataload(add(offset, 0x4e4)), R_MOD))\n                mstore(PROOF_LINEARISATION_POLY_OPENING_AT_Z_SLOT, mod(calldataload(add(offset, 0x504)), R_MOD))\n\n                // PROOF_OPENING_PROOF_AT_Z\n                {\n                    let x := mod(calldataload(add(offset, 0x524)), Q_MOD)\n                    let y := mod(calldataload(add(offset, 0x544)), Q_MOD)\n                    let xx := mulmod(x, x, Q_MOD)\n                    isValid := and(eq(mulmod(y, y, Q_MOD), addmod(mulmod(x, xx, Q_MOD), 3, Q_MOD)), isValid)\n                    mstore(PROOF_OPENING_PROOF_AT_Z_X_SLOT, x)\n                    mstore(PROOF_OPENING_PROOF_AT_Z_Y_SLOT, y)\n                }\n                // PROOF_OPENING_PROOF_AT_Z_OMEGA\n                {\n                    let x := mod(calldataload(add(offset, 0x564)), Q_MOD)\n                    let y := mod(calldataload(add(offset, 0x584)), Q_MOD)\n                    let xx := mulmod(x, x, Q_MOD)\n                    isValid := and(eq(mulmod(y, y, Q_MOD), addmod(mulmod(x, xx, Q_MOD), 3, Q_MOD)), isValid)\n                    mstore(PROOF_OPENING_PROOF_AT_Z_OMEGA_X_SLOT, x)\n                    mstore(PROOF_OPENING_PROOF_AT_Z_OMEGA_Y_SLOT, y)\n                }\n\n                // 3. Load the recursive part of the proof\n                if mload(VK_RECURSIVE_FLAG_SLOT) {\n                    // recursive part should be consist of 2 points\n\n                    // PROOF_RECURSIVE_PART_P1\n                    {\n                        let x := mod(calldataload(add(offset, 0x5a4)), Q_MOD)\n                        let y := mod(calldataload(add(offset, 0x5c4)), Q_MOD)\n                        let xx := mulmod(x, x, Q_MOD)\n                        isValid := and(eq(mulmod(y, y, Q_MOD), addmod(mulmod(x, xx, Q_MOD), 3, Q_MOD)), isValid)\n                        mstore(PROOF_RECURSIVE_PART_P1_X_SLOT, x)\n                        mstore(PROOF_RECURSIVE_PART_P1_Y_SLOT, y)\n                    }\n                    // PROOF_RECURSIVE_PART_P2\n                    {\n                        let x := mod(calldataload(add(offset, 0x5e4)), Q_MOD)\n                        let y := mod(calldataload(add(offset, 0x604)), Q_MOD)\n                        let xx := mulmod(x, x, Q_MOD)\n                        isValid := and(eq(mulmod(y, y, Q_MOD), addmod(mulmod(x, xx, Q_MOD), 3, Q_MOD)), isValid)\n                        mstore(PROOF_RECURSIVE_PART_P2_X_SLOT, x)\n                        mstore(PROOF_RECURSIVE_PART_P2_Y_SLOT, y)\n                    }\n                }\n\n                // Revert if a proof is not valid\n                if iszero(isValid) {\n                    revertWithMessage(27, \"loadProof: Proof is invalid\")\n                }\n            }\n\n            /*//////////////////////////////////////////////////////////////\n                                    2. Transcript initialization\n            //////////////////////////////////////////////////////////////*/\n\n            /// @notice Recomputes all challenges\n            /// @dev The process is the following:\n            /// Commit:   PI, [a], [b], [c], [d]\n            /// Get:      eta\n            /// Commit:   [s]\n            /// Get:      beta, gamma\n            /// Commit:   [z_perm]\n            /// Get:      beta', gamma'\n            /// Commit:   [z_lookup]\n            /// Get:      alpha\n            /// Commit:   [t_0], [t_1], [t_2], [t_3]\n            /// Get:      z\n            /// Commit:   t(z), a(z), b(z), c(z), d(z), d(z*omega),\n            ///           main_gate_selector(z),\n            ///           sigma_0(z), sigma_1(z), sigma_2(z),\n            ///           z_perm(z*omega),\n            ///           t(z), lookup_selector(z), table_type(z),\n            ///           s(x*omega), z_lookup(z*omega), t(z*omega),\n            ///           r(z)\n            /// Get:      v\n            /// Commit:   [W], [W']\n            /// Get:      u\n            function initializeTranscript() {\n                // Round 1\n                updateTranscript(mload(PROOF_PUBLIC_INPUT))\n                updateTranscript(mload(PROOF_STATE_POLYS_0_X_SLOT))\n                updateTranscript(mload(PROOF_STATE_POLYS_0_Y_SLOT))\n                updateTranscript(mload(PROOF_STATE_POLYS_1_X_SLOT))\n                updateTranscript(mload(PROOF_STATE_POLYS_1_Y_SLOT))\n                updateTranscript(mload(PROOF_STATE_POLYS_2_X_SLOT))\n                updateTranscript(mload(PROOF_STATE_POLYS_2_Y_SLOT))\n                updateTranscript(mload(PROOF_STATE_POLYS_3_X_SLOT))\n                updateTranscript(mload(PROOF_STATE_POLYS_3_Y_SLOT))\n\n                mstore(STATE_ETA_SLOT, getTranscriptChallenge(0))\n\n                // Round 1.5\n                updateTranscript(mload(PROOF_LOOKUP_S_POLY_X_SLOT))\n                updateTranscript(mload(PROOF_LOOKUP_S_POLY_Y_SLOT))\n\n                mstore(STATE_BETA_SLOT, getTranscriptChallenge(1))\n                mstore(STATE_GAMMA_SLOT, getTranscriptChallenge(2))\n\n                // Round 2\n                updateTranscript(mload(PROOF_COPY_PERMUTATION_GRAND_PRODUCT_X_SLOT))\n                updateTranscript(mload(PROOF_COPY_PERMUTATION_GRAND_PRODUCT_Y_SLOT))\n\n                mstore(STATE_BETA_LOOKUP_SLOT, getTranscriptChallenge(3))\n                mstore(STATE_GAMMA_LOOKUP_SLOT, getTranscriptChallenge(4))\n\n                // Round 2.5\n                updateTranscript(mload(PROOF_LOOKUP_GRAND_PRODUCT_X_SLOT))\n                updateTranscript(mload(PROOF_LOOKUP_GRAND_PRODUCT_Y_SLOT))\n\n                mstore(STATE_ALPHA_SLOT, getTranscriptChallenge(5))\n\n                // Round 3\n                updateTranscript(mload(PROOF_QUOTIENT_POLY_PARTS_0_X_SLOT))\n                updateTranscript(mload(PROOF_QUOTIENT_POLY_PARTS_0_Y_SLOT))\n                updateTranscript(mload(PROOF_QUOTIENT_POLY_PARTS_1_X_SLOT))\n                updateTranscript(mload(PROOF_QUOTIENT_POLY_PARTS_1_Y_SLOT))\n                updateTranscript(mload(PROOF_QUOTIENT_POLY_PARTS_2_X_SLOT))\n                updateTranscript(mload(PROOF_QUOTIENT_POLY_PARTS_2_Y_SLOT))\n                updateTranscript(mload(PROOF_QUOTIENT_POLY_PARTS_3_X_SLOT))\n                updateTranscript(mload(PROOF_QUOTIENT_POLY_PARTS_3_Y_SLOT))\n\n                {\n                    let z := getTranscriptChallenge(6)\n\n                    mstore(STATE_Z_SLOT, z)\n                    mstore(STATE_Z_IN_DOMAIN_SIZE, modexp(z, DOMAIN_SIZE))\n                }\n\n                // Round 4\n                updateTranscript(mload(PROOF_QUOTIENT_POLY_OPENING_AT_Z_SLOT))\n\n                updateTranscript(mload(PROOF_STATE_POLYS_0_OPENING_AT_Z_SLOT))\n                updateTranscript(mload(PROOF_STATE_POLYS_1_OPENING_AT_Z_SLOT))\n                updateTranscript(mload(PROOF_STATE_POLYS_2_OPENING_AT_Z_SLOT))\n                updateTranscript(mload(PROOF_STATE_POLYS_3_OPENING_AT_Z_SLOT))\n\n                updateTranscript(mload(PROOF_STATE_POLYS_3_OPENING_AT_Z_OMEGA_SLOT))\n                updateTranscript(mload(PROOF_GATE_SELECTORS_0_OPENING_AT_Z_SLOT))\n\n                updateTranscript(mload(PROOF_COPY_PERMUTATION_POLYS_0_OPENING_AT_Z_SLOT))\n                updateTranscript(mload(PROOF_COPY_PERMUTATION_POLYS_1_OPENING_AT_Z_SLOT))\n                updateTranscript(mload(PROOF_COPY_PERMUTATION_POLYS_2_OPENING_AT_Z_SLOT))\n\n                updateTranscript(mload(PROOF_COPY_PERMUTATION_GRAND_PRODUCT_OPENING_AT_Z_OMEGA_SLOT))\n                updateTranscript(mload(PROOF_LOOKUP_T_POLY_OPENING_AT_Z_SLOT))\n                updateTranscript(mload(PROOF_LOOKUP_SELECTOR_POLY_OPENING_AT_Z_SLOT))\n                updateTranscript(mload(PROOF_LOOKUP_TABLE_TYPE_POLY_OPENING_AT_Z_SLOT))\n                updateTranscript(mload(PROOF_LOOKUP_S_POLY_OPENING_AT_Z_OMEGA_SLOT))\n                updateTranscript(mload(PROOF_LOOKUP_GRAND_PRODUCT_OPENING_AT_Z_OMEGA_SLOT))\n                updateTranscript(mload(PROOF_LOOKUP_T_POLY_OPENING_AT_Z_OMEGA_SLOT))\n                updateTranscript(mload(PROOF_LINEARISATION_POLY_OPENING_AT_Z_SLOT))\n\n                mstore(STATE_V_SLOT, getTranscriptChallenge(7))\n\n                // Round 5\n                updateTranscript(mload(PROOF_OPENING_PROOF_AT_Z_X_SLOT))\n                updateTranscript(mload(PROOF_OPENING_PROOF_AT_Z_Y_SLOT))\n                updateTranscript(mload(PROOF_OPENING_PROOF_AT_Z_OMEGA_X_SLOT))\n                updateTranscript(mload(PROOF_OPENING_PROOF_AT_Z_OMEGA_Y_SLOT))\n\n                mstore(STATE_U_SLOT, getTranscriptChallenge(8))\n            }\n\n            /*//////////////////////////////////////////////////////////////\n                                    3. Verifying quotient evaluation\n            //////////////////////////////////////////////////////////////*/\n\n            /// @notice Compute linearisation polynomial's constant term: r_0\n            /// @dev To save a verifier scalar multiplication, we split linearisation polynomial\n            /// into its constant and non-constant terms. The constant term is computed with the formula:\n            ///\n            /// r_0 = alpha^0 * L_0(z) * PI * q_{main selector}(z) + r(z)         -- main gate contribution\n            ///\n            ///     - alpha^4 * z_perm(z*omega)(sigma_0(z) * beta + gamma + a(z)) \\\n            ///                           (sigma_1(z) * beta + gamma + b(z))      |\n            ///                           (sigma_2(z) * beta + gamma + c(z))      | - permutation contribution\n            ///                           (sigma_3(z) + gamma)                    |\n            ///     - alpha^5 * L_0(z)                                            /\n            ///\n            ///     + alpha^6 * (s(z*omega) * beta' + gamma' (beta' + 1))         \\\n            ///               * (z - omega^{n-1}) * z_lookup(z*omega)             | - lookup contribution\n            ///     - alpha^7 * L_0(z)                                            |\n            ///     - alpha^8 * L_{n-1}(z) * (gamma' (beta' + 1))^{n-1}           /\n            ///\n            /// In the end we should check that t(z)*Z_H(z) = r(z) + r_0!\n            function verifyQuotientEvaluation() {\n                // Compute power of alpha\n                {\n                    let alpha := mload(STATE_ALPHA_SLOT)\n                    let currentAlpha := mulmod(alpha, alpha, R_MOD)\n                    mstore(STATE_POWER_OF_ALPHA_2_SLOT, currentAlpha)\n                    currentAlpha := mulmod(currentAlpha, alpha, R_MOD)\n                    mstore(STATE_POWER_OF_ALPHA_3_SLOT, currentAlpha)\n                    currentAlpha := mulmod(currentAlpha, alpha, R_MOD)\n                    mstore(STATE_POWER_OF_ALPHA_4_SLOT, currentAlpha)\n                    currentAlpha := mulmod(currentAlpha, alpha, R_MOD)\n                    mstore(STATE_POWER_OF_ALPHA_5_SLOT, currentAlpha)\n                    currentAlpha := mulmod(currentAlpha, alpha, R_MOD)\n                    mstore(STATE_POWER_OF_ALPHA_6_SLOT, currentAlpha)\n                    currentAlpha := mulmod(currentAlpha, alpha, R_MOD)\n                    mstore(STATE_POWER_OF_ALPHA_7_SLOT, currentAlpha)\n                    currentAlpha := mulmod(currentAlpha, alpha, R_MOD)\n                    mstore(STATE_POWER_OF_ALPHA_8_SLOT, currentAlpha)\n                }\n\n                // z\n                let stateZ := mload(STATE_Z_SLOT)\n                // L_0(z)\n                mstore(STATE_L_0_AT_Z_SLOT, evaluateLagrangePolyOutOfDomain(0, stateZ))\n                // L_{n-1}(z)\n                mstore(STATE_L_N_MINUS_ONE_AT_Z_SLOT, evaluateLagrangePolyOutOfDomain(sub(DOMAIN_SIZE, 1), stateZ))\n                // L_0(z) * PI\n                let stateT := mulmod(mload(STATE_L_0_AT_Z_SLOT), mload(PROOF_PUBLIC_INPUT), R_MOD)\n\n                // Compute main gate contribution\n                let result := mulmod(stateT, mload(PROOF_GATE_SELECTORS_0_OPENING_AT_Z_SLOT), R_MOD)\n\n                // Compute permutation contribution\n                result := addmod(result, permutationQuotientContribution(), R_MOD)\n\n                // Compute lookup contribution\n                result := addmod(result, lookupQuotientContribution(), R_MOD)\n\n                // Check that r(z) + r_0 = t(z) * Z_H(z)\n                result := addmod(mload(PROOF_LINEARISATION_POLY_OPENING_AT_Z_SLOT), result, R_MOD)\n\n                let vanishing := addmod(mload(STATE_Z_IN_DOMAIN_SIZE), sub(R_MOD, 1), R_MOD)\n                let lhs := mulmod(mload(PROOF_QUOTIENT_POLY_OPENING_AT_Z_SLOT), vanishing, R_MOD)\n                if iszero(eq(lhs, result)) {\n                    revertWithMessage(27, \"invalid quotient evaluation\")\n                }\n            }\n\n            /// @notice Evaluating L_{polyNum}(at) out of domain\n            /// @dev L_i is a Lagrange polynomial for our domain such that:\n            /// L_i(omega^i) = 1 and L_i(omega^j) = 0 for all j != i\n            function evaluateLagrangePolyOutOfDomain(polyNum, at) -> res {\n                let omegaPower := 1\n                if polyNum {\n                    omegaPower := modexp(OMEGA, polyNum)\n                }\n\n                res := addmod(modexp(at, DOMAIN_SIZE), sub(R_MOD, 1), R_MOD)\n\n                // Vanishing polynomial can not be zero at point `at`\n                if iszero(res) {\n                    revertWithMessage(28, \"invalid vanishing polynomial\")\n                }\n                res := mulmod(res, omegaPower, R_MOD)\n                let denominator := addmod(at, sub(R_MOD, omegaPower), R_MOD)\n                denominator := mulmod(denominator, DOMAIN_SIZE, R_MOD)\n                denominator := modexp(denominator, sub(R_MOD, 2))\n                res := mulmod(res, denominator, R_MOD)\n            }\n\n            /// @notice Compute permutation contribution to linearisation polynomial's constant term\n            function permutationQuotientContribution() -> res {\n                // res = alpha^4 * z_perm(z*omega)\n                res := mulmod(\n                    mload(STATE_POWER_OF_ALPHA_4_SLOT),\n                    mload(PROOF_COPY_PERMUTATION_GRAND_PRODUCT_OPENING_AT_Z_OMEGA_SLOT),\n                    R_MOD\n                )\n\n                {\n                    let gamma := mload(STATE_GAMMA_SLOT)\n                    let beta := mload(STATE_BETA_SLOT)\n\n                    let factorMultiplier\n                    {\n                        // res *= sigma_0(z) * beta + gamma + a(z)\n                        factorMultiplier := mulmod(mload(PROOF_COPY_PERMUTATION_POLYS_0_OPENING_AT_Z_SLOT), beta, R_MOD)\n                        factorMultiplier := addmod(factorMultiplier, gamma, R_MOD)\n                        factorMultiplier := addmod(\n                            factorMultiplier,\n                            mload(PROOF_STATE_POLYS_0_OPENING_AT_Z_SLOT),\n                            R_MOD\n                        )\n                        res := mulmod(res, factorMultiplier, R_MOD)\n                    }\n                    {\n                        // res *= sigma_1(z) * beta + gamma + b(z)\n                        factorMultiplier := mulmod(mload(PROOF_COPY_PERMUTATION_POLYS_1_OPENING_AT_Z_SLOT), beta, R_MOD)\n                        factorMultiplier := addmod(factorMultiplier, gamma, R_MOD)\n                        factorMultiplier := addmod(\n                            factorMultiplier,\n                            mload(PROOF_STATE_POLYS_1_OPENING_AT_Z_SLOT),\n                            R_MOD\n                        )\n                        res := mulmod(res, factorMultiplier, R_MOD)\n                    }\n                    {\n                        // res *= sigma_2(z) * beta + gamma + c(z)\n                        factorMultiplier := mulmod(mload(PROOF_COPY_PERMUTATION_POLYS_2_OPENING_AT_Z_SLOT), beta, R_MOD)\n                        factorMultiplier := addmod(factorMultiplier, gamma, R_MOD)\n                        factorMultiplier := addmod(\n                            factorMultiplier,\n                            mload(PROOF_STATE_POLYS_2_OPENING_AT_Z_SLOT),\n                            R_MOD\n                        )\n                        res := mulmod(res, factorMultiplier, R_MOD)\n                    }\n\n                    // res *= sigma_3(z) + gamma\n                    res := mulmod(res, addmod(mload(PROOF_STATE_POLYS_3_OPENING_AT_Z_SLOT), gamma, R_MOD), R_MOD)\n                }\n\n                // res = -res\n                res := sub(R_MOD, res)\n\n                // -= L_0(z) * alpha^5\n                let l0AtZ := mload(STATE_L_0_AT_Z_SLOT)\n                l0AtZ := mulmod(l0AtZ, mload(STATE_POWER_OF_ALPHA_5_SLOT), R_MOD)\n                res := addmod(res, sub(R_MOD, l0AtZ), R_MOD)\n            }\n\n            /// @notice Compute lookup contribution to linearisation polynomial's constant term\n            function lookupQuotientContribution() -> res {\n                let betaLookup := mload(STATE_BETA_LOOKUP_SLOT)\n                let gammaLookup := mload(STATE_GAMMA_LOOKUP_SLOT)\n                let betaPlusOne := addmod(betaLookup, 1, R_MOD)\n                let betaGamma := mulmod(betaPlusOne, gammaLookup, R_MOD)\n\n                mstore(STATE_BETA_PLUS_ONE_SLOT, betaPlusOne)\n                mstore(STATE_BETA_GAMMA_PLUS_GAMMA_SLOT, betaGamma)\n\n                // res =  alpha^6 * (s(z*omega) * beta' + gamma' (beta' + 1)) * z_lookup(z*omega)\n                res := mulmod(mload(PROOF_LOOKUP_S_POLY_OPENING_AT_Z_OMEGA_SLOT), betaLookup, R_MOD)\n                res := addmod(res, betaGamma, R_MOD)\n                res := mulmod(res, mload(PROOF_LOOKUP_GRAND_PRODUCT_OPENING_AT_Z_OMEGA_SLOT), R_MOD)\n                res := mulmod(res, mload(STATE_POWER_OF_ALPHA_6_SLOT), R_MOD)\n\n                // res *= z - omega^{n-1}\n                {\n                    let lastOmega := modexp(OMEGA, sub(DOMAIN_SIZE, 1))\n                    let zMinusLastOmega := addmod(mload(STATE_Z_SLOT), sub(R_MOD, lastOmega), R_MOD)\n                    mstore(STATE_Z_MINUS_LAST_OMEGA_SLOT, zMinusLastOmega)\n                    res := mulmod(res, zMinusLastOmega, R_MOD)\n                }\n\n                // res -= alpha^7 * L_{0}(z)\n                {\n                    let intermediateValue := mulmod(\n                        mload(STATE_L_0_AT_Z_SLOT),\n                        mload(STATE_POWER_OF_ALPHA_7_SLOT),\n                        R_MOD\n                    )\n                    res := addmod(res, sub(R_MOD, intermediateValue), R_MOD)\n                }\n\n                // res -= alpha^8 * L_{n-1}(z) * (gamma' (beta' + 1))^{n-1}\n                {\n                    let lnMinusOneAtZ := mload(STATE_L_N_MINUS_ONE_AT_Z_SLOT)\n                    let betaGammaPowered := modexp(betaGamma, sub(DOMAIN_SIZE, 1))\n                    let alphaPower8 := mload(STATE_POWER_OF_ALPHA_8_SLOT)\n\n                    let subtrahend := mulmod(mulmod(lnMinusOneAtZ, betaGammaPowered, R_MOD), alphaPower8, R_MOD)\n                    res := addmod(res, sub(R_MOD, subtrahend), R_MOD)\n                }\n            }\n\n            /// @notice Compute main gate contribution to linearisation polynomial commitment multiplied by v\n            function mainGateLinearisationContributionWithV(\n                dest,\n                stateOpening0AtZ,\n                stateOpening1AtZ,\n                stateOpening2AtZ,\n                stateOpening3AtZ\n            ) {\n                // += a(z) * [q_a]\n                pointMulIntoDest(VK_GATE_SETUP_0_X_SLOT, stateOpening0AtZ, dest)\n                // += b(z) * [q_b]\n                pointMulAndAddIntoDest(VK_GATE_SETUP_1_X_SLOT, stateOpening1AtZ, dest)\n                // += c(z) * [q_c]\n                pointMulAndAddIntoDest(VK_GATE_SETUP_2_X_SLOT, stateOpening2AtZ, dest)\n                // += d(z) * [q_d]\n                pointMulAndAddIntoDest(VK_GATE_SETUP_3_X_SLOT, stateOpening3AtZ, dest)\n                // += a(z) * b(z) * [q_ab]\n                pointMulAndAddIntoDest(VK_GATE_SETUP_4_X_SLOT, mulmod(stateOpening0AtZ, stateOpening1AtZ, R_MOD), dest)\n                // += a(z) * c(z) * [q_ac]\n                pointMulAndAddIntoDest(VK_GATE_SETUP_5_X_SLOT, mulmod(stateOpening0AtZ, stateOpening2AtZ, R_MOD), dest)\n                // += [q_const]\n                pointAddAssign(dest, VK_GATE_SETUP_6_X_SLOT)\n                // += d(z*omega) * [q_{d_next}]\n                pointMulAndAddIntoDest(VK_GATE_SETUP_7_X_SLOT, mload(PROOF_STATE_POLYS_3_OPENING_AT_Z_OMEGA_SLOT), dest)\n\n                // *= v * main_gate_selector(z)\n                let coeff := mulmod(mload(PROOF_GATE_SELECTORS_0_OPENING_AT_Z_SLOT), mload(STATE_V_SLOT), R_MOD)\n                pointMulIntoDest(dest, coeff, dest)\n            }\n\n            /// @notice Compute custom gate contribution to linearisation polynomial commitment multiplied by v\n            function addAssignRescueCustomGateLinearisationContributionWithV(\n                dest,\n                stateOpening0AtZ,\n                stateOpening1AtZ,\n                stateOpening2AtZ,\n                stateOpening3AtZ\n            ) {\n                let accumulator\n                let intermediateValue\n                //  = alpha * (a(z)^2 - b(z))\n                accumulator := mulmod(stateOpening0AtZ, stateOpening0AtZ, R_MOD)\n                accumulator := addmod(accumulator, sub(R_MOD, stateOpening1AtZ), R_MOD)\n                accumulator := mulmod(accumulator, mload(STATE_ALPHA_SLOT), R_MOD)\n                // += alpha^2 * (b(z)^2 - c(z))\n                intermediateValue := mulmod(stateOpening1AtZ, stateOpening1AtZ, R_MOD)\n                intermediateValue := addmod(intermediateValue, sub(R_MOD, stateOpening2AtZ), R_MOD)\n                intermediateValue := mulmod(intermediateValue, mload(STATE_POWER_OF_ALPHA_2_SLOT), R_MOD)\n                accumulator := addmod(accumulator, intermediateValue, R_MOD)\n                // += alpha^3 * (c(z) * a(z) - d(z))\n                intermediateValue := mulmod(stateOpening2AtZ, stateOpening0AtZ, R_MOD)\n                intermediateValue := addmod(intermediateValue, sub(R_MOD, stateOpening3AtZ), R_MOD)\n                intermediateValue := mulmod(intermediateValue, mload(STATE_POWER_OF_ALPHA_3_SLOT), R_MOD)\n                accumulator := addmod(accumulator, intermediateValue, R_MOD)\n\n                // *= v * [custom_gate_selector]\n                accumulator := mulmod(accumulator, mload(STATE_V_SLOT), R_MOD)\n                pointMulAndAddIntoDest(VK_GATE_SELECTORS_1_X_SLOT, accumulator, dest)\n            }\n\n            /// @notice Compute copy-permutation contribution to linearisation polynomial commitment multiplied by v\n            function addAssignPermutationLinearisationContributionWithV(\n                dest,\n                stateOpening0AtZ,\n                stateOpening1AtZ,\n                stateOpening2AtZ,\n                stateOpening3AtZ\n            ) {\n                // alpha^4\n                let factor := mload(STATE_POWER_OF_ALPHA_4_SLOT)\n                // Calculate the factor\n                {\n                    // *= (a(z) + beta * z + gamma)\n                    let zMulBeta := mulmod(mload(STATE_Z_SLOT), mload(STATE_BETA_SLOT), R_MOD)\n                    let gamma := mload(STATE_GAMMA_SLOT)\n\n                    let intermediateValue := addmod(addmod(zMulBeta, gamma, R_MOD), stateOpening0AtZ, R_MOD)\n                    factor := mulmod(factor, intermediateValue, R_MOD)\n\n                    // (b(z) + beta * z * k0 + gamma)\n                    intermediateValue := addmod(\n                        addmod(mulmod(zMulBeta, NON_RESIDUES_0, R_MOD), gamma, R_MOD),\n                        stateOpening1AtZ,\n                        R_MOD\n                    )\n                    factor := mulmod(factor, intermediateValue, R_MOD)\n\n                    // (c(z) + beta * z * k1 + gamma)\n                    intermediateValue := addmod(\n                        addmod(mulmod(zMulBeta, NON_RESIDUES_1, R_MOD), gamma, R_MOD),\n                        stateOpening2AtZ,\n                        R_MOD\n                    )\n                    factor := mulmod(factor, intermediateValue, R_MOD)\n\n                    // (d(z) + beta * z * k2 + gamma)\n                    intermediateValue := addmod(\n                        addmod(mulmod(zMulBeta, NON_RESIDUES_2, R_MOD), gamma, R_MOD),\n                        stateOpening3AtZ,\n                        R_MOD\n                    )\n                    factor := mulmod(factor, intermediateValue, R_MOD)\n                }\n\n                // += alpha^5 * L_0(z)\n                let l0AtZ := mload(STATE_L_0_AT_Z_SLOT)\n                factor := addmod(factor, mulmod(l0AtZ, mload(STATE_POWER_OF_ALPHA_5_SLOT), R_MOD), R_MOD)\n\n                // Here we can optimize one scalar multiplication by aggregating coefficients near [z_perm] during\n                // computing [F]\n                // We will sum them and add and make one scalar multiplication: (coeff1 + coeff2) * [z_perm]\n                factor := mulmod(factor, mload(STATE_V_SLOT), R_MOD)\n                mstore(COPY_PERMUTATION_FIRST_AGGREGATED_COMMITMENT_COEFF, factor)\n\n                // alpha^4 * beta * z_perm(z*omega)\n                factor := mulmod(mload(STATE_POWER_OF_ALPHA_4_SLOT), mload(STATE_BETA_SLOT), R_MOD)\n                factor := mulmod(factor, mload(PROOF_COPY_PERMUTATION_GRAND_PRODUCT_OPENING_AT_Z_OMEGA_SLOT), R_MOD)\n                {\n                    // *= (a(z) + beta * sigma_0(z) + gamma)\n                    let beta := mload(STATE_BETA_SLOT)\n                    let gamma := mload(STATE_GAMMA_SLOT)\n\n                    let intermediateValue := addmod(\n                        addmod(\n                            mulmod(mload(PROOF_COPY_PERMUTATION_POLYS_0_OPENING_AT_Z_SLOT), beta, R_MOD),\n                            gamma,\n                            R_MOD\n                        ),\n                        stateOpening0AtZ,\n                        R_MOD\n                    )\n                    factor := mulmod(factor, intermediateValue, R_MOD)\n\n                    // *= (b(z) + beta * sigma_1(z) + gamma)\n                    intermediateValue := addmod(\n                        addmod(\n                            mulmod(mload(PROOF_COPY_PERMUTATION_POLYS_1_OPENING_AT_Z_SLOT), beta, R_MOD),\n                            gamma,\n                            R_MOD\n                        ),\n                        stateOpening1AtZ,\n                        R_MOD\n                    )\n                    factor := mulmod(factor, intermediateValue, R_MOD)\n\n                    // *= (c(z) + beta * sigma_2(z) + gamma)\n                    intermediateValue := addmod(\n                        addmod(\n                            mulmod(mload(PROOF_COPY_PERMUTATION_POLYS_2_OPENING_AT_Z_SLOT), beta, R_MOD),\n                            gamma,\n                            R_MOD\n                        ),\n                        stateOpening2AtZ,\n                        R_MOD\n                    )\n                    factor := mulmod(factor, intermediateValue, R_MOD)\n                }\n\n                // *= v * [sigma_3]\n                factor := mulmod(factor, mload(STATE_V_SLOT), R_MOD)\n                pointMulIntoDest(VK_PERMUTATION_3_X_SLOT, factor, QUERIES_BUFFER_POINT_SLOT)\n\n                pointSubAssign(dest, QUERIES_BUFFER_POINT_SLOT)\n            }\n\n            /// @notice Compute lookup contribution to linearisation polynomial commitment multiplied by v\n            function addAssignLookupLinearisationContributionWithV(\n                dest,\n                stateOpening0AtZ,\n                stateOpening1AtZ,\n                stateOpening2AtZ\n            ) {\n                // alpha^6 * v * z_lookup(z*omega) * (z - omega^{n-1}) * [s]\n                let factor := mload(PROOF_LOOKUP_GRAND_PRODUCT_OPENING_AT_Z_OMEGA_SLOT)\n                factor := mulmod(factor, mload(STATE_POWER_OF_ALPHA_6_SLOT), R_MOD)\n                factor := mulmod(factor, mload(STATE_Z_MINUS_LAST_OMEGA_SLOT), R_MOD)\n                factor := mulmod(factor, mload(STATE_V_SLOT), R_MOD)\n\n                // Here we can optimize one scalar multiplication by aggregating coefficients near [s] during\n                // computing [F]\n                // We will sum them and add and make one scalar multiplication: (coeff1 + coeff2) * [s]\n                mstore(LOOKUP_S_FIRST_AGGREGATED_COMMITMENT_COEFF, factor)\n\n                // gamma(1 + beta) + t(x) + beta * t(x*omega)\n                factor := mload(PROOF_LOOKUP_T_POLY_OPENING_AT_Z_OMEGA_SLOT)\n                factor := mulmod(factor, mload(STATE_BETA_LOOKUP_SLOT), R_MOD)\n                factor := addmod(factor, mload(PROOF_LOOKUP_T_POLY_OPENING_AT_Z_SLOT), R_MOD)\n                factor := addmod(factor, mload(STATE_BETA_GAMMA_PLUS_GAMMA_SLOT), R_MOD)\n\n                // *= (gamma + f(z))\n                // We should use fact that f(x) =\n                // lookup_selector(x) * (a(x) + eta * b(x) + eta^2 * c(x) + eta^3 * table_type(x))\n                // to restore f(z)\n                let fReconstructed\n                {\n                    fReconstructed := stateOpening0AtZ\n                    let eta := mload(STATE_ETA_SLOT)\n                    let currentEta := eta\n\n                    fReconstructed := addmod(fReconstructed, mulmod(currentEta, stateOpening1AtZ, R_MOD), R_MOD)\n                    currentEta := mulmod(currentEta, eta, R_MOD)\n                    fReconstructed := addmod(fReconstructed, mulmod(currentEta, stateOpening2AtZ, R_MOD), R_MOD)\n                    currentEta := mulmod(currentEta, eta, R_MOD)\n\n                    // add type of table\n                    fReconstructed := addmod(\n                        fReconstructed,\n                        mulmod(mload(PROOF_LOOKUP_TABLE_TYPE_POLY_OPENING_AT_Z_SLOT), currentEta, R_MOD),\n                        R_MOD\n                    )\n                    fReconstructed := mulmod(fReconstructed, mload(PROOF_LOOKUP_SELECTOR_POLY_OPENING_AT_Z_SLOT), R_MOD)\n                    fReconstructed := addmod(fReconstructed, mload(STATE_GAMMA_LOOKUP_SLOT), R_MOD)\n                }\n                // *= -alpha^6 * (beta + 1) * (z - omega^{n-1})\n                factor := mulmod(factor, fReconstructed, R_MOD)\n                factor := mulmod(factor, mload(STATE_BETA_PLUS_ONE_SLOT), R_MOD)\n                factor := sub(R_MOD, factor)\n                factor := mulmod(factor, mload(STATE_POWER_OF_ALPHA_6_SLOT), R_MOD)\n\n                factor := mulmod(factor, mload(STATE_Z_MINUS_LAST_OMEGA_SLOT), R_MOD)\n\n                // += alpha^7 * L_0(z)\n                factor := addmod(\n                    factor,\n                    mulmod(mload(STATE_L_0_AT_Z_SLOT), mload(STATE_POWER_OF_ALPHA_7_SLOT), R_MOD),\n                    R_MOD\n                )\n\n                // += alpha^8 * L_{n-1}(z)\n                factor := addmod(\n                    factor,\n                    mulmod(mload(STATE_L_N_MINUS_ONE_AT_Z_SLOT), mload(STATE_POWER_OF_ALPHA_8_SLOT), R_MOD),\n                    R_MOD\n                )\n\n                // Here we can optimize one scalar multiplication by aggregating coefficients near [z_lookup] during\n                // computing [F]\n                // We will sum them and add and make one scalar multiplication: (coeff1 + coeff2) * [z_lookup]\n                factor := mulmod(factor, mload(STATE_V_SLOT), R_MOD)\n                mstore(LOOKUP_GRAND_PRODUCT_FIRST_AGGREGATED_COMMITMENT_COEFF, factor)\n            }\n\n            /*//////////////////////////////////////////////////////////////\n                                    4. Prepare queries\n            //////////////////////////////////////////////////////////////*/\n\n            /// @dev Here we compute the first and second parts of batched polynomial commitment\n            /// We use the formula:\n            ///     [D0] = [t_0] + z^n * [t_1] + z^{2n} * [t_2] + z^{3n} * [t_3]\n            /// and\n            ///     [D1] = main_gate_selector(z) * (                                        \\\n            ///                a(z) * [q_a] + b(z) * [q_b] + c(z) * [q_c] + d(z) * [q_d] +  | - main gate contribution\n            ///                a(z) * b(z) * [q_ab] + a(z) * c(z) * [q_ac] +                |\n            ///                [q_const] + d(z*omega) * [q_{d_next}])                       /\n            ///\n            ///            + alpha * [custom_gate_selector] * (                             \\\n            ///                (a(z)^2 - b(z))              +                               | - custom gate contribution\n            ///                (b(z)^2 - c(z))    * alpha   +                               |\n            ///                (a(z)*c(z) - d(z)) * alpha^2 )                               /\n            ///\n            ///            + alpha^4 * [z_perm] *                                           \\\n            ///                (a(z) + beta * z      + gamma) *                             |\n            ///                (b(z) + beta * z * k0 + gamma) *                             |\n            ///                (c(z) + beta * z * k1 + gamma) *                             |\n            ///                (d(z) + beta * z * k2 + gamma)                               | - permutation contribution\n            ///            - alpha^4 * z_perm(z*omega) * beta * [sigma_3] *                 |\n            ///                (a(z) + beta * sigma_0(z) + gamma) *                         |\n            ///                (b(z) + beta * sigma_1(z) + gamma) *                         |\n            ///                (c(z) + beta * sigma_2(z) + gamma) *                         |\n            ///            + alpha^5 * L_0(z) * [z_perm]                                    /\n            ///\n            ///            - alpha^6 * (1 + beta') * (gamma' + f(z)) * (z - omega^{n-1}) *  \\\n            ///                (gamma'(1 + beta') + t(z) + beta' * t(z*omega)) * [z_lookup] |\n            ///            + alpha^6 * z_lookup(z*omega) * (z - omega^{n-1}) * [s]          | - lookup contribution\n            ///            + alpha^7 * L_0(z) * [z_lookup]                                  |\n            ///            + alpha^8 * L_{n-1}(z) * [z_lookup]                              /\n            function prepareQueries() {\n                // Calculate [D0]\n                {\n                    let zInDomainSize := mload(STATE_Z_IN_DOMAIN_SIZE)\n                    let currentZ := zInDomainSize\n\n                    mstore(QUERIES_AT_Z_0_X_SLOT, mload(PROOF_QUOTIENT_POLY_PARTS_0_X_SLOT))\n                    mstore(QUERIES_AT_Z_0_Y_SLOT, mload(PROOF_QUOTIENT_POLY_PARTS_0_Y_SLOT))\n\n                    pointMulAndAddIntoDest(PROOF_QUOTIENT_POLY_PARTS_1_X_SLOT, currentZ, QUERIES_AT_Z_0_X_SLOT)\n                    currentZ := mulmod(currentZ, zInDomainSize, R_MOD)\n\n                    pointMulAndAddIntoDest(PROOF_QUOTIENT_POLY_PARTS_2_X_SLOT, currentZ, QUERIES_AT_Z_0_X_SLOT)\n                    currentZ := mulmod(currentZ, zInDomainSize, R_MOD)\n\n                    pointMulAndAddIntoDest(PROOF_QUOTIENT_POLY_PARTS_3_X_SLOT, currentZ, QUERIES_AT_Z_0_X_SLOT)\n                }\n\n                // Calculate v * [D1]\n                // We are going to multiply all the points in the sum by v to save\n                // one scalar multiplication during [F] computation\n                {\n                    let stateOpening0AtZ := mload(PROOF_STATE_POLYS_0_OPENING_AT_Z_SLOT)\n                    let stateOpening1AtZ := mload(PROOF_STATE_POLYS_1_OPENING_AT_Z_SLOT)\n                    let stateOpening2AtZ := mload(PROOF_STATE_POLYS_2_OPENING_AT_Z_SLOT)\n                    let stateOpening3AtZ := mload(PROOF_STATE_POLYS_3_OPENING_AT_Z_SLOT)\n\n                    mainGateLinearisationContributionWithV(\n                        QUERIES_AT_Z_1_X_SLOT,\n                        stateOpening0AtZ,\n                        stateOpening1AtZ,\n                        stateOpening2AtZ,\n                        stateOpening3AtZ\n                    )\n\n                    addAssignRescueCustomGateLinearisationContributionWithV(\n                        QUERIES_AT_Z_1_X_SLOT,\n                        stateOpening0AtZ,\n                        stateOpening1AtZ,\n                        stateOpening2AtZ,\n                        stateOpening3AtZ\n                    )\n\n                    addAssignPermutationLinearisationContributionWithV(\n                        QUERIES_AT_Z_1_X_SLOT,\n                        stateOpening0AtZ,\n                        stateOpening1AtZ,\n                        stateOpening2AtZ,\n                        stateOpening3AtZ\n                    )\n\n                    addAssignLookupLinearisationContributionWithV(\n                        QUERIES_AT_Z_1_X_SLOT,\n                        stateOpening0AtZ,\n                        stateOpening1AtZ,\n                        stateOpening2AtZ\n                    )\n                }\n\n                // Also we should restore [t] for future computations\n                // [t] = [col_0] + eta*[col_1] + eta^2*[col_2] + eta^3*[col_3]\n                {\n                    mstore(QUERIES_T_POLY_AGGREGATED_X_SLOT, mload(VK_LOOKUP_TABLE_0_X_SLOT))\n                    mstore(QUERIES_T_POLY_AGGREGATED_Y_SLOT, mload(VK_LOOKUP_TABLE_0_Y_SLOT))\n\n                    let eta := mload(STATE_ETA_SLOT)\n                    let currentEta := eta\n\n                    pointMulAndAddIntoDest(VK_LOOKUP_TABLE_1_X_SLOT, currentEta, QUERIES_T_POLY_AGGREGATED_X_SLOT)\n                    currentEta := mulmod(currentEta, eta, R_MOD)\n\n                    pointMulAndAddIntoDest(VK_LOOKUP_TABLE_2_X_SLOT, currentEta, QUERIES_T_POLY_AGGREGATED_X_SLOT)\n                    currentEta := mulmod(currentEta, eta, R_MOD)\n\n                    pointMulAndAddIntoDest(VK_LOOKUP_TABLE_3_X_SLOT, currentEta, QUERIES_T_POLY_AGGREGATED_X_SLOT)\n                }\n            }\n\n            /*//////////////////////////////////////////////////////////////\n                                    5. Prepare aggregated commitment\n            //////////////////////////////////////////////////////////////*/\n\n            /// @dev Here we compute aggregated commitment for the final pairing\n            /// We use the formula:\n            /// [E] = ( t(z) + v * r(z)\n            ///       + v^2*a(z) + v^3*b(z) + v^4*c(z) + v^5*d(z)\n            ///       + v^6*main_gate_selector(z)\n            ///       + v^7*sigma_0(z) + v^8*sigma_1(z) + v^9*sigma_2(z)\n            ///       + v^10*t(z) + v^11*lookup_selector(z) + v^12*table_type(z)\n            ///       + u * (v^13*z_perm(z*omega) + v^14*d(z*omega)\n            ///           + v^15*s(z*omega) + v^16*z_lookup(z*omega) + v^17*t(z*omega)\n            ///       )\n            ///  ) * [1]\n            /// and\n            /// [F] = [D0] + v * [D1]\n            ///       + v^2*[a] + v^3*[b] + v^4*[c] + v^5*[d]\n            ///       + v^6*[main_gate_selector]\n            ///       + v^7*[sigma_0] + v^8*[sigma_1] + v^9*[sigma_2]\n            ///       + v^10*[t] + v^11*[lookup_selector] + v^12*[table_type]\n            ///       + u * ( v^13*[z_perm] + v^14*[d]\n            ///           + v^15*[s] + v^16*[z_lookup] + v^17*[t]\n            ///       )\n            function prepareAggregatedCommitment() {\n                // Here we compute parts of [E] and [F] without u multiplier\n                let aggregationChallenge := 1\n                let firstDCoeff\n                let firstTCoeff\n\n                mstore(AGGREGATED_AT_Z_X_SLOT, mload(QUERIES_AT_Z_0_X_SLOT))\n                mstore(AGGREGATED_AT_Z_Y_SLOT, mload(QUERIES_AT_Z_0_Y_SLOT))\n                let aggregatedOpeningAtZ := mload(PROOF_QUOTIENT_POLY_OPENING_AT_Z_SLOT)\n                {\n                    function updateAggregationChallenge(\n                        queriesCommitmentPoint,\n                        valueAtZ,\n                        curAggregationChallenge,\n                        curAggregatedOpeningAtZ\n                    ) -> newAggregationChallenge, newAggregatedOpeningAtZ {\n                        newAggregationChallenge := mulmod(curAggregationChallenge, mload(STATE_V_SLOT), R_MOD)\n                        pointMulAndAddIntoDest(queriesCommitmentPoint, newAggregationChallenge, AGGREGATED_AT_Z_X_SLOT)\n                        newAggregatedOpeningAtZ := addmod(\n                            curAggregatedOpeningAtZ,\n                            mulmod(newAggregationChallenge, mload(valueAtZ), R_MOD),\n                            R_MOD\n                        )\n                    }\n\n                    // We don't need to multiply by v, because we have already computed v * [D1]\n                    pointAddIntoDest(AGGREGATED_AT_Z_X_SLOT, QUERIES_AT_Z_1_X_SLOT, AGGREGATED_AT_Z_X_SLOT)\n                    aggregationChallenge := mulmod(aggregationChallenge, mload(STATE_V_SLOT), R_MOD)\n                    aggregatedOpeningAtZ := addmod(\n                        aggregatedOpeningAtZ,\n                        mulmod(aggregationChallenge, mload(PROOF_LINEARISATION_POLY_OPENING_AT_Z_SLOT), R_MOD),\n                        R_MOD\n                    )\n\n                    aggregationChallenge, aggregatedOpeningAtZ := updateAggregationChallenge(\n                        PROOF_STATE_POLYS_0_X_SLOT,\n                        PROOF_STATE_POLYS_0_OPENING_AT_Z_SLOT,\n                        aggregationChallenge,\n                        aggregatedOpeningAtZ\n                    )\n                    aggregationChallenge, aggregatedOpeningAtZ := updateAggregationChallenge(\n                        PROOF_STATE_POLYS_1_X_SLOT,\n                        PROOF_STATE_POLYS_1_OPENING_AT_Z_SLOT,\n                        aggregationChallenge,\n                        aggregatedOpeningAtZ\n                    )\n                    aggregationChallenge, aggregatedOpeningAtZ := updateAggregationChallenge(\n                        PROOF_STATE_POLYS_2_X_SLOT,\n                        PROOF_STATE_POLYS_2_OPENING_AT_Z_SLOT,\n                        aggregationChallenge,\n                        aggregatedOpeningAtZ\n                    )\n\n                    // Here we can optimize one scalar multiplication by aggregating coefficients near [d]\n                    // We will sum them and add and make one scalar multiplication: (coeff1 + coeff2) * [d]\n                    aggregationChallenge := mulmod(aggregationChallenge, mload(STATE_V_SLOT), R_MOD)\n                    firstDCoeff := aggregationChallenge\n                    aggregatedOpeningAtZ := addmod(\n                        aggregatedOpeningAtZ,\n                        mulmod(aggregationChallenge, mload(PROOF_STATE_POLYS_3_OPENING_AT_Z_SLOT), R_MOD),\n                        R_MOD\n                    )\n\n                    aggregationChallenge, aggregatedOpeningAtZ := updateAggregationChallenge(\n                        VK_GATE_SELECTORS_0_X_SLOT,\n                        PROOF_GATE_SELECTORS_0_OPENING_AT_Z_SLOT,\n                        aggregationChallenge,\n                        aggregatedOpeningAtZ\n                    )\n                    aggregationChallenge, aggregatedOpeningAtZ := updateAggregationChallenge(\n                        VK_PERMUTATION_0_X_SLOT,\n                        PROOF_COPY_PERMUTATION_POLYS_0_OPENING_AT_Z_SLOT,\n                        aggregationChallenge,\n                        aggregatedOpeningAtZ\n                    )\n                    aggregationChallenge, aggregatedOpeningAtZ := updateAggregationChallenge(\n                        VK_PERMUTATION_1_X_SLOT,\n                        PROOF_COPY_PERMUTATION_POLYS_1_OPENING_AT_Z_SLOT,\n                        aggregationChallenge,\n                        aggregatedOpeningAtZ\n                    )\n                    aggregationChallenge, aggregatedOpeningAtZ := updateAggregationChallenge(\n                        VK_PERMUTATION_2_X_SLOT,\n                        PROOF_COPY_PERMUTATION_POLYS_2_OPENING_AT_Z_SLOT,\n                        aggregationChallenge,\n                        aggregatedOpeningAtZ\n                    )\n\n                    // Here we can optimize one scalar multiplication by aggregating coefficients near [t]\n                    // We will sum them and add and make one scalar multiplication: (coeff1 + coeff2) * [t]\n                    aggregationChallenge := mulmod(aggregationChallenge, mload(STATE_V_SLOT), R_MOD)\n                    firstTCoeff := aggregationChallenge\n                    aggregatedOpeningAtZ := addmod(\n                        aggregatedOpeningAtZ,\n                        mulmod(aggregationChallenge, mload(PROOF_LOOKUP_T_POLY_OPENING_AT_Z_SLOT), R_MOD),\n                        R_MOD\n                    )\n\n                    aggregationChallenge, aggregatedOpeningAtZ := updateAggregationChallenge(\n                        VK_LOOKUP_SELECTOR_X_SLOT,\n                        PROOF_LOOKUP_SELECTOR_POLY_OPENING_AT_Z_SLOT,\n                        aggregationChallenge,\n                        aggregatedOpeningAtZ\n                    )\n                    aggregationChallenge, aggregatedOpeningAtZ := updateAggregationChallenge(\n                        VK_LOOKUP_TABLE_TYPE_X_SLOT,\n                        PROOF_LOOKUP_TABLE_TYPE_POLY_OPENING_AT_Z_SLOT,\n                        aggregationChallenge,\n                        aggregatedOpeningAtZ\n                    )\n                }\n                mstore(AGGREGATED_OPENING_AT_Z_SLOT, aggregatedOpeningAtZ)\n\n                // Here we compute parts of [E] and [F] with u multiplier\n                aggregationChallenge := mulmod(aggregationChallenge, mload(STATE_V_SLOT), R_MOD)\n\n                let copyPermutationCoeff := addmod(\n                    mload(COPY_PERMUTATION_FIRST_AGGREGATED_COMMITMENT_COEFF),\n                    mulmod(aggregationChallenge, mload(STATE_U_SLOT), R_MOD),\n                    R_MOD\n                )\n\n                pointMulIntoDest(\n                    PROOF_COPY_PERMUTATION_GRAND_PRODUCT_X_SLOT,\n                    copyPermutationCoeff,\n                    AGGREGATED_AT_Z_OMEGA_X_SLOT\n                )\n                let aggregatedOpeningAtZOmega := mulmod(\n                    mload(PROOF_COPY_PERMUTATION_GRAND_PRODUCT_OPENING_AT_Z_OMEGA_SLOT),\n                    aggregationChallenge,\n                    R_MOD\n                )\n\n                {\n                    function updateAggregationChallenge(\n                        queriesCommitmentPoint,\n                        valueAtZ_Omega,\n                        previousCoeff,\n                        curAggregationChallenge,\n                        curAggregatedOpeningAtZ_Omega\n                    ) -> newAggregationChallenge, newAggregatedOpeningAtZ_Omega {\n                        newAggregationChallenge := mulmod(curAggregationChallenge, mload(STATE_V_SLOT), R_MOD)\n                        let finalCoeff := addmod(\n                            previousCoeff,\n                            mulmod(newAggregationChallenge, mload(STATE_U_SLOT), R_MOD),\n                            R_MOD\n                        )\n                        pointMulAndAddIntoDest(queriesCommitmentPoint, finalCoeff, AGGREGATED_AT_Z_OMEGA_X_SLOT)\n                        newAggregatedOpeningAtZ_Omega := addmod(\n                            curAggregatedOpeningAtZ_Omega,\n                            mulmod(newAggregationChallenge, mload(valueAtZ_Omega), R_MOD),\n                            R_MOD\n                        )\n                    }\n\n                    aggregationChallenge, aggregatedOpeningAtZOmega := updateAggregationChallenge(\n                        PROOF_STATE_POLYS_3_X_SLOT,\n                        PROOF_STATE_POLYS_3_OPENING_AT_Z_OMEGA_SLOT,\n                        firstDCoeff,\n                        aggregationChallenge,\n                        aggregatedOpeningAtZOmega\n                    )\n                    aggregationChallenge, aggregatedOpeningAtZOmega := updateAggregationChallenge(\n                        PROOF_LOOKUP_S_POLY_X_SLOT,\n                        PROOF_LOOKUP_S_POLY_OPENING_AT_Z_OMEGA_SLOT,\n                        mload(LOOKUP_S_FIRST_AGGREGATED_COMMITMENT_COEFF),\n                        aggregationChallenge,\n                        aggregatedOpeningAtZOmega\n                    )\n                    aggregationChallenge, aggregatedOpeningAtZOmega := updateAggregationChallenge(\n                        PROOF_LOOKUP_GRAND_PRODUCT_X_SLOT,\n                        PROOF_LOOKUP_GRAND_PRODUCT_OPENING_AT_Z_OMEGA_SLOT,\n                        mload(LOOKUP_GRAND_PRODUCT_FIRST_AGGREGATED_COMMITMENT_COEFF),\n                        aggregationChallenge,\n                        aggregatedOpeningAtZOmega\n                    )\n                    aggregationChallenge, aggregatedOpeningAtZOmega := updateAggregationChallenge(\n                        QUERIES_T_POLY_AGGREGATED_X_SLOT,\n                        PROOF_LOOKUP_T_POLY_OPENING_AT_Z_OMEGA_SLOT,\n                        firstTCoeff,\n                        aggregationChallenge,\n                        aggregatedOpeningAtZOmega\n                    )\n                }\n                mstore(AGGREGATED_OPENING_AT_Z_OMEGA_SLOT, aggregatedOpeningAtZOmega)\n\n                // Now we can merge both parts and get [E] and [F]\n                let u := mload(STATE_U_SLOT)\n\n                // [F]\n                pointAddIntoDest(\n                    AGGREGATED_AT_Z_X_SLOT,\n                    AGGREGATED_AT_Z_OMEGA_X_SLOT,\n                    PAIRING_PAIR_WITH_GENERATOR_X_SLOT\n                )\n\n                // [E] = (aggregatedOpeningAtZ + u * aggregatedOpeningAtZOmega) * [1]\n                let aggregatedValue := addmod(\n                    mulmod(mload(AGGREGATED_OPENING_AT_Z_OMEGA_SLOT), u, R_MOD),\n                    mload(AGGREGATED_OPENING_AT_Z_SLOT),\n                    R_MOD\n                )\n\n                mstore(PAIRING_BUFFER_POINT_X_SLOT, 1)\n                mstore(PAIRING_BUFFER_POINT_Y_SLOT, 2)\n                pointMulIntoDest(PAIRING_BUFFER_POINT_X_SLOT, aggregatedValue, PAIRING_BUFFER_POINT_X_SLOT)\n            }\n\n            /*//////////////////////////////////////////////////////////////\n                                    5. Pairing\n            //////////////////////////////////////////////////////////////*/\n\n            /// @notice Checks the final pairing\n            /// @dev We should check the equation:\n            /// e([W] + u * [W'], [x]_2) = e(z * [W] + u * z * omega * [W'] + [F] - [E], [1]_2),\n            /// where [F] and [E] were computed previously\n            ///\n            /// Also we need to check that e([P1], [x]_2) = e([P2], [1]_2)\n            /// if we have the recursive part of the proof\n            /// where [P1] and [P2] are parts of the recursive proof\n            ///\n            /// We can aggregate both pairings into one for gas optimization:\n            /// e([W] + u * [W'] + u^2 * [P1], [x]_2) =\n            /// e(z * [W] + u * z * omega * [W'] + [F] - [E] + u^2 * [P2], [1]_2)\n            ///\n            /// u is a valid challenge for such aggregation,\n            /// because [P1] and [P2] are used in PI\n            function finalPairing() {\n                let u := mload(STATE_U_SLOT)\n                let z := mload(STATE_Z_SLOT)\n                let zOmega := mulmod(mload(STATE_Z_SLOT), OMEGA, R_MOD)\n\n                // [F] - [E]\n                pointSubAssign(PAIRING_PAIR_WITH_GENERATOR_X_SLOT, PAIRING_BUFFER_POINT_X_SLOT)\n\n                // +z * [W] + u * z * omega * [W']\n                pointMulAndAddIntoDest(PROOF_OPENING_PROOF_AT_Z_X_SLOT, z, PAIRING_PAIR_WITH_GENERATOR_X_SLOT)\n                pointMulAndAddIntoDest(\n                    PROOF_OPENING_PROOF_AT_Z_OMEGA_X_SLOT,\n                    mulmod(zOmega, u, R_MOD),\n                    PAIRING_PAIR_WITH_GENERATOR_X_SLOT\n                )\n\n                // [W] + u * [W']\n                mstore(PAIRING_PAIR_WITH_X_X_SLOT, mload(PROOF_OPENING_PROOF_AT_Z_X_SLOT))\n                mstore(PAIRING_PAIR_WITH_X_Y_SLOT, mload(PROOF_OPENING_PROOF_AT_Z_Y_SLOT))\n                pointMulAndAddIntoDest(PROOF_OPENING_PROOF_AT_Z_OMEGA_X_SLOT, u, PAIRING_PAIR_WITH_X_X_SLOT)\n                pointNegate(PAIRING_PAIR_WITH_X_X_SLOT)\n\n                // Add recursive proof part if needed\n                if mload(VK_RECURSIVE_FLAG_SLOT) {\n                    let uu := mulmod(u, u, R_MOD)\n                    pointMulAndAddIntoDest(PROOF_RECURSIVE_PART_P1_X_SLOT, uu, PAIRING_PAIR_WITH_GENERATOR_X_SLOT)\n                    pointMulAndAddIntoDest(PROOF_RECURSIVE_PART_P2_X_SLOT, uu, PAIRING_PAIR_WITH_X_X_SLOT)\n                }\n\n                // Calculate pairing\n                {\n                    mstore(0x000, mload(PAIRING_PAIR_WITH_GENERATOR_X_SLOT))\n                    mstore(0x020, mload(PAIRING_PAIR_WITH_GENERATOR_Y_SLOT))\n\n                    mstore(0x040, G2_ELEMENTS_0_X1)\n                    mstore(0x060, G2_ELEMENTS_0_X2)\n                    mstore(0x080, G2_ELEMENTS_0_Y1)\n                    mstore(0x0a0, G2_ELEMENTS_0_Y2)\n\n                    mstore(0x0c0, mload(PAIRING_PAIR_WITH_X_X_SLOT))\n                    mstore(0x0e0, mload(PAIRING_PAIR_WITH_X_Y_SLOT))\n\n                    mstore(0x100, G2_ELEMENTS_1_X1)\n                    mstore(0x120, G2_ELEMENTS_1_X2)\n                    mstore(0x140, G2_ELEMENTS_1_Y1)\n                    mstore(0x160, G2_ELEMENTS_1_Y2)\n\n                    let success := staticcall(gas(), 8, 0, 0x180, 0x00, 0x20)\n                    if iszero(success) {\n                        revertWithMessage(32, \"finalPairing: precompile failure\")\n                    }\n                    if iszero(mload(0)) {\n                        revertWithMessage(29, \"finalPairing: pairing failure\")\n                    }\n                }\n            }\n\n            /*//////////////////////////////////////////////////////////////\n                                    Verification\n            //////////////////////////////////////////////////////////////*/\n\n            // Step 1: Load the proof and check the correctness of its parts\n            loadProof()\n\n            // Step 2: Recompute all the challenges with the transcript\n            initializeTranscript()\n\n            // Step 3: Check the quotient equality\n            verifyQuotientEvaluation()\n\n            // Step 4: Compute queries [D0] and v * [D1]\n            prepareQueries()\n\n            // Step 5: Compute [E] and [F]\n            prepareAggregatedCommitment()\n\n            // Step 6: Check the final pairing with aggregated recursive proof\n            finalPairing()\n\n            mstore(0, true)\n            return(0, 32)\n        }\n    }\n}\n","deployed_bytecode":"0x608060405234801561000f575f5ffd5b5060043610610034575f3560e01c80639e8945d214610038578063b864f5a914610053575b5f5ffd5b610040610076565b6040519081526020015b60405180910390f35b6100666100613660046142aa565b610654565b604051901515815260200161004a565b5f6106497f0b4a9f5342e7afd12f0cf9e05570c9a093f0bd7cb7b78c81bf1544cb5da85b62610200527f21eb82b2d4977e4c485af279bca5c883d086e4ea1ecd00920edf7d946a650995610220527f280e3c42287d88240208d3fd01cc10690f13a6d7da1fa42a4011ee9256ac104f610240527f15dc080b2cb32132e40858645657e6b420eb468330fe66956cd03ba85bacaed4610260527f2069c413c319dd35062fa2baf6bdd6fa389f8dad854c60263d28eab3853a121c610280527f01b890b5228208ffc081f6123071ec48d4df9be9e6621381f4a3c0b2fd4c40aa6102a0527f10f3e708f45ca2efdec8841e5269243fe198c0ee52800332cdce8667bc1dc9696102c0527f2528663d1ef8e4f361da7b8731dad691ae589374ac614c1c5d1346f9e43fb5b66102e0527f07c075fea3d01d8a8ea4118b3ba844f1780f3e4071dbb62a72f33a3c85a9071f610300527f3036edf95d2870c750d7aa482c7b4c846bc1c2cbaca785d65ef0c19be2060c29610320527f302c28931968d9b0a7123b271164a047449bac619040613232e22cc826718123610340527f1011a5c84cc8cc01327e01e0fab0816a62657f7ca662b39da403b27ed1fb32ae610360527f29f5372d67002cf1b03c4b90ba0892fb4067727e6e62556d3385f7ce080c6dbc610380527f0a63248741589563e58fc34ea7ba84ac9bf4c8c8fed393c53fe76225e49f086a6103a0527f0439082913a1028f27fd9297e93291e707c66f203bc26904872dd3e17f354ab06103c0527f275078ab02afe9e191a023899a0d664819219a1a11a71df9bdc16deeb59357cd6103e0527f2b67cbcea5d975f37dafccfdacde7ae4676966cf346060b46d8c31895cd38a31610400527f1df1d2b75d5e00c4cc9ed981167e1895a74ef9a21f2253aa350c195bd7af3f5f610420527f132e3968e05ce8a19671de377801c2255c018fbc07a81625fa7b4366e0c7374f610440527f078307dbab33a8bf744787e3fd5edd7e5e183e8e8f6b11785bc01150c6e3c857610460527f22a848812e5f1fd2574b256adea75f6b29ac39d6e164535e20441b7a92e6d720610480527f06073f25cf0516c9964f5c50daafb5237f6c1fa553a47f3469fb89257168c6746104a0527f0c994cf1008a34dfac4e6cb410cacd3da3d5da38dfed7415be22d126a27348e86104c0527f23ae45e176417d3ea51607c5a7640cbe2b3ff7fdf68ca435b61c86b88f0196ca6104e0527f0e316b80565bacbb6e15df912e35ed2118659f623b55d24ed700944a85a47a55610500527f1e2be7f209a8e0f8d9994cbda5c7202e1dde2a04883f3055fa4b85be079d4baa610520527f150fc6bea1e744b30d5b150e3be4e6d16ecc89de29eef2ffaaf7797cc7ceca2a610540527f2f0b5208404ab77741d24815423f45c8fe0757233433b3a41bc90b1b4fc9ff60610560527f2c513ed74d9d57a5ec901e074032741036353a2c4513422e96e7b53b302d765b6105c0527f04dd964427e430f16004076d708c0cb21e225056cc1d57418cfbd3d4729814686105e0527f1ea83e5e65c6f8068f4677e2911678cf329b28259642a32db1f14b8347828aac610600527f1d22bc884a2da4962a893ba8de13f57aaeb785ed52c5e686994839cab8f7475d610620527f0b2e7212d0d9cff26d0bdf3d79b2cac029a25dfeb1cafdf49e2349d7db348d89610640527f1301f9b252419ea240eb67fda720ca0b16d92364027285f95e9b1349490fa283610660527f02f7b99fdfa5b418548c2d777785820e02383cfc87e7085e280a375a358153bf610680527f09d004fe08dc4d19c382df36fad22ef676185663543703e6a4b40203e50fd8a66106a0527f2ac4721a65816699ae0aaad6c38ee4756fdecc3e9b6844f1b70cb4e35e841a4f610580527f03995224b6215f409c81c7155c0373fb14c58e1c08589894168da61111eb981b6105a0527f155ac28b6e9ca210d38a17d7d71b20b0d539b503c7a5c9e222e3e11363cf200c6106c0527f130de19edf9381111ec6d004656571a8da719e3057b3902b52e01d062e4672406106e0525f61070052565b506105206102002090565b5f610c277f0b4a9f5342e7afd12f0cf9e05570c9a093f0bd7cb7b78c81bf1544cb5da85b62610200527f21eb82b2d4977e4c485af279bca5c883d086e4ea1ecd00920edf7d946a650995610220527f280e3c42287d88240208d3fd01cc10690f13a6d7da1fa42a4011ee9256ac104f610240527f15dc080b2cb32132e40858645657e6b420eb468330fe66956cd03ba85bacaed4610260527f2069c413c319dd35062fa2baf6bdd6fa389f8dad854c60263d28eab3853a121c610280527f01b890b5228208ffc081f6123071ec48d4df9be9e6621381f4a3c0b2fd4c40aa6102a0527f10f3e708f45ca2efdec8841e5269243fe198c0ee52800332cdce8667bc1dc9696102c0527f2528663d1ef8e4f361da7b8731dad691ae589374ac614c1c5d1346f9e43fb5b66102e0527f07c075fea3d01d8a8ea4118b3ba844f1780f3e4071dbb62a72f33a3c85a9071f610300527f3036edf95d2870c750d7aa482c7b4c846bc1c2cbaca785d65ef0c19be2060c29610320527f302c28931968d9b0a7123b271164a047449bac619040613232e22cc826718123610340527f1011a5c84cc8cc01327e01e0fab0816a62657f7ca662b39da403b27ed1fb32ae610360527f29f5372d67002cf1b03c4b90ba0892fb4067727e6e62556d3385f7ce080c6dbc610380527f0a63248741589563e58fc34ea7ba84ac9bf4c8c8fed393c53fe76225e49f086a6103a0527f0439082913a1028f27fd9297e93291e707c66f203bc26904872dd3e17f354ab06103c0527f275078ab02afe9e191a023899a0d664819219a1a11a71df9bdc16deeb59357cd6103e0527f2b67cbcea5d975f37dafccfdacde7ae4676966cf346060b46d8c31895cd38a31610400527f1df1d2b75d5e00c4cc9ed981167e1895a74ef9a21f2253aa350c195bd7af3f5f610420527f132e3968e05ce8a19671de377801c2255c018fbc07a81625fa7b4366e0c7374f610440527f078307dbab33a8bf744787e3fd5edd7e5e183e8e8f6b11785bc01150c6e3c857610460527f22a848812e5f1fd2574b256adea75f6b29ac39d6e164535e20441b7a92e6d720610480527f06073f25cf0516c9964f5c50daafb5237f6c1fa553a47f3469fb89257168c6746104a0527f0c994cf1008a34dfac4e6cb410cacd3da3d5da38dfed7415be22d126a27348e86104c0527f23ae45e176417d3ea51607c5a7640cbe2b3ff7fdf68ca435b61c86b88f0196ca6104e0527f0e316b80565bacbb6e15df912e35ed2118659f623b55d24ed700944a85a47a55610500527f1e2be7f209a8e0f8d9994cbda5c7202e1dde2a04883f3055fa4b85be079d4baa610520527f150fc6bea1e744b30d5b150e3be4e6d16ecc89de29eef2ffaaf7797cc7ceca2a610540527f2f0b5208404ab77741d24815423f45c8fe0757233433b3a41bc90b1b4fc9ff60610560527f2c513ed74d9d57a5ec901e074032741036353a2c4513422e96e7b53b302d765b6105c0527f04dd964427e430f16004076d708c0cb21e225056cc1d57418cfbd3d4729814686105e0527f1ea83e5e65c6f8068f4677e2911678cf329b28259642a32db1f14b8347828aac610600527f1d22bc884a2da4962a893ba8de13f57aaeb785ed52c5e686994839cab8f7475d610620527f0b2e7212d0d9cff26d0bdf3d79b2cac029a25dfeb1cafdf49e2349d7db348d89610640527f1301f9b252419ea240eb67fda720ca0b16d92364027285f95e9b1349490fa283610660527f02f7b99fdfa5b418548c2d777785820e02383cfc87e7085e280a375a358153bf610680527f09d004fe08dc4d19c382df36fad22ef676185663543703e6a4b40203e50fd8a66106a0527f2ac4721a65816699ae0aaad6c38ee4756fdecc3e9b6844f1b70cb4e35e841a4f610580527f03995224b6215f409c81c7155c0373fb14c58e1c08589894168da61111eb981b6105a0527f155ac28b6e9ca210d38a17d7d71b20b0d539b503c7a5c9e222e3e11363cf200c6106c0527f130de19edf9381111ec6d004656571a8da719e3057b3902b52e01d062e4672406106e0525f61070052565b614229565b7f08c379a0000000000000000000000000000000000000000000000000000000005f52602060045280602452508060445260645ffd5b60205f52602080526020604052806060525080608052507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160a0525f60205f60c05f60055afa610cd757610cd77f6d6f6465787020707265636f6d70696c65206661696c656400000000000000006018610c2c565b505f5190565b80515f52602081015160205250806040525060408160605f60075afa610d2857610d287f706f696e744d756c496e746f446573743a2065634d756c206661696c65640000601e610c2c565b50565b80515f52602081015160205250805160405260208101516060525060408160805f60065afa610d2857610d287f706f696e74416464496e746f446573743a206563416464206661696c65640000601e610c2c565b80515f526020810151602052815160405260208201517f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd470360605260408160805f60065afa610df357610df37f706f696e7453756241737369676e3a206563416464206661696c656400000000601c610c2c565b5050565b80515f5260208101516020528151604052602082015160605260408160805f60065afa610df357610df37f706f696e7441646441737369676e3a206563416464206661696c656400000000601c610c2c565b80515f52602081015160205250806040525060405f60605f60075afa8151604052602082015160605260408260805f60065afa1680610df357610df37f706f696e744d756c416e64416464496e746f44657374000000000000000000006016610c2c565b6020810151808015610ee557507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd470360209190910152565b825115610f1757610f177f706f696e744e65676174653a20696e76616c696420706f696e74000000000000601a610c2c565b505050565b5f610d4353610d84526064610d40206001610d43536064610d4020610d6452610d4452565b6002610d435360e01b610d84526048610d40207f1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b60043560048101356001811490507f1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60248301351661072052602435915060048201355f610700515f8114610fd15760309150610fd6565b602c91505b5014167f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47602483013581900690604484013581900690828009837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4784850914169350508161074052806107605250507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd476064830135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd476084840135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4784850914169350508161078052806107a05250507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760a4830135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760c4840135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478485091416935050816107c052806107e05250507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760e4830135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610104840135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4784850914169350508161080052806108205250507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610124830135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610144840135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4784850914169350508161084052806108605250507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610164830135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610184840135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4784850914169350508161088052806108a05250507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd476101a4830135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd476101c4840135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478485091416935050816108c052806108e05250507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd476101e4830135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610204840135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4784850914169350508161090052806109205250507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610224830135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610244840135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4784850914169350508161094052806109605250507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610264830135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610284840135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4784850914169350508161098052806109a05250507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd476102a4830135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd476102c4840135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478485091416935050816109c052806109e05250507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016102e483013506610a00527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161030483013506610a20527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161032483013506610a40527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161034483013506610a60527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161036483013506610a80527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161038483013506610aa0527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016103a483013506610ac0527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016103c483013506610ae0527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016103e483013506610b00527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161040483013506610b20527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161042483013506610b40527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161044483013506610b60527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161046483013506610b80527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161048483013506610ba0527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016104a483013506610bc0527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016104c483013506610be0527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016104e483013506610c00527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161050483013506610c20527f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610524830135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610544840135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848509141693505081610c405280610c605250507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610564830135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610584840135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848509141693505081610c805280610ca052505061070051156120e6577f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd476105a4830135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd476105c4840135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848509141693505081610cc05280610ce05250507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd476105e4830135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610604840135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848509141693505081610d005280610d205250505b80610df357610df37f6c6f616450726f6f663a2050726f6f6620697320696e76616c69640000000000601b610c2c565b61212261072051610f1c565b61212e61074051610f1c565b61213a61076051610f1c565b61214661078051610f1c565b6121526107a051610f1c565b61215e6107c051610f1c565b61216a6107e051610f1c565b61217661080051610f1c565b61218261082051610f1c565b61218b5f610f41565b610f005261219b61088051610f1c565b6121a76108a051610f1c565b6121b16001610f41565b610de0526121bf6002610f41565b610e00526121cf61084051610f1c565b6121db61086051610f1c565b6121e56003610f41565b610f20526121f36004610f41565b610f40526122036108c051610f1c565b61220f6108e051610f1c565b6122196005610f41565b610dc05261222961090051610f1c565b61223561092051610f1c565b61224161094051610f1c565b61224d61096051610f1c565b61225961098051610f1c565b6122656109a051610f1c565b6122716109c051610f1c565b61227d6109e051610f1c565b6122876006610f41565b80610fe05261229a630100000082610c62565b61106052506122ab610c0051610f1c565b6122b7610a0051610f1c565b6122c3610a2051610f1c565b6122cf610a4051610f1c565b6122db610a6051610f1c565b6122e7610a8051610f1c565b6122f3610aa051610f1c565b6122ff610ac051610f1c565b61230b610ae051610f1c565b612317610b0051610f1c565b612323610b2051610f1c565b61232f610b8051610f1c565b61233b610bc051610f1c565b612347610be051610f1c565b612353610b4051610f1c565b61235f610b6051610f1c565b61236b610ba051610f1c565b612377610c2051610f1c565b6123816007610f41565b610fa052612391610c4051610f1c565b61239d610c6051610f1c565b6123a9610c8051610f1c565b6123b5610ca051610f1c565b6123bf6008610f41565b610fc052565b610dc0517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181820980610e20527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001828209905080610e40527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001828209905080610e60527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001828209905080610e80527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001828209905080610ea0527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001828209905080610ec0527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001828209610ee0525050610fe051612501815f612692565b611020526125128162ffffff612692565b61104052507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016107205161102051097f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610aa051820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161259361283b565b820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016125c0612b18565b820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181610c20510890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010361106051087f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181610c0051099050818114610df357610df37f696e76616c69642071756f7469656e74206576616c756174696f6e0000000000601b610c2c565b5f600182156126c8576126c5837f1951441010b2b95a6e47a6075066a50a036f5ba978c050f2821df86636c0facb610c62565b90505b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000612718630100000087610c62565b0891508161274b5761274b7f696e76616c69642076616e697368696e6720706f6c796e6f6d69616c00000000601c610c2c565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181830991507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001817f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000103850890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000163010000008209905061280d7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffffff82610c62565b90507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001818309949350505050565b5f7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610b2051610e6051099050610e0051610de0515f7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000182610ac0510990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000183820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610a0051820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181850993507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000182610ae0510990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000183820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610a2051820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181850993507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000182610b00510990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000183820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610a4051820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001818509935050507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018082610a6051088309915050807f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001039050611020517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610e8051820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001817f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000103830891505090565b5f610f2051610f40517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001600183087f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001828209915080610f60525080610f80527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000182610b40510992507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181840892507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610b6051840992507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610ea05184099250612c4562ffffff7f1951441010b2b95a6e47a6075066a50a036f5ba978c050f2821df86636c0facb610c62565b91507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001827f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000103610fe05108915081611000527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000182840992507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610ec051611020510991507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001827f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001038408611040519093509150612d4562ffffff82610c62565b610ee0517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001817f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000184870909935050507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001827f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010384089250505090565b612dee8183610200610cdd565b612dfb8184610240610e49565b612e088185610280610e49565b612e1581866102c0610e49565b612e45817f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001858509610300610e49565b612e75817f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001868509610340610e49565b612e8161038082610df7565b612e9181610a80516103c0610e49565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610fa051610aa05109612ec6828284610cdd565b505050505050565b5f5f7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000184850991507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001857f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000103830891507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610dc051830991507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000185860990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001867f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000103820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610e2051820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181830891507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000184870990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001877f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000103820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610e4051820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018183089150507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610fa05182099050612ec68282610440610e49565b610e60517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610de051610fe05109610e00517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001857f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001838508087f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181850993507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001877f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001847f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160058809080890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181850993507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001887f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001847f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160078809080890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181850993507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001897f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001847f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001600a8809080890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018185099350505050611020517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000180610e8051830983089150507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610fa0518209905080611340527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610de051610e60510990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610b205182099050610de051610e00517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001857f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001837f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000186610ac0510908087f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181850993507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001877f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001847f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000187610ae05109080890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181850993507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001887f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001847f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000187610b005109080890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181850993505050507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610fa0518209905061362761108082610540610cdd565b5061363461108082610d7f565b5050505050565b50610b60517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610ea051820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161100051820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610fa05182096113805250610ba051610f20517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000190820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610b8051820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610f80518208610f00519091508290807f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000180878309840892507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000182820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000180888309840892507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000182820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018082610be051098408925050507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610bc051820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610f4051820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018183099150507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610f60518209610ea0517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000019182039250820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161100051820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000180610ec0516110205109820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000180610ee0516110405109820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610fa05182096113605250505050565b6110605180610900516110c052610920516110e0526139bc6110c082610940610e49565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000182820990506139f16110c082610980610e49565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018282099050613a266110c0826109c0610e49565b5050610a0051610a2051610a4051610a6051613a4781838587611100612de1565b613a5681838587611100612ece565b613a6581838587611100613118565b50613a7481838561110061363b565b5050506105c051611140526105e05161116052610f005180613a9b61114082610600610e49565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018282099050613ad061114082610640610e49565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018282099050610df361114082610680610e49565b60015f5f6110c051611180526110e0516111a052610c0051613b8d565b5f5f7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610fa05186099150613b5a6111808385610e49565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000180855184098708905094509492505050565b613b9e611180611100611180610d2b565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610fa051850993507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000180610c2051860982089050613c038185610a00610740613b22565b91509350613c178185610a20610780613b22565b91509350613c2b8185610a406107c0613b22565b915093507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610fa051850993508392507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000180610a6051860982089050613c978185610aa0610400613b22565b91509350613cab8185610ac0610480613b22565b91509350613cbf8185610ae06104c0613b22565b91509350613cd38185610b00610500613b22565b915093507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610fa051850993508391507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000180610b8051860982089050613d3f8185610bc0610580613b22565b91509350613d538185610be06106c0613b22565b61120052610fa0519094507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000019150840992507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000180610fc05185096113405108613dc16111c082610840610cdd565b507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000183610b205109613e85565b5f5f7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610fa051870991507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000180610fc05184098608613e506111c08286610e49565b507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018085518409880890509550959350505050565b613e96818585610a80610800613dee565b91509350613eae818561138051610b40610880613dee565b91509350613ec6818561136051610b606108c0613dee565b91509350613edb818584610ba0611140613dee565b611220525050610fc0519250613efc915061128090506111c0611180610d2b565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001611200517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001836112205109089050600161124052600261126052610d2861124082611240610cdd565b610fc051610fe0517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000017f1951441010b2b95a6e47a6075066a50a036f5ba978c050f2821df86636c0facb8209613fc0611240611280610d7f565b613fcf61128083610c40610e49565b6140016112807f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001858409610c80610e49565b5050610c405161130052610c60516113205261402261130082610c80610e49565b61402d611300610ead565b610700511561407a577f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181820961406961128082610cc0610e49565b61407861130082610d00610e49565b505b50611280515f526112a0516020527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c26040527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed6060527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b6080527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa60a0526113005160c0526113205160e0527f260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1610100527f0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0610120527f04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4610140527f22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e556101605260205f6101805f60085afa806141f5576141f57f66696e616c50616972696e673a20707265636f6d70696c65206661696c7572656020610c2c565b505f51614227576142277f66696e616c50616972696e673a2070616972696e67206661696c757265000000601d610c2c565b565b614231610f79565b614239612116565b6142416123c5565b614249613998565b614251613b05565b614259613f66565b60015f5260205ff35b5f5f83601f840112614272575f5ffd5b50813567ffffffffffffffff811115614289575f5ffd5b6020830191508360208260051b85010111156142a3575f5ffd5b9250929050565b5f5f5f5f604085870312156142bd575f5ffd5b843567ffffffffffffffff8111156142d3575f5ffd5b6142df87828801614262565b909550935050602085013567ffffffffffffffff8111156142fe575f5ffd5b61430a87828801614262565b9598949750955050505056fea2646970667358221220a5aa8695c8c7c1bd90a30d700a073464158434b86dc6593f8c7a9e394dcde13164736f6c634300081c0033","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"prague","libraries":{},"metadata":{"appendCBOR":true,"bytecodeHash":"ipfs","useLiteralContent":false},"optimizer":{"enabled":true,"runs":9999999},"outputSelection":{"*":{"":["*"],"*":["*"]}},"remappings":["@ensdomains/=node_modules/@ensdomains/","ds-test/=lib/forge-std/lib/ds-test/src/","eth-gas-reporter/=node_modules/eth-gas-reporter/","forge-std/=lib/forge-std/src/","hardhat/=node_modules/hardhat/","murky/=lib/murky/src/","foundry-test/=test/foundry/","l2-contracts/=../l2-contracts/contracts/","system-contracts/=../system-contracts/","@openzeppelin/contracts-v4/=lib/openzeppelin-contracts-v4/contracts/","@openzeppelin/contracts-upgradeable-v4/=lib/openzeppelin-contracts-upgradeable-v4/contracts/","test-utils/=test/foundry/l1/integration/utils/","openzeppelin-contracts-upgradeable-v4/=lib/openzeppelin-contracts-upgradeable-v4/","openzeppelin-contracts-v4/=lib/openzeppelin-contracts-v4/"],"viaIR":false},"optimization_runs":9999999,"sourcify_repo_url":null,"decoded_constructor_args":null,"compiler_version":"v0.8.28+commit.7893614a","is_verified_via_verifier_alliance":false,"verified_at":"2026-08-15T03:44:34.557742Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x6080604052348015600e575f5ffd5b5061434c8061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610034575f3560e01c80639e8945d214610038578063b864f5a914610053575b5f5ffd5b610040610076565b6040519081526020015b60405180910390f35b6100666100613660046142aa565b610654565b604051901515815260200161004a565b5f6106497f0b4a9f5342e7afd12f0cf9e05570c9a093f0bd7cb7b78c81bf1544cb5da85b62610200527f21eb82b2d4977e4c485af279bca5c883d086e4ea1ecd00920edf7d946a650995610220527f280e3c42287d88240208d3fd01cc10690f13a6d7da1fa42a4011ee9256ac104f610240527f15dc080b2cb32132e40858645657e6b420eb468330fe66956cd03ba85bacaed4610260527f2069c413c319dd35062fa2baf6bdd6fa389f8dad854c60263d28eab3853a121c610280527f01b890b5228208ffc081f6123071ec48d4df9be9e6621381f4a3c0b2fd4c40aa6102a0527f10f3e708f45ca2efdec8841e5269243fe198c0ee52800332cdce8667bc1dc9696102c0527f2528663d1ef8e4f361da7b8731dad691ae589374ac614c1c5d1346f9e43fb5b66102e0527f07c075fea3d01d8a8ea4118b3ba844f1780f3e4071dbb62a72f33a3c85a9071f610300527f3036edf95d2870c750d7aa482c7b4c846bc1c2cbaca785d65ef0c19be2060c29610320527f302c28931968d9b0a7123b271164a047449bac619040613232e22cc826718123610340527f1011a5c84cc8cc01327e01e0fab0816a62657f7ca662b39da403b27ed1fb32ae610360527f29f5372d67002cf1b03c4b90ba0892fb4067727e6e62556d3385f7ce080c6dbc610380527f0a63248741589563e58fc34ea7ba84ac9bf4c8c8fed393c53fe76225e49f086a6103a0527f0439082913a1028f27fd9297e93291e707c66f203bc26904872dd3e17f354ab06103c0527f275078ab02afe9e191a023899a0d664819219a1a11a71df9bdc16deeb59357cd6103e0527f2b67cbcea5d975f37dafccfdacde7ae4676966cf346060b46d8c31895cd38a31610400527f1df1d2b75d5e00c4cc9ed981167e1895a74ef9a21f2253aa350c195bd7af3f5f610420527f132e3968e05ce8a19671de377801c2255c018fbc07a81625fa7b4366e0c7374f610440527f078307dbab33a8bf744787e3fd5edd7e5e183e8e8f6b11785bc01150c6e3c857610460527f22a848812e5f1fd2574b256adea75f6b29ac39d6e164535e20441b7a92e6d720610480527f06073f25cf0516c9964f5c50daafb5237f6c1fa553a47f3469fb89257168c6746104a0527f0c994cf1008a34dfac4e6cb410cacd3da3d5da38dfed7415be22d126a27348e86104c0527f23ae45e176417d3ea51607c5a7640cbe2b3ff7fdf68ca435b61c86b88f0196ca6104e0527f0e316b80565bacbb6e15df912e35ed2118659f623b55d24ed700944a85a47a55610500527f1e2be7f209a8e0f8d9994cbda5c7202e1dde2a04883f3055fa4b85be079d4baa610520527f150fc6bea1e744b30d5b150e3be4e6d16ecc89de29eef2ffaaf7797cc7ceca2a610540527f2f0b5208404ab77741d24815423f45c8fe0757233433b3a41bc90b1b4fc9ff60610560527f2c513ed74d9d57a5ec901e074032741036353a2c4513422e96e7b53b302d765b6105c0527f04dd964427e430f16004076d708c0cb21e225056cc1d57418cfbd3d4729814686105e0527f1ea83e5e65c6f8068f4677e2911678cf329b28259642a32db1f14b8347828aac610600527f1d22bc884a2da4962a893ba8de13f57aaeb785ed52c5e686994839cab8f7475d610620527f0b2e7212d0d9cff26d0bdf3d79b2cac029a25dfeb1cafdf49e2349d7db348d89610640527f1301f9b252419ea240eb67fda720ca0b16d92364027285f95e9b1349490fa283610660527f02f7b99fdfa5b418548c2d777785820e02383cfc87e7085e280a375a358153bf610680527f09d004fe08dc4d19c382df36fad22ef676185663543703e6a4b40203e50fd8a66106a0527f2ac4721a65816699ae0aaad6c38ee4756fdecc3e9b6844f1b70cb4e35e841a4f610580527f03995224b6215f409c81c7155c0373fb14c58e1c08589894168da61111eb981b6105a0527f155ac28b6e9ca210d38a17d7d71b20b0d539b503c7a5c9e222e3e11363cf200c6106c0527f130de19edf9381111ec6d004656571a8da719e3057b3902b52e01d062e4672406106e0525f61070052565b506105206102002090565b5f610c277f0b4a9f5342e7afd12f0cf9e05570c9a093f0bd7cb7b78c81bf1544cb5da85b62610200527f21eb82b2d4977e4c485af279bca5c883d086e4ea1ecd00920edf7d946a650995610220527f280e3c42287d88240208d3fd01cc10690f13a6d7da1fa42a4011ee9256ac104f610240527f15dc080b2cb32132e40858645657e6b420eb468330fe66956cd03ba85bacaed4610260527f2069c413c319dd35062fa2baf6bdd6fa389f8dad854c60263d28eab3853a121c610280527f01b890b5228208ffc081f6123071ec48d4df9be9e6621381f4a3c0b2fd4c40aa6102a0527f10f3e708f45ca2efdec8841e5269243fe198c0ee52800332cdce8667bc1dc9696102c0527f2528663d1ef8e4f361da7b8731dad691ae589374ac614c1c5d1346f9e43fb5b66102e0527f07c075fea3d01d8a8ea4118b3ba844f1780f3e4071dbb62a72f33a3c85a9071f610300527f3036edf95d2870c750d7aa482c7b4c846bc1c2cbaca785d65ef0c19be2060c29610320527f302c28931968d9b0a7123b271164a047449bac619040613232e22cc826718123610340527f1011a5c84cc8cc01327e01e0fab0816a62657f7ca662b39da403b27ed1fb32ae610360527f29f5372d67002cf1b03c4b90ba0892fb4067727e6e62556d3385f7ce080c6dbc610380527f0a63248741589563e58fc34ea7ba84ac9bf4c8c8fed393c53fe76225e49f086a6103a0527f0439082913a1028f27fd9297e93291e707c66f203bc26904872dd3e17f354ab06103c0527f275078ab02afe9e191a023899a0d664819219a1a11a71df9bdc16deeb59357cd6103e0527f2b67cbcea5d975f37dafccfdacde7ae4676966cf346060b46d8c31895cd38a31610400527f1df1d2b75d5e00c4cc9ed981167e1895a74ef9a21f2253aa350c195bd7af3f5f610420527f132e3968e05ce8a19671de377801c2255c018fbc07a81625fa7b4366e0c7374f610440527f078307dbab33a8bf744787e3fd5edd7e5e183e8e8f6b11785bc01150c6e3c857610460527f22a848812e5f1fd2574b256adea75f6b29ac39d6e164535e20441b7a92e6d720610480527f06073f25cf0516c9964f5c50daafb5237f6c1fa553a47f3469fb89257168c6746104a0527f0c994cf1008a34dfac4e6cb410cacd3da3d5da38dfed7415be22d126a27348e86104c0527f23ae45e176417d3ea51607c5a7640cbe2b3ff7fdf68ca435b61c86b88f0196ca6104e0527f0e316b80565bacbb6e15df912e35ed2118659f623b55d24ed700944a85a47a55610500527f1e2be7f209a8e0f8d9994cbda5c7202e1dde2a04883f3055fa4b85be079d4baa610520527f150fc6bea1e744b30d5b150e3be4e6d16ecc89de29eef2ffaaf7797cc7ceca2a610540527f2f0b5208404ab77741d24815423f45c8fe0757233433b3a41bc90b1b4fc9ff60610560527f2c513ed74d9d57a5ec901e074032741036353a2c4513422e96e7b53b302d765b6105c0527f04dd964427e430f16004076d708c0cb21e225056cc1d57418cfbd3d4729814686105e0527f1ea83e5e65c6f8068f4677e2911678cf329b28259642a32db1f14b8347828aac610600527f1d22bc884a2da4962a893ba8de13f57aaeb785ed52c5e686994839cab8f7475d610620527f0b2e7212d0d9cff26d0bdf3d79b2cac029a25dfeb1cafdf49e2349d7db348d89610640527f1301f9b252419ea240eb67fda720ca0b16d92364027285f95e9b1349490fa283610660527f02f7b99fdfa5b418548c2d777785820e02383cfc87e7085e280a375a358153bf610680527f09d004fe08dc4d19c382df36fad22ef676185663543703e6a4b40203e50fd8a66106a0527f2ac4721a65816699ae0aaad6c38ee4756fdecc3e9b6844f1b70cb4e35e841a4f610580527f03995224b6215f409c81c7155c0373fb14c58e1c08589894168da61111eb981b6105a0527f155ac28b6e9ca210d38a17d7d71b20b0d539b503c7a5c9e222e3e11363cf200c6106c0527f130de19edf9381111ec6d004656571a8da719e3057b3902b52e01d062e4672406106e0525f61070052565b614229565b7f08c379a0000000000000000000000000000000000000000000000000000000005f52602060045280602452508060445260645ffd5b60205f52602080526020604052806060525080608052507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160a0525f60205f60c05f60055afa610cd757610cd77f6d6f6465787020707265636f6d70696c65206661696c656400000000000000006018610c2c565b505f5190565b80515f52602081015160205250806040525060408160605f60075afa610d2857610d287f706f696e744d756c496e746f446573743a2065634d756c206661696c65640000601e610c2c565b50565b80515f52602081015160205250805160405260208101516060525060408160805f60065afa610d2857610d287f706f696e74416464496e746f446573743a206563416464206661696c65640000601e610c2c565b80515f526020810151602052815160405260208201517f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd470360605260408160805f60065afa610df357610df37f706f696e7453756241737369676e3a206563416464206661696c656400000000601c610c2c565b5050565b80515f5260208101516020528151604052602082015160605260408160805f60065afa610df357610df37f706f696e7441646441737369676e3a206563416464206661696c656400000000601c610c2c565b80515f52602081015160205250806040525060405f60605f60075afa8151604052602082015160605260408260805f60065afa1680610df357610df37f706f696e744d756c416e64416464496e746f44657374000000000000000000006016610c2c565b6020810151808015610ee557507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd470360209190910152565b825115610f1757610f177f706f696e744e65676174653a20696e76616c696420706f696e74000000000000601a610c2c565b505050565b5f610d4353610d84526064610d40206001610d43536064610d4020610d6452610d4452565b6002610d435360e01b610d84526048610d40207f1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b60043560048101356001811490507f1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60248301351661072052602435915060048201355f610700515f8114610fd15760309150610fd6565b602c91505b5014167f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47602483013581900690604484013581900690828009837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4784850914169350508161074052806107605250507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd476064830135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd476084840135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4784850914169350508161078052806107a05250507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760a4830135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760c4840135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478485091416935050816107c052806107e05250507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760e4830135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610104840135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4784850914169350508161080052806108205250507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610124830135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610144840135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4784850914169350508161084052806108605250507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610164830135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610184840135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4784850914169350508161088052806108a05250507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd476101a4830135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd476101c4840135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478485091416935050816108c052806108e05250507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd476101e4830135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610204840135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4784850914169350508161090052806109205250507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610224830135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610244840135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4784850914169350508161094052806109605250507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610264830135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610284840135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4784850914169350508161098052806109a05250507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd476102a4830135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd476102c4840135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478485091416935050816109c052806109e05250507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016102e483013506610a00527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161030483013506610a20527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161032483013506610a40527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161034483013506610a60527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161036483013506610a80527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161038483013506610aa0527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016103a483013506610ac0527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016103c483013506610ae0527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016103e483013506610b00527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161040483013506610b20527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161042483013506610b40527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161044483013506610b60527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161046483013506610b80527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161048483013506610ba0527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016104a483013506610bc0527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016104c483013506610be0527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016104e483013506610c00527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161050483013506610c20527f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610524830135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610544840135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848509141693505081610c405280610c605250507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610564830135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610584840135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848509141693505081610c805280610ca052505061070051156120e6577f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd476105a4830135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd476105c4840135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848509141693505081610cc05280610ce05250507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd476105e4830135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47610604840135067f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47828309837f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848709087f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47848509141693505081610d005280610d205250505b80610df357610df37f6c6f616450726f6f663a2050726f6f6620697320696e76616c69640000000000601b610c2c565b61212261072051610f1c565b61212e61074051610f1c565b61213a61076051610f1c565b61214661078051610f1c565b6121526107a051610f1c565b61215e6107c051610f1c565b61216a6107e051610f1c565b61217661080051610f1c565b61218261082051610f1c565b61218b5f610f41565b610f005261219b61088051610f1c565b6121a76108a051610f1c565b6121b16001610f41565b610de0526121bf6002610f41565b610e00526121cf61084051610f1c565b6121db61086051610f1c565b6121e56003610f41565b610f20526121f36004610f41565b610f40526122036108c051610f1c565b61220f6108e051610f1c565b6122196005610f41565b610dc05261222961090051610f1c565b61223561092051610f1c565b61224161094051610f1c565b61224d61096051610f1c565b61225961098051610f1c565b6122656109a051610f1c565b6122716109c051610f1c565b61227d6109e051610f1c565b6122876006610f41565b80610fe05261229a630100000082610c62565b61106052506122ab610c0051610f1c565b6122b7610a0051610f1c565b6122c3610a2051610f1c565b6122cf610a4051610f1c565b6122db610a6051610f1c565b6122e7610a8051610f1c565b6122f3610aa051610f1c565b6122ff610ac051610f1c565b61230b610ae051610f1c565b612317610b0051610f1c565b612323610b2051610f1c565b61232f610b8051610f1c565b61233b610bc051610f1c565b612347610be051610f1c565b612353610b4051610f1c565b61235f610b6051610f1c565b61236b610ba051610f1c565b612377610c2051610f1c565b6123816007610f41565b610fa052612391610c4051610f1c565b61239d610c6051610f1c565b6123a9610c8051610f1c565b6123b5610ca051610f1c565b6123bf6008610f41565b610fc052565b610dc0517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181820980610e20527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001828209905080610e40527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001828209905080610e60527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001828209905080610e80527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001828209905080610ea0527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001828209905080610ec0527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001828209610ee0525050610fe051612501815f612692565b611020526125128162ffffff612692565b61104052507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016107205161102051097f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610aa051820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161259361283b565b820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016125c0612b18565b820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181610c20510890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010361106051087f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181610c0051099050818114610df357610df37f696e76616c69642071756f7469656e74206576616c756174696f6e0000000000601b610c2c565b5f600182156126c8576126c5837f1951441010b2b95a6e47a6075066a50a036f5ba978c050f2821df86636c0facb610c62565b90505b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000017f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000612718630100000087610c62565b0891508161274b5761274b7f696e76616c69642076616e697368696e6720706f6c796e6f6d69616c00000000601c610c2c565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181830991507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001817f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000103850890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000163010000008209905061280d7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffffff82610c62565b90507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001818309949350505050565b5f7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610b2051610e6051099050610e0051610de0515f7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000182610ac0510990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000183820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610a0051820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181850993507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000182610ae0510990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000183820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610a2051820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181850993507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000182610b00510990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000183820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610a4051820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001818509935050507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018082610a6051088309915050807f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001039050611020517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610e8051820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001817f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000103830891505090565b5f610f2051610f40517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001600183087f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001828209915080610f60525080610f80527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000182610b40510992507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181840892507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610b6051840992507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610ea05184099250612c4562ffffff7f1951441010b2b95a6e47a6075066a50a036f5ba978c050f2821df86636c0facb610c62565b91507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001827f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000103610fe05108915081611000527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000182840992507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610ec051611020510991507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001827f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001038408611040519093509150612d4562ffffff82610c62565b610ee0517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001817f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000184870909935050507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001827f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010384089250505090565b612dee8183610200610cdd565b612dfb8184610240610e49565b612e088185610280610e49565b612e1581866102c0610e49565b612e45817f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001858509610300610e49565b612e75817f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001868509610340610e49565b612e8161038082610df7565b612e9181610a80516103c0610e49565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610fa051610aa05109612ec6828284610cdd565b505050505050565b5f5f7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000184850991507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001857f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000103830891507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610dc051830991507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000185860990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001867f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000103820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610e2051820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181830891507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000184870990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001877f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000103820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610e4051820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018183089150507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610fa05182099050612ec68282610440610e49565b610e60517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610de051610fe05109610e00517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001857f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001838508087f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181850993507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001877f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001847f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160058809080890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181850993507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001887f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001847f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000160078809080890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181850993507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001897f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001847f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001600a8809080890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018185099350505050611020517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000180610e8051830983089150507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610fa0518209905080611340527f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610de051610e60510990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610b205182099050610de051610e00517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001857f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001837f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000186610ac0510908087f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181850993507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001877f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001847f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000187610ae05109080890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181850993507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001887f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001847f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000187610b005109080890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181850993505050507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610fa0518209905061362761108082610540610cdd565b5061363461108082610d7f565b5050505050565b50610b60517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610ea051820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161100051820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610fa05182096113805250610ba051610f20517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000190820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610b8051820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610f80518208610f00519091508290807f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000180878309840892507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000182820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000180888309840892507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000182820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018082610be051098408925050507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610bc051820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610f4051820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018183099150507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610f60518209610ea0517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000019182039250820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000161100051820990507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000180610ec0516110205109820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000180610ee0516110405109820890507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610fa05182096113605250505050565b6110605180610900516110c052610920516110e0526139bc6110c082610940610e49565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000182820990506139f16110c082610980610e49565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018282099050613a266110c0826109c0610e49565b5050610a0051610a2051610a4051610a6051613a4781838587611100612de1565b613a5681838587611100612ece565b613a6581838587611100613118565b50613a7481838561110061363b565b5050506105c051611140526105e05161116052610f005180613a9b61114082610600610e49565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018282099050613ad061114082610640610e49565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018282099050610df361114082610680610e49565b60015f5f6110c051611180526110e0516111a052610c0051613b8d565b5f5f7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610fa05186099150613b5a6111808385610e49565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000180855184098708905094509492505050565b613b9e611180611100611180610d2b565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610fa051850993507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000180610c2051860982089050613c038185610a00610740613b22565b91509350613c178185610a20610780613b22565b91509350613c2b8185610a406107c0613b22565b915093507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610fa051850993508392507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000180610a6051860982089050613c978185610aa0610400613b22565b91509350613cab8185610ac0610480613b22565b91509350613cbf8185610ae06104c0613b22565b91509350613cd38185610b00610500613b22565b915093507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610fa051850993508391507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000180610b8051860982089050613d3f8185610bc0610580613b22565b91509350613d538185610be06106c0613b22565b61120052610fa0519094507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000019150840992507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000180610fc05185096113405108613dc16111c082610840610cdd565b507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000183610b205109613e85565b5f5f7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001610fa051870991507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000180610fc05184098608613e506111c08286610e49565b507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000018085518409880890509550959350505050565b613e96818585610a80610800613dee565b91509350613eae818561138051610b40610880613dee565b91509350613ec6818561136051610b606108c0613dee565b91509350613edb818584610ba0611140613dee565b611220525050610fc0519250613efc915061128090506111c0611180610d2b565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001611200517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001836112205109089050600161124052600261126052610d2861124082611240610cdd565b610fc051610fe0517f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000017f1951441010b2b95a6e47a6075066a50a036f5ba978c050f2821df86636c0facb8209613fc0611240611280610d7f565b613fcf61128083610c40610e49565b6140016112807f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001858409610c80610e49565b5050610c405161130052610c60516113205261402261130082610c80610e49565b61402d611300610ead565b610700511561407a577f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181820961406961128082610cc0610e49565b61407861130082610d00610e49565b505b50611280515f526112a0516020527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c26040527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed6060527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b6080527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa60a0526113005160c0526113205160e0527f260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1610100527f0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0610120527f04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4610140527f22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e556101605260205f6101805f60085afa806141f5576141f57f66696e616c50616972696e673a20707265636f6d70696c65206661696c7572656020610c2c565b505f51614227576142277f66696e616c50616972696e673a2070616972696e67206661696c757265000000601d610c2c565b565b614231610f79565b614239612116565b6142416123c5565b614249613998565b614251613b05565b614259613f66565b60015f5260205ff35b5f5f83601f840112614272575f5ffd5b50813567ffffffffffffffff811115614289575f5ffd5b6020830191508360208260051b85010111156142a3575f5ffd5b9250929050565b5f5f5f5f604085870312156142bd575f5ffd5b843567ffffffffffffffff8111156142d3575f5ffd5b6142df87828801614262565b909550935050602085013567ffffffffffffffff8111156142fe575f5ffd5b61430a87828801614262565b9598949750955050505056fea2646970667358221220a5aa8695c8c7c1bd90a30d700a073464158434b86dc6593f8c7a9e394dcde13164736f6c634300081c0033","name":"EraVerifierPlonk","is_blueprint":false,"license_type":"none","is_fully_verified":true,"is_verified_via_eth_bytecode_db":true,"language":"solidity","evm_version":"prague","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":false,"additional_sources":[{"file_path":"contracts/state-transition/chain-interfaces/IVerifier.sol","source_code":"// SPDX-License-Identifier: MIT\n// We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version.\npragma solidity ^0.8.21;\n\n/// @notice Part of the configuration parameters of ZKP circuits\nstruct VerifierParams {\n    bytes32 recursionNodeLevelVkHash;\n    bytes32 recursionLeafLevelVkHash;\n    bytes32 recursionCircuitsSetVksHash;\n}\n\n/// @title The interface of the Verifier contract, responsible for the zero knowledge proof verification.\n/// @author Matter Labs\n/// @custom:security-contact security@matterlabs.dev\ninterface IVerifier {\n    /// @dev Verifies a zk-SNARK proof.\n    /// @return A boolean value indicating whether the zk-SNARK proof is valid.\n    /// Note: The function may revert execution instead of returning false in some cases.\n    function verify(uint256[] calldata _publicInputs, uint256[] calldata _proof) external view returns (bool);\n\n    /// @notice Calculates a keccak256 hash of the runtime loaded verification keys.\n    /// @return vkHash The keccak256 hash of the loaded verification keys.\n    function verificationKeyHash() external view returns (bytes32);\n}\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[],"name":"verificationKeyHash","outputs":[{"internalType":"bytes32","name":"vkHash","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"name":"verify","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":false,"constructor_args":null}