---
eip: 8202
title: Scheme-Agile Transactions
description: A new EIP-2718 transaction type with a common EIP-1559 fee header, scheme-agile sender authorization, and flat typed extensions
author: Giulio Rebuffo (@Giulio2002), Ben Adams (@benaadams)
discussions-to: https://ethereum-magicians.org/t/eip-8202-schemed-transaction/28044
status: Draft
type: Standards Track
category: Core
created: 2026-03-22
requires: 2, 155, 1559, 2718, 2780, 4844, 7702, 7976
---

## Abstract

This EIP introduces a new [EIP-2718](./eip-2718.md) typed transaction (`TransactionType = 0x05`) called `SchemedTransaction`.

A `SchemedTransaction` has one common [EIP-1559](./eip-1559.md)-style fee header and one common execution payload (`to`, `value`, `data`). Optional features are attached as flat typed components inside the payload rather than by minting a new top-level transaction family for every combination.

The transaction has two typed attachment lists:

* `authorizations` - ordered transaction authorizations
* `extensions` - flat typed extensions, unique by `extension_id`

Scheme agility is expressed as an authorization capability, not a separate transaction family. This EIP initially defines one required top-level authorization role, `SENDER`, and two sender signature schemes:

* secp256k1 ECDSA
* Ephemeral secp256k1 (Merkle-committed one-time ECDSA keys)

This EIP also defines two initial extensions:

* a blob extension carrying the transaction-local blob fields of [EIP-4844](./eip-4844.md)
* a set-code extension carrying [EIP-7702](./eip-7702.md)-style pre-execution authorizations

The extension model is open to future additions. For example, an [EIP-8141](./eip-8141.md)-style frame extension could attach nested execution frames to the same transaction envelope without requiring a new top-level transaction type.

The sender address is derived deterministically from the public key recovered or verified from the `SENDER` authorization. For secp256k1, address derivation is exactly the same as legacy Ethereum. For ephemeral secp256k1, the address is derived from a Merkle root over the full key sequence, providing a stable identity across key rotations.

This design keeps transaction composition flat: one execution payload, many orthogonal capabilities, and no recursive transaction structure or frame execution model.

## Motivation

### Stop proliferating top-level transaction families

Ethereum currently adds new features such as blobs and set-code authorizations by minting fresh [EIP-2718](./eip-2718.md) transaction types whose payloads are each mostly [EIP-1559](./eip-1559.md)-shaped with a few appended fields.

That approach does not compose well. A user who wants passkey signing, blobs, and set-code authorization should not require yet another top-level transaction family. The cleaner model is:

* [EIP-1559](./eip-1559.md) is the common fee header
* call/create is the base execution payload
* blobs are an optional extension
* set-code authorization is an optional pre-execution extension
* scheme agility is the sender authorization mechanism

Under [EIP-2718](./eip-2718.md), the payload of a typed transaction is already just an opaque byte string. This EIP uses that flexibility to define one outer type whose inner parts compose cleanly.

### Native quantum-safe support

Quantum computers will eventually break ECDSA over secp256k1. Ethereum needs a user-facing transaction format that lets EOAs migrate to quantum-safe signing without wrapping execution in a new abstraction.

The ephemeral secp256k1 scheme achieves quantum safety by making each key pair single-use, eliminating long-term public key exposure. This requires no new cryptographic primitives beyond Keccak-256 preimage resistance. Future signature schemes (P256/passkeys, Falcon-512, or other post-quantum algorithms) can be added as new `scheme_id` values without changing the transaction envelope.

### Flat composition, not recursive composition

This EIP is intentionally not a frame transaction system. It does not introduce recursive transactions, multiple execution payloads, new execution modes, or new opcodes.

The model is:

* one execution payload
* one or more typed authorizations
* zero or more typed extensions

This keeps validation phase-based and close to today's transaction processing, while still allowing new protocol features and new signature schemes to be added without minting a new outer transaction type for every combination.

## Specification

### Constants

