Skip to content

Commit

Permalink
add ProverRegistryVerifier & AttestationVerifier testcase (#36)
Browse files Browse the repository at this point in the history
* add ProverRegistryVerifier & AttestationVerifier testcase

* add more test

* revert packages/protocol/contract_layout_layer1.md
  • Loading branch information
chzyer authored and vikinatora committed Jan 21, 2025
1 parent 59d5e0f commit c2f2787
Show file tree
Hide file tree
Showing 10 changed files with 376 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,30 +38,28 @@ contract AttestationVerifier is IAttestationVerifier, EssentialContract {
bytes calldata _report,
bytes32 _userData,
bytes calldata _ext
)
)
external
{
if (address(automataDcapAttestation) == address(0)) return;

(bool succ, bytes memory output) = automataDcapAttestation
.verifyAndAttestOnChain(_report);
(bool succ, bytes memory output) = automataDcapAttestation.verifyAndAttestOnChain(_report);
if (!succ) revert INVALID_REPORT();

if (output.length < 32) revert INVALID_REPORT_DATA();

bytes32 quoteBodyLast32;
assembly {
quoteBodyLast32 := mload(
add(add(output, 0x20), sub(mload(output), 32))
)
quoteBodyLast32 := mload(add(add(output, 0x20), sub(mload(output), 32)))
}

ExtTpmInfo memory info = abi.decode(_ext, (ExtTpmInfo));

bytes32 dataWithNonce = sha256(abi.encodePacked(info.akDer, _userData));
if (quoteBodyLast32 != dataWithNonce) revert REPORT_DATA_MISMATCH(quoteBodyLast32, dataWithNonce);
// TODO: verify tpm info
if (quoteBodyLast32 != dataWithNonce) {
revert REPORT_DATA_MISMATCH(quoteBodyLast32, dataWithNonce);
}

if (checkPcr10 && !trustedPcr10[info.pcr10]) revert INVALID_PRC10(info.pcr10);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,28 @@
pragma solidity ^0.8.24;

/**
* @title Interface standard that implement attestation contracts whose verification logic can be implemented
* @title Interface standard that implement attestation contracts whose verification logic can be
* implemented
* both on-chain and with Risc0 ZK proofs
* @notice The interface simply provides two verification methods for a given attestation input.
* The user can either pay a possibly hefty gas cost to fully verify an attestation fully on-chain
* OR
* Provides ZK proofs from executing an off-chain program where the verification of such attestation is conducted.
* Provides ZK proofs from executing an off-chain program where the verification of such attestation
* is conducted.
* @dev should also implement Risc0 Guest Program to use this interface.
* See https://dev.risczero.com/api/blockchain-integration/bonsai-on-eth to learn more
*/
interface IAttestationV2 {
/**
* @notice full on-chain verification for an attestation
* @dev must further specify the structure of inputs/outputs, to be serialized and passed to this method
* @dev must further specify the structure of inputs/outputs, to be serialized and passed to
* this method
* @param input - serialized raw input as defined by the project
* @return success - whether the quote has been successfully verified or not
* @return output - the output upon completion of verification. The output data may require
* @return output - the output upon completion of verification. The output data may require
* post-processing by the consumer.
* For verification failures, the output is simply a UTF-8 encoded string, describing the reason for failure.
* For verification failures, the output is simply a UTF-8 encoded string, describing the reason
* for failure.
* @dev can directly type cast the failed output as a string
*/
function verifyAndAttestOnChain(bytes calldata input)
Expand All @@ -44,4 +48,4 @@ interface IAttestationV2 {
)
external
returns (bool success, bytes memory output);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,10 @@ interface IAttestationVerifier {
error INVALID_PRC10(bytes32 pcr10);

function setImagePcr10(bytes32 _pcr10, bool _trusted) external;
function verifyAttestation(bytes calldata _report, bytes32 _userData, bytes calldata ext) external;
function verifyAttestation(
bytes calldata _report,
bytes32 _userData,
bytes calldata ext
)
external;
}
23 changes: 7 additions & 16 deletions packages/protocol/contracts/layer1/verifiers/IProverRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ interface IProverRegistry {
uint256 referenceBlockNumber;
bytes32 referenceBlockHash;
bytes32 binHash;

bytes ext;
}

Expand All @@ -52,27 +51,19 @@ interface IProverRegistry {
error INVALID_PRC10(bytes32 pcr10);

event InstanceAdded(
uint256 indexed id,
address indexed instance,
address replaced,
uint256 validUntil
uint256 indexed id, address indexed instance, address replaced, uint256 validUntil
);
event VerifyProof(uint256 proofs);

/// @notice register prover instance with quote
function register(
bytes calldata _report,
ReportData calldata _data
) external;
function register(bytes calldata _report, ReportData calldata _data) external;

/// TODO: should we need to add teeType?
/// @notice validate whether the prover with (instanceID, address)
function checkProver(
uint256 _instanceID,
address _proverAddr
) external view returns (ProverInstance memory);

/// TODO: each proof should coming from different teeType
/// @notice verify multiple proofs in one call
function verifyProofs(Proof[] calldata _proofs) external;
}
)
external
view
returns (ProverInstance memory);
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ contract ProverRegistryVerifier is IVerifier, IProverRegistry, EssentialContract
address _verifierAddr,
uint256 _attestValiditySeconds,
uint256 _maxBlockNumberDiff
)
)
external
initializer
{
Expand All @@ -55,12 +55,7 @@ contract ProverRegistryVerifier is IVerifier, IProverRegistry, EssentialContract
}

