Informational Final
BIP-383: 多簽描述符
定義 multi() 和 sortedmulti() 描述符函數,用於多重簽章腳本。
Pieter Wuille, Andrew Chow 2021年6月27日
BIP 編號
383
類型
Informational
狀態
Final
創建日期
2021-06-27
摘要
BIP-383 定義了兩個用於多重簽章(multisig)的描述符函數:
multi() 和
sortedmulti()。
這些函數用於構建需要多個密鑰中的 k 個進行簽章的腳本。
multi() — 標準多簽
格式
語法:multi(k, KEY1, KEY2, ..., KEYn) 參數: • k = 所需簽章數量(閾值) • KEY1...KEYn = 參與的公鑰(n 個) 生成的腳本: OP_k <pubkey1> <pubkey2> ... <pubkeyn> OP_n OP_CHECKMULTISIG 範例(2-of-3): multi(2, 02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5, 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798, 02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9 )
腳本結構
2-of-3 多簽腳本(裸腳本): 52 // OP_2(需要 2 個簽章) 21 02c6047f... // 33 bytes 公鑰 1 21 0279be66... // 33 bytes 公鑰 2 21 02f9308a... // 33 bytes 公鑰 3 53 // OP_3(共 3 個公鑰) AE // OP_CHECKMULTISIG 腳本大小:1 + (1+33)*3 + 1 + 1 = 105 bytes
密鑰順序
重要:密鑰順序影響腳本哈希
在 multi() 中,公鑰按照描述符中指定的順序排列。 相同的公鑰以不同順序會產生不同的腳本和地址:
multi(2, KEY_A, KEY_B, KEY_C) → 地址 X multi(2, KEY_B, KEY_A, KEY_C) → 地址 Y(不同!)
這可能導致恢復問題,如果忘記了密鑰順序,就無法重建正確的地址。
sortedmulti() — 排序多簽
格式
語法:sortedmulti(k, KEY1, KEY2, ..., KEYn) 與 multi() 相同,但公鑰在構建腳本時會自動排序。 排序規則: • 按公鑰的字節序(lexicographic)排序 • 對於 xpub,派生後的公鑰進行排序 範例: sortedmulti(2, xpub1.../0/*, xpub2.../0/*, xpub3.../0/* ) 每個地址索引生成時: 1. 從每個 xpub 派生對應索引的公鑰 2. 對這些公鑰按字節序排序 3. 用排序後的順序構建多簽腳本
為何使用 sortedmulti
確定性
無論描述符中密鑰的順序如何,只要是相同的密鑰集合, 就會產生相同的地址。
易於恢復
恢復時不需要記住密鑰順序,只需要所有 xpub 和閾值。
互操作性
不同錢包使用相同的排序規則,確保相容性。
業界標準
多數現代多簽錢包都使用排序多簽。
排序範例
給定三個公鑰(hex 格式): A = 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 B = 02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5 C = 02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9 字節序排序後: 1. A(02 79 be...) 2. B(02 c6 04...) 3. C(02 f9 30...) sortedmulti(2, C, A, B) 等同於 multi(2, A, B, C) sortedmulti(2, B, C, A) 等同於 multi(2, A, B, C) ... 所有排列都產生相同的腳本!
包裝使用
multi 和 sortedmulti 需要被包裝在腳本類型函數中:
| 描述符 | 類型 | 地址格式 |
|---|---|---|
| sh(multi(...)) | P2SH 多簽 | 3... |
| sh(sortedmulti(...)) | P2SH 排序多簽 | 3... |
| wsh(multi(...)) | P2WSH 多簽 | bc1q...(62字符) |
| wsh(sortedmulti(...)) | P2WSH 排序多簽 | bc1q...(62字符) |
| sh(wsh(sortedmulti(...))) | P2SH-P2WSH 排序多簽 | 3... |
實際範例
2-of-3 公司錢包
使用 P2WSH 的 2-of-3 多簽: wsh(sortedmulti(2, [aabbccdd/48'/0'/0'/2']xpub6CEO.../0/*, [11223344/48'/0'/0'/2']xpub6CFO.../0/*, [55667788/48'/0'/0'/2']xpub6CTO.../0/* ))#checksum 說明: • 48'/0'/0'/2' = BIP-48 多簽派生路徑 • 2' = 腳本類型(2 = P2WSH) • 三個硬體錢包各持有一個 xpub • 任意兩個可以簽署交易
3-of-5 託管
wsh(sortedmulti(3, [fp1/48'/0'/0'/2']xpub_user1.../0/*, [fp2/48'/0'/0'/2']xpub_user2.../0/*, [fp3/48'/0'/0'/2']xpub_backup.../0/*, [fp4/48'/0'/0'/2']xpub_custodian1.../0/*, [fp5/48'/0'/0'/2']xpub_custodian2.../0/* ))#checksum 配置: • 用戶持有 2 個密鑰 • 備份密鑰 1 個 • 託管商持有 2 個密鑰 • 任意 3 個可以恢復資金
限制
腳本大小限制
- P2SH:贖回腳本最大 520 bytes → 最多約 15 個公鑰
- P2WSH:見證腳本最大 10,000 bytes → 理論上更多公鑰
- 標準化:標準交易規則可能進一步限制
- Taproot:對於更大的多簽,考慮使用 MuSig2 或 FROST
簽章驗證
花費 2-of-3 多簽: witness(對於 P2WSH): OP_0 // CHECKMULTISIG bug(需要額外的空元素) <sig_A> // 對應公鑰 A 的簽章 <sig_B> // 對應公鑰 B 的簽章 <witnessScript> // 完整的多簽腳本 重要:簽章順序必須與腳本中公鑰順序一致! 正確:sig_A, sig_B(假設腳本中 A 在 B 前面) 錯誤:sig_B, sig_A(會驗證失敗)
總結
BIP-383 定義了多簽描述符函數。推薦使用 sortedmulti() 而非 multi(), 因為它提供確定性的密鑰排序,使錢包恢復更加可靠。 多簽描述符需要包裝在 sh() 或 wsh() 中才能生成有效地址。
延伸閱讀: 查看 GitHub 上的完整 BIP-383 文件
已複製連結