Develop with pleasure!

福岡でCloudとかBlockchainとか。

Bitcoinのプライバシーを向上する決済プロトコル Pay to EndPoint(P2EP)

Blockstreamが先日公開した、Bitcoinのfungibilityの問題を改善するため、Pay to EndPoint(P2EP)という決済プロトコルを発表してたので見てみる↓

blockstream.com

Bitcoinのプライバシーの課題

Bitcoinの課題の1つとして挙げられるのがfungibility。

現金であれば、それがどのような使われ方をして自分の財布の中にあったとしても、その紙幣を使って支払いができる。偽札でも無い限り、紙幣での支払いを拒否されることはない。1万円札はどこに行っても同じ1万円の価値があり、交換可能。

たがBitcoinの場合、自分が持っているコインがどういう経路を辿ってきたか、ブロックチェーンを分析することである程度分かる可能性がある。そのコインの出処によってはそのコインの支払いを拒否するといった可能性も否定できない。本来、どいういう経路であれ自分が受け取り財布の中にあるコインは、同じコインとして使用できるべきで、コインの出処によって関係のないユーザーの価値が毀損されるという自体は避けたいが、現金と比べると、こういった代替可能性がBitcoinの場合は低い。

このfungibilityの課題について改善しようというのがPay-to-EndPoint (P2EP)のゴール。

コインの出処や所有権が追跡できるようにしようとブロックチェーンの分析がされているが、この分析は、1つのトランザクションのインプットは全て同じユーザーが所有している「common input ownership」という仮定に基づいて行われている。まぁマルチシグやCoinJoinのような取引を除いて、ほとんどの取引は事実そういうトランザクションになっている。コインの追跡はこの前提を元に行われるので、この前提を壊せばコインの追跡がしにくくなり、Bitcoinにおけるfungibilityの課題を改善できるのではないか?ということみたい。

では、「common input ownership」の前提を崩すにはどうすれば良いかというと、

普段コインを送金する際は、コインの受信者が送信者にアドレスを伝え、送信者がそのアドレス宛にコインを支払うトランザクションを作成&署名し、ネットワークにブロードキャストする。この場合、当然送信者が作成するトランザクションのインプットのUTXOの所有権は送信者が持つものだ。

P2EPでは、この送金トランザクションのインプットに送信者のUTXOに加え、受信者のUTXOも加えることで「common input ownership」の前提を崩そうとしている。

具体的には↓

Pay to EndPointのプロトコル

Pay to EndPointでは、以下の手順で、受信者と送信者が協力して送金トランザクションを作成する。

手順1

受信者はまずBIP-21形式の送金先URIを生成し、送金先として送信者に送る。この時、URIにP2EPのエンドポイントを付与する。

bitcoin:175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W?p2ep=3j4tau93wkc8mh32.onion

↑のようなURIが生成される。通常のBIP-21のURIに加えて、p2epキーでP2EPのエンドポイントのURI3j4tau93wkc8mh32.onionが付与されている。

※ BIP-21のURIの定義には未定義のkey-valueを指定可能なので、P2EPに対応していないウォレットは、従来の方法でコインを送ることになる。

手順2

送信者は受信者から送られてきたエンドポイントが有効であれば、受信者との対話を始める。

  • エンドポイントが有効でない場合
    通常の送金と同様BIP-21のURIに記載されているアドレス宛にコインを送金する。
  • エンドポイントが有効な場合
    UTXOの所有権の証明として、自分が送金する額を持つ自身のUTXOをトランザクションのインプットにセットした署名済みのトランザクションを受信者に送る。

手順3

受信者は署名のため多数のトランザクションを署名のため送信者に送る(これらのトランザクションはさっき送信者が送ってきた送信者のUTXOと、受信者のUTXOがセットされたものと思われる)。 ただこれらのトランザクションのうち、実際に受信者が所有しているUTXOがセットされたトランザクションは1つのみで、それ以外は未使用のUTXOプールから選択されたUTXOがセットされたトランザクションになる。

このトランザクションは、送信者に直列もしくは並列で送られる。

直列送信

順番に送信されるトランザクションのどれが受信者のUTXOを持つトランザクションかの確率は、受信者が選択し署名したトランザクションの数と順番がどのようにランダム化されたかによって代わる。一連のトランザクションの交換は、送信者が受信者のUTXOを使った署名済みのトランザクションを受信者に送ると終了する。

並列送信

受信者によって作成されたトランザクションは全て一度に送信者に送られる。送信者が受け取った一連のトランザクションの内、受信者が所有するのは1つのみ。送信者が正しいもの(受信者のUTXOを持つTx)を選択する確率は、受信者が選択して送信したトランザクションの数に比例する。送信者は全てのトランザクションに署名し、受信者に送付する。

上記いずれかの方法で受信者が送信するトランザクションの数は今のところ100個で、いずれかの側でプライバシーとデータ送信/処理のバランスを取る。

UTXOを交換する上記の方法は、Bulletproofsを使用する方法で置き換えられるかもしれない。

手順4

手順3のどちらのケースでも、受信者は署名済みのトランザクションを手に入れので、このトランザクションに受信者の署名を加えてブロードキャストする。このトランザクションのインプットには受信者と送信者の両方のUTXOが含まれている。