| Name                     | Value   | Description                                             |
| ------------------------ | ------- | ------------------------------------------------------- |
| `SCHEMED_TX_TYPE`        | `0x05`  | [EIP-2718](./eip-2718.md) transaction type byte         |
| `ROLE_SENDER`            | `0x00`  | Top-level sender authorization                          |
| `ROLE_PAYER`             | `0x01`  | Reserved for future use                                 |
| `SCHEME_SECP256K1`       | `0x00`  | secp256k1 ECDSA                                         |
| `SCHEME_EPHEMERAL_K1`    | `0x01`  | Ephemeral secp256k1 with Merkle-committed key rotation  |
| `EXT_BLOB`               | `0x01`  | Blob extension                                          |
| `EXT_SET_CODE`           | `0x02`  | Set-code / delegation extension                         |
| `SET_CODE_AUTH_MAGIC`    | `0x05`  | Domain byte for set-code authorization messages         |
| `PER_AUTH_BASE_COST`     | `12500` | Per-authorization processing base cost                  |
| `PER_EMPTY_ACCOUNT_COST` | `25000` | Per-authorization intrinsic charge                      |
| `EPHEMERAL_TREE_DEPTH`   | `20`    | Merkle tree depth for ephemeral key commitments         |
| `EPHEMERAL_PROOF_LEN`    | `640`   | Merkle proof length in bytes (20 × 32)                  |

The `role_id`, `scheme_id`, and `extension_id` spaces each range from `0x00` to `0xFF`. New values MUST be specified by a distinct EIP.

`SET_CODE_AUTH_MAGIC`, `PER_AUTH_BASE_COST`, and `PER_EMPTY_ACCOUNT_COST` intentionally match the corresponding [EIP-7702](./eip-7702.md) constants.

### Transaction Envelope

A `SchemedTransaction` is serialized as:

0x05 || rlp([
    chain_id,
    nonce,
    max_priority_fee_per_gas,
    max_fee_per_gas,
    gas_limit,
    to,
    value,
    data,
    authorizations,
    extensions
])
```

This defines one canonical base transaction body:

base = [
    chain_id,
    nonce,
    max_priority_fee_per_gas,
    max_fee_per_gas,
    gas_limit,
    to,
    value,
    data
]
```

#### Field Definitions

| Field                      | Type                  | Description                                      |
| -------------------------- | --------------------- | ------------------------------------------------ |
| `chain_id`                 | `uint256`             | [EIP-155](./eip-155.md) chain identifier         |
| `nonce`                    | `uint64`              | Sender account nonce                             |
| `max_priority_fee_per_gas` | `uint256`             | [EIP-1559](./eip-1559.md) priority fee           |
| `max_fee_per_gas`          | `uint256`             | [EIP-1559](./eip-1559.md) max fee                |
| `gas_limit`                | `uint64`              | Gas limit                                        |
| `to`                       | `Address \| null`     | Recipient address, or null for contract creation |
| `value`                    | `uint256`             | Wei to transfer                                  |
| `data`                     | `bytes`               | Calldata / initcode                              |
| `authorizations`           | `List[Authorization]` | Ordered transaction authorizations               |
| `extensions`               | `List[Extension]`     | Typed extension list                             |

Base rules:

* `to = null` means contract creation.
* There is no `access_list` in the base transaction type.
* `authorizations` is ordered and the order is signed.
* `extensions` is a flat typed list and MUST be unique by `extension_id`.
* Unknown `extension_id` is invalid.
* Exactly one `ROLE_SENDER` authorization is required.
* In this version, `ROLE_PAYER` is reserved and MUST NOT appear.

### Authorization and Extension Containers

An authorization is encoded as:

```text
authorization = [role_id, scheme_id, witness]
```

An extension is encoded as:

```text
extension = [extension_id, extension_payload]
```

`witness` and `extension_payload` are opaque bytes whose internal meaning is determined by `scheme_id` and `extension_id` respectively. In this EIP, each defined witness or extension payload is itself a canonical RLP encoding of the scheme-specific or extension-specific structure.

### Signing Data

The sender signs the full base transaction and all extensions, with authorization witnesses elided from the current and later authorization positions.

