HDウォレットと拡張秘密鍵|詳解ビットコイン⑤
『詳解ビットコイン』(Kalle Rosenbaum著、オライリージャパン)を読んでいます。その個人的なまとめとして書いていきます。
ウォレットは新アドレスを生成する
基本的にビットコインでは、BTCを受け取ったり送ったりしているうちに、どんどん新しいアドレスが生成されていき、その生成されたアドレスが利用されていくような仕組みになっています。
まず、多くのウォレットアプリでは、「受取」ボタンをクリックするたびに新しいアドレスが生成されて表示されます。たとえば、Ledger Liveというアプリでは、以下画面の「Continue」をクリックして進めると新しいアドレスが生成・表示されます。
またビットコインでは、送金をするときに「おつりアドレス」と呼ばれる新しいアドレスが生成され、そのアドレスが次回以降の支払いなどに使われるようになっています。
なぜ同じアドレスを使い回さないのか
同じアドレスを使い回さないのは、ユーザーのプライバシーをより守れるようにするためです。逆に言えば、ずっと同じアドレスを使っている場合、個人的な情報が他人に知られる恐れが高まります。
前提として、ビットコインではほかの部分でもプライバシー保護が意識されており、ブロックチェーンに取引内容を記録していく際に利用者名を含みません。利用者名の代わりにアドレス(ビットコインアドレス)を使っており、取引内容が公開されていてもある程度はプライバシーを守ることができます。
以下はアドレスを用いて記録したときのイメージです。誰が誰だかわかりづらくなります。
しかし、利用者名の代わりにアドレスを使うだけでは、プライバシー保護の点で十分だとはいえません。アドレスと利用者名が一度照合されてしまえば、その人がどんな取引をしているかが知られてしまいます。
新しいアドレスが使われることで、上記の問題をある程度は解消できます。利用者とアドレスの紐づけが完全にできなくなるわけではないですが、同じアドレスを使い続けるよりはましですね。
バックアップに工夫が必要
アドレスは公開鍵から作られ、公開鍵は秘密鍵から作られます。そのため新しいアドレスが生成されるときは、まずは秘密鍵、それから公開鍵、次にアドレスというように作られていくのが基本のはずです。
これを踏まえると、新しく作られた秘密鍵をどのようにバックアップするかを考える必要があるでしょう。ビットコインネットワークを利用していると新しいアドレスが作られていくということは、新しい秘密鍵も生成されているということで、新しく作った秘密鍵のバックアップを取っていかないといけません。
バックアップ方法の例と問題点
単純なバックアップの方法として、新しいアドレスを作るたびにバックアップファイルがメールで送られてくるというやり方が挙げられます。
しかし、このやり方には複数の問題があります。
まず、ネットワークをたくさん使う人であれば、1カ月間に何十通ものバックファイルが届くことになるはずで、そうなると管理すべきファイルが多すぎて大変でしょう。また、セキュリティ的にも問題があります。メールサーバにアクセスできる人がバックアップファイルを勝手に確認すると、秘密鍵がばれてしまいます。
改善されたバックアップ方法と問題点
詳解ビットコインには、上記の方法の改善策が記載されています。その改善策とは以下の2つです。
1ファイルに100個のアドレスの秘密鍵を記載
バックアップファイルにパスワードを設定
1つ目の方法は、あらかじめ100個のアドレスを作っており、その秘密鍵をまとめてメールで送るという内容です。そして、101個目のアドレスを作る必要ができたなら、ウォレットは101~200個目のアドレスを一気に作り、その分の秘密鍵をまとめて1ファイルでメールすることになります。この方法ならば管理すべきファイル数は少数になります。
2つ目の方法は、バックアップファイルにユーザーが指定したパスワードを設定しておくという内容です。これなら他人にファイルを見られる可能性が減ります。
しかし、まだ問題があります。問題の一つ目は、ユーザーがいちいち不規則性の高いパスワードを作れるとは考えられない点です。また、パスワードを安全な環境でしっかり保管できるかどうかも怪しく、これも問題です。面倒くさがってネット上に保存してしまうことや、うっかりパスワードをなくしてしまうことも想定できます。
HDウォレットでバックアップが容易に
ここまで見てきた中での問題は、プライバシーをしっかり保護しようとすると、秘密鍵の管理が難しくなってしまうということでした。
なかなか手ごわそうな問題ですが、ビットコインはすでにこの問題を解決しています。実際にビットコインウォレットを使ってみるとわかることですが、最初にシードフレーズのバックアップを取れば、その後にはバックアップを取る必要はありません。
これを可能にしているは、HDウォレット(階層的決定性ウォレット)という性質のウォレットです。HDウォレットでは、一つの乱数値(不規則で予測不可能な値)を派生させる形でウォレット内のすべてのアドレスを作ります。HDウォレットでは、以下のように一つの要素が枝分かれしていきます。
ちなみに、HDウォレットのようなデータ構造は「木構造」と呼ばれています。木をひっくりかえしたような構造で、ブロックチェーンでも活用されています。
HDウォレットでは、一つの乱数値を派生させる形でウォレット内のすべてのアドレスを作るので、たった一つの乱数値のバックアップさえ取れていれば、そのウォレットで生成されるすべてのアドレスのバックアップが取れていることになるのです。
以降では、HDウォレットがアドレスを生成する流れを整理していきます。
①乱数値を生成する
HDウォレットを作成すると、乱数値を生成することになります。
この乱数値はウォレット内で作られるすべてのアドレスの元になります。乱数値が知られたらウォレット内の資産にアクセスできるので、予測不可能なように作る必要があります。また、紙にメモして金庫に保管するなど、安全な方法で管理する必要もあります。
ほとんどのウォレットアプリでは、そのアプリ内で自動的に乱数値(疑似乱数値)が生成されます。この生成方法でも問題はないだろうとされていますが、セキュリティをより強固にしたい場合は、自分でサイコロを投げるなどして本物の乱数値を作ることもできます。
②マスター拡張秘密鍵を生成する
続いて、乱数のシードから「マスター拡張秘密鍵」というものを作ります。
このあとにも記載しますが、拡張秘密鍵(xprv)とは、秘密鍵に付属品(チェーンコード)がセットになった状態のもので、HDウォレット内でどんどん作られていきます。拡張秘密鍵のうち、HDウォレット内で最も上流に位置するのがマスター拡張秘密鍵です。
乱数のシードからマスター拡張秘密鍵を作るには、まず乱数値をハッシングします。
このとき利用するのは、HMAC-SHA-512という暗号学的ハッシュ関数です。512ビットの出力を生成できます。通常の入力に加えて「鍵」と呼ばれる値も入力する必要があります。(下図では「xxx…」が鍵を表しています。)
HMAC-SHA-512の出力の前半部分は、マスター秘密鍵になります。後半部分はチェーンコードと呼ばれるものになり、それ以降に行うアドレス生成時に利用されます。目的は乱雑性(エントロピー)を提供して、生成されるアドレスが予測困難なものにすることです。
秘密鍵とチェーンコードから構成されるものは、拡張秘密鍵と呼ばれます。拡張秘密鍵は、xprvと記載されることもあります。xprvは、拡張秘密鍵の英語表記(extended private key)を省略した形です。下図では「xprv (m)」としていますが、この「(m)」はマスターであることを表しています。
③子の拡張秘密鍵を生成する
マスター拡張秘密鍵を親として、その直下に子の拡張秘密鍵を作っていくことができます。
子の拡張秘密鍵を作るにはまず、親の秘密鍵を公開鍵生成関数で処理し、公開鍵を作成します。その公開鍵と親のチェーンコード、そして「鍵」を入力としてHMAC-SHA-512でハッシングします。このとき「鍵」には番号を入れます。これがインデックスとなり、親から作られる1つ目の鍵になるのであれば「0」、2つ目なら「1」といった順番で入力します。
出力の前半部分を親の秘密鍵に加算して得られた和が子秘密鍵となります。出力の後半部分はチェーンコードとなります。そして、ここで作られた子秘密鍵とチェーンコードから構成されるのが、子の拡張秘密鍵です。
このようにして、同じ親から複数の子拡張秘密鍵を作っていくことができます。また、子の拡張秘密鍵を使い、子の子にあたる拡張秘密鍵を作っていくこともできます。