上記P2EPのプロセスが何らかの理由で失敗した場合は、従来通りの方法でコインを送金する。

P2EP送金の具体例

アリスがボブに1 BTC送金したい場合、P2EPのプロトコルを使って以下のようなトランザクションを作成する。

  • アリスはトランザクションのインプットに3 BTCをセットする。
  • ボブはトランザクションのインプットに5 BTCをセットする。
  • アリスはお釣りとして2 BTC受け取る。
  • ボブはアリスからの送金分とお釣りで6 BTC受け取る。

こうやってできたトランザクションは「common input ownership」の仮定を崩したものになる。これがどういう送金なのかはいろんな解釈ができる。例えば、アリスが3 BTCと5 BTCのUTXOを使って、ボブに6 BTC支払い、2 BTCのお釣りを受け取ったなど。

P2EPの利点と欠点

利点
  • 「common input ownership」の仮定を崩せる。最小限の採用であっても、通常の非P2EPトランザクションのプライバシーを改善できる。
  • subset sum analysisを壊す。
  • 受信者のUTXOを使用することで、UTXOの膨張を低減させるのに役立つ。
  • 受信者はP2EPを使うことでUTXOセットを統合できる。
  • 従来のCoinJoinトランザクションと異なり、見た目は通常のトランザクションと変わらないので、トランザクションタイプを特定するのが困難。
  • 送信者のウォレットは軽量ウォレットでいい。
  • 送信者と受信者にはより大きなプライバシーが与えられる。
欠点

P2EPの今後

P2EPはまだ初期段階なので、正式な提案の前に今後コミュニティからのレビューと改良が加えられる。

P2EPの考え方は、支払いの分割やコインスワップなど他の形態のトランザクションを含むよう拡張することも可能と。

所感

  • 受信者側にホットウォレットとフルノードへのアクセスが必要というのは、それなりにハードル高い。
  • ↑の手順3で受信者が多数のトランザクションを送信者に送ってるのが、UTXOのスプーフィング攻撃への対応?
  • P2EPに限らず、P2Pの参加者間で対話的に決済トランザクションを作成するネットワークの標準仕様とかあると便利かも。
  • 通常のP2PKHの送金だと一般的には1つのインプットと2つのアウトプット(送金先のアウトプットとお釣りのアウトプット)が考えられ、UTXOの数は増えていくトランザクションが多いと思うけど、インプットに受信者のUTXOが増えることでUTXOの膨張を低減させるって視点はおもしろいな。

安全性とプライバシーを強化するペイメントチャネルネットワーク「Multi-Hop Locks」

LNではHTLCを使って仲介者を経由したマルチホップ決済を可能にしている。例えばアリス→キャロルのオフチェーン決済をボブとマイクを経由して行うケースでは以下のような決済フローになる。

f:id:techmedia-think:20180704140150p:plain

  1. 最初に受信者のキャロルがランダムな値Rとそのハッシュ値H(R)を生成し、H(R)をアリスに渡す(invoice)。
  2. アリスはキャロルまでの経路を決め、H(R)とタイムロックを組み合わせたHTLCトランザクションをボブとのペイメントチャネルに投げる。
  3. 仲介者はさらに経路上の隣のユーザーにHTLCを流していく。
  4. キャロルまでHTLCが届いたら、マイクにRを明かして資金を受け取る。
  5. 今度は逆方向に終着点アリスまでRと交換に資金をセトルメントしていく。

ここでタイムロックとシークレットを組み合わせたHTLCは、以下のような条件を持つコントラクト(↑のアリスとボブで考えた場合)

  • 3日経過する前にボブがハッシュを取るとH(R)になるようなRを生成できればアリスはボブにコインを支払う。
  • 3日経過するとアリスにコインが戻ってくる。

こういったマルチホップ決済について、一般化し安全性およびプライバシー保護を強化するMulti-Hop Locksという新しい提案が発表された↓

https://eprint.iacr.org/2018/472.pdf

↑のホワイトペーパーの著者であるPedro Moreno-Sanchezのプレゼン↓

youtu.be

マルチホップ決済のモデル化

↑のホワイトペーパーではこのマルチホップ決済のようなロック機構をMulti-Hop Locksという暗号プリミティブとしてモデル化している。このモデル自体はマルチホップ環境下のロックを一般化したもので、LNはその使用形態の1つ。LNの場合はロックの解除=コインの入手を意味するMulti-Hop Locksの一使用形態になる。

ホワイトペーパーでは、このモデルを実装するための方法として以下の3つの方法を提示している。

  • 一方向準同型関数を使った一般的なスクリプトベースの構成
  • Schnorr署名を使ったScriptless Scriptベースの構成
  • ECDSAを使ったScriptless Scriptベースの構成

一般的なスクリプトベースの構成では一方向の準同型関数を使った任意のコントラクトを作成できるブロックチェーンである必要があり、EthereumやHyperledger Fabricがターゲットとして挙げられている。BitcoinはまだSchnorrはサポートしていないので、現状のBitcoinベースでMulti-Hop Locksを実装する場合、ECDSAを使ったScriptless Scriptの構成になる。この場合、2017年にYehuda Lindellが発表した「Fast Secure Two-Party ECDSA Signing」を使って後述する鍵生成やロックが実装される。

(参考) techmedia-think.hatenablog.com

