比特币核心中对输出描述符的支持

  • bitcoin
  • 发布于 2024-01-06 19:17
  • 阅读 36

本文档详细介绍了比特币核心中Output Descriptors的使用方法。Output Descriptors是一种用于描述输出脚本集合的简单语言,Bitcoin Core从v0.17版本开始支持Output Descriptors,包括其特性、功能以及各种脚本类型的描述方式,并提供了大量示例和参考信息,以便开发者理解和使用。

Bitcoin Core 中对 Output Descriptor 的支持

自 Bitcoin Core v0.17 起,开始支持 Output Descriptor。这是一种简单的语言,可用于描述 output script 的集合。支持的 RPC 有:

  • scantxoutset 接受用于扫描的 descriptor 作为输入,并且还报告匹配的 UTXO 的专用 descriptor。
  • getdescriptorinfo 分析一个 descriptor,并报告一个添加了校验和的规范化版本。
  • deriveaddresses 接受一个 descriptor 作为输入,并计算相应的地址。
  • listunspent 为报告的未花费输出生成一个专用 descriptor。
  • getaddressinfo 为可解析的地址输出一个 descriptor(自 v0.18 起)。
  • generatetodescriptor 接受一个 descriptor 作为输入,并为其生成 coins(仅限 regtest,自 v0.19 起)。
  • utxoupdatepsbt 接受用于向 psbt 添加信息的 descriptor 作为输入(自 v0.19 起)。
  • createmultisigaddmultisigaddress 也返回 descriptor(自 v0.20 起)。
  • importdescriptors 接受要导入到 descriptor 钱包中的 descriptor 作为输入(自 v0.21 起)。
  • listdescriptors 输出导入到 descriptor 钱包中的 descriptor (自 v22 起)。
  • scanblocks 接受用于在区块中扫描的 descriptor 作为输入,并返回相关的 blockhash (自 v25 起)。
  • getdescriptoractivity 接受 descriptor 和 blockhash 作为输入(由 scanblocks 输出),并返回与给定 descriptor 关联的消费或接收相关的丰富事件数据。

Bitcoin Core v24 扩展了 wsh() output descriptor,支持 Miniscript(最初仅为观察模式)。Miniscript descriptor 的签名支持在 v25 中添加。并且从 v26 开始,Miniscript 表达式现在可以在 Taproot descriptor 中使用。

本文档描述了该语言。有关使用方法的具体信息,请参阅上述函数的 RPC 文档。

特性

Output Descriptor 目前支持:

  • 通过 pk 函数支持 Pay-to-pubkey scripts (P2PK)。
  • 通过 pkh 函数支持 Pay-to-pubkey-hash scripts (P2PKH)。
  • 通过 wpkh 函数支持 Pay-to-witness-pubkey-hash scripts (P2WPKH)。
  • 通过 sh 函数支持 Pay-to-script-hash scripts (P2SH)。
  • 通过 wsh 函数支持 Pay-to-witness-script-hash scripts (P2WSH)。
  • 通过 tr 函数支持 Pay-to-taproot outputs (P2TR)。
  • 通过 multi 函数支持 Multisig scripts。
  • 通过 sortedmulti 函数支持公钥按字典顺序排序的 Multisig scripts。
  • 通过 multi_a(和 sortedmulti_a)函数支持 taproot script trees 内的 Multisig scripts。
  • 通过 addr 函数支持任何类型的受支持地址。
  • 通过 raw 函数支持原始十六进制脚本。
  • 以十六进制表示的公钥(压缩和未压缩),或带有推导路径的 BIP32 扩展公钥。
  • Miniscript 表达式,位于 wsh (P2WSH) 和 tr (P2TR) 函数中。

