著者: Shew & Noah、GodRealmX
ご存知のとおり、不正防止はブロックチェーン分野で広く使用されている技術的ソリューションです。これはイーサリアム コミュニティから生まれ、Arbitrum や Optimism などの有名なイーサリアム レイヤー 2 に採用されました。 2023年にビットコインエコシステムが台頭した後、ロビン・ライナスはBitVMと呼ばれるソリューションを提案しました。これは詐欺防止を中核的なアイデアとし、Taprootなどの既存のビットコイン技術に基づいてビットコインの第2層またはブリッジに新しいセキュリティモデルを提供します。
BitVM は、論理ゲート回路に基づく初期の BitVM0 から、ZK Fraud Proof と Groth16 検証回路を中核とする後期の BitVM2 まで、いくつかの理論バージョンをリリースしました。BitVM に関連する技術実装パスは絶えず進化し、成熟しており、多くの実務家の注目を集めています。 Bitlayer、Citrea、BOB、Fiamma、GoatNetwork など、誰もが聞いたことのあるプロジェクトはすべて、BitVM を技術基盤の 1 つとして使用し、これに基づいてさまざまなバージョンを実装しています。
BitVM を体系的に説明する情報は市場に比較的少なく、理解するのが難しいため、BitVM に関する知識の普及を目的とした一連の記事を開始しました。 BitVM と不正証明の深い関係を考慮して、この記事では不正証明と ZK 不正証明に焦点を当て、できるだけわかりやすい言葉で説明します。
Optimism の不正防止スキームを材料として使用し、MIPS 仮想マシンとインタラクティブな不正防止に基づくスキーム、および ZK ベースの不正防止の主要なアイデアを分析します。
OutputRoot と StateRoot
Optimism は、よく知られている Optimistic Rollup プロジェクトであり、そのインフラストラクチャはシーケンサー (主なモジュールには op-node、op-geth、op-batcher、op-proposer が含まれます) と Ethereum チェーン上のスマート コントラクトで構成されています。
シーケンサーがトランザクション データのバッチを処理すると、DA データが Ethereum に送信されます。 Optimism ノード クライアントを実行できる場合は、シーケンサーによってアップロードされたデータをローカル コンピューターにダウンロードできます。その後、これらのトランザクションをローカルで実行し、Optimism の現在の状態セット ハッシュ (各アカウントの現在の残高やその他のデータを含むが、これらに限定されない) を計算できます。
シーケンサーが間違った状態セットハッシュをイーサリアムにアップロードした場合、ローカルで計算した状態セットハッシュは異なります。このとき、不正防止システムを通じて疑問を提起することができ、システムは判断結果に基づいてシーケンサーを制限、処罰、または処罰しないことができます。
「状態セット」という用語について言及する場合、EVM ブロックチェーンは多くの場合、ワールド ステート トライと呼ばれる Merkle ツリー スタイルのデータ構造を使用して状態セットを記録します。トランザクションが実行されると、一部のアカウントのステータスが変わり、ワールド ステート トライが変更され、その最終ハッシュも変更されます。 Ethereum は、状態セットの変更を表すために使用される World State Trie StateRoot の最終ハッシュを呼び出します。
下の図は、Ethereum stateRoot の構成を示しています。Ethereum 内のさまざまなアカウントの残高、スマート コントラクト アカウントに関連付けられたコード ハッシュ、およびその他のデータが World State Trie に集約され、これに基づいて stateRoot が計算されていることがわかります。
Optimism のアカウント システムとそのデータ構造は Ethereum とほぼ一致しており、状態セットの変更を反映するために StateRoot フィールドも使用します。 OP シーケンサーは、OutputRoot と呼ばれるキー フィールドを定期的に Ethereum にアップロードし、OutputRoot フィールドは StateRoot と他の 2 つのフィールドによって計算されます。
元の質問に戻りましょう。OP のノード クライアントを実行し、StateRoot と現在の OutputRoot をローカルで計算したときに、計算した結果が OP シーケンサーによってアップロードされた結果と一致しないことがわかった場合は、不正証明を開始できます。では、その具体的なメカニズムは何でしょうか?以下では、MIPS 仮想マシン状態検証とインタラクティブ不正防止についてそれぞれ紹介します。
MIPS 仮想マシンとメモリ Merkle Tree
前述のように、OP シーケンサーによって送信された OutputRoot に問題があることがわかった場合は、「チャレンジ」を開始できます。チャレンジ プロセスでは、チェーン上で一連の対話型アクションを完了する必要があります。対話が完了すると、関連するスマート コントラクトは、OP シーケンサーが間違った OutputRoot をアップロードしたかどうかを判断します。
チェーン上のスマートコントラクトを使用して OutputRoot の正しさを検証する場合、最も簡単な方法は、Ethereum チェーン上に OP ノードクライアントを実装し、OP シーケンサーと同じ入力パラメータを使用して同じプログラムを実行し、計算結果が一貫しているかどうかを確認することです。このスキームは Fault Proof Program と呼ばれ、オフチェーンでの実装は簡単ですが、Ethereum チェーン上で実行するのは非常に困難です。なぜなら、次の 2 つの問題があるからです。
1. Ethereum 上のスマート コントラクトは、不正行為の証明に必要な入力パラメータを自動的に取得できません。
2. Ethereum の各ブロックのガス制限は制限されており、複雑すぎる計算タスクをサポートしていません。チェーン上に OP ノード クライアントを完全に実装することはできません。
最初の問題は、オンチェーンのスマート コントラクトがオフチェーンのデータを読み取ることを許可することに相当し、これはオラクルに似たソリューションを通じて解決できます。 OP は Ethereum チェーン上に PreimageOracle コントラクトを特別に展開しており、不正防止関連のコントラクトは PreimageOracle 内の必要なデータを読み取ることができます。
理論的には、誰でも自由に契約にデータをアップロードできますが、OP の不正防止システムには、データが必要かどうかを識別する方法があります。この記事の核心的なトピックにとって重要ではないため、具体的なプロセスについてはここでは説明しません。
2 番目の質問については、OP 開発チームは Solidity で MIPS 仮想マシンを作成しました。これは、不正防止システムに十分な OP ノード クライアントの一部の機能を実装しています。 MIPSは一般的なCPU命令セットアーキテクチャであり、OPシーケンサーのコードはGolang/Rustなどの高級言語で書かれています。Golang/Rustで書かれたプログラムをMIPSプログラムにコンパイルし、Ethereumチェーン上のMIPS仮想マシンを通じて処理することができます。
OP の開発チームは、Golang を使用して、不正防止に必要な最小限のプログラムを作成しました。これは基本的に、OP ノードでのトランザクションの実行、ブロックの生成、OutputRoot のモジュール機能と一致しています。しかし、この合理化された手順はまだ「完全に実装」されていません。
つまり、各 OP ブロックには多数のトランザクションが含まれます。このトランザクションのバッチを処理すると、OutputRoot が取得されます。どのブロックの高さで OutputRoot が間違っているかはわかっていますが、チェーン上のブロックに含まれるすべてのトランザクションを実行して、対応する OutputRoot が間違っていることを証明するのは非現実的です。
さらに、各トランザクションの実行プロセスには、一連の MIPS オペコードの順序立った処理が含まれます。オンチェーン コントラクトによって実装された MIPS 仮想マシンでは、コンピューティングのオーバーヘッドとガス消費量が大きすぎるため、この一連のオペコードを実行することはできません。
この目的のために、Optimism チームはインタラクティブな不正防止システムを設計しました。その目的は、OP のトランザクション処理フローを大幅に改良することです。 OutputRoot の計算プロセス全体から、どの MIPS オペコードを処理したときに OP シーケンサーの MIPS 仮想マシンでエラーが発生したかがわかります。エラーが判定された場合、シーケンサーによって提供された OutputRoot が無効であると結論付けることができます。
すると、問題が明確になります。トランザクション パッケージング ブロックを処理する OP シーケンサーのプロセスは、膨大な数の MIPS オペコードの整然とした処理に分解できます。各 MIPS オペコードが実行されると、仮想マシンの状態ハッシュが変更され、これらのレコードを Merkle ツリーにまとめることができます。
対話型不正証明プロセスでは、OPシーケンサーがどのMIPSオペコードを実行し、仮想マシンの状態ハッシュに問題があるかを判断する必要があります。次に、そのときのMIPS仮想マシンの状態をチェーン上に再現し、オペコードを実行し、その後の状態ハッシュがシーケンサーが送信した結果と一致することを観察します。チェーン上で実行される MIPS オペコードは 1 つだけなので、複雑さは高くなく、計算プロセスは Ethereum チェーン上で完了できます。ただし、これを行うには、メモリ データなどの MIPS 仮想マシンのステータス情報をチェーンにアップロードする必要があります。
コード実装レベルでは、Ethereum チェーン上の不正防止に関連するスマート コントラクトは、Step という次の関数を通じて最終的な MIPS オペコード実行プロセスを完了します。
上記の関数パラメータの _stateData と _proof は、MIPS 仮想マシンのレジスタ状態、メモリ状態ハッシュなど、単一の MIPS オペコード実行の依存データ項目を表します。概略図は以下のとおりです。
_stateData と _proof を通じてこれらの MIPS 仮想マシンの環境パラメータを入力し、チェーン上で単一の MIPS 命令を実行して、信頼できる結果を得ることができます。チェーン上で得られた信頼できる結果がシーケンサーによって送信された結果と一致しない場合、シーケンサーが悪事を行っていることを意味します。
一般的に、_stateData のハッシュは statehash と呼ばれます。これは、大まかに言えば、MIPS 仮想マシンの状態全体のハッシュとして理解できます。 _stateData のいくつかのフィールドの中で、memRoot は最も独創的な設計です。ご存知のとおり、プログラムは実行中に大量のメモリを占有し、CPU は一部のメモリ アドレス内のデータに対して読み取りおよび書き込みのやり取りを行います。したがって、チェーン上の VM.Step 関数を通じて MIPS オペコードを実行する場合は、MIPS 仮想マシンのメモリ アドレスにデータを提供する必要があります。
OP は 32 ビット MIPS 仮想マシンを使用します。この仮想マシンのメモリには合計 2 の 27 乗のアドレスが含まれており、28 層のバイナリ Merkle ツリーに編成できます。最下層には 2 の 27 乗のリーフがあり、各リーフは仮想マシンのメモリ アドレスにデータを記録します。すべてのリーフのデータが集約された後、計算されたハッシュは memRoot になります。次の図は、MIPS 仮想マシンのメモリ データを記録する Merkle ツリーの構造を示しています。
メモリ アドレス内のコンテンツの一部を提供する必要があります。これは、ステップ関数の _proof フィールドを通じて Ethereum チェーンにアップロードされます。ここでは、ユーザー/シーケンサーによって提供されたデータがメモリ Merkle ツリーに存在し、空から作られたものではないことを証明するために、メモリ Merkle ツリーに基づく Merkle 証明もアップロードする必要があります。
インタラクティブな不正防止
上記では、2 番目の問題を解決し、MIPS オペコードのオンチェーン実行と仮想マシン ステータスの検証を完了しましたが、チャレンジャーとシーケンサーはどのようにして問題となっている MIPS オペコード命令を見つけるのでしょうか。
多くの人がインターネット上でインタラクティブ詐欺の証明についての簡単な説明を読み、その二分法について聞いたことがあると思います。 OP チームは、Fault Dispute Game (FDG) と呼ばれるプロトコルを開発しました。FDG には、チャレンジャーとディフェンダーの 2 つの役割があります。
シーケンサーによってチェーンに送信された OutputRoot に問題があることが判明した場合、FDG ではチャレンジャーとして行動し、シーケンサーはディフェンダーとして行動します。チェーン上で処理する必要がある上記の MIPS オペコードを見つけるために、FDG プロトコルでは、すべての参加者が次の特定の構造を持つ、GameTree と呼ばれる Merkle ツリーをローカルに構築する必要があります。
GameTree は実際には非常に複雑で、階層的にネストされた関係を持ち、第 1 レベルのツリーと第 2 レベルのサブツリーで構成されています。つまり、第 1 レベルのツリーの一番下のリーフ自体にツリーが含まれています。
前述したように、シーケンサーによって生成される各ブロックには OutputRoot が含まれており、GameTree の第 1 レベル ツリーのリーフ ノードは、さまざまなブロックの OutputRoot です。挑戦者と防御者は、OutputRoot で構成される Merkle ツリーで対話して、どのブロックの OutputRoot が議論の余地があるかを判断する必要があります。
紛争中のブロックを特定した後、GameTree の第 2 レベルに進みます。第 2 レベルのツリーも Merkle ツリーであり、最下部のリーフは上で紹介した MIPS 仮想マシンの状態ハッシュです。不正防止シナリオでは、紛争当事者によってローカルに構築された GameTree の一部のリーフ ノードに矛盾が生じ、特定のオペコードを処理した後の仮想マシンの状態ハッシュが異なって表示されます。
その後、両者はチェーン上で複数回やり取りし、最終的に紛争領域を特定し、チェーン上で実行する必要のある単一の MIPS オペコードを決定しました。
この時点で、インタラクティブな不正行為の証明プロセス全体が完了しました。要約すると、インタラクティブな不正証明には 2 つのコアメカニズムが含まれています。
1. FDG はまず、チェーン上で実行する必要がある MIPS オペコードとその時点での VM ステータス情報を特定します。
2. Ethereum チェーンに実装された MIPS 仮想マシンでオペコードを実行し、最終結果を取得します。
ZK 化された不正証明
上記の従来の不正防止の相互作用は非常に複雑で、FDG プロセスで複数回の相互作用が必要であり、その後チェーン上で単一の命令を再生する必要があることがわかります。ただし、このソリューションにはいくつかの困難があります。
1. イーサリアム チェーン上で複数回のやり取りをトリガーする必要があり、数十回のやり取りが必要となり、大量のガス コストが発生します。
2. インタラクティブな不正防止プロセスは長いです。インタラクションが開始されると、Rollup はトランザクションを正常に実行できなくなります。
3. チェーン上に命令を再生するための特定のVMを実装するのは比較的複雑で、開発が非常に困難です。
これらの問題を解決するために、Optimism は ZK Fraud Proof の概念を正式に提案しました。中心となるのは、チャレンジャーがチャレンジを行う際に、チェーン上でリプレイする必要があると考えるトランザクションを指定することです。Rollup シーケンサーは、チャレンジされたトランザクションの ZK 証明を提供し、これは Ethereum 上のスマート コントラクトによって検証されます。検証に合格した場合、トランザクションの処理フローは正しく、Rollup ノードは悪意のある行為を行っていないとみなされます。
上の写真のChallengerがチャレンジャー、DefenderがOPシーケンサーです。通常の状況では、OP シーケンサーは受信したトランザクションに基づいてブロックを生成し、さまざまなブロックの状態コミットメントを Ethereum に送信します。これは、単にブロックのハッシュ値と見なすことができます。挑戦者はブロックハッシュに基づいて挑戦することができます。チャレンジを受け入れた後、Defender はブロックの生成結果にエラーがないことを証明するために ZK 証明を生成します。上の写真の Bonsai は、実際には ZK 証明生成ツールです。
インタラクティブな不正証明と比較して、ZK 不正証明の最大の利点は、複数回のやり取りを 1 回の ZK 証明生成とオンチェーン検証に変更することで、時間とガス コストを大幅に節約できることです。 ZK Rollup と比較すると、ZK Fraud Proof に基づく OP Rollup では、ブロックごとに証明を生成する必要がありません。チャレンジされたときにのみ一時的に ZK 証明を生成するため、Rollup ノードの計算コストも削減されます。
ZKベースの不正防止の考え方は、BitVM2でも採用されています。 Bitlayer、Goat Network、ZKM、Fiama など、BitVM2 を使用するプロジェクトは、Bitcoin スクリプトを通じて ZK Proof 検証プログラムを実装し、チェーンにアップロードする必要があるプログラムのサイズを大幅に簡素化します。スペースの制限により、この記事では詳細には触れません。BitVM2 の実装パスをより深く理解するには、今後の記事をお待ちください。お楽しみに!