EIP-7702 驱动的极简代理实现

本文介绍了利用 EIP-7702 新特性实现极简代理合约的新方法,该方法无需工厂合约,通过密钥less直接部署到地址,减少了近 50% 的代理字节码,并通过单笔原子交易简化了整个过程, 从而节约 gas 成本。但同时,也带来了跨链重放、抢跑等新的安全问题,需要开发者注意。

多年来,开发人员一直依赖 EIP-1167 极简代理来降低合约部署期间的 Gas 成本,这已成为行业基准。 尽管如此,它们仍然需要 45 字节的运行时代码和一个工厂合约来进行原子部署和初始化。

在这篇博文中,我们提出了一种新方法,它利用新的 EIP-7702 中的强大功能来使传统的代理工厂过时。我们将演示一种无密钥、直接地址部署的技术,该技术不仅将代理字节码缩减了近 50%,而且还将整个过程简化为单个原子交易,从而节省了 Gas 并消除了工厂开销。

EIP-7702 简述

EIP-7702 引入了一种新的交易类型 0x04(“设置代码”),它允许任何外部拥有帐户 (EOA) 通过呈现授权元组的链下签名来设置或替换委托。 一旦交易被挖掘,EOA(所谓的授权者)的行为就类似于智能合约。 该规范定义:

auth_hash = keccak256( 0x05 || rlp(chainId, targetAddress, nonce) )

通过一些验证,最重要的是,如果签名元组 (v, r, s) 对于该 auth_hash 有效,则客户端将 authority 的代码设置为:

(0xef0100 || targetAddress)

这是一个委托指定。

简而言之,EIP-7702 让我们为 EOA 部署协议启用的代理。 我们可以将它们也用作极简智能合约代理吗?

用于代理的 EIP-7702?

极简代理模式(EIP-1167)因其 Gas 节省而备受喜爱,但它们仍然具有 45 字节的运行时代码,并依赖于工厂合约进行部署和初始化。 换入 EIP-7702 感觉就像一颗神奇的子弹:23 字节的 delegate-proxy 代码和一个批处理事务,但立即出现了两个障碍:

  • 我们不知道未来代理地址的私钥,那么我们如何签署授权?
  • 试图将 EIP-7702 代理字节码直接推送到新合约的幼稚尝试会在部署期间在操作码 0xEF (INVALID) 上爆炸(参见 EIP-3541)。

尽管如此,私钥所有权不是强制性的,无法生成有效的签名。

无密钥部署

这并不是第一次使用无密钥部署的想法,请参阅 The DAO Edge Cases 以及 EIP-1820EIP-4788 的部署。 通过逆向工程有效的签名,我们获得了一个单次使用的合成地址,该地址在密码学上绑定到交易输入数据(在本例中为授权元组)。

为了理解为什么可以进行无密钥部署,我们首先需要理解 ecrecover 的工作方式。 ecrecover 是执行层用来根据签名查找交易签名者的工具。 因此,ecrecover 在给定交易的情况下为我们提供了签名者的地址。 它是如何做到的?

PA=r−1[s∗K−m∗G]

其中:

  • G:群生成器
  • Q:群阶
  • P:模数
  • m:消息的哈希值
  • k:随机 nonce
  • K:(承诺)对应的点 K=kG=(x,y)
  • r:x(modQ)
  • dA:用户的私钥
  • PA:用户的公钥 PA=dA⋅G = (PAx,PAy)

如果我们设置 s 和奇偶校验 v 为常数值,并不断尝试不同的 r,如果 r 对应于 Secp256-k1 曲线上的有效点 K',我们可以获得一个有效的点 PA'。 请注意,成功的可能性几乎为 100% (Q/P)。

下面是无密钥部署的 python 实现:

  • 我们设置 s=SEED + random.getrandbits(128),以便每次调用都从签名空间的一个新切片开始,并避免在两次运行中使用相同的实现地址来挖掘相同的代理地址。
  • r 从 SEED 开始线性递增,直到 ecrecover 产生有效的公钥; 相应的地址成为我们的 authority(代理)。
SEED = 0x7702770277027702770277027702770277027702770277027702770277027702

## msg_hash = keccak256( 0x05 || rlp(chainId, targetAddress, 0) )
def mine_sig(msg_hash: bytes):
    attempts = 0
    r = SEED
    s = SEED + random.getrandbits(128)
    authority = 0
    v = 0

    while True:
        attempts += 1

        try:
            sig = keys.Signature(vrs=(v, r, s))
            pub_key = sig.recover_public_key_from_msg_hash(msg_hash)
            authority = pub_key.to_checksum_address()
            break

        except Exception:
            r += 1

            continue

    return authority, r, s, v

