跳至主要內容
Informational Final

BIP-386: Taproot 描述符

定義 tr() 描述符函數,用於表示 Taproot (SegWit v1) 輸出。

Pieter Wuille, Andrew Chow 2021年6月27日
BIP 編號

386

類型

Informational

狀態

Final

創建日期

2021-06-27

摘要

BIP-386 定義了 tr() 描述符函數, 用於表示 Taproot(SegWit v1)輸出。它支援 key path spending 和帶有腳本樹的 script path spending, 生成 bc1p 開頭的 Bech32m 地址。

基本格式

簡單 Key Path

語法:tr(KEY)

只有內部密鑰,沒有腳本樹:

tr([d34db33f/86'/0'/0']xpub6ERApfZ.../0/*)

輸出腳本:
OP_1 <32-byte-tweaked-pubkey>

其中:
• OP_1 = 見證版本 1
• tweaked_pubkey = taproot_tweak(internal_pubkey, merkle_root=None)

地址:bc1p...(Bech32m 編碼)

帶腳本樹

語法:tr(KEY, TREE)

TREE 可以是:
• 單個腳本:tr(KEY, SCRIPT)
• 腳本對:tr(KEY, {SCRIPT_A, SCRIPT_B})
• 嵌套樹:tr(KEY, {SCRIPT_A, {SCRIPT_B, SCRIPT_C}})

範例:
tr(KEY_INTERNAL, {
  pk(KEY_A),
  {pk(KEY_B), pk(KEY_C)}
})

Merkle 樹結構:
        [root]
       /      \
   pk(A)    [branch]
            /      \
        pk(B)    pk(C)

x-only 公鑰

Taproot 使用 32 bytes 的 x-only 公鑰(省略 y 座標的符號位):

標準公鑰(33 bytes):
02 c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5
│  └─────────────────────── x 座標(32 bytes)───────────────────────┘
└─ 前綴(02 或 03 表示 y 座標的奇偶)

x-only 公鑰(32 bytes):
c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5
└─────────────────────── 只有 x 座標 ───────────────────────┘

在 tr() 中,密鑰會自動轉換為 x-only 格式

腳本類型

Tapscript 函數

描述符 腳本 說明
pk(KEY) <xonly_key> OP_CHECKSIG 單一密鑰簽章
multi_a(k, K...) <K1> CHECKSIG ... CHECKSIGADD ... k NUMEQUAL k-of-n 多簽
sortedmulti_a(k, K...) (同上,密鑰排序) 排序多簽

注意:multi_a vs multi

Tapscript 使用 multi_a() 而非 multi()。 這是因為 Tapscript 使用 OP_CHECKSIGADD 替代 OP_CHECKMULTISIG, 提供更好的批量驗證和更小的見證大小。

實際範例

BIP-86 錢包

標準 Taproot 單簽錢包:

tr([d34db33f/86'/0'/0']xpub6ERApfZ.../0/*)#checksum

派生路徑:m/86'/0'/0'/0/*
• 86' = BIP-86 用途(Taproot)
• 0' = 比特幣主網
• 0' = 第一帳戶
• 0 = 接收鏈
• * = 地址索引

生成地址:bc1p...

2-of-3 Taproot 多簽

使用腳本路徑的 2-of-3:

tr(KEY_INTERNAL, sortedmulti_a(2,
  [fp1/86'/0'/0']xpub1.../0/*,
  [fp2/86'/0'/0']xpub2.../0/*,
  [fp3/86'/0'/0']xpub3.../0/*
))

花費方式:
• Key path: 用 KEY_INTERNAL 簽章(如果它是某個多簽的聚合密鑰)
• Script path: 提供 2 個簽章 + Merkle proof

複雜腳本樹

混合花費條件:

tr(KEY_INTERNAL, {
  pk(KEY_HOT),                    // 熱錢包快速花費
  {
    pk(KEY_COLD),                 // 冷錢包備份
    multi_a(2, KEY_A, KEY_B, KEY_C)  // 3 人中 2 人的恢復
  }
})

樹結構:
         [root]
        /      \
    pk(HOT)   [branch]
              /      \
        pk(COLD)   multi_a(2,A,B,C)

Merkle 深度影響見證大小:
• pk(HOT): 1 個哈希的 proof
• pk(COLD): 2 個哈希的 proof
• multi_a: 2 個哈希的 proof

Key Path vs Script Path

Key Path

  • • 只需 64 bytes Schnorr 簽章
  • • 最小的見證大小
  • • 最低的費用
  • • 看起來像普通單簽
  • • 最佳隱私

Script Path

  • • 需要揭露腳本
  • • 需要 Merkle proof
  • • 見證較大
  • • 揭露使用的條件
  • • 支援任意條件

MuSig2 整合

對於多簽場景,可以結合 MuSig2 獲得最佳效率:

使用 MuSig2 聚合密鑰作為內部密鑰:

tr(MUSIG_AGGREGATE_KEY)

其中 MUSIG_AGGREGATE_KEY 是多個參與者公鑰的聚合。

優點:
• 看起來像單簽交易
• 最小的見證大小(64 bytes)
• 最佳隱私
• 參與者數量不可見

缺點:
• 需要交互式簽章協議
• 所有參與者必須在線

Bitcoin Core 範例

# 創建 Taproot 描述符錢包
$ bitcoin-cli createwallet "taproot_wallet" false false "" false true true

# 導入 tr() 描述符
$ bitcoin-cli -rpcwallet=taproot_wallet importdescriptors '[
  {
    "desc": "tr([d34db33f/86h/0h/0h]xpub.../0/*)#checksum",
    "timestamp": "now",
    "range": [0, 999],
    "internal": false
  },
  {
    "desc": "tr([d34db33f/86h/0h/0h]xpub.../1/*)#checksum",
    "timestamp": "now",
    "range": [0, 999],
    "internal": true
  }
]'

# 獲取 Taproot 地址
$ bitcoin-cli -rpcwallet=taproot_wallet getnewaddress "" "bech32m"
bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqzk5jj0

總結

BIP-386 定義的 tr() 函數是 Taproot 時代描述符的核心。 它支援從簡單的單簽到複雜的腳本樹,並生成 bc1p 開頭的 Bech32m 地址。 結合 MuSig2,Taproot 多簽可以達到與單簽相同的鏈上足跡,提供最佳的隱私和效率。

已複製連結
已複製到剪貼簿