文章提出 GhostPool,用零知识证明、加密绑定和共享 nullifier 命名空间,解决加密 mempool 中 sender 与 nonce 被隐藏后导致的“验证失明”问题。
Encrypted mempools 在包含前会隐藏交易 内容,但通常不会隐藏身份关键的准入元数据。在许多设计中,准入路径仍然会暴露诸如 sender 和 nonce 之类的字段——或者一个承担相同实际角色的公开 envelope signer——因为这些字段正是实现动态 mempool 检查所必需的。
如果 sender 和 nonce 在没有替代方案的情况下被隐藏,节点就会失去评估 nonce 和偿付能力所需的信息。准入会变成盲目的。
GhostPool 用以下机制替代公开的 (sender, nonce) 准入检查:
主构造是在标准 account model 中陈述的,在该模型下,nonce 稳定性给出了最清晰的正确性论证,而协议自然支持 head-of-line nonce。GhostPool 保留 network-layer 的来源和经济元数据,例如 gas limits 和 fee parameters 不变。它是一个准入层协议,可与诸如 Shutter-style threshold encryption、multiparty delay encryption、用于 pending-transaction privacy 的 batched threshold encryption 以及近期的 public-envelope encrypted mempool proposals 等 encrypted-mempool 设计组合使用。
Encrypted mempools 现在是一个广泛的设计空间,而不是单一提案。示例包括 threshold-encrypted mempools、public-envelope encrypted mempools,以及基于 multiparty delay encryption 或 batched threshold encryption 的学术提案。
在这些方法中,主要目标通常是在协议定义的解密点之前隐藏 transaction contents。通常仍然暴露的是 admission interface,以及由此带来的身份关键元数据,如 sender 和 nonce。
这正是 GhostPool 所针对的层。
只要 sender 和 nonce 仍然可见,encrypted mempools 就能保留动态准入检查——但同时也保留了 account-level 泄露。当前的 universal enshrined encrypted mempool proposal 例如,保留了一个拥有自己 fee-payment 和 nonce 语义的公开 envelope,并不针对用户隐私。GhostPool 解决的是互补问题:private admission。
接收交易的节点至少必须检查四件事:
前两项是 static。后两项是 dynamic:它们需要以 sender 为键的账户查询。
这会直接带来一个权衡:
我将这种失效模式称为 validation blindness。
这与更广为人知的 mempool DoS 文献不同,后者研究的是在交易身份和价格已经可见的情况下的准入、驱逐和锁定攻击。GhostPool 的问题更简单也更根本:在 private admission 下,如果不通过密码学方式替换,动态检查本身就会消失。
GhostPool 通过将公开的 (sender, nonce) 检查替换为以下机制,来解决 private head-of-line admission 的 validation blindness:
该协议首先在标准 account model 中陈述,在该模型下,nonce-stability 论证最简单,且被跟踪的 slot 是原生 account nonce。在该设置中,可以从明文的 encrypted-admission path 中移除 sender 和 nonce,而不会重新引入 validation blindness。
该协议刻意聚焦于:
第 7 节讨论了更广泛的 account model,以及 GhostPool 不隐藏的其余元数据。
对于标准 account model,GhostPool 依赖一个简单的单调性事实:
如果一个账户的 nonce 自证明生成以来没有变化,那么它的 balance 只可能保持不变或增加。
因此,偿付能力证明不需要在每个新区块都重新生成。它只需要保持相关 nonce slot 尚未被占用。
GhostPool 通过为每个 (account, nonce) 对分配一个确定性的 nullifier,而不在加密准入路径中暴露账户,把 stale-proof 问题转化为 slot-tracking 问题。

