--- eip: 6493 title: SSZ transaction signature scheme description: Signature scheme for native SSZ transactions author: Etan Kissling (@etan-status), Gajinder Singh (@g11tech), Matt Garnett (@lightclient), Vitalik Buterin (@vbuterin) discussions-to: https://ethereum-magicians.org/t/eip-6493-ssz-transaction-signature-scheme/13050 status: Draft type: Standards Track category: Core created: 2023-02-24 requires: 6404, 6466 --- ## Abstract This EIP defines a signature scheme for native [Simple Serialize (SSZ)](https://github.com/ethereum/consensus-specs/blob/b3e83f6691c61e5b35136000146015653b22ed38/ssz/simple-serialize.md) encoded transactions. ## Motivation [EIP-6404](./eip-6404.md) introduces SSZ transactions by converting from RLP transactions. Defining a signature scheme for native SSZ transactions further reduces required conversions and unlocks the forward compatibility benefits of SSZ [`ProgressiveContainer`](./eip-7495.md). ## Specification The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. ### Transaction signature scheme Native SSZ transactions are based on the `TransactionPayload` defined in [EIP-6404](./eip-6404.md) and emit an [EIP-6466](./eip-6466.md) `Receipt`. To distinguish native SSZ transactions from those converted from RLP, native SSZ transactions do not contain the RLP `TransactionType` field in their `TransactionPayload`. All native SSZ transactions follow a scheme based on [`hash_tree_root`](https://github.com/ethereum/consensus-specs/blob/b3e83f6691c61e5b35136000146015653b22ed38/ssz/simple-serialize.md#merkleization) to compute their signing hash (`sig_hash`). Likewise, native SSZ authorizations use such a scheme to derive their signing hash (`auth_hash`). Additional information is mixed into `sig_hash` and `auth_hash` to uniquely identify the underlying specification and avoid hash collisions across different signature kinds. Vendor-defined networks MUST use a different `DomainType` for signing custom transaction or authorization types. | Name | Value | Description | | - | - | - | | `DOMAIN_TX_SSZ` | `DomainType('0x01000008')` | [`DomainType`](https://github.com/ethereum/consensus-specs/blob/b3e83f6691c61e5b35136000146015653b22ed38/specs/phase0/beacon-chain.md#custom-types) for signing native SSZ transactions compatible with this EIP | | `DOMAIN_AUTH_SSZ` | `DomainType('0x02000008')` | [`DomainType`](https://github.com/ethereum/consensus-specs/blob/b3e83f6691c61e5b35136000146015653b22ed38/specs/phase0/beacon-chain.md#custom-types) for signing native SSZ authorizations compatible with this EIP | ```python class ExecutionSigningData(Container): object_root: Root domain_type: DomainType def compute_ssz_sig_hash(payload: SszTransactionPayload) -> Hash32: return Hash32(ExecutionSigningData( object_root=payload.hash_tree_root(), domain_type=DOMAIN_TX_SSZ, ).hash_tree_root()) def compute_ssz_auth_hash(payload: SszAuthorizationPayload) -> Hash32: return Hash32(ExecutionSigningData( object_root=payload.hash_tree_root(), domain_type=DOMAIN_AUTH_SSZ, ).hash_tree_root()) ``` ### Native transactions New [EIP-6404](./eip-7495.md) `TransactionPayload` definitions are introduced to represent native SSZ transactions: - `BasicTransactionPayload` and `CreateTransactionPayload` share the functionality of [EIP-1559](./eip-1559.md#specification) fee market transactions - `BlobTransactionPayload` shares the functionality of [EIP-4844](./eip-4844.md#parameters) blob transactions - `SetCodeTransactionPayload` shares the functionality of [EIP-7702](./eip-7702.md#parameters) set code transactions; native SSZ types are introduced for authorizations ```python class BasicTransactionPayload( ProgressiveContainer(active_fields=[0, 1, 1, 1, 1, 1, 1, 1, 1, 1]) ): chain_id: ChainId nonce: uint64 max_fees_per_gas: BasicFeesPerGas gas: GasAmount to: ExecutionAddress value: uint256 input_: ProgressiveByteList access_list: ProgressiveList[AccessTuple] max_priority_fees_per_gas: BasicFeesPerGas class CreateTransactionPayload( ProgressiveContainer(active_fields=[0, 1, 1, 1, 1, 0, 1, 1, 1, 1]) ): chain_id: ChainId nonce: uint64 max_fees_per_gas: BasicFeesPerGas gas: GasAmount value: uint256 input_: ProgressiveByteList access_list: ProgressiveList[AccessTuple] max_priority_fees_per_gas: BasicFeesPerGas class BlobTransactionPayload( ProgressiveContainer(active_fields=[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) ): chain_id: ChainId nonce: uint64 max_fees_per_gas: BlobFeesPerGas gas: GasAmount to: ExecutionAddress value: uint256 input_: ProgressiveByteList access_list: ProgressiveList[AccessTuple] max_priority_fees_per_gas: BasicFeesPerGas blob_versioned_hashes: ProgressiveList[VersionedHash] class ReplayableBasicAuthorizationPayload(ProgressiveContainer(active_fields=[0, 0, 1, 1])): address: ExecutionAddress nonce: uint64 class BasicAuthorizationPayload(ProgressiveContainer(active_fields=[0, 1, 1, 1])): chain_id: ChainId address: ExecutionAddress nonce: uint64 class SetCodeAuthorizationPayload(CompatibleUnion({ 0x01: RlpReplayableBasicAuthorizationPayload, 0x02: RlpBasicAuthorizationPayload, # [New in EIP-6493] 0x11: ReplayableBasicAuthorizationPayload, 0x12: BasicAuthorizationPayload, })): pass class SetCodeAuthorization(Container): payload: SetCodeAuthorizationPayload signature: ExecutionSignature class SetCodeTransactionPayload( ProgressiveContainer(active_fields=[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1]) ): chain_id: ChainId nonce: uint64 max_fees_per_gas: BasicFeesPerGas gas: GasAmount to: ExecutionAddress value: uint256 input_: ProgressiveByteList access_list: ProgressiveList[AccessTuple] max_priority_fees_per_gas: BasicFeesPerGas authorization_list: ProgressiveList[SetCodeAuthorization] SszTransactionPayload = ( BasicTransactionPayload | CreateTransactionPayload | BlobTransactionPayload | SetCodeTransactionPayload ) SszAuthorizationPayload = ( ReplayableBasicAuthorizationPayload | BasicAuthorizationPayload ) ``` #### Transaction helpers The helpers from [EIP-6404](./eip-6404.md) are updated to support native SSZ transactions. ```python class TransactionPayload(CompatibleUnion({ 0x01: RlpLegacyReplayableBasicTransactionPayload, 0x02: RlpLegacyReplayableCreateTransactionPayload, 0x03: RlpLegacyBasicTransactionPayload, 0x04: RlpLegacyCreateTransactionPayload, 0x05: RlpAccessListBasicTransactionPayload, 0x06: RlpAccessListCreateTransactionPayload, 0x07: RlpBasicTransactionPayload, 0x08: RlpCreateTransactionPayload, 0x09: RlpBlobTransactionPayload, 0x0a: RlpSetCodeTransactionPayload, # [New in EIP-6493] 0x11: BasicTransactionPayload, 0x12: CreateTransactionPayload, 0x13: BlobTransactionPayload, 0x14: SetCodeTransactionPayload, })): pass ``` ### JSON-RPC | Name | Value | Description | | - | - | - | | `SSZ_TX_TYPE` | `TransactionType(0x1f)` | Endpoint specific SSZ object | Certain JSON-RPC endpoints such as `eth_getTransactionByHash` indicate the corresponding [EIP-2718](./eip-2718.md) envelope type prefix in a `type` field. When representing native SSZ transactions on such endpoints, `SSZ_TX_TYPE` SHOULD be indicated as their `type`. Omitting the `type` is NOT RECOMMENDED as certain client applications could confuse the omission with untyped `LegacyTransaction`. ### Unique transaction identifier The unique RPC transaction identifier `tx_hash` for native SSZ transactions is defined to match the [EIP-6404](./eip-6404.md#unique-transaction-identifier) `tx_root` value. ## Rationale The SSZ signature scheme reduces hashing overhead and ensures that `tx_hash` commitments are available on-chain. It also provides a flexible basis for future transaction functionality. ## Backwards Compatibility The new transaction signature scheme is solely used for native SSZ transactions and is representable using a unique [EIP-2718](./eip-2718.md) envelope type prefix (`SSZ_TX_TYPE`) different from existing RLP transactions. ## Security Considerations SSZ signatures MUST NOT collide with RLP transaction and message hashes. As RLP messages are hashed using keccak256, and all SSZ objects are hashed using SHA256. These two hashing algorithms are both considered cryptographically secure and are based on fundamentally different approaches, minimizing the risk of hash collision between those two hashing algorithms. Furthermore, RLP messages are hashed linearly across their serialization, while SSZ objects are hashed using a recursive Merkle tree. Having a different mechanism further reduces the risk of hash collisions. ## Copyright Copyright and related rights waived via [CC0](../LICENSE.md).