For this EIP, valid transactions contain exactly one top-level authorization, so this reduces to signing the full transaction with the sender witness omitted.

```python
def signing_hash(tx, auth_index):
    committed_auths = []
    for j, auth in enumerate(tx.authorizations):
        if j < auth_index:
            committed_auths.append(auth)
        else:
            committed_auths.append([auth.role_id, auth.scheme_id])

    return keccak256(
        SCHEMED_TX_TYPE || rlp([
            tx.chain_id,
            tx.nonce,
            tx.max_priority_fee_per_gas,
            tx.max_fee_per_gas,
            tx.gas_limit,
            tx.to,
            tx.value,
            tx.data,
            committed_auths,
            tx.extensions
        ])
    )
```

For the required sender authorization at index `0`, this is equivalent to:

```python
def sender_signing_hash(tx):
    return keccak256(
        SCHEMED_TX_TYPE || rlp([
            tx.chain_id,
            tx.nonce,
            tx.max_priority_fee_per_gas,
            tx.max_fee_per_gas,
            tx.gas_limit,
            tx.to,
            tx.value,
            tx.data,
            [[ROLE_SENDER, tx.authorizations[0].scheme_id]],
            tx.extensions
        ])
    )
```

### Scheme Registry

Each registered signature scheme defines:

* `scheme_id`
* witness format
* `verify_or_recover(message, witness) -> pubkey`
* sender address derivation
* intrinsic gas surcharge

This EIP initially defines two `scheme_id` values.

### Signature Schemes

#### secp256k1 (`0x00`)

Witness payload:

```text
rlp([y_parity, r, s])
```

| Field      | Size     |
| ---------- | -------- |
| `y_parity` | 1 byte   |
| `r`        | 32 bytes |
| `s`        | 32 bytes |

`s` MUST satisfy `s <= secp256k1n / 2` per [EIP-2](./eip-2.md).

Public key recovery and address derivation:

```python
pubkey = ecrecover(sender_signing_hash(tx), y_parity, r, s)  # 64-byte uncompressed x || y
sender = keccak256(pubkey)[12:]
```

This intentionally preserves legacy Ethereum address derivation for secp256k1 keys.

Scheme gas surcharge: **0**.

#### Ephemeral secp256k1 (`0x01`)

This scheme achieves quantum safety by making each secp256k1 key pair single-use. At account creation, the user derives a deterministic sequence of key pairs (e.g. via [BIP 44]) and commits to all future public keys by constructing a Merkle tree over their hashes. The Merkle root is embedded in the sender address. Each transaction provides a standard ECDSA signature plus a Merkle proof that the signing key is the leaf at position `nonce` in the committed tree.

[BIP 44]: https://github.com/bitcoin/bips/blob/69a63f629f4c27b249882b4e0db6af516f1bcea9/bip-0044.mediawiki

The long-lived secret is the user's seed (e.g. a BIP-39 mnemonic), which never touches the chain. Each ephemeral private key `sk_i` is derived on-the-fly, used exactly once for the transaction at nonce `i`, and is never valid again because the protocol binds the Merkle leaf index to the account nonce.

##### Account Setup

Account setup is performed entirely off-chain:

```python
seed = generate_bip39_mnemonic()

leaves = []
for i in range(2**EPHEMERAL_TREE_DEPTH):
    sk_i = derive_bip44(seed, path=f"m/44'/60'/0'/0/{i}")
    pk_i = secp256k1_pubkey(sk_i)        # 64 bytes, uncompressed x || y
    leaves.append(keccak256(pk_i))

merkle_root = build_merkle_tree(leaves)   # binary Keccak-256 Merkle tree

# The address is derived from the root — no on-chain state required
address = keccak256(SCHEME_EPHEMERAL_K1 || merkle_root)[12:]
```

No on-chain registration, storage writes, or contract deployment is required. The Merkle root is carried in every transaction witness and validated against the sender address.

##### Witness Payload

```text
rlp([y_parity, r, s, merkle_root, merkle_proof])
```

