Bitcoinの鍵を管理するウォレットでは、BIP-32のHDウォレットの仕様↓をサポートし、マスターシードから取引に使用する個別の鍵を導出するようになっているのがほとんど。
techmedia-think.hatenablog.com
さらにBIP-39の仕様を利用してマスターシードを12個、24個の単語(ニーモニック)にして、ユーザーにバックアップさせることが多い。
これらの仕様により鍵のバックアップは随分簡単になったけど、
- Bitcoin CoreのウォレットはHDウォレットはサポートしているけど、BIP-39のニーモニックはサポートしていない。
- Bitcoinのウォレットでも例えばElectrumはBIP-39との互換性がないなど、ウォレット間で必ずしも同じ仕様に準拠していない。
- さらに暗号通貨が異なると採用されているニーモニックの導出仕様も違う。
といった課題があり、複数のウォレットや暗号通貨を利用する場合、結局異なるウォレットで別のマスターシードを作成して、ニーモニックもそれぞれ別に管理するといった不便な状況が発生する。
この課題について、エントロピーからマスターシードを導出する部分はどのウォレットや暗号通貨でも変わらないので、BIP32のキーチェンの仕様をエントロピーを導出する仕様に使うことで、↑の課題を解決しようと新しく提案されたのがBIP-85↓
https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki
このBIPではBIP-32のキーチェンの仕組みを使って、各アプリケーション用に(以下は現在定義されているアプリケーション)、エントロピーを導出できるようにしている。
そのためユーザーはBIP-85のマスタールートキーのみをバックアップしておけば(直接保存しても、これをBIP-39のニーモニックで保存してもOK)、各アプリケーション用のエントロピーを復元することができる。
※ なお、元となる初期エントロピーの生成方法については、このBIPでは特に規定していない。
以下、BIPの意訳↓(ちなみにパスに出てくる83696968
という数字は、SEED
という文字列のASCIIコード表現) 2021/02/12時点の内容で更新
概要
「1つのシードですべてを支配し、1つの鍵がすべてを見つけ、1つのパスがすべてをもたらし、暗号でそれらを縛る」
いろんなウォレットで使用される全てのキーチェーンについて、単一の(ニーモニックのような)シードバックアップを維持することは、互換性のないいろんな規格があるため不可能だ。複数のウォレットにまたがったシードの共有はセキュリティ上の理由から望ましくない。そして複数のシードを物理的に保管することは、必要とされるセキュリティや冗長性に応じて困難だ。
HDキーチェーンは基本的に初期エントロピーから導出されるので、この提案では、ウォレットが初期ニーモニックシードやルートキーを導出するために使用することができるエントロピーをキーチェーンから導出する方法を提供する。
定義
世間で使われているキーチェーンに関する用語は多岐にわたっている。例えば、「シード」はいろんな意味を持っている。この文書では、以下の用語を定義する。
- BIP32ルートキーは、BIP32におけるキーチェーンのトップルートとして表されるルート拡張秘密鍵である。
- BIP39ニーモニックは、エントロピーから計算されたニーモニックフレーズで、BIP39でニーモニックのハッシュの前に(ニーモニックシードを算出するのに)使われる。
- BIP39ニーモニックシードは、BIP39ニーモニックシードををハッシュした結果である。
動機
ほとんどのウォレットは、BIP32ルートキーを使ってキーチェーンを導出する方法を定義しているBIP32を実装している。その結果、BIP32ルートキーのバックアップだけで、そこから導出した全ての鍵が含まれていることになる。BIP32では、BIP32ルートキー(もしくは通常BIP32拡張鍵と言われる)を人間が使いやすいようシリアライズする機能は持っていないため、紙でのバックアップや手入力で鍵を復元するとエラーが発生しやすくなる。BIP39はこの問題を解決するために設計されたが、BIP32ルートキーをシリアライズするのではなく、「シードニーモニック」にエンコードされたエントロピーを受け取り、これをハッシュしてBIP32ルートキーに変換することができるBIP39シードを導出する。BIP39ニーモニックを保存すれば、BIP32キーチェーン全体を再構築するのに十分だが、BIP32ルートキーをBIP39ニーモニックに戻すことはできない。
ほとんどのウォレットはBIP39を実装しているため、初期化や復元の際にはBIP39ニーモニックを使わなければならない。ほとんどのウォレットはBIP32拡張秘密鍵をサポートしていないので、各ウォレットは同じBIP39ニーモニックを共有するか、全く別のBIP39ニーモニックを持つ必要がある。どちらのケースもセキュリティ上の理由から満足できるものではない。例えば、スマートフォン上で動作するホットウォレットやJoin Marketサーバー、Lightning Networkノードのように本質的に低セキュリティなウォレットがある。複数のシードを持つことは、特に地理的に異なる場所にある分割した鍵や冗長バックアップに依存している人にとっては望ましくない。シードを追加するのにハードルがあるため、後の鍵の追加ほど怠惰になる可能性があり、ユーザーがセキュリティを損なうか鍵の損失につながるような可能性がある。
他の規格を実装しているウォレットはや、まったく規格のないウォレットでは、さらに複雑さが増す。Bitcoin CoreウォレットはhdseedとしてWIFを使っているが、他のウォレットではBIP32ルートキーを導出するのにElectrumのように異なるニーモニックスキームを使用しているケースもある。Moneroのような他の暗号通貨も、まったく異なるニーモニックスキームを使っている。
最終的に、すべてのニーモニック/シードスキームは、ニーモニック/シードを導出するための「初期エントロピー」から始まって、ニーモニックをBIP32ルートキーもしくは秘密鍵にする。我々は、BIP32自体を使って「初期エントロピー」を導出し、ターゲットとなるウォレットの特定のアプリケーション標準に従って、同じニーモニックやシードを再作成することができる。BIP44のような分類を使って、ターゲットアプリケーションタイプに応じた鍵の導出を確実にすることができる。
仕様
我々は単一のBIP32マスタールートキーを想定する。この仕様では、それがどうやって導出されたか(直接なのか、BIP39などのニーモニックスキームを介してなのかなど)には関係しない。
独自のウォレットを必要とする各アプリケーションに対して、完全な強化導出パスを使ってBIP32マスタールートキーから一意の秘密鍵が導出される。結果として得られた秘密鍵(k)は、続いてHMAC-SHA512で処理される。なお、この時に使用される鍵はbip-entropy-from-k
で、メッセージペイロードは秘密鍵k
を使う、つまりHMAC-SHA512(key="bip-entropy-from-k", msg=k)
。結果、512 bitのエントロピーが生成される。各アプリケーションは、操作に必要なbit数を使用し、残りは切り捨てる。
HMAC-SHA512関数はRFC 4231で定義されている。
Test Vectors
テストケース1
入力:
- マスターBIP32ルートキー:
xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb - PATH: m/83696968'/0'/0'
出力:
- 導出鍵:
cca20ccb0e9a90feb0912870c3323b24874b0ca3d8018c4b96d0b97c0e82ded0 - 導出されたエントロピー:
efecfbccffea313214232d29e71563d941229afb4338c21f9517c41aaa0d16f00b83d2a09ef747e7a64e8e2bd5a14869e693da66ce94ac2da570ab7ee48618f7
テストケース2
入力:
- マスターBIP32ルートキー:
xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb - PATH: m/83696968'/0'/1'
出力:
- 導出鍵:
503776919131758bb7de7beb6c0ae24894f4ec042c26032890c29359216e21ba - 導出されたエントロピー:
70c6e3e8ebee8dc4c0dbba66076819bb8c09672527c4277ca8729532ad711872218f826919f6b67218adde99018a6df9095ab2b58d803b5b93ec9802085a690e
BIP85-DRNG
BIP85-DRNG-SHAKE256は、決定論的な出力を必要とするが、その関数への入力がBIP85のHMAC出力によって提供される64バイト以上を必要とする暗号関数用の決定論的な乱数生成器である。BIP85-DRNG-SHAKE256は、(SHA-3標準の)SHAKE256ストリームをシードするためにBIP85を使用する。入力は正確に(BIP85のHMAC出力からで)64バイトでなければならない。
RSA鍵生成は64バイト以上のランダムな入力を必要とする機能の一例。さらに関数が完了するまで、必要なランダム入力の量を事前に計算することはできない。
drng_reader = BIP85DRNG.new(bip85_entropy)
rsa_key = RSA.generate_key(4096, drng_reader.read())
Test Vector
入力:xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb
- マスターBIP32ルートキー:m/83696968'/0'/0'
出力:
- 導出鍵:cca20ccb0e9a90feb0912870c3323b24874b0ca3d8018c4b96d0b97c0e82ded0
- 導出されたエントロピー:efecfbccffea313214232d29e71563d941229afb4338c21f9517c41aaa0d16f00b83d2a09ef747e7a64e8e2bd5a14869e693da66ce94ac2da570ab7ee48618f7
- DRNG(80バイト):b78b1ee6b345eae6836c2d53d33c64cdaf9a696487be81b03e822dc84b3f1cd883d7559e53d175f243e4c349e822a957bbff9224bc5dde9492ef54e8a439f6bc8c7355b87a925a37ee405a7502991111
参照実装
- Pythonライブラリ実装: python-bipentropy
- JavaScripライブラリ実装:bip85-js
他の実装
- JavaScripライブラリ実装:bip85-js
- Coldcard Firmware: https://github.com/Coldcard/firmware/pull/39
アプリケーション
アプリケーション番号は、エントロピーが後続のプロセスでどのように使用されるかを定義する。以下に基本的な例を示す。
導出パスm/83696968/' + /app_no' + /index'
を使用する場合、app_no
はアプリケーションのパスで、index
はアプリケーション内のインデックスを表す。
m/83696968'/39'/0'/12'/0'
は12個の英単語を持つBIP39ニーモニックの(最初のインデックスの)パスで、次のキーのパスはm/83696968'/39'/0'/12'/1'
。
BIP39
アプリケーション番号: 39'
エントロピーの末尾(最下位)のバイトについては、関連する単語の長さにマップするのに必要なビット数に切り詰める。12単語の場合は128 bit、24単語の場合は256 bit。
導出パスのフォーマットは:m/83696968'/39'/{language}'/{words}'/{index}'
12英単語のBIP39ニーモニックの最初のインデックスのパスはm/83696968'/39'/0'/12'/0'
で、次の鍵のパスはm/83696968'/39'/0'/12'/1'
。
言語表
単語リスト | コード |
---|---|
English | 0' |
Japanese | 1' |
Korean | 2' |
Spanish | 3' |
Chinese (Simplified) | 4' |
Chinese (Traditional) | 5' |
French | 6' |
Italian | 7' |
Czech | 8' |
単語表
単語|エントロピー|コード 12単語|128 bit|12' 18単語|192 bit|18' 24単語|256 bit|24'
12英単語
BIP39の12英単語ニーモニックシード
12単語のニーモニックを導出するためBIP39への入力として128 bitのエントロピーが必要
入力:
- マスターBIP32ルートキー:
xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb - パス: m/83696968'/39'/0'/12'/0'
出力:
- 導出鍵: 6250b68daf746d12a24d58b4787a714b
- 導出されたBIP39ニーモニック: girl mad pet galaxy egg matter matrix prison refuse sense ordinary nose
18英単語
BIP39の18英単語ニーモニックシード
18単語のニーモニックを導出するためBIP39への入力として196 bitのエントロピーが必要
入力:
- マスターBIP32ルートキー:
xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb - パス: m/83696968'/39'/0'/18'/0'
出力:
- 導出鍵: 938033ed8b12698449d4bbca3c853c66b293ea1b1ce9d9dc
- 導出されたBIP39ニーモニック: near account window bike charge season chef number sketch tomorrow excuse sniff circle vital hockey outdoor supply token
24英単語
BIP39の24英単語ニーモニックシード
24単語のニーモニックを導出するためBIP39への入力として256 bitのエントロピーが必要
入力:
- マスターBIP32ルートキー:
xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb - パス: m/83696968'/39'/0'/24'/0'
出力:
- マスターBIP32ルートキー:
xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb - パス: m/83696968'/39'/0'/18'/0'
出力:
- 導出鍵: 938033ed8b12698449d4bbca3c853c66b293ea1b1ce9d9dc
- 導出されたBIP39ニーモニック: near account window bike charge season chef number sketch tomorrow excuse sniff circle vital hockey outdoor supply token
- 導出鍵: ae131e2312cdc61331542efe0d1077bac5ea803adf24b313a4f0e48e9c51f37f
- 導出されたBIP39ニーモニック: puppy ocean match cereal symbol another shed magic wrap hammer bulb intact gadget divorce twin tonight reason outdoor destroy simple truth cigar social volcano
WIF形式のHDシード
アプリケーション番号: 2'
256 bit*1のエントロピーをsecret exponentとして秘密鍵を導出し、Bitcoin Coreウォレットのhdseedとして使用される圧縮WIFとしてエンコードする。
BIP32より、parse256(IL) ≥ n もしくは ki = 0の場合、結果の鍵は無効で、iを次の値に進める必要がある(これは1/2127 よりも低い確率)。
パスフォーマット: m/83696968'/2'/{index}'
入力:
- マスターBIP32ルートキー:
xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb - パス: m/83696968'/2'/0'
出力:
- 導出鍵: 7040bb53104f27367f317558e78a994ada7296c6fde36a364e5baf206e502bb1
- 導出されたWIF: Kzyv4uF39d4Jrw2W7UryTHwZr1zQVNk4dAFyqE6BuMrMh1Za7uhp
XPRV
アプリケーション番号: 32'
(BIP32の拡張ルート秘密鍵の導出)HMACダイジェストの64バイトについて、最初の32バイトがchaincode、後半の32バイトがBIP32 XPRV値の秘密鍵となる。子どもの番号、深さ、親のfingerprintは強制的に0になる。
パスフォーマット: m/83696968'/32'/{index}'
入力:
- マスターBIP32ルートキー:
xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb - パス: m/83696968'/32'/0'
出力:
- 導出鍵: ead0b33988a616cf6a497f1c169d9e92562604e38305ccd3fc96f2252c177682
- 導出されたWIF:
xprv9s21ZrQH143K2srSbCSg4m4kLvPMzcWydgmKEnMmoZUurYuBuYG46c6P71UGXMzmriLzCCBvKQWBUv3vPB3m1SATMhp3uEjXHJ42jFg7myX
HEX
アプリケーション番号: 128169'
導出パスフォーマット: m/83696968'/128169'/{num_bytes}'/{index}
16 <= num_bytes <= 64
num_bytes
の後のエントロピーの末尾(最下位)のバイトは切り捨てる。
入力:
- マスターBIP32ルートキー:
xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb - パス: m/83696968'/128169'/64'/0'
出力:
- 導出されたエントロピー:
492db4698cf3b73a5a24998aa3e9d7fa96275d85724a91e71aa2d645442f878555d078fd1f1f67e368976f04137b1f7a0d19232136ca50c44614af72b5582a5c
RSA
アプリケーション番号: 828365'
導出パスフォーマット:m/83696968'/828365'/{key_bits}'/{key_index}'
RSA鍵生成器は、入力のRNG関数としてBIP85-DRNGを使用する必要がある。
RS GPG
RSA-GPG用に割り当てられた鍵は、以下のスキームを使用する:
- Main key <code>m/83696968'/828365'/{key_bits}'/{key_index}'</code> - Sub keys: <code>m/83696968'/828365'/{key_bits}'/{key_index}'/{sub_key}'</code>
- key_indexはCERTIFY機能の親鍵
- sub_key 0' は、暗号化鍵として使われる。
- sub_key 1' は、認証鍵として使われる。
- sub_key 2' は、署名鍵として使われる。
タイムスタンプに関する注意:
生成されたRSA鍵は、鍵のFingerprintが作成日に影響されるため、作成日をUnixエポックタイムスタンプ1231006505(Bitcoinのジェネシスブロックの時間'2009-01-03 18:05:05' UTC)に固定しなければならないGPG鍵を作成するのに使用することができる(古い鍵のGNUPG実装ではレガシーな動作のため、エポックタイムスタンプ0は選択されなかった)。さらに、GNUPGにおいて鍵の下にあるサブキーをインポートする差異には、インポートする前に(faketimeなどを使って)システム時刻を同じタイムスタンプに固定しなければならない。
スマートカード/ハードウェアデバイスのGPG鍵機能に関する注意:
GPG対応のスマートカードは次のようにロードする必要がある。暗号化スロットはENCRYPTION対応の鍵でロードされるべきで、認証スロットはAUTHENTICATION対応の鍵でロードされる必要がある。署名可能なスロットにはSIGNATURE対応の鍵をロードする必要がある。
しかし、スマートカード上の利用可能なスロットおよび好ましいポリシーによっては、CERTIFY対応の鍵はCERTIFYおよびSIGNATURE機能でフラグが立てられ、SIGNATURE対応のスロットにロードされることがある(例えば、スマートカードに3つのスロットしかなく、同じカードにCERTIFY機能が必要な場合など)。この場合、CERTIFY対応の鍵が二重で目的を果たすため、SIGNATURE対応のサブキーは無視される。
後方互換性
この仕様については、他の既存の仕様は存在しないため、後方互換性はない。
この仕様はBIP32に依存しているが、BIP32ルートキーの導出方法には依存していない。そのため、この標準はBIP39やElectrumウォレットスタイルのニーモニックのような初期化スキームでウォレットの導出を可能にしている。
ディスカッション
HMAC-SHA512を使って鍵を導出し、必要に応じて使用しない後続バイトを削除する理由は、導出鍵(k)が危殆化した場合に親ツリーが漏洩するのを防ぐため。仕様ではこれを防ぐために強化導出の使用を要求しているが、強化導出を強制することはできない。ただしこの方法であれば導出されたエントロピーが確実に強化される。また意味的な観点からも、目的は秘密鍵を導出することではなくて、エントロピーを導出することなので、子鍵を変換する必要がある。これは二重の目的でkを使用する必要がある場合(nonce hash(k)を含めると望ましくない予期せぬ作用が発生する可能性がある)、不要な副作用を防ぐために十分な注意を払って動作する。
*1:ゼロもしくは曲線の位数より大きい無効な鍵を作成する可能性は僅かで、この場合ソフトウェアは完全に失敗し、ユーザーは次のインデックスまで繰り返す必要がある。