bitbank techblog

Adaptor 署名を用いた DLC について

これは ビットバンク株式会社 Advent Calendar 2020 の 14 日目の記事です。

Bitbank の宮本です。
最近 Bitcoin の Discreet Log Contracts (DLC) について調べる機会があったので、備忘のためにまとめます。

Overview

DLC とは

DLC とは、一言で言うと Bitcoin で予測市場を作るためのプロトコルです。
予測市場とは、未来の任意の出来事に応じて賭けを行う、非常に一般化された金融市場のことです。

なぜ予測市場が重要なのか

予測市場は、既存の金融市場の拡張として論じる場合と、意見を表明する新しい方法として論じる場合があります。前者は比較的わかりやすいので、ここでは後者の視点から述べます。

社会に対して意見を表明する方法には、テキストベースの方法 (SNS, ブログ)と、投票ベース(選挙)の方法がすでに存在します。

これらに関して匿名性が重要であることは誰もが認識していることですが、テキストベースの方法の場合はスパム耐性がない(フェイクニュースを防げない)、投票ベースの場合はスケールしない(参加人数に比例して一票の重みが小さくなっていくので、投票しないことが合理的になってしまう)という問題があり、緩和することはできても根本的な解決は不可能です。

予測市場は、将来のある出来事について、意見の表明に対してリスクを負わせるようにすることで上記の問題の解決を目指したものです。

例えば

  1. 政府がマスクを配るか否か
  2. COVID-19 の感染者は減少するか否か

という二つの Event があったとして、「配らない && 感染者は減少する」と、 「配る && 感染者は減少しない」というポジションをとれば、「マスクの配布は感染対策として逆効果である」という意見を述べることができます。

意見はマーケットに反映され、間違った意見を述べた場合は資産を失うというペナルティを受けるので、意見の表明に対して慎重にならざるを得ません。この辺りは普通の金融市場と同じです。

なぜ匿名性が重要なのかというと、(この例の場合)マスクの配布で利権を得る人にとっては反対意見(や、そもそものマーケットの存在)を封じる強いインセンティブがあるためです。

ピンとこない人は、上記の例を別のものに置き換えてみるとわかりやすいかもしれません。
例えばタバコと肺がんの因果関係について、実際にタバコ会社は長い間反対意見を封じる努力をしていました。
あるいは化石燃料と地球温暖化の関係なども一例です。

既存のプロジェクトとの違い

オルトチェーン上では、予測市場を行うプラットフォームとして Augur, Gnosis といったプロジェクトがありますが、ビットコインでこれを行おうとするものはほとんどありませんでした。 [1]

スマートコントラクトベースのオルトチェーンでは、匿名性を担保するのが難しいと言う問題点がありましたが、 DLC では匿名性に主眼が置かれています。

DLC 特有の概念

Oracle, Event, Outcome, Offerer, Acceptor と言う概念があり、だいたい以下のような理解をしておくと良いと思います。

  • Event ... 賭けの対象とする未来の出来事。Oracle によって作成されて周知される。 二つ以上の Outcome と、対応する単一の nonce point $R$ を持つ。
  • Outcome ... Event の結果。Offerer が倍率を提案し、 Acceptor が了承すれば賭けが始まる。後述の、署名対象のメッセージ $m$ として機能する。
  • Oracle ... Event を作成し、結果を判断して署名を配布する主体
  • Offerer ... 既存の Event から、特定の倍率で賭けをすることを提案する主体。 いわゆる Maker と (多分) 同じ
  • Acceptor ... 賭けを受ける主体。 Taker。

Schnorr 署名

DLC には Schnorr 署名[3]を使います。色々な場所で解説されているので手短に述べます。知っている方は飛ばしてください。

メッセージ $m$ に対する Schnorr 署名は通常、適当な楕円曲線上で

$$s = k - h(R || P || m)*a$$

