协议演进 / BIP/比特币改进提案 / BIP-340
BIP-340
为 secp256k1 定义字节级完全确定的 64 字节 Schnorr 签名标准:32 字节 x-only 公钥、可批量验证,是 Taproot 的签名地基。本 BIP 目前处于已部署状态。
一、档案卡
| 编号 | BIP-340 |
|---|---|
| 标题 | Schnorr Signatures for secp256k1 |
| 作者 | Pieter Wuille <[email protected]>; Jonas Nick <[email protected]>; Tim Ruffing <[email protected]> |
| 指定日期 | 2020-01-19 |
| 讨论日期 | 2018-07-06 |
| 层级 | 未标注(签名规范) |
| 类型 | Specification(规范类) |
| 状态 | Deployed(已部署) |
| 阅读版 | https://bips.dev/340 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki |
二、放在哪一族
签名方案族,是 Taproot 三件套的地基:BIP-340 定签名本身,BIP-341 定 SegWit v1 输出的花费规则,BIP-342 定脚本(Tapscript)里的签名验证语义。后两者的 Schnorr 验证都直接引用本文档的算法。
它接替的不是某一篇旧 BIP,而是比特币自创世以来使用的 ECDSA(配合 SHA256、同一条 secp256k1 曲线)。原文开宗明义:沿用同一条曲线与同一个哈希函数,既有的密钥生成机制(如 BIP-32 及其派生方案)全部保留,不引入对曲线与哈希函数的新安全假设。
下游应用包括:基于线性性质的多签与门限签名协议 MuSig2(BIP-327)、FROST,以及适配器签名(adaptor signatures)、盲签名等构造——这些在原文 Applications 一节都有专门论述。
三、它要解决什么
原文 Motivation 把 Schnorr 相对 ECDSA 的优势列为三条:
- 可证明安全:Schnorr 签名在随机预言机模型与通用群模型下有安全性证明(强不可伪造,SUF-CMA);ECDSA 的最好证明结果依赖更强的假设;
- 不可锻性(non-malleability):由 SUF-CMA 直接推出。ECDSA 则天生可锻:若 (r, s) 有效,(r, n−s) 对同一消息与公钥同样有效,第三方无需私钥就能把一份有效签名改成另一份——比特币只能靠网络策略规则压住其中一种形态,相关讨论见 BIP-62 与 BIP-146;
- 线性(linearity):多方可以协作产生一个对“公钥之和”有效的签名,这是多签、门限签名等上层构造的基石,验证者看到的只是一份普通签名。
既然要新立标准,原文顺手把几个与 Schnorr 本身无关的问题一并解决:签名改用定长 64 字节编码(ECDSA 的 DER 编码变长、最长可达 72 字节);公钥只编 x 坐标、32 字节(现行压缩公钥是 33 字节);支持批量验证;最重要的是字节级完全定义——验证算法在每个字节上都没有歧义,保证没人能造出“对部分验证者有效、对另一部分无效”的签名。ECDSA 的 DER 解析当年定义不严,酿成过真实问题,最后要靠 BIP-66 打补丁,原文明确以此为戒。
四、规则本身
4.1 最终方案的形状
签名是 (R, s) 对:验证等式为 s⋅G = R + hash(R ‖ P ‖ m)⋅P,其中 P 为公钥点、m 为消息、G 为曲线基点。原文在两种变体中选了 (R, s) 而非 (e, s),关键理由是 (R, s) 变体支持批量验证,且不必为了缩短签名而使用短哈希——短哈希的碰撞在多方协作签名场景下会被恶意共签者利用。
三项关键设计:
- 密钥前缀(key prefixing):挑战哈希的输入里放进公钥,即 hash(R ‖ P ‖ m)。这是为了防“相关密钥攻击”:没有前缀时,第三方可把对 P 的签名平移成对 P + a⋅G 的签名,这会击穿 BIP-32 的非硬化派生以及 Taproot 这类对密钥做加法微调(tweak)的构造;
- 只编 x 坐标:公钥与 R 都只取 x 坐标,y 坐标隐含取偶数那一个。这与现行 33 字节压缩公钥兼容性最好(等价于在 x-only 公钥前加上 0x02 前缀),原文同时论证了隐含 y 坐标并不降低安全性;
- 标签哈希(tagged hashes):所有哈希都用带标签的形式 hash_name(x) = SHA256(SHA256(tag) ‖ SHA256(tag) ‖ x),使不同用途的哈希互不串扰。本方案用到三个标签:BIP0340/aux、BIP0340/nonce、BIP0340/challenge。
4.2 编码
- 公钥:32 字节,即公钥点的 x 坐标;
- 签名:64 字节,前 32 字节是 R 的 x 坐标,后 32 字节是整数 s;
- 因此每个公钥对应两个私钥(d 与 n−d 给出同一个 x-only 公钥),签名算法内部会按 P 的 y 坐标奇偶把私钥规范化到 y 为偶数的那一个。
4.3 签名算法(默认)
原文给出的默认算法是确定性流程加一份“合成随机数”保险:把 32 字节辅助随机数据 a 经 BIP0340/aux 标签哈希后与私钥异或,再经 BIP0340/nonce 标签哈希(输入还包含公钥与消息)得到随机数材料,导出一次性值 k,并同样按 R 的 y 坐标奇偶规范化;挑战值 e 由 BIP0340/challenge 标签哈希算出,签名 s = k + e⋅d。输出前先自验一遍,验证失败即中止,以防计算错误泄露私钥信息。
要点有二:其一,随机性只是对侧信道与故障注入攻击的补充防线,方案的常规安全性质不依赖签名时随机数发生器的质量;其二,原文明确警告,默认算法(及任何确定性随机数生成方式)不能直接用于多签协议——MuSig2 等协议有自己的随机数要求,误用会不安全。其他产出合法签名的替代算法允许存在,但其随机数材料必须是全新、均匀随机且不可预测的,且不得跨签名方案复用同一私钥。
4.4 验证与批量验证
验证:由公钥 x 坐标经 lift_x 提升为 y 偶数的点 P;检查签名两半分别小于域大小 p 与曲线阶 n;算出挑战 e 与 R = s⋅G − e⋅P;当且仅当 R 非无穷远点、y 为偶数、且 x(R) 等于签名中的 r 时通过。
批量验证:多份签名可按随机系数线性组合后一次验证。全部合法时批量验证必然通过;只要有一份不合法,批量验证误放行的概率可忽略。系数由全部输入的哈希播种的密码学安全随机源确定性生成,以满足“批量结果不得与逐个验证实质不同”的字节级确定性要求。
4.5 消息长度与测试材料
现行规范接受任意长度的消息(早期修订曾限定恰为 32 字节,后已取消,变更记录在原文 Changelog);大消息出于性能考虑建议先预哈希。原文同时给出 CSV 格式的测试向量与纯 Python 参考实现(仅供演示,不可用于生产),以及应用消息的域分离(domain separation)最佳实践。
五、谁必须动
普通持币人:无直接动作。是否用上 Schnorr 签名,取决于钱包是否支持 Taproot 类输出;旧地址与旧交易分毫不变。
钱包与签名设备开发者:必须逐字节实现原文算法——公私钥规范化、标签哈希、随机数导出一步都不能自创;并用原文测试向量对拍。交互式多签场景不得套用默认签名算法的随机数生成。
全节点与验证者:在 BIP-341、BIP-342 的花费规则里调用本算法验签;可利用批量验证加速。
密码学协议开发者:MuSig2、门限签名、适配器签名等构造以本方案的线性与密钥前缀性质为前提,应按原文 Applications 一节的边界使用。
六、现在算不算数,以及一个常见误读
状态为 Deployed(已部署)。它已经作为 Taproot 的签名标准定稿:编码、签名、验证、批量验证全部字节级写死,并配有测试向量与参考实现,供各实现互操作。需要注意它自身的定位:BIP-340 是一份签名方案规范,本身不修改任何链上规则——真正在共识层启用它的是 BIP-341 与 BIP-342。
常见误读:
“BIP-340 之后,比特币把 ECDSA 淘汰了。”
不对。它新增了一套签名方案,而不是替换旧方案:存量输出类型(传统地址、SegWit v0 等)的 ECDSA 验证规则原封不动;Schnorr 签名只在 Taproot 花费中登场。同一条链上,两套签名体系按输出类型分工、长期并存。
七、延伸
- 阅读版:https://bips.dev/340
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
- 相关:BIP-341 Taproot 花费规则、BIP-342 Taproot 脚本验证、BIP-327 MuSig2 多签
- 仓库总目录:https://github.com/bitcoin/bips
