签名只认一种写法:ERC-8111 绑定签名用 v=27 消灭可延展性
你可能见过一种攻击叙事:用户签了一份“购买确认”消息,服务方收到后没有原样存证,而是把签名稍微一变形,声称这就是另一份文件。签名可延展性(malleability)是 ECDSA 在以太坊上的老毛病:同一份摘要,(r, s, v=27) 与 (r, N−s, v=28) 都能通过 ecrecover 校验——数学上二者等价,编码却是两串不同字节。ERC-8111 绑定签名(Bound Signatures)用一刀切的方法消灭歧义:合约只接受 v=27。状态为 Review,创建于 2025 年 12 月 23 日。
归一化的算术
规则一句话:接受绑定签名的合约必须只给 ecrecover 传 27,不得接受任何其他 v 值;合约外的签名在送入这类合约前必须先做绑定。转换原理是椭圆曲线群的性质:把 s 替换为群阶 N 减 s、v 归一为 27,恢复出的 signer 完全相同。文档给出一段 TypeScript 参考实现:若 v 已是目标值原样返回,否则输出新签名 r 不变、s 取 SECP256K1_N - s、v 固定 27;合约侧对应写法就是 ecrecover(digest, 27, r, s) 加零地址检查。
理由部分交代了两个取舍。其一,另一种压缩签名方案 ERC-2098 把 y-parity 塞进 s 的最高位,存储省一个字段,但合约要自己解包再计算,绑定签名直接就是 ecrecover 的合法输入,更省 gas。其二,如果合约同时接受 27 与 28,等于把可延展性重新请回——所以只能二选一;选 27 而非 28,是为了让 y-parity 落在“假值”一侧,规则最简。

这件事对谁真正重要
第一类是协议开发者:凡用 EIP-712 签名消息做免 gas 领取、铸造、授权或链下撮合的合约,校验逻辑用经过审计的 ECDSA 库并拒绝非规范签名,本质就是这种归一化哲学的落地;ERC-8111 把散落的最佳实践升格为可声明的标准。第二类是撮合与存证系统:订单、意向单一旦以签名做唯一键,可延展性意味着同一份订单存在两种合法字节表示——去重、防双花、防“改了 v 当新单广播”全要靠下游补洞;规定绑定签名后,一份消息对应唯一合法编码,重放判定从“比较语义”退化成“比较哈希”,工程上干净得多。第三类是市场结算:理解 v 与 s 的归一,就能理解“把别人签名换个 v 就能冒充重放”的说法多半是吓人的营销话术——真正该防的是语义层面的消息复用(同一签名换个场景再提交),而不是编码变形本身。
使用与审计清单
合约侧:校验路径不得手写“接受 27 或 28”;引入第三方 ECDSA 库时确认版本支持规范签名校验。链下侧:签名库输出后先做一次绑定变换再存储;数据库以“摘要加 signer”为主键时,同步保存规范编码的签名原件以备争议仲裁。用户侧:你几乎不需要直接感知 8111,但值得记住一条防御常识——一个严谨的签名系统会把“你签过的每份消息”视为可核对的档案;凡声称“签名作废不需要上链取消、只要他们内部标记”的平台,要求它说明消息唯一键怎么定义、如何防旧签名在新场景复活,是合理的问题。
一句概括:绑定签名没有改变 ECDSA 的安全性,改变的是“同一份签名有几种合法写法”这个问题——答案从两种变一种,依赖签名的系统就少踩一个经典深坑。它的兄弟 ERC-2098 适合极致省存储的场合,需要走 ecrecover 的场合则优先绑定形式。
与 2098 的取舍再给一句实操总结:要极致紧凑的六十四字节存储编码选 ERC-2098,要合约校验便宜、与 ecrecover 无缝对接选绑定签名;同一系统内两者可以共存——签名库按用途转换编码落库,校验合约只暴露 v 为 27 的单一路径。无论选哪条,规范编码校验都必须在合约层强制执行:链下库的归一只是礼貌,不是防线。
最后提醒:本文讲签名机制与防御,不构成投资建议;集成签名校验前请审计依赖库版本并核对所有合约地址。
发表评论
还没有评论,来说两句吧。
评论区为展示样式,提交不会被处理。