Mempool Encryption Mechanics: A Review of Ethereum Improvement Proposals 8105 and 8184

  • Wallet address: 0xf523737b27dB9fE56f500c52695770ee6248274e
  • Pseudonym: crownghoul
  • Role: Independent spec-level Ethereum protocol researcher

**

Note: I find it particularly important to address this review as not just for a bounty submission, but also as a proper open-source beacon so that other security researchers scrolling across Ethereum forums online can actually grep it, understand the threat models, and contribute. I am not assuming the readers’ basic familiarity with mempool encryption, so I have also included an early explanation of the fundamentals.

**

Encrypted Mempools on Ethereum:

Abstract

Public mempools expose pending transactions to visibility-based exploitation, allowing searchers and builders to extract value via front-running and sandwich attacks. This has been a persistent problem across Ethereum’s history. This review examines EIP-8105 and EIP-8184, two protocol-level proposals that introduce mempool payload encryption. By analyzing their cryptographic orchestration, key-provider mechanics, and execution pipelines, I evaluate how each proposal mitigates MEV extraction, identify specification-level inconsistencies and theoretically derived vulnerabilities, and discuss edge cases relevant to real-world deployment.


Table of Contents

  1. The shared problem
  2. Working principles
    • 2.1 EIP-8105 — Universal Enshrined Encrypted Mempool
    • 2.2 EIP-8184 — LUCID
  3. Methodology and scope
  4. Notation and terminology
  5. Findings — EIP-8105 Normative Patch Set
    • Patch A — bind decrypted output to a submission-time commitment
    • Patch B — protocol-checked key-ID namespacing and cross-envelope ciphertext binding
    • Patch C — bind key messages to the block hash at the protocol level
    • Patch D — scale the PTC validation gas ceiling per registered scheme
    • Patch E — decrypted-transaction gas must count toward the inclusion block’s gas limit
    • Patch F — add a signature_id byte to the envelope for forward compatibility with EIP-8141
    • New finding — normative text contradicts the “same-slot execution” marketing claim
  6. Findings — EIP-8184 (LUCID) Supplementary Review
    • Correction — the “full gas-limit charging” critique is already substantially addressed
    • Finding LUCID-1 — the non-reveal penalty is not what the Rationale says it is
    • Candidate issues investigated and ruled out
  7. Cross-cutting findings — applicable to both EIPs
    • Metadata privacy is out of scope for both proposals, and neither says so
    • Provider/publisher trust is a strong, not weak, trust assumption
  8. Summary of findings and severity assessment
  9. References

1. The shared problem

Right now, broadcasting a transaction to the public mempool exposes its contents (calldata, recipient, value) before it’s ordered into a block. This lets:

  • Searchers/builders front-run and sandwich — see your DEX trade, insert trades around it, extract value.
  • Builders/relays censor in real time — filter transactions based on what they say or who sent them.
  • Both of these effects push users toward private RPCs / private order flow, which centralizes power in a handful of trusted builders and starves the public mempool (today one builder reportedly does ~50% of blocks).

The fix both EIPs pursue is this: hide transaction contents until after ordering is fixed, then reveal and execute. This is “commit before reveal,” implemented as an encrypted transaction whose plaintext only appears once its position in the chain can no longer be gamed.

A key piece of context I discovered and deem important to add here, because it reframes this whole comparison: these aren’t really two competing proposals anymore. EIP-8105’s own author (Jannik Luhn, Shutter) publicly withdrew it as a Hegotá headliner in Feb 2026 and threw the team’s full support behind LUCID (EIP-8184), while keeping 8105 open just for discussion. So the more accurate way to picture these proposals is: 8105 was the first design, LUCID (8184) iterated on it, and now the field has mostly consolidated around LUCID. Both proposals nonetheless remain live, independently reviewable specification documents, and both are treated as such throughout this review.


2. Working principles

2.1 EIP-8105 — Universal Enshrined Encrypted Mempool

Core idea: scheme-agnostic key providers plus two new transaction types.

EIP-8105 introduces type 0x05 for encrypted transactions and type 0x06 for decrypted transactions. An on-chain key-provider registry allows any entity to register as a key custodian by exposing custom decryption and validation logic, while declaring trusted peer providers to form a directed trust graph. Trust is defined as reachability in this graph: provider A trusts provider B if and only if a directed path from A to B exists.

A typical transaction execution flow is:

  1. Submission. The sender encrypts the transaction payload using a key supplied by a registered key provider, wrapping it in a type 0x05 transaction containing the chain ID, fee parameters, gas amount, key-provider ID, key ID, and ciphertext. Upfront gas for the envelope (gas_amount) is paid immediately, analogously to EIP-1559.
  2. Block inclusion. Block builders include these encrypted transactions at the tail end of the block payload — after decrypted transactions and after any other plaintext transactions — without prior knowledge of the underlying contents. An ordering constraint additionally requires that if encrypted transaction A is preceded by encrypted transaction B in the block, A and B must either share a key provider or B’s provider must be trusted by A’s provider.
  3. Key revelation. The responsible key provider observes the block and must publish either the decryption key or an explicit withhold notice for every key ID it is referenced by. This may happen immediately upon observing the payload or be delayed to a later point in the slot.
  4. PTC validation. The Payload Timeliness Committee (PTC), extended from EIP-7732 (ePBS), validates the published keys using the registered provider’s validation function, under a hardcoded small gas limit per key, and attests to the presence or absence of a valid key for each encrypted transaction. If valid and timely, the protocol executes the transaction as a type 0x06 decrypted transaction the following block. If keys are withheld or invalid, the corresponding transaction is skipped.

Because the decryption and key-validation functions are registered as arbitrary on-chain EVM bytecode, executed on-chain by the PTC, the protocol places no constraint whatsoever on what cryptographic scheme that bytecode implements — it may be backed by threshold encryption, MPC committees, TEEs, delay encryption, FHE, or, as discussed in Section 5 (Patch A), nothing cryptographic at all. This is the design’s stated “universality”: neutrality toward encryption technology, at the cost of pushing essentially all correctness guarantees for a given provider onto that provider’s own registered implementation rather than the protocol itself.

Gas provisioning for the encrypted transaction envelope is separated from gas provisioning for the eventual decrypted execution: the envelope consumes gas_amount against the block in which it is included, while the corresponding decrypted transaction, executed one block later, draws on a gas limit derived from gas_amount minus overhead, but — as the current normative text stands — does not count against the gas limit of the block in which it executes (see Patch E).

Key-provider incentives are explicitly left out of the base protocol. Providers may be compensated via off-chain agreements with builders, per-transaction user payments, or may operate as public goods; they may voluntarily submit to off-chain slashing arrangements for unjustified key withholding, but no such mechanism is enshrined.

2.2 EIP-8184 — LUCID

Core idea: commit-reveal via FOCIL inclusion lists, with a priced top-of-block (ToB) auction and a one-slot execution delay.

A sealed transaction (ST) pairs a signed ST ticket — a visible, EIP-2718-typed transaction that charges the sender, binds a key_publisher, and specifies a maximum ToB fee — with a ciphertext envelope, which remains hidden until the corresponding decryption key is released. The plaintext transaction (PT) that the ciphertext decrypts to may have a different sender than the ST ticket itself, since the ticket only needs to authenticate the charge, not the eventual on-chain actor. Senders encrypt to a key publisher following that publisher’s off-protocol instructions, or arrange trustless self-decryption.

