EIP-7797 深度解析通过定制 SHA-256 为 hash_tree_root 带来双倍性能【免费下载链接】EIPsThe Ethereum Improvement Proposal repository项目地址: https://gitcode.com/GitHub_Trending/ei/EIPs导读EIP-7797Double speed for hash_tree_root是面向以太坊共识层Consensus Layer的 Core 类标准提案其核心思路是利用hash_tree_root中所有输入消息长度恒定为 512 位的特性定义一个跳过消息预处理步骤的定制版 SHA-256——SHA-256-512从而将底层哈希吞吐量提升一倍。本文将以 EIPS/eip-7797.md 为主体结合本仓库中 SSZ Merkleization 的参考实现如 assets/eip-4881/eip_4881.py与相关联的 EIP-7495、EIP-7688、EIP-7916 等提案完整解读其背景动机、算法规范、性能收益、兼容性影响与安全边界。读完本文你将理解为什么 SHA-256 在hash_tree_root场景下白做了约一半工作、SHA-256-512 如何把这些工作省掉以及该方案与 Progressive SSZ 类型改造之间的关系。背景为什么哈希是共识层的性能瓶颈在以太坊共识层实现中哈希Hashing是占主导地位的性能瓶颈。随着验证者validator数量的增长状态根state root的计算、区块签名验证、证明校验等操作都在持续消耗 CPU。为了支撑大规模验证者数量优化哈希性能至关重要见 EIPS/eip-7797.md Motivation 一节。共识层的所有哈希都基于hash_tree_root——一种将数据切分成 chunk、再把相邻的两个 chunk 递归组合并哈希为单个父 chunk、直到只剩一个根 chunk 的 Merkle 化merkleization机制。其典型实现可以在本仓库 EIP-4881 的参考实现 中看到MerkleTree.Node.get_root()直接对左右子树根做sha256(left right)assets/eip-4881/deposit_snapshot.pyzerohashes预计算也依赖sha256(h h)逐层生成assets/eip-4881/eip_4881.py。这正是 EIP-7797 想优化的热路径每次树节点合并都是一次对两个 32 字节子根共 64 字节 512 位的 SHA-256 计算。EIP-7797 观察到一个关键事实SHA-256 对可变长度输入消息恰好产生 256 位32 字节输出而hash_tree_root会把所有输入 chunk 都填充到恰好 256 位因此hash_tree_root场景下 SHA-256 的实际输入消息长度永远是恰好 512 位。既然输入长度恒定就可以针对这一先验知识对 SHA-256 做定制化改造在保留安全属性的前提下把性能翻倍。SHA-256 的预处理被浪费的那一半工作标准的 SHA-256 在正式计算哈希之前要先对输入消息做预处理preprocessing在消息末尾追加一个1位随后补足若干0位最后附上一个大端序的uint64表示输入消息的位长度。0位的数量被选择为使填充后消息总大小成为 512 位的最小倍数。在hash_tree_root场景下输入消息大小恰好为 512 位预处理后得到的填充消息如下来自 EIPS/eip-7797.md Specification0 1 2 3 4 5 6 7 8 9 A B C D E F -------------------------------- 0x00 | | 0x10 | Input | 0x20 | message | 0x30 | | -------------------------------- 0x40 |80|00 00 00 00 00 00 00 00 00 00 00 00 00 00 00| 0x50 |00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00| 0x60 |00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00| 0x70 |00 00 00 00 00 00 00 00|00 00 00 00 00 00 02 00| --------------------------------解读这张图0x00~0x30原始的 512 位64 字节输入消息0x40首字节80追加的1位其后跟 7 个0位0x40~0x6F用于补齐的0位0x70末尾 8 字节00 00 00 00 00 00 02 00大端序uint64值为0x200 512即输入消息的位长度。注意由于 512 位输入恰好是 SHA-256 块大小的整数倍填充后消息变成了整整 1024 位两个 512 位块。两个消息块一块承载数据一块完全是静态数据SHA-256 按 512 位消息块message block为单位进行压缩运算。在hash_tree_root的 512 位输入场景下预处理后形成两个消息块第一个块包含完整的输入消息真实数据第二个块完全由预处理步骤产生的静态数据80 零填充 位长度字段。第二个 512 位块不提供任何熵entropy它唯一的用途是在通用 SHA-256 中区分共享共同前缀、仅在尾部0位数量上不同的输入消息。而hash_tree_root使用固定消息长度根本不需要这种区分。此外密码学上 SHA-256 对恰好能塞进单个消息块的填充后消息同样被认为是安全的。因此可以安全地跳过第二个静态块的压缩运算——这就是性能翻倍的来源原本每 64 字节输入要做两轮 512 位块压缩现在只需做一轮。SHA-256-512跳过预处理、限定 512 位输入的新算法EIP-7797 据此定义一个新算法 SHA-256-512它是修改版的 SHA-256跳过输入消息预处理它仅限于恰好 512 位的输入输入消息按原样作为单个 512 位 SHA-256 消息块处理。在规范层面本 EIP 遵循 RFC 2119 / RFC 8174 的 MUST / SHOULD / MAY 措辞约定见 EIPS/eip-7797.md Specification 开头对于每一个正在使用的复合 SSZ 类型composite SSZ type实现方**必须SHALL**支持一个新的、功能完全相同的类型区别仅在于使用 SHA-256-512 而非常规 SHA-256 进行哈希从引入本 EIP 的硬分叉开始基于 SHA-256-512 的复合 SSZ 类型**应当SHOULD**优先于现有的 SHA-256 类型被使用。值得注意的是SHA-256-512只改动 SHA-256 的预处理环节其核心的 512 位消息块压缩函数compression function保持不变。因此现有的 SHA-256 硬件加速方案依然完全可用——硬件加速通常只实现消息块函数而这部分在本 EIP 中没有任何改变。共识类型的历史数据处理切换到新哈希后存在两类需要特殊处理的历史数据场景见 EIPS/eip-7797.md Consensus types 一节历史对象回算某些覆盖历史对象的用例可能MAY需要转换回历史数据类型、并用原始的 SHA-256 类型重新哈希才能恢复其历史根。典型例子包括compute_signing_root对历史数据签名以及BeaconState.latest_block_header这类可能引用先前分叉数据的字段——例如BeaconBlockHeader这类历史结构体需要新的逻辑来正确选择哈希算法保持原算法某些对象如DepositData、VoluntaryExit**可能MAY**继续依赖现有的 SHA-256 逻辑不必迁移到 SHA-256-512。这暗示迁移的落地形态不是一刀切替换所有哈希而是按类型区分新旧算法确保历史根historical root的可恢复性。收益量化哈希吞吐翻倍意味着什么关于性能收益EIPS/eip-7797.md Rationale 给出了量化说明将底层哈希算法吞吐量翻倍允许在相同硬件上支撑更多验证者或者把省下的 CPU 时间用于其他任务即便在跨计算缓存了很少变化的中间哈希如BeaconState的validators列表并且使用了针对树结构进一步优化的硬件加速 SHA-256 实现例如prysmaticlabs/hashtree这类库共识层状态转换函数中的状态根校验步骤仍可消耗约 25% 的 CPU 时间Holesky 测试网约 170 万验证者其中大部分开销来自频繁变化的每个验证者结构体例如EpochParticipationFlagsepoch 参与标志列表。从源码结构可以推断这正是BeaconState中validators、balances、previous_epoch_participation、current_epoch_participation等字段在 Merkle 树中层层上推时所产生的大量 SHA-256 调用——每层树节点合并都是一次 512 位输入的哈希。SHA-256-512 让每一次这样的合并只做一轮块压缩而不是两轮直接把该热路径的哈希开销减半。面向未来的哈希算法迁移提前排雷EIP-7797 的另一个动机是为未来更换更 ZK 友好zero-knowledge friendly的哈希算法铺路未来如果要把哈希算法换成更 ZK 友好的算法需要识别哪些位置的历史对象必须用历史哈希算法进行哈希并引入新的复合 SSZ 类型从 SHA-256 切换到 SHA-256-512 相当于提前完成这项工作未来任何哈希算法变更都只需在这些已知位置上扩展即可多次切换哈希算法的总工作量与只切换一次相当。也就是说SHA-256-512 充当了一次干跑——把历史对象用旧哈希、新对象用新哈希的迁移框架和类型机制先建立起来后续真正换哈希时可以直接复用。向后兼容性EIPS/eip-7797.md Backwards Compatibility 一节明确了影响范围验证共识层数据的智能合约与客户端应用需要更新才能与使用 SHA-256-512 哈希的数据保持兼容对于BeaconBlockHeader等历史结构体可能需要新的逻辑来正确选择哈希算法历史数据用 SHA-256新数据用 SHA-256-512不受影响的部分SSZ 序列化、广义索引generalized indices以及各对象字段的语义均保持不变。这一点与 EIP-7688Forward compatible consensus data structures将共识 SSZ 数据结构迁移到ProgressiveContainer形成呼应EIP-7688 只改变 Merkle 树形态merkleization不改变序列化EIP-7797 则只改变哈希算法同样不触碰序列化与字段语义。两者都是改树不改序列化类型的核心层变更因此都存在历史数据必须用旧逻辑校验的兼容性要求。安全考量跨算法碰撞的理论边界EIP-7797 在 Security Considerations 中主动披露了一个重要的理论碰撞场景某些 512 位数据的 SHA-256-512 哈希可能与较短数据的常规 SHA-256 哈希发生碰撞。具体示例任意共同的 440 位前缀COMMON_PREFIX : 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30313233343536SHA-256-512(COMMON_PREFIX 0x80 0x00000000000001b8) 463eb28e72f82e0a96c0a4cc53690c571281131f672aa229e0d45ae59b598b59SHA-256(COMMON_PREFIX) 463eb28e72f82e0a96c0a4cc53690c571281131f672aa229e0d45ae59b598b59为什么会出现这种现象因为 SHA-256-512 跳过了预处理而常规 SHA-256 对COMMON_PREFIX440 位的预处理恰好会追加0x80和位长度0x1b8440形成与前者相同的 512 位输入——于是两个算法的输出一致。不过这一理论碰撞在 SSZ 语境下并不可行SSZ 从未哈希过 512 位以外大小的数据因此基于 SHA-256 的 SSZ 哈希与基于 SHA-256-512 的 SSZ 哈希不会发生碰撞规范同时明确SHA-256-512 不应SHOULD NOT被用于 SSZ Merkleization 以外的任何目的——它不是一个通用哈希算法而是一个为 SSZ 定制的专用原语。仓库内证据SHA-256 在 Merkle 化中的实际形态本仓库虽然没有 EIP-7797 专用的参考实现目录但 EIP-4881 的参考实现完整展示了以 SHA-256 为原语的 Merkle 化代码形态可作为理解热路径的实证底层包装def sha256(x) - Hash32: return SHA256(x).digest()assets/eip-4881/eip_4881.py所有 Merkle 树节点合并都经由它节点合并Node.get_root()返回sha256(self.left.get_root() self.right.get_root())assets/eip-4881/deposit_snapshot.py——左右子根各 32 字节拼接后恰好 64 字节 512 位正是 SHA-256-512 的目标输入长度零哈希预计算zerohashes[i] sha256(zerohashes[i-1] zerohashes[i-1])assets/eip-4881/eip_4881.py根混合长度get_root()返回sha256(self.tree.get_root() to_le_bytes(self.mix_in_length))assets/eip-4881/deposit_snapshot.py——同样是 512 位输入。由此可见共识层 Merkle 化中的每一次sha256(a b)调用输入都是两个 32 字节值拼接成的 512 位。把这些调用替换为 SHA-256-512单块压缩即可直接获得近一倍的吞吐提升且无需改动 Merkle 树结构本身。与 SSZ 类型演进提案的关系EIP-7797 的为每个复合 SSZ 类型引入并行的新类型思路与仓库内另外几份由同一作者群推进的 SSZ 类型提案形成清晰的路线图EIP-7916SSZ ProgressiveList引入渐进式 Merkle 树形态列表按需生长、消除容量上限与不必要的零填充哈希EIP-7495SSZ ProgressiveContainer引入字段级稳定广义索引的前向兼容容器EIP-7688Forward compatible consensus data structures把共识数据结构整体迁移到上述渐进式类型。从源码结构可以推断这些提案与 EIP-7797 共享同一个目标在不改变 SSZ 序列化与字段语义的前提下重塑共识层的哈希路径——前者优化哈希多少次、树长什么样后者优化每一次哈希多快。若未来 SHA-256-512 落地共识层状态根校验Holesky 约 170 万验证者下约占 25% CPU有望显著下降为更大规模验证者集或 ZK 化共识留出空间。版权说明EIP-7797 的版权及相关权利已通过 CC0 许可 放弃其规范文本可自由引用与实现。【免费下载链接】EIPsThe Ethereum Improvement Proposal repository项目地址: https://gitcode.com/GitHub_Trending/ei/EIPs创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考