Develop with pleasure!

福岡でCloudとかBlockchainとか。

タイムロック付きのFelidity bondのアドレス導出スキームを定義するBIP-46

最近マージされたBIP-46は、Join Marketで既に展開されているFelidity bondのアドレス導出スキームをBIP化したもの↓

https://github.com/bitcoin/bips/blob/master/bip-0046.mediawiki

Fidelity bondとは?

元々の意味は、身元保証で、ある人物の行為によって他者に損害を与えた場合に、身元保証人がその被害を保証する契約を指す。

BitcoinでCoinJoinを用いたミキシングを実装しているJoin Marketでは、シビル攻撃への耐性を高めプライバシーの向上のめにFidelity bondという仕組みを導入している。具体的には、ビットコインを長期間ロックアップすることで(ビットコインを使用できない時間的な犠牲を伴うことで)、シビル耐性を持つ暗号学的IDを作成するというもの。

IDの所有者であることは、

  • ロックしたUTXOのOutPointと
  • ロックしたアドレスのredeem scriptと
  • redeem script内の公開鍵に対応する秘密鍵を使ってメッセージに署名

することで第三者に証明することができる。

鍵導出

BIP-46では、OP_CHECKLOCKTIMEVERIFY opcodeを使用して指定時間までビットコインをロックするスクリプトを、マスターシードから導出するための仕様を定義している。

通常こういったタイムロックされたスクリプトを管理するためには、そのredeem script自体やその一部(タイムロック値)の情報も保存しておく必要があるけど、それらを決定論的に導出するスキームを定義することで、シード以外の情報を保管しなくて済むようにしようというのが狙い。

公開鍵

まず、各公開鍵は、BIP-44の形式↓

m / purpose' / coin_type' / account' / change / address_index

と同様のアカウント構造を使用して導出される↓

m / 84' / 0' / 0' / 2 / index

BIP-44ではchangeの部分は0=受け取り用、1=お釣り用として定義されているけど、BIP-46では2をセットして使用するようになっている。

タイムロックの値

既存のBIPでは、↑のindexの値は0から順番にインクリメントしていくけど、このBIPではindexにロックタイムの値を設定する。指定可能な値は、0〜960まで。指定した値は、2020年1月から2099年12月までの月をカウントするのに使われる。例えば、

  • 0→2020-01-01
  • 1→2020-02-01
  • 2→2020-03-01

と続いていく。こうして指定された月の1日の0:00のUNIXタイムスタンプがFidelity bondのタイムロックの値になる。

Fidelity bondを作成する際に選択した月から、indexの値を計算し、対象の公開鍵を導出する。

既存のアドレス導出のBIPでは、0からインクリメントしてアドレスを導出していき、それらのアドレスが未使用な状態が一定数続いたら、アドレスの導出を止めるgap limitを採用していたるけど、このBIPでは、960個すべてのアドレスを導出して、対象アドレスがチェーン上で使われているかを走査するようになってる。

アドレス

↑で、タイムロックの値と公開鍵が導出できたらそれを使ってFidelity bondのコントラクトを作成する↓

<タイムロック値> OP_CHECKLOCKTIMEVERIFY OP_DROP <公開鍵> OP_CHECKSIG

上記をwitnes scriptとして、P2WSHアドレスを生成すれば、それがFidelity bondのアドレスになる。

中間鍵と証明書

Fidelity bondは上記のように作成されるけど、ロックアップした資金の秘密鍵はコールドストレージで保管したいというユースケースに対応するため、Fidelity bondの所有者であることを証明する中間鍵ペアを用意する。

  1. この中間鍵の鍵情報を記載した証明書を作成し、
  2. それに対してロックアップした秘密鍵で署名を生成し、
  3. 以降Fidelity bondの所有の証明は、中間鍵を用いて行う。

証明書は以下のデータで構成される

fidelity-bond-cert | cert_pubkey | cert_expiry

cert_pubkeyは中間鍵の公開鍵、cert_expiryはこの証明書の有効期限で、2016ブロックの期間の番号で指定する。例えば、cert_expiry = 330の場合、その有効期限はブロック高2016×330 = 665280

ただ、証明書の失効の仕組みはないので、もし中間鍵が侵害された場合、有効期限までは攻撃者によって誤った所有の証明が提供される可能性がある。

証明書への署名は、

0x18 || Bitcoin Signed Message:\n || 証明書のバイトサイズ || 証明書

をメッセージとして、導出した公開鍵に対応する秘密鍵を使って生成される。この署名の生成自体は、任意のメッセージに対して署名する既存のBitcoinのツールの「Sign Message」機能で行える。

以上が、BIP-46の機能。スクリプトエンコードするタイムロックの値を導出スキームに含めることで、Fidelity bondのコントラクトを導出可能にして、シード以外のデータの保存要件をなくしてるのが面白い。

既存のBIPとの非互換性

PRのコメントにあるように、鍵の導出パスのpurposeの部分が、なぜかP2WPKHベースの導出スキームであるBIP-84の番号になっている。purposeの値はサポートするBIPの値ということになってるので、既存のBIPから見ると非互換な仕様になっている。