Develop with pleasure!

福岡でCloudとかBlockchainとか。

LitecoinのMWEBで非対話型トランザクションを構築するプロトコル(LIP-0004)

Litecoinでは、Extension Blockを利用してMimblewimbleを実装するMWEBの開発が行われているけど、その中でMimblewimbleのトランザクションを送信者のみが構築するプロトコルがLIP-0004として提案されている↓(まだ正式にLIPとしてマージされてる訳ではななくMWEBの開発者であるDavid Burkettのリポジトリ

https://github.com/DavidBurkett/lips/blob/master/lip-0004.mediawiki

MWのトランザクション構築

Mimblewimbleでは、基本的に送信者と受信者が協力してトランザクションを作成する必要がある。これは送信者が所有するインプットのUTXOのブラインドファクターと、受信者が新たに所有するアウトプットのブラインドファクターの値をそれぞれ秘匿した状態で、インプットのコミットメントとアウトプットのコミットメントの差分値(超過値)に対して共同で署名する必要があるためだ。詳しい仕組みについてはGBECのMimblewimble動画を参照。

非対話型にするための課題

トランザクションの構築が対話型になると、送信者と受信者の通信が必要になり、両者がオンラインになっている必要がある。LNも同様だが、Bitcoinのように送信者のみでトランザクションを構築できると利便性は上がる。そのような非対話型のトランザクションの構築にあたって課題になるのがブラインドファクターの共有。

送信者のみでトランザクションを構築するということは、新たに作られる受信者のUTXOのブラインドファクターを送信者が生成することになる。この場合、

  • 生成したブラインドファクターをどう受信者に伝えるのか?
  • 従来MWプロトコルではこのブラインドファクターが秘密鍵の代わりをしているため、送信者がこれを知るということは、そのコインは完全に受信者だけのものではなく送信者も使えてしまうことになる。

といった課題が発生する。

初期の提案

David Burkettは、Mimblewimbleを実装しているGrinでも送信者のみでトランザクションを構築する提案をしている↓

https://gist.github.com/DavidBurkett/32e33835b03f9101666690b7d6185203

仕組みとしては、送信者と受信者の鍵でECDHを実行し共有シークレットを生成し、それでブラインドファクターとコインの量を暗号化してアウトプットにセットすることで、受信者がブラインドファクターを抽出可能にする。そして別途受信者の公開鍵もアウトプットに追加し、ブラインドファクターによる検証+その公開鍵に対して有効な署名が提供されているか追加のチェックをコンセンサスに加えることで、送信者が受信者のブラインドファクターを知っている状態でも、受信者しかコインが使用できないようにするというもの。

プロトコルの詳細は、以前書いた↓の「非対話型トランザクション作成」参照

techmedia-think.hatenablog.com

初期提案の問題点

↑の提案に対して、3つの問題点が指摘されている↓

  • トランザクションがブロックに入る前に、受信者はトランザクションからブラインドファクターを抽出でき、それを変更できるため*1、資金を受け取った事実を否定することができる。
  • トランザクション・カットスルーにより、アウトプットがブロックに格納される前に削除された場合、支払いの証明をオンチェーンで行えない。
  • 署名がアウトプットやカーネルをカバーしていない場合、ランダム性の欠如によりインプットの署名を再利用することができてしまう。つまり、アリスからボブに支払いをし、その後ボブがチャーリーに支払いをした場合、アリスはreorgを発生させ、ボブ→チャーリーのトランザクションの署名を使って、ボブ→アリスのように支払いを送り返すことができる*2

LIP-0004の提案

↑の問題を解決するために、Owner Offsetという新たな要素を追加する。

もともと、Mimblewimbleプロトコルでは、コインのインフレーションが発生していないことをチェックするため、以下の検証を行っている

全アウトプットのコミットメントの合計 + 手数料*H - 全インプットのコミットメントの合計 == Kernel excess(超過値)

で、Kernel excessを公開鍵として、それに対して有効な署名を提供する(正確にはKernel excessはkernel offsetとkernel commitmentで構成される)。

↑はコインの量のインフレーションに対するチェックだが、これと似たチェックを送信者の公開鍵に対して行う。トランザクションに新たにOwner excessというフィールドを追加し(正確にはowner offsetとowner proof commitmentで構成される)

全アウトプットのsender_pubkeyの合算値 - 全インプットのreceiver_pubkeyの合算値 == Owner excess

が成立するかチェックする。Owner excessに対する有効な署名があるかチェックする。

アウトプットのsender_pubkeyというのは、受信者がECDHで共有シークレットを導出するための送信者の一時公開鍵。インプットのreceiver_pubkeyというのは、インプットが参照するUTXO(つまり、コイン送信者のUTXO)にセットされている公開鍵。なので、どちらも送信者の公開鍵である(じゃないと非対話型でトランザクション作れない)。

このチェックにより、アリス→ボブ→チャーリーの支払いにおいて、アリスがreorgを起こしてもボブ→チャーリーのトランザクションのOwner excessの署名を再利用することはできなくなる。これは、Owner excessがボブがチャーリーに送金する際の一時公開鍵も含めて計算されているため。

仕様

LIP-0004の仕様を詳細に書くと、

各アウトプットにコミットメント以外に追加のoutput_dataを追加し、それは以下の要素で構成される:

  • sender_pubkey:送信者の一時公開鍵
  • receiver_pubkey:受信者の公開鍵
  • encrypted_data:(送信者の鍵と受信者の鍵による)ECDHで生成された共有シークレットを使って暗号化したデータ(アウトプットの量とブラインドファクター)
  • sender_signature:送信者の鍵を使ったメッセージreceiver_pubkey || public_nonce || encrypted_dataへの署名

実際に拡張される項目は↓の青色の部分

https://github.com/DavidBurkett/lips/raw/master/lip-0004/tx-model.png

コンセンサスルールで、以下のチェックを追加する。

  1. output_datasender_signatureが公開鍵sender_pubkeyとメッセージreceiver_pubkey || public_nonce || encrypted_dataに対して有効な署名であること。
  2. 各インプットのinput_signatureは、それが参照するアウトプットのreceiver_pubkeyに対して有効な署名であること(メッセージはTBDみたい)
  3. owner_proofowner_signatureはブロック内のカーネルのハッシュに対し有効な署名であること。
  4. 各ブロックについて、sum(output.sender_pubkey) - sum(input.receiver_pubkey) == sum(owner_offset)*G + sum(owner_proof.commitment)が成立すること。

攻撃の可能性

↑のowner_offsetの検証が有効なのは、最新のブロックからhorizonブロックまでということなので、それを超えるreorgを発生させると攻撃の可能性が残っているとされている。reorgのコストと攻撃により得られる利益が釣り合うかが判断ポイントで、そのため大きめの資金を受け取った場合は、すぐに自分宛てに使用することで、攻撃を防御可能と。

このhorizonブロックの位置づけがよく分かってないので、また時間があるときにでも調べよう。

*1:Bitcoinなどではトランザクションを一部でも変更すると署名が無効になるが、現状のMWプロトコルではトランザクションアウトプットは署名に含まれないため変更ができてしまう

*2:Bitcoinと違って、トランザクションインプットやアウトプットが署名対象に含まれていない、かつ送信者が受信者のブラインドファクターを知っているため、アウトプットに受信者の公開鍵をセットしたとしても、このような攻撃が可能になる