pub const EVM_HALO2_VERIFIER_TEMPLATE: &str = "// SPDX-License-Identifier: MIT\npragma solidity 0.8.19;\n\nimport { Halo2Verifier } from \"./Halo2Verifier.sol\";\nimport { IOpenVmHalo2Verifier } from \"./interfaces/IOpenVmHalo2Verifier.sol\";\n\ntype MemoryPointer is uint256;\n\n/// @notice This contract provides a thin wrapper around the Halo2 verifier\n/// outputted by `snark-verifier`, exposing a more user-friendly interface.\ncontract OpenVmHalo2Verifier is Halo2Verifier, IOpenVmHalo2Verifier {\n /// @dev Invalid public values length\n error InvalidPublicValuesLength(uint256 expected, uint256 actual);\n\n /// @dev Invalid proof data length\n error InvalidProofDataLength(uint256 expected, uint256 actual);\n\n /// @dev Proof verification failed\n error ProofVerificationFailed();\n\n /// @dev The length of the proof data, in bytes.\n uint256 private constant PROOF_DATA_LENGTH = (12 + 43) * 32;\n\n /// @dev The length of the public values, in bytes. This value is set by\n /// OpenVM and is guaranteed to be no larger than 8192.\n uint256 private constant PUBLIC_VALUES_LENGTH = {PUBLIC_VALUES_LENGTH};\n\n /// @dev The length of the full proof, in bytes\n uint256 private constant FULL_PROOF_LENGTH = (12 + 2 + PUBLIC_VALUES_LENGTH + 43) * 32;\n\n /// @dev The version of OpenVM that generated this verifier.\n string public constant OPENVM_VERSION = \"{OPENVM_VERSION}\";\n\n /// @notice A wrapper that constructs the proof into the right format for\n /// use with the `snark-verifier` verification.\n ///\n /// @dev The verifier expected proof format is:\n /// proof[..12 * 32]: KZG accumulator\n /// proof[12 * 32..13 * 32]: app exe commit\n /// proof[13 * 32..14 * 32]: app vm commit\n /// proof[14 * 32..(14 + PUBLIC_VALUES_LENGTH) * 32]: publicValues[0..PUBLIC_VALUES_LENGTH]\n /// proof[(14 + PUBLIC_VALUES_LENGTH) * 32..]: Proof Suffix\n ///\n /// @param publicValues The PVs revealed by the OpenVM guest program.\n /// @param proofData All components of the proof except the public values and\n /// app exe and vm commits. The expected format is:\n /// `abi.encodePacked(kzgAccumulator, proofSuffix)`\n /// @param appExeCommit The commitment to the OpenVM application executable whose execution\n /// is being verified.\n /// @param appVmCommit The commitment to the VM configuration.\n function verify(bytes calldata publicValues, bytes calldata proofData, bytes32 appExeCommit, bytes32 appVmCommit) external view {\n if (publicValues.length != PUBLIC_VALUES_LENGTH) revert InvalidPublicValuesLength(PUBLIC_VALUES_LENGTH, publicValues.length);\n if (proofData.length != PROOF_DATA_LENGTH) revert InvalidProofDataLength(PROOF_DATA_LENGTH, proofData.length);\n\n // We will format the public values and construct the full proof payload\n // below.\n\n MemoryPointer proofPtr = _constructProof(publicValues, proofData, appExeCommit, appVmCommit);\n\n uint256 fullProofLength = FULL_PROOF_LENGTH;\n\n /// @solidity memory-safe-assembly\n assembly {\n // Self-call using the proof as calldata\n if iszero(staticcall(gas(), address(), proofPtr, fullProofLength, 0, 0)) {\n mstore(0x00, 0xd611c318) // ProofVerificationFailed()\n revert(0x1c, 0x04)\n }\n }\n }\n\n /// @dev The assembly code should perform the same function as the following\n /// solidity code:\n //\n /// ```solidity\n /// bytes memory proof =\n /// abi.encodePacked(proofData[0:0x180], appExeCommit, appVmCommit, publicValuesPayload, proofData[0x180:]);\n /// ```\n //\n /// where `publicValuesPayload` is a memory payload with each byte in\n /// `publicValues` separated into its own `bytes32` word.\n ///\n /// This function does not clean the memory it allocates. Since it is the\n /// only memory write that occurs in the call frame, we know that\n /// the memory region cannot have been dirtied.\n ///\n /// @return proofPtr Memory pointer to the beginning of the constructed\n /// proof. This pointer does not follow `bytes memory` semantics.\n function _constructProof(bytes calldata publicValues, bytes calldata proofData, bytes32 appExeCommit, bytes32 appVmCommit)\n internal\n pure\n returns (MemoryPointer proofPtr)\n {\n uint256 fullProofLength = FULL_PROOF_LENGTH;\n\n // The expected proof format using hex offsets:\n //\n // proof[..0x180]: KZG accumulator\n // proof[0x180..0x1a0]: app exe commit\n // proof[0x1a0..0x1c0]: app vm commit\n // proof[0x1c0..(0x1c0 + PUBLIC_VALUES_LENGTH * 32)]: publicValues[0..PUBLIC_VALUES_LENGTH]\n // proof[(0x1c0 + PUBLIC_VALUES_LENGTH * 32)..]: Proof Suffix\n\n /// @solidity memory-safe-assembly\n assembly {\n proofPtr := mload(0x40)\n // Allocate the memory as a safety measure.\n mstore(0x40, add(proofPtr, fullProofLength))\n\n // Copy the KZG accumulator (length 0x180) into the beginning of\n // the memory buffer\n calldatacopy(proofPtr, proofData.offset, 0x180)\n\n // Copy the App Exe Commit and App Vm Commit into the memory buffer\n mstore(add(proofPtr, 0x180), appExeCommit)\n mstore(add(proofPtr, 0x1a0), appVmCommit)\n\n // Copy the Proof Suffix (length 43 * 32 = 0x560) into the\n // end of the memory buffer, leaving PUBLIC_VALUES_LENGTH words in\n // between for the publicValuesPayload.\n //\n // Begin copying from the end of the KZG accumulator in the\n // calldata buffer (0x180)\n let proofSuffixOffset := add(0x1c0, shl(5, PUBLIC_VALUES_LENGTH))\n calldatacopy(add(proofPtr, proofSuffixOffset), add(proofData.offset, 0x180), 0x560)\n\n // Copy each byte of the public values into the proof. It copies the\n // most significant bytes of public values first.\n let publicValuesMemOffset := add(add(proofPtr, 0x1c0), 0x1f)\n for { let i := 0 } iszero(eq(i, PUBLIC_VALUES_LENGTH)) { i := add(i, 1) } {\n calldatacopy(add(publicValuesMemOffset, shl(5, i)), add(publicValues.offset, i), 0x01)\n }\n }\n }\n}\n";