を行うことで作成し、$(s, R)$ を署名とします。
ただし

  • $k$ は nonce, $R$ は nonce point と呼ばれる。 公開鍵、秘密鍵と同様の形式であり、$R = k * G$ を満たす。 ECDSA の nonce と同様、署名者が k を再利用すると危険
  • $G$ ... 楕円曲線の base point
  • $h$ ... 適当な hash 関数
  • $||$ ... byte 列の結合
  • $a$ は署名者の秘密鍵、 $P$ は公開鍵

検証は、$ s * G$ が $ (k - h(R || P || m) * a)* G$ すなわち $R - h (R || P || m) * P $ と一致するか否かをチェックすることで行います。

この $s * G$ を Sigpoint と呼びます。

DLC において重要なのは、 同一の nonce で二回署名を行うと、それぞれの署名の差分を取ることで公開情報から秘密鍵が復元できてしまう点です。

Oracle は、 Event を作成、アナウンスした時点で、その Event に nonce を紐づけておきます。したがって、単一の Event に二度署名すると、秘密鍵が流出することが周りから検証できるようになります。

Oracle が長期間同じ秘密鍵/公開鍵を利用する (つまり、 Oracle を特定の公開鍵に紐付ける)ことで、一度もその秘密鍵が流出していない (= Oracle は「同じ Event に対して二度署名を行う」と言う不正を一度も働いていない)と言うことがわかるので、参加者はより Oracle を信用しやすくなります。

現在のビットコインでは、 Schnorr をトランザクションの署名のために使うことはできません。 Taproot [5] の導入で使えるようになる予定です。
なお、 DLC では TX ではなくメッセージへの署名に使うので、 Taproot は必須ではありません。

用語の定義

元々 DLC を提案した Thaddeus Dryja さんは、現在普及している Lightning Network (以下 LN) の仕組みを考案した人でした。
なので、 DLC の元々のプロトコルは、現在の LN に近いものになっています。
LN の仕組みは基本的にまず、二者間で共通の UTXO に資産を入ます。この UTXO を送信するトランザクションを、 Funding TX と呼びます。
次に、この UTXO から支払われる TX (Commitment TX)を更新することで (ブロックチェーンに TX を取り込ませなくても) 支払いを完了したことにする。と言うものです。
更新に際して古い TX を無効にする必要があり、そのために秘密を相手に明かし、相手がこの秘密を使って古い TX の全資産を横取りできるようにする。と言う仕組みを使います。[2]

DLC の場合、「状態を更新するのではなく、複数の可能な状態のうちから Oracle が一つを選ぶ」と言う点以外は LN と似ているため、ほぼ LN の Commitment TX と同じ構造の TX を使うことで達成できます。
なお、 DLC において Commitment TX に相当する TX を、 **Contract Execution Transaction (CET)**と呼びます。

また、Oracle は、あらかじめ Event に Nonce point $R$ を紐付けて周知していることを思い出しましょう。
これにより、 見込まれる Outcome ごとの Sigpoint をあらかじめ計算しておくことができます。
仮に、 outcome は UP と DOWN の二値のいずれかを取るとしましょう。(Oracle は一週間後の BTC の値が 20000$ を超えていたら UP に署名し、そうでなければ DOWN に署名して公開するものとします)

署名対象のメッセージである、 "UP", "DOWN" のバイト表現をそれぞれ $m_{UP}$, $m_{DOWN}$ とします。

Sigpoint は以下のようになります。

$$s_{UP} * G = R - h( R || P || m_{UP}) * P$$
$$s_{DOWN} * G = R - h (R || P || m_{DOWN}) * P$$

元々のプロトコル

DLC の元々のプロトコルと LN との唯一の違いは、自分(の公開鍵)に対して支払うのではなく、「自分の公開鍵 + Sigpoint 」に支払うことで、「自分の秘密鍵 + Oracle の署名」を秘密鍵として使うことで初めて使用可能になると言う点です。

Schnorr 署名は加法に関して準同型性を持っているため、公開鍵を足し合わせたものへの署名は、それらの公開鍵の元になった秘密鍵を足し合わせて作成した秘密鍵で行うことができます。

