forked from OffchainLabs/nitro-contracts
-
Notifications
You must be signed in to change notification settings - Fork 7
Contract changes for Stateless Batch Poster design #46
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
Draft
Sneh1999
wants to merge
4
commits into
celestia-feat-stateless-batcher
Choose a base branch
from
stateless-batcher-contract-changes
base: celestia-feat-stateless-batcher
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from 1 commit
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
import { | ||
V3QuoteVerifier | ||
} from "@automata-network/dcap-attestation/contracts/verifiers/V3QuoteVerifier.sol"; | ||
import {BELE} from "@automata-network/dcap-attestation/contracts/utils/BELE.sol"; | ||
import {Header} from "@automata-network/dcap-attestation/contracts/types/CommonStruct.sol"; | ||
import { | ||
HEADER_LENGTH, | ||
ENCLAVE_REPORT_LENGTH | ||
} from "@automata-network/dcap-attestation/contracts/types/Constants.sol"; | ||
import {EnclaveReport} from "@automata-network/dcap-attestation/contracts/types/V3Structs.sol"; | ||
import {BytesUtils} from "@automata-network/dcap-attestation/contracts/utils/BytesUtils.sol"; | ||
import "@openzeppelin/contracts/access/Ownable2Step.sol"; | ||
import {IEspressoSGXTEEVerifier} from "./IEspressoSGXTEEVerifier.sol"; | ||
|
||
/** | ||
* | ||
* @title Verifies quotes from the TEE and attests on-chain | ||
* @notice Contains the logic to verify a quote from the TEE and attest on-chain. It uses the V3QuoteVerifier contract | ||
* from automata to verify the quote. Along with some additional verification logic. | ||
*/ | ||
contract EspressoSGXTEEVerifier is IEspressoSGXTEEVerifier, Ownable2Step { | ||
using BytesUtils for bytes; | ||
|
||
// V3QuoteVerififer contract from automata to verify the quote | ||
V3QuoteVerifier public quoteVerifier; | ||
|
||
mapping(bytes32 => bool) public registeredEnclaveHash; | ||
mapping(address => bool) public registeredSigners; | ||
|
||
constructor(bytes32 enclaveHash, address _quoteVerifier) { | ||
quoteVerifier = V3QuoteVerifier(_quoteVerifier); | ||
registeredEnclaveHash[enclaveHash] = true; | ||
} | ||
|
||
/* | ||
@notice Verify a quote from the TEE and attest on-chain | ||
The verification is considered successful if the function does not revert. | ||
@param rawQuote The quote from the TEE | ||
@param reportDataHash The hash of the report data | ||
*/ | ||
function verify( | ||
bytes calldata rawQuote, | ||
bytes32 reportDataHash | ||
) public view returns (EnclaveReport memory) { | ||
// Parse the header | ||
Header memory header = parseQuoteHeader(rawQuote); | ||
|
||
// Currently only version 3 is supported | ||
if (header.version != 3) { | ||
revert InvalidHeaderVersion(); | ||
} | ||
|
||
// Verify the quote | ||
(bool success, ) = quoteVerifier.verifyQuote(header, rawQuote); | ||
if (!success) { | ||
revert InvalidQuote(); | ||
} | ||
|
||
// Parse enclave quote | ||
uint256 lastIndex = HEADER_LENGTH + ENCLAVE_REPORT_LENGTH; | ||
EnclaveReport memory localReport; | ||
(success, localReport) = parseEnclaveReport(rawQuote[HEADER_LENGTH:lastIndex]); | ||
if (!success) { | ||
revert FailedToParseEnclaveReport(); | ||
} | ||
|
||
// Check that mrEnclave match | ||
if (!registeredEnclaveHash[localReport.mrEnclave]) { | ||
revert InvalidEnclaveHash(); | ||
} | ||
|
||
// Verify that the reportDataHash if the hash signed by the TEE | ||
// We do not check the signature because `quoteVerifier.verifyQuote` already does that | ||
if (reportDataHash != bytes32(localReport.reportData.substring(0, 32))) { | ||
revert InvalidReportDataHash(); | ||
} | ||
|
||
return localReport; | ||
} | ||
|
||
/* | ||
@notice Register a new signer by verifying a quote from the TEE | ||
@param attestation The attestation from the TEE | ||
@param data when registering a signer, data can be passed for each TEE type | ||
rest are the address | ||
*/ | ||
function registerSigner(bytes calldata attestation, bytes calldata data) external { | ||
// Check that the data length is 32 bytes because verify function expects bytes32 | ||
if (data.length != 32) { | ||
revert InvalidDataLength(); | ||
} | ||
|
||
// Convert the data to bytes32 and pass it to the verify function | ||
bytes32 paddedSignerAddress = bytes32(data); | ||
EnclaveReport memory localReport = verify(attestation, paddedSignerAddress); | ||
|
||
if (localReport.reportData.length < 20) { | ||
revert ReportDataTooShort(); | ||
} | ||
|
||
// Extract the first 20 bytes of the reportData as the address | ||
address signerFromReport = address(uint160(uint256(keccak256(data[:20])))); | ||
|
||
// Check if the extracted address is valid | ||
if (signerFromReport == address(0)) { | ||
revert InvalidSignerAddress(); // Custom revert if the address is invalid | ||
} | ||
// Mark the signer as registered | ||
registeredSigners[signerFromReport] = true; | ||
} | ||
|
||
/* | ||
@notice Parses the header from the quote | ||
@param rawQuote The raw quote in bytes | ||
@return header The parsed header | ||
*/ | ||
function parseQuoteHeader(bytes calldata rawQuote) public pure returns (Header memory header) { | ||
header = Header({ | ||
version: uint16(BELE.leBytesToBeUint(rawQuote[0:2])), | ||
attestationKeyType: bytes2(rawQuote[2:4]), | ||
teeType: bytes4(uint32(BELE.leBytesToBeUint(rawQuote[4:8]))), | ||
qeSvn: bytes2(rawQuote[8:10]), | ||
pceSvn: bytes2(rawQuote[10:12]), | ||
qeVendorId: bytes16(rawQuote[12:28]), | ||
userData: bytes20(rawQuote[28:48]) | ||
}); | ||
} | ||
|
||
/* | ||
@notice Parses the enclave report from the quote | ||
@param rawEnclaveReport The raw enclave report from the quote in bytes | ||
@return success True if the enclave report was parsed successfully | ||
@return enclaveReport The parsed enclave report | ||
*/ | ||
function parseEnclaveReport( | ||
bytes memory rawEnclaveReport | ||
) public pure returns (bool success, EnclaveReport memory enclaveReport) { | ||
if (rawEnclaveReport.length != ENCLAVE_REPORT_LENGTH) { | ||
return (false, enclaveReport); | ||
} | ||
enclaveReport.cpuSvn = bytes16(rawEnclaveReport.substring(0, 16)); | ||
enclaveReport.miscSelect = bytes4(rawEnclaveReport.substring(16, 4)); | ||
enclaveReport.reserved1 = bytes28(rawEnclaveReport.substring(20, 28)); | ||
enclaveReport.attributes = bytes16(rawEnclaveReport.substring(48, 16)); | ||
enclaveReport.mrEnclave = bytes32(rawEnclaveReport.substring(64, 32)); | ||
enclaveReport.reserved2 = bytes32(rawEnclaveReport.substring(96, 32)); | ||
enclaveReport.mrSigner = bytes32(rawEnclaveReport.substring(128, 32)); | ||
enclaveReport.reserved3 = rawEnclaveReport.substring(160, 96); | ||
enclaveReport.isvProdId = uint16(BELE.leBytesToBeUint(rawEnclaveReport.substring(256, 2))); | ||
enclaveReport.isvSvn = uint16(BELE.leBytesToBeUint(rawEnclaveReport.substring(258, 2))); | ||
enclaveReport.reserved4 = rawEnclaveReport.substring(260, 60); | ||
enclaveReport.reportData = rawEnclaveReport.substring(320, 64); | ||
success = true; | ||
} | ||
|
||
// TODO: check if enclave hash is bytes32 in aws nitro or not | ||
function setEnclaveHash(bytes32 enclaveHash, bool valid) external onlyOwner { | ||
if (valid) { | ||
registeredEnclaveHash[enclaveHash] = false; | ||
} else { | ||
delete registeredEnclaveHash[enclaveHash]; | ||
} | ||
} | ||
|
||
function deleteRegisteredSigner(address signer) external onlyOwner { | ||
delete registeredSigners[signer]; | ||
} | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.