公開鍵暗号と決定性ウォレットへの発展

楕円曲線暗号とECDSA署名

ビットコインにおいては、今まで多用されていきたRSAではなく、楕円曲線暗号を使用する。これは、RSA暗号に比較し、処理速度が早いことが理由である。 これが採用できる重要な理由は、一方向性関数であることだ。

その性質に違いはない。公開鍵で暗号化したメッセージは、それに対応した秘密鍵でしか複合できない。
逆に、秘密鍵で暗号化したメッセージは、それに対応した公開鍵でしか復元できない。この方式をECDSA署名と呼ぶ。

公開鍵暗号方式のbitcoinへの応用

bitcoinへのアクセスコントロールは、公開鍵暗号方式が利用される。
この場合、公開鍵は受け取りに、秘密鍵はbitcoinのトランザクション生成への署名に利用される。

異なるのは、下記の仕組みだ。

  1. 秘密鍵は、ランダムに生成される
  2. 公開鍵は、秘密鍵から、楕円曲線アルゴリズムによって生成される。
  3. さらに、この公開鍵から不可逆ハッシュ関数を用いて、bitcoinアドレスが生成される。

bitcoinアドレス

bitcoinアドレスは、公開鍵から不可逆ハッシュアルゴリズムを使用して生成される。それは、1から始まる。

なぜ、公開鍵ではなく、さらにbitcoinアドレスという抽象化された名称を生成するのか。これは、原論文の説明で理解できる。

公開鍵を匿名にするのである。ある額を誰かが誰かに送金したことは全参加者に知られるが、他に情報がなければ、どういった人物が取引に関わったかは見抜かれない。

bitcoinアドレスは、sha256等の組み合わせによって作成されるが、この一方向性関数を利用したハッシュは、広範囲に利用される。具体的には、bitcoinアドレス、scriptアドレス、proof of workアルゴリズムに使用される。

加えて、そのハッシュ値は、Base58Checkにより、エンコードする。これは、ひとが理解できる形式にするためだ。

ウォレットの概念

暗号通貨に置けるウォレットも、既存の直感には反する。 ウォレットは秘密鍵のコンテナであり、簡単なデータベースをイメージしてもらえればと思う。

要は、bitcoinウォレットにおいては、キーを保持しているだけで、コインそのものは保持していない。ウォレットというよりは、キーホルダーといったほうが表現は正しいだろう。

非決定性ウォレット

これが実装当初のBitcoin walletだ。 単に、ランダムに生成された秘密鍵の集合である。 生成された秘密鍵は一度しか使用しない。例えば、ウォレットを生成したタイミングで、100個の秘密鍵を作り、それぞれは一回しか使われない。

Just a bunch of keysとも呼ばれるが、生成されたキーはすべて保存する必要があり、その利便性の低さからほとんど利用されない。

決定性ウォレット

決定性ウォレットは、別名seededウォレットとも呼ばれる。

秘密鍵の生成の前に、一段かませるのである。それはseedと呼ばれ、シードからお決まりの一方向性関数から生成される。

seedの値は、指数またはchain codeにより定まる。
このseed自体、きわめて人間には覚えづらい形式となっているため、BIP0032において、単語から構成された「パスフレーズ」からseedを作成することが可能となった。

これは、日本語のパスフレーズから生成することも可能だ。ただし、これはBIPであり、すべてのウォレットで互換性があるわけではない。 例えば、モバイルウォレットのbreadは日本語のパスフレーズを生成するにも関わらず、デスクトップウォレットのMultibit HDは英語にしか対応していないので、英語ユーザーはbreadwallet⇒Multibit HDのパスフレーズのインポートができるが、日本語ユーザーはできないという状況になる。

Mnemonic Code Words

上記パスフレーズは、Mnemonic Code Wordsと呼ばれる。 これはBIP0039において定義されている。

Mnemonic Codeとseedの生成は下記の手順のように定義されている。

  1. ランダムな配列(entropy)を生成する
  2. entropyを11bitで分割する
  3. Mnemonic Codeを表す単語を生成する
  4. PBKDF2という拡張関数を使用し、seedが生成される

階層的決定性ウォレット

決定性ウォレットをさらに発展し、1つのシードから多くのキーを生成するためにBIP0032で定義された形が、階層的決定性ウォレット、またはHDウォレットである。

