LINEで送る
Pocket

安土 茂亨(@techmedia_think)は株式会社ハウインターナショナルに所属する開発者で2ndレイヤー技術を中心に研究開発を行っている。Open Assets ProtocolのRuby実装”openassets-ruby”や、BitcoinプロトコルのRuby実装”bitcoinrb”を開発中。


bitcoin-bank-blockchain

よくあるビットコインの支払いでは、ECサイトや店頭で商品を購入する際、サイトやレジに支払先のBitcoinアドレスと金額が表示され、顧客は自分のウォレットからそのアドレス宛てに指定された額のビットコインを送金するトランザクションを作成し、Bitcoinネットワークにブロードキャストする。ブロードキャストしたトランザクションが店舗側のノードで検知できたら支払いが行われたと判断し、決済が完了する。

この時使われるアドレスは、店舗側で管理する鍵に対応したP2PKH(Pay to Pubkey Hash)アドレスやマルチシグアドレスが一般的だ。ただ、これらのアドレスはあくまでアドレス宛てにビットコイン決済が行われたこと示すだけで、アドレス自体は購入内容や契約内容についてのコミットメント(誓約; 契約の履行を約束すること)にはならない。

顧客と事業者間で実際に商取引をする場合、以下のようなプロセスが考えられる。

  1. 顧客が購入したい商品/サービスを注文する。
  2. 事業者が必要な代金や契約内容をとりまとめた請求書を作成する。
  3. 顧客は請求内容を確認し入金する。
  4. 事業者は顧客からの入金を確認し領収書を発行し、商品を発送する。

単純に送金手段としてビットコインを使用するだけでなく、こういった契約にもとづく商取引における当事者間のやりとりをビットコイン決済に適用するのがPay to Contractと呼ばれるプロトコルだ。

※ Pay to Contractのホワイトペーパー
https://arxiv.org/pdf/1212.3257.pdf

Pay to Contractの仕組み

一般的な公開鍵ハッシュへの支払いであるP2PKHや、スクリプトハッシュへの支払いであるP2SH(Pay to Script Hash)と同じように、Pay to Contractというのは契約への支払いを意味し、楕円曲線のキーペアの準同型特性を利用して契約のドキュメントからアドレスを生成する。

Pay to Contractを使った決済は以下の要素とステップで行われる。

  • コントラクトドキュメント
    商品の内容や価格、サービス条件、保証内容、支払期限など顧客と事業者が合意する契約内容や、必要に応じて商品の配送先情報などを記述するドキュメントで、特に必須項目やフォーマットなどは定義されてはいない。
  • 店舗側の公開鍵
    アドレスを導出する際のベースとなる店舗側の公開鍵
  • 暗号学的ハッシュ関数
    SHA256などのハッシュ関数

Pay to Contractを使った決済のステップ

  1. 事業者は予め安全な方法で自身の公開鍵を顧客に公開する。
  2. 顧客からの注文を受けた事業者が契約内容を示すコントラクトドキュメントを作成し顧客に渡す。
  3. 顧客は受け取ったコントラクトドキュメントの記載内容に問題がないか確認する。
  4. 顧客はコントラクトドキュメントの内容に問題がなければ、暗号学的ハッシュ関数を使ってドキュメントのハッシュ値を計算する。
  5. 1で入手した事業者の公開鍵=楕円曲線上の点に、4で計算したハッシュ値から計算した楕円曲線上の点を加算し、新しい楕円曲線上の点=公開鍵を計算する。
  6. 算出した公開鍵からP2PKHアドレスを計算する。
  7. 顧客はP2PKHアドレス宛に指定された額のビットコインを送金する。
  8. 事業者は顧客に開示した公開鍵に対応する秘密鍵に、コントラクトドキュメントのハッシュを加算してコインを入手するのに必要な秘密鍵を計算し、それを使って顧客が送金したビットコインを入手する。

(※ 2の段階で事業者側も6のアドレスを計算し顧客に送っておき、顧客は自分が算出したアドレスと同じか検証する。)

このようにしてコントラクトドキュメントから生成したアドレスに送金することで、契約(コントラクトドキュメント)にコミットした決済となる。取引の参加者は、いずれもコントラクトドキュメントを保持しており、どういった内容の契約をしたのかを示す暗号学的証拠を保持する。ブロックチェーン上には単なるP2PKHの決済を行ったトランザクションがあるだけなので、取引の当事者以外が契約内容を知ることはなく、第三者にとっては必要のないデータがブロックチェーン上に記録されブロックチェーンのスペースを消費することもない。

契約へのコミットメントという特性以外にも以下のような使い方も考えられる。

ECサイトのセキュリティをより堅牢に

ECサイトでビットコイン決済をする場合、ECサイトのサーバー上では各決済毎に支払先のBitcoinアドレスを生成する必要がある。決済アドレスの生成自体はBIP-32のようなHDウォレットを使用すると、サーバー上ではマスターとなる拡張公開鍵だけ保管しておけば、そこから決済に使用するアドレスを都度導出することができる。対応する秘密鍵はサーバー上に保管しておく必要はなく、ECサイトのサーバーが攻撃され侵入されたとしても、事業者側のビットコインが直接盗まれる心配は無い。