Multi-Hop Locksは以下の5つのプロトコルで構成される。

f:id:techmedia-think:20180705095024p:plain

1. 鍵生成

チャネルを構成する二者間の鍵を生成するプロトコルで、アリスとボブがいた場合アリスの鍵 {sk_1}とボブの鍵 {sk_2}、最後にアリスとボブの共通公開鍵 {pk}を返す。

基本的にはチャネルを開設した時点で、お互いの公開鍵を知り、共通公開鍵を共有している状態(チャネルを開いた時点で鍵生成プロトコルは実行済み)になると思われる。

2. セットアップ

セットアッププロトコルは、参加者の集合(=LNで決済する際の経路)が与えられた際に、経路上の各参加者に状態 {s_i}を与えられる。また最後の参加者(=LNでコインの最終的な受信者)にはさらにオープン鍵 {k_n}が与えられる。各状態はこの後のロックを生成するのに使われる。

3. ロック

続いて隣り合う各参加者のペアがロックプロトコルを実行する。ユーザーのペアを {U_i} {U_{i+1}}とした場合、2人は両者の初期状態 {s_i} {s_{i+1}}を使ってロック( {L_i})を作成する。このロックは、ある暗号条件が {U_{i+1}}によって解かれた場合に、 {U_{i}}がある量のコインを {U_{i+1}}に支払うというコミットメントになっている。

既存のLNではこのロックをアンロックする際に必要となるのは、受信者がコインを受け取る際に必要なプリイメージで、経路上の全ノードのコミットメントで同じ値が使用されるが、Multi-Hop Locksの場合はアンロック条件は隣り合うノード毎に異なるのが特徴だ。

↑の図のアリスとボブの場合は、初期状態 {s_0} {s_1}を使って、ロック {L_0}を生成し、 {s_0^{R}}をアリスに {s_1^{L}}をボブに送る。

このロックは、 {L_0}のロックを解いたらアリスがボブにコインを支払うというコミットメントを表す。

4. リリース

リリースプロトコルは↑のロックを解放するプロトコルで、オープン鍵kと {(s_i , s_i^{R}, s_{i}^{L})}が与えられた時、新しいオープン鍵k'を返す。

↑の図では、キャロルがロック {L_2}をアンロックするために、最初に受信したオープン鍵 {k_3} {(s_3 , s_{3}^{L})}を使って新しいオープン鍵 {k_2}を入手する。キャロルは {k_2}でL2をアンロックすると、今度はマイクが {k_2} {(s_2 , s_2^{R}, s_{2}^{L})}を使って、L1をアンロックするためのオープン鍵 {k_1}を入手できる。これを送信者のアリスに辿り着くまで続ける。

5. 検証

検証プロトコルは、↑のリリースプロトコルで生成したオープン鍵とロックから、そのロックがリリースできるか検証する。

一方向準同型関数を使った実装

モデルでなんとなーくのイメージは掴めるけど、一般化されたモデルで実際のロジックが分かりづらいため、一方向準同型関数を使った実装で理解する。

一方向準同型関数というのは、 { y = f(x)}のような関数で、yからxを計算することが困難で、かつ {f(x) \cdot f(x') = f(x \cdot x')}のような準同型性がある関数。

楕円曲線の鍵ペアを使うのが簡単で、秘密鍵をxとした場合y = xGとなり、xG + x'G = (x + x')Gとなる性質を持つ関数を採用する。

セットアップフェーズ

  1. LNで支払いを行う送信者は受信者までの数分(n)、ランダムに値をサンプリング( {y_0, ..., y_n})する。
  2. 送信者は受信者までの各ユーザーに対して3つのアイテム= {(\sum_{j=0}^{i-1}y_jG,\, \sum_{j=0}^{i}y_jG,\, y_i)}を送る。参加者が3人の場合、以下のデータが送られる。
    •  {U_0}(送信者)には {(n/a, y_0G, y_0)}
    •  {U_1}(中間者)には {(y_0G, (y_0 + y_1)G, y_1)}
    •  {U_2}(受信者)には {((y_0 + y_1)G, (y_0 + y_1 + y_2)G, y_2)}
  3. 受信者にだけ、 {\sum_{i=0}^{n-1}y_i}をオープン鍵を送る(この場合オープン鍵 =  {y_0 + y_1 + y_2})。

ロックフェーズ

各ユーザーは、送信者から送られたデータを元に、ロックスクリプトを構成する。3つ受信したアイテムの内、右側のノードの2つめのアイテムと、左側のノードの1つめのアイテムは同じデータを指しているので、それを使ってロックをする。

例えばU_2U_3の間のロックはU_2 {(y_0G, (y_0 + y_1)G, y_1)}の2つめのデータと、U_3 {((y_0 + y_1)G, (y_0 + y_1 + y_2)G, y_2)}の1つめのデータは {(y_0 + y_1)G}で同じ値になる。これを使ってロックスクリプトを構成する。この時の条件は、 {y_0 + y_1}が明らかになればU_2からU_3にコインを支払うというもの。

これがHTLCの代わりで経路上の全ノードが実行する。

リリースフェーズ