| Field          | Size                                    |
| -------------- | --------------------------------------- |
| `y_parity`     | 1 byte                                  |
| `r`            | 32 bytes                                |
| `s`            | 32 bytes                                |
| `merkle_root`  | 32 bytes                                |
| `merkle_proof` | `EPHEMERAL_TREE_DEPTH * 32` = 640 bytes |

`s` MUST satisfy `s <= secp256k1n / 2` per [EIP-2](./eip-2.md).

`merkle_proof` is an ordered list of `EPHEMERAL_TREE_DEPTH` sibling hashes for the leaf-to-root path.

##### Signing

```python
def sign_ephemeral(tx, seed, merkle_tree):
    i = tx.nonce
    sk_i = derive_bip44(seed, path=f"m/44'/60'/0'/0/{i}")

    # Compute signing hash — identical to all other schemes
    msg = sender_signing_hash(tx)

    # Standard secp256k1 ECDSA
    y_parity, r, s = ecdsa_sign(sk_i, msg)

    # Merkle proof that pk_i is the leaf at position i
    merkle_root = merkle_tree.root
    merkle_proof = merkle_tree.prove(i)   # EPHEMERAL_TREE_DEPTH × 32 bytes

    # Construct the witness
    witness = rlp([y_parity, r, s, merkle_root, merkle_proof])

    # Build the authorization
    tx.authorizations = [[ROLE_SENDER, SCHEME_EPHEMERAL_K1, witness]]

    return tx
```

##### Verification and Address Derivation

```python
def verify_ephemeral_k1(tx):
    auth = tx.authorizations[0]
    assert auth.role_id == ROLE_SENDER
    assert auth.scheme_id == SCHEME_EPHEMERAL_K1

    y_parity, r, s, merkle_root, merkle_proof = rlp_decode(auth.witness)

    # 1. Address binding — the Merkle root must match the sender address
    derived_address = keccak256(SCHEME_EPHEMERAL_K1 || merkle_root)[12:]
    assert derived_address == tx.sender

    # 2. Recover public key from ECDSA signature
    msg = sender_signing_hash(tx)
    pubkey = ecrecover(msg, y_parity, r, s)

    # 3. Merkle membership — pubkey hash must be the leaf at position nonce
    leaf = keccak256(pubkey)
    assert verify_merkle_proof(merkle_root, merkle_proof, leaf, index=tx.nonce)

    # 4. Standard s-value check (EIP-2)
    assert s <= secp256k1n // 2

    return derived_address
```

The Merkle proof verification uses a standard binary Keccak-256 Merkle tree. `verify_merkle_proof` checks that hashing the leaf with the provided sibling path from position `index` produces `merkle_root`.

##### Key Material Summary

| Secret | Location | On-chain exposure |
| --- | --- | --- |
| [BIP 39] seed | User's device only | Never |
| `sk_i` (ephemeral private key) | Derived on-the-fly for nonce `i` | Never (public key exposed for exactly one transaction) |
| `merkle_root` | Encoded in the address, carried in witness | Fully public by design |
| `merkle_tree` | User's device (or recomputable from seed) | Per-transaction proof is public |

[BIP 39]: https://github.com/bitcoin/bips/blob/69a63f629f4c27b249882b4e0db6af516f1bcea9/bip-0039.mediawiki
##### Why This Is Quantum-Safe

After transaction at nonce `i`, the attacker observes `pk_i` (recoverable from the ECDSA signature). A quantum computer running Shor's algorithm can derive `sk_i` from `pk_i`. However, `sk_i` is now useless: the next valid transaction requires nonce `i+1`, which requires a Merkle proof for leaf `i+1`. To forge that transaction, the attacker needs `sk_{i+1}`, which requires `pk_{i+1}`, which requires inverting `keccak256(pk_{i+1})` from the Merkle leaf — a preimage attack on Keccak-256. Grover's algorithm provides a quadratic speedup on brute-force preimage search but Keccak-256 retains 128-bit security against Grover's, which is computationally infeasible.

