Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(protocol): add SP1 verification support #17861

Merged
merged 8 commits into from
Aug 1, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions packages/protocol/contracts/verifiers/IVerifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,28 @@ interface IVerifier {
)
external;
}

/// @title SP1 Verifier Interface
/// @author Succinct Labs
/// @notice This interface is for the deployed SP1 Verifier and 100% brought over from :
/// https://github.com/succinctlabs/sp1-contracts/blob/main/contracts/src/ISP1Verifier.sol
interface ISP1Verifier {
adaki2004 marked this conversation as resolved.
Show resolved Hide resolved
/// @notice Verifies a proof with given public values and vkey.
/// @dev It is expected that the first 4 bytes of proofBytes must match the first 4 bytes of
/// target verifier's VERIFIER_HASH.
/// @param programVKey The verification key for the RISC-V program.
/// @param publicValues The public values encoded as bytes.
/// @param proofBytes The proof of the program execution the SP1 zkVM encoded as bytes.
function verifyProof(
bytes32 programVKey,
bytes calldata publicValues,
bytes calldata proofBytes
)
external
view;
}

interface ISP1VerifierWithHash is ISP1Verifier {
/// @notice Returns the hash of the verifier.
function VERIFIER_HASH() external pure returns (bytes32);
}
98 changes: 98 additions & 0 deletions packages/protocol/contracts/verifiers/SP1Verifier.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import "../common/EssentialContract.sol";
import "../common/LibStrings.sol";
import "../L1/ITaikoL1.sol";
import "./IVerifier.sol";
import "./libs/LibPublicInput.sol";

/// @title SuccinctVerifier
/// @custom:security-contact [email protected]
contract SP1Verifier is EssentialContract, IVerifier {
/// @notice The address of the SP1 verifier contract.
/// @dev This can either be a specific SP1Verifier for a specific version, or the
/// SP1VerifierGateway which can be used to verify proofs for any version of SP1.
/// For the list of supported verifiers on each chain, see:
/// https://github.com/succinctlabs/sp1-contracts/tree/main/contracts/deployments
address public verifier;
adaki2004 marked this conversation as resolved.
Show resolved Hide resolved

/// @notice The verification keys mappings for the proving programs.
mapping(bytes32 provingProgramVKey => bool trusted) public isProgramTrusted;

uint256[48] private __gap;

/// @dev Emitted when a trusted image is set / unset.
/// @param programVKey The id of the image
/// @param trusted The block's assigned prover.
event ProgramTrusted(bytes32 programVKey, bool trusted);

/// @dev Emitted when a new verifier address is set.
/// @param verifier The address of the verifier.
event NewVerifierAddress(address verifier);

error SP1_INVALID_PROGRAM_VKEY();

/// @notice Initializes the contract with the provided address manager.
/// @param _owner The address of the owner.
/// @param _addressManager The address of the AddressManager.
/// @param _verifier The address of the SP1Verifiers.
function init(
address _owner,
address _addressManager,
address _verifier
)
external
initializer
{
__Essential_init(_owner, _addressManager);

verifier = _verifier;
}

/// @notice Sets/unsets an the program's verification key as trusted entity
/// @param _programVKey The verification key of the program.
/// @param _trusted True if trusted, false otherwise.
function setProgramTrusted(bytes32 _programVKey, bool _trusted) external onlyOwner {
isProgramTrusted[_programVKey] = _trusted;

emit ProgramTrusted(_programVKey, _trusted);
}

/// @notice Sets the verifier contract.
/// @param _verifier The address of the verifier contract.
function setVerifierContract(address _verifier) external onlyOwner {
verifier = _verifier;

emit NewVerifierAddress(_verifier);
}

/// @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
(bytes32 programVKey, bytes memory proof) = abi.decode(_proof.data, (bytes32, bytes));
adaki2004 marked this conversation as resolved.
Show resolved Hide resolved

if (!isProgramTrusted[programVKey]) {
revert SP1_INVALID_PROGRAM_VKEY();
}

uint64 chainId = ITaikoL1(resolve(LibStrings.B_TAIKO, false)).getConfig().chainId;
adaki2004 marked this conversation as resolved.
Show resolved Hide resolved

// Need to be converted from bytes32 to bytes
bytes32 hashedPublicInput = LibPublicInput.hashPublicInputs(
adaki2004 marked this conversation as resolved.
Show resolved Hide resolved
_tran, address(this), address(0), _ctx.prover, _ctx.metaHash, chainId
);

ISP1Verifier(verifier).verifyProof(programVKey, abi.encode(hashedPublicInput), proof);
}
}