Alice の秘密鍵、公開鍵を $a$, $A$ 。 Bob のそれを $b$, $B$ とします。
仮に Alice が UP という outcome に賭けたとすると、それぞれの保持する CET の Output の利用条件は以下のようになります。

  • Alice ... ($A + s_{UP} * G$) or ($B + TimeDelay$)
  • Bob ... ($B + s_{DOWN} * G$) or ($A + TimeDelay$)

仮に $s_{UP}$ が明かされれば、 Alice は $s_{UP} + a$ という秘密鍵が手に入るので、自分の Commitment TX の利用条件が分かります。

二つ目の条件として、一定時間が経ったら相手が無条件で取得することができる。という条件がついています。これは LN では相手が「古い状態をブロードキャストした場合」の罰則のために存在しますが、ここでは相手が「負けた CET をブロードキャストした場合 」の罰則として機能します。例えば Alice が CET をブロードキャストしたが一定時間以内に使用しなかった場合、利用条件がわからない (= $s_{UP}$ を知らない)と見なされ、相手に資産を取られます。

これだけで機能はしますが、以下の欠点があります。

  • 相手が「負けた」 CET をブロードキャストすることは(相手に利点がないとはいえ)可能なので、対処を考えておく必要がある。
  • 罰則を行うために CET で何らかの Timelock を使う必要があるので匿名性が下がる。
  • Bob と Oracle が同一人物であり、間違った値に署名することで資産を盗んだ場合、その証拠が手に入らない。
    • 例えば、BTC の値段が 20000$ を超えていたにも関わらず、 "DOWN" に署名して賭けに不正に勝利するケースがありえます。これは Oracle を信用する以上防げないですが、このことを公にする方法があれば、不正のリスクは下がります。

このことから現在は Adaptor Signature を用いた手法が提案されています。
Adaptor Signature 自体は、 ECDSA でも利用可能ですが、 Schnorr の方が単純なので Schnorr を前提にします。
現在の DLC のプロトコルでは ECDSA を使っていますが、 Taproot が使えるようになったらどうせ全て Schnorr になるので、無理して理解する必要はありません。「同じことが一応できるんだな〜」程度に考えておきましょう。

Adaptor Signature の活用により、「CETに対する罰則が有効になるか否か」ではなく、「そもそも CET の署名が有効になるか否か」という形式で賭けを行えるので、 CET の後続の TX を作る必要がなく、よりシンプルになります。

Adaptor Signature を用いたプロトコル

Adaptor Signature とは

Adaptor Signature とは、別に難しいことをしているわけではなく、単に署名を暗号化したもののことです。
ただし、以下の性質を満たします。

  1. 「特定の(公開鍵に対応する)秘密鍵で復号したら、あるメッセージに対する有効な署名になるか否か」を、暗号化したまま検証することができる(検証可能性)。
  2. 一度復号した値を公開したら、復号に用いた秘密鍵を再構築することができる(one-time 性)

これらの性質から、 One-time Verifiable Encrypted Signature[4] とも呼ばれています。

その方法は、Schnorr と ECDSA で異なりますが、興味がある人はそれぞれググりましょう。方法を解説した記事は多いですが、多くの人には方法はそこまで重要ではないです。

ビットコインの文脈では、主に LN のマルチホップや、Atomic Swap の匿名性の改善などへの応用が見込まれています。

Sigpoint を用いた署名の暗号化

自分が Alice であると仮定します。

まず、相手と合意した額の支払いを行う CET を作成します。 CET は funding TX のマルチシグから支払うので、そのマルチシグのうち自分の分を署名し相手に渡します。ただし、渡す前に Event の情報から導出した Sigpoint ($s_{UP} * G$)を使って、署名を暗号化してから渡します。

Adaptor 署名は、「1. 秘密鍵または公開鍵で暗号化し、2. 秘密鍵で復号できる」ものです。Sigpoint は公開鍵と同じく楕円曲線上の点なので暗号化を行えます。