受信者がセットアップフェーズで送信者から送られた y_{n-1}とオープン鍵を使ってコインを入手する。3者の場合、受信者U_3は、y_2を知っているので、別途送信者からもらったオープン鍵 {k = y_0 + y_1 + y_2}からy_2を引いて {y_0 + y_1}の知識を得る。 {y_0 + y_1}は、  {U_2} {U_3}間でロックされているコインのアンロックするのに有効なプリイメージなので、これを  {U_2}開示するとコインを入手することができる。

続いて {U_2} {y_0 + y_1}が分かるので、セットアップフェーズで受信したy_1を引いてy_0を計算する。y_0が分かれば {U_0}からコインを入手できるという仕組みだ。

図にまとめると↓な感じ。

f:id:techmedia-think:20180801142831p:plain

説明のためにプリイメージのみをアンロック条件として記載しているけど、実際はプリイメージを知っているアリスが不正をしないよう、各ノード間のコントラクトには別途参加者の鍵での署名も条件に加わると思われる。

こうやって準同型性のある一方向関数を使うことで、受信者側(左側)から順にコインをアンロックし、アンロックに使用した値がさらにその先のロックをアンロックするのに使われる仕組みを実現しており、これがHTLCの代替になる。HTLCと比べて各中間ノードで扱われる条件はそれぞれ異なるのでプライバシー及びセキュリティの向上になると考えられる。

※ なお、現状のBitcoinでは一方向準同型関数を使った構成はスクリプトで実装できないので、現状のBitcoinに適用する場合は別のECDSAを使ったScriptless Scriptの構成を取る必要がある。SchnorrやECDSAを利用した実装については、別途書けるといいな。

Multi-Hop Locks のメリット

従来のペイメントチャネルが、ハッシュのプリイメージとコインを交換するHTLCの連鎖であったのに対し、Multi-Hop Locksでは各ホップで両者の状態( {s_i, s_{i+1}})を使ってロックを構成し、そのロックは右側のロックをリリースした際のオープン鍵を使ってアンロックできるようになっている。

このモデルでは既存のペイメントチャネルに比べて以下のようなメリットがある。

  • HTLCでは経路上に同じシークレット値とそのハッシュを使用するが、Multi-Hop Locksは各ホップ毎にロック条件が異なるのでプライバシーが向上する。
  • HTLCの場合、途中のコミットメントトランザクションがブロードキャストされると、HTLCが使われていたことがチェーン上で明らかになるが、Scriptlessで構成した場合チェーン上に現れるのは(P2PKHのような)通常の決済のトランザクションと同じになるのでプライバシーが向上し、さらにトランザクションサイズも削減され、その結果、手数料、オンチェーン上のスペースの削減が見込まれる。
  • Scriptlessの構成の場合、EthereumなどのECDSA(もしくはSchnorr)をサポートするその他の暗号通貨にも同様に適用可能。
  • LNに限らずAtomic SwapもScriptlessベースで行うと、HTLCトランザクションがオンチェーン上に記録されることはなく、プライバシーの向上が見込める。

Bitcoinベースの新しいデジタルアセットプロトコル「RGB」

Lightining Networkとの連携も含めた、「RGB」というBitcoinベースの新しいデジタルアセットプロトコルが発表された↓

github.com

RGBのプロトコル仕様は、現状以下の5つのモジュールに分かれている。

  1. RGB
    プロトコルのコアおよび低レベルのアセットロジックを定義。
  2. Kaleidoscope
    他のモジュールを包括しプロトコルとして相互作用するための高レベルの機能を定義。
  3. Bifröst
    クライアントサイド検証の枠組みのプルーフの保存と公開について定義。
  4. Lighting Network Integration
    RGBをLighting Networkに適用する(アセットに対応したルーティング、チャネルの更新、クローズなど)ために必要なBOLTの拡張などを定義。
  5. Proofmarshal
    アセットに特化した形で、スケーラビリティとプライバシーを向上させる、Lightning Networkを補完・代替するレイヤー2ソリューションの定義。

まだ完成という訳ではないっぽく、現時点で使用が少しでも記載されてるのはRGBと、Bifröst、Lighting Network Integration。いずれもまだ作成途中っぽい。Lighting Networkで任意のアセットをオフチェーンで取引するための拡張仕様が定義されてたり、LNとは別のスケーラビリティソリューションの提案とか特徴的。

まずは、RGBモジュールみながらコア機能についてまとめた。

アセットの検証

一般的に、カラードコインはOP_RETURNを利用してBitcoinのトランザクションレイヤーを拡張しているが、Bitconのプロトコル上、OP_RETURNにあるデータは何の意味ももたず、その上に構成されるアセットの取引もコンセンサスレベルで関与することはない。そのため、こういった拡張プロトコルでは、そのプロトコルに対応したウォレットやノードなどのクライアントが、アセットの振る舞いの検証をするClient Side Validationモデルを採用する。RGBも他のカラードコインのプロトコルと同様このClient Side Validationを採用している。

コントラクト

アセットがどのようなもので、アセットの発行方法、転送のルールなどを定義したものをコントラクトと呼んでいる。このコントラクトのデータは以下の2つのデータで構成される。

  • header
    コントラクトの全種類共通のヘッダ項目
  • body
    コントラクトの種類毎に定義される項目

headerのデータ項目は以下の通り。

