Develop with pleasure!

福岡でCloudとかBlockchainとか。

Pay-to-contract プロトコル

サイドチェーンElements AlphaでBitcoinのブロックチェーンとサイドチェーン間で資金を移動する際に使われているPay-to-contractと呼ばれるプロトコルについてざっとホワイトペーパー読んでみた。

https://arxiv.org/pdf/1212.3257.pdf

Pay-to-contractプロトコルの概要

Pay-to-contractプロトコルは、売り手と顧客の間の決済を安全に行う仕組みとして提案されているプロトコルになる。

顧客がPCのブラウザでECサイトにアクセスして、安全にBitcoin決済をするユースケースを考える。顧客のPCにはウォレットはインストールされておらず、顧客のBitcoinは信頼できるハードウェアウォレットデバイスで管理されているとする。

よくある決済の手順としては

  1. 顧客がブラウザで、ECサイトに安全なSSL接続でブラウジングする。
  2. 顧客がECサイトで注文をする。
  3. ECサイトは自身のウォレットから支払先のBitcoinアドレスを選択する。
    (アドレスの秘密鍵ECサイトのサーバとは別にオフラインのキーウォレットに保存されているとする)
  4. 支払先のアドレスを顧客に通知する。
  5. 顧客はハードウェアウォレットを使って支払いを行うトランザクションに署名する。
  6. 顧客は署名したトランザクションBitcoinネットワークにブロードキャストする。
  7. 店舗側は決済が確認できたので商品の発送手続きに移る

攻撃のポイント

ここで悪意あるユーザからの攻撃のポイントを考える。
プロトコル開始前に顧客はECサイトの公開鍵をPKI等の別の仕組みを使って知っている前提での話)

ECサイトへの攻撃

もしECサイトが悪意あるユーザに侵入された場合、以下のことが考えられる。

  • 4でECサイトから顧客に通知される支払先のBitcoinアドレスを攻撃者のものに改竄する
  • 注文情報(配送先の住所など)を改竄する
  • 売り手のBitcoin秘密鍵ECサイト上で管理されていないので、売り手のBitcoinが盗まれるということはない。

この攻撃を防ぐには、決済プロトコルに署名の検証を組み込む。

注文情報をバンドルした請求書を作りECサイトが署名し、顧客に送る。顧客は署名を検証することで改竄の有無を検知できる。

ただ、ECサイトに侵入さているという状況では、その署名をECサイト上で行うことはできないので、別途ファイアウォール等で保護されたセキュアなデバイスを追加して、その上で秘密鍵の管理や署名を行う必要がある。

この場合の課題は、

などがある。

顧客への攻撃

もし顧客のPCが悪意あるユーザに侵入された場合、ECサイトとPC間で中間者攻撃が行われ

  • 注文情報(配送先住所など)を改竄する
  • ハードウェアウォレットと連携する際に偽のBitcoinアドレスにすり替える

といった攻撃が可能になる。

この攻撃を防ぐには、署名の検証を顧客のPCではなく、安全なハードウェアウォレット上で行うことで改善を検知することができ、検証プロセスの中で、請求内容を顧客に提示しインタラクティブな確認を求める。

※ この場合ECサイトの公開鍵はプロトコル開始前にハードウェアウォレット上に保存されている必要がある。ブラウザに同梱されているルート証明書のようにハードウェアウォレットにルートキーを同梱するなどの仕組みが必要。

プロトコル仕様

↑の課題に対して、ECサイト側のセキュアデバイスを追加することなく中間者攻撃の影響を受けることがない決済プラットフォームを考察するのがこのプロトコルのゴール。

Contract

このプロトコルでは顧客が実行する支払いを指定したContractと呼ばれる概念を導入している。通常ECサイトBitcoinによる支払いをする場合、明示的に支払先のアドレスが提示されるが、このプロトコルでは支払先のアドレスはこのContractから生成する。

具体的な仕組みとしては、ECDSAの準同型性を利用して、↓の関数を実装する。
※ P=ECサイトの公開鍵、K=ECサイト秘密鍵、H=ハッシュ関数、x=Contract

  • daddr(P, H(x))
    PとH(x)からユニークなBitcoinアドレスを生成する関数
  • dpriv(K, H(x))
    daddr(P, H(x)) に対応する秘密鍵を生成する関数

daddrでは公開鍵Pに対してContract x(正確にはそのハッシュ)を加算して新しい公開鍵を作りそこからアドレスを生成している。そしてdprivでは秘密鍵Kに対してContract xを加算して新しい秘密鍵を生成している。ECDSAの加法特性を利用することで、生成した公開鍵に対応する秘密鍵を生成している。

なお、これらの関数は既に実装されている決定性ウォレットを利用することで期待する値が得られる。

Contract x の支払先のアドレスをb := daddr(P, H(x))とした時、顧客はContract x とECサイトの公開鍵からbを計算することができ、秘密鍵Kを保有するECサイトの事業者だけがbに送られたコインを入手することができる。