The security assumption is therefore: Keccak-256 preimage resistance, not the hardness of the discrete logarithm problem.

Scheme gas surcharge: **5,000 gas**.

### Extensions

Extensions attach optional typed protocol features to the transaction without minting a new outer transaction type.

Each extension is encoded as:

```text
extension = [extension_id, extension_payload]
```

Rules:

* `extensions` MUST be unique by `extension_id`
* unknown `extension_id` is invalid
* extension payloads are fully committed by the sender signing hash
* extension processing is flat and non-recursive

This EIP defines two initial extensions.

#### Blob Extension (`EXT_BLOB = 0x01`)

Extension payload:

```text
rlp([max_fee_per_blob_gas, blob_versioned_hashes])
```

| Field                   | Type            | Description                           |
| ----------------------- | --------------- | ------------------------------------- |
| `max_fee_per_blob_gas`  | `uint256`       | Per-blob gas cap                      |
| `blob_versioned_hashes` | `List[bytes32]` | Versioned hashes for referenced blobs |

This extension carries the transaction-local blob fields of [EIP-4844](./eip-4844.md) under a typed extension instead of requiring a dedicated top-level blob transaction family. [EIP-4844](./eip-4844.md) defines these as `max_fee_per_blob_gas` and `blob_versioned_hashes`, and blob transactions there also forbid `to = nil`; this extension preserves those transaction-local semantics. The sidecar format, blob fee lane, and block-level blob accounting remain those of [EIP-4844](./eip-4844.md).

Additional rules:

* if `EXT_BLOB` is present, `to` MUST NOT be `null`
* `blob_versioned_hashes` MUST be non-empty
* blob validity, fee charging, and inclusion rules follow [EIP-4844](./eip-4844.md)

#### Set-Code Extension (`EXT_SET_CODE = 0x02`)

Extension payload:

```text
rlp([authorization_list])
```

Where each authorization item is:

```text
set_code_authorization = [chain_id, delegate_address, nonce, scheme_id, witness]
```

This extension carries [EIP-7702](./eip-7702.md)-style pre-execution set-code authorizations. All processing rules, gas constants, and refund behavior follow [EIP-7702](./eip-7702.md). The differences from [EIP-7702](./eip-7702.md) are:

* `(y_parity, r, s)` is replaced by `(scheme_id, witness)`, making authorizations scheme-agile
* `scheme_id` is included in the authorization message hash: `keccak256(SET_CODE_AUTH_MAGIC || rlp([chain_id, delegate_address, nonce, scheme_id]))`
* authority address derivation uses the same scheme-specific rules as top-level sender authorization
* no inherited `access_list` intrinsic charge (the base envelope has no `access_list`)

If `EXT_SET_CODE` is present, `authorization_list` MUST be non-empty.

##### Set-Code Gas Accounting

Relative to [EIP-7702](./eip-7702.md), the gas accounting delta is only envelope-level:

* this extension charges `25000` per authorization exactly as [EIP-7702](./eip-7702.md) does
* this extension refunds `12500` for non-empty `authority` exactly as [EIP-7702](./eip-7702.md) does
* unlike [EIP-7702](./eip-7702.md), there is no inherited access-list intrinsic charge because `SchemedTransaction` has no base `access_list`

The set-code authorization gas constants and refund behavior are otherwise identical to [EIP-7702](./eip-7702.md).

The intrinsic gas for a `SchemedTransaction` follows the decomposed model of [EIP-2780](./eip-2780.md) and the calldata floor of [EIP-7976](./eip-7976.md):

```text
intrinsic_gas =
    TX_BASE_COST
    + calldata_gas(data)
    + sender_scheme_gas_surcharge(sender_authorization)
    + extension_intrinsic_gas(extensions)
```

Where `TX_BASE_COST` is the decomposed base cost from [EIP-2780](./eip-2780.md) (replacing the legacy flat 21,000) and `calldata_gas` follows the uniform per-byte floor of [EIP-7976](./eip-7976.md).

The sender scheme surcharge replaces the `ECRECOVER` component of the [EIP-2780](./eip-2780.md) base cost. For secp256k1, the cost is equivalent. For other schemes, the surcharge reflects the verification cost and witness size:

