把一个点安全地放进曲线:哈希进曲线与 EIP-3068 的预编译设想 图 1
把一个点安全地放进曲线:哈希进曲线与 EIP-3068 的预编译设想 · 图 1

天真做法为什么会坏

密码协议经常需要这样的操作:把一段任意长度的消息映射到椭圆曲线上的一个点。最直觉的做法是拿消息哈希当作横坐标去解曲线方程,可随机猜出的横坐标大约只有一半概率落在曲线上,而且这个解法路径本身会泄露信息——验证者能反推你试过什么、知道哪个原像。更糟的是,如果映射过程依赖某个知道随机数的参与者,那个参与者就掌握了这个点的离散对数,等于偷偷拿着一把能冒充你的钥匙。

安全的哈希进曲线必须满足一个叫不可预测性的性质:算法对所有人都是公开的,任何人都算得出这个点,但没有任何人(包括实现者)知道它对应的离散对数。做不到这一点,依赖该点的协议安全性就整体归零。

标准方法长什么样

互联网工程任务组在二零二三年八月发布了 RFC 9380,把这件事做成了标准信息:先做一步域哈希,把消息变成基域上的均匀元素;再经过一段映射函数投到曲线上;最后用一遍 cofactor clearing 把点推进正确的子群。文档给了两类映射:一类追求每一步都是封闭公式、性能高但实现苛刻;另一类结构直白、每一步都可简单审计,RFC 的建议是拿不准就选后者。整个流程没有任何私密输入,因此所有人都算得出一样的结果,离散对数则无人所知。

对以太坊来说,这条标准还差一环:曲线运算要发生在 EVM 里。BN256 配对曲线的有限域加法、乘法在预编译里已经有,但哈希进曲线这段既没有专用预编译,用普通操作码手写又贵得离谱——域逆、开平方这类步骤在字节码里动辄几万燃料。

EIP-3068 的位置

EIP-3068 在二零二零年十月提出,作者是密码研究员 Christopher Gorman,依赖早期的配对预编译(编号 198 与其燃料修订 1108),设想在 BN256 上新增一个预编译入口,输入消息、输出按标准方法得到的曲线点,让依赖它的合约用固定燃料拿到标准映射。提案文本把动机写得很清楚:BLS 签名验证在以太坊越来越有用,而 BLS 哈希到 G2 的那一步是协议安全的咽喉,用预编译固化标准实现好过每个合约各写一遍各错一遍。

后续几年里这条提案没有前进:在规范仓库中它的状态停在停滞一档,同赛道的努力转向了别的容器——执行层的 BLS 预编译以另一条编号(2537)继续推进并入列近年升级,链下工具链则普遍采用经过审计的库实现 RFC 9380。读这条提案,最有价值的不是落地与否,而是它标记出的问题:协议级原语如果只能靠社区合约重复造轮子,出错面积会大得吓人。

什么时候你会碰到它

普通用户永远不需要知道这段数学;合约开发者的触发点通常有三类:做聚合签名、做链下计算上链验证、做基于身份的方案。此时你的实际选择是:在支持的链上用现成预编译;不支持就调审计过的库、把燃料花在刀刃上;或者把映射挪到链下、链上只验结果。三种路径的信任假设不同,预算也不同,选之前先想清楚协议到底在哪一层信任什么。

截至本文核验时,EIP-3068 在规范仓库中的状态是停滞,以太坊主网没有这个预编译;相关能力以当期规范与客户端实现为准。 顺带把域分离记牢:哈希进曲线的标准流程里有专用的域分隔字符串,同样一段消息在两个不同协议里映射出必然不同的点,这正是防止一份签名在另一场景被复用为有效点的防线,读任何实现先看这一步有没有做对。

风险提示:本文仅作技术科普,不构成投资建议。