例子

  • pk(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798) 描述了一个带有指定public key的 P2PK 输出。
  • pkh(02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5) 描述了一个带有指定public key的 P2PKH 输出。
  • wpkh(02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9) 描述了一个带有指定public key的 P2WPKH 输出。
  • sh(wpkh(03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556)) 描述了一个带有指定public key的 P2SH-P2WPKH 输出。
  • combo(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798) 描述了具有指定public key的任何 P2PK、P2PKH、P2WPKH 或 P2SH-P2WPKH 输出。
  • sh(wsh(pkh(02e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13))) 描述了一个(过于复杂的)带有指定public key的 P2SH-P2WSH-P2PKH 输出。
  • multi(1,022f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4,025cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc) 描述了一个具有指定顺序的密钥的裸 1-of-2 multisig 输出。
  • sh(multi(2,022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01,03acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe)) 描述了一个具有指定顺序密钥的 P2SH 2-of-2 multisig 输出。
  • sh(sortedmulti(2,03acd484e2f0c7f65309ad178a9f559abde09796974c57e714c35f110dfc27ccbe,022f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a01)) 描述了一个 P2SH 2-of-2 multisig 输出,其密钥在生成的 redeemScript 中按字典顺序排序。
  • wsh(multi(2,03a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7,03774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cb,03d01115d548e7561b15c38f004d734633687cf4419620095bc5b0f47070afe85a)) 描述了一个具有指定顺序密钥的 P2WSH 2-of-3 multisig 输出。
  • sh(wsh(multi(1,03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8,03499fdf9e895e719cfd64e67f07d38e3226aa7b63678949e6e49b241a60e823e4,02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e))) 描述了一个具有指定顺序密钥的 P2SH-P2WSH 1-of-3 multisig 输出。
  • pk(xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8) 描述了一个带有指定 xpub 的 public key 的 P2PK 输出。
  • pkh(xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw/1/2) 描述了一个带有指定 xpub 的子密钥 1/2 的 P2PKH 输出。
  • pkh([d34db33f/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*) 描述了一组 P2PKH 输出,但还指定指定的 xpub 是指纹为 d34db33f 的主密钥的子密钥,并使用路径 44'/0'/0' 导出。
  • wsh(multi(1,xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/1/0/*,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/0/0/*)) 描述了一组 1-of-2 P2WSH multisig 输出,其中第一个 multisig 密钥是第一个指定 xpub 的 1/0/i 子密钥,第二个 multisig 密钥是第二个指定 xpub 的 0/0/i 子密钥,并且 i 是可配置范围内的任何数字(默认为 0-1000)。
  • wsh(sortedmulti(1,xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/1/0/*,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/0/0/*)) 描述了一组 1-of-2 P2WSH multisig 输出,其中一个 multisig 密钥是第一个指定 xpub 的 1/0/i 子密钥,另一个 multisig 密钥是第二个指定 xpub 的 0/0/i 子密钥,并且 i 是可配置范围内的任何数字(默认为 0-1000)。生成的 witnessScripts 中 public key 的顺序由该索引处 public key 的字典顺序决定。
  • tr(c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5,{pk(fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556),pk(e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13)}) 描述了一个 P2TR 输出,其 c6... x-only public key 作为内部密钥,以及两个 script paths。
  • tr(c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5,sortedmulti_a(2,2f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4,5cbdf0646e5db4eaa398f365f2ea7a0e3d419b7e0330e39ce92bddedcac4f9bc)) 描述了一个 P2TR 输出,其 c6... x-only public key 作为内部密钥,以及一个需要 2 个签名的单个 multi_a 脚本,该脚本具有 2 个指定的 x-only 密钥,这些密钥将按字典顺序排序。
  • wsh(sortedmulti(2,[6f53d49c/44h/1h/0h]tpubDDjsCRDQ9YzyaAq9rspCfq8RZFrWoBpYnLxK6sS2hS2yukqSczgcYiur8Scx4Hd5AZatxTuzMtJQJhchufv1FRFanLqUP7JHwusSSpfcEp2/0/*,[e6807791/44h/1h/0h]tpubDDAfvogaaAxaFJ6c15ht7Tq6ZmiqFYfrSmZsHu7tHXBgnjMZSHAeHSwhvjARNA6Qybon4ksPksjRbPDVp7yXA1KjTjSd5x18KHqbppnXP1s/0/*,[367c9cfa/44h/1h/0h]tpubDDtPnSgWYk8dDnaDwnof4ehcnjuL5VoUt1eW2MoAed1grPHuXPDnkX1fWMvXfcz3NqFxPbhqNZ3QBdYjLz2hABeM9Z2oqMR1Gt2HHYDoCgh/0/*))#av0kxgw0 描述了一个 2-of-3 multisig。为了简洁起见,此处未包含伴随上述外部“接收” descriptor 的内部“找零” descriptor,但它通常仅在 xpub 派生步骤中有所不同,以 /1/* 结尾作为找零地址。
  • wsh(thresh(4,pk([7258e4f9/44h/1h/0h]tpubDCZrkQoEU3845aFKUu9VQBYWZtrTwxMzcxnBwKFCYXHD6gEXvtFcxddCCLFsEwmxQaG15izcHxj48SXg1QS5FQGMBx5Ak6deXKPAL7wauBU/0/*),s:pk([c80b1469/44h/1h/0h]tpubDD3UwwHoNUF4F3Vi5PiUVTc3ji1uThuRfFyBexTSHoAcHuWW2z8qEE2YujegcLtgthr3wMp3ZauvNG9eT9xfJyxXCfNty8h6rDBYU8UU1qq/0/*),s:pk([4e5024fe/44h/1h/0h]tpubDDLrpPymPLSCJyCMLQdmcWxrAWwsqqssm5NdxT2WSdEBPSXNXxwbeKtsHAyXPpLkhUyKovtZgCi47QxVpw9iVkg95UUgeevyAqtJ9dqBqa1/0/*),s:pk([3b1d1ee9/44h/1h/0h]tpubDCmDTANBWPzf6d8Ap1J5Ku7J1Ay92MpHMrEV7M5muWxCrTBN1g5f1NPcjMEL6dJHxbvEKNZtYCdowaSTN81DAyLsmv6w6xjJHCQNkxrsrfu/0/*),sln:after(840000),sln:after(1050000),sln:after(1260000)))#k28080kv 描述了一个 Miniscript multisig,其消费策略为:thresh(4,pk(key_1),pk(key_2),pk(key_3),pk(key_4),after(t1),after(t2),after(t3)),它从 4-of-4 开始,并在每个未来的减半区块高度“衰减”为 3-of-4、2-of-4,最后为 1-of-4。为了简洁起见,此处未包含伴随上述外部“接收” descriptor 的内部“找零” descriptor,但它通常仅在 xpub 派生步骤中有所不同,以 /1/* 结尾作为找零地址。

参考

Descriptor 由几种类型的表达式组成。顶层表达式是 SCRIPT,或者 SCRIPT#CHECKSUM,其中 CHECKSUM 是一个 8 个字符的字母数字 descriptor 校验和。

SCRIPT 表达式:

  • sh(SCRIPT)(仅限顶层):P2SH 嵌入参数。
  • wsh(SCRIPT)(仅限顶层或 sh 内部):P2WSH 嵌入参数。
  • pk(KEY)(任何位置):给定 public key 的 P2PK 输出。
  • pkh(KEY)(不在 tr 内部):给定 public key 的 P2PKH 输出(如果你只知道 public key hash,请使用 addr)。
  • wpkh(KEY)(仅限顶层或 sh 内部):给定压缩 public key 的 P2WPKH 输出。
  • combo(KEY)(仅限顶层):pk(KEY)pkh(KEY) 的集合的别名。如果密钥被压缩,它还包括 wpkh(KEY) 和 `sh(wpkh(KEY))”。
  • multi(k,KEY_1,KEY_2,...,KEY_n)(不在 tr 内部):使用 OP_CHECKMULTISIG 的 k-of-n multisig script。
  • sortedmulti(k,KEY_1,KEY_2,...,KEY_n)(不在 tr 内部):k-of-n multisig script,其中密钥在生成的脚本中按字典顺序排序。
  • multi_a(k,KEY_1,KEY_2,...,KEY_N)(仅在 tr 内部):使用 OP_CHECKSIG、OP_CHECKSIGADD 和 OP_NUMEQUAL 的 k-of-n multisig script。
  • sortedmulti_a(k,KEY_1,KEY_2,...,KEY_N)(仅在 tr 内部):与 multi_a 类似,但其中的(x-only)公钥将按字典顺序排序。
  • tr(KEY)tr(KEY,TREE)(仅限顶层):P2TR 输出,其指定密钥作为内部密钥,并可选择 script paths 树。
  • addr(ADDR)(仅限顶层):ADDR 扩展到的脚本。
  • raw(HEX)(仅限顶层):十六进制编码为 HEX 的脚本。
  • rawtr(KEY) (仅限顶层): P2TR 输出,使用指定的 KEY 作为输出密钥。注意:虽然可以使用这个来构建钱包,但是它有一些缺点,比如无法证明不存在隐藏的 script path。使用风险自负。

KEY 表达式:

  • 可选地,密钥来源信息,包括:
    • 一个左方括号 [
    • 密钥开始派生的位置的密钥指纹的精确 8 个十六进制字符(有关详细信息,请参见 BIP32)
    • 后跟零个或多个 /NUM/NUM' 路径元素,以指示指纹和后面的密钥或 xpub/xprv 根之间的非硬化或硬化派生步骤
    • 一个右方括号 ]
  • 后跟实际的密钥,可以是:
    • 十六进制编码的公钥(压缩公钥为 66 个字符,以 0203 开头,或者未压缩公钥为 130 个字符,以 04 开头)。
    • wpkhwsh 内部,仅允许压缩的公钥。
    • trrawtr 内部,也允许使用 x-only 公钥(64 个十六进制字符)。
    • 可以指定 WIF 编码的私钥来代替相应的公钥,含义相同。
    • xpub 编码的扩展公钥或 xprv 编码的扩展私钥(如 BIP 32 中定义)。
    • 后跟零个或多个 /NUM 非硬化和 /NUM' 硬化 BIP32 派生步骤。
      • 这些派生步骤中,最多只能有一个采用 <NUM;NUM;...;NUM> 的形式(包括带有任一或两个 NUM 的硬化指示符)。如果包含此类说明符,则会将 descriptor 解析为多个 descriptor,其中第一个 descriptor 对所有 KEY 表达式使用该对中的所有第一个 NUM,第二个 descriptor 对所有 KEY 表达式使用该对中的第二个 NUM,依此类推。
    • 可选地,后跟一个 /*/*' 最终步骤,表示所有(直接)非硬化或硬化的子密钥。
    • 使用硬化派生步骤需要提供私钥。

(任何允许使用 ' 后缀表示硬化派生的位置,都可以使用后缀 h 代替。)

TREE 表达式:

  • 任何 SCRIPT 表达式
  • 左大括号 {、一个 TREE 表达式、一个逗号 ,、一个 TREE 表达式和一个右大括号 }

ADDR 表达式是任何类型的受支持地址:

  • P2PKH 地址(base58,对于主网,形式为 1...,对于测试网,形式为 [nm]...)。请注意,descriptor 中的 P2PKH 地址不能用于 P2PK 输出(请改用 pk 函数)。
  • P2SH 地址(base58,对于主网,形式为 3...,对于测试网,形式为 2...,在 BIP 13 中定义)。
  • Segwit 地址(bech32 和 bech32m,对于主网,形式为 bc1...,对于测试网,形式为 tb1...,在 BIP 173BIP 350 中定义)。

说明

单密钥脚本

实际上,许多单密钥结构被使用,通常包括 P2PK、P2PKH、P2WPKH 和 P2SH-P2WPKH。可以想象出更多的组合,尽管它们可能不是最佳的:P2SH-P2PK、P2SH-P2PKH、P2WSH-P2PK、P2WSH-P2PKH、P2SH-P2WSH-P2PK、P2SH-P2WSH-P2PKH。

为了描述这些,我们将这些建模为函数。函数 pk (P2PK)、pkh (P2PKH) 和 wpkh (P2WPKH) 接受一个 KEY 表达式作为输入,并返回相应的 scriptPubKey。函数 sh (P2SH) 和 wsh (P2WSH) 接受一个 SCRIPT 表达式作为输入,并返回描述 P2SH 和 P2WSH 的脚本,并将输入作为嵌入脚本。这些函数的名称不包含 "p2" 以保持简洁。

Multisig

一些软件使用基于 Bitcoin 的 OP_CHECKMULTISIG 操作码的多签名(multisig)脚本。为了支持这些,我们引入了 multi(k,key_1,key_2,...,key_n)sortedmulti(k,key_1,key_2,...,key_n) 函数。它们表示 k-of-n multisig 策略,其中必须由 n 个提供的 KEY 表达式中的任何 k 个签名。

密钥顺序对于 multi() 很重要。multi() 表达式描述了一个 multisig 脚本,其密钥顺序已指定,并且在搜索 TXO 时,它将不匹配具有相同密钥但顺序不同的 multisig scriptPubKey 的输出。此外,为了防止搜索空间的组合爆炸,如果 multi() 密钥参数中超过一个是 BIP32 通配符路径,以 /**' 结尾,则 multi() 表达式仅匹配来自每个通配符路径的第 i 个子密钥按步调一致的 multisig 脚本,而不是来自每个通配符路径的子密钥的任意组合的脚本。

密钥顺序对于 sortedmulti() 无关紧要。sortedmulti() 的行为方式与 multi() 相同,但密钥在生成的脚本中重新排序,以便按照 BIP67 中的描述按字典顺序排序。

基本 multisig 示例

有关在多个参与者之间使用 descriptor 钱包和 PSBT 的基本 M-of-N multisig 以及签名流程的一个很好的示例,请参阅 此功能测试

免责声明:重要的是要注意,此示例用作快速入门,并为了便于阅读而保持基本状态。此处概述的方法的一个缺点是,每个参与者都必须维护(和备份)两个单独的钱包:签名者和相应的 multisig。还应注意的是,隐私最佳实践在这里不是“默认”的 - 参与者应注意仅使用签名者来签署与我们要创建的相应 multisig 相关的交易。最后,不建议使用 Bitcoin Core descriptor 钱包以外的任何其他钱包来用作你的签名者。其他钱包,无论是硬件还是软件,都可能施加额外的检查和保护措施,以防止用户签署可能导致资金损失或被视为安全隐患的交易。符合各种第三方检查和验证不在此示例的范围内。

基本步骤是:

  1. 每个参与者生成一个 xpub。最直接的方法是创建一个新的 descriptor 钱包,我们将其称为参与者的签名者钱包。避免将此钱包重新用于除签署我们要创建的相应 multisig 交易之外的任何目的。提示:使用 listdescriptors 提取钱包的 xpub,并从 pkh descriptor 中选择一个,因为它最不可能被意外重用(旧版地址)
  2. 创建一个仅观察 descriptor 钱包(空白,私钥已禁用)。现在,通过导入外部和内部 descriptor 来创建 multisig:wsh(sortedmulti(<M>,XPUB1/0/*,XPUB2/0/*,…,XPUBN/0/*))wsh(sortedmulti(<M>,XPUB1/1/*,XPUB2/1/*,…,XPUBN/1/*)) (一个带有 0 用于接收地址的 descriptor,另一个带有 1 用于零钱)。每个参与者都这样做。所有密钥来源信息(主密钥指纹和所有派生步骤)都应包含在 xpub 中,以便正确支持硬件设备/外部签名者
  3. 为 multisig 生成一个接收地址。作为检查以确保步骤 2 正确完成,每个参与者应验证他们获得了相同的地址
  4. 资金被发送到生成的地址
  5. 使用 walletcreatefundedpsbt 创建来自 multisig 的发送交易(任何人都可以启动此操作)。在 GUI 中,转到 multisig 钱包中的“发送”选项卡并创建一个未签名交易(PSBT)即可轻松完成此操作
  6. 至少 M 位参与者在签署之前使用 decodepsbt 通过其 multisig 检查 PSBT,以验证交易是否可以。
  7. (如果可以)参与者使用 walletprocesspsbt 使用其签名者钱包签署 PSBT。在 GUI 中,从文件加载 PSBT 并对其进行签名即可轻松完成此操作
  8. 使用 combinepsbt 收集已签名的 PSBT,使用 finalizepsbt 进行最终确定,然后将生成的交易广播到网络。请注意,任何钱包(例如签名者或 multisig 之一)都可以执行此操作。
  9. 检查在交易包含在一个区块中后余额是否正确

你可能更喜欢菊花链签名流程,其中每个参与者一个接一个地签署 PSBT,直到 PSBT 被签名 M 次并且“完成”。在大多数情况下,上面的步骤保持不变,除了 (6, 7) 略有变化,从并行签署原始 PSBT 更改为按顺序签署 PSBT。使用此签名流程不需要 combinepsbt,最后一个 ( m th) 签名者可以在签名后广播 PSBT。请注意,在有更多签名者的情况下,并行签名流程可能是更可取的。此签名流程也包含在测试/ Python 示例中。 该测试 的目的是既是文档又是功能测试,因此尽可能保持简单和可读性。

基本支持 Miniscript 的“衰减” multisig 示例

有关从 4-of-4 开始并在每个未来的减半区块高度“衰减”为 3-of-4、2-of-4,最后为 1-of-4 的 multisig 示例,请参阅 此功能测试

它具有与上述 基本 multisig 示例 相同的“架构”和签名流程。基本步骤是相同的,除了定义此钱包的 descriptor 之外,该 descriptor 的形式为:wsh(thresh(4,pk(XPUB1),s:pk(XPUB2),s:pk(XPUB3),s:pk(XPUB4),sln:after(t1),sln:after(t2),sln:after(t3)))

该测试 的目的是既是文档又是功能测试,因此尽可能保持简单和可读性。

BIP32 派生密钥和链

大多数现代钱包软件和硬件都使用使用 BIP32(“HD 密钥”)派生的密钥。我们通过允许字符串直接支持这些,这些字符串包括扩展的公共密钥(通常称为 xpub)以及在任何需要公共密钥的地方的派生路径。派生路径由一系列 0 个或多个整数(范围为 0..2<sup>31</sup>-1)组成,每个整数可选地后跟 'h,并用 / 字符分隔。字符串可以选择以字面量 /*/*'(或 /*h)结尾,以引用可配置范围内的所有非硬化或硬化子密钥(默认情况下为 0-1000,包括)。

每当使用硬化派生步骤描述公共密钥时,如果没有对相应私钥的访问权限,则无法计算脚本。

密钥来源识别

为了描述其签名密钥位于另一个设备上的脚本,可能需要识别 xpub 派生的主密钥和派生路径。

例如,当遵循 BIP44 时,直接将更改链描述为 xpub.../44'/0'/0'/1/* 将会很有用,其中 xpub... 对应于主密钥 m。不幸的是,由于在 xpub 之后有硬化派生步骤,因此如果没有对相应私钥的访问权限,则此 descriptor 不允许你计算脚本。而是应将其编写为 xpub.../1/*,其中 xpub 对应于 m/44'/0'/0'

与硬件设备交互时,可能需要包括从主密钥下来的整个路径。BIP174 通过提供主密钥指纹(主公钥的 Hash160 的前 32 位)以及所有派生步骤来对此进行标准化。为了支持构造这些密钥,我们允许在 descriptor 语言中提供此密钥来源信息,即使它不影响它所引用的实际 scriptPubKey。 每个公钥都可以添加一个8个字符的十六进制指纹前缀,加上可选的推导步骤(固化非固化),用括号括起来,用于标识密钥或xpub是由哪个master和推导路径推导出来的。

请注意,父节点的指纹仅用作在软件中快速检测父节点和子节点的方法,并且软件必须能够处理冲突。

包含私钥

通常,将脚本的描述与必要的私钥一起传递非常有用。因此,只要支持公钥或xpub的地方,都可以提供WIF格式的私钥或xprv。当私钥对于固化推导步骤,签名交易或转储包括私钥材料的钱包描述符是必需的时,这非常有用。

例如,在将以下2-of-3多重签名描述符导入钱包后,可以使用signrawtransactionwithwallet来使用第一个密钥对交易进行签名:

sh(multi(2,xprv.../84'/0'/0'/0/0,xpub1...,xpub2...))

请注意,第一个密钥是具有特定推导路径的xprv私钥,而其他两个是公钥。

在一个描述符中指定接收和更改描述符

由于接收地址和更改地址通常是从同一个扩展密钥推导而来,但只有一个推导索引发生了更改,因此可以指定一个可以在两个不同索引处推导的描述符会很方便。因此,在扩展密钥之后的每个推导路径中,都允许使用单个索引元组。当解析此描述符时,将生成多个描述符,第一个将为所有密钥表达式使用元组中的第一个索引,第二个将使用第二个索引,第三个将使用第三个索引,依此类推。

例如,以下形式的描述符:

multi(2,xpub.../&lt;0;1;2>/0/*,xpub.../&lt;2;3;4>/*)

将扩展为3个描述符

multi(2,xpub.../0/0/*,xpub.../2/*)
multi(2,xpub.../1/0/*,xpub.../3/*)
multi(2,xpub.../2/0/*,xpub.../4/*)

当此元组仅包含两个元素时,钱包实现可以使用第一个描述符作为接收地址,第二个描述符作为更改地址。

与旧钱包的兼容性

为了轻松表示现有比特币核心钱包当前支持的脚本集,提供了一个方便的函数combo,该函数以公钥作为输入,并描述该密钥的一组P2PK,P2PKH,P2WPKH和P2SH-P2WPKH脚本。如果密钥未压缩,则该集合仅包括P2PK和P2PKH脚本。

校验和

描述符可以选择在其后附加校验和,以防止输入错误或复制粘贴错误。

这些校验和由8个字母数字字符组成。只要错误仅限于将0123456789()[],'/*abcdefgh@:$%{}中的字符替换为该集合中的其他字符,并更改字母大小写,则在501个字符以内的描述符中,最多可以检测到4个错误,而在更长的描述符中,最多可以检测到3个错误。对于大量错误或其他类型的错误,大约有万亿分之一的机会无法检测到这些错误。

比特币核心中的所有RPC都将在其输出中包含校验和。只有某些RPC需要在输入中提供校验和,包括deriveaddressesimportdescriptors。可以使用getdescriptorinfo RPC计算没有校验和的描述符的校验和。

  • 原文链接: github.com/bitcoin/bitco...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
bitcoin
bitcoin
江湖只有他的大名,没有他的介绍。