Develop with pleasure!

福岡でCloudとかBlockchainとか。

任意のデータに対する署名検証を行うOP_DATASIGVERIFY(BUIP-78)

OP_GROUPに加えてBitcoin Cashの中期開発計画に含まれているのが、Bitcoinトランザクションの署名検証の際に使われるECDSAと同じアルゴリズムを使って、任意のデータの署名を検証するOP_DATASIGVERIFYという新しいopcode。

https://github.com/BitcoinUnlimited/BUIP/blob/master/078.mediawiki

通常BitcoinスクリプトではOP_CHECKSIGを使って署名の検証をするけど、この時検証に使われるデータはあくまでトランザクションのデータ。この署名検証においてトランザクションに限らず任意のデータに対して署名検証できるようにするスクリプトOP_DATASIGVERIFYというわけだ。

任意のデータについて署名検証できると何が嬉しいの?という話だが、外部の情報をトランザクションに持ち込むオラクルを想定しているようだ。

相変わらずBUIP単体ではプロトコルの内容が分からないので、Andrew Stoneのブログ記事を読もう↓

medium.com

Bitcoinというのはプログラマブルなお金なので、シンプルなプログラマブルマネーということで考えると以下のようなifを使った条件が考えられる。

if (condition) then pay A else pay B

この時重要になるのが、条件を評価するところ、特に外部データをインプットして条件評価をする部分だ。

基本的にBitcoinもEthereumもスクリプトサンドボックス環境で動作するようになっているため、スクリプトを評価する際にスクリプトが外部API叩いて値を取得するといったことはできない。まぁAPIを叩いたところでそれが正しいデータという保証は無いし、中間者攻撃のようなリスクも考えられる。

そのため外部データをブロックチェーンに取り込む場合、オラクルと呼ばれる信頼できるエンティティが登場する。オラクルは現実世界のデータをBitcoinスクリプトで利用可能な形式に変換して提供する存在だ。もちろんオラクルが嘘を付けば破綻するのでオラクルへの信頼が必要になる。極力このオラクルへの信頼を取り除いていく仕組みやインセンティブ設計がいろいろと研究されており、Discreet Log Contractsなんかもそういった点が設計されている↓

techmedia-think.hatenablog.com

ちなみにこのBUIP自体ではオラクルへの信頼の問題を解消する方法については特に触れてはいない。

Andrew Stoneのブログでは株価などのデータを提供するオラクルサービスを仮定し、単純なif文を使ってバイナリオプションがサンプルのユースケースとして挙げて、OP_DATASIGVERIFYの使い方を説明している。

オラクルのデータ提供方法

OP_RETURNの利用

データを提供するオラクルは、OP_RETURNを使ってデータをブロックチェーンに記録できるが、他のスクリプトがそのデータを参照する方法は無い。そこで新しいopcodedata = OP_GET_DATA(address)を追加する。このopcodeはaddressによって署名されたブロックチェーンの履歴を調べ、そのOP_RETURNのデータをスタックにプッシュする。そのアドレスで署名されているトランザクションが無い場合、opcodeは失敗して終了する。そのUTXOは現在使用不可能となる。まだオラクルが嘘をつくという問題はあるが、オラクルだけがそのアドレスのお金を使える(そのアドレスで署名できる)ため、それが提供元(オラクルよる)データであるという真正性は確認できる。

この方法の問題点は、オラクルがたくさんのトランザクションで情報をブロックチェーンに記録しても、それを使用するユーザーがおらず未使用に終わる可能性がある点だ。

OP_DATASIGVERIFYの利用

より現実的なオプションは、オラクルがバイナリオプションを使用するスクリプトの一部として使用できる署名付きにステートメントを個別に公開する方法だ。しかし、これはスクリプトがそのステートメントの真正性を検証しなければならないことを意味する。Bitcoinは簡単に署名を検証できるが、CHECKSIGopcodeはトランザクションデータへの署名のみを検証し、任意のデータの署名は検証できない。そこで

data = OP_DATASIGVERIFY(signature, data, pubkeyhash)

というopcodeを追加する必要がある。

このopcodeはトランザクションではなくスタック上のデータに対してOP_CHECKSIGVERIFYを行う。具体的には↓

  1. スタックからトップ3アイテム(公開鍵ハッシュ、署名、任意のデータ)をポップする。
  2. 署名が任意のデータに対する有効な署名か検証する。
  3. 署名の公開鍵のハッシュが公開鍵ハッシュと一致するか検証する。

この検証のいずれかで失敗するとトランザクションの検証は失敗する。検証が終わるとデータはスタックにプッシュバックされ残りのスクリプトで使われる。

オラクルが署名したデータが、1日の株価の中央値だったとする(証券コードと日付も含めて、データを一意にする)。このメタデータの検証をブロックチェーン上で行う場合、データを証券名、日付、金額の3つのパートに分け独立して評価されるよう、文字列を操作するopcodeを再度有効化する必要がある。

バイナリオプションのスクリプト構成例

とりあえずデータの一意性(証券名とか日付とか)を無視してバイナリオプションスクリプトを作成すると、バイナリオプションに勝ったユーザーが資金を入手する際のscriptSigは次のようなスタックを構成する。

オラクルの署名
オラクルのデータ
勝者の公開鍵 (標準のP2PKHの場合)
勝者のトランザクションの署名 (標準のP2PKHの場合)

参照されるscriptPubkeyは以下のような構成になる。

# オラクルの公開鍵をスタックにプッシュ
OP_PUSHDATA(オラクルの公開鍵ハッシュ)

# 上記のスクリプトのデータと署名を検証
OP_DATASIGVERIFY

# 検証が成功したら、オラクルのデータはスタック上に残り、バイナリオプションのストライクプライスをスタックにプッシュ
OP_PUSHDATA(バイナリオプションのストライクプライス)

# プッシュしたストライクプライスとオラクルのデータを比較
OP_LESSTHAN
# データの比較結果によって、参加者のいずれかへの支払いを許可する
OP_IF
  # 通常のP2PKHトランザクションの始まり
  OP_DUP  # 勝者の公開鍵をコピーする
  OP_HASH160 # 公開鍵をアドレスに変換
  OP_DATA(参加者Aのアドレス)
OP_ELSE
  OP_DUP
  OP_HASH160
  OP_DATA(参加者Bのアドレス)
OP_ENDIF
# 通常のP2PKHトランザクション終わり
OP_EQUALVERIFY # アドレスをハッシュされた公開鍵と比較
OP_CHECKSIGVERIFY # トランザクションと署名が一致するか検証

↑は単純な条件分岐だけど、MASTなんかと組み合わせるとより複雑な条件構成を持ち秘匿性のあるスクリプトにもできそう。

所感

  • 任意のデータについての署名検証ができると確かにコントラクトの応用は広がりそう。そういうユースケースが増えるとオラクルへの信頼問題の研究も進むかもね。
  • でもOP_GET_DATAブロックチェーン上のデータ検索してOP_RETURN探すとか流石に無謀だろう…。
  • ElementsやScaling BitcoinBitcoin Script 2.0なんかでも言われているけど、現在無効化されている文字列やビット列を操作するopcodeについては再有効化を求める声が多い。