ただ、サーバーに侵入され、顧客に提供する支払先のアドレスを攻撃者のアドレスに改竄されてしまうと、顧客が支払うビットコインが攻撃者に盗まれてしまうという危険性は考えられる。またECサイトのサーバーが正常でも、顧客側の端末に攻撃者が侵入した場合も同様の危険性がある。

Pay to Contractプロトコルを利用すると、支払先のアドレスはコントラクトから導出されるため、顧客側の端末でコントラクトの内容を確認し、ハードウェアウォレット等の信頼できるデバイスでアドレスを生成すれば、支払先のアドレスの改竄を防ぐことができる。

また、例えコントラクト自体が別のコントラクトに改竄され、そこから生成したアドレスにビットコインを送金したとしても、マスター拡張公開鍵に対応する秘密鍵を知らない攻撃者にビットコインが盗まれることはない。事業者側もコントラクトが改竄されていると、そのアドレス宛ての着金を検知しないため、商品が発送されることもない。顧客は改竄されたコントラクトを事業者に提示することで、コイン自体を取り戻すことが可能だ。

※ ただ、ベースとなるECサイト側の公開鍵はPKIなどを利用し改竄されない形で顧客が知っている必要がある。今回のようなケース以外でも、アドレスや公開鍵の正真性を担保する仕組みは別途必要だろう。

オフライン決済

送金先のアドレスはコントラクトから生成されるため、一度コントラクトを使った決済をすると、ECサイトなどで商品を選択して注文処理といったことをすることなく、同じアドレスに同じ額を送金するトランザクションを作成しブロードキャストするだけで再注文ができる(ただ在庫などの確認はできないので、実商品には向かない可能性もある)。

また極端な話、決済機能を持つECサイトなどを公開しなくても、事業者の公開鍵とコントラクトを生成するためのフォームさえ公開しておけば、顧客はそこからアドレスを算出し一方的に注文をすることも可能だ。

HDウォレットとの組み合わせ

ホワイトペーパーではコントラクトから生成したハッシュ値を直接公開鍵や秘密鍵に加算して決済に使用する鍵を導出しているが、HDウォレットの鍵導出でもPay to Contractをサポートするための仕組みが最近BIP-175として提案された。

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

HDウォレットでは、マスター鍵(m)を先頭に用途やコインの種類、アカウント、決済回数など用途に応じた要素毎に以下のような階層型のパスを形成し、決済に使用する秘密鍵および公開鍵は全てマスター鍵からその階層を辿って導出される。

m / purpose’ / coin_type’ / account’ / … / …

BIP-175では、以下のようにコントラクトドキュメントのハッシュ値をパスの一部にして、HDウォレットでPay to Contractの決済に使用する秘密鍵および公開鍵を導出する仕組みを提案している。

m / purpose’ / coin_type’ / contract_hash

contract_hashの部分のパスは以下のステップで算出できる。

  1. コントラクトドキュメントのSHA256ハッシュ値を計算する(複数のコントラクトドキュメントがある場合、それぞれについてSHA256ハッシュ値を計算する)。
  2. 複数のコントラクトドキュメントのハッシュ値を辞書順にソートし、結合する。
  3. ハッシュ値を結合した値について再度SHA256ハッシュ値を計算する。
  4. 生成した32バイトのハッシュ値を4文字ずつに分割する。
    ハッシュ値 :ec321de56af3b66fb49e89cfe346562388af387db689165d6f662a3950286a57
    分割後:
    ec32 / 1de5 / 6af3 / b66f / b49e / 89cf / e346 / 5623 / 88af / 387d / b689 / 165d / 6f66 / 2a39 / 5028 / 6a57
  5. 分割した4文字を10進の整数に変換する。
    60466 / 7653 / 27379 / 46703 / 46238 / 35279 / 58182 / 22051 / 34991 / 14461 / 46729 / 5725 / 28518 / 10809 / 20520 / 27223
  6. 変換した数値をパスに適用する。
    m / purpose’ / coin_type’ / 60466 / 7653 / 27379 / 46703 / 46238 / 35279 / 58182 / 22051 / 34991 / 14461 / 46729 / 5725 / 28518 / 10809 / 20520 / 27223

上記のようにコントラクトドキュメントからHDウォレットのパスが導出できれば、後はそのパスを使ってHDウォレットで決済に使用するアドレスや、秘密鍵を導出することができる。

最近はBIP-175以外にもアプリケーションレイヤーのBIPの提案も増えてきており、単純にビットコインを送金するだけでなく、決済で表現できることの幅は今後広がっていくと思われる。ただ、Bitcoinのスクリプトでもさまざまなコントラクトの作り方が提案される一方、ウォレット自体がそういったスクリプトにまだ対応できていないという状態にあるため、こういった拡張機能をサポートするウォレットの登場が待ち望まれる。