GhostPool: Hiding Identity-Critical Metadata in Encrypted Mempool Admission
Abstract
Encrypted mempools hide transaction contents before inclusion, but they generally do not hide identity-critical admission metadata. In many designs, the admission path still exposes fields such as sender and nonce—or a public envelope signer that serves the same practical role—because these fields are what make dynamic mempool checks possible.
If sender and nonce are hidden without replacement, nodes lose the information needed to evaluate nonce and solvency. Admission becomes blind.
GhostPool replaces public (sender, nonce) admission checks with:
- a root-bound zero-knowledge admission proof for encrypted transactions,
- a ciphertext-to-payload commitment binding,
- and a shared nullifier namespace spanning encrypted and plaintext transactions.
The main construction is stated in the standard account model, where nonce stability gives the clearest correctness argument and the protocol naturally supports the head-of-line nonce. GhostPool leaves network-layer origin and economic metadata such as gas limits and fee parameters unchanged. It is an admission-layer protocol that composes with encrypted-mempool designs such as Shutter-style threshold encryption, multiparty delay encryption, batched threshold encryption for pending-transaction privacy, and recent public-envelope encrypted mempool proposals.
1. Introduction
1.1 Encrypted mempools hide payloads, not admission metadata
Encrypted mempools are now a broad design space rather than a single proposal. Examples include threshold-encrypted mempools, public-envelope encrypted mempools, and academic proposals based on multiparty delay encryption or batched threshold encryption.
Across these approaches, the main objective is usually to hide transaction contents until a protocol-defined decryption point. What generally remains exposed is the admission interface and, with it, identity-critical metadata such as sender and nonce.
That is the layer GhostPool targets.
As long as sender and nonce remain visible, encrypted mempools preserve dynamic admission checks—but also preserve account-level leakage. The current universal enshrined encrypted mempool proposal, for example, keeps a public envelope with its own fee-payment and nonce semantics and does not target user privacy. GhostPool addresses the complementary problem: private admission.
1.2 Validation blindness
A node receiving a transaction must check at least four things:
- Format: envelope structure, field sizes, valid encoding
- Authorization: valid signature from the sender
- Nonce: the transaction targets the sender’s next usable nonce
- Solvency: the account can cover the transaction’s worst-case cost
The first two are static. The latter two are dynamic: they require an account lookup keyed by the sender.
This creates a direct tradeoff:
- If sender and nonce stay visible, nodes preserve dynamic admission checks, but encrypted submissions still leak account-level activity.
- If sender and nonce are hidden without replacement, nodes can no longer perform nonce or solvency checks at all.
I refer to this failure mode as validation blindness.
This is distinct from the better-known mempool DoS literature, which studies admission, eviction, and locking attacks under already-visible transaction identities and prices. GhostPool’s problem is simpler and more fundamental: under private admission, the dynamic checks themselves disappear unless they are cryptographically replaced.
1.3 Protocol statement
GhostPool resolves validation blindness for private head-of-line admission by replacing public (sender, nonce) checks with:
- a root-bound zero-knowledge admission proof,
- a ciphertext binding through a public payload commitment,
- and a shared nullifier namespace that tracks nonce-slot consumption across both encrypted and plaintext transactions.
The protocol is first stated in the standard account model, where the nonce-stability argument is simplest and the tracked slot is the native account nonce. Within that setting, sender and nonce can be removed from the cleartext encrypted-admission path without reintroducing validation blindness.
The protocol deliberately focuses on:
- the head-of-line nonce,
- encrypted-mempool formats that can authenticate a payload commitment for ciphertexts,
- and public fee/gas metadata.
Section 7 discusses broader account models and the remaining metadata that GhostPool does not hide.
2. GhostPool at a glance
For the standard account model, GhostPool relies on a simple monotonicity fact:
If an account’s nonce has not changed since a proof was generated, then its balance could only have stayed the same or increased.
A solvency proof therefore does not need to be regenerated on every new block. It only needs to remain true that the relevant nonce slot has not been consumed.
GhostPool turns the stale-proof problem into a slot-tracking problem by assigning each (account, nonce) pair a deterministic nullifier without exposing the account in the encrypted admission path.
Figure 1. GhostPool replaces public (sender, nonce) admission checks with a root-bound proof plus a slot nullifier, removing sender/nonce from the encrypted admission path without reintroducing validation blindness.
3. Protocol
3.1 Envelope format
A submitted encrypted transaction takes the form of an envelope:
where:
ciphertextis the encrypted payload,payload_commitmentis a public commitment to the hidden payload,- N is the canonical nullifier,
- \pi_{\text{leaf}} is the leaf proof,
ref_rootis the exact state root the proof was generated against,public_metacontains non-private transport and pool-management fields.
In the base construction, public_meta also contains the execution-relevant fields intentionally left in the clear for packing and ordering, such as:
gas_limit,max_fee_per_gas,max_priority_fee_per_gas,- and any expiry or routing hints.
GhostPool does not require the latest state root. It requires an exact root and a bounded freshness rule.
3.2 Leaf proof
The leaf proof \pi_{\text{leaf}} attests to the following without revealing sender or nonce:
- Authorization: the hidden transaction is signed by a valid key corresponding to the hidden account.
- Nonce validity: the account’s on-chain nonce equals the hidden nonce used in the transaction.
- Solvency: the account’s balance covers the transaction’s declared worst-case execution cost, i.e. its value plus a fee bound derived from the public gas and fee fields.
- Public-field consistency: any execution-relevant fields intentionally kept in the clear match the corresponding fields of the hidden transaction.
- Nullifier binding: the public nullifier N is correctly derived from the same hidden key and hidden nonce.
- Payload commitment binding: the hidden transaction commits to the public
payload_commitment. - Anchor binding: all state witnesses are proven against the exact
ref_root.
The proof establishes authorization, nonce validity, solvency, and slot binding against a fixed state root. Freshness and current includability under the latest base fee remain mempool policy decisions evaluated outside the proof.
For Ethereum-style fee semantics, the natural proof statement is a worst-case cost bound using the transaction’s declared fee bound, rather than a claim about current includability at the latest base fee.
3.3 Ciphertext binding
A valid proof is not sufficient by itself. Nodes must also know that the proof refers to the same hidden transaction as the public ciphertext.
GhostPool splits this binding into two parts:
- inside the proof: hidden transaction \rightarrow
payload_commitment - inside the encryption layer:
ciphertext\rightarrowpayload_commitment
The enclosing encrypted-mempool format must therefore authenticate a payload commitment for ciphertexts—for example through associated data, authenticated wrapping, or an equivalent mechanism. GhostPool does not require one specific encryption scheme. It requires this authenticated commitment hook.
This removes the attack where a user proves validity for one hidden transaction while attaching ciphertext for another.
3.4 Nullifier
Each nonce slot is assigned a canonical nullifier:
where sk is the sender secret key and address = \mathsf{Addr}(pk).
GhostPool does not use a plain hash such as H(address \,\|\, nonce), or any deterministic public artifact that an observer can recompute directly from visible state. The design target is slot uniqueness without public enumerability from visible state alone.
The nullifier serves four purposes:
- slot uniqueness: the same
(account, nonce)yields the same N, - unforgeability: without the sender secret key, third parties cannot produce a valid nullifier for that slot,
- non-enumerability from public state: guessing
(address, nonce)is not enough to test a guess against an observed N, - shared slot semantics: the same slot key is used across encrypted and plaintext flows.
At an intuitive level, an observer can derive B_{\mathrm{slot}} from public data but cannot test whether an observed N belongs to that slot without either the sender secret key or a valid public certificate.
HashToCurve should be instantiated as a constant-time hash-to-curve or encode-to-curve method with proper domain separation; see RFC 9380. The protocol-level nullifier is the canonical encoding of the group element N. Implementations may additionally hash it for local indexing.
This construction is adjacent to deterministic public-artifact designs such as PLUME, but GhostPool uses the nullifier specifically as a nonce-slot key for mempool admission.
3.5 Plaintext path
GhostPool does not force plaintext transactions into the encrypted admission circuit.
A plaintext transaction continues to use the ordinary mempool path with visible sender, nonce, and fee fields. The only additional requirement is that it also carry:
- the canonical nullifier N for its visible nonce slot, and
- a lightweight slot certificate \pi_{\text{slot}} proving:
equivalently,
The verifier recovers pk from the ordinary transaction signature, computes B_{\mathrm{slot}} from (address, nonce), and checks \pi_{\text{slot}} as a DLEQ / Chaum–Pedersen relation. This is much lighter than a full leaf proof and uses standard machinery; see RFC 9497.
This is the public certification path for the same nullifier object that encrypted transactions prove inside the leaf circuit. It also gives plaintext and encrypted transactions one shared slot namespace.
3.6 Admission pipeline
When a node receives an encrypted envelope E, it runs checks from cheapest to most expensive:
- Envelope sanity: valid structure, required fields present, size caps respected.
- Nullifier prefilter: check whether N conflicts with an existing pool entry.
- Anchor freshness: verify
ref_rootis canonical and recent enough. - Ciphertext commitment check: verify that the ciphertext authenticates the declared
payload_commitment. - Leaf proof verification: verify \pi_{\text{leaf}}.
- Replacement finalization: if policy allows it, replace the older entry for the same nullifier.
The ordering is chosen to reject malformed or stale objects before proof verification.
4. Shared nullifier namespace
GhostPool’s architectural core is that encrypted and plaintext transactions take different admission paths but converge on one shared slot namespace.
Figure 2. Encrypted and plaintext transactions use different admission checks but converge on one shared nullifier namespace and one spent-nullifier view.
This shared namespace is what makes the nonce-stability argument usable in practice. A pending encrypted proof remains live as long as:
- its reference root is still fresh enough, and
- its nullifier has not entered the spent set.
In deployment, plaintext nullifier artifacts must be available across the reorg horizon so that the spent set remains reconstructible. How those artifacts are persisted is a transport or format choice. The admission logic itself is unchanged.
5. Pool policy
5.1 Requirement
Every transaction that enters the mempool—encrypted or plaintext—must carry a canonical nullifier:
- for encrypted transactions, nullifier correctness is established inside \pi_{\text{leaf}};
- for plaintext transactions, nullifier correctness is established by the ordinary signature path plus \pi_{\text{slot}}.
GhostPool therefore relies on a single slot-tracking invariant:
Any event capable of consuming the tracked nonce slot must be represented in the same slot-consumption view.
In the base construction, this is achieved directly because encrypted and plaintext transactions both participate in the shared nullifier namespace.
5.2 Freshness window
GhostPool accepts an encrypted proof only if its ref_root remains within the last W canonical block roots.
Conceptually, encrypted entries remain pending while:
ref_rootis within the window,- and N \notin \texttt{spent}.
Expiry applies only to encrypted entries. Plaintext entries do not carry root-bound GhostPool leaf proofs.
5.3 Replacement
Replacement is defined over the shared nullifier slot, not over visible sender fields.
If two pool entries carry the same nullifier, they compete for the same underlying (account, nonce) slot. A new entry may replace an older one if local policy allows it.
GhostPool standardizes slot equality through the nullifier. It does not standardize one universal fee-bump rule across plaintext and encrypted flows.
5.4 Reorgs
When the chain reorgs, included transactions in reverted blocks are no longer final, so their nullifiers must move back out of the spent set.
Nodes maintain a per-block nullifier update log. On reorg:
- replay reverted blocks in reverse,
- apply new canonical blocks forward,
- re-evaluate pending encrypted entries whose freshness or spentness changed.
6. Aggregation and propagation
Recursive STARK aggregation is the natural propagation layer for GhostPool when leaf proofs are large.
If encrypted envelopes were propagated naively together with their leaf proofs, both proof bandwidth and network-wide verification work would grow quickly with throughput. The recursive propagation pattern proposed in Recursive-STARK-based bandwidth-efficient mempool addresses this setting: nodes verify fresh objects once, then periodically publish recursive proofs over the valid objects they currently know about.
GhostPool uses that pattern on the encrypted path.
A node that first receives an encrypted envelope verifies its leaf proof once. Then, at every tick, it generates a recursive STARK covering all still-valid encrypted envelopes in its local view and forwards that recursive proof to peers together with any encrypted envelopes that the peer has not yet seen, but without their original leaf proofs.
The recursive proof’s public input is a set descriptor for the covered encrypted envelopes—for example, a bitfield or a list of envelope hashes. The recursive circuit then takes:
- zero or more encrypted envelopes with their leaf proofs,
- zero or more other recursive STARKs of the same type,
- and a discard set,
and proves the validity of the union of all directly supplied envelopes and all recursively imported sets, minus the envelopes that are discarded.
This “union minus discard” structure matches GhostPool well. It allows the aggregate to evolve with the mempool:
- envelopes whose
ref_roothas fallen outside the freshness window can be discarded, - envelopes whose nullifier has entered the spent set can be discarded,
- envelopes replaced by a newer transaction for the same slot can be discarded.
If one node currently has {Tx1, Tx2, Tx3} and another has {Tx2, Tx3, Tx4}, their recursive proofs can be merged into a larger proof covering the union {Tx1, Tx2, Tx3, Tx4}. A builder that receives multiple partially overlapping aggregates can combine them in exactly the same way.
Figure 3. Recursive aggregation merges overlapping encrypted transaction sets into a single proof over their union, with invalidated objects removed through the discard set.
This gives GhostPool two concrete advantages on the encrypted path.
First, it reduces network-wide verification work. A fresh encrypted envelope still needs to be checked once when it first enters the network, but downstream nodes increasingly verify recursive coverage proofs over sets of envelopes rather than re-verifying every leaf proof independently.
Second, it reduces proof propagation overhead. Each encrypted envelope body still needs to propagate through the network, but proof traffic becomes tick-based per peer rather than per envelope. That is the main bandwidth gain of the recursive construction: object data scales with the number of envelopes, while proof overhead scales with the tick rate and peer count.
7. Discussion
7.1 Broader account models
The nonce-stability argument is simplest in the standard account model because outgoing transactions are the mechanism that both consume nonce and reduce balance.
EIP-7702 shows why that simplicity does not survive unchanged once delegated execution paths are introduced. In those settings, native balance can no longer be reasoned about from nonce stability alone, and the tracked slot may be consumed through authorization paths that are not ordinary GhostPool-tracked transactions.
That changes the object that the protocol needs to track. One natural recovery direction is to replace native-balance solvency with an escrow-style solvency object and to broaden slot-consumption tracking accordingly. The admission architecture itself does not change.
7.2 Transaction chains
The base protocol supports only the head-of-line nonce.
If a user wants to queue private transactions for nonces n, n+1, n+2, the later ones are not independently provable against current on-chain state. A naive dependency pointer from n+1 to the nullifier of n would reintroduce linkage.
Private queued transaction chains therefore need another layer, most likely a set-membership or dependency proof over admissible parent nullifiers.
7.3 Economic metadata and fingerprinting
GhostPool hides sender and nonce in the encrypted admission path, but economic metadata remains a meaningful privacy risk. Fee parameters and gas limits can act as strong statistical fingerprints, and they become even more revealing when combined with other observable features such as ciphertext size, timing, and application-specific behavior.
Hiding economic metadata is substantially harder because builders need it for ordering and packing. More importantly, standard cryptographic ideas like ORE or HE do not solve this in a public submission setting. If anyone can produce encryptions or interact with the comparison interface, then small-domain metadata can still be recovered by probing: encrypt guesses, compare outcomes, and infer the underlying value.
Designing fee and gas confidentiality that still works with public submission, builder incentives, and block construction remains an open problem. GhostPool treats it as separate work.
8. Conclusion
Encrypted mempools already have credible designs for hiding transaction contents until inclusion order is fixed. What they generally do not yet provide is a private way to decide whether an encrypted transaction is admissible in the first place, without reintroducing validation blindness.
GhostPool fills that gap.
Within its base scope—head-of-line nonce admission in the standard account model, under encrypted formats that authenticate a payload commitment—GhostPool replaces public (sender, nonce) admission checks with a root-bound ZK proof plus a shared nullifier namespace spanning encrypted and plaintext transactions. This removes identity-critical admission metadata from the cleartext encrypted-admission path while preserving semantic admission checks.
Appendix
Everything below is optional. It makes the proposal easier to implement and review, but can be removed without changing the core narrative.
Appendix A. Notation and parameters
- h: current head block number observed by the node
- W: freshness window (in blocks)
- \mathcal{R}_h: the set of canonical block roots in the window, e.g. \{\texttt{root}[h-W], \dots, \texttt{root}[h]\}
ref_root: exact root used inside \pi_{\text{leaf}}payload_commitment: public commitment to the hidden transaction payload- sk, pk: signing secret/public key
- address = \mathsf{Addr}(pk): account address
- nonce: account nonce
- \mathsf{HashToCurve}(\cdot): domain-separated hash-to-curve or encode-to-curve function
Recommended domain separation inputs for B_{\mathrm{slot}}:
- protocol domain string, e.g.
"ghostpool/nullifier/v1" chainidaddressnonce
Appendix B. Informal proof statements
B.1 Encrypted leaf proof relation
Public inputs
payload_commitment- N
ref_root- public fee and packing fields from
public_meta
Witness
- sk, pk, address, nonce
- hidden transaction fields (
to,value,gas_limit,max_fee_per_gas,max_priority_fee_per_gas, calldata, etc.) - signature material
- account and state witnesses under
ref_root
Statement
The prover shows existence of a witness such that:
- address = \mathsf{Addr}(pk)
- the hidden transaction signature verifies under pk
- \mathsf{nonce}(address;\ ref\_root) = nonce
- \mathsf{balance}(address;\ ref\_root) \ge \texttt{worst_case_cost(hidden_tx)}
- the public gas and fee fields equal the corresponding fields of the hidden transaction
payload_commitment = Commit(hidden_tx)- B_{\mathrm{slot}} = \mathsf{HashToCurve}(\texttt{dst} | \texttt{chainid} | address | nonce)
- N = sk \cdot B_{\mathrm{slot}}
B.2 Plaintext slot certificate relation
Public inputs
- pk (recovered from the ordinary transaction signature)
- B_{\mathrm{slot}} (computed from visible
(address, nonce)) - N
Witness
- sk
Statement
Prove:
This is a standard DLEQ / Chaum–Pedersen statement; see RFC 9497.
Appendix C. Slot certificate details
A standard Chaum–Pedersen proof of equality of discrete logs over a prime-order group works as follows:
- Prover knows sk such that pk = sk \cdot G and N = sk \cdot B.
- Prover samples random r and computes commitments:a_1 = r \cdot G,\qquad a_2 = r \cdot B
- Verifier supplies challenge c.
- Prover responds:z = r + c \cdot sk
- Verifier checks:z \cdot G = a_1 + c \cdot pkandz \cdot B = a_2 + c \cdot N
A Fiat–Shamir transform makes this non-interactive.
Appendix D. Practical notes
-
A natural starting point is W \in [32, 128] blocks.
-
Storage overhead is mainly:
pending_map, bounded by mempool sizespent_set, bounded by the recent chain horizon tracked for recovery and reorg safety
-
The most expensive engineering point is likely the encrypted leaf proof, especially if the implementation keeps secp256k1-style authorization relations inside the proof system.
-
Wallet support may need to expose either:
- direct nullifier-generation support,
- or a generic “prove slot certificate” path compatible with the chosen DLEQ implementation.


