|
| 1 | +// SPDX-License-Identifier: MIT |
| 2 | + |
| 3 | +pragma solidity =0.8.24; |
| 4 | + |
| 5 | +import {IZkEvmVerifierV2} from "./IZkEvmVerifier.sol"; |
| 6 | + |
| 7 | +// solhint-disable no-inline-assembly |
| 8 | + |
| 9 | +contract ZkEvmVerifierPostFeynman is IZkEvmVerifierV2 { |
| 10 | + /********** |
| 11 | + * Errors * |
| 12 | + **********/ |
| 13 | + |
| 14 | + /// @dev Thrown when bundle recursion zk proof verification is failed. |
| 15 | + error VerificationFailed(); |
| 16 | + |
| 17 | + /************* |
| 18 | + * Constants * |
| 19 | + *************/ |
| 20 | + |
| 21 | + /// @notice The address of highly optimized plonk verifier contract. |
| 22 | + address public immutable plonkVerifier; |
| 23 | + |
| 24 | + /// @notice A predetermined digest for the `plonkVerifier`. |
| 25 | + bytes32 public immutable verifierDigest1; |
| 26 | + |
| 27 | + /// @notice A predetermined digest for the `plonkVerifier`. |
| 28 | + bytes32 public immutable verifierDigest2; |
| 29 | + |
| 30 | + /// @notice The version of the protocol. |
| 31 | + uint256 public immutable protocolVersion; |
| 32 | + |
| 33 | + /*************** |
| 34 | + * Constructor * |
| 35 | + ***************/ |
| 36 | + |
| 37 | + constructor( |
| 38 | + address _verifier, |
| 39 | + bytes32 _verifierDigest1, |
| 40 | + bytes32 _verifierDigest2, |
| 41 | + uint256 _protocolVersion |
| 42 | + ) { |
| 43 | + plonkVerifier = _verifier; |
| 44 | + verifierDigest1 = _verifierDigest1; |
| 45 | + verifierDigest2 = _verifierDigest2; |
| 46 | + protocolVersion = _protocolVersion; |
| 47 | + } |
| 48 | + |
| 49 | + /************************* |
| 50 | + * Public View Functions * |
| 51 | + *************************/ |
| 52 | + |
| 53 | + /// @inheritdoc IZkEvmVerifierV2 |
| 54 | + /// |
| 55 | + /// @dev Encoding for `publicInput`. And this is exactly the same as `ZkEvmVerifierV2`. |
| 56 | + /// ```text |
| 57 | + /// | layer2ChainId | numBatches | prevStateRoot | prevBatchHash | postStateRoot | batchHash | withdrawRoot | |
| 58 | + /// | 8 bytes | 4 bytes | 32 bytes | 32 bytes | 32 bytes | 32 bytes | 32 bytes | |
| 59 | + /// ``` |
| 60 | + function verify(bytes calldata bundleProof, bytes calldata publicInput) external view override { |
| 61 | + address _verifier = plonkVerifier; |
| 62 | + bytes32 _verifierDigest1 = verifierDigest1; |
| 63 | + bytes32 _verifierDigest2 = verifierDigest2; |
| 64 | + bytes32 publicInputHash = keccak256(abi.encodePacked(protocolVersion, publicInput)); |
| 65 | + bool success; |
| 66 | + |
| 67 | + // 1. the first 12 * 32 (0x180) bytes of `bundleProof` is `accumulator` |
| 68 | + // 2. the rest bytes of `bundleProof` is the actual `bundle_proof` |
| 69 | + // 3. Inserted between `accumulator` and `bundle_proof` are |
| 70 | + // 32 * 34 (0x440) bytes, such that: |
| 71 | + // | start | end | field | |
| 72 | + // |---------------|---------------|-------------------------| |
| 73 | + // | 0x00 | 0x180 | bundleProof[0x00:0x180] | |
| 74 | + // | 0x180 | 0x180 + 0x20 | verifierDigest1 | |
| 75 | + // | 0x180 + 0x20 | 0x180 + 0x40 | verifierDigest2 | |
| 76 | + // | 0x180 + 0x40 | 0x180 + 0x60 | publicInputHash[0] | |
| 77 | + // | 0x180 + 0x60 | 0x180 + 0x80 | publicInputHash[1] | |
| 78 | + // ... |
| 79 | + // | 0x180 + 0x420 | 0x180 + 0x440 | publicInputHash[31] | |
| 80 | + // | 0x180 + 0x440 | dynamic | bundleProof[0x180:] | |
| 81 | + assembly { |
| 82 | + let p := mload(0x40) |
| 83 | + // 1. copy the accumulator's 0x180 bytes |
| 84 | + calldatacopy(p, bundleProof.offset, 0x180) |
| 85 | + // 2. insert the public input's 0x440 bytes |
| 86 | + mstore(add(p, 0x180), _verifierDigest1) // verifierDigest1 |
| 87 | + mstore(add(p, 0x1a0), _verifierDigest2) // verifierDigest2 |
| 88 | + for { |
| 89 | + let i := 0 |
| 90 | + } lt(i, 0x400) { |
| 91 | + i := add(i, 0x20) |
| 92 | + } { |
| 93 | + mstore(add(p, sub(0x5a0, i)), and(publicInputHash, 0xff)) |
| 94 | + publicInputHash := shr(8, publicInputHash) |
| 95 | + } |
| 96 | + // 3. copy all remaining bytes from bundleProof |
| 97 | + calldatacopy(add(p, 0x5c0), add(bundleProof.offset, 0x180), sub(bundleProof.length, 0x180)) |
| 98 | + // 4. call plonk verifier |
| 99 | + success := staticcall(gas(), _verifier, p, add(bundleProof.length, 0x440), 0x00, 0x00) |
| 100 | + } |
| 101 | + if (!success) { |
| 102 | + revert VerificationFailed(); |
| 103 | + } |
| 104 | + } |
| 105 | +} |
0 commit comments