Warning
This repository is a work in progress, and for now only functions as a showcase. This code is not intended to secure any valuable information.
This repository contains the smart contracts and development environment for SUAVE's intermediate programming layer, where Solidity contracts directly control SGX trusted hardware features like attestation and sealing. This also contains the code and examples that go along with the post "Sirrah: Speedrunning a TEE Coprocessor."
The Andromeda precompiles are a minimal way to add Trusted Hardware Enclaves to the Solidity environment. The interface is defined in ./src/IAndromeda.sol). It basically adds four new things:
- Sampling random bytes.
function localRandom() view external returns(bytes32);
This returns new random bytes each time it is called, sampled using the RDRAND
x86 instruction.
- Process storage
function volatileSet(bytes32 tag, bytes32 value) external;
function volatileGet(bytes32 tag) external returns(bytes32 value);
This provides a key value storage. Each caller has its own isolated storage. If a message call reverts, it will not undo the side effects of volatileSet
. All this storage is cleared each time the process restarts.
- Persistent storage
function sealingKey() view external;
This provides a persistent key. For each caller, each MRENCLAVE on each CPU gets its own one of these. This is used so the enclave can store an encrypted file and retrieve it later if the process restarts.
- Remote attestation
function attestSgx(bytes32 appData) external returns (bytes memory att);
function verifySgx(address caller, bytes32 appData, bytes memory att) external view returns (bool);`
This produces evidence that the appData
was requested by the caller
. The verification routine is pure Solidity, and does not require any special precompiles.
- External services
Currently there are two external services defined: redis (persistent) key-value store and redis pubsub:
interface Redis {
function set(string memory key, bytes memory value) external;
function get(string memory key) external returns (bytes memory);
}
interface RedisPubsub {
function publish(string memory topic, bytes memory msg) external;
function get_message(string memory topic) external returns (bytes memory);
function subscribe(string memory topic) external;
function unsubscribe(string memory topic) external;
}
For interacting with external services see lib/revm-services/Interfaces.sol and the RedisConfidentialStore example contract.
We provide three implementations of the Andromeda interface:
- A forge mockup environment. This is sufficient for logical testing of smart contracts. ./src/AndromedaForge.sol
- A remote environment using actual remote attestations, computed via a remote service (dummy attester service) ./src/AndromedaRemote.sol
- Invoke the actual the precompiles recognized by the Andromeda EVM in separate repository, suave-andromeda-revm.
To reiterate, the forge development environment here (implementations 1 and 2) does NOT require any use of SGX, so you can develop on any machine (even on TEE-level components like a Key Manager and TCB recovery handling).
Here's the motivating scenario to go along with the blogpost: Looking at ./src/examples/SpeedrunAuction.sol:LeakyAuction, we can see a second price auction in plain ordinary Solidity. But, due to a lack of privacy, this is vulnerable to griefing through MEV.
The point of this demo is to solve this problem using the Andromeda precompiles. See: ./src/examples/Auction.sol:SealedAuction
The "speedrun" was a little unsatisfying because you have to bootstrap a new key each time you carry out an auction. Instead, we want to have a singletone Key Manager that encapsulates a single bootstrapping ceremony, and thereafter many applications as well as many separate kettles can provide confidential coprocessing service. The proposed key manager has the following features:
- Verification of a raw SGX attestation (expensive in Solidity gas) only needs to occur once per Kettle. After initial registration, ordinary digital signatures can be used instead. Much cheaper.
- Multiple Kettles can join. Newly registered Kettles receive a copy of the key from existing Kettles that already have it
- A single instance of the Key Manager contract can be used by other contracts.
This is still a simplified strawman example, as it does not support upgrading the enclave, revoking keys, etc. This is meant as a starting point, and those ideas can be explored in Solidity.
As one demo, we include a sample application in the form of a timelock decryption service. The code is at ./src/examples/Timelock.sol:Timelock and the smart contract is found on the Rigil test network https://explorer.rigil.suave.flashbots.net/address/0x6858162E579DFC66a623AE1bA357d67BF026dDD6.
The application is very simple: messages are encrypted to the public key of the contract. A TEE kettle can only decrypt them only after the light client reports that a deadline has passed on the blockchain.
The frontend is hosted at https://timelock.sirrah.suave.flashbots.net/
You'll need to point your web3 browser extension like Metamask to point to a Rigil endpoint. If you don't have Rigil testnet coins you can get some at faucet.rigil.suave.flashbots.net.
In another demo, RedisConfidentialStore, we show how we can use redis's key-value store and pubsub to implement a replicated bundle database which preserves integrity and confidentiality.
This specific demo aims to bring us closer to feature parity with Rigil by implementing the confidential data store.
This demo is also very simple, and allows inserting bundles, indexing them (by the block they target), and fetching them. The demo is built in a way that also allows replicating bundles across multiple kettles (as long as they are onboarded to the same key manager - not shown on the demo).
The RedisConfidentialStore contract is deployed to the Rigil testnet, and can be found at https://explorer.rigil.suave.flashbots.net/address/0xF1b9942f1DBf1dD9538FC2ee8e2FC533b7070366.
Relies on Foundry for contrats, Python 3 for various utilities, and npm for automation and demo.
For ease of use we provide the following make
targets:
make build
to build contractsmake format
to format contractsmake test
to test contractsmake deploy
to deploy contractsmake configure-all-tcbinfos
to configureAndromeda
contracts with TCBInfo from Intelmake bootstrap
to bootstrap a kettle forKeyManager
make onboard
to onboard a kettle toKeyManager
from one already bootstrappedmake deploy-examples
to deploySealedAuction
andTimelock
for use in the demo webappmake test-examples
to automatically deploy and testSealedAuction
andTimelock
on chain
Deployed contracts are kept track of in the deployment.json file. If you want to re-deploy a contract, simply remove it from the ADDR_OVERRIDES
section. The various deployment scripts write to the file on successful deployments.
If you want to build and deploy only some of the contracts, here are ones predeployed to Rigil.
- Contracts
In [deployment.json] change the ADDR_OVERRIDES
to include:
"ADDR_OVERRIDES": {
"out/SigVerifyLib.sol/SigVerifyLib.json": "0xed16804dB4D00A61e85569362ac10ef66126B13e",
"out/Andromeda.sol/Andromeda.json": "0x76832d4d9823eCD154598Ce2969D5C4e794E84c4"
}
- Demo apps
If you want to use predeployed Timelock
demo, one is available on Rigil. Include the following in the ADDR_OVERRIDES
:
"ADDR_OVERRIDES": {
"out/Timelock.sol/Timelock.json": "0x6858162E579DFC66a623AE1bA357d67BF026dDD6",
"out/RedisConfidentialStore.sol/BundleConfidentialStore.json": "0xF1b9942f1DBf1dD9538FC2ee8e2FC533b7070366"
}
Warning
The addresses will change, so don't depend on them too much. This is intended for quick prototyping rather than something that is highly available.
If you don't want to run a kettle yourself, you can always connect to the development TEE kettle at https://kettle.sirrah.suave.flashbots.net.
The code in this project is free software under the MIT license.