Skip to content

Commit

Permalink
feat(protocol): add ComposeVerifier (#17961)
Browse files Browse the repository at this point in the history
  • Loading branch information
dantaik committed Aug 22, 2024
1 parent 4225407 commit e5dd9a5
Show file tree
Hide file tree
Showing 7 changed files with 290 additions and 0 deletions.
22 changes: 22 additions & 0 deletions packages/protocol/contracts/L1/tiers/TierProviderBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,17 @@ abstract contract TierProviderBase is ITierProvider {
});
}

if (_tierId == LibTiers.TIER_TEE_ANY) {
return ITierProvider.Tier({
verifierName: LibStrings.B_TIER_TEE_ANY,
validityBond: 150 ether, // TAIKO
contestBond: 984.375 ether, // = 150 TAIKO * 6.5625
cooldownWindow: 1440, // 24 hours
provingWindow: GRACE_PERIOD + 60, // 1 hour
maxBlocksToVerifyPerProof: 0
});
}

if (_tierId == LibTiers.TIER_ZKVM_RISC0) {
return ITierProvider.Tier({
verifierName: LibStrings.B_TIER_ZKVM_RISC0,
Expand All @@ -81,6 +92,17 @@ abstract contract TierProviderBase is ITierProvider {
});
}

if (_tierId == LibTiers.TIER_ZKVM_ANY) {
return ITierProvider.Tier({
verifierName: LibStrings.B_TIER_ZKVM_ANY,
validityBond: 250 ether, // TAIKO
contestBond: 1640.625 ether, // = 250 TAIKO * 6.5625
cooldownWindow: 1440, // 24 hours
provingWindow: GRACE_PERIOD + 180, // 3 hours
maxBlocksToVerifyPerProof: 0
});
}

if (_tierId == LibTiers.TIER_GUARDIAN_MINORITY) {
return ITierProvider.Tier({
verifierName: LibStrings.B_TIER_GUARDIAN_MINORITY,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import "../../../verifiers/compose/TeeAnyVerifier.sol";
import "../../addrcache/RollupAddressCache.sol";

/// @title MainnetTeeAnyVerifier
/// @custom:security-contact security@taiko.xyz
contract MainnetTeeAnyVerifier is TeeAnyVerifier, RollupAddressCache {
function _getAddress(uint64 _chainId, bytes32 _name) internal view override returns (address) {
return getAddress(_chainId, _name, super._getAddress);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import "../../../verifiers/compose/ZkAnyVerifier.sol";
import "../../addrcache/RollupAddressCache.sol";

/// @title MainnetZkAnyVerifier
/// @custom:security-contact security@taiko.xyz
contract MainnetZkAnyVerifier is ZkAnyVerifier, RollupAddressCache {
function _getAddress(uint64 _chainId, bytes32 _name) internal view override returns (address) {
return getAddress(_chainId, _name, super._getAddress);
}
}
97 changes: 97 additions & 0 deletions packages/protocol/contracts/verifiers/compose/ComposeVerifier.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import "../../common/EssentialContract.sol";
import "../IVerifier.sol";

/// @title ComposeVerifier
/// @notice This contract is an abstract verifier that composes multiple sub-verifiers to validate
/// proofs.
/// It ensures that a set of sub-proofs are verified by their respective verifiers before
/// considering the overall proof as valid.
/// @custom:security-contact security@taiko.xyz
abstract contract ComposeVerifier is EssentialContract, IVerifier {
struct SubProof {
address verifier;
bytes proof;
}

event InvalidSubProof(address indexed verifier, bytes returnData);

error INSUFFICIENT_PROOF();

/// @notice Initializes the contract.
/// @param _owner The owner of this contract. msg.sender will be used if this value is zero.
/// @param _rollupAddressManager The address of the {AddressManager} contract.
function init(address _owner, address _rollupAddressManager) external initializer {
__Essential_init(_owner, _rollupAddressManager);
}

/// @notice Verifies one or more sub-proofs.
/// @param _ctx The context of the proof verification.
/// @param _tran The transition to verify.
/// @param _proof The proof to verify.
function verifyProof(
Context calldata _ctx,
TaikoData.Transition calldata _tran,
TaikoData.TierProof calldata _proof
)
external
{
(address[] memory verifiers, uint256 threshold) = getSubVerifiersAndThreshold();

for (uint256 i; i < verifiers.length; ++i) {
// Store the value 1 in the temporary storage slot using inline assembly
uint256 slot = uint256(uint160(verifiers[i]));
if (slot != 0) {
assembly {
tstore(slot, 1)
}
}
}

SubProof[] memory subproofs = abi.decode(_proof.data, (SubProof[]));
uint256 numSuccesses;

for (uint256 i; i < subproofs.length; ++i) {
uint256 slot = uint256(uint160(subproofs[i].verifier));

assembly {
switch tload(slot)
case 1 { tstore(slot, 0) }
default {
let message := "INVALID_VERIFIER"
mstore(0x0, message)
revert(0x0, 0x20)
}
}

(bool success, bytes memory returnData) = subproofs[i].verifier.call(
abi.encodeCall(
IVerifier.verifyProof,
(_ctx, _tran, TaikoData.TierProof(_proof.tier, subproofs[i].proof))
)
);
if (success) {
unchecked {
numSuccesses += 1;
}
} else {
emit InvalidSubProof(subproofs[i].verifier, returnData);
}
}

if (numSuccesses < threshold) {
revert INSUFFICIENT_PROOF();
}
}

/// @notice Returns the list of sub-verifiers and calculates the threshold.
/// @return verifiers_ An array of addresses of sub-verifiers.
/// @return threshold_ The threshold number of successful verifications required.
function getSubVerifiersAndThreshold()
public
view
virtual
returns (address[] memory verifiers_, uint256 threshold_);
}
24 changes: 24 additions & 0 deletions packages/protocol/contracts/verifiers/compose/TeeAnyVerifier.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import "../../common/LibStrings.sol";
import "./ComposeVerifier.sol";

/// @title TeeAnyVerifier
/// @notice This contract is a verifier for the Mainnet ZkVM that composes RiscZero and SP1
/// Verifiers.
/// @custom:security-contact security@taiko.xyz
contract TeeAnyVerifier is EssentialContract, ComposeVerifier {
/// @inheritdoc ComposeVerifier
function getSubVerifiersAndThreshold()
public
view
override
returns (address[] memory verifiers_, uint256 threshold_)
{
verifiers_ = new address[](2);
verifiers_[0] = resolve(LibStrings.B_TIER_SGX, false);
verifiers_[1] = resolve(LibStrings.B_TIER_TDX, false);
threshold_ = 1;
}
}
25 changes: 25 additions & 0 deletions packages/protocol/contracts/verifiers/compose/ZKAnyVerifier.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import "../../common/EssentialContract.sol";
import "../../common/LibStrings.sol";
import "./ComposeVerifier.sol";

/// @title ZkAnyVerifier
/// @notice This contract is a verifier for the Mainnet ZkVM that composes RiscZero and SP1
/// Verifiers.
/// @custom:security-contact security@taiko.xyz
contract ZkAnyVerifier is EssentialContract, ComposeVerifier {
/// @inheritdoc ComposeVerifier
function getSubVerifiersAndThreshold()
public
view
override
returns (address[] memory verifiers_, uint256 threshold_)
{
verifiers_ = new address[](2);
verifiers_[0] = resolve(LibStrings.B_TIER_ZKVM_RISC0, false);
verifiers_[1] = resolve(LibStrings.B_TIER_ZKVM_SP1, false);
threshold_ = 1;
}
}
96 changes: 96 additions & 0 deletions packages/protocol/test/verifiers/compose/ComposeVerifeir.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import "../../TaikoTest.sol";
import "../../../contracts/verifiers/compose/ComposeVerifier.sol";

contract ComposeVerifierForTest is ComposeVerifier {
uint256 private threshold;
address[] private verifiers;

function setThreshold(uint256 _threshold) external {
threshold = _threshold;
}

function getSubVerifiersAndThreshold()
public
view
override
returns (address[] memory, uint256)
{
return (verifiers, threshold);
}

function addSubVerifier(address _verifier) external {
verifiers.push(_verifier);
}
}

contract MockVerifier is IVerifier {
bool private shouldSucceed;

constructor(bool _shouldSucceed) {
shouldSucceed = _shouldSucceed;
}

function verifyProof(
Context calldata,
TaikoData.Transition calldata,
TaikoData.TierProof calldata
)
external
view
override
{
if (!shouldSucceed) {
revert("MockVerifier: Verification failed");
}
}
}

contract ComposeVerifierTest is TaikoTest {
ComposeVerifierForTest private composeVerifier;

IVerifier.Context private ctx;
TaikoData.Transition private tran;
TaikoData.TierProof proof;
address private verifier1;
address private verifier2;
address private verifier3;

function setUp() public {
verifier1 = address(new MockVerifier(true));
verifier2 = address(new MockVerifier(false));
verifier3 = address(new MockVerifier(true));

composeVerifier = new ComposeVerifierForTest();
composeVerifier.addSubVerifier(verifier1);
composeVerifier.addSubVerifier(verifier2);
composeVerifier.addSubVerifier(verifier3);

ComposeVerifier.SubProof[] memory subProofs = new ComposeVerifier.SubProof[](3);
subProofs[0] = ComposeVerifier.SubProof(verifier1, "");
subProofs[1] = ComposeVerifier.SubProof(verifier2, "");
subProofs[2] = ComposeVerifier.SubProof(verifier3, "");

proof = TaikoData.TierProof({ tier: 1, data: abi.encode(subProofs) });
}

function test_composeVerifeir_All() public {
composeVerifier.setThreshold(3);

// Expect the verification to fail because not all verifiers succeed
vm.expectRevert(ComposeVerifier.INSUFFICIENT_PROOF.selector);
composeVerifier.verifyProof(ctx, tran, proof);
}

function test_composeVerifeir_Majority() public {
composeVerifier.setThreshold(2);
composeVerifier.verifyProof(ctx, tran, proof);
}

function test_composeVerifeir_One() public {
composeVerifier.setThreshold(1);
composeVerifier.verifyProof(ctx, tran, proof);
}
}

0 comments on commit e5dd9a5

Please sign in to comment.