The flow, spanning roughly two slots, is:

  1. Propagation. Before the FOCIL attester deadline of slot n, includers propagate inclusion lists (ILs) that may incorporate STs and ST bundles alongside ordinary plaintext transactions. STs can be bundled together if every ST ticket in the bundle shares the same key_publisher, who signs the bundle to authenticate its composition and order.
  2. Commitment. Once builders know which ILs and keys (released the previous slot) they must adhere to, they cast an extended ExecutionPayloadBid containing ST-commitments — hashes of the STs/bundles they intend to include, together with a builder-declared executable bitfield and gas_obligation, ordered by descending ToB fee (commitment_tob_fee), tie-broken by descending gas_obligation and then ascending commitment_root. The proposer includes the winning bid in the beacon block for slot n.
  3. Key release. Each key publisher observes the ST-commitments in the beacon block, confirms its own commitment’s declared gas_obligation is correct and that the aggregate gas_obligation across all commitments fits within tob_gas_limit, and — once confident the beacon block will become canonical — releases the decryption key(s) (LucidKeyMessage) that reveal its STs. Keys are flooded peer-to-peer and must be observed by the next slot’s PTC before a fixed deadline.
  4. Timeliness attestation. The PTC of slot n+1 casts a bitfield vote (LucidKeyTimelinessVote) on which committed keys it observed in time, using a threshold rule over committee votes to determine, per commitment, whether the builder must treat that key as “observed” or “missing.”
  5. Execution. The ST ticket is charged in the block for slot n (base fee, key publication fee, priority fee, and ToB fee are deducted at that point, capped by the sender’s declared maxima). The corresponding decrypted transaction executes top-of-block in the block for slot n+1, run against the header context of block n (not n+1) specifically to prevent the builder from injecting information into its execution that was only available after witnessing other decrypted transactions. Successful decryption triggers a partial refund: unused base fee (relative to actual gas used) and a (TOB_FEE_FRACTION − 1) / TOB_FEE_FRACTION fraction of the posted ToB fee are returned to the sender; the priority fee is never refunded, on the reasoning that the ST occupied bounded block space upon commitment regardless of outcome.

Non-reveal — whether from deliberate withholding or an innocent failure to propagate or release a key in time — is priced through forfeiture of the ToB fee, and, as discussed in Section 6 (Finding LUCID-1), of considerably more than just the ToB fee under the current mechanism. A max_preceding_commitments field lets each sender cap how many earlier, still-unrevealed commitments may execute ahead of them, trading protection from probabilistic front-running against a higher required ToB fee to secure an early position. LUCID additionally requires EIP-7805 (FOCIL) for its inclusion-list machinery, in addition to the ePBS foundation (EIP-7732) both EIPs share.


3. Methodology and scope

I decided to make this review as a specification-level audit: it examines the normative text of both EIPs as published on eips.ethereum.org (canonical source, ethereum/EIPs master branch, both fetched 2026-07-25), cross-referenced against the associated pre-EIP research discussions on ethresear.ch, the live implementation-readiness and bounty-feedback threads on Ethereum Magicians, and independent, non-EIP-specific security literature on encrypted mempools as a general design class (zkSecurity’s May 2026 treatment of encrypted-mempool security invariants, and a16z crypto’s July 2025 systematic survey of technical and economic limitations). The latter two sources were used specifically to check whether general, previously-documented failure classes for this category of design — ciphertext-context binding, metadata leakage, and the strong-vs-weak trust-assumption distinction for decryption committees — had concrete, EIP-specific instances that the EIP text itself does not address; one of them (Patch B) did. Every author statements from forum threads were used to disambiguate or corroborate ambiguous normative language, and are quoted directly rather than paraphrased wherever relied upon. No client implementation, testnet deployment, or executable proof-of-concept was produced or run against either specification; all findings below are derived from close reading of the text itself, tracing field definitions and validity conditions across sections to check internal consistency, cross-referencing against documented general failure modes in the wider literature, and constructing concrete adversarial or edge-case scenarios by hand against the stated rules.

My findings are presented in the same drop-in-diff convention throughout: quoted current text, a proposed replacement adoptable without further design work, and a rationale explaining the underlying defect and its consequence. Two categories of content are distinguished: original findings developed independently in the course of this review, and one section (§6, EIP-8184) that was deliberately scoped to avoid duplicating an existing, independently authored community revision covering key-timeliness threshold ambiguity, censorship-resistance exclusion/placement inversion, recovery-payload reordering across scheduling blocks, the executable/ordering fixpoint definition, top-of-block tie-break grinding, and DEM nonce reuse under ticket replacement. That revision is referenced descriptively at the relevant point below rather than reproduced.

4. Notation and terminology

Term Meaning
PTC Payload Timeliness Committee (EIP-7732/ePBS)
FOCIL Fork-Choice Enforced Inclusion Lists (EIP-7805)
IL Inclusion list
ST Sealed transaction (EIP-8184)
PT Plaintext transaction — the decrypted content of an ST
ToB Top-of-block
tob_fee Fee an ST posts to compete for top-of-block execution priority
gas_obligation Aggregate gas an ST-commitment (or bundle) claims against the ToB gas budget
key_provider / key_publisher 8105 / 8184 terms respectively for the party responsible for releasing a decryption key
Envelope (8105) The plaintext-visible wrapper of an encrypted transaction, carrying fee parameters and ciphertext
Ticket (8184) The plaintext-visible wrapper of a sealed transaction, carrying fee parameters and a ciphertext hash
Commital (scheme property) An encryption scheme in which the ciphertext binds the decryptor to a single, predetermined plaintext, such that no choice of decryption key can produce an alternative output


Please, continue reading as Part 2 — EIP-8105 Normative Patch Set]

[Here is my part 2 of 3 — continued from above. Part 1 already covered the shared problem, working principles for both EIPs, methodology, and terminology.]

5. Findings — EIP-8105 Normative Patch Set

Reviewed against eip-8105.md, ethereum/EIPs master, as fetched 2026-07-25. Format follows the drop-in-diff convention: quoted current text → proposed replacement → rationale. Each patch is adoptable as-is by an author with no further design work.

Method note, since it is the actual finding underneath four of the five patches: three separate security properties this EIP relies on — output integrity, key-ID namespacing, and reorg/replay safety — are each described in prose as things a key provider “should” or “can” implement, but none of the three is checked by the protocol itself. All three failure modes below are instances of the same root cause: the registry accepts arbitrary bytecode for decrypt/verify, and the specification never requires that bytecode to satisfy the property the surrounding Rationale and Security Considerations text assumes it has.


Patch A — bind decrypted output to a submission-time commitment (closes unrestricted decrypt() output)

Current text (“Key Provider Registry”):

Registration requires specifying a contract with a decryption and a key validation function, each of which accept a key ID and a key message as byte strings.

Current text (“Block Structure”):

A decrypted transaction must not be included if and only if any of the following conditions is met:

  • the key is attested as missing
  • decryption fails
  • decryption does not yield a structurally valid decrypted transaction
  • the decrypted transaction’s envelope_signer does not match the signer of the corresponding encrypted transaction
  • including the decrypted transaction would result in an invalid block (e.g., because of a nonce mismatch)

Nowhere in these checks — or anywhere else in the spec — is the decrypted output required to match anything fixed at submission time. The only binding constraint is that envelope_signer matches, which the submitter trivially controls since it’s their own transaction.

Proposed replacement. Add a payload_commitment field to the encrypted transaction envelope:

0x05 || rlp([chain_id, envelope_nonce, max_priority_fee_per_gas, max_fee_per_gas,
             gas_amount, key_provider_id, key_id, payload_commitment,
             encrypted_payload, envelope_signature_y_parity,
             envelope_signature_r, envelope_signature_s])