相手はこの暗号化された署名を調べ、「Oracle が $s_{UP}$ を公開すれば、これを復号して ( CET に対する) 有効な署名にできる。」ということを検証します。

相手は逆に、 $s_{DOWN} * G$ で暗号化した署名を渡してきます。同様に検証します。

お互いに検証が済んだら、 Funding TX をブロードキャストして開始します。

Oracle は後々 $s_{UP}$ か $s_{DOWN}$ を明かすはずなので(明かさなければ Oracle としての役割を放棄したと見なされ、信用を失う)交換した署名のうち、いずれかが有効に、つまり復号できるようになります。自分のが有効になったら、自分の署名を加えて有効な CET を作り、これをブロードキャストして資産をゲットします。

また、上記の One-time 性から署名を再構築することができます。これにより、相手が不正な値に署名した場合、誰からでも検証できるような不正の証拠を入手することができます。

実際には Oracle や相手がいなくなった場合に取引を無かったことにする TX を準備する必要があるなど、もう少し複雑にはなりますが概ねこんな感じです。

Sigpoint の応用

「$R$ (nonce point) のみを先に公開することで Sigpoint を計算できるようにする」という手法は他にも応用が効きます。
例えば、LN 支払いで署名を売ることができるようになります。

現在の LN では、invoice (請求書)に hash を含めておいて、その元になったデータ (preimage)を支払い時に渡し、これをレシートとして扱えるようになっています。

Schnorr 署名の導入後は、この hash-preimage は point-preimage で置き換えられる予定です。つまり、 hash 関数の代わりに $G$ の乗算を行い、公開鍵/秘密鍵で、同様のことをするということです。

これには様々な利点がありますが、応用例の一つとして、 「invoice に Sigpoint (あるいは $R$ ) を含めることで、任意のデータに対する署名をレシートにできる」というものが挙げらられます。

理論上は、これで CET を受け取る権利を売ることができます(馬券を転売するみたいなイメージです。あるいは先物のポジションをクリアリング前に解消する行為に等しいです)。

実際には、LN 特有の問題点があります。
例えば

  1. 元の CET の権利のキャンセルが容易ではない。
  2. (馬券の価値は刻一刻と変化するので、)途中で支払いをキャンセルする権利がどちらかに一方的に存在するような状況では無料のオプション取引が作れてしまう。

これを防ぐため、Escrow を使って処理の Atomic 性を担保する方法が提案されています。
興味がある人は Barrier Escrow とかでググってみましょう。[9]

Outcome を連続値にする

上記の例では Outcome はカテゴリカルな値でしたが、実際は特定の数値を利用する場合が多いです。

例えば、 BTC の価格は UP と DOWN のいずれかではなく、数値で表されるはずです。

これをそのまま賭けの対象にしようとすると、ありうる全ての Sigpoint を最初に計算しておく必要があり、計算量と通信量の観点から現実的ではありません。

そこで、Oracle が署名する値を複数に分け、それらの Sigpoint を足し合わせることで用意しておくべき CET の数を減らす方法が提案されています。

例えば "123" という値に賭けたい場合、 (100 の位の署名が 1 である) AND (10のくらいの署名が 2 である) AND (1 のくらいの署名が 3 である。)
という風に表現し、それぞれの署名を
$s_{100_1}, s_{10_2}, s_{1_3}$ とすると、以下のようにして Sigpoint を計算しておくことができます。

$$s_{123} * G = s_{100_1} * G + s_{10_2} * G + s_{1_3} * G$$

この Sigpoint で暗号化した署名を復号するには、 $s_{100_1}, s_{10_2}, s_{1_3}$ 全てが必要になります。ここで例えば 1 の桁の Sigpoint だけを除外することで、より粒度を荒くできるので (特定の値ではなく) 適当な range に賭けることができるようになります。

Offerer と Acceptor の間で、興味のある range だけを粒度を細かくし、それ以外の部分を荒くすることで、セットアップのオーバーヘッドを少なくすることができます。