请注意,authority(要部署的代理)是一个新帐户,因此它的 nonce 将为 0。 并且如果 SEED 是固定的,则恢复的公钥,因此 authority 地址(代理)是授权元组确定的。

setCode 交易允许包含多个授权元组。 因此,可以在一个交易中部署一批代理

总而言之,部署 EIP-7702 代理需要以下步骤:

  1. 像以前一样部署你的实现合约。
  2. 从所需的授权元组中逆向工程有效的签名。
  3. 提交包含授权元组的 setCode 交易。 要在同一交易中初始化它,tx.to 应该设置为合成地址,并且对 initialize() 的调用应该嵌入到 tx.data 中。

影响

EIP-7702 代理具有以下优点:

  1. 更少的字节码:23 字节的 EIP-7702 与 45 字节的 EIP-1167,尺寸减少了近 50%
  2. 无工厂:减少了工厂开发和审计的开销。
  3. 更便宜的部署:我们的示例部署(见下文)显示 Gas 使用量减少了 18%(95,654 与 116,357)。
  4. 更便宜的调用:每次调用代理都更便宜,因为消除了 EIP-1167 的剩余开销。 Gas 差异取决于调用参数,在我们的示例中,每次调用为 2,669 Gas。

安全注意事项

跨链重放

设置 chainId == 0 会有效地禁用重放保护。 相同的授权元组可以在任何网络上广播,从而在每个地方生成相同的代理地址,但是每个实例可以使用不同的参数进行初始化,从而将控制权交给在该链上首先抢跑的人。

抢跑和部署验证

如果函数 initialize() 是无权限的,则部署和初始化应捆绑在同一 setCode 交易中。 分割它们会打开一个竞争窗口,在该窗口中,新部署的代理处于无权限状态,可能会被劫持。

但是,捆绑它们并不能阻止抢跑。 观察者可以在你的挖掘签名 (v,r,s) 到达内存池后复制它,并使用修改后的 calldata 进行自己的 setCode 交易抢跑。 例如,原本用于所有者 A 的有权限合约可以首先由攻击者部署,该攻击者换入所有者 B,从而不可撤销地窃取该地址。

因此,部署验证对于确保 EIP-7702 代理按预期部署至关重要。

地址冲突

EIP-7702 修改了 EIP-3607 的限制(必须拒绝来自具有代码的帐户的交易)以获得有效的委托指示符。

因此,从理论上讲,可以找到 EIP-7702 代理的私钥,从而使攻击者能够以代理的名义进行交易。 这有两个潜在的后果:

  1. 恶意部署者可能会假装执行“无密钥”部署,即使他们先前已在 EIP-7702 代理地址和由私钥控制的 EOA 之间创建了冲突。 这使他们以后可以接管。 这需要大约 <img src="https://www.w3.org/1998/Math/MathML" display="inline">280</math> 计算操作。
  2. 攻击者可能会尝试查找正确的“无密钥”部署的私钥。 但是,这应该与查找任何其他 EOA 地址的私钥一样困难,因此没有量子计算机是不可行的。

结论

EIP-7702 可以通过简单的 setCode 交易部署“真正的”极简代理。 可以在单个原子交易中实现部署和初始化。 与以前的“极简”EIP-1167 相比:

EIP-1167 代理

  • 🧱 需要工厂
  • 📦 更大的字节码大小
  • ⛽️ 更高的部署 Gas
  • 💸 更昂贵的调用

EIP-7702 代理

  • 🚫 无需工厂
  • 🪶 更小的字节码
  • 💨 更便宜的部署
  • ⚡️ 更低的调用成本

但是,在比较安全性时,新方法更糟:

  • 抢跑初始化比在大多数工厂部署的 EIP-1167 代理中更大的问题。 作为一种防御措施,如果实施合约知道,它可以添加特定于应用程序的抢跑保护。 此外,正如 最近发现的,“传统”代理也存在初始化抢跑的问题。
  • 恶意部署使用地址冲突(随着计算能力的增长,这变得越来越重要)存在迫在眉睫的问题,这使某人可以接管看似安全的代理。 部署过程的标准化可以增加额外的安全性。

自己重现它

示例存储库:https://github.com/ChainSecurity/real-minimal-proxy/

‍ 祝你黑客愉快!

关于我们

准备好对你的 7702 推广进行健全性检查了吗?

我们已经审核了许多帐户抽象堆栈(我们的钱包和 AA 审核报告),并且我们构建了开源的 部署验证 工具。

如果你有任何疑问,请随时通过 contact@chainsecurity.com 与我们联系,以获取一般请求(包括审核请求),以及有关此漏洞或其他漏洞的问题。 也可以访问我们的网站 chainsecurity.com

外部链接

  • 原文链接: chainsecurity.com/blog/t...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
chainsecurity
chainsecurity
江湖只有他的大名,没有他的介绍。