フィールド 内容
title アセットコントラクトのタイトル
description アセットコントラクトの定義
contract_url コントラクトとlight-anchorの発行に関する一意のURL
issuance_utxo このコントラクトをデプロイするためのコミットメントを持つトランザクションで使用されるUTXO
network 使用中のネットワーク(mainnet, testnet)
total_supply 総供給量(単位はsatoshi)
min_amount dust limitのように転送する際のトークンの最小量
max_hops 再発行前の最大ホップ数(この機能を無効にする場合は0xFFFFFFFFを設定する)
reissuance_enabled 再発行機能を有効にするかどうか
reissuance_utxo (オプション)トークンを再発行する際に使用するUTXO
burn_address トークンを償却する際の送信先アドレス
commitment_scheme このコントラクトで使用するコミットメント方式
version 使用されたブループリントのバージョンを表す16 bitの数値

Open Assets ProtocolなんかだとAsset Definition Fileに近いけどあれはメタデータ的な位置付けで、↑ではアセットの種類による振る舞いやルールも定義するようになっている。

アセット識別子:asste_id

各アセットはasset_idで識別される。このasset_idコントラクトのいくつかのデータ項目のハッシュから計算されるようだが、現時点では算出方法については書かれてない。

Proof-of-burn

アセットを焼却する際は、コントラクトのheader内のburn_addressで指定されたアドレスにアセットを送る。

ブループリント

コントラクトには種類があって、この種類によってアセットがどのように管理されるかであったりその振る舞いが決まる。これをブループリントと呼んでいる。

現状定義されているブループリントは以下の3つ。

Simple issuance: 0x01, version: 0x0008

シンプルなアセット発行のコントラクトで、headerのtotal_supplyで指定された量のアセットを発行し、owner_utxo宛に送る。

このタイプのコントラクトのbodyのデータ項目は、以下の通り。

フィールド 内容
owner_utxo 全てのトークンを受け取るUTXO

この場合コントラクトは以下のようになる。

{
  "kind": 0x01 // 作成するコントラクトの種類で、これは一般的な発行
  "version": 0x0008 // このコントラクトの種類で使われるバージョン
  "title": <String>, // アセットコントラクトのタイトル
  "description": <String>, // 償還可能なアクションと非スクリプトによる条件の定義
  "issuance_utxo": <String>, // このコントラクトへのコミットメントに使われるUTXO
  "contract_url": <String>, // コントラクトおよびlight-anchorを公開するための一意のURL
  "total_supply": <Integer>, // 総供給量(satoshi)
  "max_hops": <Integer>, // 再発行前にアセットに対して実行可能なオンチェーン転送の最大量
  "min_amount": <Integer>, //一緒に転送可能なカラーリングされたsatoshiの最小量
  "network": "BITCOIN", // 使用するネットワーク
  "reissuance_enabled": 0, // 再発行の無効化
  "burn_address": <Address>, // トークンを焼却するのに使用するアドレス
  "commitment_scheme": "OP_RETURN", // このアセットで使用するコミットメント方式
  "owner_utxo": <String>, // 全ての発行トークンを受信するUTXOで、コントラクト指定のフィールド。
}
Crowdsale: 0x02, version: 0x0008

クラウドセール用のブループリント。total_supplyまで指定した価格でトークンを販売する。コントラクトには異なるasset_idをもつ2つのアセットが作られる。1つは通常のトークン用のアセットでもう1つは払い戻し用のトークン。払い戻し用のトークンはクラウドセールの期間前や後に送金してセールを逃したユーザー向けのもの。

このタイプのコントラクトのbodyのデータ項目は、以下の通り。

フィールド 内容
deposit_address トークンを購入する際のBitcoinの送金先アドレス
price_sat 1トークンあたりの価格(satoshi)
from_block クラウドセールを開始するブロック
to_block クラウドセール終了のブロック
Re-issuance: 0x03, version: 0x0008

アセットの発行者が、供給量を増やすことでアセットの再発行を可能にするブループリント。このコントラクトを使用する際は、オリジナルのコントラクトのreissuance_enabledが0でないこと。またオリジナルコントラクトのreissuance_utxoで指定されているUTXOを使ってデプロイする必要がある。

このコントラクトの場合、header内のtitle,description,network,min_amount,max_hops,burn_address,commitment_schemeはオリジナルから変わらないので全て0をセットする。

またbodyのデータ項目はない。

プルーフ

コントラクトは上記のように種類によってルールが異なるが、各コントラクトに設定された全ての条件を満たすことでアセットの所有権を証明し、そのアセットの送付が可能になる。このコントラクトに設定された全ての条件を満たしたことを証明するのがプルーフになる。

プルーフコントラクトと同様headerbodyを持つとされているが、具体的な項目についてはまだ定義されていないっぽい。

アセット送付時のプルーフ

アセットを送付する際は、以下のデータがプルーフになる。

  • アセットの発行から今までの全てのプルーフのチェーン
  • 以下3つの項目からなるリスト
    • 取引するトークンのカラー
    • 取引する量
    • 送信するトークンのアウトプットに関する情報で、UTXOベースのトランザクションを送信する場合はSHA256D(TX_HASH || OUTPUT_INDEX_AS_U32)で、アドレスベースのトランザクションを送信する場合は受信者に送信するアウトプットインデックス。
  • (オプション)meta-dataに関連するmeta-script