またContractはアドレスだけでなく、顧客にとって支払いの証明にもなる。ただ証明の際にContractを開示する必要があるが、Contractには配送先住所などのプライベートな情報も含まれているため、そういったデータを除外した形で支払いの証明をできるようにしたい。そのためContractをまーくるツリーとして構成することで、Contractの全データを開示することなく支払いの証明を行うことができる。

実際にContractに含むデータのレイアウトは店舗側で自由に決められるが一般的には↓のようなデータが考えられる。

  • 静的なデータ
    価格、売り手のサービス条件、保証、売り手の監査人の名前など
  • 動的なデータ
    品目番号、数量、価格、納品先住所、納期、支払先住所、支払い期限、クライアントを参照/トラッキングするトークン、売り手を参照/トラッキングするトークンなど

※静的なデータはContractを構築する前にECサイトの事業によって署名されている。

Contractを使ったプロトコル

Contractを使ったプロトコルは↓のようになる。

  • 顧客からの注文を受けてECサイトはContract xを生成し顧客に送る。
  • xにはECサイトの公開鍵も含まれ、顧客は注文が内容通りか確認し、問題なければハードウェアウォレットに転送する。
  • ハードウェアウォレットはx内の全ての署名を検証し、公開鍵とxの内容を顧客に表示する。
  • 顧客が内容を承認すると、ハードウェアウォレットはb := daddr(P, H(x))を計算し、そのアドレスにxに記述された金額を支払うトランザクションを作成し、Bitcoinネットワークにブロードキャストする。

この時顧客はハードウェアウォレットが表示したxの内容を確認するため、コインの支払先は必ず正しいアドレスdaddr(P, H(x))になる。

仮にxが改竄されx'になったとして、その支払先のアドレスはdaddr(P, H(x'))になる。この場合、ECサイト側はこのアドレスへの支払いは検知しないので、商品が発送されることは無い。商品が発送されないので、後日顧客は別の連絡手段でECサイトに問い合わせ支払いの証明x'を開示する。この場合x'に送られたコインを入手できるのはいずれにせよECサイトの事業者のみであるため、攻撃者に資金や商品が盗まれることは無い。

結果、攻撃者ができる攻撃はDoS攻撃くらいになる。

ここまでが Pay-to-contractプロトコルの基本概念になる。

オフライン決済

↑のように支払先のアドレスはContract xから計算されるので、例えばリピート等で再注文をする場合、顧客はContract xを既にしっているため、ECサイトにアクセスすることなく、daddr(P, H(x))への支払いトランザクションを作成しブロードキャストするだけで注文が完了する。(ただし、実商品の場合、在庫チェックなどは行えない)

ということは Contract xさえ作れればECサイトは別に必要ないということになる。予めEC事業者が署名済みのContract Formをパブリックなスペースに公開しておけば、顧客からのEC事業者の一方向の通信のみで決済が可能になる。
(ただし、何らかの方法でEC事業者の公開鍵を事前に顧客が知っている必要はある。)

分散ファイルシステムとDH鍵交換を使った秘匿取引

EC事業者が出来る限り匿名のまま自分の活動を隠したい場合、オフラインでかいつ第三者のオブザーバーに気付かれることなくContractを償還する↓の2つからなるプロトコルも提案されている。

このプロトコルは↓のようなものになる。(Contract xを入手した後に)

まず顧客側で↓の手順を実行する。

  1. ハードウェアウォレットでdaddr関数を使ってContract xへの支払いアドレスを計算する
  2. DH鍵合意で共通鍵を生成する
    (顧客の秘密鍵と事前に入手しているEC事業者の公開鍵から作成)
  3. トランザクションを作成し共通鍵でタグ付けする
    (このトランザクションの入力か出力のどちらかに顧客に公開鍵を入れる)
  4. トランザクションに署名しBitcoinネットワークにブロードキャストする
  5. 共通鍵からファイル名を生成する
  6. Contractを共通鍵(対称鍵)を使って暗号化する
  7. 暗号化したContractを5で生成したファイル名で分散ファイルシステムにポストする

その後、EC事業者は↓の手順を実行してContractを償還する。

  1. ブロックチェーンを関しし、タグ付きのトランザクションを識別する
  2. タグ付きのトランザクションから共通鍵を導出する(EC事業者の秘密鍵トランザクション内の顧客の公開鍵から作成)
  3. タグからファイル名を導出して分散ファイルシステムを検索する
  4. 分散ファイルシステムからデータを取得し、共通鍵で解読したContractを入手する
  5. Contractから支払先のアドレスを計算する
  6. 計算したアドレスとトランザクションのアドレスの出力が等しければ支払いは正しいので、顧客からの注文を受け入れる

所感

  • 支払先のアドレスを提示するのでなく、顧客側にContractから計算させるアプローチをとることで、中間者攻撃からコインや商品を守ってる。
  • データとその証明にマークルツリーを利用するのはありだなー。
  • このプロトコルに限った話でもないけど、公開鍵をPKIなどで事前に共有する仕組みは必要で、ブロックチェーン単体では認証はできない。
  • 最後のDH鍵交換の部分でタグ付けしたトランザクションの識別方法はどうやってるんだろう?