协议演进 / BIP/比特币改进提案 / BIP-379
BIP-379
为比特币脚本定义一种结构化子集语言 Miniscript,让签名、哈希锁与时间锁组合成的花费条件可分析、可组合、可通用签名,并能预先推算花费成本。本 BIP 目前处于草案状态。
一、档案卡
| 编号 | BIP-379 |
|---|---|
| 标题 | Miniscript |
| 作者 | Pieter Wuille <[email protected]>, Andrew Poelstra <[email protected]>, Sanket Kanjalkar <[email protected]>, Antoine Poinsot <[email protected]>, Ava Chow <[email protected]> |
| 指定日期 | 2023-10-10 |
| 层级 | Applications(应用) |
| 类型 | Specification(规范类) |
| 状态 | Draft(草案) |
| 依赖 | BIP-380 |
| 阅读版 | https://bips.dev/379 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0379.md |
二、放在哪一族
描述符与脚本分析族,位置在输出脚本描述符之上、具体花费策略之下。
BIP-380 定义描述符的通用语法与密钥表达式;Miniscript 的密钥表达式直接沿用它,所以本 BIP 在档案上依赖 BIP-380。
Miniscript 本身不是独立于描述符之外的另一套语言。从使用者的角度看,它是描述符语言的一次重大扩展:片段预期用在 BIP-382 的 wsh() 描述符与 BIP-386 的 tr() 描述符里,分别对应 P2WSH 与 Tapscript 两种上下文。
它处理的脚本范围也由这两类上下文决定:适用于 P2WSH(见 BIP-141)与 Tapscript(见 BIP-342),两者只有细微差别;P2SH 与裸脚本被明确排除在外。
三、它要解决什么
比特币脚本是一种基于栈的语言,边角情形很多。它要表达的花费条件,无非是签名、哈希锁、时间锁的各种组合。但即便功能有限,下面这些事仍然很难做:
- 给定一组花费条件,找出实现它的最省的脚本;
- 给定两个脚本,拼出一个实现两者条件组合的新脚本(例如多签里的一把“钥匙”本身又是另一个多签);
- 给定一个脚本,反推出它到底允许哪些花费方式;
- 给定一个脚本、再拿到足够的一组私钥,通用地构造出满足它的见证(witness);
- 给定一个脚本,预先算出花费一笔输出要付出的成本;
- 判断花费时是否会撞上操作数上限等资源限制。
原文的办法不是再发明一套脚本,而是给脚本加一层结构化表示:只收录能安全、正确组合的片段,并为每个片段配上明确的语义与类型。这样,上面的分析、组合与通用签名才有可能由程序自动完成;花费策略编译器也可以把策略编译到 Miniscript;与之兼容的既有脚本还能转回 Miniscript 形式,签名设备等就不必再靠额外元数据才能理解它。
四、规则本身
4.1 片段与包装器
Miniscript 由一组片段(fragment)组成。普通片段写作 fragment(arg1,arg2,...);不改变子表达式语义的片段叫包装器(wrapper),写作前缀加冒号,如 dv:older(144) 表示先给 older(144) 套 v:、再套 d:,相邻包装器之间的冒号可省略。
主要片段按语义可分几组:
- 常量与签名检查:
0(假)、1(真)、pk_k(key)、pk_h(key),以及语法糖pk(key)、pkh(key); - 时间锁:
older(n)对应<n> CHECKSEQUENCEVERIFY(相对锁定),after(n)对应<n> CHECKLOCKTIMEVERIFY(绝对锁定),均要求 1 ≤ n < 2³¹; - 哈希锁:
sha256(h)、hash256(h)、ripemd160(h)、hash160(h),都要求原像长度恰为 32 字节,再比对哈希; - 逻辑组合:
andor(X,Y,Z)、and_v(X,Y)、and_b(X,Y)、and_n(X,Y)、or_b(X,Z)、or_c(X,Z)、or_d(X,Z)、or_i(X,Z); - 门限:
thresh(k,X_1,...,X_n),要求 n 个子条件中恰好满足 k 个; - 多签:
multi(k,key_1,...,key_n)只用于 P2WSH,对应CHECKMULTISIG,要求 1 ≤ k ≤ n ≤ 20;multi_a(k,key_1,...,key_n)只用于 Tapscript,对应逐个CHECKSIG再CHECKSIGADD累加比对。
包装器包括 a:、s:、c:、d:、v:、j:、n:,以及语法糖 t:、l:、u:。它们负责在栈上搬移、校验或转换子表达式的结果形态,是片段能严丝合缝拼起来的关键。
4.2 正确性类型系统
不是任意片段都能和任意片段相接。为此原文定义了四个基本类型:B(base,结果留在栈顶)、V(verify,只校验、不留结果,不满足就中止)、K(key,只把公钥压栈、还差一步签名)、W(wrapped,从栈顶下一层取输入)。
再加五个正确性修饰符:z(恰好吃 0 个栈元素)、o(恰好吃 1 个)、n(至少吃 1 个且满足时不要求栈顶为零)、d(可不满足,即能无条件构造出“不满足”的解法)、u(满足时栈上留下的恰好是 1)。每个片段对子表达式的类型有明确要求,达不到要求的表达式根本不是合法 Miniscript。
还有一条额外规则:四种时间锁(绝对高度、绝对时间、相对高度、相对时间)不得以不兼容的方式混用。在 and 类组合器与 k ≥ 2 的 thresh 中,高度型与时间型不得同类混杂;绝对与相对之间则始终可以混用。
4.3 可锻性分析与满足算法
原文再引入三个可锻性(malleability)修饰符:s(满足必然需要签名)、f(不满足必然需要签名)、e(expressive,存在唯一的无条件不满足解法)。据此可以静态判断:一个脚本在任何情况下能否被非可锻地满足——也就是没有私钥的第三方无法把一份有效见证改造成另一份有效见证。
在此基础上,原文给出“非可锻满足算法”:递归求各子表达式的最优满足与不满足解法,按 HASSIG(解法中是否含签名)标记筛选,排除非规范(non-canonical)与过度满足的选项,最后取见证体积最小者;若顶层无解、结果为 DONTUSE,或用到了时间锁却没有签名参与,则失败。
4.4 安全目标与资源限制
原文为 Miniscript 定的安全目标主要有:共识健全性(不满足花费条件就不可能构造出共识有效的见证)、标准性完备性(在资源限制内、且无时间锁混用时,每条花费路径都能构造出符合标准性的见证),外加见证的非可锻性与最大体积可预测。哈希原像被限定为 32 字节,也是为了堵住若干骚扰与跨链交换等滥用,并让满足成本能算准。
资源限制需单独核查,例如:P2WSH 脚本超过 3600 字节不符合标准性;P2WSH 满足时非压栈操作码数加参与 CHECKMULTISIG 的钥匙数超过 201 会触及共识上限;执行中栈元素不得超过 1000。静态分析可以判断各条花费路径是否会撞上这些限制。
五、谁必须动
普通持币人:不必直接写 Miniscript。它的价值经由钱包与签名设备体现:花费条件写得更复杂时,仍能被正确分析与签名。
钱包开发者:若要支持 P2WSH 或 Tapscript 下的复杂花费条件,需实现片段的解析、类型检查、编译为脚本,以及非可锻满足算法;密钥表达式按 BIP-380 处理,并遵守 wsh()、tr() 上下文对密钥的限制。
签名设备与协同签名方:支持 Miniscript 后,可依据结构本身判断脚本允许什么、花哪条路径,而不必依赖发起方另附的元数据。
全节点与矿工:无须改动。Miniscript 编译出的仍是原有的 P2WSH / Tapscript 脚本,共识与标准性规则不变。
六、现在算不算数,以及一个常见误读
状态为 Draft(草案)。原文记载了参考实现的落地情况:P2WSH 版 Miniscript 经 Bitcoin Core 的若干 PR 合入,随 Bitcoin Core 25.0 发布;Tapscript 版经 PR 27255 合入,随 Bitcoin Core 26.0 发布。但“已有实现”与“BIP 状态已定稿”是两回事,阅读时以仓库当前标注的 Draft 为准。
它的实际意义不在改规则,而在把一类原本只能靠人工逐案处理的脚本,变成可自动分析的工件:条件是什么、哪条路径最便宜、见证最大能有多大、会不会被第三方篡改,都可以在签名前算清。
常见误读:
“Miniscript 是一种新的链上脚本语言,要靠升级比特币才能用。”
不对。它是对既有脚本的一个子集的结构化表示,编译结果仍是 P2WSH 与 Tapscript 里原有的脚本,不新增操作码、不改共识。原文还明确把 P2SH 与裸脚本排除在外,不能拿它去描述这两类输出。
七、延伸
- 阅读版:https://bips.dev/379
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0379.md
- 相关:BIP-380 描述符通用操作、BIP-382 Segwit 描述符、BIP-386
tr()描述符、BIP-141 SegWit、BIP-342 Tapscript 验证 - 仓库总目录:https://github.com/bitcoin/bips
