// SPDX-License-Identifier: MIT pragma solidity =0.8.24; import {IZkEvmVerifierV1} from "./IZkEvmVerifier.sol"; // solhint-disable no-inline-assembly contract ZkEvmVerifierV1 is IZkEvmVerifierV1 { /********** * Errors * **********/ /// @dev Thrown when aggregate zk proof verification is failed. error VerificationFailed(); /************* * Constants * *************/ /// @notice The address of highly optimized plonk verifier contract. address public immutable plonkVerifier; /*************** * Constructor * ***************/ constructor(address _verifier) { plonkVerifier = _verifier; } /************************* * Public View Functions * *************************/ /// @inheritdoc IZkEvmVerifierV1 function verify(bytes calldata aggrProof, bytes32 publicInputHash) external view override { address _verifier = plonkVerifier; bool success; // 1. the first 12 * 32 (0x180) bytes of `aggrProof` is `accumulator` // 2. the rest bytes of `aggrProof` is the actual `batch_aggregated_proof` // 3. each byte of the `public_input_hash` should be converted to a `uint256` and the // 1024 (0x400) bytes should inserted between `accumulator` and `batch_aggregated_proof`. assembly { let p := mload(0x40) calldatacopy(p, aggrProof.offset, 0x180) for { let i := 0 } lt(i, 0x400) { i := add(i, 0x20) } { mstore(add(p, sub(0x560, i)), and(publicInputHash, 0xff)) publicInputHash := shr(8, publicInputHash) } calldatacopy(add(p, 0x580), add(aggrProof.offset, 0x180), sub(aggrProof.length, 0x180)) success := staticcall(gas(), _verifier, p, add(aggrProof.length, 0x400), 0x00, 0x00) } if (!success) { revert VerificationFailed(); } } }