Develop with pleasure!

福岡でCloudとかBlockchainとか。

Federated Pegのアドレス導出スキーム

Blockstreamが公開しているSidechainのホワイトペーパーのAppendixにFederated Pegを行う際のP2SHアドレスの導出スキームが定義されている。このFederated Pegの仕組みは同じくBlockstreamが公開しているサイドチェーンの実装Elements Alphaでも利用されている。

techmedia-think.hatenablog.com

楕円曲線の準同型性を利用したこのアドレス導出のスキームの実装がどうなってるのか見てみる。

Federated Pegのコンセプト

現在のBitcoinスクリプトにはSPV proof検証が行えるような機能は無いため、Bitcoinとサイドチェーンをペグする方法としてはFederated Pegを利用する方法がとられている。OP_SIDECHAINPROOFVERIFYのようなソフトフォークも考えられているみたいだけど、最近のSegwitのデプロイ状況を見てもわかるようにソフトフォークといっても合意を取るのは難しいので、ソフトフォーク無しでペグするのが現状は妥当なアプローチだと思う。

Federated Pegでは、信頼できる連合の職員にスクリプトを評価させることで、Bitcoinスクリプトを拡張して実現しようとしていた機能を外部的に実装している。そのため連合の職員というトラスポイントが発生する。

ホワイトペーパーに記載されている例より

連合職員5人の内3人の署名が必要なケースを考えた場合、連合はsecp256k1の楕円曲線上の点(公開鍵)P1、P2、P3、P4、P5と、redeemscriptのテンプレート3 x x x x x 5 OP_CHECKMULTISIGを持ち、それらはサイドチェーンの全参加者に知られている。ユーザはfederated pegを使ってサイドチェーン上でコインを有効にするため、以下のスキームでクロスチェーンP2SHアドレスを導出する。

f:id:techmedia-think:20161218161811p:plain

この導出スキームはBIP-32で使われているのと同じ準同型の手法をベースにしていて、第三者がリンク不可能なアドレスを生成でき、pay-to-contractトランザクションと同じ構成でもある。

アドレスを生成すると、そのアドレス宛てにコインを送る。コインを送ったユーザは連合の職員にnonceとscriptPubkey、SPV proofに提供すると(職員がBitcoinのブロックチェーン上の支払いを確認するのに必要)、送ったコインと同額のコインをサイドチェーン上で入手することができる。Bitcoinとサイドチェーン間のコインの転送は、標準のP2SHアドレスへ支払い、任意のScriptPubKeyに対して支払われるので、マルチシグアドレスをサポートしているBitcoinサービスであればすぐにでもfederated pegを利用してサイドチェーンへのコインの支払い、サイドチェーンからのコインの受取ができる。

federated pegのアプローチではチェーン間の移動の際に連合の職員というトラストポイントが発生するが、Bitcoinになんら変更を加える必要がないのと、サイドチェーンの利用を限られたユーザのみにしぼりたい場合も、連合の職員によってそういった制御をすることが可能になるといったメリットもある。

実装

実はこれをRubyで実装したものがbitcoin-rubyの一部にある↓

https://github.com/lian/bitcoin-ruby/blob/master/lib/bitcoin/contracthash.rb

ので、身近なRubyの実装でみていく。

アドレスの導出

コインをBitcoinからサイドチェーンに送る際のP2SHアドレスを計算する。

bitcoin-rubyでこれを実装しているのがBitcoin::ContractHash#generate

引数に渡すのが↓の3つ

  • redeem_script_template
    redeemscriptのテンプレートで↑のホワイトペーパーでは、3 x x x x x 5 OP_CHECKMULTISIGの部分。
  • payee_address
    サイドチェーン上でコインを受け取るアドレス(ホワイトペーパーではScriptPubKey)
  • nonce_hex
    128bitの乱数

この実装が↑のホワイトペーパーに記載されているアドレス導出スキームの実装にあたり、以下のプロセスでP2SHアドレスを生成している。

  1. noncepayee_addressを組み合わせてdataを生成する
  2. redeem_script_template3 x x x x x 5 OP_CHECKMULTISIG)のマルチシグの各公開鍵=楕円曲線上の点に対して、1で生成したdataを加算して新しい点=公開鍵を生成する。
  3. redeem_script_templateの各公開鍵の部分を、2で生成した新しい公開鍵に置き換えたP2SHスクリプトを生成する。
  4. 3で生成したP2SHスクリプトから生成したP2SHアドレスとそのredeem_scriptnonceを返す。

ユーザは生成されたP2SHアドレスにコインを送付する。

連合の職員の秘密鍵

ユーザーは職員にpayee_address(ホワイトペーパーではScriptPubKey)とnonceを渡す。連合の職員は渡されたpayee_addressnonceを使って秘密鍵を入手する。

この処理を実装しているのがBitcoin::ContractHash#claimで、

引数に渡すのが↓の3つ

  • private_key
    元々公開していた公開鍵の秘密鍵
  • payee_address
    ユーザから渡された支払先のアドレス(ホワイトペーパーではScriptPubKey)
  • nonce
    ユーザから渡されたnonce

↑でユーザがコインを送付したアドレスのロックを解除するための秘密鍵を↑のclaimメソッドで生成している。ユーザから渡されたpayee_addressnonceから元々の公開鍵に加算されたdataを計算し、秘密鍵にそのdataを加算した新しい秘密鍵を生成している。

ポイントとなるのは、ユーザは公開されている職員の公開鍵に対してnonceとアドレスから生成したdataを加算した公開鍵を生成しており、職員はそれに対応する秘密鍵を同じく秘密鍵dadtaを加算して入手してる点で楕円曲線の準同型性を利用している。ユーザがコインを送付するマルチシグは連合のマルチシグの各公開鍵にデータを加算したマルチシグであるため、このアドレスへの支払いがサイドチェーンへの支払いになっていることを第三者がリンクすることはできない。