Miniscript

Bitcoinのスマートコントラクトのこれまでとこれから

序文

宮本です。最近は複数種類の仕事がさみだれ的にやってきて、発達障害気味な自分にはコンテキストスイッチのオーバーヘッドが辛いです。カフェインで乗り切ります。

さて、先日のStanford Blockchain Conference 2019 で、Pieter Wuille (sipa) がMiniscript というプロトコルについて発表していました。

これは、結論から言うと単に Bitcoin Script にコンパイルする DSL で、発想自体は昔から存在するものなのですが、ルーツが面白いので今日はその辺りを解説します。

Bitcoin Core の Wallet 機能

1年ほど前まで、ビットコイン標準実装である bitcoin core の wallet 機能は他のWalletに比べて様々な面で十分とはいえない出来でした。

Wallet のコードがブロックチェーン本体のコードと密結合になっており、複数の wallet を単一のブロックチェーンノードと運用することができないというのが最も根本的な問題でしたが、他にもマルチシグを作る際のRPCの挙動がイケテナイとか、アドレスに対してのインデックスを張れないので Wallet 側からのアドレスの監視が難しい(これはBIP157, 158によって解決しますが、今回は触れません)とかそういった諸々がイマイチでした。

このような状態になっていた理由は、元々の実装が汚かったというのもありますが、1年以上前はスケーリングの問題が逼迫しており、 mempool のスパム耐性の向上やIBD(Initial Blockchain Download: 初期立ち上げ時のブロックチェーンの同期)の改善などに集中的に取り組まざるを得なかったためです。(並行して wallet の作業をすると git rebase 時に面倒なことになりがち)

現在は、スケーリングの問題がいったん落ち着いたため、wallet 周辺の機能の改善が目覚ましいです。私の印象では大きく三つの領域に別れます

  1. マルチ Wallet のサポートと、Output Descriptor によるブロックチェーンのフレキシブルな監視
  2. BIP157, 158 の実装と BIP37 (SPV クライアント)の Deprecation
  3. PSBT(BIP174) によるハードウェアウォレットのサポート (1に依存)

このうち 1が Miniscript 登場の背景に関与しているので、詳しく解説します。

Output descriptor

ビットコインには「受け取り専用の Wallet 」と言う概念が存在します。単にアドレスをウェブサイトに貼っておくだけだと以下の問題が生じるためです。

  1. 毎回同じアドレスを使用するためプライバシーを大きく損なう(自分だけでなく、自分から支払う人のプライバシーまで損なう)
  2. 不特定多数から受け取るような場合、誰から支払いを受けたのかがただちにわからない。

この問題に対処するため、 公開鍵ではなく公開鍵を生成する xpub をアップロードして、そこから毎回異なるアドレスを生成して受け取る必要がありました。このようなタスクを行うサーバーをペイメントプロセッサーと呼びます。

問題は、xpub から生成するアドレスの形式が一意に定まらない点です。p2pkh, p2pk, p2wpkh, p2sh-p2pkh のうちのどれを使用すれば良いのでしょうか?

加えて、セキュリティ向上のため複数のxpub からマルチシグアドレスを生成し、そこに対して受けとりたいと言うのも大きな需要として存在しますが、p2sh, p2wsh, p2sh-p2wsh が存在するのでさらに複雑になります。(しかも、今後スクリプトのバージョンアップデートが予想されるので、さらに複雑になることが予想されます。)

この問題に対処するため、例えばOSSの代表的なペイメントプロセッサーである BTCPayServer では生成されるアドレスを一意に指定するため独自の形式で指定していますが、その形式と同等なものを bitcoin core が採用したのが Output Descriptor です。

現時点でBIPは存在しませんが、こちらにリファレンスがあります。例えば、 xpub1とxpub2 から1-of-2マルチシグのp2wsh アドレスを生成したい場合

wsh(multi(1, <xpub1のhex>/1/0/*, <xpub2のhex>/0/0/*))

こんな感じになります。わかりやすいですね。hexの後についているのは、Derivation path です。

現在これを採用しているのは、scantxoutset と言うRPC だけですが、後々はHW Wallet との連携のために取り込まれていく予定のようです。

MiniScript

で、(前置きが長くなりましたが)、 Miniscript と言うのはこのOutput Descriptor を拡張して、スクリプト自体の生成にも適用したものです。

上記のDescriptor をよく見ると、multi() と言う関数で、マルチシグスクリプトを生成しています。これをもう少し細かくして、マルチシグ以外の別のスクリプトを指定できるようにしたと言うのが Miniscript です。

例えば、C1, C2 を特定の公開鍵のhexとすると、以下は

or(multi(C1, C2), and(time(1000), pk(C1))

2019/02/27 微妙に間違っていたので訂正します。正しくは
or(multi(2, C1, C2), and(time(1000), pk(C1))) でした。

「C1, C2 の2-of-2マルチシグ」または「1000ブロック経過後にC1の署名」

で解除できるスクリプトを生成します。わかりやすいですね。

Miniscript の、Sipa の作成したデモサイトはこちらにあります。C++ の実装を WASM コンパイルしてブラウザで実行しているようです。(C++ の実装は探したけれど見つかりませんでした。多分 Schnorr 署名の実装と同じ理由で隠していると思われます。セキュリティモデルを理解しないままの利用を避けるため?)。 Andrew Poelstra による rust の実装はこちら

これは、図らずも Ivy のような既存の DSL に近い機能を持つものになっています。 Ivy は Solidity を参考にしたような文法であるという違いはありますが、機能的に似たようなものになるのは興味深いですね。

今後の予想

Ivy が開発を停滞させていたのは、単一の DSL から Deterministic にコンパイルするのが (Bitcoin Script のような単純な言語でさえ) 以外と難しいということがわかったためでした。Detereministic なコンパイルはマリアビリティを避けるのに重要ですが、同時にできる限り小さなスクリプトにコンパイルしたいので、今後はその最適化が課題であると思われます。

Ethereum 上のスマートコントラクト言語である Solidity の方は、 Bitcoinとは逆に自由度が高すぎて危険なコントラクトが書けてしまうという批判があったため、スマートコントラクト言語は案外同じような形式へと収斂していくかもしれませんね。

お知らせ
■ブロックチェーンエンジニア集中講座開講中!
HashHubではブロックチェーンエンジニアを育成するための短期集中講座を開講しています。お申込み、詳細は下記のページをご覧ください。
ブロックチェーンエンジニア集中講座:https://www.blockchain-edu.jp/
■フレセッツ株式会社では仮想通貨の事業者向け BtoB ウォレットの開発をしていただけるエンジニアを募集しています!詳しくはこちら→https://fressets.com/career/
■HashHubでは入居者募集中です!
HashHubは、ブロックチェーン業界で働いている人のためのコワーキングスペースを運営しています。ご利用をご検討の方は、下記のWEBサイトからお問い合わせください。また、最新情報はTwitterで発信中です。
HashHub:https://hashhub.tokyo/
Twitter:https://twitter.com/HashHub_Tokyo