where payload_commitment = keccak256(rlp([nonce, destination, amount, data, access_list])) — i.e., a commitment to the unsigned fields of the decrypted transaction, computed and fixed by the sender before submission (they hold the plaintext, having just encrypted it). Add a sixth exclusion condition to the Block Structure list:

  • keccak256(rlp([decrypted.nonce, decrypted.destination, decrypted.amount, decrypted.data, decrypted.access_list])) != payload_commitment

Rationale. Because decrypt is arbitrary registered bytecode, nothing stops a provider from registering decrypt(_, key, _) = key and verify(...) = true. Concretely: an attacker registers such a provider, submits an encrypted transaction using it, and — because the envelope only fixes gas parameters, not content — waits until the PTC attestation window (per the ethresear.ch discussion of this EIP, roughly the 25%–75% slot marks) to observe the rest of the block’s now-plaintext content. They then publish key = D for any transaction bytes D they choose, signed as required by envelope_signer (which they control, being their own transaction). verify() returns true unconditionally; decrypt() returns D unconditionally; the only remaining checks are structural well-formedness and signer match, both trivially satisfiable. Total cost: one envelope’s gas fee. Result: a fully retroactive, perfect-information transaction insertion — strictly more powerful than a malicious builder’s ordering leverage today, since this attacker gets to see the finished block before choosing content, not just influence its construction. This is explicitly not the “one bit of reveal/withhold influence” the Security Considerations section describes and bounds as low-impact; it’s unbounded content choice, and the spec’s own severity analysis doesn’t cover it because that analysis assumes a “commital” decryption scheme without requiring one.

Binding the decrypted output to a commitment fixed before block ordering is known closes this regardless of what bytecode is registered: to satisfy payload_commitment, the attacker must know the exact plaintext before the commitment is made, i.e., before they’ve seen any of the state they wanted to condition on. This is exactly the property LUCID enforces generically via reveal_commitment = hash_tree_root(RevealCommitmentPreimage(...)) (EIP-8184 §Sealed transactions) — EIP-8105 currently has no equivalent, and should adopt the same pattern rather than relying on each registered scheme to independently be “commital,” which is asserted informally in the ethresear.ch thread (jannikluhn, Feb 5 2026: “reasonable key providers will use encryption functions that are ‘commital’”) but never required.


Patch B — protocol-checked key-ID namespacing and cross-envelope ciphertext binding

Current text (“Key ID Front Running”):

Key providers can protect their users from this attack. One possible strategy to do so is “namespacing” key IDs: Providers only release keys for key IDs that are prefixed with the envelope signer’s address and withhold all others.

This is presented as a strategy a provider may adopt, not a protocol requirement. The registry performs no check that a provider’s verify/decrypt implements it. On its own, this is already a real gap (see the original front-running scenario the EIP’s own Security Considerations describes). But tracing the consequence of the gap further reveals something considerably more severe than front-running: a way to force premature, protocol-independent disclosure of any pending encrypted transaction still sitting in the public P2P mempool, before it is ever included, executed, or even attempted — against any key provider, including a perfectly honest one running sound, correctly implemented cryptography.

The attack. Independent security research on encrypted mempools as a general class (zkSecurity, “Encrypted Mempools: Security Beyond Encryption,” May 2026) identifies this exact failure mode in the abstract: “the ciphertext needs to be authenticated with the sender’s context: sender identity, signing key or authentication material, chain ID, epoch, and any other public fields that define where the transaction is valid… an attacker may copy another user’s encrypted transaction, wrap it in their own transaction, and sign it with their own key. Even if execution later rejects it, the copied ciphertext may still be decrypted, leaking the original user’s intent.” EIP-8105’s specific mechanics realize this precisely:

  1. A victim broadcasts an encrypted (type 0x05) transaction. Before block inclusion, this envelope — including its key_provider_id, key_id, and encrypted_payload — is public: it propagates through the P2P mempool exactly like any pending transaction, visible to every observer.
  2. An attacker copies these three fields verbatim (key_provider_id, key_id, encrypted_payload) into a new envelope of their own construction, signed with the attacker’s own key (envelope_signer = attacker, envelope_nonce = attacker’s own). This is trivial: nothing binds the ciphertext or the key ID to the specific envelope that originally carried them.
  3. The attacker gets their copy included in a block — straightforward, since they can simply outbid the victim’s own gas_amount/priority fee to be included first, or included at all if the victim’s transaction never lands.
  4. The key provider observes the block, sees key_id referenced, and — per “Key Provider Responsibilities,” which triggers release per key_id observed in an included block, not per specific envelope — publishes the corresponding decryption key. This step requires no misbehavior; a fully honest provider running textbook-correct cryptography does exactly this.
  5. The decrypted transaction from the attacker’s copy fails the existing “envelope_signer must match” check (§ Block Structure) and is correctly excluded from execution. But this check runs after the key has already been published. The key is not scoped to the attacker’s envelope — it is the decryption key for key_id, full stop, and it decrypts the original, identical ciphertext exactly as well as the copy. The victim’s plaintext transaction is now public, and derivable by anyone, independent of whether the victim’s own original transaction is ever included, executed, or even attempted.

This defeats the core “hidden until ordering is fixed” guarantee that is the entire premise of the EIP — for any transaction an attacker notices in the pending pool, not just ones that get included. It requires no malicious key provider (distinguishing it from Patch A), no control over block building beyond ordinary fee competition, and works identically against every registered scheme, since it exploits a protocol-level binding gap rather than anything about a specific provider’s implementation.

Why namespacing, properly scoped, closes this. The natural fix is the same namespacing mechanism the EIP already gestures at, but enforced at a different point and with a materially different binding target than the original text describes. The original namespacing idea (§ Key ID Front Running) binds key_id to the signer’s identity to stop a second, distinct transaction from claiming the same key_id. That is necessary but not sufficient here: the attacker in this attack is not minting a new key_id — they are copying the victim’s key_id, which is already correctly prefixed by the victim’s address. The fix has to reject the attacker’s envelope at inclusion time, before any key is ever requested or released — not merely gate the key-release step, by which point the key is already public.

Proposed replacement. Make namespacing a structural, protocol-checked field, enforced as a transaction-validity condition on the encrypted transaction itself, not merely a key-release-time check:

Every key_id MUST be constructed as key_id = keccak256(envelope_signer || envelope_nonce) || key_id_suffix, where key_id_suffix is provider- and scheme-specific. An encrypted (type 0x05) transaction is invalid, and must not be included in a block, if its key_id does not begin with keccak256(envelope_signer || envelope_nonce) for its own envelope_signer and envelope_nonce. This check is performed by the protocol at transaction-validity time, independent of and prior to any registered provider logic, and prior to any key ever being requested or released for that key_id.

Binding to (envelope_signer, envelope_nonce) rather than envelope_signer alone is deliberate: binding to the signer’s address alone would still let the same sender’s own future transaction collide with an earlier pending key_id of theirs; binding the nonce in closes that residual gap along with the cross-sender copy attack. This is a strictly stronger, differently-targeted requirement than the version originally proposed for the ordinary front-running case, and it should replace rather than supplement that weaker framing — it closes both the originally-described front-running scenario and the more severe premature-disclosure attack above, since an attacker’s copied envelope can never satisfy a key-ID derivation tied to the attacker’s own, different (envelope_signer, envelope_nonce) pair, and the check now runs before any key request can reach a provider at all.