| Scheme               | Surcharge |
| -------------------- | --------- |
| `SCHEME_SECP256K1`   | 0         |
| `SCHEME_EPHEMERAL_K1`| 5,000     |

Extension-specific charging rules are:

* `EXT_BLOB` reuses the blob fee lane and blob accounting of [EIP-4844](./eip-4844.md)
* `EXT_SET_CODE` adds `25000 * len(authorization_list)` intrinsic gas and refunds `12500` for each successfully processed non-empty authority

The overhead of a non-secp256k1 sender scheme relative to a standard ECDSA transaction is:

```text
scheme_overhead = calldata_cost(scheme_witness) - calldata_cost(ecdsa_witness) + scheme_surcharge
```

Where `ecdsa_witness` is the 65-byte secp256k1 `(y_parity, r, s)` witness and `calldata_cost` follows the [EIP-7976](./eip-7976.md) uniform floor (64 gas/byte). For ephemeral secp256k1 (737-byte witness including Merkle root and proof), the calldata overhead is `(737 - 65) * 64 = 43,008 gas` plus the 5,000 gas surcharge; verification is a standard ecrecover plus `EPHEMERAL_TREE_DEPTH` Keccak-256 hashes for the Merkle proof.

### Transaction Validation

A node validating a `SchemedTransaction` MUST perform the following checks in order:

1. **Type check**

   * First byte is `0x05`.

2. **RLP decode**

   * Decode the payload according to the field list above.

3. **Chain ID**

   * `chain_id` matches the node's chain.

4. **Authorization structure**

   * `authorizations` contains exactly one `ROLE_SENDER`.
   * Unknown `role_id` is invalid.
   * Unknown `scheme_id` is invalid.

5. **Extension structure**

   * `extensions` contains no duplicate `extension_id`.
   * Unknown `extension_id` is invalid.
   * Each extension payload is statelessly well-formed.

6. **Sender verification**

   * Compute `sender_signing_hash(tx)`.
   * Verify or recover the sender public key using the sender authorization scheme.
   * For `SCHEME_EPHEMERAL_K1`: verify that the Merkle root in the witness matches the sender address, recover the public key, and verify the Merkle proof at leaf index `tx.nonce`.
   * Derive the sender address.

7. **Nonce and balance**

   * Sender account nonce matches `tx.nonce`.
   * Sender has sufficient balance for transaction execution and all extension-specific fee lanes.

8. **Pre-execution extension processing**

   * Apply stateless and fee-lane checks for `EXT_BLOB`.
   * Apply set-code authorizations for `EXT_SET_CODE`.

9. **Intrinsic gas**

   * Charge base intrinsic gas, calldata cost, sender scheme surcharge, and extension-specific intrinsic charges.

10. **Execute**

* Execute the normal call/create payload using `to`, `value`, and `data`.

### Receipt

The [EIP-2718](./eip-2718.md) `ReceiptPayload` for this transaction is:

```text
rlp([status, cumulative_transaction_gas_used, logs_bloom, logs])
```

Identical to [EIP-1559](./eip-1559.md), [EIP-4844](./eip-4844.md), and [EIP-7702](./eip-7702.md).

## Rationale

### Why a single outer transaction type?

A single new transaction type is still needed because the transaction body itself changes. The point of this EIP is not to avoid adding one new outer type - it is to avoid adding a new outer type for every future combination of features.

### Why make scheme agility an authorization capability?

Signature scheme choice determines how the sender proves control of the transaction. That is an authorization concern, not a payload family. Defining scheme agility as an authorization capability means future signature schemes only register:

* a `scheme_id`
* a witness format
* verification or recovery logic
* address derivation
* gas pricing

They do not need to redefine the outer transaction envelope.

### Why flat extensions instead of nested transactions?

Composing whole existing payloads inside a new transaction preserves the inheritance tree this EIP is trying to remove. The cleaner model is:

* one fresh canonical base transaction
* one execution payload
* orthogonal typed attachments

