From 01ad297e3280f7290e705136d26105a7802a2add Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Keszey=20D=C3=A1niel?= Date: Tue, 5 Mar 2024 17:19:43 +0100 Subject: [PATCH 1/9] risc0 verifier contract --- .../contracts/verifiers/RiscZeroVerifier.sol | 111 ++++++++++++++++++ .../contracts/verifiers/SgxVerifier.sol | 39 ++---- .../contracts/verifiers/libs/LibProofHash.sol | 36 ++++++ packages/protocol/test/L1/TaikoL1TestBase.sol | 5 +- packages/protocol/test/TaikoTest.sol | 1 + .../protocol/test/verifiers/SgxVerifier.t.sol | 24 +++- 6 files changed, 179 insertions(+), 37 deletions(-) create mode 100644 packages/protocol/contracts/verifiers/RiscZeroVerifier.sol create mode 100644 packages/protocol/contracts/verifiers/libs/LibProofHash.sol diff --git a/packages/protocol/contracts/verifiers/RiscZeroVerifier.sol b/packages/protocol/contracts/verifiers/RiscZeroVerifier.sol new file mode 100644 index 00000000000..a3d49586503 --- /dev/null +++ b/packages/protocol/contracts/verifiers/RiscZeroVerifier.sol @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +import "../common/EssentialContract.sol"; +import "../L1/ITaikoL1.sol"; +import "./IVerifier.sol"; +import "./libs/LibProofHash.sol"; + +/// @notice Verifier interface for RISC Zero receipts of execution. +/// https://github.com/risc0/risc0-ethereum/blob/release-0.7/contracts/src/IRiscZeroVerifier.sol +interface IRiscZeroVerifier { + /// @notice Verify that the given seal is a valid RISC Zero proof of execution with the + /// given image ID, post-state digest, and journal digest. + /// @dev This method additionally ensures that the input hash is all-zeros (i.e. no + /// committed input), the exit code is (Halted, 0), and there are no assumptions (i.e. the + /// receipt is unconditional). + /// @param seal The encoded cryptographic proof (i.e. SNARK). + /// @param imageId The identifier for the guest program. + /// @param postStateDigest A hash of the final memory state. Required to run the verifier, but + /// otherwise can be left unconstrained for most use cases. + /// @param journalDigest The SHA-256 digest of the journal bytes. + /// @return true if the receipt passes the verification checks. The return code must be checked. + function verify( + bytes calldata seal, + bytes32 imageId, + bytes32 postStateDigest, + bytes32 journalDigest + ) + external + view + returns (bool); +} + +/// @title RiscZeroVerifier +/// @custom:security-contact security@taiko.xyz +contract RiscZeroVerifier is EssentialContract, IVerifier { + /// @dev For RiscZeroVerifier's verify() + struct RiscZeroVerifierInput { + bytes seal; + bytes32 imageId; + bytes32 postStateDigest; + bytes32 journalDigest; + } + + /// @notice RISC Zero verifier contract address. + IRiscZeroVerifier public riscZeroVerifier; + /// @notice Trusted imageId mapping + mapping(bytes32 imageId => bool trusted) public trustedImageId; + + uint256[48] private __gap; + + error RISC_ZERO_INVALID_IMAGE_ID(); + error RISC_ZERO_INVALID_PROOF(); + + /// @notice Initializes the contract with the provided address manager. + /// @param _addressManager The address of the address manager contract. + function init(address _addressManager, address _riscZeroVerifier) external initializer { + __Essential_init(_addressManager); + riscZeroVerifier = IRiscZeroVerifier(_riscZeroVerifier); + } + + /// @notice Sets/unsets an the imageId as trusted entity + /// @param _imageId The id of the image. + /// @param _trusted True if trusted, false otherwise. + function setImageIdTrusted(bytes32 _imageId, bool _trusted) external onlyOwner { + trustedImageId[_imageId] = _trusted; + } + + /// @inheritdoc IVerifier + function verifyProof( + Context calldata _ctx, + TaikoData.Transition calldata _tran, + TaikoData.TierProof calldata _proof + ) + external + view + { + // Do not run proof verification to contest an existing proof + if (_ctx.isContesting) return; + + // Decode will throw if not proper length/encoding + // Off-chain RiscZeroVerifierInput.journalDigest can be left empty or bytes32(0) + RiscZeroVerifierInput memory riscZeroProof = + abi.decode(_proof.data, (RiscZeroVerifierInput)); + + if (!trustedImageId[riscZeroProof.imageId]) { + revert RISC_ZERO_INVALID_IMAGE_ID(); + } + + uint64 chainId = ITaikoL1(resolve("taiko", false)).getConfig().chainId; + + riscZeroProof.journalDigest = sha256( + abi.encode( + LibProofHash.getProofHash( + _tran, address(this), address(0), _ctx.prover, _ctx.metaHash, chainId + ) + ) + ); + + if ( + !riscZeroVerifier.verify( + riscZeroProof.seal, + riscZeroProof.imageId, + riscZeroProof.postStateDigest, + riscZeroProof.journalDigest + ) + ) { + revert RISC_ZERO_INVALID_PROOF(); + } + } +} diff --git a/packages/protocol/contracts/verifiers/SgxVerifier.sol b/packages/protocol/contracts/verifiers/SgxVerifier.sol index 8d1eb83f616..feea5f4d24d 100644 --- a/packages/protocol/contracts/verifiers/SgxVerifier.sol +++ b/packages/protocol/contracts/verifiers/SgxVerifier.sol @@ -7,6 +7,7 @@ import "../common/EssentialContract.sol"; import "../automata-attestation/interfaces/IAttestation.sol"; import "../automata-attestation/lib/QuoteV3Auth/V3Struct.sol"; import "./IVerifier.sol"; +import "./libs/LibProofHash.sol"; /// @title SgxVerifier /// @notice This contract is the implementation of verifying SGX signature proofs @@ -152,44 +153,20 @@ contract SgxVerifier is EssentialContract, IVerifier { uint32 id = uint32(bytes4(_proof.data[:4])); address newInstance = address(bytes20(_proof.data[4:24])); + + uint64 chainId = ITaikoL1(resolve("taiko", false)).getConfig().chainId; + address oldInstance = ECDSA.recover( - getSignedHash(_tran, newInstance, _ctx.prover, _ctx.metaHash), _proof.data[24:] + LibProofHash.getProofHash( + _tran, address(this), newInstance, _ctx.prover, _ctx.metaHash, chainId + ), + _proof.data[24:] ); if (!_isInstanceValid(id, oldInstance)) revert SGX_INVALID_INSTANCE(); _replaceInstance(id, oldInstance, newInstance); } - /// @notice Gets the signed hash for the proof verification. - /// @param _tran The transition to verify. - /// @param _newInstance The new instance address. - /// @param _prover The prover address. - /// @param _metaHash The meta hash. - /// @return The signed hash. - function getSignedHash( - TaikoData.Transition memory _tran, - address _newInstance, - address _prover, - bytes32 _metaHash - ) - public - view - returns (bytes32) - { - address taikoL1 = resolve("taiko", false); - return keccak256( - abi.encode( - "VERIFY_PROOF", - ITaikoL1(taikoL1).getConfig().chainId, - address(this), - _tran, - _newInstance, - _prover, - _metaHash - ) - ); - } - function _addInstances( address[] memory _instances, bool instantValid diff --git a/packages/protocol/contracts/verifiers/libs/LibProofHash.sol b/packages/protocol/contracts/verifiers/libs/LibProofHash.sol new file mode 100644 index 00000000000..dd0c61fe7ce --- /dev/null +++ b/packages/protocol/contracts/verifiers/libs/LibProofHash.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +import "../../L1/ITaikoL1.sol"; + +/// @title LibProofHash +/// @notice A library for handling hashing the so-called public input hash, used by sgx and zk +/// proofs. +/// @custom:security-contact security@taiko.xyz +library LibProofHash { + /// @notice Gets the hash for the proof verification. + /// @param _tran The transition to verify. + /// @param _newInstance The new instance address. For SGX it is the new signer address, for ZK + /// this variable is not used. + /// @param _prover The prover address. + /// @param _metaHash The meta hash. + /// @return The public input hash. + function getProofHash( + TaikoData.Transition memory _tran, + address _verifierContract, + address _newInstance, + address _prover, + bytes32 _metaHash, + uint64 _chainId + ) + public + pure + returns (bytes32) + { + return keccak256( + abi.encode( + "VERIFY_PROOF", _chainId, _verifierContract, _tran, _newInstance, _prover, _metaHash + ) + ); + } +} diff --git a/packages/protocol/test/L1/TaikoL1TestBase.sol b/packages/protocol/test/L1/TaikoL1TestBase.sol index 51f79e1887d..9a2ceca6020 100644 --- a/packages/protocol/test/L1/TaikoL1TestBase.sol +++ b/packages/protocol/test/L1/TaikoL1TestBase.sol @@ -330,7 +330,10 @@ abstract contract TaikoL1TestBase is TaikoTest { view returns (bytes memory signature) { - bytes32 digest = sv.getSignedHash(tran, newInstance, prover, metaHash); + uint64 chainId = L1.getConfig().chainId; + bytes32 digest = + LibProofHash.getProofHash(tran, address(sv), newInstance, prover, metaHash, chainId); + //bytes32 digest = sv.getSignedHash(tran, newInstance, prover, metaHash); uint256 signerPrivateKey; diff --git a/packages/protocol/test/TaikoTest.sol b/packages/protocol/test/TaikoTest.sol index 861ce02643a..318db39cb49 100644 --- a/packages/protocol/test/TaikoTest.sol +++ b/packages/protocol/test/TaikoTest.sol @@ -20,6 +20,7 @@ import "../contracts/tokenvault/ERC1155Vault.sol"; import "../contracts/L1/TaikoToken.sol"; import "../contracts/L1/TaikoL1.sol"; +import "../contracts/verifiers/libs/LibProofHash.sol"; import "../contracts/verifiers/SgxVerifier.sol"; import "../contracts/verifiers/GuardianVerifier.sol"; import "../contracts/L1/tiers/TestnetTierProvider.sol"; diff --git a/packages/protocol/test/verifiers/SgxVerifier.t.sol b/packages/protocol/test/verifiers/SgxVerifier.t.sol index 779414827ee..f1ba7c73464 100644 --- a/packages/protocol/test/verifiers/SgxVerifier.t.sol +++ b/packages/protocol/test/verifiers/SgxVerifier.t.sol @@ -202,12 +202,18 @@ contract TestSgxVerifier is TaikoL1TestBase, AttestationBase { // TierProof address newInstance = address(0x33); - bytes32 signedHash = sv.getSignedHash(transition, newInstance, ctx.prover, ctx.metaHash); + uint64 chainId = L1.getConfig().chainId; + bytes32 signedHash = LibProofHash.getProofHash( + transition, address(sv), newInstance, ctx.prover, ctx.metaHash, chainId + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(KNOWN_ADDRESS_PRIV_KEY, signedHash); bytes memory signature = abi.encodePacked(r, s, v); - bytes memory data = abi.encodePacked(id, newInstance, signature); - TaikoData.TierProof memory proof = TaikoData.TierProof({ tier: 100, data: data }); + // bytes memory data = abi.encodePacked(id, newInstance, signature); -> comment out to avoid + // stack too deep. + TaikoData.TierProof memory proof = + TaikoData.TierProof({ tier: 100, data: abi.encodePacked(id, newInstance, signature) }); vm.warp(block.timestamp + 5); @@ -356,7 +362,11 @@ contract TestSgxVerifier is TaikoL1TestBase, AttestationBase { // TierProof address newInstance = address(0x33); - bytes32 signedHash = sv.getSignedHash(transition, newInstance, ctx.prover, ctx.metaHash); + uint64 chainId = L1.getConfig().chainId; + bytes32 signedHash = LibProofHash.getProofHash( + transition, address(sv), newInstance, ctx.prover, ctx.metaHash, chainId + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(KNOWN_ADDRESS_PRIV_KEY, signedHash); bytes memory signature = abi.encodePacked(r, s, v); @@ -397,7 +407,11 @@ contract TestSgxVerifier is TaikoL1TestBase, AttestationBase { uint32 id = 0; address newInstance = address(0x33); - bytes32 signedHash = sv.getSignedHash(transition, newInstance, ctx.prover, ctx.metaHash); + uint64 chainId = L1.getConfig().chainId; + bytes32 signedHash = LibProofHash.getProofHash( + transition, address(sv), newInstance, ctx.prover, ctx.metaHash, chainId + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(KNOWN_ADDRESS_PRIV_KEY, signedHash); bytes memory signature = abi.encodePacked(r, s, v); From 07c865269ef8c6ec0695e7e56bd8f56af5b6077a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Keszey=20D=C3=A1niel?= Date: Tue, 5 Mar 2024 17:24:55 +0100 Subject: [PATCH 2/9] remove comment --- packages/protocol/test/L1/TaikoL1TestBase.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/protocol/test/L1/TaikoL1TestBase.sol b/packages/protocol/test/L1/TaikoL1TestBase.sol index 9a2ceca6020..34e24cca437 100644 --- a/packages/protocol/test/L1/TaikoL1TestBase.sol +++ b/packages/protocol/test/L1/TaikoL1TestBase.sol @@ -333,7 +333,6 @@ abstract contract TaikoL1TestBase is TaikoTest { uint64 chainId = L1.getConfig().chainId; bytes32 digest = LibProofHash.getProofHash(tran, address(sv), newInstance, prover, metaHash, chainId); - //bytes32 digest = sv.getSignedHash(tran, newInstance, prover, metaHash); uint256 signerPrivateKey; From cdff48c08071052e1dff404f12c25ffb54096347 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Keszey=20D=C3=A1niel?= Date: Wed, 6 Mar 2024 16:44:12 +0100 Subject: [PATCH 3/9] test and pr review --- .../contracts/verifiers/RiscZeroVerifier.sol | 51 ++--- .../contracts/verifiers/SgxVerifier.sol | 4 +- ...ibProofHash.sol => LibPublicInputHash.sol} | 14 +- packages/protocol/test/L1/TaikoL1TestBase.sol | 6 +- packages/protocol/test/TaikoTest.sol | 3 +- .../test/verifiers/RiscZeroVerifier.t.sol | 186 ++++++++++++++++++ .../protocol/test/verifiers/SgxVerifier.t.sol | 6 +- 7 files changed, 222 insertions(+), 48 deletions(-) rename packages/protocol/contracts/verifiers/libs/{LibProofHash.sol => LibPublicInputHash.sol} (70%) create mode 100644 packages/protocol/test/verifiers/RiscZeroVerifier.t.sol diff --git a/packages/protocol/contracts/verifiers/RiscZeroVerifier.sol b/packages/protocol/contracts/verifiers/RiscZeroVerifier.sol index a3d49586503..90519f9a1a6 100644 --- a/packages/protocol/contracts/verifiers/RiscZeroVerifier.sol +++ b/packages/protocol/contracts/verifiers/RiscZeroVerifier.sol @@ -4,20 +4,20 @@ pragma solidity 0.8.24; import "../common/EssentialContract.sol"; import "../L1/ITaikoL1.sol"; import "./IVerifier.sol"; -import "./libs/LibProofHash.sol"; +import "./libs/LibPublicInputHash.sol"; /// @notice Verifier interface for RISC Zero receipts of execution. /// https://github.com/risc0/risc0-ethereum/blob/release-0.7/contracts/src/IRiscZeroVerifier.sol interface IRiscZeroVerifier { /// @notice Verify that the given seal is a valid RISC Zero proof of execution with the - /// given image ID, post-state digest, and journal digest. + /// given image ID, post-state digest, and journal digest. /// @dev This method additionally ensures that the input hash is all-zeros (i.e. no /// committed input), the exit code is (Halted, 0), and there are no assumptions (i.e. the /// receipt is unconditional). /// @param seal The encoded cryptographic proof (i.e. SNARK). /// @param imageId The identifier for the guest program. /// @param postStateDigest A hash of the final memory state. Required to run the verifier, but - /// otherwise can be left unconstrained for most use cases. + /// otherwise can be left unconstrained for most use cases. /// @param journalDigest The SHA-256 digest of the journal bytes. /// @return true if the receipt passes the verification checks. The return code must be checked. function verify( @@ -34,18 +34,10 @@ interface IRiscZeroVerifier { /// @title RiscZeroVerifier /// @custom:security-contact security@taiko.xyz contract RiscZeroVerifier is EssentialContract, IVerifier { - /// @dev For RiscZeroVerifier's verify() - struct RiscZeroVerifierInput { - bytes seal; - bytes32 imageId; - bytes32 postStateDigest; - bytes32 journalDigest; - } - /// @notice RISC Zero verifier contract address. IRiscZeroVerifier public riscZeroVerifier; /// @notice Trusted imageId mapping - mapping(bytes32 imageId => bool trusted) public trustedImageId; + mapping(bytes32 imageId => bool trusted) public isImageTrusted; uint256[48] private __gap; @@ -53,9 +45,10 @@ contract RiscZeroVerifier is EssentialContract, IVerifier { error RISC_ZERO_INVALID_PROOF(); /// @notice Initializes the contract with the provided address manager. - /// @param _addressManager The address of the address manager contract. + /// @param _addressManager The address of the AddressManager. + /// @param _riscZeroVerifier The address of the risc zero verifier contract. function init(address _addressManager, address _riscZeroVerifier) external initializer { - __Essential_init(_addressManager); + __Essential_init(address(0), _addressManager); riscZeroVerifier = IRiscZeroVerifier(_riscZeroVerifier); } @@ -63,7 +56,7 @@ contract RiscZeroVerifier is EssentialContract, IVerifier { /// @param _imageId The id of the image. /// @param _trusted True if trusted, false otherwise. function setImageIdTrusted(bytes32 _imageId, bool _trusted) external onlyOwner { - trustedImageId[_imageId] = _trusted; + isImageTrusted[_imageId] = _trusted; } /// @inheritdoc IVerifier @@ -79,32 +72,22 @@ contract RiscZeroVerifier is EssentialContract, IVerifier { if (_ctx.isContesting) return; // Decode will throw if not proper length/encoding - // Off-chain RiscZeroVerifierInput.journalDigest can be left empty or bytes32(0) - RiscZeroVerifierInput memory riscZeroProof = - abi.decode(_proof.data, (RiscZeroVerifierInput)); + (bytes memory seal, bytes32 imageId, bytes32 postStateDigest) = + abi.decode(_proof.data, (bytes, bytes32, bytes32)); - if (!trustedImageId[riscZeroProof.imageId]) { + if (!isImageTrusted[imageId]) { revert RISC_ZERO_INVALID_IMAGE_ID(); } uint64 chainId = ITaikoL1(resolve("taiko", false)).getConfig().chainId; - - riscZeroProof.journalDigest = sha256( - abi.encode( - LibProofHash.getProofHash( - _tran, address(this), address(0), _ctx.prover, _ctx.metaHash, chainId - ) - ) + bytes32 hash = LibPublicInputHash.hashPublicInputs( + _tran, address(this), address(0), _ctx.prover, _ctx.metaHash, chainId ); - if ( - !riscZeroVerifier.verify( - riscZeroProof.seal, - riscZeroProof.imageId, - riscZeroProof.postStateDigest, - riscZeroProof.journalDigest - ) - ) { + // journalDigest is the sha256 hash of the hashed public input + bytes32 journalDigest = sha256(bytes.concat(hash)); + + if (!riscZeroVerifier.verify(seal, imageId, postStateDigest, journalDigest)) { revert RISC_ZERO_INVALID_PROOF(); } } diff --git a/packages/protocol/contracts/verifiers/SgxVerifier.sol b/packages/protocol/contracts/verifiers/SgxVerifier.sol index feea5f4d24d..48d0f413afb 100644 --- a/packages/protocol/contracts/verifiers/SgxVerifier.sol +++ b/packages/protocol/contracts/verifiers/SgxVerifier.sol @@ -7,7 +7,7 @@ import "../common/EssentialContract.sol"; import "../automata-attestation/interfaces/IAttestation.sol"; import "../automata-attestation/lib/QuoteV3Auth/V3Struct.sol"; import "./IVerifier.sol"; -import "./libs/LibProofHash.sol"; +import "./libs/LibPublicInputHash.sol"; /// @title SgxVerifier /// @notice This contract is the implementation of verifying SGX signature proofs @@ -157,7 +157,7 @@ contract SgxVerifier is EssentialContract, IVerifier { uint64 chainId = ITaikoL1(resolve("taiko", false)).getConfig().chainId; address oldInstance = ECDSA.recover( - LibProofHash.getProofHash( + LibPublicInputHash.hashPublicInputs( _tran, address(this), newInstance, _ctx.prover, _ctx.metaHash, chainId ), _proof.data[24:] diff --git a/packages/protocol/contracts/verifiers/libs/LibProofHash.sol b/packages/protocol/contracts/verifiers/libs/LibPublicInputHash.sol similarity index 70% rename from packages/protocol/contracts/verifiers/libs/LibProofHash.sol rename to packages/protocol/contracts/verifiers/libs/LibPublicInputHash.sol index dd0c61fe7ce..7c53d79f67d 100644 --- a/packages/protocol/contracts/verifiers/libs/LibProofHash.sol +++ b/packages/protocol/contracts/verifiers/libs/LibPublicInputHash.sol @@ -1,21 +1,23 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.24; -import "../../L1/ITaikoL1.sol"; +import "../../L1/TaikoData.sol"; -/// @title LibProofHash +/// @title LibPublicInputHash /// @notice A library for handling hashing the so-called public input hash, used by sgx and zk /// proofs. /// @custom:security-contact security@taiko.xyz -library LibProofHash { - /// @notice Gets the hash for the proof verification. +library LibPublicInputHash { + /// @notice Hashes the public input for the proof verification. /// @param _tran The transition to verify. + /// @param _verifierContract The contract address which as current verifier. /// @param _newInstance The new instance address. For SGX it is the new signer address, for ZK - /// this variable is not used. + /// this variable is not used and must have value address(0). /// @param _prover The prover address. /// @param _metaHash The meta hash. + /// @param _chainId The chain id. /// @return The public input hash. - function getProofHash( + function hashPublicInputs( TaikoData.Transition memory _tran, address _verifierContract, address _newInstance, diff --git a/packages/protocol/test/L1/TaikoL1TestBase.sol b/packages/protocol/test/L1/TaikoL1TestBase.sol index 34e24cca437..75fb4395f3e 100644 --- a/packages/protocol/test/L1/TaikoL1TestBase.sol +++ b/packages/protocol/test/L1/TaikoL1TestBase.sol @@ -11,6 +11,7 @@ abstract contract TaikoL1TestBase is TaikoTest { TaikoL1 public L1; TaikoData.Config conf; uint256 internal logCount; + RiscZeroVerifier public rv; SgxVerifier public sv; GuardianVerifier public gv; GuardianProver public gp; @@ -331,8 +332,9 @@ abstract contract TaikoL1TestBase is TaikoTest { returns (bytes memory signature) { uint64 chainId = L1.getConfig().chainId; - bytes32 digest = - LibProofHash.getProofHash(tran, address(sv), newInstance, prover, metaHash, chainId); + bytes32 digest = LibPublicInputHash.hashPublicInputs( + tran, address(sv), newInstance, prover, metaHash, chainId + ); uint256 signerPrivateKey; diff --git a/packages/protocol/test/TaikoTest.sol b/packages/protocol/test/TaikoTest.sol index 318db39cb49..e9cafd4ab0d 100644 --- a/packages/protocol/test/TaikoTest.sol +++ b/packages/protocol/test/TaikoTest.sol @@ -20,8 +20,9 @@ import "../contracts/tokenvault/ERC1155Vault.sol"; import "../contracts/L1/TaikoToken.sol"; import "../contracts/L1/TaikoL1.sol"; -import "../contracts/verifiers/libs/LibProofHash.sol"; +import "../contracts/verifiers/libs/LibPublicInputHash.sol"; import "../contracts/verifiers/SgxVerifier.sol"; +import "../contracts/verifiers/RiscZeroVerifier.sol"; import "../contracts/verifiers/GuardianVerifier.sol"; import "../contracts/L1/tiers/TestnetTierProvider.sol"; import "../contracts/L1/tiers/ITierProvider.sol"; diff --git a/packages/protocol/test/verifiers/RiscZeroVerifier.t.sol b/packages/protocol/test/verifiers/RiscZeroVerifier.t.sol new file mode 100644 index 00000000000..1f14ae8f914 --- /dev/null +++ b/packages/protocol/test/verifiers/RiscZeroVerifier.t.sol @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +import "../L1/TaikoL1TestBase.sol"; + +contract MockRiscZeroRemoteVerifier { + // To simulate failing and succeeding + bool public verifying; + + function setVerifier(bool _verifying) public { + verifying = _verifying; + } + + function verify( + bytes calldata, /*seal*/ + bytes32, /*imageId*/ + bytes32, /*postStateDigest*/ + bytes32 /*journalDigest*/ + ) + external + view + returns (bool) + { + return verifying; + } +} + +contract TestRiscZeroVerifier is TaikoL1TestBase { + MockRiscZeroRemoteVerifier riscZeroRemoteVerifier; + + function deployTaikoL1() internal override returns (TaikoL1) { + return + TaikoL1(payable(deployProxy({ name: "taiko", impl: address(new TaikoL1()), data: "" }))); + } + + function setUp() public override { + // Call the TaikoL1TestBase setUp() + super.setUp(); + + riscZeroRemoteVerifier = new MockRiscZeroRemoteVerifier(); + riscZeroRemoteVerifier.setVerifier(true); + + // Deploy Taiko's RiscZero proof verifier + rv = RiscZeroVerifier( + deployProxy({ + name: "tier_risc_zero", + impl: address(new RiscZeroVerifier()), + data: abi.encodeCall( + RiscZeroVerifier.init, (address(addressManager), address(riscZeroRemoteVerifier)) + ) + }) + ); + + rv.setImageIdTrusted(bytes32("11"), true); + + registerAddress("risc_zero_verifier", address(rv)); + } + + // Test `verifyProof()` happy path + function test_verifyProof() external { + vm.stopPrank(); + + // Caller not necessary has to be TaikoL1 contract because there is no keys (as in SGX keys) + // to be front run. + vm.startPrank(Alice); + + // Context + IVerifier.Context memory ctx = IVerifier.Context({ + metaHash: bytes32("ab"), + blobHash: bytes32("cd"), + prover: address(0), + msgSender: address(0), + blockId: 10, + isContesting: false, + blobUsed: false + }); + + // Transition + TaikoData.Transition memory transition = TaikoData.Transition({ + parentHash: bytes32("12"), + blockHash: bytes32("34"), + stateRoot: bytes32("56"), + graffiti: bytes32("78") + }); + + bytes memory seal = hex"00"; + bytes32 imageId = bytes32("11"); + bytes32 postStateDigest = bytes32("22"); + + // TierProof + TaikoData.TierProof memory proof = + TaikoData.TierProof({ tier: 100, data: abi.encode(seal, imageId, postStateDigest) }); + + vm.warp(block.timestamp + 5); + + // `verifyProof()` + rv.verifyProof(ctx, transition, proof); + + vm.stopPrank(); + } + + function test_verifyProof_invalidImageId() external { + vm.stopPrank(); + + // Caller not necessary has to be TaikoL1 contract because there is no keys (as in SGX keys) + // to be front run. + vm.startPrank(Alice); + + // Context + IVerifier.Context memory ctx = IVerifier.Context({ + metaHash: bytes32("ab"), + blobHash: bytes32("cd"), + prover: address(0), + msgSender: address(0), + blockId: 10, + isContesting: false, + blobUsed: false + }); + + // Transition + TaikoData.Transition memory transition = TaikoData.Transition({ + parentHash: bytes32("12"), + blockHash: bytes32("34"), + stateRoot: bytes32("56"), + graffiti: bytes32("78") + }); + + bytes memory seal = hex"00"; + bytes32 imageId = bytes32("121"); + bytes32 postStateDigest = bytes32("22"); + + // TierProof + TaikoData.TierProof memory proof = + TaikoData.TierProof({ tier: 100, data: abi.encode(seal, imageId, postStateDigest) }); + + vm.warp(block.timestamp + 5); + + vm.expectRevert(RiscZeroVerifier.RISC_ZERO_INVALID_IMAGE_ID.selector); + rv.verifyProof(ctx, transition, proof); + + vm.stopPrank(); + } + + function test_verifyProof_invalidProof() external { + riscZeroRemoteVerifier.setVerifier(false); + vm.stopPrank(); + + // Caller not necessary has to be TaikoL1 contract because there is no keys (as in SGX keys) + // to be front run. + vm.startPrank(Alice); + + // Context + IVerifier.Context memory ctx = IVerifier.Context({ + metaHash: bytes32("ab"), + blobHash: bytes32("cd"), + prover: address(0), + msgSender: address(0), + blockId: 10, + isContesting: false, + blobUsed: false + }); + + // Transition + TaikoData.Transition memory transition = TaikoData.Transition({ + parentHash: bytes32("12"), + blockHash: bytes32("34"), + stateRoot: bytes32("56"), + graffiti: bytes32("78") + }); + + bytes memory seal = hex"00"; + bytes32 imageId = bytes32("11"); + bytes32 postStateDigest = bytes32("22"); + + // TierProof + TaikoData.TierProof memory proof = + TaikoData.TierProof({ tier: 100, data: abi.encode(seal, imageId, postStateDigest) }); + + vm.warp(block.timestamp + 5); + + vm.expectRevert(RiscZeroVerifier.RISC_ZERO_INVALID_PROOF.selector); + rv.verifyProof(ctx, transition, proof); + + vm.stopPrank(); + } +} diff --git a/packages/protocol/test/verifiers/SgxVerifier.t.sol b/packages/protocol/test/verifiers/SgxVerifier.t.sol index f1ba7c73464..02c82e72532 100644 --- a/packages/protocol/test/verifiers/SgxVerifier.t.sol +++ b/packages/protocol/test/verifiers/SgxVerifier.t.sol @@ -203,7 +203,7 @@ contract TestSgxVerifier is TaikoL1TestBase, AttestationBase { address newInstance = address(0x33); uint64 chainId = L1.getConfig().chainId; - bytes32 signedHash = LibProofHash.getProofHash( + bytes32 signedHash = LibPublicInputHash.hashPublicInputs( transition, address(sv), newInstance, ctx.prover, ctx.metaHash, chainId ); @@ -363,7 +363,7 @@ contract TestSgxVerifier is TaikoL1TestBase, AttestationBase { address newInstance = address(0x33); uint64 chainId = L1.getConfig().chainId; - bytes32 signedHash = LibProofHash.getProofHash( + bytes32 signedHash = LibPublicInputHash.hashPublicInputs( transition, address(sv), newInstance, ctx.prover, ctx.metaHash, chainId ); @@ -408,7 +408,7 @@ contract TestSgxVerifier is TaikoL1TestBase, AttestationBase { address newInstance = address(0x33); uint64 chainId = L1.getConfig().chainId; - bytes32 signedHash = LibProofHash.getProofHash( + bytes32 signedHash = LibPublicInputHash.hashPublicInputs( transition, address(sv), newInstance, ctx.prover, ctx.metaHash, chainId ); From bc3e7b03a40a23e96f2beae5d1aed456a7e919ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Keszey=20D=C3=A1niel?= Date: Thu, 7 Mar 2024 11:03:29 +0100 Subject: [PATCH 4/9] pr findings --- .../risczero/IRiscZeroRemoteVerifier.sol | 27 +++++++++++ .../contracts/verifiers/RiscZeroVerifier.sol | 48 ++++++++----------- .../test/verifiers/RiscZeroVerifier.t.sol | 3 +- 3 files changed, 49 insertions(+), 29 deletions(-) create mode 100644 packages/protocol/contracts/thirdparty/risczero/IRiscZeroRemoteVerifier.sol diff --git a/packages/protocol/contracts/thirdparty/risczero/IRiscZeroRemoteVerifier.sol b/packages/protocol/contracts/thirdparty/risczero/IRiscZeroRemoteVerifier.sol new file mode 100644 index 00000000000..72940f8fc02 --- /dev/null +++ b/packages/protocol/contracts/thirdparty/risczero/IRiscZeroRemoteVerifier.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +/// @notice Verifier interface for RISC Zero receipts of execution. +/// https://github.com/risc0/risc0-ethereum/blob/release-0.7/contracts/src/IRiscZeroVerifier.sol +interface IRiscZeroRemoteVerifier { + /// @notice Verify that the given seal is a valid RISC Zero proof of execution with the + /// given image ID, post-state digest, and journal digest. + /// @dev This method additionally ensures that the input hash is all-zeros (i.e. no + /// committed input), the exit code is (Halted, 0), and there are no assumptions (i.e. the + /// receipt is unconditional). + /// @param seal The encoded cryptographic proof (i.e. SNARK). + /// @param imageId The identifier for the guest program. + /// @param postStateDigest A hash of the final memory state. Required to run the verifier, but + /// otherwise can be left unconstrained for most use cases. + /// @param journalDigest The SHA-256 digest of the journal bytes. + /// @return true if the receipt passes the verification checks. The return code must be checked. + function verify( + bytes calldata seal, + bytes32 imageId, + bytes32 postStateDigest, + bytes32 journalDigest + ) + external + view + returns (bool); +} diff --git a/packages/protocol/contracts/verifiers/RiscZeroVerifier.sol b/packages/protocol/contracts/verifiers/RiscZeroVerifier.sol index 90519f9a1a6..2b21ffb49ed 100644 --- a/packages/protocol/contracts/verifiers/RiscZeroVerifier.sol +++ b/packages/protocol/contracts/verifiers/RiscZeroVerifier.sol @@ -6,50 +6,40 @@ import "../L1/ITaikoL1.sol"; import "./IVerifier.sol"; import "./libs/LibPublicInputHash.sol"; -/// @notice Verifier interface for RISC Zero receipts of execution. -/// https://github.com/risc0/risc0-ethereum/blob/release-0.7/contracts/src/IRiscZeroVerifier.sol -interface IRiscZeroVerifier { - /// @notice Verify that the given seal is a valid RISC Zero proof of execution with the - /// given image ID, post-state digest, and journal digest. - /// @dev This method additionally ensures that the input hash is all-zeros (i.e. no - /// committed input), the exit code is (Halted, 0), and there are no assumptions (i.e. the - /// receipt is unconditional). - /// @param seal The encoded cryptographic proof (i.e. SNARK). - /// @param imageId The identifier for the guest program. - /// @param postStateDigest A hash of the final memory state. Required to run the verifier, but - /// otherwise can be left unconstrained for most use cases. - /// @param journalDigest The SHA-256 digest of the journal bytes. - /// @return true if the receipt passes the verification checks. The return code must be checked. - function verify( - bytes calldata seal, - bytes32 imageId, - bytes32 postStateDigest, - bytes32 journalDigest - ) - external - view - returns (bool); -} +import "../thirdparty/risczero/IRiscZeroRemoteVerifier.sol"; /// @title RiscZeroVerifier /// @custom:security-contact security@taiko.xyz contract RiscZeroVerifier is EssentialContract, IVerifier { /// @notice RISC Zero verifier contract address. - IRiscZeroVerifier public riscZeroVerifier; + IRiscZeroRemoteVerifier public riscZeroVerifier; /// @notice Trusted imageId mapping mapping(bytes32 imageId => bool trusted) public isImageTrusted; uint256[48] private __gap; + /// @dev Emitted when a trusted image is set / unset. + /// @param imageId The id of the image + /// @param trusted The block's assigned prover. + event SetImageTrusted(bytes32 imageId, bool trusted); + error RISC_ZERO_INVALID_IMAGE_ID(); error RISC_ZERO_INVALID_PROOF(); /// @notice Initializes the contract with the provided address manager. + /// @param _owner The address of the owner. /// @param _addressManager The address of the AddressManager. /// @param _riscZeroVerifier The address of the risc zero verifier contract. - function init(address _addressManager, address _riscZeroVerifier) external initializer { - __Essential_init(address(0), _addressManager); - riscZeroVerifier = IRiscZeroVerifier(_riscZeroVerifier); + function init( + address _owner, + address _addressManager, + address _riscZeroVerifier + ) + external + initializer + { + __Essential_init(_owner, _addressManager); + riscZeroVerifier = IRiscZeroRemoteVerifier(_riscZeroVerifier); } /// @notice Sets/unsets an the imageId as trusted entity @@ -57,6 +47,8 @@ contract RiscZeroVerifier is EssentialContract, IVerifier { /// @param _trusted True if trusted, false otherwise. function setImageIdTrusted(bytes32 _imageId, bool _trusted) external onlyOwner { isImageTrusted[_imageId] = _trusted; + + emit SetImageTrusted(_imageId, _trusted); } /// @inheritdoc IVerifier diff --git a/packages/protocol/test/verifiers/RiscZeroVerifier.t.sol b/packages/protocol/test/verifiers/RiscZeroVerifier.t.sol index 1f14ae8f914..053f3233188 100644 --- a/packages/protocol/test/verifiers/RiscZeroVerifier.t.sol +++ b/packages/protocol/test/verifiers/RiscZeroVerifier.t.sol @@ -46,7 +46,8 @@ contract TestRiscZeroVerifier is TaikoL1TestBase { name: "tier_risc_zero", impl: address(new RiscZeroVerifier()), data: abi.encodeCall( - RiscZeroVerifier.init, (address(addressManager), address(riscZeroRemoteVerifier)) + RiscZeroVerifier.init, + (address(0), address(addressManager), address(riscZeroRemoteVerifier)) ) }) ); From 6c99b11cf947dd71aa39e7c7884bfaedfdc0096d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Keszey=20D=C3=A1niel?= Date: Thu, 7 Mar 2024 14:55:02 +0100 Subject: [PATCH 5/9] renamings --- .../protocol/contracts/thirdparty/README.md | 4 +++- ...ifier.sol => IRiscZeroReceiptVerifier.sol} | 2 +- .../contracts/verifiers/RiscZeroVerifier.sol | 22 +++++++++---------- .../contracts/verifiers/SgxVerifier.sol | 4 ++-- ...PublicInputHash.sol => LibPublicInput.sol} | 4 ++-- packages/protocol/test/L1/TaikoL1TestBase.sol | 2 +- packages/protocol/test/TaikoTest.sol | 2 +- .../protocol/test/verifiers/SgxVerifier.t.sol | 6 ++--- 8 files changed, 24 insertions(+), 22 deletions(-) rename packages/protocol/contracts/thirdparty/risczero/{IRiscZeroRemoteVerifier.sol => IRiscZeroReceiptVerifier.sol} (97%) rename packages/protocol/contracts/verifiers/libs/{LibPublicInputHash.sol => LibPublicInput.sol} (95%) diff --git a/packages/protocol/contracts/thirdparty/README.md b/packages/protocol/contracts/thirdparty/README.md index 94e0ed63769..730c337fe1d 100644 --- a/packages/protocol/contracts/thirdparty/README.md +++ b/packages/protocol/contracts/thirdparty/README.md @@ -4,4 +4,6 @@ - /solmate: code copied from https://github.com/transmissions11/solmate/blob/v7/src/utils/FixedPointMathLib.sol as-is with only solidity pragma changed. -- /nomad-xyz: code copied from https://github.com/nomad-xyz/ExcessivelySafeCall/blob/main/src/ExcessivelySafeCall.sol with unused coded removed and solidity pragma changed. \ No newline at end of file +- /nomad-xyz: code copied from https://github.com/nomad-xyz/ExcessivelySafeCall/blob/main/src/ExcessivelySafeCall.sol with unused coded removed and solidity pragma changed. + +- /risczero: interface copied from https://sepolia.etherscan.io/address/0x83c2e9cd64b2a16d3908e94c7654f3864212e2f8#code as per: https://dev.risczero.com/api/bonsai/bonsai-on-eth#verifier-contract diff --git a/packages/protocol/contracts/thirdparty/risczero/IRiscZeroRemoteVerifier.sol b/packages/protocol/contracts/thirdparty/risczero/IRiscZeroReceiptVerifier.sol similarity index 97% rename from packages/protocol/contracts/thirdparty/risczero/IRiscZeroRemoteVerifier.sol rename to packages/protocol/contracts/thirdparty/risczero/IRiscZeroReceiptVerifier.sol index 72940f8fc02..841b1c99423 100644 --- a/packages/protocol/contracts/thirdparty/risczero/IRiscZeroRemoteVerifier.sol +++ b/packages/protocol/contracts/thirdparty/risczero/IRiscZeroReceiptVerifier.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.24; /// @notice Verifier interface for RISC Zero receipts of execution. /// https://github.com/risc0/risc0-ethereum/blob/release-0.7/contracts/src/IRiscZeroVerifier.sol -interface IRiscZeroRemoteVerifier { +interface IRiscZeroReceiptVerifier { /// @notice Verify that the given seal is a valid RISC Zero proof of execution with the /// given image ID, post-state digest, and journal digest. /// @dev This method additionally ensures that the input hash is all-zeros (i.e. no diff --git a/packages/protocol/contracts/verifiers/RiscZeroVerifier.sol b/packages/protocol/contracts/verifiers/RiscZeroVerifier.sol index 2b21ffb49ed..76615b04583 100644 --- a/packages/protocol/contracts/verifiers/RiscZeroVerifier.sol +++ b/packages/protocol/contracts/verifiers/RiscZeroVerifier.sol @@ -4,15 +4,15 @@ pragma solidity 0.8.24; import "../common/EssentialContract.sol"; import "../L1/ITaikoL1.sol"; import "./IVerifier.sol"; -import "./libs/LibPublicInputHash.sol"; +import "./libs/LibPublicInput.sol"; -import "../thirdparty/risczero/IRiscZeroRemoteVerifier.sol"; +import "../thirdparty/risczero/IRiscZeroReceiptVerifier.sol"; /// @title RiscZeroVerifier /// @custom:security-contact security@taiko.xyz contract RiscZeroVerifier is EssentialContract, IVerifier { - /// @notice RISC Zero verifier contract address. - IRiscZeroRemoteVerifier public riscZeroVerifier; + /// @notice RISC Zero remote verifier contract address. + IRiscZeroReceiptVerifier public receiptVerifier; /// @notice Trusted imageId mapping mapping(bytes32 imageId => bool trusted) public isImageTrusted; @@ -21,7 +21,7 @@ contract RiscZeroVerifier is EssentialContract, IVerifier { /// @dev Emitted when a trusted image is set / unset. /// @param imageId The id of the image /// @param trusted The block's assigned prover. - event SetImageTrusted(bytes32 imageId, bool trusted); + event ImageTrusted(bytes32 imageId, bool trusted); error RISC_ZERO_INVALID_IMAGE_ID(); error RISC_ZERO_INVALID_PROOF(); @@ -29,17 +29,17 @@ contract RiscZeroVerifier is EssentialContract, IVerifier { /// @notice Initializes the contract with the provided address manager. /// @param _owner The address of the owner. /// @param _addressManager The address of the AddressManager. - /// @param _riscZeroVerifier The address of the risc zero verifier contract. + /// @param _receiptVerifier The address of the risc zero receipt verifier contract. function init( address _owner, address _addressManager, - address _riscZeroVerifier + address _receiptVerifier ) external initializer { __Essential_init(_owner, _addressManager); - riscZeroVerifier = IRiscZeroRemoteVerifier(_riscZeroVerifier); + receiptVerifier = IRiscZeroReceiptVerifier(_receiptVerifier); } /// @notice Sets/unsets an the imageId as trusted entity @@ -48,7 +48,7 @@ contract RiscZeroVerifier is EssentialContract, IVerifier { function setImageIdTrusted(bytes32 _imageId, bool _trusted) external onlyOwner { isImageTrusted[_imageId] = _trusted; - emit SetImageTrusted(_imageId, _trusted); + emit ImageTrusted(_imageId, _trusted); } /// @inheritdoc IVerifier @@ -72,14 +72,14 @@ contract RiscZeroVerifier is EssentialContract, IVerifier { } uint64 chainId = ITaikoL1(resolve("taiko", false)).getConfig().chainId; - bytes32 hash = LibPublicInputHash.hashPublicInputs( + bytes32 hash = LibPublicInput.hashPublicInputs( _tran, address(this), address(0), _ctx.prover, _ctx.metaHash, chainId ); // journalDigest is the sha256 hash of the hashed public input bytes32 journalDigest = sha256(bytes.concat(hash)); - if (!riscZeroVerifier.verify(seal, imageId, postStateDigest, journalDigest)) { + if (!receiptVerifier.verify(seal, imageId, postStateDigest, journalDigest)) { revert RISC_ZERO_INVALID_PROOF(); } } diff --git a/packages/protocol/contracts/verifiers/SgxVerifier.sol b/packages/protocol/contracts/verifiers/SgxVerifier.sol index 48d0f413afb..d970ede0e8e 100644 --- a/packages/protocol/contracts/verifiers/SgxVerifier.sol +++ b/packages/protocol/contracts/verifiers/SgxVerifier.sol @@ -7,7 +7,7 @@ import "../common/EssentialContract.sol"; import "../automata-attestation/interfaces/IAttestation.sol"; import "../automata-attestation/lib/QuoteV3Auth/V3Struct.sol"; import "./IVerifier.sol"; -import "./libs/LibPublicInputHash.sol"; +import "./libs/LibPublicInput.sol"; /// @title SgxVerifier /// @notice This contract is the implementation of verifying SGX signature proofs @@ -157,7 +157,7 @@ contract SgxVerifier is EssentialContract, IVerifier { uint64 chainId = ITaikoL1(resolve("taiko", false)).getConfig().chainId; address oldInstance = ECDSA.recover( - LibPublicInputHash.hashPublicInputs( + LibPublicInput.hashPublicInputs( _tran, address(this), newInstance, _ctx.prover, _ctx.metaHash, chainId ), _proof.data[24:] diff --git a/packages/protocol/contracts/verifiers/libs/LibPublicInputHash.sol b/packages/protocol/contracts/verifiers/libs/LibPublicInput.sol similarity index 95% rename from packages/protocol/contracts/verifiers/libs/LibPublicInputHash.sol rename to packages/protocol/contracts/verifiers/libs/LibPublicInput.sol index 7c53d79f67d..722dc187d71 100644 --- a/packages/protocol/contracts/verifiers/libs/LibPublicInputHash.sol +++ b/packages/protocol/contracts/verifiers/libs/LibPublicInput.sol @@ -3,11 +3,11 @@ pragma solidity 0.8.24; import "../../L1/TaikoData.sol"; -/// @title LibPublicInputHash +/// @title LibPublicInput /// @notice A library for handling hashing the so-called public input hash, used by sgx and zk /// proofs. /// @custom:security-contact security@taiko.xyz -library LibPublicInputHash { +library LibPublicInput { /// @notice Hashes the public input for the proof verification. /// @param _tran The transition to verify. /// @param _verifierContract The contract address which as current verifier. diff --git a/packages/protocol/test/L1/TaikoL1TestBase.sol b/packages/protocol/test/L1/TaikoL1TestBase.sol index 75fb4395f3e..114480b7003 100644 --- a/packages/protocol/test/L1/TaikoL1TestBase.sol +++ b/packages/protocol/test/L1/TaikoL1TestBase.sol @@ -332,7 +332,7 @@ abstract contract TaikoL1TestBase is TaikoTest { returns (bytes memory signature) { uint64 chainId = L1.getConfig().chainId; - bytes32 digest = LibPublicInputHash.hashPublicInputs( + bytes32 digest = LibPublicInput.hashPublicInputs( tran, address(sv), newInstance, prover, metaHash, chainId ); diff --git a/packages/protocol/test/TaikoTest.sol b/packages/protocol/test/TaikoTest.sol index e9cafd4ab0d..972db50860e 100644 --- a/packages/protocol/test/TaikoTest.sol +++ b/packages/protocol/test/TaikoTest.sol @@ -20,7 +20,7 @@ import "../contracts/tokenvault/ERC1155Vault.sol"; import "../contracts/L1/TaikoToken.sol"; import "../contracts/L1/TaikoL1.sol"; -import "../contracts/verifiers/libs/LibPublicInputHash.sol"; +import "../contracts/verifiers/libs/LibPublicInput.sol"; import "../contracts/verifiers/SgxVerifier.sol"; import "../contracts/verifiers/RiscZeroVerifier.sol"; import "../contracts/verifiers/GuardianVerifier.sol"; diff --git a/packages/protocol/test/verifiers/SgxVerifier.t.sol b/packages/protocol/test/verifiers/SgxVerifier.t.sol index 02c82e72532..84fad1104fe 100644 --- a/packages/protocol/test/verifiers/SgxVerifier.t.sol +++ b/packages/protocol/test/verifiers/SgxVerifier.t.sol @@ -203,7 +203,7 @@ contract TestSgxVerifier is TaikoL1TestBase, AttestationBase { address newInstance = address(0x33); uint64 chainId = L1.getConfig().chainId; - bytes32 signedHash = LibPublicInputHash.hashPublicInputs( + bytes32 signedHash = LibPublicInput.hashPublicInputs( transition, address(sv), newInstance, ctx.prover, ctx.metaHash, chainId ); @@ -363,7 +363,7 @@ contract TestSgxVerifier is TaikoL1TestBase, AttestationBase { address newInstance = address(0x33); uint64 chainId = L1.getConfig().chainId; - bytes32 signedHash = LibPublicInputHash.hashPublicInputs( + bytes32 signedHash = LibPublicInput.hashPublicInputs( transition, address(sv), newInstance, ctx.prover, ctx.metaHash, chainId ); @@ -408,7 +408,7 @@ contract TestSgxVerifier is TaikoL1TestBase, AttestationBase { address newInstance = address(0x33); uint64 chainId = L1.getConfig().chainId; - bytes32 signedHash = LibPublicInputHash.hashPublicInputs( + bytes32 signedHash = LibPublicInput.hashPublicInputs( transition, address(sv), newInstance, ctx.prover, ctx.metaHash, chainId ); From d6d7cd50b2e7251052e6f8dd0fabd8e48e93a62f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Keszey=20D=C3=A1niel?= Date: Fri, 8 Mar 2024 10:16:01 +0100 Subject: [PATCH 6/9] pr comments --- .../contracts/verifiers/RiscZeroVerifier.sol | 3 +- .../test/verifiers/RiscZeroVerifier.t.sol | 89 +++++++------------ 2 files changed, 35 insertions(+), 57 deletions(-) diff --git a/packages/protocol/contracts/verifiers/RiscZeroVerifier.sol b/packages/protocol/contracts/verifiers/RiscZeroVerifier.sol index 76615b04583..e9deb4dd396 100644 --- a/packages/protocol/contracts/verifiers/RiscZeroVerifier.sol +++ b/packages/protocol/contracts/verifiers/RiscZeroVerifier.sol @@ -11,7 +11,8 @@ import "../thirdparty/risczero/IRiscZeroReceiptVerifier.sol"; /// @title RiscZeroVerifier /// @custom:security-contact security@taiko.xyz contract RiscZeroVerifier is EssentialContract, IVerifier { - /// @notice RISC Zero remote verifier contract address. + /// @notice RISC Zero remote verifier contract address, e.g.: + /// https://sepolia.etherscan.io/address/0x83c2e9cd64b2a16d3908e94c7654f3864212e2f8 IRiscZeroReceiptVerifier public receiptVerifier; /// @notice Trusted imageId mapping mapping(bytes32 imageId => bool trusted) public isImageTrusted; diff --git a/packages/protocol/test/verifiers/RiscZeroVerifier.t.sol b/packages/protocol/test/verifiers/RiscZeroVerifier.t.sol index 053f3233188..77c719d8a2e 100644 --- a/packages/protocol/test/verifiers/RiscZeroVerifier.t.sol +++ b/packages/protocol/test/verifiers/RiscZeroVerifier.t.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.24; import "../L1/TaikoL1TestBase.sol"; -contract MockRiscZeroRemoteVerifier { +contract MockRiscZeroRemoteVerifier is IRiscZeroReceiptVerifier { // To simulate failing and succeeding bool public verifying; @@ -65,25 +65,6 @@ contract TestRiscZeroVerifier is TaikoL1TestBase { // to be front run. vm.startPrank(Alice); - // Context - IVerifier.Context memory ctx = IVerifier.Context({ - metaHash: bytes32("ab"), - blobHash: bytes32("cd"), - prover: address(0), - msgSender: address(0), - blockId: 10, - isContesting: false, - blobUsed: false - }); - - // Transition - TaikoData.Transition memory transition = TaikoData.Transition({ - parentHash: bytes32("12"), - blockHash: bytes32("34"), - stateRoot: bytes32("56"), - graffiti: bytes32("78") - }); - bytes memory seal = hex"00"; bytes32 imageId = bytes32("11"); bytes32 postStateDigest = bytes32("22"); @@ -94,6 +75,9 @@ contract TestRiscZeroVerifier is TaikoL1TestBase { vm.warp(block.timestamp + 5); + (IVerifier.Context memory ctx, TaikoData.Transition memory transition) = + _getDummyContextAndTransition(); + // `verifyProof()` rv.verifyProof(ctx, transition, proof); @@ -107,25 +91,6 @@ contract TestRiscZeroVerifier is TaikoL1TestBase { // to be front run. vm.startPrank(Alice); - // Context - IVerifier.Context memory ctx = IVerifier.Context({ - metaHash: bytes32("ab"), - blobHash: bytes32("cd"), - prover: address(0), - msgSender: address(0), - blockId: 10, - isContesting: false, - blobUsed: false - }); - - // Transition - TaikoData.Transition memory transition = TaikoData.Transition({ - parentHash: bytes32("12"), - blockHash: bytes32("34"), - stateRoot: bytes32("56"), - graffiti: bytes32("78") - }); - bytes memory seal = hex"00"; bytes32 imageId = bytes32("121"); bytes32 postStateDigest = bytes32("22"); @@ -136,6 +101,9 @@ contract TestRiscZeroVerifier is TaikoL1TestBase { vm.warp(block.timestamp + 5); + (IVerifier.Context memory ctx, TaikoData.Transition memory transition) = + _getDummyContextAndTransition(); + vm.expectRevert(RiscZeroVerifier.RISC_ZERO_INVALID_IMAGE_ID.selector); rv.verifyProof(ctx, transition, proof); @@ -150,8 +118,32 @@ contract TestRiscZeroVerifier is TaikoL1TestBase { // to be front run. vm.startPrank(Alice); + bytes memory seal = hex"00"; + bytes32 imageId = bytes32("11"); + bytes32 postStateDigest = bytes32("22"); + + // TierProof + TaikoData.TierProof memory proof = + TaikoData.TierProof({ tier: 100, data: abi.encode(seal, imageId, postStateDigest) }); + + vm.warp(block.timestamp + 5); + + (IVerifier.Context memory ctx, TaikoData.Transition memory transition) = + _getDummyContextAndTransition(); + + vm.expectRevert(RiscZeroVerifier.RISC_ZERO_INVALID_PROOF.selector); + rv.verifyProof(ctx, transition, proof); + + vm.stopPrank(); + } + + function _getDummyContextAndTransition() + internal + pure + returns (IVerifier.Context memory ctx, TaikoData.Transition memory transition) + { // Context - IVerifier.Context memory ctx = IVerifier.Context({ + ctx = IVerifier.Context({ metaHash: bytes32("ab"), blobHash: bytes32("cd"), prover: address(0), @@ -162,26 +154,11 @@ contract TestRiscZeroVerifier is TaikoL1TestBase { }); // Transition - TaikoData.Transition memory transition = TaikoData.Transition({ + transition = TaikoData.Transition({ parentHash: bytes32("12"), blockHash: bytes32("34"), stateRoot: bytes32("56"), graffiti: bytes32("78") }); - - bytes memory seal = hex"00"; - bytes32 imageId = bytes32("11"); - bytes32 postStateDigest = bytes32("22"); - - // TierProof - TaikoData.TierProof memory proof = - TaikoData.TierProof({ tier: 100, data: abi.encode(seal, imageId, postStateDigest) }); - - vm.warp(block.timestamp + 5); - - vm.expectRevert(RiscZeroVerifier.RISC_ZERO_INVALID_PROOF.selector); - rv.verifyProof(ctx, transition, proof); - - vm.stopPrank(); } } From 4ce83c1ff36d95596b2f7a39f549b446034c2412 Mon Sep 17 00:00:00 2001 From: Daniel Wang <99078276+dantaik@users.noreply.github.com> Date: Mon, 11 Mar 2024 11:26:07 +0800 Subject: [PATCH 7/9] Update RiscZeroVerifier.sol --- packages/protocol/contracts/verifiers/RiscZeroVerifier.sol | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/protocol/contracts/verifiers/RiscZeroVerifier.sol b/packages/protocol/contracts/verifiers/RiscZeroVerifier.sol index e9deb4dd396..1876120813f 100644 --- a/packages/protocol/contracts/verifiers/RiscZeroVerifier.sol +++ b/packages/protocol/contracts/verifiers/RiscZeroVerifier.sol @@ -2,12 +2,11 @@ pragma solidity 0.8.24; import "../common/EssentialContract.sol"; +import "../thirdparty/risczero/IRiscZeroReceiptVerifier.sol"; import "../L1/ITaikoL1.sol"; import "./IVerifier.sol"; import "./libs/LibPublicInput.sol"; -import "../thirdparty/risczero/IRiscZeroReceiptVerifier.sol"; - /// @title RiscZeroVerifier /// @custom:security-contact security@taiko.xyz contract RiscZeroVerifier is EssentialContract, IVerifier { From 5700886c80a50c487cf422419fd4df05ba9e0639 Mon Sep 17 00:00:00 2001 From: Daniel Wang <99078276+dantaik@users.noreply.github.com> Date: Mon, 11 Mar 2024 11:26:32 +0800 Subject: [PATCH 8/9] Update SgxVerifier.sol --- packages/protocol/contracts/verifiers/SgxVerifier.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/protocol/contracts/verifiers/SgxVerifier.sol b/packages/protocol/contracts/verifiers/SgxVerifier.sol index d970ede0e8e..e28b1fd4199 100644 --- a/packages/protocol/contracts/verifiers/SgxVerifier.sol +++ b/packages/protocol/contracts/verifiers/SgxVerifier.sol @@ -6,8 +6,8 @@ import "../L1/ITaikoL1.sol"; import "../common/EssentialContract.sol"; import "../automata-attestation/interfaces/IAttestation.sol"; import "../automata-attestation/lib/QuoteV3Auth/V3Struct.sol"; -import "./IVerifier.sol"; import "./libs/LibPublicInput.sol"; +import "./IVerifier.sol"; /// @title SgxVerifier /// @notice This contract is the implementation of verifying SGX signature proofs From 99650421964c28f815c8525095d88b69f83c40d5 Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Tue, 12 Mar 2024 19:24:21 +0800 Subject: [PATCH 9/9] Update getAddress.test.ts --- packages/bridge-ui/src/libs/token/getAddress.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/bridge-ui/src/libs/token/getAddress.test.ts b/packages/bridge-ui/src/libs/token/getAddress.test.ts index 3622f6cb9eb..1977209a729 100644 --- a/packages/bridge-ui/src/libs/token/getAddress.test.ts +++ b/packages/bridge-ui/src/libs/token/getAddress.test.ts @@ -70,7 +70,7 @@ describe('getAddress', () => { ).toEqual(BridgedHORSEToken.addresses[PUBLIC_L2_CHAIN_ID]); }); - it('should return undefined if ERC20 and has no address on the source chain and no destination chain is is passed in', async () => { + it('should return undefined if ERC20 and has no address on the source chain and no destination chain is passed in', async () => { expect(await getAddress({ token: HORSEToken, srcChainId: Number(PUBLIC_L2_CHAIN_ID) })).toBeUndefined(); }); });