图 1。GhostPool 用一个 root-bound proof 加上一个 slot nullifier 替代公开的 (sender, nonce) 准入检查,从而在不重新引入 validation blindness 的情况下,将 sender/nonce 从加密准入路径中移除。
提交的加密交易采用一个 envelope 的形式:
E = (ciphertext, payload_commitment, N, π_leaf, ref_root, public_meta)
其中:
ciphertext 是加密后的 payload,payload_commitment 是对隐藏 payload 的公开 commitment,N 是 canonical nullifier,π_leaf 是 leaf proof,ref_root 是证明生成时所依据的确切 state root,public_meta 包含非私密的传输和池管理字段。在基础构造中,public_meta 还包含为打包和排序而有意保留明文的执行相关字段,例如:
gas_limit,max_fee_per_gas,max_priority_fee_per_gas,GhostPool 不要求最新 state root。它要求一个确切 root 和一个有界的新鲜度规则。
Leaf proof π_leaf 在不泄露 sender 或 nonce 的情况下证明以下内容:
N 正确地由同一隐藏密钥和隐藏 nonce 导出。 payload_commitment 做出 commitment。 ref_root 上证明的。该证明在固定 state root 上建立授权、nonce 有效性、偿付能力和 slot 绑定。关于最新 base fee 的新鲜性和当前可包含性仍然是由 proof 之外的 mempool policy 决定的。
对于 Ethereum-style fee semantics,最自然的证明语句是使用交易声明的 fee bound 的 worst-case cost bound,而不是关于最新 base fee 下当前可包含性的断言。
单独的有效证明并不充分。节点还必须知道该证明指向的是与公开 ciphertext 同一个隐藏交易。
GhostPool 将这种绑定拆分为两部分:
payload_commitmentciphertext → payload_commitment因此,外层的 encrypted-mempool 格式必须为 ciphertext 认证一个 payload commitment——例如通过 associated data、authenticated wrapping,或等价机制。GhostPool 不要求某一种特定的加密方案。它要求这个经过认证的 commitment Hook。
这消除了这样一种攻击:用户为一个隐藏交易证明了有效性,却附加了另一个交易的 ciphertext。
每个 nonce slot 都被分配一个 canonical nullifier:
B_slot = HashToCurve("ghostpool/nullifier/v1" | chainid | address | nonce)
N = sk · B_slot
其中 sk 是 sender secret key,address = Addr(pk)。
GhostPool 不使用诸如 H(address | nonce) 的简单 hash,也不使用任何观察者可以从可见状态直接重新计算的确定性公开产物。设计目标是 slot uniqueness without public enumerability from visible state alone。
该 nullifier 有四个用途:
(account, nonce) 产生相同的 N,(address, nonce),也不足以用观察到的 N 来检验猜测,在直观层面,观察者可以从公开数据推导出 B_slot,但在没有 sender secret key 或有效 public certificate 的情况下,无法判断一个观察到的 N 是否属于该 slot。
HashToCurve 应实现为具有适当 domain separation 的 constant-time hash-to-curve 或 encode-to-curve 方法;见 RFC 9380。协议层面的 nullifier 是 group element N 的 canonical 编码。实现上也可以为了本地索引而额外对其做 hash。
这种构造与 PLUME 等确定性公开产物设计相邻,但 GhostPool 将 nullifier 具体用作 mempool admission 的 nonce-slot key。
GhostPool 不强制将明文交易纳入加密准入电路。
明文交易继续使用普通 mempool 路径,sender、nonce 和 fee 字段保持可见。唯一的额外要求是它还必须携带:
N,以及π_slot,证明:pk = sk · G
和
N = sk · B_slot
等价地,
log_G(pk) = log_B_slot(N)
验证者从普通交易签名中恢复 pk,根据 (address, nonce) 计算 B_slot,并将 π_slot 作为 DLEQ / Chaum–Pedersen 关系进行检查。这比完整的 leaf proof 轻得多,并且使用标准机制;见 RFC 9497。
这是一条针对同一 nullifier 对象的公开认证路径,而加密交易则在 leaf circuit 内对其进行证明。它也为明文和加密交易提供了一个共享的 slot namespace。
当节点接收到一个加密 envelope E 时,它按照从最便宜到最昂贵的顺序执行检查:
N 是否与现有池条目冲突。ref_root 是否 canonical 且足够新。payload_commitment。π_leaf。该顺序的选择是为了在进行 proof verification 之前拒绝格式错误或过期对象。
GhostPool 的架构核心在于:加密和明文交易使用不同的准入路径,但在一个共享 slot namespace 上汇合。