Rationale, restated. As written, whether an attacker can either front-run a key_id or force a victim’s pending, uncommitted transaction into premature public disclosure depends entirely on whether the specific provider a victim happens to use has voluntarily implemented namespacing — and even a provider that has does not stop the attack above, because the existing framing only ever describes namespacing as something a provider chooses to apply when deciding whether to release a key, not as a check on whether an encrypted transaction is valid at all. There is no on-chain signal distinguishing a provider that does the former from one that doesn’t, and the premature-disclosure attack succeeds against providers that do nothing wrong whatsoever. Moving the check into protocol-level, pre-inclusion transaction validity (performed once, generically, before any registered verify call and before any key request is ever issued) converts this from “hope every provider gets it right” to “provably impossible for every registered provider,” at the cost of a fixed key_id derivation format — a minor interface constraint against what is, on inspection, one of the more severe attack classes documented against this design.


Patch C — bind key messages to the block hash at the protocol level

Current text (“Key Provider Responsibilities”):

For each of those, they must publish either the corresponding decryption key or a key withhold notice. The corresponding message references the beacon block hash to prevent replays in a future slot.

Current text (“Reorgs”):

Decryption keys are published before the corresponding encrypted transactions are finalized. Thus, in the event of a chain reorg, a transaction may become public even though it is not necessarily included in the chain. However, since the decryption key message includes the block hash, it can be invalidated by the key validation function.

The reorg-safety claim rests entirely on “it can be invalidated by the key validation function” — that function is, again, arbitrary registered bytecode. Nothing requires it to actually check the referenced block hash against the current canonical block before treating a key as valid.

Proposed replacement. Move the block-hash check out of the registered verify function and into protocol-level key-message validation, analogous to Patch B:

A key message is a tuple (key_provider_id, key_id, key, beacon_block_hash). Prior to invoking the registered validation function, the protocol MUST reject any key message whose beacon_block_hash does not match the canonical beacon block hash of the slot in which the referenced encrypted transaction was included. The registered verify(key_provider_id, key_id, key) function is invoked only on key messages that pass this check, and receives key without the block-hash component (already validated).

Rationale. This is the same root problem as Patch B applied to a different property: the Security Considerations section’s reorg-safety argument is written as though block-hash binding is a protocol guarantee, but as specified it’s a per-provider implementation choice. A provider (malicious, or simply buggy — this doesn’t require intent) that omits the block-hash check in its registered verify reintroduces exactly the replay risk the Reorgs section claims is handled: a key revealed for a transaction in a reorged-out block could be replayed to unlock the same key_id in a competing fork, converting the reorg from an accidental disclosure into an exploitable replay depending entirely on that specific provider’s bytecode. As with Patch B, moving this into generic protocol-level validation makes the guarantee uniform across every registered provider instead of contingent on independent correct reimplementation by each one.


Patch D — scale the PTC validation gas ceiling per registered scheme, set at registration time

Current text (“Additional Payload Timeliness Committee Responsibilities”):

They must validate these keys using the validation function specified in the registry contract, using a hardcoded small gas limit per key.

Proposed replacement.

Each key provider specifies, at registration time, a verification_gas_limit for its verify function, bonded by a stake proportional to verification_gas_limit * MAX_ENCRYPTED_TXS_PER_BLOCK. The PTC charges each key’s validation against its provider’s registered verification_gas_limit rather than a single protocol-wide constant. A provider whose verify function exceeds its own registered limit at attestation time has its keys treated as invalid for that slot (equivalent to “missing”), and repeated overruns are slashable against the bond.

Rationale. “A hardcoded small gas limit” is not specified anywhere in the EIP — no number is given, and the number chosen effectively decides which cryptographic schemes are viable in practice before a single line of registry code exists. A limit sized for ECDSA-style verification may be infeasible for some threshold-signature or FHE-adjacent validation routines the EIP’s own Motivation section explicitly says it wants to support (“threshold encryption, MPC committees, TEEs, delay encryption, or FHE schemes”); a limit sized generously enough for the heaviest scheme imposes a per-key PTC execution cost on every validator for every encrypted transaction, scaling with adoption. A single global constant forces a one-size-fits-all tradeoff between scheme flexibility and validator load that the “universal, encryption-agnostic” framing of the EIP is specifically trying to avoid making. Per-provider registered limits, bonded so a provider can’t grief the PTC by registering a cheap limit and then deploying expensive bytecode, let heavier schemes participate without taxing every validator on every block regardless of whether they’re used.


Patch E — decrypted-transaction gas must count toward the inclusion block’s gas limit

Current text (“Transaction Execution”, Specification):

Decrypted transactions are executed as a regular transaction under the execution context of the inclusion block (e.g., for block.slot and block.coinbase). The gas limit of the transaction is given by the corresponding encrypted transaction’s gas_amount minus the cost of the encrypted transaction as well as decryption. However, the consumed gas does not count towards the block gas limit and no fee is paid.

Current text (“Transaction Execution”, Rationale):

All gas is consumed in the block in which the encrypted transaction is included and none in the block in which the decrypted transaction is executed. This is for incentive compatibility: The builder of one block should not be able to sell block space of the next.

Nothing elsewhere in the spec exempts an encrypted transaction’s own gas from counting toward its block’s gas limit — only the decrypted side, executed one block later, gets this exemption.

Proposed replacement.

Decrypted transactions are executed as a regular transaction under the execution context of the inclusion block. The gas limit of the transaction is given by the corresponding encrypted transaction’s gas_amount minus the cost of the encrypted transaction as well as decryption. No additional fee is charged for this gas (it was already paid for at envelope inclusion in the previous block), but it MUST count towards the current block’s gas limit for the purpose of bounding total per-block execution work. A block is invalid if gas_used_by_newly_included_transactions + gas_used_by_inherited_decrypted_transactions exceeds the protocol gas limit. Builders MUST account for the aggregate gas_amount inherited from the previous block’s encrypted transactions when selecting how much new transaction gas to additionally include.

Rationale. As written, block N’s encrypted-transaction envelopes count toward N’s own gas limit G (ordinary EIP-1559-style accounting, no stated exception), so the aggregate gas_amount committed in block N is bounded by G. But the corresponding decrypted transactions, executed in block N+1, are explicitly exempted from N+1’s gas limit. In the worst case — block N saturated with encrypted transactions, aggregate gas_amount ≈ G — block N+1 must execute up to G of inherited decrypted-transaction computation in addition to its own full G of newly-included transactions: up to 2G of real EVM execution work while the protocol’s own gas accounting, and every downstream system built on the assumption that gas limit bounds per-block computation (sync-time budgets, node hardware provisioning, light-client heuristics, block-explorer “gas used” figures), only registers G.

This is not a one-off attack requiring an adversary to force a pathological block — ordinary, honest, fee-paying adoption of the EIP’s own headline feature is sufficient to produce it, and it recurs every block for as long as encrypted-transaction volume stays high. The gap between declared and actual computational cost scales directly with the EIP’s own adoption success: the more users encrypt transactions (the explicit goal), the larger the permanent, protocol-invisible tax on real per-block execution time becomes. The block gas limit is Ethereum’s foundational per-block DoS bound; a mechanism that lets real computation exceed it by up to 100% while remaining invisible to gas accounting is a regression of that invariant, and it isn’t addressed anywhere in the existing Security Considerations section (Trusted Key Providers, Reorgs, Key ID Front Running, Key Provider-Child Builder Collusion, and Envelope/Payload Stripping Attacks all address adversarial-trust or front-running concerns; none address resource bounds).