これらのプルーフは以下のdark-tagを使ってAES256で暗号化され、Publisher Serverに送られる。

dark-tag

アセットの受取人が生成する30バイトのエントロピーを持つ共通鍵で、アセットを送ってもらう際に、アドレスおよびPublisher Serverの情報と一緒に、アセットの送信元に送る。

受取人がdark-tagを生成する際は、受信用のアドレスを生成するのに使用しているBIP32ベースの導出鍵を使って導出する。

プルーフの情報はこのdark-tagで暗号化されているため、取引されているカラーや量に関してはこのdark-tagを知っているユーザーのみが把握でき、第三者ブロックチェーン上のトランザクションを確認してもこれらの情報は確認できないと思われる。

dark-tagが漏洩すると、発行トランザクションからそのトランザクションまでのアセットの流通経路は分かるが、途中で分岐していた場合などはそっちのアセットの流通経路までは分からない。

Publisher Server

Publisher Serverは、各アセットの取引で生成された暗号化されたプルーフを保存し、そのクエリに対応するサーバー。アセットの発行者によってメンテナンスされる場合もあるし、個々の受信者がメンテナンスしたり、第三者によって提供されることも考えられる。

BitTorrentやIPFSなどの分散ストレージの利用も挙げられているが、RGB自体はPublisher Serverについてシンプルさのため集中型の管理もありとしてる。

コミットメント方式

アセットを新規発行する際は↑のコントラクトのデータを、アセットを送付する際はその条件を満たしていることを証明する↑のプルーフをそれぞれブロックチェーンにコミットする必要がある。Open Assets Protocolでは、これらは基本的にOP_RETURNのアウトプットにMakerOutputと呼ばれるOA用のペイロードをプッシュする形態をとっていたけど、RGBの場合は以下の2種類の方法が用意されている。

OP_RETURN

他のカラードコイン同様OP_RETURNを使う方法で、OP_RETURNの後に↑のコントラクトやプルーフのエンティティ情報をプッシュする。OP_RETURNを使ったRGBの有効なコミットメントを含むトランザクションのルールは以下の通り。

pay-to-contract

pay-to-contractは直訳するとコントラクトへの支払い。コントラクトの内容を元に鍵およびアドレスを生成するプロトコルで、昔Blockstreamが発表したSidechainのホワイトペーパーなどで紹介されている。

RGBのエンティティにコミットするpay-to-contractアドレスは以下のように計算する。

  1. ランダムに128 bitのnonceを生成する。
  2. weak = hmac_sha256(key=original_pubkey, data=(nonce||double_sha256(RGBのエンティティ)))を計算する。
  3. new_pubkey = original_pubkey + G * tweakを計算する。
  4. 計算したnew_pubkeyを公開鍵として、P2WPKH or P2PKHアドレスを生成する。

この公開鍵に対応する秘密鍵は、元の秘密鍵に対して同じ計算を適用することで計算できる。

後は計算したアドレス宛に送金するトランザクションを作るだけで、トランザクションの構成は通常の支払いと何ら変わらない。

アセットの送付方法

RGBで実際にアセットを送付する際、送信者は以下の2つの方法でアセットの所有権を移転できる。

アドレスベース

アセットの受信者がアセットのUTXO自体を受け取りたい場合に使用する。この場合、プルーフには、トランザクション内の受信者の送信先アドレス宛のアウトプットのインデックスをセットする。

※ アセットを受信者のアドレスに送るという直観的に分かりやすい方法で、他のカラードコインなどでも一般的によく使われている方法。

UTXOベース

受信者が既に持っているUTXOに、トークンをバインドしたい場合に使用する。このためこの送付トランザクションには受信者向けのアウトプットは含まれず、プルーフには、送信先のUTXOのハッシュをセットする。

※ この場合ブロックチェーントランザクションを見ただけでは、誰から誰にアセットが送付されているのか推測できない。

この場合、複数のアセットが同じUTXOを指定していた場合、そのUTXOは両方のアセットを持つということになるのかな?

RgbOutPoint

上記のようにアドレスベースの場合は送信トランザクションのアウトプットインデックスを、UTXOベースの場合は受信者の既存のUTXOのOutPointを指定することになるが、それぞれをエンコードしたオブジェクトをRgbOutPointと呼んでいる。

RgbOutPointシリアライズする際は、どちらか分かるようUTXOベースの場合は0x01、アドレスベースの場合は0x02がプレフィックスとして付与される。(長さで分かりそうな気がするけど)

所感

Open Assets Protocolとかだと、取引するアセットの量や宛先は全てトランザクション内のMarkerOutput(OP_RETURNにOpen Assets Payloadをプッシュしたもの)で管理されていて、OAのトランザクションを解釈できれば、ブロックチェーン上でどのアドレスからどのアドレスにいくつのアセットが送られているか確認できるプロトコルだったけど、RGBの場合取引するアセットやその量は全てプルーフに記載され、受信者が生成した共通鍵dark-tagで暗号化されPublisher Serverと呼ばれる外部ストレージに保存されるようになっている。ブロックチェーン単体ではアセットの動きは追えず、外部にあるプルーフが必要になる。UTXOベースのトランザクションであれば、プルーフのみがブロックチェーンアンカリングされているといっても良い。

