先日、マルチシグを安全にセットアップするための提案Bitcoin Secure Multisig Setup (BSMS)が、新しくBIP-129として定義された、↓
https://github.com/bitcoin/bips/blob/master/bip-0129.mediawiki
PSBTなどで、ウォレット間で協力してトランザクションを構築する際のデータフォーマットは標準化されたけど、そのプロセスの標準化はされていなかったので、その提案。
BSMSでは、マルチシグで使用するスクリプトや必要な鍵の数、署名の数に、鍵の導出パスが改ざんされることなく参加者間で共有され、第三者に対してその漏洩を防ぐためのプロトコルが定義されている。
コーディネーターと呼ばれるロールが、セットアップの調整を行い、署名者は主にハードウェアウォレットを対象としている。コーディネーターがシークレットトークンを生成・配布し、そこから暗号鍵を導出し、各署名者が署名に用いる鍵情報をAESで暗号化して返送する。コーディネーターはそれらを収集し、マルチシグに使用するdescriptorを生成し、各署名者に配布するというのが大まかな流れ。プロセスをまとめて絵にすると↓な感じ。
プロトコルの詳細は↓のBIP訳参照。
ただ、これを利用するためには、マルチシグ参加者のすべてのウォレットがBSMSに対応していないといけないので、それが利用までの一番のハードルになりそう。
イントロダクション
概要
このドキュメントは、マルチシグウォレットを安全にセットアップする仕組みを提案する。
Copyright
このBIPは2-clause BSDライセンス。
動機
Bitcoinのマルチシグのエクスペリエンスは、BIP-0174(Partially Signed Bitcoin Transaction)で、大幅に合理化された。しかし、異なるベンダー間でマルチシグウォレットを安全にセットアップするための標準的なプロセスはまだない。
マルチシグウォレットをセットアップする際には、いくつかの懸念事項がある:
- マルチシグの設定には、署名者のメンバーシップや、スクリプトの種類、必要な署名の数や鍵の導出パスが求められ、それが正しく、改ざんされていないかどうか。
- セットアップ中に鍵やマルチシグの設定やが漏洩していないかどうか。
- 署名者がマルチシグの設定をそれぞれのストレージに保存しているか、またどんなフォーマットで保存しているか。
- 署名者のストレージが改ざん防止されているかどうか。
- 署名者がその後マルチシグの設定を使って、受信アドレスやお釣り用のアドレスを生成および検証しているかどうか。
マルチシグの設定を改ざんできる攻撃者は、ユーザーを騙して間違ったアドレスに資金を送信させることで、資金を盗んだり身代金を要求することができる。設定は改ざんできないが、鍵や設定について知ることができる攻撃者は、ウォレット内のトランザクションを関しすることができ、その結果プライバシーが失われる。
この提案は、上記の1, 2, 3の懸念を解決するために初期設定段階での改ざんリスクを軽減し、相互運用可能なマルチシグの設定フォーマットを定義することを目的としている。
懸念事項4, 5については署名者が処理すべきであり、本提案のスコープ外である。
仕様
前提条件
この提案は、マルチシグの参加者がBIP-0032およびBIP-0322、descriptor言語とAES暗号化をサポートしていることを前提とする。
ファイルの拡張子
すべてのdescriptorおよび鍵レコードのファイル拡張子は.bsms
とする。暗号化されたデータは.dat
拡張子を付ける。
ロール
コーディネーター
コーディネーターがマルチシグのセットアップを開始する。コーディネーターはどんな種類のマルチシグを使用するか、また正確なポリシースクリプトを決定する。暗号化が必要な場合は、コーディネーターは安全な通信のために、関係者に共有シークレットを配布する。コーディネーターは、署名者から情報を収集し、descriptorレコードを生成する。コーディネーターはdescriptorrレコードを署名者に配布する。
署名者
署名者は、秘密鍵を管理し、その鍵を使って署名できるソフトウェアもしくはハードウェアである。署名者はマルチシグの参加者で、公開鍵や拡張公開鍵(XPUB)を含む鍵レコードをコーディネーターに提供し、その鍵がdescriptorレコードに含まれていることを検証し、descriptorレコードをストレージに保存する責任がある。
セットアップ手順
ラウンド1
コーディネーター
- コーディネーターは新しいマルチシグウォレット作成セッションを作成する。コーディネーターはmultisigスクリプトと、必要な署名数や署名者の総数(
M
およびN
)などのポリシーパラメータを作成する。 - セッションは、コーディネーターが決めた時間(例えば24時間など)を超えると失効する。このタイムアウトにより暗号鍵のエントロピーが小さくなる。
- 暗号化が必要な場合、コーディネーターは秘密の
TOKEN
を安全なチャネルを介して各署名者に配布する。署名者はそのTOKEN
を使ってENCRYPTION_KEY
を導出することができる。TOKEN
および鍵導出関数と暗号化方式の詳細については、以下の暗号化セクションを参照。コーディネーターは、ユースケースに応じて、すべての署名者の共通のTOKEN
を使用するか、署名者毎にTOKEN
を使用するか決定することができる。 - 暗号化が必要ない場合、
TOKEN
は0x00
に設定され、以下のすべての暗号化/復号化の手順はスキップされる。
署名者
- 署名者は、
TOKEN
を設定することでマルチシグウォレット作成セッションを開始する。署名者はTOKEN
からENCRYPTION_KEY
を導出する。異なるTOKEN
の値が設定されるまでセッションを継続できる。 - 署名者は、ユーザーにマルチシグの導出パスの入力を求め、導出パスの
KEY
を取得し、鍵レコードを生成する。また署名者がユーザーに代わってパスを選択することも可能。署名者がパスを選択する場合は、異なるウォレット間でKEY
を使い回さないようにすべき。 - レコードの最初の行は仕様のバージョンでなければならない(これを書いている時点では
BSMS 1.0
)。2行目には、hexエンコードされたTOKEN
で、3行目はKEY
でなければならない。KEY
は公開鍵もしくはXPUB
にkey origin情報を加えたもので、descriptorで定義されたフォーマット、例えば[{master key fingerprint}/{derivation path}]{KEY}
で記述される。4行目は、鍵の説明のテキストで、最大80文字。5行目はSIG
でなければならず、このSIG
は公開鍵もしくはXPUB
の関連する秘密鍵を使って、最初の4行に署名した署名データである。署名はBIP-0322に運居し、レガシーフォーマットも受け入れられる。 - 署名者は、レコードのメッセージ認証コード(MAC)を計算する。
MAC
の先頭16バイトは、暗号化のための初期ベクトル(IV)として機能する。 - 署名者は、
ENCRYPTION_KEY
とIV
を使って鍵レコードを暗号化する。 - 署名者は、
MAC
と暗号文を16進フォーマットでエンコードし、その結果を結合す:(MAC || ciphertext)
。
ラウンド2
コーディネーター
- コーディネーターは、すべての参加署名者から鍵レコードを集める。
- コーディネーターは、ウォレットセットアップセッションが失効する前に、正確にN個の一意な鍵レコードがあることを確認する。
- 各鍵レコードについて、コーディネーターはデータから
MAC
を取り出し、MAC
の先頭16バイトをIV
にセットして、ENCRYPTION_KEY
とIV
を使って暗号文を復号する。 - コーディネーターは、得られた平文から
MAC
が正しいことを検証する。 - コーディネーターは、鍵レコードが互換性のある仕様バージョンであることを確認する。
- コーディネーターは、含まれる
SIG
がKEY
に対して有効か検証する。 - すべての鍵レコードに問題がなければ、コーディネーターは、必要な情報をすべて使って、descriptorレコードを生成する。
- descriptorレコードの最初の行は、仕様のバージョンでなければならない(これを書いている時点では
BSMS 1.0
)。2行目は、descriptorもしくはdescriptorテンプレートでなければならない。3行目はカンマ区切りの導出パス制限のリストでなければならない。パスは必ず/
から始まり、非強化導出でなければならない。テンプレートや制限がない場合、No path restrictions
と記述しなければならない。4行目はウォレットの最初のアドレスでなければならない。パスの制限がある場合、パス制限を最初のアドレスから使用する。 - コーディネーターは、レコードの
MAC
を計算する。MAC
の先頭16バイトは、暗号化のための初期ベクトル(IV)として機能する。 - コーディネーターは、
ENCRYPTION_KEY
とIV
を使ってdescriptorレコードを暗号化する。 - コーディネーターは、
MAC
と暗号文を16進フォーマットでエンコードし、その結果を結合す:(MAC || ciphertext)
。 - コーディネーターは、暗号化されたdescriptorレコードを参加中のすべての署名者に送信する。
署名者
- 署名者は、descriptorレコードをインポートする。
- 署名者は、データから
MAC
を取り出し、MAC
の先頭16バイトをIV
にセットして、(セッション開始時の)ENCRYPTION_KEY
とIV
を使って暗号文を復号する。 - 署名者は、得られた平文から
MAC
が正しいことを検証する。 - 署名者は、descriptorレコードが互換性のある仕様バージョンであることを確認する。
- 署名者は、そのdescriptorもしくはdescriptorテンプレートをサポートできるか検証する。
- 署名者は、提供されたパスとfingerprintの情報を使って、descriptorもしくはdescriptorテンプレートに
KEY
が含まれていることを確認する。チェックではKEY
が正確に一致するか検証し、偽装が容易なfingerprintを一致させるようなショートカットを使ってはならない。 - 署名者は、導出パスの制限と互換性があることを検証する。
- 署名者は、ウォレットの最初のアドレスが有効であることを検証する。
- 確認のため、署名者はユーザーに、ウォレットの最初のアドレスと導出パスの制限、
M
、N
、ポリシースクリプト内で署名者が所有するKEY
の位置などのポリシーパラメータを表示しなえればならない。署名者の総数N
は、KEY
挿入攻撃を防ぐのに重要である。位置は、KEY
の順序が重要なスクリプトにとて重要で、該当する場合、KEY
のすべての位置を表示しなければならない。完全なdescriptorもしくはdescriptorテンプレートは、ユーザーの要求に応じて確認できなければならない。 - 参加者は、すべての署名者が同じ確認事項(
KEY
の位置を除く)を持っていることを確認しなければならない。 - すべてのチェックをパスした場合、署名者はそのdescriptorレコードを保存しなければならない。
これでセットアップは完了。
暗号化
トークン
3つの暗号化モードを定義する。
NO_ENCRYPTION
:TOKEN
には0x00
をセットする。暗号化は無効。STANDARD
:TOKEN
は64ビットのnonce。EXTENDED
:TOKEN
は128ビットのnonce。
TOKEN
は次のいずれかのフォーマットに変換できる:
- 10進数(推奨)。この数値はnonceの最大値を超えてはならない。
- BIP-0039ワードリストを使ったニーモニックフレーズ。
STANDARD
モードでは6個の単語になる。シードのニーモニックとTOKEN
のニーモニックを混同するおそれがあるため、EXTENDED
モードではこのエンコーディングは推奨されない。 - QRコード
- その他のフォーマット
データフォーマットの柔軟性により、各署名者はそれぞれの機能に基づいてUXをカスタマイズできる。
鍵の導出
鍵導出関数はPBKDF2で、PRF = SHA512。具体的には:
DKey = PBKDF2(PRF, Password, Salt, c, dkLen)
ここで:
- PRF = SHA512
- Password = "No SPOF"
- Salt =
TOKEN
- c = 2048
- dkLen = 256
- DKEY = 導出された
ENCRYPTION_KEY
暗号化方式
暗号化方式は、AES-256-CTR。
MAC = HMAC-SHA256(HMAC_Key, hexエンコードされた TOKEN || Data) IV = MACの先頭16バイト 暗号文 = AES-256-CTR-Encrypt(平文, DKey, IV) 平文 = AES-256-CTR-Decrypt(暗号文, DKey, IV)
ここで:
- DKey =
ENCRYPTION_KEY
- HMAC_Key = SHA256(
ENCRYPTION_KEY
) - Data = 平文。例:ラウンド1では鍵レコード全体、ラウンド2ではdescriptorレコード全体
MAC
は、上記のように鍵レコードおよびdescriptorレコードと一緒に送信される。これは平文全体に対するMAC
であるため、基本的に認証付き暗号のEncrypt-and-MACフォーマットである。
descriptorテンプレート
output descriptor言語は、1次元のリストのみをサポートする。この提案では、多次元リストを表すdescriptorテンプレートを導入している。
XPUB/**
/**
は、導出パスの制限いくつでも置き換えることができる。
descriptorテンプレートには導出パスの制限を伴う必要がある。署名者は/**
を制限に置き換えて、テンプレートを具体的なdescriptorに拡張する必要がある。
例えば、以下のテンプレートと導出パス制限がある場合:
wsh(sortedmulti(2,XPUB1/**,XPUB2/**))
/0/*,/1/*
以下のような2つの具体的なdescriptorに変換する必要がある:
wsh(sortedmulti(2,XPUB1/0/*,XPUB2/0/*))
wsh(sortedmulti(2,XPUB1/1/*,XPUB2/1/*))
QRコード
QRコードを使ってデータを送信する署名者の場合、BCR標準に従って鍵レコードとdescriptorレコードをQRコードに変換できる。
詳細は、BIP44アカウントのURタイプ定義およびBitcoin Output DescriptorのURタイプ定義を参照。
互換性
この仕様は、既存のマルチシグ実装との後方互換性はない。
BSMSはオプトインで、つまり既存のマルチシグ実装はそのまま継続して使うことができるが、さまざまな落とし穴がある可能性がある。既存のソリューションの問題のいくつかは動機セクションで説明されている。
この標準に準拠するには、署名者はdescriptorレコードをストレージに永続化できる必要がある。
マルチシグウォレットにBSMSを使用するためには、マルチシグに参加しているすべての参加者がBSMSを実装するまで待つ必要がある。
安全性
この提案では2つの保護レイヤーを導入している。1つめは、一時的なシークレットTOKEN
で、もう1つはウォレットの最初のアドレスを確認すること。
TOKEN
は、署名者とコーディネーター間の2階の通信を暗号化するのに使われる。また、交換したデータを認証するために、TOKEN
と平文からMAC
が生成される。TOKEN
はセットアップフェーズでのみ必要で、その後は安全に破棄することができる。同じTOKEN
を複数のウォレット作成セッションで使うのは推奨されない。
一方、ウォレットの最初のアドレスは、マルチシグ設定の安全性を確認するために使用することができる。マルチシグの設定を改ざんした攻撃者は、ウォレットの最初のアドレスも変更しなければならない。参加者は、改ざんの可能性を減らすために、すべての署名者が同じアドレスとポリシーパラメータを確認していることを互いに確認しなければならない。
プライバシー
暗号化は、平文での鍵とdescriptorの共有を回避することで、ウォレットのプライバシーを向上させるのに役立つ。
参加者がより強いプライバシーを望む場合、ビット数の大きいTOKEN
を使用し、マルチシグのセットアップ完了後TOKEN
の知識を完全に消去することを推奨する。
Test Vector
BIP参照。