图 2。加密和明文交易使用不同的准入检查,但在一个共享 nullifier namespace 和一个 spent-nullifier 视图上汇合。
正是这个共享 namespace 使 nonce-stability 论证能够在实践中使用。一个 pending 的加密 proof 只要满足以下条件就保持有效:
在部署中,plaintext nullifier artifacts 必须在 reorg horizon 上可用,以便 spent set 仍然可重建。这些 artifacts 如何持久化是传输或格式选择的问题。准入逻辑本身不变。
进入 mempool 的每笔交易——无论加密还是明文——都必须携带一个 canonical nullifier:
π_leaf 内建立;π_slot 建立。因此,GhostPool 依赖一个单一的 slot-tracking 不变量:
任何能够消耗被跟踪 nonce slot 的事件,都必须体现在同一个 slot-consumption 视图中。
在基础构造中,这一点可以直接实现,因为加密和明文交易都参与 shared nullifier namespace。
GhostPool 只接受 ref_root 仍处于最近 W 个 canonical block roots 之内的加密证明。
概念上,加密条目在以下条件下保持 pending:
ref_root 处于窗口内,N ∉ spent。过期仅适用于加密条目。明文条目不携带 root-bound GhostPool leaf proofs。
替换是定义在 shared nullifier slot 上的,而不是定义在可见 sender 字段上。
如果两个池条目携带相同的 nullifier,它们就竞争同一个底层的 (account, nonce) slot。若本地 policy 允许,新条目可以替换旧条目。
GhostPool 通过 nullifier 标准化 slot equality。它并不在明文和加密流程之间标准化一条统一的 fee-bump 规则。
当链发生 reorg 时,已包含于回退区块中的交易不再最终确定,因此它们的 nullifier 必须从 spent set 中移回。
节点维护一个按区块划分的 nullifier 更新日志。发生 reorg 时:
当 leaf proofs 很大时,递归 STARK 聚合是 GhostPool 的自然传播层。
如果加密 envelope 与其 leaf proofs 一起被天真地传播,那么 proof 带宽和全网验证工作都会随着吞吐量快速增长。 Recursive-STARK-based bandwidth-efficient mempool 中提出的递归传播模式适用于这种场景:节点先验证新对象一次,然后定期对它们当前已知的有效对象发布递归证明。
GhostPool 在 加密路径 上使用该模式。
一个首次接收加密 envelope 的节点只验证一次其 leaf proof。随后,在每个 tick,它生成一个覆盖本地视图中所有仍然有效的加密 envelope 的 recursive STARK,并将该递归证明与该 peer 尚未见过的任何加密 envelope 一起转发给 peers,但不包含它们原始的 leaf proofs。
递归证明的 public input 是被覆盖的加密 envelope 的一个集合描述符——例如 bitfield 或 envelope hashes 列表。递归 circuit 随后接收:
并证明所有直接提供的 envelope 以及所有递归导入集合的并集,在减去被丢弃的 envelope 后,都是有效的。
这种“union minus discard”结构与 GhostPool 非常契合。它允许 aggregate 随着 mempool 演化:
ref_root 已经落出新鲜度窗口的 envelope 可以被丢弃,如果一个节点当前有 {Tx1, Tx2, Tx3},另一个节点有 {Tx2, Tx3, Tx4},那么它们的递归证明可以合并成一个更大的证明,覆盖并集 {Tx1, Tx2, Tx3, Tx4}。接收多个部分重叠 aggregate 的 builder 也可以完全以相同方式进行组合。