This yields:

* plain secp256k1 transaction = base + sender auth(k1)
* ephemeral quantum-safe transaction = base + sender auth(ephemeral k1)
* blob transaction = base + sender auth(...) + blob extension
* set-code transaction = base + sender auth(...) + set-code extension
* ephemeral k1 + blobs + set-code = base + sender auth(ephemeral k1) + blob extension + set-code extension

No new outer type is needed for any of those combinations.

### Why no access list in the base type?

Transaction-level access lists are being deprecated. Any protocol benefit they provided has been superseded by block-level access lists ([EIP-7928](./eip-7928.md)), and [EIP-7981](./eip-7981.md) increases their cost to reflect their diminished utility. This EIP omits `access_list` from the base transaction entirely rather than carrying forward a deprecated field. Similarly, a frame extension as proposed in [EIP-8141](./eip-8141.md) could be added as a new `extension_id` to support nested execution frames within the same transaction envelope.

### Why preserve the legacy secp256k1 address?

For `SCHEME_SECP256K1`, this EIP intentionally preserves Ethereum's existing `keccak256(pubkey)[12:]` address derivation. That avoids creating a second address for the same secp256k1 key and lets current EOAs use the new transaction format without on-chain migration.

### Why hash `scheme_id` into non-secp256k1 addresses?

For non-secp256k1 schemes, `keccak256(scheme_id || pubkey)[12:]` or `keccak256(scheme_id || merkle_root)[12:]` provides address domain separation from secp256k1 and from each other. Future schemes (P256/passkeys, Falcon-512, etc.) added via new `scheme_id` values will inherit this separation automatically.

### Why include an ephemeral secp256k1 scheme?

The ephemeral secp256k1 scheme provides an immediately deployable quantum-safe alternative that reuses existing ECDSA infrastructure, with no new cryptographic primitives.