より詳しくはこちらを参照してください。

取引の合成

冒頭で述べた複数の Event を組み合わせたような取引も、 Sigpoint を足し合わせることで行うことができます。

上記の連続値 Outcome では、同一の Oracle が発行した Event で複数の Sigpoint を足し合わせていましたが、別の Oracle が発行した Event から導出した Sigpoint を足し合わせれば、同様のやり方で複雑なデリバティブを作ることができます。

今後の拡張

LN との統合

上記で解説してきたプロトコルは、(転売の話を除き)全て on-chain 資産のやりとりに関するものです。
今後 off-chain での payment が主流になっていけば、それを直接 DLC による賭けの対象にするのが自然ですが、これは単純ではありません。
78 のような案がありますが、 Generalized LN Channels を先に考慮した方が良いと思われるので (筆者の主観) 今のところ色々未知数です。

マッチング

Offerer と Acceptor はどこで交換を行っても良いはずですが、実際には相手を探す際に一箇所で行った方が便利です。この辺りは普通の暗号通貨取引と同じです。

自動マーケットメイカー

既存の暗号通貨取引と異なる点として、Event (取引対象)の自由度が非常に高いという点があります。

予測市場を内部告発や世論調査の手段として普及させたい場合、誰でも Event や Event の組み合わせを公開できる仕組みがあることが望ましいですが、その際に作成される取引板が(既存の多くの取引所のように)単なるマッチングを行うものであると問題が生じます。

具体的には、(特に取引が開始されたばかりの時点で)流動性が低く bid-ask spread が大きくなり、正確な価格(= 世論)を知りにくくなったり、誰も taker になりたがらなくなったりといった問題が発生することが知られています。

これは特に、Event を組み合わせることでポジションの種類が増えるとより顕著になります。

この問題を防ぐため、初めに Event 作成者が積極的に Make することで流動性を供給する必要がありますが、マーケットメイクは専門知識が必要で、誰にでもできることではありません。

この問題は予測市場の分野で古くから研究されており、自動マーケットメイカーを用意することで解決することができます。

この点はビットコインよりも他のチェーン上での DeFi で研究が進んでいます

例えば Twitter の poll 機能のように、誰でも手軽に予測市場が作れるようなサービスができれば、より普及が進むでしょう。

終わりに

  • DLC の実装を見たい方は、 p2pderivatives, NDLC, Bitcoin-S を参照しましょう。
  • DLC の仕様は dlcspecs というレポジトリにまとまっています。興味があったら読むか改善案をだしてみましょう。
  • DLC の理解 (と、dotnet での GUI アプリケーション構築のテスト)のために、 NDLC 向けに GUI を作りました。興味がある方がいたらどうぞ。 (自分は忙しくて続きをできそうにないですが、やりたい人がいればアドバイスします。)

注釈

[1]: 一応Truthcoin(Hivemind) と言うのがあります。こちらは DLC と違い完全なトラストレスを目指したものであり、 Augur の着想元になったプロジェクトです。完全トラストレスは非常にハードルが高いので現在は停滞しています。
[2]: この仕組みだと、過去の TX とそれらに対応する秘密を全て覚えておく必要があるため、 TX 数が増えると大変だったり、常にブロックチェーンを監視し続けておく必要があったりと行った欠点があるので、後々別の仕組みにしていく予定です。
[3]: ビットコインにおける Schnorr 署名の仕様はBIP340を参照
[4]: このような性質についての議論は One-time Verifiably encrypted signature を参照
[5]: Taproot は、BIP341 の変更を指すが、 BIP340, BIP342 も同時に導入されるので三つの変更点をひとまとめにして「Taproot」と呼ぶことが多い。

[9]: あるいはここの議論を辿っても良いかも: https://lists.linuxfoundation.org/pipermail/lightning-dev/2019-June/002028.html

Author image
About Joe Miyamoto
Tokyo Website
expand_less