The rationale given for excluding this gas from N+1’s accounting — preventing “the builder of one block from selling block space of the next” — is a legitimate economic concern, but it conflates two separable properties: who gets paid for the gas and whether the gas counts against the block’s execution-time budget. The proposed replacement preserves the existing fee treatment (no new charge in N+1, already paid in N) while restoring the gas limit’s role as a hard cap on aggregate per-block computation, which is the property actually load-bearing for DoS resistance.


Patch F — add a signature_id byte to the envelope for forward compatibility with EIP-8141

Current text (“Transaction Types”):

0x05 || rlp([chain_id, envelope_nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_amount,
            key_provider_id, key_id, encrypted_payload,
            envelope_signature_y_parity, envelope_signature_r, envelope_signature_s])

The envelope’s signature is ECDSA-only, hardcoded into the RLP tuple as a fixed (y_parity, r, s) triple, with no field selecting or versioning the signature scheme.

Proposed replacement.

0x05 || rlp([chain_id, envelope_nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_amount,
            key_provider_id, key_id, payload_commitment, encrypted_payload,
            signature_id, signature_bytes])

signature_id: uint8 selects the signature scheme; signature_id = 0x01 (ECDSA) is the only currently valid value and is interpreted as the existing (y_parity, r, s) triple for backward compatibility. signature_bytes is bounded by MAX_SIGNATURE_SIZE and its interpretation is determined entirely by signature_id.

(This also folds in the payload_commitment field from Patch A, since both changes touch the same envelope structure — an author adopting both patches together only needs to land one RLP layout change, not two.)

Rationale. EIP-8184 (LUCID) already carries exactly this abstraction in its ST ticket: a signature_id: uint8 field, currently fixed to EC_DSA_TYPE == 0x01, explicitly reserved so that signature_id = FRAME_TX_TYPE can later indicate the ticket has no standalone signature and instead appears inside an enclosing EIP-8141 frame transaction (§ Rationale / Alternative specifications / Frame transaction integration). This means LUCID’s STs are FRAME-ready by construction — the migration is a one-byte value change, requiring no further protocol upgrade to the ST ticket format itself. EIP-8105’s envelope has no analogous field. Migrating it to FRAME later requires redefining the RLP tuple outright — a coordinated hard fork touching every wallet, every key provider, every RPC endpoint, and every block explorer that parses type 0x05 transactions, all at once. Given that EIP-8141 is explicitly anticipated as Ethereum’s path to post-quantum-safe signatures, and that both EIPs sit in the same “encrypted mempool” design space competing for the same Hegotá slot, leaving one of the two hardcoded to non-PQ-safe ECDSA while the other is already migration-ready is an avoidable, asymmetric deployment liability for 8105 specifically. The fix is minimal: one byte and a length-prefixed signature field, matching a pattern the sibling EIP has already validated as sufficient.

(Credit: this gap was independently identified in a public comparative submission to the same feedback process this review is being submitted to — 0xwans, “Comparative Analysis: EIP-8105 vs EIP-8184 (LUCID),” Ethereum Magicians, June 2026. The finding is corroborated and reformulated here in the drop-in-diff format used throughout this review, integrated with Patch A’s envelope changes, rather than reproduced verbatim.)


New finding — the spec’s own normative text contradicts the “same-slot execution” claim used to sell this EIP over LUCID

This one isn’t a vulnerability — it’s a documentation/marketing inconsistency worth flagging because it’s load-bearing for how this EIP gets compared to LUCID.

Normative text (“Block Structure”):

Each decrypted transaction must correspond to an encrypted transaction in the previous block.

Author statement, same claim, ethresear.ch thread (jannikluhn, Feb 5 2026, replying to a direct question about whether encrypted-transaction state changes land in the same block’s state root):

“Yes, at inclusion time the transactions are still encrypted. They therefore can only affect the state root of the next block… Depending on how you see it, encrypted transactions are only executed in the following block.”

Conflicting claim, Shutter blog FAQ (the EIP’s own promotional material, “Introducing EIP-8105”):

“Encrypted txs: execution happens in the same block if keys arrive on time, with <1 slot overhead for key publication and PTC attestation.”

These aren’t reconcilable as written. The normative spec text says a decrypted transaction corresponds to an encrypted transaction in the previous block — meaning the envelope is included in block N, and execution of the decrypted payload happens in block N+1, once the PTC has attested to key availability for block N’s encrypted transactions. The EIP’s own author confirms this reading directly on the research thread. But the FAQ — the document most likely to actually be quoted in Hegotá headliner comparisons, including the “<1 slot overhead” framing that’s repeatedly used as 8105’s key latency advantage over LUCID’s explicit N+1 design — describes same-block execution.

Why this matters for feedback, not just accuracy: Now, if the normative reading (next-block execution) is correct, then 8105 and LUCID have the same execution-latency profile — one slot of delay between commitment and execution — and the “same-slot, <1 slot overhead” framing is simply wrong, not just imprecise. That removes what is currently treated in comparative analysis of the two EIPs as 8105’s single clearest advantage over LUCID in the execution-quality tradeoff. If instead same-block execution is intended and the normative text is the one that’s wrong, then the “previous block” language in Block Structure needs to be corrected, and the mechanism by which same-block execution would actually work (PTC attestation is specified to land as late as 75% into the slot — leaving execution to happen in the remaining 25%, which is a much tighter claim than “<1 slot overhead” suggests) needs to be spelled out, since nothing else in the spec currently describes a same-block execution path.

Proposed resolution. Either: (a) amend the FAQ/promotional material to state next-block execution explicitly and retire the “<1 slot overhead” framing in any headliner comparison against LUCID, or (b) if same-block execution is genuinely intended, add normative text describing how a decrypted payload executes within the same block as its envelope given the PTC attestation deadline, since “the previous block” in the current Block Structure section says the opposite and is the only normative statement on the question.

This should be resolved before further comparative claims treat “same-slot execution” as an established, uncontested advantage of 8105 over LUCID.



[Continued in next reply: Part 3 — EIP-8184 (LUCID) findings, cross-cutting findings, severity summary, and references]

[Part 3 of 3 — continued from above.]

6. Findings — EIP-8184 (LUCID) Supplementary Review

Reviewed against eip-8184.md, ethereum/EIPs master, as fetched 2026-07-25. This section is deliberately scoped to avoid duplicating an existing, independently authored community revision, which addresses: key-timeliness threshold ambiguity between the “missing” and “observed” predicates, an exclusion-vs-placement inversion in how max_preceding_commitments interacts with the censorship-resistance guarantee for inclusion-list entries, enforcement of max_preceding_commitments across scheduling blocks during payload-rejection recovery, a circularity in the definition of the executable/gas_obligation/ordering fixpoint, grinding of the commitment_root tie-break to defeat intended backrun adjacency, and DEM nonce reuse under ticket replacement. Each finding below was checked against that revision’s scope before inclusion, to avoid overlap.


Correction — the “full gas-limit charging” critique is already substantially addressed in the current normative text

A common line of criticism in comparative discussion of LUCID holds that it charges senders for their full declared gas_limit with no reconciliation against actual usage, making it impractical for anything beyond simple transfers. Re-reading the current “Block processing” section shows this is only half true, and worth correcting before it propagates further.

Current text:

