少し前に、取引所に自分が預けているコインが本当に存在するか一斉に引出して確認してみようとするProof of Keysというイベントがあって、どこぞの取引所が事前に引き出し制限始めたというニュースもあったけど、ユーザーにとっては預けている資産がちゃんと存在することを検証できるのは重要なこと。
進んでそういった証明を開示してくれる取引所があれば素晴らしく、そういったアプローチをする取引所もあるが、証明方法については明確な標準はない。そこで最近Blockstreamがその標準化の提案をしている↓
もともとBlockstreamが提供するサイドチェーンLiquid上での監査のために着手したものみたい。提案されたBIP-127が↓
https://github.com/bitcoin/bips/blob/master/bip-0127.mediawiki
プルーフのフォーマットの定義とそのコミットメントと保有するUTXOで構成されたBitcoinトランザクションとしてエンコードする仕様(BIP 174のPSBTの拡張を含む)を定義したシンプルなBIP。
このProof of Reserveの仕組みにより取引所などのカストディが保持する金額を把握できる仕組み標準化しようということだが、これだけだと自分のコインがちゃんと存在するかという証明には不十分である。証明しているのは総量だけなので、確実に取引所が預かっている顧客資産に対し十分な支払い能力があるか証明するためには、
が必要になる。この事は実際BIPの記述でも触れられているが、最後の支払能力の証明までやろうとすると、↓のProof of Solvencyまで必要になる。
techmedia-think.hatenablog.com
今回は1つめの資産の証明をまずは、なるべく既存のウォレットと互換性のある形で標準化しようというアプローチになる。
以下BIP案を和訳したもの↓
概要
このBIPは、proof-of-reserveトランザクションを構築するための簡単な方法を説明する。この提案は、そのような証明を構築し、既存のウォレットインフラを使ってそれらの構築を容易にし、一般的な証明検証ソフトウェアを可能にするための標準フォーマットを形式化する。このフォーマットは、通常のBitcoinトランザクションのシリアライゼーション/検証およびBIP 174 PBSTフォーマットなどの既存の規格に依存する。この提案には、ユーザーエクスペリエンスを向上するためのPSBTの拡張機能の説明も含まれている。
動機
Bitcoinの歴史の初期の頃から、ユーザーのためにBitcoinを管理する会社があった。これらのユーザーは特定のサービスと引き換えにコインの管理を放棄する。必然的にそのような企業がユーザーのBitcoinを失うことがあり、そのような事が起きても事件が公に公開されることはなかった。Proof of Reserveは大量の資金を管理している企業が一定額の資金に対する所有権を証明するための方法だ。定期的な所有権の証明は、重大な損失が発生していないことを確認するのに役立つ。
Proof-of-Reserveという用語は決して新しいものではないが、この手順は多くの資金を持つカストディアン企業であまり一般化されていない。その理由の1つは、proof-of-reserveを実行しようとするすべての企業は、それぞれ独自の方法で構築する必要があること。従って、そのユーザーはその証明を検証するために証明の構造を理解しなければならない。これは管理者にとってもユーザーにとっても参入障壁を高めることになる。
このBIPでしないこと
このドキュメントで説明されているProof-of-Reserveの構造には、主にそのプライバシー特性について、いくつかの既知の欠点がある。より優れたプライバシー特性を持つ改良されたProof-of-Reserveの仕組みに関する研究があるが*1、このBIPは意図的に事実上の既存の方法を形式化するだけだ。
仕様
我々の仕様は以下の2つのパートで構成される:
- 実際の証明のフォーマット
- 証明と関連メタデータのセットをパッケージ化するために使用されるファイルフォーマット
最終的な構成は以下の特性を持つべきである:
- 複雑なウォレットインフラをサポートするための柔軟なプルーフ構造
- 既存のウォレットソリューション(ハードウェア、ソフトウェア両方)との簡単な統合
- プルーフの発行元に関係なく、標準手順による検証のサポート
- プルーフは、メッセージに対してコミットすることで他の当事者によるプルーフの再利用を防ぐ
- 発行者が特定のブロックにおいてあるコインが自分の管理下にあることの検証を許可する(その後のブロックでどうなるかに関わらず)
プルーフフォーマット
既存のシステムと最大限の互換性を担保するため、プルーフは通常のBitcoinトランザクションとしてフォーマットされる。ただし以下の2つの機能を持つ1つの小さな適応をトランザクションに対して行う。
結果として得られる構造は、以下の特徴を持つBitcoinトランザクションとなる。
- 最初のインプット(コミットメントインプット)
- 残りのインプット
- コミットメントインプットにコミットする署名(例えばSIGHASH_ALLを使った)を持たなければならない。
- トランザクションは、コミットメントインプットのコインの量を0と仮定して、すべてのインプットのコインの量の正確な合計を持つ単一のアウトプットを持たなければならない。これはトランザクションがマイニング手数料を持たないことを意味する。
最初のインプット(単なるコミットメントハッシュ)の存在は、このトランザクションが無効であり決して承認されるものではないことを保証する。
プルーフファイルフォーマット
理論的には、仕様の最初の部分は実用最小限の標準として十分である。しかし、追加のメタデータレイヤーを使って標準を拡張するする動機は多数ある。
- 複数のプルーフの構築と結合
何千ものUTXOを異なるオフライン、オンラインのウォレットに分散させると、その全てのUTXOを使って単一のトランザクションでプルーフを作成するのは困難な可能性がある。同一のコミットメントメッセージとブロック番号を持つ複数のプルーフトランザクションを許容することで、複雑なウォレットインフラを持つカストディにとって、結合されたプルーフの安全性を低下させることなく、さらなる柔軟性が得られる。 - 検証用のメタデータ
検証に使われる全てのシステムが全てのトランザクションの完全なインデックスにアクセスできるわけではない。ただし、プルーフに使われているUTXOが既に未使用でなくなった後でも、プルーフは簡単に検証できるはずである。プルーフに存在するメタデータは、トランザクションインデックスが使えない場合でも、プルーフの比較的効率的な検証を可能にする。 - 将来の改善の可能性
拡張可能なメタデータフォーマットは、将来の標準の修正を可能にする。1つの潜在的な改善はUTXOセットコミットメントを持つことだ。これらは、プルーフ構成のブロックでUTXOセット内の全ての使用されたUTXOのproof-of-inclusionをproof-of-reserveが付随することを可能にする(検証をさらに効率的にする)。
提案するproof-fileのフォーマットは、複数のプルーフと関連するメタデータを結合するための簡単な方法を提供する。フォーマットの仕様はProtocol Bufferフォーマット*3である。
syntax = "proto3"; import "google/protobuf/any.proto"; message OutputMeta { // OutPointの識別子 bytes txid = 1; uint32 vout = 2; // このアウトプットが作成されたブロックのブロックハッシュ bytes block_hash = 3; } message FinalProof { // プルーフトランザクション。 通常のBitcoinトランザクションのようにパース可能。 bytes proof_tx = 1; // プルーフトランザクションで使用されるアウトプットのメタデータ。 repeated OutputMeta output_metadata = 2; } message ProofOfReserves { // 追加フィールドを拡張できるよう、このフォーマットのバージョン番号 uint32 version = 1; // プルーフが有効なネットワークのネットワークマジック。 // mainnetは0xD9B4BEF9, testnetは0x0709110B //TODO BIP44のcoin type idを代わりに検討 // https://github.com/satoshilabs/slips/blob/master/slip-0044.md uint32 network_magic = 2; // このproof-of-reservesのコミットメントメッセージ。 // このメッセージは全てのプルーフのためのグローバルなもの。 string message = 3; // このプルーフが検証されるブロック。 // 検証では、このブロック高でアウトプットが未使用であることを考慮する必要がある。 bytes block_hash = 4; // アウトプットメタデータを含む最終プルーフトランザクションのセット。 repeated FinalProof final_proofs = 5; // proof-constructionツールで使われる可能性のある予約フィールド。 // 検証では無視される。 repeated google.protobuf.Any pending_proofs = 6; }
最後のフィールドpending_proofs
は proof-constructionツールで使われるスペースを同じファイル内にいくつか確保する。これによりファイルフォーマットを切り替えることなく、さまざまなプルーフを段階的に構築できる。
PSBT(BIP 174)の拡張
プルーフフォーマットのセクションで詳述されているコミットメントインプットは既存のUTXOを使用するわけではないので、署名されるべきではない(scriptSigとwitnessは空)。このタイプのトランザクションに署名する際、いくつか問題を引き起こす可能性がある。例えば、ハードウェアウォレットは、よく署名しようとしているトランザクションの全インプットに関する情報(前のアウトプットや前のトランザクションなど)を提供するよう署名者に求める。しかし、このデータは明らかにコミットメントインプットには存在しない。
ほとんどの既存デバイスでは、ダミーデータを提供するか、この特定のインプットを無視するようデバイスに指示することで、こららの要件を回避することができる。それでもUXの問題が残る。ハードウェアウォレットデバイスは、そのトランザクションをproof-of-reserveトランザクションとして認識しないため、UTXOの全てのお金を使用する通常のトランザクションに署名していると捉えられる。ほとんどのデイバスは「XXX BTCをアドレス[...]に送信してよろしいですか?」というメッセージで確認を求めるが、これは最高のUXではない。
BIP 174 PSBTフォーマットに定義を追加することで、署名デバイスがProof-of-Reserveを認識することができる。以下のフィールドがBIP 174のINPUT Mapに追加される。
- タイプ:Proof-of-Reserve コミットメント
PSBT_IN_POR_COMMITMENT = 0x09
このフィールドがセットされているインプットを処理するウォレットは、
- 上述したように、OutPointにプレフィックス付きコミットメントメッセージの文字列のSHA-256ハッシュがセットされていることを確認しなければならない。
- インプットの値(コインの量)は0と仮定しなければならない(前のアウトプットのトランザクションを提供する必要はない)。
- 任意のインプットに署名する前に、確認のためコミットメントメッセージをユーザーに表示し確認を求めるべきである。
- このインプットにコミットするSIGHASHが使われている署名のみを提供するべきである。
- このインプットについては、(scriptPubkeyがOP_TRUEであるかのように)空のscriptSigを受け入れる必要がある。
実装
PSBT拡張のproof of conceptの実装がrust-bitcoinプロジェクトのpsbt-porブランチにある。
https://github.com/stevenroose/rust-bitcoin/tree/psbt-por
上記フォーマットのプルーフを生成、検証するツールの進行中の実装が以下にある。