作者:Nunchuk
1. 引言
什麼是 “Miniscript”?
比特幣協議一直都帶有一種強大的編程語言(Bitcoin Script),可以將資金鎖定在 “一個正確的簽名即可解鎖資金” 以外的條件中。使用 Bitcoin Script,你可以將多個公鑰、時間鎖、哈希原像和複雜的邏輯分支結合起來。然而,在現實中,Bitcoin Script 很少被直接使用,因為難以編寫正確的代碼,而錯誤代碼可能導致資金永久鎖定,而且最終的代碼幾乎無法直接分析。
“Miniscript(BIP-379)” 是由 Pieter Wuille 及其合作者提出的一種 “以結構化方法編寫 Bitcoin Script 代碼的語言,帶來了分析、組合以及通用簽名的能力”。它解決了裸 Bitcoin Script 代碼的可用性和安全性問題,同時保持了跟當前的比特幣規則的完全兼容。
從內核來看,Miniscript 就像是比特幣花費規則的樂高積木箱子。每一個積木都有一個小型的、準確定義的條件,比如某個公鑰必須簽名、必須經過一段時間,或者必須揭曉一個秘密值。一塊積木可以換成另一塊機密,也就是允許靈活低構造替代的花費路徑。使用 “AND(和)”、“OR(或)” 以及 “閾值(threshold)” 這樣的邏輯操作符將積木們結合起來,你就可以按需開發出所需的花費條件,無論是簡單還是複雜。最重要的是,Miniscript 條件(policies)是可以分析的:錢包可以提前檢查誰可以花費、在什麼條件下花費,從而減少資金被無效腳本鎖定的風險。
這種結構化的方法使我們可以安全地表示如下的花費條件:
- 要求 3 位董事中至少 2 位簽名 —— 除非資金已經連續 6 個月沒有移動過,那麼只需其中 1 位簽名就可以移動資金了。
- Alice 和 Bob 必須一起,才能花費資金;或者,在資金靜置 1 年後,Charlie 可以獨自移動其中的資金。
- 要麼揭曉一個哈希值的原像,要麼到待到區塊高度 100 0000 之後(才能花費)。
它有什麼意義?
使用 Miniscript,花費條件就可以超越單簽名(single-sig)和簡單的多簽名(multisig)。你可以定義這樣的規則:
- “A 和 B 一起可以隨時花費資金;或者,C 可以獨自在資金靜置 1 年後花費資金”;
- “現在要求 3 個公鑰中的 2 個一同簽名;在資金靜置 6 個月之後,就只需要 3 個公鑰中的其中 1 個簽名”。
這些靈活的條件契合實際的用途,比如遺產規劃、分級的公司財務、緊急復原;它們讓普通的比特幣用戶也能接觸到高級的安全性。重要的是,所有的 Miniscript 條件都是直接在比特幣區塊鏈上強制執行的,除了對比特幣網絡自身的信任之外,不需要任何額外的信任假設。
2. Miniscript 的核心概念
現在,我們來看看 Miniscript 的核心模塊。每一種元素(也即一種 Miniscript 片段)都代表著一種具體的花費條件,它們組合在一起,就能創造出靈活又安全的花費策略。
2.1 公鑰
公鑰:pk(k)
這是 Miniscript 中最簡單的條件,表示要求一個具體的公鑰的一個簽名。它代表著基礎的 “單簽名” 花費條件,也用作更高級的花費條件的基礎。
- 例子:要求提供一個簽名來花費資金
- Miniscript:
pk(Alice)
- Miniscript 片段:公鑰 -
2.2 多簽名
多簽名:multi(k, …)
傳統的多簽名花費條件,要求 n 個公鑰中的 k 個提供簽名。其子元素只能是公鑰。
- 例子:需要 3 個公鑰中的 2 個提供簽名才能花費。
- Miniscript:
multi(2, Alice, Bob, Charlie)
- Miniscript 片段:多簽名 -
2.3 時間鎖
時間鎖防止被它鎖定的比特幣在某個時間點之前被花費。它是 Bitcoin Script 的原生功能,也是最有用的 Miniscript 模塊之一。
時間鎖強制執行 “資金只能在 6 個月之後移動” 和 “這個公鑰只有在資金存入的 30 天之後才能動用” 這樣的規則。比特幣網絡中的節點會拒絕嘗試在此之前花費這筆資金的交易。一旦越過這個時間點,資金就可以正常花費,而且被啟用的花費路徑不會再鎖回去。
Bitcoin Script 有兩種時間鎖:絕對時間鎖和相對時間鎖。
絕對時間鎖:after(n)
在網絡到達某一個區塊高度或者時間點之前,資金會一直鎖定。一旦區塊鏈增長到超過那個高度,帶有這個時間鎖的花費條件就激活並永久可用。
- 例子:在區塊鏈時間達到 UNIX 時間戳 17 5000 0000(大約是 2025 年 6 月)之後,用一個簽名來花費。
- Miniscript:
and_v(v:pk(Alice),after(1750000000))
絕對時間鎖會設置一個固定的未來時間;在一個絕對時間鎖過期後,以相同條件設置絕對時間鎖將不再有約束作用。
- Miniscript 片段:絕對時間鎖 -
相對時間鎖:older(n)
鎖定資金一段時間,直到這段時間過去。這段時間可以用區塊數量來定義,也可以用日曆時間(日期、小時)來定義。相對時間鎖從帶有它的 UTXO 被創造的一刻開始倒計時,一旦所定義的時間段過去,相關的花費路徑也就激活。
- 例子:在資金誕生的 1 2960 個區塊(大約 90 天)之後,需要一個簽名來花費。
- Miniscript:
and_v(v:pk(Alice),older(12960)
各個 UTXO 的相對時間鎖是相互獨立的,不會因為它們都處於同一個錢包中而統一計時。在一個 UTXO 的相對時間鎖到期之後,可使用相同的時間鎖條件來 “刷新” 倒計時 ——可以將它轉移到同一錢包的新地址來重設時間鎖。
- Miniscript 片段:相對時間鎖 -
- - -
在設定時間鎖的時候,錢包軟件界面所展示的日曆日期只是一種估計。如果所設置的時間鎖基於區塊高度,那麼網絡到達那個高度之後,這個時間鎖就過期。如果所設置的時間鎖基於日曆時間,比特幣網絡使用過往區塊時間中值(具體來說,過去 11 個區塊的時間戳的中值)來決定當前時間,會跟人們使用的日曆和時鐘有些偏差,所以,花費交易變得有效的時間取決於比特幣網絡的狀態,不會跟人們的預期(界面所展示的時間)完全一致。
2.4 哈希鎖
哈希鎖要求揭曉與一個哈希值對應的秘密值(其原像)。除非秘密揭曉,否則這個鎖不會解開。
- 例子:揭曉一個 SHA256 哈希值 H 背後的原像,並提供一個簽名,才能花費。
- Miniscript:
and_v(v:pk(Alice),sha256(H))
Miniscript 中的哈希鎖類型
sha256(H)
—— 原像必須在 SHA256 操作後得到 H(預期原像是一個 64 位的十六進制字符串)hash256(H)
—— 原像必須在連續兩次 SHA256 操作後得到 H(預期原像是一個 64 位的十六進制字符串)ripemd160(H)
—— 原像必須在RIPEMD-160 操作後得到 H(預期原像是一個 40 位的十六進制字符串)hash160(H)
—— 也想必須在 HASH160 操作(先運行 SHA256 操作,再運行 RIPEMD160 操作)後得到 H(預期原像是一個 40 位的十六進制字符串)
- Miniscript 片段:哈希鎖 -
2.5 邏輯基礎:AND、OR、ANDOR
這三種邏輯操作符是 Miniscript 的基礎。它們描述了不同的條件是如何組合的(通常通過時間鎖)。
AND:要解鎖,必須讓兩個條件都為真。
- 例子:花費需要 Alice 的簽名,並且要在收到資金的 1 2960 個區塊(大約 90 天)以後。
- Miniscript:
and_v(v:pk(Alice),older(12960))
- Miniscript 片段:AND -
- - -
OR:兩個條件中,至少一個為真,即可解鎖。
- 例子:花費需要兩個公鑰中的任意一個簽名。
- Miniscript:
or_d(pk(Alice),pk(Bob))
- Miniscript 片段:OR -
ANDOR:資金會使用一個 if/else 規則來鎖定:如果第一個條件為真,那麼第二個條件也必須為真(才能解鎖);如果第一個條件為假,那麼第三個條件必須為真(才能花費)。
- 例子:如果 Alice 簽名了,那麼 Bob 也需要簽名;如果 Alice 沒簽名,那麼需要 Charlie 的簽名。
- Miniscript:
andor(pk(Alice), pk(Bob), pk(Charlie))
- Miniscript 片段:ANDOR -
2.6 閾值
閾值:thresh(k, …)
閾值條件比多簽名更為靈活。它要求 k 個條件為真;但與多簽名不同的是,它的子元素並不限於公鑰,可以是邏輯表達式、時間鎖、哈希鎖,等等。
- 例子:Alice 和 Bob 一起簽名(才能花費);資金靜置 90 天以後,兩個人中的任何一個都可以獨自花費。
- Miniscript:
thresh(2,pk(Alice),s:pk(Bob),sln:older(12960))
- Miniscript 片段:閾值 -
2.7 Taproot Scripts
Taproot 讓你可以為資金承諾多個花費分支,而在使用時只需揭曉一個(也就是你真正使用的那個)。它提供了兩種花費方式:
- 密鑰路徑:用一個聚合公鑰來花費。這樣的交易在區塊鏈上的表現就是一個普通的單簽名交易,即使這個公鑰是由多個人共同構造的(比如使用 MuSig2)。
- 腳本路徑:使用被承諾的其中一個 Taproot 腳本分支。只有你用到的那個分支才會揭曉,其餘分支會被隱藏。
這種結構兼顧了效率和隱私性:日常使用可以通過密鑰路徑;而更復雜的花費條件可以隱藏起來,直到需要動用的時候才揭曉。
- 例子:日常花費使用密鑰路徑中的一個聚合公鑰(稱為 Alice);如果聚合公鑰無法簽名,腳本路徑允許 Charlie 隨時用簽名來花費,而 Bob 在資金創建的 90 天才能花費。
- Miniscript:
tr(pk(Alice), {and_v(v:pk(Bob),older(12960)),pk(Charlie)})
- Miniscript 片段:Taproot scripts -
2.8 MuSig2
“MuSig2” 是一個基於 Schnorr 的多重簽名方案,它讓多個參與者可以一同生成一個聚合簽名。在鏈上,這個聚合簽名看起來跟常規的單簽名沒有區別。這提高了隱私性和效率,同時降低了交易體積和手續費。
- 例子:需要 Alice、Bob 和 Charlie 三人中的兩個簽名才能花費。他們所生成的簽名,在區塊鏈上看起來就是一個單簽名,所以沒有人能夠分辨出這是一個多方錢包。所以多方錢包變得更加隱私和高效了。
- Miniscript:
tr(musig(Alice, Charlie), {pk(musig(Alice, Bob)),pk(musig(Bob, Charlie))})
- Miniscript 片段:MuSig2 -
3. 在 Nunchuk 中使用 Miniscript
3.1 創建 Miniscript 錢包
Nunchuk 讓用戶輕鬆就能用 Miniscript 構建高級的花費條件。你可以從現成的模板開始,也可以輸入自己定製的腳本。
在 Nunchuk 中創建一個 miniscript 錢包:Home → Create new wallet(創建新錢包) → Miniscript
- 模板:選擇花費條件,比如 “Expanding Multisig(擴展的多簽名)”、“Decaying Multisig(遞減式多簽名)” 或 “Flexible Multisig(靈活多簽名)”。每一種模板都可以調整參數,比如公鑰的數量、時間延遲,不需要你編寫任何代碼。
- 通過模板創建 miniscript 錢包 -
- 自定義腳本:對於高級用戶,你可以粘貼一個明文的 Miniscript 花費條件,或者從文件中導入。Nunchuk 會自動分析腳本、檢查正確性,並用大白話向你展示花費條件。
- 使用自定義腳本創建一個 miniscript 錢包 -
3.2 Miniscript 團體錢包
Nunchuk 的 “團體錢包(Group Wallet)” 功能讓使用多臺設備的多個人可以一起管理一個比特幣錢包,並且他們之間的數據通信是端到端加密的。每一個參與者都可以自己的密鑰,而花費條件是集體強制執行的,不依賴於任何託管商。在跟 Miniscript 結合時,團體錢包支持高級的多方條件,可以反映現實世界中的治理機制。跟普通的 miniscript 錢包一樣,你可以從現成的模板開始,也可以自定義腳本。
要在 Nunchuk 中創建一個 miniscript 團體錢包,請點擊:Home → Create new wallet(創建新錢包) → Group wallet(團體錢包) → Settings(設定) → Miniscript.
- 例子:一個公司的兩位執行官和四位董事建立了一個團體錢包。日常操作只需要兩個執行官簽名;但在另一條花費路徑中,四位董事中的任何三位都可以授權一筆交易 -
3.3 Miniscript 錢包復原
要復原 miniscript 錢包,除了常用材料,比如私鑰和原像,備份好的錢包配置文件(無論是輸出描述符形式還是 BSMS 文件形式),是絕對必要的。
BSMS 格式是圍繞 “輸出描述符(Output Descriptor)” 的封裝形式,包含了比如錢包的第一個地址這樣的元數據。這些元數據作為一種校驗和(checksum),並且可以快速定位錢包。錢包配置文件相當於一種地圖,定義了一個錢包是如何構造出來的。
Miniscript 團體錢包也用同樣的要求:沒有錢包配置文件,錢包就無法重新構造出來,即使所有成員的私鑰都沒有丟失,也做不到。
要在 Nunchuk 中復原一個 miniscript 錢包,請點擊:
Home → Create new wallet(創建新錢包) → Recover existing wallet(復原現有錢包) → Recover using BSMS/descriptors(使用 BSMS/描述符 來複原)
要在 Nunchuk 中復原一個 miniscript 團體錢包,請點擊:
Home → Create new wallet(創建新錢包 → Recover existing wallet(復原現有錢包) → Recover group wallet(復原團體錢包)
- 復原一個 miniscript 錢包或 miniscript 團體錢包 -
BSMS 1.0tr(xpub661MyMwAqRbcGgLWCDJNFcLYg8KgQimdffZdRobPJ585b93QjtCgqbPCo54DP3kpzwFpaZxoi6Snia3VDSV4oV81H4BxfaUbAzP2EpGHWDr/**,{multi_a(2,[8a0ba421/87'/0'/0']xpub6DWv19xigzHyBJJvE4iMTyTxQrn5TkBAr8k4gUJ8gycB8U7S7s8QRfBTa4Je2on9FE7jiUa3ijxuNyygEcpe8CGQUEz6W2PGtZ8SUJWc8fC/**,[d33f8331/87'/0'/0']xpub6C3RqV6jatGDLEiGpi92fsDLApCLC6SB28bMjwSaU4w3sdxmhWJRmzsxPDr8zv2hkyt1czkd3siMHJ6uAzN4T1gC5W6Vdd75XyJknN9N1Zb/**,[45c72f63/87'/0'/0']xpub6Ci35gULWq49uY6txiEHLJd8R9ESbadyed8zPACMgi6Cu5cd4BLG9p1ZDP3PnGNNaEHbGuy1uzEJDsEdWQck1C75DkaB13P8kX8UZkc7E8i/**),and_v(v:multi_a(1,[1e897bbf/87'/0'/0']xpub6CSCZZo8sDS2wjXUitr4FQUZwenEL1KcZrgYvi2mvSnVbYztYBxVLj5mKYcpNvB6RkLNEQzaaf8SWquzdhC6ncwasXk8STEjKwYRrd1QZcZ/**,[0cd15c3e/87'/0'/0']xpub6C3JCSGe5J2iqZymN7pKrYisD9po9FRqSRNot6561iLrzFjrPMNm8qn5VeYgTdWAtR66Kfr9oZWrjxSDLxB7GQ5dEi7hiUbjHyDxjaQxww6/**,[03c341e8/87'/0'/0']xpub6Bw2SYRUCc3Pcsgk39WkvkewHnxSLSERZmkUPBy91nrzKXehFBNLEzF2uJ2YiBhrS7kqagpGxBqhVziYawzUHePkB7pQGBMAnQmoYAxEAwz/**),after(1758819600))})/0/*,/1/*bc1pzmlufvqn5dpcquqysj4fr9skwxjj60wg7zyrpk4j8ftccz9ck9rs9fmjam
- 一個 miniscript 錢包的 BSMS 文件 -
4. 應用場景和案例
4.1 應用場景
Miniscript 為超越基礎多簽名的花費策略打開了大門。一些現實世界的應用場景包括:
- 遺產規劃:一種保險櫃,繼承人可以在一個定義好的時延之後解鎖,同時錢包的主人可以在自己生前完全控制其中的資金。
- 公司財庫:要求多位執行官簽名以從財庫支出,同時隱藏為緊急情形而準備的備用花費路徑。
- 託管與交易:使用哈希鎖和時間鎖來支出原子化的互換以及安全託管,無需中介。
- 保險:保險供應商可以強制執行賠付條件(需要多個簽名),或者,資金可以在時間鎖過期、提供一個可驗證的事件聲明之後釋放。
- 借貸:貸款可以用比特幣抵押品來擔保;比特幣抵押品可以通過閾值條件、時間鎖和退款路徑來強制執行還款或者清算,從而減少對可信任中介的需要。
- 緊急復原:一個通常需要 2-of-3 多簽名來解鎖的錢包,在資金長期不移動之後,激活一個緊急復原花費條件,一個或一組復原密鑰可以解鎖資金。
- 保護隱私的託管:使用 Taproot 和 MuSig2,即使複雜的多方條款,其花費交易在鏈上看起來也跟單簽名交易一樣,在保護隱私的同時,也保留了健壯的安全性。
4.2 案例
A)帶有時間鎖的繼承(一勞永逸的復原)
花費條件背後的想法:當前使用 2-of-3 多簽名;在你離線 6 個月之後,一個指定的後備密鑰可以取出錢包中的資金。
有何意義:減少資金永久丟失的風險,同時,不將直接的控制權交給他人。
如何工作:閾值簽名和一個帶有時間鎖的復原路徑。
Miniscript 例子:
andor( pk(backup_key), older(4224679), multi(2,A,B,C) )
B)帶有分級許可機制的企業財庫
花費條件背後的想法:
- 日常花費:任意 2 位財務總監 + 1 個聯合簽名機器(例如 硬件簽名模塊(HSM)/KMS(密鑰管理服務器))
- 大額支出:任意 2 位財務總監 + 首席財務官(CFO)
- 延遲/緊急 訪問:任何 2 位財務總監在為期 7 天的延遲之後可以花費
有何意義:日常便利和安全保障。
如何工作:閾值/AND 加上 OR 分支和一個可選的時間鎖。團隊在使用時自己選擇分支。
Miniscript 例子:
and_v( or_c( pk(HSM), or_i( v:pk(CFO), v:older(4195485) ) ), multi(2,LeadA,LeadB,LeadC))
C)用於 OTC 交易的可控託管
花費條件背後的想法:買方 + 賣方,或者,時間窗口結束後,任何一方 + 仲裁方
有何意義:無託管者。清晰的、基於規則的調解路徑。
如何工作:帶有一個時間鎖備用條件的 OR 邏輯。
Miniscript 例子:
thresh(2, pk(Buyer), s:pk(Seller), sj:and_v( v:pk(Arbiter), n:older(4194472) ) )
D)在鏈上難尋蹤跡的多方錢包
花費條件背後的想法:三個設備共同控制;可以使用一個聚合公鑰來花費,所以簽名者的數量不會暴露。
有何意義:實現團隊安全性,同時無需暴露治理結構。
如何工作:可以選擇 Taproot 和 MuSig2 。MuSig2 將多個簽名者聚合成一個公鑰;Taproot 隱藏未使用的分支。在一個腳本路徑中,只有被執行的分支才會揭曉。
Miniscript 例子(Taproot):
tr( musig(A,B), { pk(musig(A,C)), pk(musig(B,C)) } )
5. 結論
比特幣一向具有使用豐富花費條件的能力,但其低層編程語言太過困難,而且對絕大部分用戶都很危險。Miniscript 通過提供一種結構化的、安全的、可組合的語言來表達花費條件,改變了局面。
使用 Miniscript,遺產規劃、企業財庫、原子化互換、保護隱私的託管等等高級用途都成為了囊中之物。
作為一款軟件錢包,Nunchuk 將 Miniscript 帶到了用戶友好的界面中,比特幣生態系統也獲得了一種強大的新標準。最終,複雜的合約也可以用安全、可分析、易讀的方式來表達 —— 開啟下一代的比特幣保管和智能合約設計。
腳註:支持 MiniScript 的硬件簽名器
(最後更新於 2025年 8 月 27 日)
- 支持單純的隔離見證 Miniscript :Tapsigner、Coldcard(EDGE 固件 v6.3.3 及更高版本)、Jade(固件 v1.0.30 及更高版本)、Jade Plus(固件 v1.0.30 及更高版本)、Ledger(固件 v2.1.0 及更高版本)、Specter DIY(固件 v1.5.0 及更高版本)
- 支持 Taproot Miniscript :Coldcard(EDGE 固件 v6.3.3 及更高版本)、Ledger(固件 v2.2.1 及更高版本)、Specter DIY(固件 v1.9.0 及更高版本)
- 支持 MuSig2:尚無(即當前只能使用軟件密鑰)
(完)