图 3。递归聚合将重叠的加密交易集合合并为一个关于其并集的单一证明,并通过 discard set 移除失效对象。
这使 GhostPool 在加密路径上具有两个具体优势。
首先,它减少了 全网验证工作。一个新的加密 envelope 在首次进入网络时仍然需要被检查一次,但下游节点越来越多地验证的是覆盖 envelopes 集合的递归 coverage proofs,而不是独立地重新验证每个 leaf proof。
其次,它减少了 proof 传播开销。每个加密 envelope 的主体仍然需要在网络中传播,但 proof 流量变成了 按 tick、按 peer,而不是 按 envelope。这就是递归构造的主要带宽收益:对象数据随 envelope 数量扩展,而 proof 开销随 tick rate 和 peer 数量扩展。
nonce-stability 论证在标准 account model 中最简单,因为外发交易既是消耗 nonce 又是减少 balance 的机制。
EIP-7702 说明,一旦引入 delegated execution paths,这种简单性就不再保持不变。在这些场景中,仅凭 nonce 稳定性就无法再推断原生 balance,而被跟踪的 slot 可能会通过非普通 GhostPool-tracked transactions 的 authorization paths 被消耗。
这改变了协议需要跟踪的对象。一个自然的恢复方向是将 native-balance solvency 替换为 escrow-style solvency object,并相应扩展 slot-consumption tracking。准入架构本身不变。
基础协议仅支持 head-of-line nonce。
如果用户想为 nonce n、n+1、n+2 排队 private transactions,则后面的交易无法独立地针对当前链上状态进行证明。从 n+1 到 n 的 nullifier 的一个天真的依赖指针会重新引入 linkage。
因此,private queued transaction chains 需要另一层机制,最可能的是对可接受的 parent nullifier 做 set-membership 或 dependency proof。
GhostPool 在加密准入路径中隐藏 sender 和 nonce,但 经济元数据 仍然是一个显著的隐私风险。Fee parameters 和 gas limits 可以作为强统计指纹,并且当它们与 ciphertext size、timing 以及应用特定行为等其他可观察特征结合时,会变得更加暴露。
隐藏经济元数据要困难得多,因为 builders 在排序和打包时需要它们。更重要的是,像 ORE 或 HE 这样的标准密码学思想在公开提交场景下并不能解决这个问题。如果任何人都可以生成加密或与 comparison interface 交互,那么小域元数据仍可能通过探测被恢复:加密猜测、比较结果,并推断底层值。
设计一种既能支持公开提交、builder incentives 和 block construction 的 fee 和 gas 保密性,仍然是一个开放问题。GhostPool 将其视为单独的工作。
Encrypted mempools 已经有了可信的设计,可以在 inclusion order 固定之前隐藏交易 内容。它们通常尚未提供的是一种私密方式,来决定一个加密交易是否首先是 admissible,而不重新引入 validation blindness。
GhostPool 填补了这一空白。
在其基础范围内——标准 account model 下的 head-of-line nonce admission,并且位于认证 payload commitment 的 encrypted 格式中——GhostPool 用一个 root-bound ZK proof 加上一个覆盖加密和明文交易的共享 nullifier namespace,替代公开的 (sender, nonce) 准入检查。这在保留语义准入检查的同时,将身份关键的准入元数据从明文加密准入路径中移除。
以下内容均为可选。它使提案更易于实现和审阅,但删除后不会改变核心叙述。
R_h:窗口内 canonical block roots 的集合,例如 {root[h-W], ..., root[h]}ref_root:在 π_leaf 内使用的确切 rootpayload_commitment:对隐藏交易 payload 的公开 commitmentaddress = Addr(pk):账户地址nonce:账户 nonceHashToCurve(·):带 domain separation 的 hash-to-curve 或 encode-to-curve 函数B_slot 的推荐 domain separation 输入:
"ghostpool/nullifier/v1"chainidaddressnoncePublic inputs
payload_commitmentNref_rootpublic_meta 的公开 fee 和 packing 字段Witness
to, value, gas_limit, max_fee_per_gas, max_priority_fee_per_gas, calldata 等)ref_root 下的账户和 state witnessStatement
证明者展示一个 witness 的存在,使得:
address = Addr(pk)nonce(address; ref_root) = noncebalance(address; ref_root) ≥ worst_case_cost(hidden_tx)payload_commitment = Commit(hidden_tx)B_slot = HashToCurve("dst" | chainid | address | nonce)N = sk · B_slotPublic inputs
B_slot(根据可见 (address, nonce) 计算)NWitness
Statement
证明:
log_G(pk) = log_B_slot(N)
这是一个标准的 DLEQ / Chaum–Pedersen 语句;见 RFC 9497。
在素数阶群上,标准的 Chaum–Pedersen 证明可按如下方式证明离散对数相等:
pk = sk · G 且 N = sk · B。r 并计算承诺:a_1 = r · G, a_2 = r · B
c。z = r + c · sk
z · G = a_1 + c · pk
以及
z · B = a_2 + c · N
Fiat–Shamir 变换可使其非交互化。
W ∈ [32, 128] 个区块。pending_map,受 mempool 大小限制spent_set,受为恢复和 reorg 安全而跟踪的近期链跨度限制
- 原文链接: ethresear.ch/t/ghostpool...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!