Upon successful decryption, the calldata cost of the decrypted transaction is computed using max(len(ciphertext_envelope), len(plaintext_tx.data)) bytes. The PT is then executed as a regular transaction, except that it bypasses the ordinary EIP-1559 fee-cap validation and no gas fee is charged, since the fee was already prepaid by the ST ticket. The gas_used is referred to as dual_gas_used… The unused gas, previously charged to the parent_ticket according to the base fee of the previous block, is then returned to the sender, together with the parent_tob_fee reserved for the penalty:

parent_ticket.signer.balance += parent.base_fee_per_gas * (parent_ticket.gas_limit - dual_gas_used) + parent_tob_fee * (TOB_FEE_FRACTION - 1) // TOB_FEE_FRACTION

The priority_fee is not reconciled with gas_used since the ST still took up bounded space upon commitment.

So: base_fee is refunded for unused gas on successful decryption, and (F-1)/F of tob_fee is refunded too. Only priority_fee is charged flat regardless of actual usage, with an explicit, reasoned justification (space reservation). This means the current draft has already moved past the version of the critique commonly repeated in comparative write-ups — it is not simply “pay for your full gas limit, no refund,” it is “pay for your full gas limit, get back unused base fee and most of the ToB fee if you decrypt successfully, keep paying flat for priority fee.” Any feedback submitted going forward should reflect the current text, not the earlier state of the public discussion.

This correction is also what led directly to the finding below — reading the refund code closely to verify exactly what it covers is what exposed the gap in what it doesn’t cover.


Finding LUCID-1 — the non-reveal penalty is not what the Rationale says it is

Current text (“Probabilistic front-running”, Rationale, point 4):

ST-commitments are ordered by ToB fee, a fraction of which is returned upon reveal. Selective reveal is therefore priced both in expectation and ex post. Concretely: (a) … it must also consistently pay the part of the ToB fee that is not returned upon reveal – tob_fee / TOB_FEE_FRACTION. (b) … it must pay the higher penalty for every bit of information it communicates upon non-reveal – tob_fee.

This is stated and restated throughout the Rationale — and underlies the entire “Competition for the ToB” economic model, in which $F$, $B$, $V_a$, $V_e$, and $f(m)$ are all defined purely in terms of tob_fee — as though tob_fee is the quantity at risk on non-reveal.

Current text (“Block processing”):

Upon successful decryption, … [refund logic quoted above, gated entirely behind successful decryption]

There is no refund logic anywhere in the spec for the case where decryption does not succeed. ticket_fee = base_fee + key_publication_fee + priority_fee + tob_fee is deducted in full at ticket-charging time, in block $n$, unconditionally. The only refund path — unused base_fee and (F-1)/F of tob_fee — executes exclusively “upon successful decryption.” If a key is withheld, an ST’s bytes fail to propagate in time, or a bundle’s gas_obligation turns out to exceed tob_gas_limit, none of that refund logic runs. The sender loses all four fee components — not just tob_fee, but base_fee (for the full gas_limit, despite zero computation ever occurring), key_publication_fee, and priority_fee too.

Why this is a real gap, not just an imprecise summary. The Rationale’s quantitative model treats tob_fee as the whole priced stake — the sender’s exposure the model reasons about when deciding how much ToB fee to post, and the entire basis for the $FBf(m)$ separation analysis in “Competition for the ToB.” But the sender’s actual expected loss on non-reveal is ticket_fee, not tob_fee. For an ST with a large gas_limit (a complex, multi-step DeFi transaction — precisely the kind of “autogenous MEV” transaction the Motivation section holds up as LUCID’s flagship use case) and a comparatively modest tob_fee, base_fee can dwarf tob_fee in absolute terms. A sender in that position is exposed to losing far more than the “priced penalty” the Rationale describes, for reasons that may have nothing to do with a key publisher’s strategic withholding decision — an honest key publisher’s infra outage, network propagation delay past the PTC deadline, or a bundle’s peers pushing aggregate gas_obligation over tob_gas_limit, are all indistinguishable in their financial consequence to the sender from deliberate malicious withholding.

This has two concrete downstream effects worth flagging separately:

  1. The economic model in “Competition for the ToB” is incomplete for exactly the users it’s built to reason about. The model asks whether an autogenous-MEV sender can outbid an exogenous-MEV sender via FBf(m), entirely in tob_fee terms. It doesn’t model the sender’s total value-at-risk, which includes the full ticket_fee. A sender with a large, gas-hungry transaction and only a small tob_fee budget is more exposed per unit of tob_fee posted than the model implies, which could bias real usage toward smaller, cheaper transactions — the opposite of the “large repricing trade” example the Motivation section uses to justify the design.
  2. Non-reveal for entirely benign reasons (no malicious key publisher involved) still destroys the sender’s full payment, with no mechanism to distinguish it from adversarial withholding. The “Key publisher liability for non-reveal” section’s sponsor-ST workaround addresses the key-publisher-absorbs-the-loss case, but it’s opt-in and bundle-specific — a self-decrypting sender, or a sender in a bundle without a sponsor arrangement, has no such protection, and forfeits everything for what may simply be bad luck.

Proposed resolution. Either:

(a) Extend the refund logic to always execute for base_fee and key_publication_fee (return them to the sender regardless of decryption outcome, since neither is conceptually part of the “priced withholding penalty” the Rationale describes — the penalty should isolate to tob_fee alone, consistent with how the Rationale actually frames it), reserving full or partial tob_fee forfeiture as the sole non-reveal penalty; or

(b) if flat forfeiture of the entire ticket_fee on any non-reveal is the intended design (consistent with the existing “the ST still took up bounded space upon commitment” reasoning already used to justify non-reconciliation of priority_fee, extended to the total-failure case), then the Rationale text and the “Competition for the ToB” model should be corrected to state the sender’s true expected loss as ticket_fee, not tob_fee, and the $FBf(m)$ separation analysis should be redone against total value-at-risk rather than tob_fee alone — since this changes the real answer to “can an autogenous-MEV sender afford to use the encrypted mempool,” which is the central question the Motivation section is trying to answer in LUCID’s favor.

Either resolution is preferable to the current state, where the mechanism (total forfeiture on any failure) and the advertised economic model (penalty = tob_fee) describe two different things, and only the mechanism is normative.


Finding LUCID-2 — the non-reveal penalty falls on the wrong party by default

Finding LUCID-1 establishes that non-reveal forfeits the sender’s full ticket_fee, not merely tob_fee. Tracing who actually bears that forfeiture surfaces a second, independent problem: in the baseline mechanism, it is not the party capable of causing non-reveal who pays it.

Current text (“Block processing”, refund logic, quoted in full above under the Correction):

parent_ticket.signer.balance += parent.base_fee_per_gas * (parent_ticket.gas_limit - dual_gas_used) + parent_tob_fee * (TOB_FEE_FRACTION - 1) // TOB_FEE_FRACTION

Both the initial ticket_fee deduction and any refund apply to ticket.signer — the sender. The key_publisher is a distinct field on the ST ticket, a separate address with no independent stake in that specific ST’s ticket_fee. A key publisher who withholds a decryption key it is responsible for causes the sender’s entire ticket_fee to be forfeited (per Finding LUCID-1), while the publisher itself loses nothing, unless it has voluntarily attached its own sponsor ST to the bundle — the mechanism described in “Key publisher liability for non-reveal” — which is explicitly optional and bundle-specific, not a default protocol requirement.

