EIP-8197 - Cryptographically Agile Transactions

Created 2025-03-04
Status Draft
Category Core
Type Standards Track
Authors
  • Danno Ferrin (@shemnon) <danno at tectonic.xyz>

  • Ron Kahat <ron at tectonic.xyz>

Requires

Abstract

CATX (Cryptographically Agile Transactions) is an EIP-2718 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 transaction type TBD
ECDSA_SIG_TYPE ECDSA signature identifier 0x00
SET_CODE_AUTH_TYPE EIP-7702 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 1 [chain_id, nonce, gas_price, gas_limit, to, value, data, access_list]
0x02 EIP-1559 1 [chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, to, value, data, access_list]
0x03 EIP-4844 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 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 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), 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.

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. 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. 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:

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.

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-1559/EIP-4844/EIP-7702 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.