Miniscript 應用完全指南
理解比特幣腳本的高級表示法 Miniscript,包括語法、類型系統與實際應用場景。
Miniscript 應用完全指南
概述
Miniscript 是一種用於比特幣腳本的高級表示法,由 Bitcoin Core 貢獻者 Pieter Wuille 提出。Miniscript 使得複雜的比特幣腳本可以被人類可讀的方式編寫、驗證和分析,同時保留了比特幣腳本的全部功能。
為什麼需要 Miniscript?
傳統比特幣腳本的問題
傳統的比特幣腳本(Bitcoin Script)使用底層操作碼(OP_CODE)編寫,存在以下問題:
- 難以閱讀:原始腳本字串對人類不友好
- 難以驗證:難以確認腳本是否安全或正確
- 無法靜態分析:無法在簽名前分析腳本行為
- 錢包相容性差:不同錢包對複雜腳本的支持程度不同
Miniscript 的優勢
Miniscript 解決了這些問題:
- 可讀性:類似程式語法的表示法
- 可分析性:可以在簽名前預知腳本行為
- 可組合性:可以組合多個條件
- 錢包相容:有明確的編譯策略
Miniscript 語法基礎
基礎片段(Fragments)
Miniscript 使用「片段」來構建腳本。每個片段都有明確的類型和參數:
| 片段 | 語法 | 說明 |
|---|---|---|
| PK | pk(key) | 公鑰簽名驗證 |
| PkH | pk_h(key) | 公鑰雜湊驗證 |
| Multi | multi(k, key1, key2, ...) | 多簽名閾值 |
| Thresh | thresh(k, expr1, expr2, ...) | K-of-N 閾值 |
| After | after(n) | 時間鎖定 |
| Older | older(n) | 區塊高度鎖定 |
| Sha256 | sha256(h) | SHA256 雜湊預映證 |
| Hash256 | hash256(h) | Double SHA256 |
| Ripemd160 | ripemd160(h) | RIPEMD160 雜湊預映證 |
| Hash160 | hash160(h) | RIPEMD160+SHA256 |
示例語法
// 2-of-3 多簽名
multi(2, key1, key2, key3)
// 2-of-3 多簽名加上時間鎖
and_v(v:multi(2, key1, key2, key3), after(1000))
// 任意一個公鑰或時間鎖
or_d(v:pk(key1), v:after(500))
Miniscript 類型系統
Miniscript 為每個片段分配類型,用於靜態分析和安全性驗證:
類型標記
| 類型 | 標記 | 說明 |
|---|---|---|
| B | Boolean | 返回布爾值 |
| V | Value | 需要值才能滿足 |
| K | Key | 需要簽名 |
| W | Wrapped | 包裝的條件 |
類型組合
常見類型組合:
- B:返回布爾值,如
and_b - V:需要值,如
a:pk - K:需要密鑰,如
pk - W:包裝類型,如
c:pk(包裹的條件)
實際應用場景
場景一:時間鎖定遺產
// 立即可以使用任何一個私鑰
// 或者 1 年後可以使用任何一個私鑰
or(
pk(key1),
and(older(525600), pk(key1))
)
轉換為比特幣腳本後:
OP_IF
<key1> OP_CHECKSIG
OP_ELSE
525600 OP_CHECKSEQUENCEVERIFY OP_DROP
<key1> OP_CHECKSIG
OP_ENDIF
場景二:閾值多簽名
// 3-of-5 多簽名
multi(3, key1, key2, key3, key4, key5)
場景三:需要額外條件的支出
// 需要 key1 簽名加上 1 天後冷卻期
// 或者 2-of-3 多簽名
or(
and_v(v:pk(key1), older(144)),
and_v(v:multi(2, key2, key3, key4), after(1000))
)
場景四:硬體錢包 + 手機錢包
// 手機錢包(日常使用)+ 硬體錢包(備份)
or(
pk(hardware_key),
and_v(v:pk(backup_key), older(1000))
)
Miniscript 編譯工具
miniscript.fun
線上工具可以將 Miniscript 轉換為比特幣腳本:
- 訪問 miniscript.fun
- 輸入 Miniscript 表達式
- 選擇目標地址類型(P2WSH 或 P2TR)
- 獲取編譯後的腳本和地址
Bitcoin Core
Bitcoin Core 24.0+ 內建 Miniscript 支援:
# 解析 Miniscript
getminiscript "pk(key)"
# 從 Miniscript 獲取腳本
toderawminiscript "pk(key)"
程式庫
| 語言 | 庫 |
|---|---|
| Rust | rust-miniscript |
| C++ | Bitcoin Core 內建 |
| Python | python-miniscript |
| JavaScript | miniscript-js |
安全性分析
提前終止(Earliest Termination)
Miniscript 可以分析腳本是否會提前終止(提前返回成功/失敗):
- 提前終止安全:腳本在中間狀態不會意外返回成功
- 非提前終止:腳本總是執行到最後
滿足性(Satisfiability)
分析腳本是否可以被滿足(即是否存在有效的解鎖方式):
// 總是可以滿足的(總有分支可以達成)
or(pk(key1), pk(key2))
// 可能無法滿足的(兩個條件都無法達成)
and(pk(key1), after(999999999))
完美隱私
某些 Miniscript 結構可以提供「完美隱私」—— 外部觀察者無法從腳本結構推斷出內部邏輯:
// 使用 thresh 提供完美隱私
thresh(1, pk(key1), pk(key2), pk(key3))
這與 multi(1, ...) 行為相同,但結構更複雜。
Miniscript 與 Taproot
Taproot 地址
Miniscript 可以編譯為 P2TR(Taproot)地址:
# 編譯為 Taproot
toderawminiscript "pk(key)" - tapped
腳本樹
Taproot 允許腳本樹結構,Miniscript 可以表示:
// Taproot 腳本樹
or(
pk(key_main),
and(older(1000), pk(key_backup))
)
這會創建一個展示為單一公鑰的 Taproot 地址,但包含備份支出路徑。
進階 Miniscript 程式設計
使用 Rust 庫實現
use rust_miniscript::miniscript::Miniscript;
use rust_miniscript::bitcoin::PublicKey;
use rust_miniscript::bitcoin::secp256k1::Secp256k1;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let secp = Secp256k1::new();
// 生成三個測試公鑰
let (_, pk1) = secp.generate_keypair(&mut rand::thread_rng());
let (_, pk2) = secp.generate_keypair(&mut rand::thread_rng());
let (_, pk3) = secp.generate_keypair(&mut rand::thread_rng());
// 創建 2-of-3 多簽名 Miniscript
let ms = Miniscript::<PublicKey,>::from_str(&format!(
"multi(2,{},{},{})",
pk1, pk2, pk3
))?;
// 獲取腳本
let script = ms.encode();
println!("P2WSH 腳本: {}", script);
// 獲取地址
let address = ms.address(Network::Bitcoin);
println!("比特幣地址: {}", address);
Ok(())
}
使用 Python 實現
from miniscript import Miniscript, Key
def create_timelock_escrow(
escrow_key: Key,
buyer_key: Key,
seller_key: Key,
timelock_blocks: int
) -> Miniscript:
"""
創建一個帶時間鎖的托管合約
邏輯:
- 買家和賣家共同簽名可以立即轉帳
- 或者一段時間後只有賣家可以轉帳(退款)
"""
# 2-of-2 多簽名
multi_2of2 = Miniscript.multi(
k=2,
keys=[buyer_key, seller_key]
)
# 時間鎖路徑:賣家單獨可以在 timelock 後提款
timelock_path = Miniscript.and_(
Miniscript.older(timelock_blocks),
Miniscript.pk(seller_key)
)
# 組合邏輯:多簽 OR 時間鎖
escrow = Miniscript.or_(multi_2of2, timelock_path)
return escrow
def create_inheritance_contract(
heir_keys: list[Key],
timelock_months: int
) -> Miniscript:
"""
創建遺產合約
邏輯:
- 主要繼承人需要 2-of-3 簽名
- 或者 1 年後任何一個備用繼承人可以獲得資金
"""
# 2-of-3 主要路徑
primary = Miniscript.multi(k=2, keys=heir_keys)
# 備份路徑:1年後任何備用金鑰
backup = Miniscript.and_(
Miniscript.older(timelock_months * 4320), # 假設每月約 4320 區塊
Miniscript.multi(k=1, keys=heir_keys)
)
return Miniscript.or_(primary, backup)
完整錢包整合示例
// TypeScript 錢包整合示例
interface WalletConfig {
mainKey: PublicKey;
backupKeys: PublicKey[];
timelockBlocks: number;
network: 'mainnet' | 'testnet';
}
class MiniscriptWallet {
private config: WalletConfig;
constructor(config: WalletConfig) {
this.config = config;
}
/**
* 創建日常使用的錢包(主要密鑰 + 備份)
*
* 邏輯:
* - 主密鑰可以隨時使用
* - 備份密鑰需要 30 天冷卻期
*/
createDailyWallet(): Miniscript {
const mainPath = Miniscript.pk(this.config.mainKey);
const backupPath = Miniscript.and_(
Miniscript.older(this.config.timelockBlocks),
Miniscript.pk(this.config.backupKeys[0])
);
// 任一路徑都可以提款
return Miniscript.or_(mainPath, backupPath);
}
/**
* 創建冷存儲錢包(高安全性)
*
* 邏輯:
* - 3-of-5 多簽名
* - 需要大多數持有人同意
*/
createColdStorage(): Miniscript {
return Miniscript.multi(
k=3,
keys=[
this.config.mainKey,
...this.config.backupKeys
]
);
}
/**
* 創建商業帳戶(需要審批)
*
* 邏輯:
* - 經理 A + 經理 B 同時簽名
* - 或者 3-of-5 董事簽名
* - 或者 1 年後資金自動釋出
*/
createBusinessAccount(
managerKeys: PublicKey[],
directorKeys: PublicKey[]
): Miniscript {
// 雙經理路徑
const managerPath = Miniscript.multi(k=2, keys=managerKeys);
// 董事路徑
const directorPath = Miniscript.multi(k=3, keys=directorKeys);
// 時間解鎖路徑(自動釋出)
const timelockPath = Miniscript.and_(
Miniscript.older(525600), // 約 1 年
Miniscript.pk(this.config.mainKey)
);
// 組合:經理 OR 董事 OR 時間鎖
return Miniscript.or_(
managerPath,
Miniscript.or_(directorPath, timelockPath)
);
}
/**
* 生成比特幣地址
*/
generateAddress(miniscript: Miniscript): string {
const script = miniscript.encode();
const hash = sha256(script);
return bech32.encode('bc', hash, this.config.network);
}
}
比特幣核心 RPC 整合
# 使用 Bitcoin Core 創建和兌現 Miniscript
# 1. 解析 Miniscript
bitcoin-cli getminiscript "multi(2,03a0434e9e2cfaea60e8a2a6a00d5d7a8d6b9e2cfaea60e8a2a6a00d5d7a8d6b,03b0434e9e2cfaea60e8a2a6a00d5d7a8d6b9e2cfaea60e8a2a6a00d5d7a8d6)"
# 2. 獲取腳本
bitcoin-cli decodepsbt "psbt_base64"
# 3. 創建 P2TR 地址
bitcoin-cli getdescriptorinfo "tr(/0'/0'/0')"
# 4. 創建 Miniscript 錢包
bitcoin-cli createwallet "miniscript_wallet" true true
# 5. 導入 Miniscript 描述符
importdescriptors '[
{
"desc": "wsh(multi(2,03a0434e9e2cfaea60e8a2a6a00d5d7a8d6b9e2cfaea60e8a2a6a00d5d7a8d6b,03b0434e9e2cfaea60e8a2a6a00d5d7a8d6b9e2cfaea60e8a2a6a00d5d7a8d6))",
"timestamp": "now",
"watchonly": true,
"range": [0, 100],
"next_index": 1
}
]'
常見問題
Miniscript 與普通腳本有什麼區別?
Miniscript 是比特幣腳本的可讀表示,兩者在區塊鏈上的表現完全相同。Miniscript 只是讓編寫和驗證比特幣腳本變得更容易。
Miniscript 是否需要新的比特幣升級?
不需要。Miniscript 完全相容現有的比特幣共識層,可以直接在任何現代比特幣腳本中使用。
使用 Miniscript 是否有額外費用?
沒有。Miniscript 編譯後產生的腳本與手寫腳本的大小相同,不會產生額外的區塊空間費用。
Miniscript 是否支援智能合約?
是的。Miniscript 可以實現各種複雜的支出條件,包括時間鎖、多簽名、雜湊預映證等,這些是比特幣智能合約的基礎。
Miniscript 安全性分析深入
提前終止安全(Earliest-Termination)
Miniscript 的類型系統允許靜態分析腳本的提前終止屬性:
// 提前終止安全的腳本範例
and_b(pk(A), pk(B))
// 兩個條件都必須滿足,無法提前終止
// 可能提前終止的腳本
or_b(pk(A), pk(B))
// 如果 A 簽名成功,腳本提前終止
提前終止分析的重要性:
- 防止意外資金損失
- 確保資金在滿足條件前不會被釋放
- 钱包软件可以根据此属性优化交易构建
安全性類型詳解
Miniscript 使用四個基礎類型標記:
類型組合矩陣
════════════════════════════════════════════════════
基礎類型:
┌─────────────────────────────────────────────────┐
│ B (Boolean) - 返回 TRUE/FALSE │
│ V (Value) - 需要提供數值才能滿足 │
│ K (Key) - 需要提供密鑰/簽名 │
│ W (Wrapped) - 包裝類型,自動解包 │
└─────────────────────────────────────────────────┘
組合類型:
┌─────────────────────────────────────────────────┐
│ Bk - Boolean + Key │
│ Kv - Key + Value │
│ Bv - Boolean + Value │
│ Kw - Key + Wrapped │
│ ... │
└─────────────────────────────────────────────────┘
安全性驗證流程
def verify_miniscript_safety(miniscript: str) -> dict:
"""
驗證 Miniscript 安全性
"""
# 1. 解析 Miniscript
ms = parse_miniscript(miniscript)
# 2. 類型檢查
type_check(ms)
# 3. 提前終止分析
is_earliest_termination = analyze_earliest_termination(ms)
# 4. 滿足性檢查
is_satisfiable = check_satisfiability(ms)
# 5. 安全 性檢查
is_safe = check_malleability(ms)
return {
"type": ms.type,
"earliest_termination": is_earliest_termination,
"satisfiable": is_satisfiable,
"safe": is_safe
}
常見安全陷阱
安全陷阱清單
═════════════════════════════════════════════════════
1. 不可滿足的腳本
┌───────────────────────────────────────────────┐
│ and(pk(A), after(999999999)) │
│ │
│ 問題:時間永遠不會到來,永遠無法花費 │
│ 解決:使用 or 確保總是可以滿足 │
└───────────────────────────────────────────────┘
2. 隱藏的提前終止
┌───────────────────────────────────────────────┐
│ or(pk(A), and(pk(B), after(100))) │
│ │
│ 問題:A 簽名後腳本提前終止,B 的資金被鎖住 │
│ 解決:仔細分析所有分支的行為 │
└───────────────────────────────────────────────┘
3. 時間鎖陷阱
┌───────────────────────────────────────────────┐
│ and(older(525600), pk(A)) │
│ │
│ 問題:1年後才能提款,且需要 A 簽名 │
│ 解決:添加備份路徑 │
└───────────────────────────────────────────────┘
4. 多簽名閾值錯誤
┌───────────────────────────────────────────────┐
│ multi(3, A, B, C, D, E) │
│ │
│ 問題:需要 5 人中的 3 人,不是 3-of-5 │
│ 解決:確保 k <= n │
└───────────────────────────────────────────────┘
Miniscript 實際部署範例
企業比特幣托管方案
企業級 Miniscript 架構
═════════════════════════════════════════════════════
層級 1:日常運營帳戶
───────────────────────────────────────────────────
Miniscript: multi(2, CEO_key, CFO_key)
特點:
- 需要 CEO 和 CFO 共同簽名
- 適合日常支出
- 金額限制:$100,000/日
層級 2:儲備帳戶
───────────────────────────────────────────────────
Miniscript: or(
multi(3, CEO_key, CFO_key, CTO_key),
and(older(1000), multi(2, CEO_key, Chairman_key))
)
特點:
- 需要 3 位高管簽名
- 或 2 位高管 + 1 年等待期
- 適合大額支出
層級 3:離線冷存儲
───────────────────────────────────────────────────
Miniscript: multi(5,
CEO_key,
CFO_key,
Chairman_key,
External_Auditor_key,
Time_Lock_Recovery_key
)
特點:
- 需要全部 5 把密鑰
- 完全離線存儲
- 適合長期儲備
去中心化儲蓄合約
// 自動儲蓄計劃合約
or(
// 路徑 1:每月自動存款
and(
older(4320), // 約 1 個月
pk(savings_contract)
),
// 路徑 2:緊急提款(需要 3-of-5 同意)
multi(3,
user_key,
spouse_key,
lawyer_key,
accountant_key,
bank_key
)
)
// 邏輯:
// - 合約地址每月自動存入固定金額
// - 用戶在任何時候可以通過多簽提款
// - 實現自動化儲蓄目標
聯合創投基金
// 創投基金合約
or(
// 路徑 1:投資委員會批準
and(
multi(3, GP_key1, GP_key2, GP_key3),
after(5000) // 鎖定期
),
// 路徑 2:有限合夥人投票
and(
multi(4, LP_key1, LP_key2, LP_key3, LP_key4),
older(10000) // 更長鎖定期
),
// 路徑 3:到期還本
and(
older(20000), // 約 4 年
pk(fund_address)
)
)
// 邏輯:
// - GP 批準 + 鎖定期後可以投資
// - LP 多數同意可以還款
// - 4 年後自動還本
總結
Miniscript 是比特幣腳本開發的重要工具,它使得複雜的比特幣腳本變得可讀、可分析和可驗證。通過 Miniscript,開發者可以安全地構建多簽名、時間鎖和其他高級腳本,同時錢包和工具可以更好地理解和處理這些腳本。隨著 Taproot 的採用,Miniscript 的重要性將進一步提升。
主要優點:
- 可讀性:人類可理解的腳本表示
- 可分析性:靜態分析腳本行為
- 可驗證性:確保腳本安全
- 可組合性:靈活構建複雜邏輯
- 兼容性:支持 Taproot 和各種地址類型
應用場景:
- 企業級比特幣管理
- 去中心化金融合約
- 遺產規劃
- 聯合投資
- 時間鎖定儲蓄
相關文章
- 比特幣腳本語言入門 — 理解 Bitcoin Script 的基本指令與運作原理。
- 比特幣合約 (Covenants) — 理解比特幣腳本限制與合約實現的可能性。
- 比特幣腳本協定層級深度解析 — 從密碼學證明到實際實現,深入分析比特幣腳本語言的數學基礎、協定規範與安全特性。
- P2PKH 與 P2SH 腳本類型 — 從 Pay to Public Key Hash 到 Pay to Script Hash 的演進。
- Taproot 全面解析 — 比特幣最新的腳本升級:MAST、BIP-340/341/342。
延伸閱讀與來源
這篇文章對您有幫助嗎?
請告訴我們如何改進:
評論
發表評論
注意:由於這是靜態網站,您的評論將儲存在本地瀏覽器中,不會公開顯示。
目前尚無評論,成為第一個發表評論的人吧!