Develop with pleasure!

福岡でCloudとかBlockchainとか。

BIP-32のキーチェーンから決定論的にエントロピーを導出する仕様BIP-85

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コード表現) 2020/08/01時点の内容で更新

概要

「1つのシードですべてを支配し、1つの鍵がすべてを見つけ、1つのパスがすべてをもたらし、暗号でそれらを縛る」

いろんなウォレットで使用される全てのキーチェーンについて、単一の(ニーモニックのような)シードバックアップを維持することは、互換性のないいろんな規格があるため不可能だ。複数のウォレットにまたがったシードの共有はセキュリティ上の理由から望ましくない。そして複数のシードを物理的に保管することは、必要とされるセキュリティや冗長性に応じて困難だ。

HDキーチェーンは基本的に初期エントロピーから導出されるので、この提案では、ウォレットが初期ニーモニックシードやルートキーを導出するために使用することができるエントロピーをキーチェーンから導出する方法を提供する。

定義

世間で使われているキーチェーンに関する用語は多岐にわたっている。例えば、「シード」はいろんな意味を持っている。この文書では、以下の用語を定義する。

  1. BIP32ルートキーは、BIP32におけるキーチェーンのトップルートとして表されるルート拡張秘密鍵である。
  2. BIP39ニーモニックは、エントロピーから計算されたニーモニックフレーズで、BIP39でニーモニックのハッシュの前に(ニーモニックシードを算出するのに)使われる。
  3. 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

参照実装

Pythonライブラリ実装: python-bipentropy

他の実装

Coldcard Firmwarehttps://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

後方互換

この仕様については、他の既存の仕様は存在しないため、後方互換性はない。

この仕様はBIP32に依存しているが、BIP32ルートキーの導出方法には依存していない。そのため、この標準はBIP39やElectrumウォレットスタイルのニーモニックのような初期化スキームでウォレットの導出を可能にしている。

ディスカッション

HMAC-SHA512を使って鍵を導出し、必要に応じて使用しない後続バイトを削除する理由は、導出鍵(k)が危殆化した場合に親ツリーが漏洩するのを防ぐため。仕様ではこれを防ぐために強化導出の使用を要求しているが、強化導出を強制することはできない。ただしこの方法であれば導出されたエントロピーが確実に強化される。また意味的な観点からも、目的は秘密鍵を導出することではなくて、エントロピーを導出することなので、子鍵を変換する必要がある。これは二重の目的でkを使用する必要がある場合(nonce hash(k)を含めると望ましくない予期せぬ作用が発生する可能性がある)、不要な副作用を防ぐために十分な注意を払って動作する。

*1:ゼロもしくは曲線の位数より大きい無効な鍵を作成する可能性は僅かで、この場合ソフトウェアは完全に失敗し、ユーザーは次のインデックスまで繰り返す必要がある。