これは、キーが階層的にツリー構造を作り、子キーがさらに子キーを無限の階層を作り出すことが可能である。

ランダムと比較することで、HDのメリットが見えてくる。大きなメリットは、下記の2つだ。

  1. この階層構造に、付加的な組織的意味合いを内包する。例えば、サブキーのブランチごとに、おつり受け取り用と支払い用で分ける、とか、ブランチを組織単位にする、とか。

  2. ユーザは、秘密鍵に触れることなく公開鍵を生成することができる。公開鍵をあらかじめサーバに配置する必要もないため、きわめてセキュアな構造とできる。ただし、秘密鍵は保持できない。

シード、HDの関係性の整理

ルートシードは、上述の決定性ウォレットと性質は変わらない。 単語から構成された「パスフレーズ」からseedを作成することが可能だ。

HD上に存在するすべては、このルートシードから再導出することが可能である。つまり、ルートシードさえコピーすれば、全ての子キーのバックアップ、リストア、エクスポートが可能となる。

ルートシードは、一方向性関数HMAC SHA512に対するインプットであり、その出力としてmaster key とmaster chain codeが生成される。 chain codeは親キーから子キーを生成する際のエントロピーの導入に利用されている、

child keyの導出

これは、child key derivation(CKD)関数により行われる。 インプットは下記だ。

  1. chain code(seed)
  2. 子秘密鍵または子公開鍵(ECDSA圧縮)
  3. インデックス

このインプットからの出力の流れは、ルートシードの時と同じだ。上記は、一方向性関数HMAC SHA512に対するインプットであり、その出力としてchild key とchain codeが生成される。

このインデックスを変更することで、同一のchain codeと、キーから異なる子キーを作成することが可能となる。最大数は20だ。この繰り返しによって、ツリー構造で無限に下っていくことが可能となる。

それぞれの子キーは、いかなるほかの子キーを知ることもできない。

拡張キー

chain codeと秘密鍵の組み合わせを、拡張キー、または拡張可能キーと呼ぶ。子キーを生成することができるからだ。

この拡張キーは、拡張秘密鍵と、公開鍵限定の拡張公開鍵に分けることができる。

この拡張キーは、BASE58Checkでエンコードされる。この仕組みを使うことで、BIP0032対応ウォレット間では互換性が生まれ、エクスポート、及びインポートを柔軟に実施することが可能となる。

拡張キーから子キーを作るためには、二つの性質があることになる。 一つ目は、子公開キーを子秘密キーから作るか、親公開キーから作るかである。

この、後者からの仕組みは非常にセキュアなサーバの構築を可能にする。このサーバには公開鍵、及びそこから生成されるビットコインアドレスしか残していなければ、万が一このサーバがハッキングされても、送金トランザクションへの署名手段は存在しないことになる。

応用例が、ハードウェアウォレットである。 拡張秘密鍵をペーパーウォレットやハードウェアデバイスに格納し、受け取りはオンライン上の拡張公開鍵で実行して、送金時にはハードウェアウォレットへの送金を実施する。

潜在的リスクは、chain codeを含んでいるため、秘密鍵が流出した場合はそれにつらなるすべての子秘密鍵が流出してしまうことだ。このリスクには、対策が実装されている。 HDでは、hardened derivationという仕組みがある。これは、親公開鍵と、子chain codeの関係性を壊す。この仕組みにおいては、親公開キーではなく、親秘密キーを用いて、子chain codeを導出する。さらに、これは親秘密鍵や兄弟秘密鍵との関係を導出できないchain codeが使用されているため、ファイヤーウォールのような動きをする。

ベストプラクティスは、マスターキーの一階層目をhardened derivation関数を用いて導出しておくことだろう。

暗号化秘密鍵

秘密鍵は絶対に公開してはいけない。ということはわかるが、それを守り続けることは難しい。自分がアクセスできるということは、他の人もアクセスできるということだ。

この問題を解決するため、持ち出し可能な暗号化秘密鍵がBIP0038提案されている。既に、多くのウォレットで導入済である。

パスフレーズで秘密鍵をさらに暗号化し、Base58Checkでエンコードを行う。この暗号化基準は、軍用アプリケーション基準に広く使われている。 結果、6Pから始まる暗号化秘密鍵が得られ、通常の秘密鍵形式に戻すためには、パスフレーズが必要となる。