The security model shifts from "the signature scheme is quantum-resistant" to "each key is used exactly once, so recovering it is useless." This relies only on Keccak-256 preimage resistance (128-bit security against Grover's algorithm), not on any new cryptographic assumption.

The ephemeral scheme is stateless at the protocol level: the Merkle root is embedded in the sender address and carried in every witness. No new account fields, no storage writes, no contract deployment. The account nonce, already enforced by the protocol, serves as the Merkle leaf index. This makes it the lightest-weight quantum migration path available.

Users can start with `SCHEME_EPHEMERAL_K1` for immediate quantum safety and later migrate to a future post-quantum scheme as those mature — potentially using `EXT_SET_CODE` to delegate their ephemeral account to a contract that bridges the transition.

### Why spell out the set-code extension instead of inheriting [EIP-7702](./eip-7702.md) by reference?

Because set-code authorizations now participate in a scheme-agile transaction model, each authorization in the list carries its own `(scheme_id, witness)` pair. This means different authorizations within the same transaction can use different schemes. [EIP-7702](./eip-7702.md) hardcodes `(y_parity, r, s)` which limits set-code to secp256k1 only. The exact signed payload and exact gas accounting must therefore be explicit. This EIP spells out:

* the exact authorization message hash
* the exact per-tuple processing order
* the exact intrinsic and refund accounting
* the exact deltas relative to [EIP-7702](./eip-7702.md)

The only semantic changes are:

* `scheme_id` is added to the signed set-code authorization payload
* `(y_parity, r, s)` is replaced by `(scheme_id, witness)`
* base transaction access-list intrinsic gas is absent because the base envelope has no `access_list`

Everything else intentionally stays aligned with [EIP-7702](./eip-7702.md).

## Backwards Compatibility

* A `SchemedTransaction` using `SCHEME_SECP256K1` produces the same sender address and the same execution semantics as a normal [EIP-1559](./eip-1559.md) transaction, but it uses a distinct typed envelope and signing hash.
* Existing EOAs can migrate to `SchemedTransaction` without changing address when they continue using secp256k1.
* Contracts see the derived sender address through `msg.sender` and `tx.origin` regardless of which authorization scheme was used.
* A user who migrates from secp256k1 to ephemeral secp256k1 will have a new address, because the ephemeral address is derived from the Merkle root rather than a single public key.
* Blob and set-code semantics remain those of [EIP-4844](./eip-4844.md) and [EIP-7702](./eip-7702.md), but are attached as extensions rather than as separate top-level transaction families.

<!-- TODO

## Test Cases

...

-->
## Security Considerations

### Address collision across schemes

For secp256k1, this EIP deliberately preserves Ethereum's existing address derivation. For all other schemes, `keccak256(scheme_id || pubkey)[12:]` or `keccak256(scheme_id || merkle_root)[12:]` provides domain separation from secp256k1 and from each other. A collision would require a preimage attack on Keccak-256 across distinct inputs, which is computationally infeasible.

### Unknown capability handling

Unknown `scheme_id`, `role_id`, or `extension_id` values are invalid. Clients MUST reject them rather than ignore them. Silent acceptance of unknown capabilities would create consensus and wallet-safety hazards.

### Flat composition reduces validation complexity

This EIP allows multiple orthogonal capabilities, but only one execution payload. It intentionally forbids recursive transaction composition. That avoids drifting into frame-transaction validation complexity, where mempool validation may require richer execution-aware processing before inclusion.

### Quantum migration timing

Any secp256k1 address whose public key has already been revealed on-chain remains vulnerable once ECDSA can be broken. This EIP enables proactive migration to `SCHEME_EPHEMERAL_K1`.

Users of `SCHEME_EPHEMERAL_K1` are protected against retrospective key recovery: even after a quantum computer exists, previously used ephemeral keys are useless because the nonce has advanced. However, the mempool exposure window remains (see below).

### Mempool exposure for ephemeral secp256k1

While a `SCHEME_EPHEMERAL_K1` transaction is pending in the mempool, the current signing public key `pk_i` is visible in the witness. A quantum attacker who can run Shor's algorithm within a single block time could recover `sk_i` and submit a competing transaction at the same nonce. This requires breaking ECDSA within seconds, which is far beyond near-term quantum capabilities. Mitigations include private mempools and L2s with shorter inclusion latencies.

### Ephemeral key exhaustion

A `SCHEME_EPHEMERAL_K1` account with tree depth `EPHEMERAL_TREE_DEPTH = 20` supports `2^20` (approximately 1,048,576) transactions. This is more than sufficient for any individual EOA. If exhaustion approaches, the user should migrate funds to a new ephemeral account (new seed, new Merkle root, new address) or transition to a post-quantum scheme.

### Large witness DoS

Ephemeral secp256k1 witnesses are larger than standard ECDSA witnesses (737 bytes vs 65 bytes). The sender surcharge exists to avoid systematic under-pricing of bandwidth and storage costs. Extensions with large payloads must likewise carry their own appropriate pricing.

### Set-code non-rollback

As with [EIP-7702](./eip-7702.md), processed set-code authorizations are not rolled back if the later execution phase reverts or otherwise fails. Wallets and users MUST treat set-code authorization as a state change that can persist even when the call payload does not succeed.

### Downgrade attacks

A future attacker who can forge secp256k1 signatures could target addresses that continue to authorize transactions with `SCHEME_SECP256K1`. This is not introduced by this EIP. It is the pre-existing quantum threat. Users concerned about it SHOULD migrate to `SCHEME_EPHEMERAL_K1`.

### Keccak-256 and post-quantum security margin

Address derivation, signing hashes, and ephemeral key Merkle trees all rely on Keccak-256. While Keccak is not broken by Shor's algorithm, Grover's algorithm reduces its effective security margin from 256 bits to 128 bits for preimage resistance. For the ephemeral scheme, this 128-bit margin is the primary security parameter — it is what prevents an attacker from recovering a future key from its Merkle leaf. This remains adequate for the foreseeable future, but a later fully post-quantum Ethereum may wish to revisit the hash choice for signing and address derivation. This EIP does not require such a change.

## Copyright

Copyright and related rights waived via [CC0](../LICENSE.md).
