ビットコインで決済をするとその内容はブロックチェーンに書き込まれ、誰もが検証可能な状態になる。このブロックチェーンの特性を利用すると、ブロックチェーン上である決済をした人にのみ特定のサービスを提供するようなことも可能だ。

例えばホテルの宿泊の決済をビットコインで行うと、そのホテルの部屋のロックをビットコインの決済情報からコントロールしたり、支払いを証明することで会員登録する必要なく各種サービスをどんなデバイスからでも利用できるようになったり、関連会社のサービスを購入していれば特典を受けられるといったことも考えられる。

この時必要になるのが、ブロックチェーン上の決済を行った本人であることを証明する仕組みだ。BIP-120でこの支払いの証明（Proof of Payment）について提案されているので紹介したい。

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

Proof of Paymentの仕組み

Proof of Paymentの仕組みはシンプルで、決済に使用したトランザクションのインプットのロックを解除することができることを証明することで、支払いの証明を行う。

Proof of Paymentの作成

まずユーザーはBitcoinのトランザクションを作成し、それをBitcoinネットワークにブロードキャストすることでビットコインの支払いを行う。このとき作成したトランザクションを以下のようなトランザクション T1とする。

その後ユーザーはサービス事業者のサーバーなどと連携して、そのトランザクションによって確かに支払いを行った本人であることを証明する。

まずユーザーは、サービス事業者のサーバーから証明に使用するnonceを取得し、支払いの証明のため以下のようなProof of Paymentのトランザクションを作成する。

このトランザクションはユーザーが実際に支払いをしたトランザクションT1と同じインプットを持つ。ただし、sequenceの値だけはT1とは異なり全て0となる。sequenceが0xffffffffだと、locktimeが無視されるためだ。

このトランザクションは、pop outputと呼ばれるOP_RETURNで始まる特殊なアウトプットを１つだけ持ち、OP_RETURNの後には以下のペイロードが続く。

OP_RETURN <version> <txid> <nonce>

ペイロードの各値の意味は次のとおり

<table style="border:2px #ccc solid"> <tr> <td>項目</td> <td>バイト数</td> <td>内容</td> </tr> <tr> <td>version</td> <td>2</td> <td>Proof of Paymentのプロトコルのバージョンで現在は 0x01 0x00</td> </tr> <tr> <td>txid</td> <td>32</td> <td>支払いに使用したトランザクションのtxid</td> </tr> <tr> <td>nonce</td> <td>6</td> <td>サービス事業者が証明を求める際に提示したしたランダムな値</td> </tr></table>

このペイロードは、どの支払いを、事業者から取得したどのnonceで証明しようとしているのかを示すデータになる。

Proof of Paymentのトランザクションのlocktimeには必ず499999999をセットする。これは誤ってこのトランザクションがBitcoinネットワークにブロードキャストされてもブロックに取り込まれないようにするため仕掛けだ。ロックタイムが499999999だと、499999999ブロックになるまで、そのトランザクションはブロックに入れられない。

Proof of Paymentのトランザクションの雛形を作成したら、最後に各インプットに署名をしてサービス事業者に送付する。T1と同じインプットを持つトランザクションに署名ができるのは基本的にT1を作成した本人だけであるため、この署名が支払いの証明になる。尚、このトランザクション自体はブロックチェーンには記録されないので、Bitcoinネットワークとは別の方法で事業者のサーバーやアプリと通信して送付することになる。

Proof of Paymentの検証

署名済みのProof of Paymentのトランザクションを受信した事業者は、以下の手順でProof of Paymentを検証する。

Proof of Paymentのトランザクションを検証する。入力が使用済みであることを除いて、トランザクションの検証に成功すること。 ロックタイムが499999999であるかチェックする。 アウトプットは１つだけで、pop outputのペイロードのフォーマットに準拠しているかチェックする。 pop outputに記載されているtxidが検証対象のトランザクションかチェックする。 ペイロード内のnonceが事業者が送信したものかチェックする。 全てのインプットがsequenceを除いて、T1 と同じかチェックする。 全てのインプットのスクリプトを実行して、全てtrueとなるかチェックする。

全てのチェックをパスしたら、正しい支払いの証明であると判定できる。

※ ユーザーのウォレットと事業者のサーバー間で支払い対象のトランザクションを特定する際にtxidが使用できると簡単なので、txidに関するmalleabilityの問題が無いSegwitトランザクションの使用を推奨する。

BitcoinのウォレットではMyceliumがProof of Paymentに対応しており、このBIPの作者であるKalle RosenbaumがProof of Paymentを行うサーバー側のコードやデモを公開しているので、このサイトで実際に試すことができる。

尚、プロトコル自体はBitcoinに限定したものではないので、他の暗号通貨にも適用可能だ。

https://www.youtube.com/watch?v=euzZcoCilhc