同一个地址两个主人?EIP-3607 怎么堵住地址碰撞的漏洞 图 1
同一个地址两个主人?EIP-3607 怎么堵住地址碰撞的漏洞 · 图 1

以太坊地址只有 160 位,理论上存在两个不同“主人”共用同一地址的可能:一个合约部署后生成的地址,恰好和某个私钥对应的普通地址一模一样。EIP-3607 不解决碰撞怎么找出来,它规定了一条更干脆的防线——有代码的地址不能发起交易。这篇讲清这种碰撞的攻击形态、官方给出的难度估算,以及这条规则挡住的和没挡住的。

十六万分之一以下的概率,为什么还有人当真

地址是 20 字节、160 位。按生日攻击的思路,算出两个地址相撞需要海量尝试。EIP-3607 文本给了一组估算:暴力存储两的八十次方个地址需要约 24 尧字节内存,现实中存不下;但配合碰撞搜索算法,不必存全部地址,文本估计以大约一百亿美元的硬件与电力投入、约一年时间可以找到一次合约与普通账户的地址碰撞。这个量级对个人荒谬、对有组织的攻击者却并非天方夜谭——EIP 因此被提出,状态 Final,随 2021 年伦敦升级生效。

攻击长什么样

假设攻击者花大价钱找到一个普通账户地址,它恰好等于某个合约将部署到的地址。接下来最危险的剧本是:攻击者部署一个外表体面的合约(比如某个代币包装器),吸引用户向“这个地址的合约”存资产;如果协议允许有代码的账户用私钥签名发起交易,攻击者就能以普通账户的身份把同地址资产转走。最朴素的受害形态则更简单——用户先向一个尚未部署合约的地址打款,攻击者抢先部署同地址合约再接管资金。

同一地址牌前两条钥匙路径被红色禁令条封住一条的示意

规则本身:有代码的发送方一律无效

EIP-3607 的规格只有一句话:任何发送方账户代码哈希不等于空代码哈希的交易,必须被判定为无效,不得进入任何区块。代码哈希是账户字段的固定项,普通账户没有代码,合约账户有代码——于是“合约地址用私钥签名发交易”这条路被协议层彻底关闭,碰撞攻击里最严重的一支就此失效。

规则之外,用户怎么自查

这条防线在协议层默默生效,用户端也有对应的核验动作。第一,向一个地址转资产前,先在区块浏览器看它有没有“合约代码”标签与已验证源码——一个声称是合约、却查不到代码的地址,要么是还没部署,要么根本是普通账户。第二,合约地址由部署者地址和当时的随机数(nonce)推导,同一账户按交易次序会派生出不同的合约地址,项目公告的部署地址要以链上实际部署记录为准,不要按“计划中的地址”提前注资。第三,翻看地址的历史交易时区分角色:它在部署前作为接收方出现过,只是普通转账记录,但意味着任何在该合约上线前打进去的资产都无法被合约逻辑管理;如果它在有代码之后还能作为发送方签名,那与协议规则矛盾,应当怀疑页面或节点被篡改,换公开节点复核。

它没有消灭碰撞本身

需要看清边界。碰撞仍可存在:同一地址可能既有一把私钥、又有部署在其上的合约,只是双方不能互换身份行事。用户在合约部署前向目标地址转款的风险,属于另一类问题,EIP-3607 帮不上忙。EIP 文本也记录了长期方案——把地址扩展到 256 位可让碰撞彻底超出可行范围,但那属于更底层、更伤筋动骨的改动,尚无时间表。对普通用户,可操作的建议朴素而有效:向合约地址转账前确认合约已部署、已验证,别为“预定地址”提前注资。本文仅作协议机制说明,不构成投资建议。