-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
refactor(protocol): extract SgxVerifierBase to be reused #18231
Merged
Merged
Changes from all commits
Commits
Show all changes
2 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 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
This file contains 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
171 changes: 171 additions & 0 deletions
171
packages/protocol/contracts/layer1/verifiers/SgxVerifierBase.sol
This file contains 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.24; | ||
|
||
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; | ||
import "src/shared/common/EssentialContract.sol"; | ||
import "src/shared/common/LibStrings.sol"; | ||
import "../automata-attestation/interfaces/IAttestation.sol"; | ||
import "../automata-attestation/lib/QuoteV3Auth/V3Struct.sol"; | ||
|
||
/// @title SgxVerifierBase | ||
/// @dev Please see references below: | ||
/// - Reference #1: https://ethresear.ch/t/2fa-zk-rollups-using-sgx/14462 | ||
/// - Reference #2: https://github.com/gramineproject/gramine/discussions/1579 | ||
/// @custom:security-contact security@taiko.xyz | ||
abstract contract SgxVerifierBase is EssentialContract { | ||
/// @dev Each public-private key pair (Ethereum address) is generated within | ||
/// the SGX program when it boots up. The off-chain remote attestation | ||
/// ensures the validity of the program hash and has the capability of | ||
/// bootstrapping the network with trustworthy instances. | ||
struct Instance { | ||
address addr; | ||
uint64 validSince; | ||
} | ||
|
||
/// @notice The expiry time for the SGX instance. | ||
uint64 public constant INSTANCE_EXPIRY = 365 days; | ||
|
||
/// @notice A security feature, a delay until an instance is enabled when using onchain RA | ||
/// verification | ||
uint64 public constant INSTANCE_VALIDITY_DELAY = 0; | ||
|
||
/// @dev For gas savings, we shall assign each SGX instance with an id that when we need to | ||
/// set a new pub key, just write storage once. | ||
/// Slot 1. | ||
uint256 public nextInstanceId; | ||
|
||
/// @dev One SGX instance is uniquely identified (on-chain) by it's ECDSA public key | ||
/// (or rather ethereum address). Once that address is used (by proof verification) it has to be | ||
/// overwritten by a new one (representing the same instance). This is due to side-channel | ||
/// protection. Also this public key shall expire after some time | ||
/// (for now it is a long enough 6 months setting). | ||
/// Slot 2. | ||
mapping(uint256 instanceId => Instance instance) public instances; | ||
|
||
/// @dev One address shall be registered (during attestation) only once, otherwise it could | ||
/// bypass this contract's expiry check by always registering with the same attestation and | ||
/// getting multiple valid instanceIds. While during proving, it is technically possible to | ||
/// register the old addresses, it is less of a problem, because the instanceId would be the | ||
/// same for those addresses and if deleted - the attestation cannot be reused anyways. | ||
/// Slot 3. | ||
mapping(address instanceAddress => bool alreadyAttested) public addressRegistered; | ||
|
||
uint256[47] private __gap; | ||
|
||
/// @notice Emitted when a new SGX instance is added to the registry, or replaced. | ||
/// @param id The ID of the SGX instance. | ||
/// @param instance The address of the SGX instance. | ||
/// @param replaced The address of the SGX instance that was replaced. If it is the first | ||
/// instance, this value is zero address. | ||
/// @param validSince The time since the instance is valid. | ||
event InstanceAdded( | ||
uint256 indexed id, address indexed instance, address indexed replaced, uint256 validSince | ||
); | ||
|
||
/// @notice Emitted when an SGX instance is deleted from the registry. | ||
/// @param id The ID of the SGX instance. | ||
/// @param instance The address of the SGX instance. | ||
event InstanceDeleted(uint256 indexed id, address indexed instance); | ||
|
||
error SGX_ALREADY_ATTESTED(); | ||
error SGX_INVALID_ATTESTATION(); | ||
error SGX_INVALID_INSTANCE(); | ||
error SGX_INVALID_PROOF(); | ||
error SGX_RA_NOT_SUPPORTED(); | ||
|
||
/// @notice Register an SGX instance after the attestation is verified | ||
/// @param _attestation The parsed attestation quote. | ||
/// @return The respective instanceId | ||
function registerInstance(V3Struct.ParsedV3QuoteStruct calldata _attestation) | ||
external | ||
returns (uint256) | ||
{ | ||
address automataDcapAttestation = resolve(LibStrings.B_AUTOMATA_DCAP_ATTESTATION, true); | ||
|
||
if (automataDcapAttestation == address(0)) { | ||
revert SGX_RA_NOT_SUPPORTED(); | ||
} | ||
|
||
(bool verified,) = IAttestation(automataDcapAttestation).verifyParsedQuote(_attestation); | ||
|
||
if (!verified) revert SGX_INVALID_ATTESTATION(); | ||
|
||
address[] memory addresses = new address[](1); | ||
addresses[0] = address(bytes20(_attestation.localEnclaveReport.reportData)); | ||
|
||
return _addInstances(addresses, false)[0]; | ||
} | ||
|
||
/// @notice Adds trusted SGX instances to the registry. | ||
/// @param _instances The address array of trusted SGX instances. | ||
/// @return The respective instanceId array per addresses. | ||
function addInstances(address[] calldata _instances) | ||
external | ||
onlyOwner | ||
returns (uint256[] memory) | ||
{ | ||
return _addInstances(_instances, true); | ||
} | ||
|
||
/// @notice Deletes SGX instances from the registry. | ||
/// @param _ids The ids array of SGX instances. | ||
function deleteInstances(uint256[] calldata _ids) | ||
external | ||
onlyFromOwnerOrNamed(LibStrings.B_SGX_WATCHDOG) | ||
{ | ||
for (uint256 i; i < _ids.length; ++i) { | ||
uint256 idx = _ids[i]; | ||
|
||
if (instances[idx].addr == address(0)) revert SGX_INVALID_INSTANCE(); | ||
|
||
emit InstanceDeleted(idx, instances[idx].addr); | ||
|
||
delete instances[idx]; | ||
} | ||
} | ||
|
||
function _addInstances( | ||
address[] memory _instances, | ||
bool instantValid | ||
) | ||
internal | ||
returns (uint256[] memory ids) | ||
{ | ||
ids = new uint256[](_instances.length); | ||
|
||
uint64 validSince = uint64(block.timestamp); | ||
|
||
if (!instantValid) { | ||
validSince += INSTANCE_VALIDITY_DELAY; | ||
} | ||
|
||
for (uint256 i; i < _instances.length; ++i) { | ||
if (addressRegistered[_instances[i]]) revert SGX_ALREADY_ATTESTED(); | ||
|
||
addressRegistered[_instances[i]] = true; | ||
|
||
if (_instances[i] == address(0)) revert SGX_INVALID_INSTANCE(); | ||
|
||
instances[nextInstanceId] = Instance(_instances[i], validSince); | ||
ids[i] = nextInstanceId; | ||
|
||
emit InstanceAdded(nextInstanceId, _instances[i], address(0), validSince); | ||
|
||
++nextInstanceId; | ||
} | ||
} | ||
|
||
function _replaceInstance(uint256 id, address oldInstance, address newInstance) internal { | ||
// Replacing an instance means, it went through a cooldown (if added by on-chain RA) so no | ||
// need to have a cooldown | ||
instances[id] = Instance(newInstance, uint64(block.timestamp)); | ||
emit InstanceAdded(id, newInstance, oldInstance, block.timestamp); | ||
} | ||
|
||
function _isInstanceValid(uint256 id, address instance) internal view returns (bool) { | ||
if (instance == address(0)) return false; | ||
if (instance != instances[id].addr) return false; | ||
return instances[id].validSince <= block.timestamp | ||
&& block.timestamp <= instances[id].validSince + INSTANCE_EXPIRY; | ||
} | ||
} |
This file contains 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
This file contains 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
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change function order