昨年Bitcoinの開発メーリングリストにポストされたConfidential TransactionをBitcoinのソフトフォークとして導入する話↓
[bitcoin-dev] Confidential Transactions as a soft fork (using segwit)
Confidential TransactionについてはBlockstreamが開発したサイドチェーンの実装であるElements Alphaに実装されている。
そもそもトランザクションの出力に量の代わりにコミットメントと呼ばれる楕円曲線上の点(公開鍵)をセットしたりrange proofや明示的な手数料など、既存のBitcoinの仕様とは異なるのでサイドチェーンによる拡張として実装されていた。
これをBitcoinにソフトフォークしようというのが↑のポスト。
トランザクションの拡張
このソフトフォークではSegwitの新しいwitness programを定義することで、Confidential Transactionを評価する仕組みを導入しようとしている。
既存のSegwitでは、トランザクションは以下のデータで構成される。
もともとSegwitでは入力のscirptSigをwitness scriptとして入力の外に分離する仕様だが、このソフトフォークではさらに、出力にも入力と同様のwitness領域を設けるようトランザクションの構造を拡張する↓
各出力の既存のBitcoinの量のフィールドには0をセットし、量の代わりになるConfidential Transactionのペダーセンコミットメントとそのrange proofをwitnessOutsにセットする。このソフトフォークに対応していないノードでは入力と出力のビットコインの量が0に見える。
こうやって、既存のトランザクションのデータ構造にないコミットメントとrange proofを格納する場所をトランザクションの別の領域に確保する。
コミットメントとrange proof以外にも、Confidential Transactionでは手数料を明示的に指定する必要がある。このため誰もが使用可能な(anyone-can-spend)出力(GCTXO)をその手数料用に作成する。
新しいトランザクションタイプ
Confidential Transactionは、blinding
、unblinding
、confidential
という新しい3つのタイプのトランザクションを組み合わせることで実現する。また、これらの新しいタイプのトランザクションを含むブロックは、そのコインベーストランザクションに特殊な出力を含み、さらに追加で新しい特別なConfidential base transactionを含める必要がある。
Blinding Transaction
Blinding Transactionは通常のUTXOを入力にとり、出力が秘匿化したUTXOになるトランザクションで、以下のような構成になる。
Ins: 全て秘匿されていない通常のUTXOを参照する Outs: 0..N: 新しい秘匿対象の出力 量: 0 scriptPubkey: `OP_2 <32バイトのハッシュ値>` witnessOut: `0x{petersen-commitment}> <0x{range-proof}>` 最後の出力: 量: 0 scriptPubkey: `OP_RETURN OP_2 {blinding-fee-amount}` Fee: 全入力のコインの合計
全出力の量は全て0になるため、通常のBitcoinのトランザクションとして考えると、全ての入力のコインが手数料になることになるように思えるが、このコインは秘匿化された手数料を除いて全て、このトランザクションが含まれるブロックのコインベーストランザクションの特殊な出力(GCTXO)にセットされる。
出力の最後のスクリプトはこのトランザクションがBlinding Transactionであることを示すマーカーにもなる。ソフトフォークがアクティベートされた後は、マイナーがBlinding Transactionのコインをコインベースの出力に入れずに自身のアドレスに送るようなスクリプトを書いた場合、そのブロックは無効なブロックとして扱われる。
コインベーストランザクション
Blinding Transactionを含むブロックは、Blinding Transactionの全ての手数料を新しい出力(Confidential base transaction)に送金する必要がある。GCTXOのコインは同じブロックのConfidential base transactionでのみ使用可能なためscriptPubkeyは重要でなくOP_TRUE
とかで良い。
Unblinding Transaction
Blinding Transactionは秘匿化されたUTXOを入力にとり、出力が通常の秘匿化していないUTXOになるトランザクションで、以下のような構成になる。
Ins: prev: CTXO[n] scriptSig: 空 witnessIn: `<署名> <0x{redeem script}>` Outs: 0..N: 量: 0 scriptPubkey: `OP_RETURN OP_2 {アンブラインドするコインの量} {p2sh-destination}` witnessOut: 空 最後の出力: 量: 0 scriptPubkey: `OP_RETURN OP_2 {unblinding-fee-amount}` Fee: 0
このトランザクションは入力のUTXOセットから秘匿性を削除する。このトランザクションの出力自体は全てOP_RETURN
であるため使用可能な出力ではないが、同じブロックにGCTXOを償還するマイナーが作成したConfidential base transactionが含まれる。
Confidential transaction
Confidential transactionは秘匿化されたUTXOを入力にとり、それを別の出力に秘匿化されたまま送金するトランザクションで、以下のような構成になる。
Ins: prev: CTXO[n] scriptSig: 空 witnessIn: `<署名> <0x{redeem script}>` Outs: 0..N: 新しい秘匿対象の出力 量: 0 scriptPubkey: `OP_2 <32バイトのハッシュ値>` witnessOut: `0x{petersen-commitment}> <0x{range-proof}>` 最後の出力: 量: 0 scriptPubkey: `OP_RETURN OP_2 {confidential-fee-amount}` Fee: 0
入力、出力とものに全てのコインの量は0で、誰もが使用可能なスクリプトになっている。ただこのトランザクションはコミットメントとそのrange proofが有効な場合のみ有効なトランザクションと判断される。このトランザクションのマイナーへの手数料は、最後の出力で表現されている。
Confidential base transaction
上記トランザクションのいずれかを含むブロックでは、そのブロックの最後のトランザクションとして以下のトランザクションが含まれる。
Ins: GCTXO[last_block], GCTXO[coinbase] Outs: 0: GCTXO[current_block] 量: {last_block + coinbase - unblindings} scriptPubkey: `OP_TRUE` 1..N: 量/scriptPubkey: このブロック内でアンブラインドしたいトランザクションの出力
このトランザクションの入力にセットするのは、以下の2つのGCTXOになる。
- GCTXO[coinbase]: このブロックのコインベーストランザクションのGCTXO。コインベースのGCTXOには、そのブロック内のBlinding Transactionで秘匿化した全てのコインの量がセットされている。
- GCTXO[last_block]:この前のブロックのConfidential base transactionの0番目の出力(そのブロック内の秘匿化された量からアンブラインドしたコインを除外した量)のコインがセットされている。
Fee: このブロック内の全Confidential transactionの`OP_RETURN OP_2 <手数料>`で表現される手数料の合計
このトランザクションはブロックを作ったマイナーによって作成され、ブロック内の全Confidential Transactionの手数料を入手する。
まとめ&所感
ざっと見ただけだと分かりにくいけど、秘匿したコインがブロックチェーン上で無くなることなくブラインド/アンブラインドできるようになってる。
簡単に言うと、コインを秘匿化したい場合はBlinding Transactionを作成するが、このトランザクションの出力は全て量が0(秘匿化された量はちゃんと別にある)になるので一見コインが全て手数料になってしまうように思えるが、このコインは全てBlinding Transactionが含まれるブロックのコインベーストランザクションの特殊な出力(GCTXO)の量として加算される。そしてこのGCTXOのコインは、同じブロックの最後のトランザクションであるConfidential base transactionの入力になる。
秘匿化されたコインは基本的に全てGCTXOが保持することになり、ブロック内にUnblinding Transactionが存在する場合は、アンブラインドするコインをConfidential base transactionの1番目以降の出力にそれぞれ通常のUTXOとしてセットする。こうするとConfidential base transactionの0番目の出力(GCTXO)にはコインベースのGCTXOからアンブラインドした量を引いいた量がセットされる。がもう1つ前のブロックのConfidential base transactionの0番目の出力のコインの量も加算される。
こうやってブロックチェーン内のコインベースと最後のConfidential base transactionのGCTXOで秘匿化されたコインのバランスを担保している。
- Confidential Transactionを新たなwitness programを定義して(なのでSegwit前提)Bitcoinのソフトフォークとして導入するアプローチ。
- 既存のSegwitのwitnessは入力の署名を分離するが、出力用のwitness(witnessOuts)を用意し、そこにコミットメントとrange proofを格納する。
- Unblinding Transactionの出力のscriptPubkeyが全て
OP_RETURN
なのは如何なものか。 - 既存のBitcoinのプロトコルに存在しない秘匿した量をどうやって整合性とるのか疑問だったけど、コインベーストランザクションとConfidential base transactionでその整合性をマイナーに取らせていて、秘匿された量が勝手に消えない仕組みになってる。この辺はよく破綻しないよう考えたなー。
- 結構マイナーがやらないといけないこと多く、それに対するインセンティブも無いので、これをソフトフォークとしてアクティベートするのは難しいんじゃないかな。
- MLにはこのポストがあるだけで、特にレスは付いて無いようで、このソフトフォークの仕組み自体は現在進んでいないのか?
- 量の代わりにコミットメントをセットすることで出力のサイズが28バイト増えるのはまだしも、witnessOutsを導入するとは言えやはりrange proofの2.5KBというサイズがネックだと思う。