Why this matters, independent of Finding LUCID-1’s severity point. Even if the Rationale’s economic model were corrected to accurately price the size of the non-reveal penalty at ticket_fee rather than tob_fee (Finding LUCID-1’s proposed resolution (b)), that correction alone does not fix who pays it. A malicious or simply unreliable key publisher operating without a sponsor ST faces a penalty of exactly zero for withholding, regardless of how large the sender’s forfeited ticket_fee is. The entire deterrence argument in “Probabilistic front-running” and “Competition for the ToB” — that selective reveal is “priced both in expectation and ex post” — implicitly assumes the party who decides whether to reveal is the party who bears the cost of not revealing. In the default (non-sponsored) configuration, this assumption is false: the sender, who has no ability to influence the reveal decision once their key is in the publisher’s hands, is the one who pays for it.

This connects directly to the key-withholding-as-embedded-optionality analysis independently raised in this same feedback process (Favor|Bonux, “Key-Withholding Optionality as a Structural MEV Risk in EIP-8105 and LUCID,” Shutter Forum, July 2026), which models a publisher’s reveal/withhold decision as a rational option priced against tob_fee. That analysis, read against the ticket-charging mechanism directly, understates the problem in a specific way: it treats the publisher as the party facing the F × (TOB_FEE_FRACTION − 1)/TOB_FEE_FRACTION cost of avoiding withholding, when in the unsponsored default case the publisher faces no cost at all — the option is not merely underpriced, as that analysis argues, it is priced against an account that never pays it.

Proposed resolution. Make the sponsor-ST mechanism, or an equivalent bond posted by the key_publisher address itself, mandatory rather than optional for any ST or bundle whose key_publisher differs from ticket.signer — i.e., whenever the party who can cause non-reveal is not the party who bears its cost by default. Concretely:

Every ST or bundle MUST include, alongside its ordinary commitments, a bond posted by key_publisher and forfeited under the same non-reveal conditions that apply to the bundle’s own ticket_fee. A key publisher declining to post this bond MAY only be designated for STs where key_publisher == ticket.signer (i.e., self-decryption, where the party bearing the cost and the party controlling reveal are already the same).

This does not change the size of the deterrent modeled in either Finding LUCID-1 or the Bonux analysis — it changes whose balance it is deducted from, which is a precondition for either of those analyses’ pricing arguments to actually constrain the party the mechanism is meant to constrain.


Candidate issues investigated and ruled out

For completeness, and to make clear that the absence of further findings reflects deliberate investigation rather than an incomplete pass, two additional candidate issues were examined in depth and ruled out:

EIP-2935 / EIP-4788 deferred history-registry writes. The “Block processing” section defers the addition of the parent block hash (EIP-2935) and parent beacon root (EIP-4788) to their respective history registries until after the last ST has executed, rather than at the top of the block as in ordinary post-Prague processing. On first inspection this looks like a gap — decrypted transactions executing early in block n+1 cannot query the just-added parent hash via the history mechanism. On closer analysis this is correct as designed, not a flaw: it preserves the ordinary EVM invariant that a block cannot observe its own hash while executing, applied consistently to STs, which are specified to execute “against the header of the block in which their ST ticket was committed to” — i.e., logically still inside block n, which by definition cannot see its own (block n’s) hash. Regular transactions in block n+1, which execute after the deferred write completes, see the parent hash exactly as expected. No inconsistency survives close reading.

Calldata-cost underpayment via max(len(ciphertext_envelope), len(plaintext_tx.data)). The formula for calldata gas cost at decryption time takes the larger of the ciphertext envelope’s byte length and the plaintext transaction data’s byte length, raising the question of whether a sender could construct a small ciphertext envelope that decrypts to a disproportionately large plaintext, underpaying for the actual data cost. In practice this does not yield an exploitable gap: ChaCha20-Poly1305 ciphertext length is deterministically plaintext_length + 16 bytes (the authentication tag), and the ciphertext envelope further encodes the full RLP-encoded plaintext transaction — nonce, gas fields, and signature in addition to calldata — meaning len(ciphertext_envelope) is essentially always the binding term in the max() expression in practice, not len(plaintext_tx.data) alone.

A third candidate — a potential time-of-check-to-time-of-use race between the executable bitfield computed at bid-commitment time and the ticket-charging validation performed at payload-release time — was also considered, but ruled out as a distinct issue: st_tickets are always processed first within the execution payload by construction, so there is no window in which an intervening state change from another transaction in the same block could invalidate a bid-time executable determination before charging occurs. This risk is, in any case, already subsumed by the correctness fix required for the executable/ordering fixpoint circularity referenced in the scope note at the top of this section.


7. Cross-cutting findings — applicable to both EIPs

Metadata privacy is out of scope for both proposals, and neither says so

Both EIPs protect the content of a transaction — destination, calldata, value — until reveal. Neither protects the metadata surrounding it, and this is not a minor omission: it is a well-documented, structural limitation of encrypted mempools as a design class, not specific to either EIP’s implementation choices, and it is currently undocumented in either spec’s Security Considerations section.

In EIP-8105, the encrypted transaction envelope leaves gas_amount, max_priority_fee_per_gas, max_fee_per_gas, key_provider_id, and the sending address (envelope_signer, recoverable from the envelope signature) entirely in plaintext. In EIP-8184, the ST ticket leaves max_priority_fee_per_gas, max_fee_per_gas, gas_limit, max_tob_fee, key_publisher, and the ticket’s sending address equally exposed. Both designs make this choice deliberately and for good reason — a16z crypto’s systematic treatment of encrypted-mempool design space (“On the limits of encrypted mempools,” July 2025) explains why encrypting fee data specifically is close to untenable: “If transaction fee payment data is encrypted, then anybody can broadcast malformed encrypted transactions that will be ordered but have no ability to pay fees… [and] builders use fees to build the most profitable block and establish the current market price for onchain resources. Encrypting this data disrupts this process.” Both EIPs correctly avoid this trap. But the same source is equally clear that what remains exposed is a real attack surface: “transaction size… does not hide the size of the encrypted plaintext… certain transaction types might have a specific size which leaks information,” and gas budgets specifically, since “interacting with a specific DEX might require a specific amount of gas which is identifiable.” A sophisticated searcher does not need certainty to profit from speculative MEV — a reasonable probability that a given gas_limit/gas_amount and destination-adjacent metadata correspond to, say, a specific DEX’s swap function is enough to justify a speculative counter-transaction, independent of anything either EIP’s cryptography protects.

This is not a design flaw to be patched — both EIPs’ authors almost certainly know this and made a reasonable, deliberate tradeoff. It is a documentation gap: neither EIP’s Security Considerations section currently states plainly that metadata-based speculative MEV (transaction size, gas parameters, sender address, broadcast timing) remains possible against fully-encrypted, correctly-functioning content. This matters because the entire motivation section of both EIPs frames the problem as “front-running and sandwich attacks,” which content encryption genuinely solves — but a reader could reasonably come away believing the broader MEV problem is solved, when only the content-visibility component of it is. zkSecurity’s general treatment of the design space makes the same point directly: “networks should clearly document what encrypted mempools do and do not protect. Users need to understand the capability and limitations of the feature so they do not treat it as full transaction privacy.”

Proposed resolution. Both EIPs should add an explicit subsection to Security Considerations — “Metadata privacy is out of scope” or similar — stating plainly that sender address, gas parameters, transaction size, and broadcast timing remain observable, and that speculative MEV strategies conditioned on this metadata are not mitigated by either design. This costs nothing technically and directly prevents the misapprehension that encrypted-mempool adoption is a complete MEV solution — a misapprehension that, if left uncorrected, is likely to surface as a credibility problem for whichever EIP ships first once the gap becomes visible in production.

Provider/publisher trust is a strong, not weak, trust assumption

