--- eip: 8197 title: Cryptographically Agile Transactions description: Cryptographically Agile Transaction format separating signature from transaction body author: Danno Ferrin (@shemnon) , Ron Kahat discussions-to: https://ethereum-magicians.org/t/eip-8197-cryptographically-agile-transactions-catx/28003 status: Draft type: Standards Track category: Core created: 2025-03-04 requires: 1559, 2718, 2930, 4844, 7702 --- ## Abstract CATX (Cryptographically Agile Transactions) is an [EIP-2718](./eip-2718.md) transaction format that separates the transaction body from its signatures using a flat structure: `[payload_type, payload_body, (sig_type, sig_body)+]`. This enables future migration to post-quantum cryptography without modifying transaction semantics, supports multi-signature payloads resistant to key substitution attacks using chained signature hashes, and facilitates future support of zk signature aggregation. ## Motivation Current Ethereum transactions tightly couple body and signature by embedding algorithm-specific fields in the transaction, requiring new transaction types for each signature algorithm. CATX addresses three key concerns: 1. **Post-quantum cryptography adoption**: Signature types are independent of payload types, enabling migration to PQC algorithms without modifying transaction semantics 2. **Key substitution resistance**: Chained signature hashes prevent key substitution attacks (Fujita et al., 2024) in multi-signature payloads 3. **ZK signature aggregation**: Trailing signatures can be easily stripped and replaced for aggregation schemes, with the payload body remaining intact for proof generation ## Specification ### Parameters | Name | Description | Value | |----------------------|------------------------------------------------------|--------| | `CA_TX_TYPE` | [EIP-2718](./eip-2718.md) transaction type | TBD | | `ECDSA_SIG_TYPE` | ECDSA signature identifier | `0x00` | | `SET_CODE_AUTH_TYPE` | [EIP-7702](./eip-7702.md) authorization type (MAGIC) | `0x05` | This EIP defines the transaction format and encoding rules. The assignment of `sig_type` values to specific cryptographic algorithms will be governed by other EIPs. The ECDSA signature type (`0x00`) is specified here as the existing signature algorithm—in the event of conflict, the signature type registry EIP takes precedence. ### Transaction Encoding ``` CA_TX_TYPE || rlp([payload_type, payload_body, (sig_type, sig_body)+]) ``` Signatures are appended as flat alternating `sig_type, sig_body` pairs. The number of signature pairs required is controlled by the payload (either fixed per `payload_type` or determined by fields within `payload_body`). If a transaction does not contain exactly the required number of signatures, the transaction is invalid. ### Payload Types and Data | Type | Name | Sig Count | payload_body | |--------|---------------------------|-----------|------------------------------------------------------------------------------------------------------------------------------------------------------| | `0x01` | [EIP-2930](./eip-2930.md) | 1 | `[chain_id, nonce, gas_price, gas_limit, to, value, data, access_list]` | | `0x02` | [EIP-1559](./eip-1559.md) | 1 | `[chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, to, value, data, access_list]` | | `0x03` | [EIP-4844](./eip-4844.md) | 1 | `[chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, to, value, data, access_list, max_fee_per_blob_gas, blob_versioned_hashes]` | | `0x04` | [EIP-7702](./eip-7702.md) | 1 | `[chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, to, value, data, access_list, authorization_list]` | Legacy (type 0) transactions are not supported. `payload_body` corresponds to the signing form of the related transaction types. The referenced EIPs govern the meaning and validation of the fields in their respective payload bodies, except as noted below. #### [EIP-7702](./eip-7702.md) Authorization List For type `0x04` payloads, the `authorization_list` contains CATX-formatted authorization tuples: ``` authorization_list = [[SET_CODE_AUTH_TYPE, [chain_id, address, nonce], sig_type, sig_body], ...] ``` Each authorization follows the same flat structure as the outer transaction: a type byte, a body, and a signature pair. The authorization signature hash is: ``` auth_hash = keccak256(rlp(SET_CODE_AUTH_TYPE) || rlp([chain_id, address, nonce])) ``` The authority address is recovered from the authorization signature using the same address derivation rules as the outer transaction signatures. Authorization processing follows EIP-7702 semantics. ### Signatures Each signature consists of a `sig_type, sig_body` pair. `sig_type` is encoded as an RLP number. `sig_body` is encoded as an RLP byte string (using either short or long string encoding as appropriate for the signature length). When a signature is transmitted with both public key or verification key and signature data, the public key or verification key should be first in the `sig_body`. This does not apply to algorithms that support key extraction such as ECDSA. Some proposed transaction types, like Frame transactions ([EIP-8141](./eip-8141.md)), will require multiple signatures committing to the whole transaction. The payload body controls how many signatures are required. ### Signature Hash Each signature commits to the payload and all preceding signatures. The hash is computed as: ``` payload_commitment = CA_TX_TYPE || rlp(payload_type) || rlp(payload_body) signature_hash(0) = keccak256(payload_commitment) signature_hash(i) = keccak256(payload_commitment || rlp(sig_type_0) || rlp(sig_body_0) || ... || rlp(sig_type_{i-1}) || rlp(sig_body_{i-1})) ``` Where `payload_type` is the inner type byte. The `CA_TX_TYPE` prefix in `payload_commitment` binds all signatures to the CATX transaction format. Each signature at index `i > 0` additionally includes all preceding `(sig_type, sig_body)` pairs, creating an ordered commitment chain. ### Signature Type 0: ECDSA The ECDSA signature type (`sig_type = 0x00`, RLP encoded as `0x80`) is specified here for bootstrapping purposes. In the event of conflict for the ECDSA type definition other specifications prevail. The signature body for ECDSA(secp256k1) is defined as: ``` sig_body = y_parity[1] || r[32] || s[32] ``` Where `y_parity` uses 0/1 parity (not legacy `v` values of 27/28); any other value is invalid. The length of the sig_body is 65 bytes; if it is not 65 bytes, the signature is invalid. Existing rules regarding ECDSA signatures, such as `s` being in the lower half of the curve order, are observed as well. ### Address Derivation Address derivation depends on the signature type. **ECDSA (0x00)**: Uses the legacy Ethereum address derivation for backwards compatibility: ``` address = keccak256(uncompressed_pubkey)[12:32] ``` Where `uncompressed_pubkey` is the 64-byte public key (without the `0x04` prefix). **Non-ECDSA signature types**: Include the signature type in the hash. ```python def derive_address(sig_type: uint8, public_key: bytes) -> ExecutionAddress: if sig_type == 0x00: # ECDSA: legacy derivation return keccak256(public_key)[12:32] elif len(public_key) == 63: # Pad 63-byte keys with 0x00 between sig_type and key return keccak256(sig_type || 0x00 || public_key)[12:32] else: return keccak256(sig_type || public_key)[12:32] ``` ### Receipts The common receipt formatting is used ``` CA_TX_TYPE || rlp([status, cumulative_gas_used, logs_bloom, logs]) ``` ### Transaction Hash The transaction hash is computed as: ``` tx_hash = keccak256(CA_TX_TYPE || rlp([payload_type, payload_body, sig_type, sig_body, ...])) ``` This is the keccak256 hash over the entire encoded transaction. ### Gas Costs Gas costing rules for each payload type are governed by their respective EIPs. ECDSA signatures impose no additional cost beyond what the referenced EIPs already specify. EIPs defining new signature types should specify a gas penalty or discount relative to ECDSA to account for the algorithm's verification cost, as well as adjustments for signature size differences comparable to calldata costs. ## Rationale ### Separation of Format and Algorithm Registry This EIP intentionally limits its scope to the transaction format—encoding, signature hash chaining, and address derivation rules—without establishing a comprehensive signature type registry. Algorithm assignments, `sig_body` encoding rules, and gas cost adjustments for new signature types are concerns that evolve independently of the transaction format and are better managed by a dedicated registry EIP such as [EIP-7932](./eip-7932.md). The ECDSA type is included here only to make the format immediately usable; deferring to the registry in case of conflict avoids locking algorithm-specific decisions into the transaction format specification. ### Flat Structure Enables independent extension of payload types and signature algorithms without unneeded RLP nesting structures. ### Payload-Controlled Signature Count The payload controls how many signatures are required: either as a fixed count per `payload_type` or determined by fields within the `payload_body`. This allows payload types to define their own multi-signature semantics (e.g., variable frame counts in EIP-8141) while ensuring all required signatures are present. ### Trailing vs. Embedded Signatures The trailing signature table is for signatures that commit to the entire transaction. EIP-7702 authorization signatures commit to a substructure (the delegation tuple) rather than the entire transaction, so they remain embedded within the `payload_body` using the same `[type, body, sig_type, sig_body]` structure. This distinction is important: trailing signatures can be stripped for ZK aggregation while embedded signatures are part of the payload semantics. ### CATX-Formatted Authorizations EIP-7702 authorizations use `SET_CODE_AUTH_TYPE` (`0x05`) as their type byte, which is the same MAGIC value used in EIP-7702. This means the authorization signing hash `keccak256(0x05 || rlp([chain_id, address, nonce]))` is unchanged from EIP-7702, and like the outer transaction, the signed data can be obtained by slicing the encoded structure rather than re-serializing it. `SET_CODE_AUTH_TYPE` serves the same role as `payload_type` in the outer transaction—the signed message can be extracted by slicing the encoded authorization without re-serialization. This also means existing ECDSA EIP-7702 authorization signatures can be directly converted into CATX-formatted authorizations without re-signing. If authorization convertibility is not desired, the same chained hashing scheme used for outer signatures could be applied to authorization signatures to bind them to the CATX format. ### CATX Signature Domain Separation The `CA_TX_TYPE || rlp(payload_type)` construction in `payload_commitment` avoids signature malleability with non-CATX transaction types. Non-CATX types prefix only their own type byte (e.g., `0x02` for EIP-1559) before the RLP payload, while CATX prepends the additional `CA_TX_TYPE` byte. This ensures that a signature produced for a non-CATX transaction cannot be replayed as a CATX signature, and a CATX signature cannot be extracted and used in a non-CATX transaction. Transactions must be re-signed when converting between formats. ### Chained Signature Hashes This EIP uses the chained commitment structure first described in [EIP-8175](./eip-8175.md). This commits each signature to all prior signatures in the transaction. This provides stronger guarantees than simple position indexing because each signer explicitly endorses the identity and commitment of all preceding signers. The chained hash structure ensures: - Signature at index 0 signs `hash(payload_commitment)` - Signature at index 1 signs `hash(payload_commitment || payload_commitment || rlp(sig_type_0) || rlp(sig_body_0))` - Signature at index 2 signs `hash(CA_TX_TYPE || payload_commitment payload_commitment || rlp(sig_type_0) || rlp(sig_body_0) || rlp(sig_type_1) || rlp(sig_body_1))` - Signatures cannot be reordered or substituted between positions For example, a paymaster agreeing to sponsor a transaction can include the sender's signature in its own signing hash, ensuring it only pays for a transaction actually signed by the expected sender. Without chaining, a paymaster's signature could be paired with a different sender's signature for the same payload, potentially changing who benefits from the sponsorship. This is critical for payload types like EIP-8141 Frame transactions where multiple parties (sender, sponsor) sign the same transaction body but for different purposes. ### Legacy Transaction Exclusion Legacy (type 0) transactions are not supported because payload information is encoded in the signature, making it impossible to cleanly separate the body from the signature. ### Address Derivation and Cross-Scheme Collisions Address derivation depends on the signature type to prevent cross-scheme collisions. The 63-byte special case inserts a `0x00` padding byte. Without it, `keccak256(sig_type || 63_byte_key)` would be 64 bytes—the same length as ECDSA's `keccak256(64_byte_key)`—creating potential collision risk. This approach is consistent with [EIP-7932](./eip-7932.md). ### Reduced Signature Manipulation The signature hash uses a byte-slice of the payload instead of a re-written container for the payload, simplifying memory management. ## Backwards Compatibility This is a new transaction type and does not affect existing types. [EIP-2930](./eip-2930.md)/[EIP-1559](./eip-1559.md)/[EIP-4844](./eip-4844.md)/[EIP-7702](./eip-7702.md) transactions can be converted to CATX format. The `CA_TX_TYPE` prefix in the signature hash means existing signatures are not directly compatible—transactions must be re-signed for CATX format. ## Security Considerations ### Signature Algorithm Binding The `sig_type` field binds each signature to a specific algorithm. Implementations MUST verify that the correct algorithm is used for each signature and MUST reject transactions where the signature count does not exactly match the count required by the payload. The valid set of signature types can be updated during hard forks, enabling deprecation of vulnerable schemes while keeping existing transaction structures intact. ### Key Substitution Attacks In a multi-signature transaction, a key substitution attack (Fujita, Sakai, Yamashita, & Hanaoka, "On Key Substitution Attacks against Aggregate Signatures and Multi-Signatures," IACR ePrint 2024/1728) occurs when one signer's signature is replaced or reordered to change the authorization semantics. The chained signature hash structure defends against this: because each signature at index `i` commits to all preceding signatures, later signers cryptographically endorse the specific identities of all earlier signers. Replacing an earlier signature invalidates every following signature in the chain, and reordering signatures changes the hash inputs, making the substituted signatures unverifiable. ### Cross-Scheme Address Collisions Non-ECDSA types use distinct address derivation that includes the `sig_type` in the hash input, ensuring that different signature algorithms produce non-overlapping address spaces. This prevents an attacker from exploiting a collision between key formats of different algorithms to claim control of an address derived under a different scheme. ### CATX Signature Domain Separation The `payload_commitment` includes `CA_TX_TYPE` as a prefix before `rlp(payload_type)`, ensuring that CATX signatures are not valid for the corresponding non-CATX transaction types and vice versa. A non-CATX EIP-1559 signature signs `keccak256(0x02 || rlp([...]))` while a CATX signature for the same payload signs `keccak256(CA_TX_TYPE || 0x02 || rlp([...]))`. This binds all CATX signatures—including index 0—to the CATX representation, preventing cross-format signature reuse. ### Authorization Signature Malleability Because the EIP-7702 authorization signing hash is identical between standard type-4 transactions and CATX transactions, authorization signatures can be freely converted between the two formats. This is intentional and safe—the authorization semantics are identical regardless of the containing transaction format. ## Copyright Copyright and related rights waived via [CC0](../LICENSE.md).