/// @notice register prover instance with quote
function register(
bytes calldata _report,
ReportData calldata _data
)
external
{
function register(bytes calldata _report, ReportData calldata _data) external {
_checkBlockNumber(_data.referenceBlockNumber, _data.referenceBlockHash);
bytes32 dataHash = keccak256(abi.encode(_data));

Expand All @@ -74,11 +69,7 @@ contract ProverRegistryVerifier is IVerifier, IProverRegistry, EssentialContract
nextInstanceId += 1;

uint256 validUnitl = block.timestamp + attestValiditySeconds;
attestedProvers[instanceID] = ProverInstance(
_data.addr,
validUnitl,
_data.teeType
);
attestedProvers[instanceID] = ProverInstance(_data.addr, validUnitl, _data.teeType);

emit InstanceAdded(instanceID, _data.addr, address(0), validUnitl);
}
Expand Down Expand Up @@ -125,37 +116,14 @@ contract ProverRegistryVerifier is IVerifier, IProverRegistry, EssentialContract
notImplemented
{ }

/// TODO: each proof should coming from different teeType
/// @notice verify multiple proofs in one call
function verifyProofs(Proof[] calldata _proofs)
external
onlyFromNamedEither(LibStrings.B_TAIKO, LibStrings.B_TIER_TDX)
{
require(_proofs.length >= 1, "missing proofs");
for (uint i = 0; i < _proofs.length; i++) {
IProverRegistry.SignedPoe calldata poe = _proofs[i].poe;
address oldInstance = ECDSA.recover(
LibPublicInput.hashPublicInputs(
poe.transition, address(this), poe.newInstance, _proofs[i].ctx.prover,_proofs[i].ctx.metaHash, uniFiChainId()
),
poe.signature
);

ProverInstance memory prover = checkProver(poe.id, oldInstance);
if (poe.teeType != prover.teeType) revert PROVER_TYPE_MISMATCH();
if (oldInstance != poe.newInstance) {
attestedProvers[poe.id].addr = poe.newInstance;
emit InstanceAdded(poe.id, oldInstance, poe.newInstance, prover.validUntil);
}
}

emit VerifyProof(_proofs.length);
}

function checkProver(
uint256 _instanceID,
address _proverAddr
) public view returns (ProverInstance memory) {
)
public
view
returns (ProverInstance memory)
{
ProverInstance memory prover;
if (_instanceID == 0) revert PROVER_INVALID_INSTANCE_ID(_instanceID);
if (_proverAddr == address(0)) revert PROVER_INVALID_ADDR(_proverAddr);
Expand All @@ -169,16 +137,16 @@ contract ProverRegistryVerifier is IVerifier, IProverRegistry, EssentialContract
return ITaikoL1(resolve(LibStrings.B_TAIKO, false)).getConfig().chainId;
}

// Due to the inherent unpredictability of blockHash, it mitigates the risk of mass-generation
// of attestation reports in a short time frame, preventing their delayed and gradual exploitation.
// This function will make sure the attestation report generated in recent ${maxBlockNumberDiff} blocks
function _checkBlockNumber(
uint256 blockNumber,
bytes32 blockHash
) private view {
// Due to the inherent unpredictability of blockHash, it mitigates the risk of mass-generation
// of attestation reports in a short time frame, preventing their delayed and gradual
// exploitation.
// This function will make sure the attestation report generated in recent ${maxBlockNumberDiff}
// blocks
function _checkBlockNumber(uint256 blockNumber, bytes32 blockHash) private view {
if (blockNumber >= block.number) revert INVALID_BLOCK_NUMBER();
if (block.number - blockNumber >= maxBlockNumberDiff)
if (block.number - blockNumber >= maxBlockNumberDiff) {
revert BLOCK_NUMBER_OUT_OF_DATE();
}
if (blockhash(blockNumber) != blockHash) revert BLOCK_NUMBER_MISMATCH();
}
}
}
13 changes: 10 additions & 3 deletions packages/protocol/script/layer1/DeployProtocolOnL1.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,9 @@ contract DeployProtocolOnL1 is DeployCapability {
TaikoL1 taikoL1;
if (keccak256(abi.encode(vm.envString("TIER_ROUTER"))) == keccak256(abi.encode("devnet"))) {
taikoL1 = TaikoL1(address(new DevnetTaikoL1()));
} else if (keccak256(abi.encode(vm.envString("TIER_PROVIDER"))) == keccak256(abi.encode("testnet"))) {
} else if (
keccak256(abi.encode(vm.envString("TIER_PROVIDER"))) == keccak256(abi.encode("testnet"))
) {
taikoL1 = TaikoL1(address(new TestnetUniFiL1()));
} else {
taikoL1 = TaikoL1(address(new TaikoL1()));
Expand Down Expand Up @@ -341,13 +343,18 @@ contract DeployProtocolOnL1 is DeployCapability {
address attestationVerifier = deployProxy({
name: "attestation_verifier",
impl: address(new AttestationVerifier()),
data: abi.encodeCall(AttestationVerifier.init, (owner, vm.envAddress("AUTOMATA_DCAP_ATTESTATION"), true))
data: abi.encodeCall(
AttestationVerifier.init, (owner, vm.envAddress("AUTOMATA_DCAP_ATTESTATION"), true)
)
});

deployProxy({
name: "tier_tdx",
impl: address(new ProverRegistryVerifier()),
data: abi.encodeCall(ProverRegistryVerifier.init, (owner, rollupAddressManager, attestationVerifier, 3600, 25)),
data: abi.encodeCall(
ProverRegistryVerifier.init,
(owner, rollupAddressManager, attestationVerifier, 3600, 25)
),
registerTo: rollupAddressManager
});
}
Expand Down
14 changes: 11 additions & 3 deletions packages/protocol/script/layer1/DeployProverRegistryVerifier.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,18 @@ contract DeployProverRegistryVerifier is DeployCapability {
deployProxy({
name: "tier_tdx",
impl: address(proverRegistryVerifier),
data: abi.encodeCall(ProverRegistryVerifier.init, (msg.sender, rollupAddressManager, attestationVerifier, attestationValiditySeconds, maxBlockNumberDiff)),
registerTo: rollupAddressManager
data: abi.encodeCall(
ProverRegistryVerifier.init,
(
msg.sender,
rollupAddressManager,
attestationVerifier,
attestationValiditySeconds,
maxBlockNumberDiff
)
)
});

vm.stopBroadcast();
}
}
}
2 changes: 2 additions & 0 deletions packages/protocol/test/layer1/TaikoL1Test.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "src/layer1/automata-attestation/AttestationVerifier.sol";
import "src/layer1/verifiers/ProverRegistryVerifier.sol";
import "src/layer1/based/TaikoL1.sol";
import "src/layer1/token/TaikoToken.sol";
import "src/layer1/verifiers/SgxVerifier.sol";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import { IAttestationV2 } from
"../../../contracts/layer1/automata-attestation/interfaces/IAttestationV2.sol";

/// @title MockAutomataDcapAttestation
contract MockAutomataDcapAttestation is IAttestationV2 {
error FUNC_NOT_IMPLEMENTED();

function verifyAndAttestOnChain(bytes calldata input)
external
returns (bool success, bytes memory output)
{
return (true, input);
}

function verifyAndAttestWithZKProof(
bytes calldata journal,
bytes calldata seal
)
external
returns (bool success, bytes memory output)
{
revert FUNC_NOT_IMPLEMENTED();
}
}
Loading

0 comments on commit c2f2787

Please sign in to comment.