Skip to content

Commit

Permalink
Merge branch 'zkvm_verifier' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
dantaik committed Mar 12, 2024
2 parents b170a39 + 5700886 commit e1a2814
Show file tree
Hide file tree
Showing 9 changed files with 352 additions and 38 deletions.
4 changes: 3 additions & 1 deletion packages/protocol/contracts/thirdparty/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
- /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
Original file line number Diff line number Diff line change
@@ -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 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
/// 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);
}
86 changes: 86 additions & 0 deletions packages/protocol/contracts/verifiers/RiscZeroVerifier.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// SPDX-License-Identifier: MIT
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";

/// @title RiscZeroVerifier
/// @custom:security-contact [email protected]
contract RiscZeroVerifier is EssentialContract, IVerifier {
/// @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;

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 ImageTrusted(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 _receiptVerifier The address of the risc zero receipt verifier contract.
function init(
address _owner,
address _addressManager,
address _receiptVerifier
)
external
initializer
{
__Essential_init(_owner, _addressManager);
receiptVerifier = IRiscZeroReceiptVerifier(_receiptVerifier);
}

/// @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 {
isImageTrusted[_imageId] = _trusted;

emit ImageTrusted(_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
(bytes memory seal, bytes32 imageId, bytes32 postStateDigest) =
abi.decode(_proof.data, (bytes, bytes32, bytes32));

if (!isImageTrusted[imageId]) {
revert RISC_ZERO_INVALID_IMAGE_ID();
}

uint64 chainId = ITaikoL1(resolve("taiko", false)).getConfig().chainId;
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 (!receiptVerifier.verify(seal, imageId, postStateDigest, journalDigest)) {
revert RISC_ZERO_INVALID_PROOF();
}
}
}
39 changes: 8 additions & 31 deletions packages/protocol/contracts/verifiers/SgxVerifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import "../L1/ITaikoL1.sol";
import "../common/EssentialContract.sol";
import "../automata-attestation/interfaces/IAttestation.sol";
import "../automata-attestation/lib/QuoteV3Auth/V3Struct.sol";
import "./libs/LibPublicInput.sol";
import "./IVerifier.sol";

/// @title SgxVerifier
Expand Down Expand Up @@ -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:]
LibPublicInput.hashPublicInputs(
_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
Expand Down
38 changes: 38 additions & 0 deletions packages/protocol/contracts/verifiers/libs/LibPublicInput.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import "../../L1/TaikoData.sol";

/// @title LibPublicInput
/// @notice A library for handling hashing the so-called public input hash, used by sgx and zk
/// proofs.
/// @custom:security-contact [email protected]
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.
/// @param _newInstance The new instance address. For SGX it is the new signer address, for ZK
/// 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 hashPublicInputs(
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
)
);
}
}
6 changes: 5 additions & 1 deletion packages/protocol/test/L1/TaikoL1TestBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -331,7 +332,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 = LibPublicInput.hashPublicInputs(
tran, address(sv), newInstance, prover, metaHash, chainId
);

uint256 signerPrivateKey;

Expand Down
2 changes: 2 additions & 0 deletions packages/protocol/test/TaikoTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ import "../contracts/tokenvault/ERC1155Vault.sol";

import "../contracts/L1/TaikoToken.sol";
import "../contracts/L1/TaikoL1.sol";
import "../contracts/verifiers/libs/LibPublicInput.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";
Expand Down
Loading

0 comments on commit e1a2814

Please sign in to comment.