Both EIPs’ accountability models for key providers (8105) and key publishers (8184) — discussed at several points above (Patches B/C, Correction, Finding LUCID-1) — ultimately rest on the same underlying structural weakness, which is worth naming explicitly and precisely rather than leaving implicit across several separate findings. a16z crypto’s treatment draws a sharp and useful distinction here: “Consensus failures like forking the chain are publicly visible (called a weak trust assumption), whereas a malicious committee privately decrypting transactions early will generate no public evidence and hence such an attack cannot be detected or slashed (a strong trust assumption). Thus while, from the outside, the security assumptions for consensus and an encryption committee might look the same, practical considerations make the assumption that a committee won’t collude more tenuous.”

This distinction sharpens what is otherwise easy to wave away as “both EIPs are honest that provider incentives are off-chain, so it’s a known limitation.” It is not merely unenshrined — it is a strictly weaker category of security guarantee than the consensus-safety assumption Ethereum otherwise relies on for everything else in the protocol, because a key provider or publisher choosing to privately decrypt early, or share plaintext with a favored searcher before public reveal, produces no on-chain evidence whatsoever. There is nothing for a PTC vote, a slashing contract, or an observer to ever detect, in contrast to equivocation (which both EIPs do detect and vellichorlabs’s LUCID revision addresses directly for the key-timeliness case) or withholding (which both EIPs’ PTC bitfields do record). Early private disclosure is a fundamentally different, undetectable failure mode from either equivocation or withholding, and neither EIP’s Security Considerations section currently distinguishes it from the cases they do address. This does not have a clean protocol-level fix — it is closer to a fundamental limitation of the committee/provider model itself than a bug — but both EIPs should say so explicitly, rather than implicitly folding it into the same “reputation-based, off-chain” language used for withholding, which readers may reasonably (and incorrectly) assume is equally detectable after the fact.


8. Summary of findings and severity assessment

# EIP Finding Category Severity
A 8105 Unbound decrypt() output permits retroactive, perfect-information transaction content selection Access control / commitment integrity Critical
B 8105 Namespacing is unenforced; the consequence extends beyond front-running to attacker-forced premature disclosure of any pending encrypted transaction via ciphertext copying, against any provider, malicious or not Ciphertext-context binding / premature disclosure Critical
C 8105 Reorg/replay safety depends on unenforced provider bytecode behavior Replay protection gap High
D 8105 PTC validation gas ceiling unspecified, pre-selects viable schemes Implementation / scalability ambiguity Medium
E 8105 Decrypted-transaction gas exempted from destination block’s gas limit Resource-bound / DoS regression High
F 8105 No signature_id field; migrating to EIP-8141 (FRAME) requires a coordinated hard fork, unlike LUCID’s already-migration-ready ST ticket Implementation complexity / deployment risk Medium
— 8105 Normative “previous block” text contradicts FAQ’s “same-slot” marketing claim Documentation inconsistency Medium (high downstream impact on comparative claims)
— 8184 Prior “full gas-limit charging” critique is stale relative to current text Correction N/A
LUCID-1 8184 Non-reveal forfeits entire ticket_fee, not just tob_fee as the Rationale states Economic model / documentation inconsistency High
LUCID-2 8184 Non-reveal penalty is charged to the sender, not the key publisher, unless a bond is voluntarily posted — the party who decides is not the party who pays, by default Incentive design / accountability gap High
— Both Metadata privacy (size, gas parameters, sender, timing) is unaddressed and undocumented as out of scope Documentation gap Medium
— Both Provider/publisher early-disclosure is an undetectable (“strong”) trust assumption, distinct from and weaker than the equivocation/withholding cases both EIPs do handle Trust model documentation gap Medium

Findings A and B on EIP-8105 are now assessed as the two highest-priority items, both critical: A because it substantively defeats the commit-before-reveal guarantee for any provider whose bytecode is not independently, voluntarily commital, and B because — once traced to its full consequence via the general ciphertext-context-binding failure class documented in independent encrypted-mempool security research — it permits forcing premature public disclosure of any observed pending transaction against any provider, including fully honest ones, which is a strictly broader attack surface than A’s (A requires a malicious provider; B does not). E remains high-priority because it represents a protocol-invisible regression of Ethereum’s foundational per-block computational bound, scaling directly with the feature’s own adoption. Findings LUCID-1 and LUCID-2 on EIP-8184 are assessed as high priority together, since they compound: LUCID-1 establishes that the true non-reveal loss is the full ticket_fee, not tob_fee as advertised, and LUCID-2 establishes that this loss, however large, is borne entirely by the sender rather than the publisher whenever no voluntary bond is posted — meaning the deterrence argument in “Competition for the ToB” does not currently constrain the party actually capable of causing non-reveal. Both need resolving together before the economic claims in that section can be relied upon. The two cross-cutting findings are lower urgency but zero-cost to address (documentation only) and directly relevant to how either EIP’s privacy guarantees get represented to end users and wallet developers.

9. References

  • EIP-8105: Universal Enshrined Encrypted Mempool. EIP-8105: Universal Enshrined Encrypted Mempool
  • EIP-8184: LUCID encrypted mempool. EIP-8184: LUCID encrypted mempool
  • EIP-7732: Enshrined Proposer-Builder Separation (ePBS).
  • EIP-7805: Fork-Choice Enforced Inclusion Lists (FOCIL).
  • EIP-8141: Frame Transactions.
  • Shutter Network. “Introducing the Universal Enshrined Encrypted Mempool EIP.” https://blog.shutter.network/introducing-the-universal-enshrined-encrypted-mempool-eip/
  • Ethereum Magicians. “Hegotá Headliner Proposal: EIP-8105 Universal Enshrined Encrypted Mempool (EEM).” https://ethereum-magicians.org/t/hegota-headliner-proposal-eip-8105-universal-enshrined-encrypted-mempool-eem/27448
  • Ethereum Magicians. “Hegotá Headliner: LUCID Encrypted Mempool.” https://ethereum-magicians.org/t/hegota-headliner-lucid-encrypted-mempool/27658
  • Ethereum Magicians. “Encrypt The Mempool! — Provide feedback on the draft EIPs (8105 & 8184),” bounty submission thread, including 0xwans, “Comparative Analysis: EIP-8105 vs EIP-8184 (LUCID)” (June 2026), credited in Patch F. https://ethereum-magicians.org/t/encrypt-the-mempool-provide-feedback-on-the-draft-eips-8105-8184/28804
  • ethresear.ch. “Universal Enshrined Encrypted Mempool EIP” discussion thread.
  • ethresear.ch. “LUCID: Encrypted mempool with distributed payload propagation” discussion thread.
  • Gong, Suneal (zkSecurity). “Encrypted Mempools: Security Beyond Encryption.” ZK/SEC Quarterly, May 2026. https://blog.zksecurity.xyz/posts/encrypted-mempool-security/
  • Garimidi, Pranav; Bonneau, Joseph; Heimbach, Lioba (a16z crypto). “On the limits of encrypted mempools.” July 2025. https://a16zcrypto.com/posts/article/limits-encrypted-mempools/
  • Favor|Bonux. “Key-Withholding Optionality as a Structural MEV Risk in EIP-8105 and LUCID: Analysis, Quantification, and Mitigation Proposals.” Shutter Forum, July 2026, credited in Finding LUCID-2. https://shutternetwork.discourse.group/t/key-withholding-optionality-as-a-structural-mev-risk-in-eip-8105-and-lucid-analysis-quantification-and-mitigation-proposals/897