Tx Lifecycle
This page describes how Seismic transactions work from end-to-end.

Key management
The network manages its keys through the
seismic-enclave-servercrate. Reth (and Summit) can make RPC calls to this server. One such call is to get the network keysEnclave can boot in either
--genesis-nodeor--peers <ip>mode. The former generates its own root key and shares it with peers after they pass validation. The latter loops through its peer IPs until it receives the root key from one of themEnclave then derives a few different keys from that root key. Most importantly, it derives the encryption secret key. This is the key used to decrypt Seismic transaction calldata
When
seismic-rethboots, it requests the derived keys from the enclave and keeps them in memoryWe exposed a new RPC method,
seismic_getTeePublicKey. Its response is the public key of the aforementioned secret key that decrypts Seismic transactions. Calling this endpoint is the first step that a client takes to build a Seismic transactionClients also generate their own secret key, which can be either ephemeral (default) or long-lived, if they prefer to manage this themselves
Their secret key and the network public key combine to create an AES key, which is used to encrypt calldata
Encryption & Metadata
The client will include their encryption public key in the transaction, along with four other parameters to tighten the security of encryption. These are:
a 12-byte
encryptionNoncerecentBlockHash, which must be within 100 blocks of the latest blockan
expiresAtBlocknumber, after which this transaction is invalidoptionally, a boolean
signedRead. If set, it only allows the transaction to be used for signed reads. Otherwise, it will be rejected by transaction pool validation
There is one other field in Seismic transaction metadata: an integer called
messageVersion. This field is a hack to allow browser extension wallets (e.g. MetaMask) to support the Seismic transaction type. Message version 0, the default, means a standard Seismic transaction as described above. Message version 2 corresponds to a transaction sent as EIP-712 typed data, which browser extension wallets can sign. There is no message version 1, but we reserved this for implementing Seismic transactions viaeth_personalSignThese six Seismic-specific fields are called
SeismicElements: the client encryption public key, the four security fields above, and the message version. They are combined with the EOA address (sender),chainId,nonce,toaddress, andvalue. The full set of 11 fields is referred to as the Seismic transaction metadata (TxSeismicMetadata) inseismic-alloy-consensusTo encrypt calldata, we use AES with AEAD. The AEAD is an RLP encoding of the
TxSeismicMetadata. The nonce for this encryption is the same 12-byte encryption nonce as we included in the metadataThe encrypted calldata is then passed to a Seismic transaction in the data/input field. Seismic transactions work just like Legacy Ethereum transactions, except:
they have a tx type of
74or0x4athey have these
SeismicElementsattached as well
Decryption
Transactions sent with type
0x4abut incomplete Seismic elements are rejected from the tx pool, as are transactions not marked as0x4abut do contain Seismic elementsNodes will decrypt Seismic transactions by:
decoding the transaction
recovering the signer
assembling the metadata
encoding it as AEAD via RLP
generating the AES key by combining the network's secret key with the transaction's encryption public key
If transaction decryption fails, the transaction is removed from the transaction pool
If it succeeds, it passes to the revm transaction environment as plaintext
Calls to get transaction information after they have landed on chain should return input as the encrypted calldata, and not the plaintext
A note on calldata encoding: s-types are encoded the same way as their public analogues. The consequence is an interesting artifact of the Seismic protocol (and maybe a security concern): Solidity has no clue whether functions are called with Seismic transactions or not. As a result, it's totally allowed to alter shielded state with vanilla Ethereum transactions. It's also allowed to do the reverse, by altering public state with Seismic transactions
Shielded storage
Inside Solidity, we've defined two new opcodes:
CLOADandCSTORE. These are the shielded analogues toSLOADandSSTORE. We useCLOAD/CSTOREwhen the underlying type is an s-type.Importantly, we maintain only one state tree, as you can see in
seismic-trie(a fork of alloy-trie). We modified the state tree by adding an extra boolean flag,is_private, to leaves. This is wrapped inside the struct calledFlaggedStorage, which replacesStorageValue(a plainU256). We use this flag to validateCLOAD/CSTOREcalls, and to know whether we can expose this piece of storage, via e.g.eth_getStorageAtWhen we see a
CLOADopcode insideseismic-revm, we load the storage slot and validate that it either hasis_privateset totrueor is an uninitialized slot. ForCSTORE, we write the storage value withis_private = true. We throw errors when trying toCLOAD/CSTOREaFlaggedStoragethat hasis_private = false(“Invalid public storage access”). Similarly, we throw errors when trying toSLOAD/SSTOREonFlaggedStoragethat hasis_private = true(“Invalid private storage access”). These errors are thrown insideseismic-revm.Unlike SSTORE/SLOAD, the gas cost of CLOAD/CSTORE does not change based on the length of the word stored. This is to prevent attackers from deducing information about shielded storage values
Notes
Outside of
SeismicElementsand the encrypted calldata, Seismic transactions have the same fields as legacy transactions. In particular, it uses the same gas parameters:gasPriceandgasLimitSeismic transactions cannot be used to deploy bytecode via
Createcalls. Instead, we only allow Seismic transactions to be sent to a specific address. We did this to make metadata validation easier, and we can’t see a good reason to deploy encrypted bytecode
Last updated