ノードはトランザクション内のコミットメントとプルーフから受信したアセットの情報を判断するので、フルノードでなくSPVノードのような軽量ウォレットでもアセットの管理ができるだろう。

まだ不明点も多いので具体的な実装を含めてプロトコルの完成までまだ時間かかりそうだけど、他にもLNとの連携や、LNとは別のスケーラビリティソリューションなど面白そうな機能はあるので、今後が楽しみ。

不明点

↓のようにドキュメントの中に出てくるけど、内容や仕組みについてまだ書かれてないことが多い。

  • asset_idの計算方法
  • プルーフの具体的な構成と、検証の仕組み
  • プルーフチェーンの構成方法とその正しさの証明
  • meta-dataやmeta-scriptの内容と振る舞い
  • dark-tagの導出方式
  • Publish Serverと通信する際の具体的なプロトコル

ペイメントチャネルへの資金のチャージ/引き出しを行うSplicing

Lightning Networkはオフチェーン決済を行う2者が資金を両者のマルチシグにデポジットするトランザクション(Funding Tx)をオンチェーンにブロードキャストし、そのデポジットした額(キャパシティ)の範囲内でオフチェーン決済を行う。キャパシティを超える額の決済はできないし、どちらか一方の残高が0になると、0になったユーザーからのそれ以上の送金はできなくなる。ここでチャネルに資金をチャージできるようになると便利だし、逆にチャネルの資金の一部を、別のオンチェーン決済に使いたいというケースも考えられる。こういった既存のチャネルへのチャージおよび既存のチャネルからの引き出しをできるようにしようというのがSplicingのコンセプト。

現在提案されている基本的なSplicingは以下のように動作する。

Splice-in

アリスとボブのペイメントチャネルにアリスが資金をチャージしたいケースでは、以下のようにチャネルに資金をチャージする。

f:id:techmedia-think:20180623145002p:plain

アリスとボブは新しいFunding Txを作成する。この新Funding Txのインプットは

  • 既存のペイメントチャネルのFunding Txのアウトプット
  • アリスがチャネルにチャージするコインを持つUTXO

の2つ。新Funding Txのアウトプットは変わらずアリスとボブの2-of-2のマルチシグ。

続いて新Funding Txをインプットにして、それぞれCommitment Txを作成する。この新しいチャネルのCommitment Txの初期状態の残高は

  • ボブの残高は、旧チャネルの最終のCommitment Txのボブの残高
  • アリスの残高は旧チャネルの最終のCommitment Txのアリスの残高 + 新しく追加したUTXOのコインの量

となる。

両者が新しいCommitment Txの作成・署名・交換を終えたら、新Funding Txをブロードキャストする。これにより、旧チャネルのクローズと新チャネルのオープンが同時に行われる=セトルメントトランザクションが自動的に新しいチャネルのFunding Txになる。

また新Funding Txの作成途中や、新Funding Txがオンチェーン上で必要な承認数を待っている間も、ペイメントチャネルを使ったオフチェーン決済は可能で、新旧両方のチャネルでそれぞれ決済を反映したCommitment Txの更新をすれば良い。

Splice-out

反対にチャネルから資金を取り出すケースも同様の仕組みで対処することができる。

アリスがチャネル上の資金の一部を使ってオンチェーン決済を行うケースでは、以下のようにチャネルから資金を取り出してオンチェーン決済を行う。

f:id:techmedia-think:20180623153436p:plain

アリスとボブは新しいFunding Txを作成する。この新Funding Txのインプットは

  • 既存のペイメントチャネルのFunding Txのアウトプット

新Funding Txのアウトプットは、

  • アリスとボブの2-of-2のマルチシグ。
  • アリスがオンチェーン決済したいアドレス宛のアウトプット。

の2つ。

続いて新Funding Txをインプットにして、それぞれCommitment Txを作成する。この新しいチャネルのCommitment Txの初期状態の残高は

  • ボブの残高は、旧チャネルの最終のCommitment Txのボブの残高
  • アリスの残高は旧チャネルの最終のCommitment Txのアリスの残高 - オンチェーン決済に使用するコインの量

となる。

後はSplice-inと同様、両者が新しいCommitment Txの作成・署名・交換を終えたら、新Funding Txをブロードキャストする。

HTLCを使ったSplicing

もともとSplicingの議論は昨年LNの開発者MLの↓の投稿から始まった。

[Lightning-dev] Channel top-up

↑のプロトコルは、アリスがチャージしたい額のコインをオンチェーンでボブに送信し、それと同額のコインをチャネル上でボブからアリスに送る処理をHTLCを使ってアトミックにするというものだった。

この場合、アリスがボブにオンチェーン上で送金するトランザクションと、ボブからHTLCに設定された期間内にその送金を受け取るトランザクションの2つをオンチェーン上にブロードキャストする必要が出てくる。

↑のSplicingを使えば、オンチェーン上のトランザクションは1つだけで済むのと、プロトコル的にもシンプルになる。ただチャネルのクローズが発生するため、LNの各ノード上はペイメントチャネルのクローズとして認識してしまう。実際はSplicingによりキャパシティの変更があっただけで、チャネル及びルーティングは有効なままなので、それらを認識できるようなメッセージの追加なりが必要になる。

