スマートコントラクトの形式的検証と AI 支援監査
スマートコントラクト監査における形式的検証
形式的検証とは、数学的および論理ベースの技術を用いて、スマートコントラクトの正確性とセキュリティを証明することを指します。実際には、これにはプロパティベースのファズテストやシンボリック実行から、厳密な定理証明やモデル検査まで、さまざまな方法論が含まれます。その目的は、コントラクトが仕様を満たし、考えられるすべての入力と状態において悪用可能なバグを含まないことを保証することです。DeFi プロトコルには数十億ドルがロックされているという高いリスクを考慮すると、形式的手法はイーサリアムやその他のブロックチェーンプラットフォームにとってますます重要になっています。
従来のアプローチ: イーサリアムにおける初期の形式的手法には、Oyente や Mythril のようなシンボリック実行ツールや、Slither や Securify のような静的アナライザーが含まれていました。シンボリック実行は、シンボリックな入力を用いてプログラムのパスを探索し、問題 (例: リエントラシー、整数オーバーフロー) を検出します。一方、静的分析はルールベースのパターンマッチングを使用します。これらのツールは成功を収めてきましたが、限界もありました。例えば、Oyente は単純なコントラクトでさえ多くの誤報を出し、Slither のパターンベースの検出器はいくつかの偽陽性を生み出す可能性がありました。さらに、2023 年の研究では、現在のツールでは悪用可能なコントラクトのバグの 80% 以上 (特に複雑な「ビジネスロジック」のバグ) が見逃されていることが判明し、より堅牢な検証技術の必要性が浮き彫りになりました。
完全検証の可能性と課題: 理論上、形式的検証はすべての状態に対して不変条件を網羅的にチェックすることで、バグの不在を証明できます。Certora Prover や Ethereum Foundation の KEVM フレームワークのようなツールは、形式的仕様に対してスマートコントラクトを数学的に検証することを目指しています。例えば、Certora の「自動化された数学的監査人」は、仕様言語 (CVL) を使用して、ユーザー定義のルールを証明または反証します。しかし実際には、現実世界のコントラクトでプロパティを完全に証明することは、しばしば達成不可能であるか、非常に手間がかかります。検証のためにコードを単純化された形式に書き直す必要があったり、カスタム仕様を作成する必要があったり、ループや複雑な算術には手動で境界や抽象化が必要だったり、SMT ソルバーが複雑なロジックで頻繁にタイムアウトしたりします。Trail of Bits のエンジニアが指摘したように、「バグがないことを証明することは、通常、些細でないコードベースでは達成不可能です」。そして、それを達成するには、多くの場合、ユーザーの多大な介入と専門知識が必要です。このため、形式的検証ツールは伝統的に、コントラクト全体をエンドツーエンドで検証するのではなく、重要なコードの一部 (例: トークンの不変条件やコンセンサスアルゴリズムの検証) に限定的に使用されてきました。
Foundry のファズテストと不変条件テスト
近年、完全な形式的証明に代わる実用的な代替手段として、プロパティベースのテストが登場しました。イーサリアムの人気開発フレームワークである Foundry は、ファズテストと不変条件テストを組み込みでサポートしています。これらの技術はテストカバレッジを大幅に向上させ、軽量な形式的検証と見なすことができます。Foundry のファズテストは、指定されたプロパティに違反しようと多数の入力を自動的に生成し、不変条件テストはこれを状態変化を伴う一連の操作に拡張します。
-
ファズテスト: 特定の入力に対する単体テストを作成する代わりに、開発者は任意の入力に対して成立すべきプロパティや不変条件を 指定します。その後、Foundry は何百、何千ものランダムな入力を生成して関数をテストし、プロパティが常に成立することを確認します。これにより、開発者が手動でテストしようと考えつかないようなエッジケースを捉えることができます。例えば、ファズテストでは、関数の戻り値が常に非負であることや、入力に関わらず特定の事後条件が真であることを表明 (assert) するかもしれません。Foundry のエンジンは、関数のシグネチャを分析し、エッジケースの値 (0, max uint など) を導入することで、プロパティを破る可能性のあるコーナーケースを突くインテリジェントなヒューリスティクスを使用します。アサーションが失敗した場合、Foundry はプロパティに違反する反例入力を報告します。
-
不変条件テスト: Foundry の不変条件テスト (別名ステートフルファジング) はさらに進んで、複数の関数呼び出しと状態遷移を連続して実行します。開発者は、コントラクトのライフタイムを通じて真であるべき不変条件関数 (例: 総資産 = ユーザー残高の合計) を記述します。Foundry はその後、ランダムな呼び出しシーケンス (ランダムな入力付き) を生成して多くの可能な使用シナリオをシミュレートし、不変条件が真であり続けることを定期的にチェックします。これにより、特定の操作シーケンスの後にのみ現れる複雑なバグを発見できます。本質的に、不変条件テストはコントラクトの状態空間をより徹底的に探索し、有効なトランザクションのいかなるシーケンスも、述べられたプロパティに違反できないことを保証します。
Foundry が重要な理由: Foundry はこれらの高度なテスト技術をアクセスしやすくしました。ファジングと不変条件の機能は開発者のワークフローにネイティブであり、特別なハーネスや外部ツールは不要で、テストは単体テストと並行して Solidity で記述されます。Rust ベースのエンジンのおかげで、Foundry は何千ものテストを迅速に (並列化して) 実行し、不変条件違反に対する詳細な失敗トレースを提供できます。開発者からは、Foundry のファザーは使いやすく高性能であり、わずかな設定 (例: 反復回数の設定や入力を制約するための仮定の追加) しか必要ないと報告されています。Foundry のドキュメントにある簡単な例は、divide(a,b)
関数のファズテストで、vm.assume(b != 0)
を使用して自明な無効入力を避け、result * b <= a
のような数学的な事後条件を表明します。このようなテストを何千ものランダムな (a,b)
ペアで実行することで、Foundry は手動の推論では見つけるのが難しいエッジケース (オーバーフローの境界など) を迅速に発見するかもしれません。
比較: Foundry のアプローチは、コミュニティにおける先行研究に基づいています。Trail of Bits の Echidna ファザーは、イーサリアム向けの初期のプロパティベースのテストツールでした。Echidna も同様に、ブール値を返す Solidity 関数として表現された不変条件の違反を見つけるためにランダムなトランザクションを生成します。これは「インテリジェントな」入力生成 (カバレッジガイド付きファジングを組み込む) で知られており、多くのバグを発見するために使用されてきました。実際、セキュリティ研究者は Echidna のエンジンが非常に効果的であると指摘しています – 「Trail of Bits の Echidna は、そのインテリジェントな乱数選択により、最高のファザーです」 – ただし、Foundry の統合されたワークフローは、開発者にとってテストの記述をよりシンプルにします。実際には、Foundry のファズテストは、従来の単体テストを補完するものとして、安全な Solidity 開発のための新しい**「最低限の基準」**と見なされることがよくあります。これは (ランダム化されており網羅的ではないため) バグの不在を証明することはできませんが、広範な入力と状態の組み合わせをカバーすることで、信頼性を大幅に向上させます。
ファジングを超えて: 形式的証明と高度なツール
ファジングと不変条件は多くの問題を捉えますが、より強力な形式的手法が使用されるケースもあります。モデル検査と定理証明は、望ましいプロパティを形式論理で指定し、自動化された証明器を使用してコントラクトコードに対してそれらをチェックすることを含みます。Certora Prover (最近オープンソース化) は、このカテゴリの著名なツールです。これにより、開発者はドメイン固有言語 (CVL) でルールを記述し、コントラクトがそれらのルールに違反していないかを自動的 にチェックできます。Certora は、MakerDAO や Compound のようなプロトコルで重要な不変条件を検証するために使用されてきました。例えば、MakerDAO の「DAI 債務不変条件」バグ (4 年間気づかれなかった微妙な会計上の不整合) を特定しました。特筆すべきは、Certora のエンジンが現在複数のプラットフォーム (EVM, Solana の VM, eWASM) をサポートしており、2025 年にオープンソース化することで、イーサリアム、Solana、Stellar で産業グレードの形式的検証を無料で利用可能にしたことです。この動きは、形式的証明が資金力のあるチームだけの贅沢であってはならないという認識を示しています。
その他の形式的ツールには、ランタイム検証アプローチ (例: イーサリアムの KEVM セマンティクス、または Move ベースのチェーン用の Move Prover) があります。特に Move Prover は、Move 言語 (Aptos および Sui ブロックチェーンで使用) に組み込まれています。これにより、コードと並行して形式的仕様を記述でき、リンターや型チェッカーと同様のユーザーエクスペリエンスで特定のプロパティを自動的に証明できます。この緊密な統合により、これらのプラットフォームの開発者が開発の一部として形式的検証を使用する際の障壁が低くなります。
まとめ: 今日のスマートコントラクト監査は、これらの方法論を融合させています。ファジングと不変条件テスト (Foundry と Echidna が代表例) は、使いやすさと一般的なバグの捕捉における有効性から広く採用されています。シンボリック実行と静的アナライザーは、既知の脆弱性パターンを迅速にスキャンするために依然 として役立っています (Slither のようなツールはしばしば CI パイプラインに統合されます)。一方、形式的検証ツールは成熟し、チェーンを越えて拡大していますが、その複雑さから、通常は特定の重要なプロパティや専門の監査会社によって使用されます。実際には、多くの監査はこれらのアプローチを組み合わせています。例えば、ファザーを使用してランタイムエラーを見つけ、静的ツールで明らかな間違いを指摘し、形式的仕様チェックで「トークン残高が総供給量を超えない」といった主要な不変条件を確認します。
大規模言語モデルによる AI 支援監査
OpenAI の GPT-3/4 (ChatGPT) や Codex のような大規模言語モデル (LLM) の登場は、スマートコントラクト分析に新しいパラダイムをもたらしました。これらのモデルは、膨大な量のコードと自然言語でトレーニングされており、プログラムの振る舞いについて推論し、コードを説明し、パターン認識と「常識」的な知識によって特定の脆弱性を検出することさえできます。問題は、AI がスマートコントラクト監査を補強、あるいは自動化できるかということです。