AI・機械学習
AIと暗号技術の出会い 1: AIがCloudflareのCirclに見出したもの
AI Meets Cryptography 1: What AI Found in Cloudflare's Circl (blog.zksecurity.xyz)
要約
zkSecurityは、AI監査パイプラインをCloudflareの実験的な暗号ライブラリCIRCLに適用し、クリティカルな浮動小数点精度損失からアクセス制御の完全な破綻まで、7つのバグを発見しました。これらのバグはすべて修正済みです。この記事は、AIがオープンソース暗号ライブラリで見つけたバグに関するシリーズの最初の投稿であり、AI監査エージェント「zkao」の開発と、暗号分野におけるLLMの推論能力に関する洞察を共有しています。
全文翻訳
AIと暗号技術の出会い 1: AIがCloudflareのCirclに見出したもの
私たちはAI監査パイプラインをCloudflareのCIRCL実験的暗号ライブラリに向け、クリティカルな浮動小数点64ビット精度損失から属性ベース暗号における完全なアクセス制御の破綻まで、7つの実際のバグを確認しました。これら7つのバグはすべて、アップストリームで修正されました。
これは、私たちのエージェントがオープンソース暗号全体で見つけたバグに関するシリーズの最初の投稿です。zkSecurityでは、AI監査エージェントであるzkaoを構築しています。
目標は、単純に述べることはできますが、実行するのは困難です。AIにコードを継続的に見張らせ、他のAIツールが見つけられるバグがなくなるまで続けます。
私たちは、そのアプローチがなぜ重要なのかをzkao: Security That Compoundsで論じました。
zkaoの構築は反復的なプロセスであり、AIによって検出可能なすべてのバグを見つけることができる自動監査人の作成を最終目標としています。
これには、新しいアイデアやテクニックのブレインストーミング、zkSecurityのセキュリティ研究者の専門知識をzkaoに体系的にエンコードすること、ベンチマークに偏ることなく最新かつ最も深刻な脆弱性を検出することを保証すること、そして重要なことに、何が機能し、何が機能しないか、モデルがどのように進化するかを理解し、AIによるバグ発見の理解を深めるための継続的な実験の実施が含まれます。
これらの実験の中には、製品とは独立して共有する価値のあるものもあります。そして、それがこの投稿シリーズの主題です。
もう一つの動機もあります。これらの実験は、zkaoのベンチマークスイートを構築する方法であり、その過程で、LLMが暗号について実際にどのように推論するかについての洞察が常に現れてきます。
彼らが鋭いところ、盲点、そして前者を増幅し、後者を封じ込める方法です。バグは目に見える成果ですが、私たちが最も気にかけているのは推論パターンです。
数ヶ月前、私たちは選択されたコードベースで実験を開始しました。いくつかのオープンソース暗号プロジェクトを、2つの構成でLLMを使用してスキャンしました。
LLMのみ、シンプルなプロンプト付き。
LLMとスキル付き。スキルはチームの専門家によって維持されていました。
その後、LLMが実際の脆弱性を見つけた重要なプロジェクトについては、zkaoを実行して、それが同じ問題を独自に検出できたかどうかを確認しました。
ほとんどの場合、zkaoはそれらすべてを見つけただけでなく、より複雑でより深刻なものも特定しました。
結果は十分に良かったので、書き出すことにしました。
このシリーズは、高度でポスト量子暗号のライブラリであるCloudflareのCIRCLから開始します。
CIRCLでは、私たちのパイプラインは多くの候補発見を生成し、そのうち7つはここで報告する価値があります。
これら7つはすべて、アップストリームで修正されました。
ほとんどはCloudflareのHackerOneプログラムの下で確認され、バウンティが授与されました。
明確化:AIは最終レポートではなく、候補発見を生成しました。私たちのチームの人間が各問題を検証し、エクスプロイト可能性をチェックし、必要に応じてPOCを最小化し、開示を処理しました。
この人間参加のステップは依然として非常に重要です。なぜなら、AIの候補発見は安価ですが、信頼できるレポートはそうではないからです。
このステップを最小化することは、zkaoが構築されている主な目的の1つであり、まだ進行中ですが、現在のバージョンはすでにこの検証作業の多くを自身で引き受けています。
重要度と修正の概要
詳細に入る前に指摘する価値のあることの1つは、AIが自身の発見に割り当てる重要度はノイズが多いということです。
ここでは、AIが評価した各バグと、修正後にCloudflareが確認した重要度を示します。
また、zkaoの現在のバージョンですべての7つが一貫して再現可能であることを確認しました。
# Bug | AI severity | Cloudflare severity | Fix commit | Found by
---|---|---|---|---
1 | float64 precision loss in TSS/RSA polynomial eval | Critical | Low | f7d2180 | Opus 4.6 + skills
2 | qndleq forgery via prover-controlled SecParam | High | Low | 757dde4 | Opus 4.6 + skills
3 | BLS aggregate missing message distinctness | Medium | High | 9798df7 | Opus 4.6 + skills
4 | DLEQ soundness break via FillBytes sign collision | High | Low | 19848a5 | Opus 4.6 + skills
5 | HPKE PSK validation bypass via bitwise-OR switch | Medium | Medium (Duplicate) | a3b4fa3 | GPT-5.3 + skills
6 | TSS/RSA Lagrange coefficients in int64 | High | Medium | 751e372 | Opus 4.6 + skills
7 | CP-ABE access-control break via AND-share bug | Critical | Critical | def2fd3 | zkao
AIの重要度と確認された重要度の間のギャップ自体が興味深い洞察であり、最後にそれに戻ります。
それでは、7つのバグを1つずつ見ていきましょう。
バグ1:float64における多項式評価
これはCIRCLの閾値RSA実装(tss/rsa)にあります。閾値署名は、シャミアスタイルの秘密分散を使用してn人のプレイヤーに秘密を分割します。Deal()は各プレイヤーのインデックスで秘密多項式を評価します。
係数は、当然ながらbig.Intですが、項 $x^i$ は次のように計算されました。
// tss/rsa/rsa_threshold.go
xi := int64(math.Pow(float64(x), float64(i)))
float64は53ビットのマントッサを持っています。$x^i$ が $2^{53}$(約 $9 imes 10^{15}$)を超えると、結果は整数にキャストされる前にサイレントに丸められます。
例えば、100人のプレイヤーと27の閾値で、$x = 100$、$i = 26$ で評価する場合、$100^{26} = 10^{52}$ を要求しますが、これは $2^{53}$ を36桁も超えます。
$x = 20$、$i = 16$ でさえ既に壊れます。
結果として、多項式は不正確に評価され、プレイヤーに渡されるキーのシェアは間違ったものになります。
パラメータによっては、署名の組み合わせが完全に失敗するか、見た目は正常だが意図したキーを再構築しないシェアが生成されます。
私たちのエージェントはこれをクリティカルとフラグ付けしました。なぜなら、不正確なキーシェアの生成につながり、プロトコルの正確性を損なうからです。
Cloudflareは最終的に、実際には影響を受ける条件が発生する可能性が低いことを理由に、この問題を低重要度と評価しました。
修正は、浮動小数点指数計算を、コード自身のTODOコメントがずっと提案していたHorner法による評価に置き換えることで、すべてbig.Intのままで行われます。コミットf7d2180。
バグ2:プロバー制御のセキュリティパラメータによるDLEQ証明偽造
これはzk/qndleq、CIRCLのDLEQ(離散対数等価性)証明、特に$(\mathbb{Z}/n\mathbb{Z})^*$ の平方のサブグループに関するものです。
DLEQ証明は、2つのペアが同じ離散対数を共有していることを証明します。攻撃者が検証者に偽のステートメントの証明を受け入れさせることができれば、証明システムは壊れます。
この証明のチャレンジはFiat-Shamirスタイルで導出され、そのビット長はSecParamによって制御されます。
問題は、SecParamがProof構造体自体の中に存在することでした。
type Proof struct {
Z, C *big.Int
SecParam uint
}
検証中、コードは証明自身のSecParamを使用してチャレンジを再計算しました。そのフィールドは攻撃者によって制御可能です。
SecParam = 1 に設定すると、チャレンジは単一ビット、値0または1に縮小されます。偽造試行ごとにコインフリップです。
SecParam = 8 に設定すると、総当たり攻撃は約 $2^8 = 256$ 回の試行で済みます。
どちらにしても、健全性は失われます。
これは、検証者によって固定されるべきセキュリティパラメータが、プロバーから提供されたデータから読み取られるという、繰り返されるパターンのクリーンな例です。
修正は、SecParamを証明から削除し、Verifyがそれを明示的な引数として取るようにすることで、検証者がそれを設定するようにします。コミット757dde4。
バグ3:メッセージの区別がないBLS集約検証
これはバッチの中でAIが過小評価した唯一のバグです。エージェントはこれをミディアムとラベル付けしました。
実際には、これは教科書的なローグキー攻撃であり、広く知られているクリティカルクラスの欠陥です。私たちはこれをクリティカルとして報告し、Cloudflareはこれをハイと確認しました。
sign/blsのVerifyAggregateは、BLS BASIC集約モードを実装しています。
このモードは、バッチ内のすべてのメッセージが異なる場合にのみ安全であり、これがローグキー攻撃に対する防御策です。
この関数は集約ペアリング方程式をチェックしましたが、メッセージが異なるかどうかは決してチェックせず、そのクリティカルな要件を呼び出し元に委ねていました。
これがないと、標準的なローグキー攻撃が適用されます。
被害者の公開鍵 $\mathsf{pk}_v$ とメッセージ $m$ を見た敵対者は、被害者の秘密鍵を知ることなく、$(\mathsf{pk}_v, m)$ と $(\mathsf{pk}_a, m)$ に対する集約署名を偽造するために、$\mathsf{pk}_a = g^{\mathsf{sk}_a} - \mathsf{pk}_v$ を登録できます。
CIRCLは