いずれにせよ、LNにおけるSplicingの仕様はまだFixされている訳ではないので、今後新しいアプローチが出てくるかもしれない。

ECDSAベースのScriptless Lightning Network

少し時間が空いたけど、Scriptless Scripts with ECDSAのホワイトペーパーについて

techmedia-think.hatenablog.com

techmedia-think.hatenablog.com

と見てきたので、最後のLightning Networkへの適用について見てみる。

Lightning NetworkのベースとなるのはPayment Channelで、このPayment ChannelはBitcoinスクリプトで

  • タイムロック
  • ハッシュプリイメージのチャレンジ

を組み合わせて実装されているコントラクトだ。

↑のホワイトペーパーでは、LNの後者のハッシュプリイメージのチャレンジをマルチホップを意識してECDSAでスクリプトレスに実装するプロトコルについて説明している。基本的なハッシュプリイメージのチャレンジは↑のAdaptor Signatureのプロトコルでも利用されているが、第三者を経由するマルチホップ決済をするため、このプロトコルとは若干異なったものになる。

Scriptless Lightning Network with ECDSA

三者を経由した決済をするHTLCを考える。この基本的な動作は↓

techmedia-think.hatenablog.com

ここでアリスがボブを経由してキャロルに送金する場合、キャロルが作成したシークレットを使ってトラストレスに三者間の決済が行われる。

(タイムロックの部分は置いといて)このハッシュプリイメージのチャレンジを3者間で行うのを、Scriptless Scriptでどう実現するかというのが課題になる。

ベースは↑のAdaptor Signatureのプロトコルで、シークレットαの取り扱いだけ変更する必要がある。Adaptor Signatureではシークレットαの値をボブが生成していたけど、これを生成するのがキャロルになり、アリスとボブは最初αの値を知らない。

アリスとボブの両者がαの値について知らない場合、Adaptor Signatureのプロトコルの手順3でRを計算できないという問題が出てくる。この問題を解決すれば残りのプロトコルはそのままで良い。

解決策を簡単に言うと、αを生成したキャロルは、楕円曲線上の点(=公開鍵) A = gαをアリスとボブに公開して、そのAを使ってRを計算することでこの問題を解決する。

修正されたプロトコルは以下のようになる。

  1. アリスとボブはP1, P2, R1 = gk1, R2 = gk2, m',  {Q = g^{x1 \cdot x2}}について同意する。
  2. ボブは {R3 := (A)^{k2}}を計算し、k2の値を明らかにすることなく {R2 = g^{k2} \land R3 = (A)^{k2} }のゼロ知識証明と一緒にアリスに送る。アリスも同様に {R'3 := (g^{α})^{k1}}を計算し、k1の値を明らかにすることなく {R1 = g^{k1} \land R'3 = (g^{α})^{k1} }のゼロ知識証明と一緒にボブに送る。
  3. アリスは {R \gets (R3)^{k1}}でRを計算し、ボブは {R \gets (R'3)^{k2}}でRを計算する。計算した同じ楕円曲線上の点Rのx座標をrとする。
  4. ボブは {c1 \gets Enc_{pkA}((k2)^{-1} \cdot m' + pq)} {c2 \gets (ckey) \odot (x2 \cdot r \cdot (k2)^{-1})}を計算する。続いてボブは {c_3 = c_1 \oplus c_2}を計算する。この {\oplus}はPaillier暗号の加法準同型演算を表す。結果、 {c3 = EncpkA((k2)^{-1} \cdot m' + pq + x1 \cdot x2 \cdot r \cdot (k2)^{-1})}となるc3をアリスに送る。
  5. アリスはc3を復号しs'を取得する。ここでアリスはボブが暗号化中に不正行為をしていないか確認する必要がある。これは、 {(R_2)^{s' mod q} = Q^{r} \cdot g^{m'}}が成立するか検証すればいい。問題なければ、 {s'' \gets s' \cdot (k1)^{-1}}を計算しs''をボブに送る。
  6. 少ししてボブはペイメントパス上のキャロルから値αを得る(キャロルがボブからの送金と引き換えにαをボブに公開する)。ボブは {s \gets (α)^{-1} \cdot s''}を計算し、署名(r, s)を出力する。
  7. ボブが作成した署名が公開されると、アリスは {α \gets (s \cdot (s'')^{-1})^{-1}}を計算する。

という形で、ECDSAベースでもHTLCを利用した中間者決済をするScriptless Scriptが実装できると。
(ほとんどAdaptor Signatureのプロトコルと同じなのでサンプルコードは割愛)

タイムロックの取り扱い

Payment Channelを構成するもう1つの要素がタイムロックだが、こちらはおそらくScriptless Scriptとして実装するのは難しいので、スクリプトとは別にタイムロックを担保する仕組みが必要になるだろう。

ちなみに、MimbleWimbleの最小実装をするGrinではトランザクションのタイムロックを実現するのに以下のような変更を提案している。

https://github.com/mimblewimble/grin/blob/master/doc/contracts.md

  • 署名対象のメッセージMについて、そのトランザクションが使用可能になるブロック高をhとし手数料と結合してM = fee | hとする。
  • ロックするブロック高はトランザクションカーネルに含まれる。
  • 現在のブロック高より大きいブロック高が設定されているカーネルを含むブロックはリジェクトされる。