./research / verifiable-audit-layer
AI のための検証可能な監査レイヤー.
モデル推論とエージェント実行のための改ざん検知可能な監査レイヤー。正規化シリアライズ、ドメイン分離ハッシュ、DSSE 署名、実行ごとの Merkle DAG、そしてどの実行も削除されていないことを証明する実行横断の Merkle Mountain Range。各プリミティブは実在の代替手段との直接ベンチマークから選び、生データもコミットしています。本ノートはその設計と、背後にある実験です。
脅威モデル
私たちはストレージを支配し、記録を事後に書き換えられる敵対者を想定します。記録を生成した運用者自身も含みます。目標は、封印された実行へのいかなる編集も検知可能であること、記録が年単位で測られる保持期間にわたり検証可能であり続けること、そして検証がいかなる私的入力も露出しないことです。二つの性質を全体を通じて区別します。単一実行の*完全性(integrity)と、実行集合の網羅性(completeness)*です。実行ごとのレシートは前者を与え、後者については何も語らないため、両者は別々に設計されます。
以下の各選択は同じやり方で行いました。あるプリミティブが最良だとは主張しません。信頼できる代替手段と同じマシン上で比較し、生データをコミットするので、ここのどの数値も一つのコマンドで再現できます。計時はウォームアップを捨てたうえで複数回の最速値であり、不安定な計測が隠されず示されるよう平均と標準偏差を保持します。数値は CPython 3.14 上の単一の AMD64 ホストによるもので、絶対値ではなく比として意味を持ちます。
実験と結果
各マイルストーンは単一の計測ではなく、実在の代替手段との直接テストでした。概観は下記。各詳細は続く各節にあります。
| マイルストーン | 対比対象 | 結果 |
|---|---|---|
| 正規形 | 素朴な JSON、CBOR | JCS、バイト一致、約 3x のコスト |
| ハッシュ | SHA-256、BLAKE3、keccak-256 | keccak ネイティブ 17x、同一バイト |
| ネイティブ核 | pip バックエンド vs Rust | 封印 6x、根はバイト一致 |
| 署名 | ECDSA、BLS、ML-DSA | Ed25519、64 B、決定的 |
| ポスト量子 | ML-DSA 44 / 65 / 87 | 段階的、検証は同等、38x のサイズ |
| 実行ごとの証跡 | 8 種の偽造攻撃、オーバーヘッド | すべて捕捉、約 121 us / イベント |
| 実行横断ログ | 素朴な Merkle 再構築 | MMR、平坦な追記、483x |
正規化シリアライズ
カプセルは、私たちの Python 核、TypeScript クライアント、そして監査者自身のツールで同一バイトにハッシュされねばならず、さもなければ有効な記録が検証に失敗します。私たちは RFC 8785(JSON Canonicalization Scheme)を用います。これは数値の書式、UTF-16 コード単位によるキー順、非有限値の拒否を固定します。素朴なキーソート JSON および CBOR と対比してテストしました。
| 手法 | Python vs Node | コスト |
|---|---|---|
| 素朴なソート JSON | Unicode と数値で乖離 | 基準 |
| RFC 8785 JCS | バイト一致 | シリアライズで約 3x |
| CBOR | バイナリ、読むにはデコーダが要る | コンパクト |
素朴な JSON はランタイム間で Unicode の順序と数値書式が乖離し、言語横断の検証を静かに壊します。JCS は両者でバイト一致し、シリアライズ時間は約 3x で、ハッシュごとに一度支払われ、周囲のハッシュやネットワーク処理に比べれば無視できます。私たちはその実装をちょうど一つだけ保ちます。ネイティブモジュールが独自の JSON シリアライザを持ち込んだとき、それを削除しました。通常の入力では一致し、敵対者が選べる境界事例で乖離する二つ目の正規化器は、無いよりも悪いからです。
ハッシュとネイティブ核
葉は BLAKE3 で、Merkle ノードは keccak-256 でハッシュし、いずれも RFC 6962 のドメイン分離(葉と内部ノードで異なる接頭辞)を用いて、内部ノードを葉として提示する第二原像のクラスを塞ぎます。keccak-256 は SHA3-256 ではありません。両者は置換を共有しますが 1 パディングバイトで異なり、オンチェーン検証器は keccak を話すため、静かな置換はすべての根をオンチェーンで失敗させます。したがってハッシュ層は要求された算法を計算するか例外を投げるかのいずれかで、そっくりさんは決して返さず、各カプセルに算法を記録して、検証器がローカルにインストールされたものから推測するのではなく正確な関数を再現できるようにします。
| プリミティブ、64 B 入力 | スループット | 備考 |
|---|---|---|
| SHA-256(stdlib) | 1.50M ops/s | 基準、常に存在 |
| BLAKE3(pip) | 1.44M ops/s | SHA-256 と同等 |
| keccak-256(pip) | 99k ops/s | 15x 遅い、ボトルネック |
| keccak-256(Rust 核) | 1.69M ops/s | pip より 17x 速い |
keccak には標準ライブラリ実装が無く、それがネイティブモジュールを作る価値を生みました。差はイベントサイズの入力で最大です。そこでの pycryptodome のコストはハッシュではなく呼び出しごとのオブジェクト割り当てであり、まさに監査証跡が最も多くハッシュするサイズだからです。端から端まで、ネイティブ核は 1000 イベントの実行の封印を毎秒 78 から 491 封印へ、約 6x 引き上げます。決定的なのは、アクセラレータの有効化が結果を変えられない点です。同じ実行をこの crate 有り無しで封印するとビット一致の根が得られ、適合スイートが算法作者の公開ベクトルに対し両経路を検査し、CI は単一の安定 ABI(abi3)ホイールを構築し、その唯一の成果物を 3.10 から 3.14 までのすべての Python で検証します。インストールは速度を変え、それ以外は何も変えません。
十年もつ記録のための署名
監査記録の署名は、記録が争える限り持続せねばならず、AI のログ保持義務は今や十年へ向かいます。記録がまだ保持ウィンドウ内にあるうちに方式が破られれば、敵対者はそれを偽造し日付を遡らせられ、アーカイブ全体が一度に崩れます。私たちは Ed25519 を ECDSA、BLS、NIST ポスト量子ファミリー ML-DSA と、スループットとサイズで比較しました。
| 方式 | 検証(ops/s) | 署名サイズ |
|---|---|---|
| ECDSA P-256 | 16,887 | ~72 B |
| ML-DSA-44(ポスト量子) | 10,725 | 2,420 B |
| Ed25519 | 10,375 | 64 B |
| BLS12-381 | 参照実装のみ | 96 B、集約可 |
私たちが持ち込んでいた前提を二つの結果が覆し、両方を記録に残します。Ed25519 は検証が最速ではありません。ECDSA P-256 は最適化されたライブラリアセンブリ上で約 1.6x 速く計測されました。Ed25519 が既定であり続けるのは署名サイズと決定性(RFC 8032)ゆえで、これは署名がまだ検証できるうちに秘密鍵を漏らす ECDSA の nonce 再利用障害を取り除きます。そしてポスト量子署名は検証が遅くありません。ML-DSA-44 は Ed25519 をわずかに上回り、そのコストは署名(約 13x 遅い)とサイズ(約 38x のバイト)にあります。証跡は一度署名され何年も検証されるため、高価な側こそ私たちが最も行わない側です。BLS は数字ではなく要件で却下しました。集約は多くの署名を 96 バイトへ畳みますが、集約体は全か無かで検証され、すべての鍵とメッセージを要し、これは決定の一つの枝を残りを明かさず開示することと両立しません。
肝心な捉え直し。署名は機密ではないので「今収穫し後で復号」は当てはまらず、真の脅威は保持ウィンドウ内の遡及的偽造です。根を公開台帳へアンカーすると、記録がいつ存在したかを署名方式とは独立に証明でき、破られた鍵は記録を誰が封印したかを証明する能力を奪いますが、いつや何をは奪いません。ゆえにアンカーはクリティカルパス上にあり、ML-DSA はその後ろに段階的に置かれ、DSSE エンベロープは算法アジャイルに保ち、算法はカプセルごとに記録します。
実行ごとの監査証跡
各実行は追記専用でハッシュ連鎖されたイベント列(LLM 呼び出し、ツール呼び出し、検索、サブエージェント生成、人間の承認、ガードレール判断)であり、その全体にわたる Merkle 根と、根に対する DSSE 署名を持ちます。入力と出力のハッシュのみを保存し、ペイロードは決して保存しないため、証跡は既定でプライバシーを保ちます。検証器は単に有効か無効かを返すのではなく、破れた保証を名指しします。
| 操作(102 イベントの実行) | コスト | スケーリング |
|---|---|---|
| 1 イベントを記録 | ~121 us | 平坦、1 ステップの 0.01% 未満 |
| 封印、根を構築 | 0.15 ms | イベント数に線形 |
| 検証、全葉を再計算 | 9.2 ms | 線形、封印の約 60x |
記録は、モデルの往復に支配される典型的なエージェントステップの百分の一パーセント未満であり、ゆえにオーバーヘッドはサンプリングの理由にならず、証跡は統計的でなく完全なまま保たれます。検証は封印よりはるかに重く、封印が既にあるハッシュの上に木を構築するだけなのに対し、検証は各葉を内容から再計算するからです。この非対称は監査証跡にとって正しく、記録は一定で検証は稀であり、一括再検証をネイティブ核と並列性が次に効く場所として印づけます。保証を具体化するため、あるデモは封印済み実行を八通りに攻撃し、各々を具体的な理由で拒否します。
| 攻撃 | 拒否理由 |
|---|---|
| モデル出力を書き換える | 葉ハッシュ不一致 |
| イベントを削除または挿入する | イベント数不一致 |
| イベントを並べ替える | 連鎖の破断 |
| 実行を切り詰める | 連鎖先頭の不一致 |
| ハッシュ算法を格下げする | 葉ハッシュ不一致 |
| 誤った鍵で提示する | 署名が検証できない |
実行横断の透明性ログ
有効な実行ごとのカプセルは、実行集合が完全であることを証明できません。都合の悪い実行を落とす運用者は、個別には完璧なカプセルの集まりと、穴の空いた履歴を手にします。私たちはこれを、カプセル根の単一の追記専用ログで塞ぎます。それは包含証明(ある実行がログにある)と一貫性証明(以前のサイズのログが今のログの正確な接頭辞である)を支えます。一貫性は検閲を捕らえます。ある実行を除いて再構築したログは内部的には整合し、生き残った各カプセルも依然として検証されますが、以前に公開された根に対する一貫性検査に失敗し、同じ検査が日付を遡らせた挿入を拒否します。これは改ざん前にコミットされた根に対してのみ機能するため、その根は運用者が改訂できないどこか、たとえば公開アンカーに存在せねばなりません。
私たちは素朴な Merkle 木ではなく Merkle Mountain Range を用います。追記はノードを加えるだけで決して書き換えないため、ログを追記一回限りまたはオブジェクトストレージ上に置け、ログが伸びても古い包含証明を有効に保てるからです。この性質は単に便利なだけでなくほぼ最適です。ePrint 2025/234 は、いかなる簡潔な追記専用コミットメントも超線形個の証人更新を誘発せねばならないことを証明し、近い MMR の変種は本質的にその限界に達します。
| ログサイズ | MMR 構築 | 素朴な再構築 |
|---|---|---|
| 500 | 1.3 ms | 158 ms(120x) |
| 1,000 | 2.6 ms | 618 ms(237x) |
| 2,000 | 5.2 ms | 2,491 ms(483x) |
追記はログが伸びても平坦なまま(100 でも 10,000 エントリでも毎秒約 390k 追記)であるのに対し、素朴な木の再構築は同じ範囲で毎秒 8,176 から 84 根へ落ちます。二次対線形対数の特徴です。ストレージはエントリあたり 2.00 の保存ハッシュに落ち着き、包含証明は 100 から 100,000 エントリの間で 7 から 17 ステップにしか伸びません。私たちが負けるところ。私たちの一貫性証明は O(log^2 n) であり、達成可能な O(log n) ではなく旧ログのピークごとに 1 経路を運びます。100,000 エントリで数キロバイト、そして査読者が読んで検査できる構成のための意図的な取引です。
私たちが越えない限界
ハッシュは改ざんの証拠を与えるのであって、改ざん不能性を与えるのではありません。実行を再構築しその根を再計算する敵対者は自己整合的な記録を生みます。Merkle 根はイベントが根と一致することを証明するのであって、その根が公開されたものであることを証明しないからです。署名がそれを捕らえ、公開アンカーが時刻を証明します。透明性ログは大局において同じ前提に依ります。削除された実行を、削除前にコミットされた根に対してのみ検知します。私たちはこれらの境界を製品とそのデモで明言し、偽造デモが私たちの止めない攻撃を示し続けることをあるテストが表明するので、この正直な事例が静かに消えることはありません。
再現性
ここのどの数値も、一つのコマンドで再走するコミット済みベンチマークから来ています。テスト群、言語横断・実装横断の適合スイート、ネイティブ核の有無で Python 3.10 から 3.14 を走らせる CI マトリクスと並んで。方法論、生の JSON、決定ノート(各選択が負ける次元も含む)はリポジトリにあります。AI を監査可能にするレイヤーは、それ自身が監査可能でなければならないからです。