协议演进 / BIP/比特币改进提案 / BIP-382
BIP-382
定义 wpkh() 与 wsh() 两种输出脚本描述符表达式,分别用一个密钥或一段脚本生成 P2WPKH 与 P2WSH 输出脚本。本 BIP 目前处于已部署状态。
一、档案卡
| 编号 | BIP-382 |
|---|---|
| 标题 | Segwit Output Script Descriptors |
| 作者 | Pieter Wuille <[email protected]>, Ava Chow <[email protected]> |
| 指定日期 | 2021-06-27 |
| 层级 | Applications(应用) |
| 类型 | Specification(规范类) |
| 状态 | Deployed(已部署) |
| 依赖 | BIP-380 |
| 阅读版 | https://bips.dev/382 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0382.mediawiki |
二、放在哪一族
输出脚本描述符族中负责 Segwit 格式的一篇。通用语法、校验和与密钥表达式都在 BIP-380,本 BIP 在档案上依赖它,只新增两个脚本表达式。
同族分工是:
BIP-381:pk()、pkh()、sh(),对应非 Segwit 格式
BIP-382(本篇):wpkh()、wsh(),对应 SegWit 新增的两种标准输出格式
BIP-383:multi()、sortedmulti() 多签表达式,其脚本常被放进本篇的 wsh() 里
BIP-379:Miniscript,其片段预期用在 wsh() 描述符中——本篇是 Miniscript 落到 P2WSH 的入口
BIP-384:combo(),其 P2WPKH 与 P2SH-P2WPKH 两项正是复用本篇的 wpkh() 与 sh(wpkh()) 组合
三、它要解决什么
隔离见证(SegWit,见 BIP-141)新增了两种主要标准输出格式:P2WPKH 与 P2WSH。钱包要备份、导出、恢复这两类输出,同样需要把“用哪把钥匙、套哪种格式”写进描述符。
原文的动机只有一句话:这些表达式让上述格式能以描述符的形式被指定。通用背景——只存私钥不足以恢复 SegWit 钱包、须把脚本类型与派生路径写显式——见 BIP-380。事实上 BIP-380 特意点明:备份不足的问题正是 SegWit 引入新输出类型后变得突出的;本篇补的就是 SegWit 这一半的描述能力。
四、规则本身
两个新脚本表达式:wpkh()、wsh()。参数与密钥表达式的通用写法见 BIP-380。
4.1 wpkh()
wpkh(KEY) 可作顶层表达式,也可放在 sh() 里面(即 P2SH 嵌套的 P2WPKH,地址以 3 开头的那一类)。它取一个密钥表达式,生成 P2WPKH 输出脚本:
OP_0 <KEY_hash160>
即版本号 OP_0 加公钥的 HASH160 哈希,花费规则与 P2PKH 类似,但签名等见证数据放在 witness 中。一条硬限制:wpkh() 里只能放压缩公钥的钥匙——钥匙本身是压缩公钥、或派生后得到压缩公钥;放入非压缩公钥(例如未压缩 WIF 私钥或以 04 开头的公钥)的描述符无效。
4.2 wsh()
wsh(SCRIPT) 可作顶层表达式,也可放在 sh() 里面。它取一个脚本表达式,生成 P2WSH 输出脚本:
OP_0 <SCRIPT_sha256>
即版本号 OP_0 加内层脚本的 SHA256 哈希。同时它还产生一个 witnessScript——就是参数 SCRIPT 生成的那段脚本本身;花费时必须出示它并满足它,作用相当于 P2SH 的 redeemScript 在 SegWit 下的对应物。
限制有两条:其一,wsh() 内部任何位置出现的密钥表达式,都只能产生压缩公钥;其二,嵌套有禁区——wpkh() 不能放进 wsh(),wsh() 不能再套 wsh(),wsh() 的参数必须是脚本表达式而不能直接是钥匙。原文把这些组合逐一列为无效描述符。
与 BIP-381 对照着看,分工很清楚:sh() 包的是 HASH160、产物在 scriptSig 里交 redeemScript;wsh() 包的是 SHA256、产物在 witness 里交 witnessScript。
五、谁必须动
普通持币人:无直接变化。使用原生 SegWit 地址的钱包,可以用 wpkh()、wsh() 把收款脚本写成可备份、可迁移的描述符。
钱包开发者:实现描述符时需支持这两个表达式,严格执行压缩公钥限制与嵌套禁区;使用 wsh() 时必须同时保存 witnessScript,否则日后无法花费;生成多签或 Miniscript 输出时,内层脚本经 wsh() 包好再交给上层。
全节点与矿工:无须改动。生成的 P2WPKH、P2WSH 都是 SegWit 既有的标准脚本,共识规则不变。
六、现在算不算数,以及一个常见误读
状态为 Deployed(已部署)。原文记载:wpkh()、wsh() 描述符自 Bitcoin Core 0.17 起已有实现。它们采用 BIP-380 的格式与通用操作;作为全新描述符,它们与此前任何实现并不兼容,但生成的脚本都是标准脚本,既有软件对这些脚本本身并不陌生。
常见误读:
“wpkh() 和 pkh() 差不多,钥匙随便放哪种格式都行。”
不对。原文为 SegWit 表达式单列了压缩公钥限制:wpkh() 中只能用压缩公钥,wsh() 内部所有钥匙也只能产生压缩公钥,放入非压缩公钥的描述符直接判为无效。这不是写法偏好,而是规范的一部分,实现若不校验,就会生成与别的钱包对不上的结果。
七、延伸
- 阅读版:https://bips.dev/382
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0382.mediawiki
- 相关:BIP-380 描述符通用操作、BIP-381 非 Segwit 描述符、BIP-383 多签描述符、BIP-384
combo()描述符、BIP-379 Miniscript、BIP-141 SegWit 共识层 - 仓库总目录:https://github.com/bitcoin/bips
