編集者注: この記事は以下から引用しました 編集者注: この記事は以下から引用しました(ID:secbitlabs)アンビーラボラトリーズ
多数のゼロ知識証明プロジェクトで特定の zkSNARKs コントラクト ライブラリが誤って使用されたため、「入力エイリアス」の脆弱性が導入され、証明書の偽造、二重支出、リプレイなどの攻撃、および攻撃コストにつながる可能性があります。極めて低いです。イーサリアム コミュニティの多くのオープンソース プロジェクトが影響を受けます。これには、最も一般的に使用されている 3 つの zkSNARK ゼロ知識開発ライブラリ snarkjs、ethsnarks、および ZoKrates のほか、最近人気のある 3 つの通貨混合 (匿名送金) アプリケーション hopper、Heiswap、および Miximus が含まれます。これは、Solidity言語の父であるクリスが2年前に投稿したコードによって引き起こされた殺人事件です。
副題
二重支出の脆弱性: 初期エクスポージャー
セマフォは、有名な開発者 barryWhiteHat の以前のコイン混合プロジェクトから発展した、ゼロ知識証明技術を使用した匿名セマフォ システムです。
ロシアの開発者 poma は、このプロジェクトには二重支出の脆弱性がある可能性があると最初に指摘しました [1]。
問題は 83 行目のコード [2] にあります。注意深く見てください。
この関数では、呼び出し元が契約からお金を引き出すことができるというゼロ知識証明を構築する必要があります。 「二重支払い」の発生を防ぐために、この関数は「破棄リスト」も読み取り、証明書の指定された要素がマークされているかどうかを確認します。証明書が放棄リストにある場合、契約では検証が失敗したと判断され、呼び出し元はお金を引き出すことができません。開発者は、この方法により、同じ証明書を営利目的で繰り返し送信することができなくなり、これにより二重支出やリプレイ攻撃を効果的に防止できると考えています。
この問題は 2017 年にまで遡ることができます。Solidity 言語の発明者である Christian Reitwiessner は、zkSNARK のコントラクト暗号化実装の例を提供しました [3]。それ以来、イーサリアム上で zkSNARKs テクノロジーを使用するほぼすべてのコントラクトがこの実装に従っています。そのため、以下のようなプロセスによる攻撃を受ける可能性があります。
副題
通貨混合アプリケーション: このセキュリティ問題で最も大きな打撃を受けた領域
イーサリアムにおけるゼロ知識証明技術の最も初期かつ最も広く普及したアプリケーション シナリオは、通貨混合契約、または匿名送金とプライベート トランザクションです。イーサリアム自体が匿名取引をサポートしていないことや、プライバシー保護を求めるコミュニティの声がますます強くなっていることから、多くの人気プロジェクトが登場している。ここでは、混合通貨契約の適用シナリオを例として、ゼロ知識プロジェクトに対する「入力仮名」の脆弱性のセキュリティ脅威を紹介します。
契約または匿名送金を混在させるには、次の 2 つの主要なポイントが含まれます。
1. お金があることを証明する
2. お金が使われていないことを証明する
理解を容易にするために、プロセスを簡単に説明します。
1. A はまとまったお金を使います。
2. A は、そのお金を所有していることを証明する必要があります。 A は、ハッシュのプリイメージ (HashA) を知っていることを証明するために zkproof を提示し、このハッシュはルートでマークされたツリーのリーフ上にあり、このプリイメージの別のハッシュが HashB であることを証明します。このうち、HashA は証人、HashB は公述人です。 A は HashA を公開する必要がないため、匿名です。
3. コントラクトは zkproof を検証し、HashB が破棄リストに含まれているかどうかを確認します。そうでない場合は、お金が使用されておらず、使用できることを意味します(この A の呼び出しは許可されます)。
4. 使用できる場合、コントラクトは HashB を破棄リストに追加する必要があります。これは、HashB で表されるお金が使用済みであり、再度使用できないことを示します。
多くの zkSNARKs コントラクト、特に混合通貨コントラクトの中心となるロジックは 82 行目と 83 行目に似ているため、それらはすべて同じセキュリティ問題を抱えており、「入力仮名」の脆弱性を悪用して攻撃される可能性があります。
副題
脆弱性分析: 匿名で 5 倍の金額を費やすには?
上記の verifyProof(a, b, c, input) 関数の機能は、入力値に従って楕円曲線上の計算と検証を実行することであり、コアは scalar_mul() という名前の関数を使用して楕円曲線上のスカラー乗算を実現します[4]。
イーサリアムには、楕円曲線上で暗号操作を実行し、チェーン上の zkSNARK 検証のガス消費を削減するために、複数のプリコンパイルされたコントラクトが組み込まれていることがわかっています。関数 scalar_mul() の実装は、イーサリアムのプリコンパイル済み No. 7 コントラクトを呼び出し、EIP 196 [5] に従って楕円曲線 alt_bn128 上のスカラー乗算を実現します。以下の図は、イエロー ペーパーでのこの操作の定義を示しています。この操作は、多くの場合 ECMUL または ecc_mul と呼ばれています。
暗号学では、楕円曲線の {x, y} の値領域は mod p に基づく有限体であり、この有限体は Zp または Fp と呼ばれます。つまり、楕円曲線上の点 {x,y} です。ここで、x,y は Fp の値です。楕円曲線上のいくつかの点はより大きな循環グループを形成し、これらの点の数はグループの次数と呼ばれ、q で示されます。この巡回グループでは楕円曲線に基づく暗号化が行われる。この巡回群の次数 (q) が素数の場合、暗号化は有限体 mod q で実行でき、Fq と表されます。
一般に、より大きな巡回グループが暗号化計算の基礎として選択されます。巡回グループでは、生成元 G として非無限大点をランダムに選択し (通常、このグループの次数 q は大きな素数であるため、ゼロ以外の点はすべて同等です)、他のすべての点は G+ G+ を通過できます。 ..生成されました。このグループの要素の数は q です。つまり、合計 q 個の点があり、0,1,2,3,....q-1 を使用して各点に番号を付けることができます。ここでの 0 番目の点は無限遠点であり、点 1 は先ほど述べた G であり、基点とも呼ばれます。ポイント 2 は G+G、ポイント 3 は G+G+G です。
したがって、点を表現したい場合には 2 つの方法があります。 1 つ目は、この点の座標 {x,y} を与えることです。ここで、x,y は Fp に属します。 2 番目の方法は、n*G の形式で与える方法ですが、G は公開されているため、n を与えるだけで済みます。 n は Fq に属します。
scalar_mul(G1Point point, uint s) 関数シグネチャを見て、point をジェネレーターとして使用し、point+point+.....+point を計算し、合計 n 点を追加します。これは、循環グループ内の点を表すために上記の 2 番目の方法を使用することに属します。
Solidity スマート コントラクトの実装では、Fq をエンコードするために uint256 型を使用する必要がありますが、uint256 型の最大値が q の値より大きい場合、このような状況が発生します。uint256 内の複数の数値は次のようになります。の mod 演算値の後の同じ Fq。たとえば、s と s + q は同じ点、つまり s 番目の点を表します。これは、点 q が巡回群の点 0 と実際には等価であるためです (各点は 0、1、2、3、... q-1 に対応します)。同様に、s + 2q などはすべて点 s に対応します。同じ Fq の値に対応する複数の大きな整数が入力される現象を、「入力仮名」と呼びます。つまり、これらの数値は互いに仮名です。
イーサリアム 7 コントラクトによって実装された楕円曲線は、y^2 = ax^3+bx+c です。 p、qはそれぞれ以下のとおりです。
ここでのq値は上記のグループの次数です。次に、uint256 型の範囲には、合計 uint256_max / q が存在します。これは、同じ点を表す整数が最大 5 つあることを意味します (5 つの「入力エイリアス」)。
したがって、ユーザーが取り消しのためにゼロ知識証明を契約に提示すると、契約は input[1] (つまり、特定の s) を無効化リストに追加します。ユーザー (または他の攻撃者) は、別の 4 つの値を使用して証明書を再度送信することもできます。これら4つの値はこれまで「放棄リスト」に含まれていなかったため、「偽造」証明はスムーズに検証を通過でき、5つの「入力仮名」を使用して5回の金額を費やすことができ、攻撃コストは非常に低いです!
副題
さらに多くの影響を受けるプロジェクト
その中でも、snarkjs、ethsnarks、ZoKrates など、いくつかの有名な zkSNARKs ライブラリまたはフレームワーク プロジェクトが最も大きな影響を与えています。多くのアプリケーション プロジェクトは、コードを直接引用または参照して開発するため、セキュリティ リスクが回避されます。その結果、前述の 3 つの項目はすぐにセキュリティ修正で更新されました。さらに、Hopper、Heiswap、Miximus など、zkSNARKs テクノロジーを使用した多くの有名な通貨混合プロジェクトも、すぐに同期修復を実行しました。これらのプロジェクトはコミュニティで非常に人気があり、その中でも Heiswap は「Vitalik のお気に入りプロジェクト」と呼ばれています。
副題
「入力仮名」の脆弱性に対する解決策
幸いなことに、修正は簡単です。必要なのは、検証関数に入力パラメータのサイズのチェックを追加して、入力値が上記の q 値よりも小さくなるように強制することだけです。つまり、「仮名を入力する」ことは固く禁じられており、同じ点を表すために複数の数字を使用することは禁止されています。
副題
露呈した根深い問題は熟考する価値がある
この「入力仮名」によって引き起こされるセキュリティの抜け穴は、コミュニティによる真剣な反省に値します。もう一度全体のストーリーを振り返ってみましょう。 2017 年、Christian は独自の zkSNARKs 契約計算の実装を Gist Web サイトに投稿しました。コンピューティング ライブラリとして、その実装にはセキュリティ上の問題はなく、暗号化の常識に違反せず、契約上の証明検証作業も完全に完了していると考えられます。実際、Solidity 言語の発明者である Christian は、ここで低レベルの間違いを犯すことはありません。 2 年後の今日、このコードはセキュリティ上の大きな嵐を引き起こしています。 2 年以上にわたり、数え切れないほどの同僚や専門家が、わずか 200 行を超えるこのコードを見たり使用したりしましたが、何の問題も見つかりませんでした。
核心的な問題はどこにあるのでしょうか?基礎となるライブラリの実装者とライブラリのユーザーの間でプログラム インターフェイスの理解にずれがある可能性があります。つまり、基盤となるライブラリの実装者は、アプリケーション開発者の不正使用に対する配慮が欠けており、上位のアプリケーション開発者は、基盤となる実装原理や使用上の注意事項を深く理解しておらず、誤ったセキュリティの前提を置いているのです。
「Input Pseudonym」の脆弱性は、以前に頻繁に公開された「Integer Overflow」の脆弱性を思い出さずにはいられません。この 2 つは非常に多くの類似点があります: どちらも多数の開発者の間違った仮定に由来しています; どちらも Solidity の uint256 型に関連しています; どちらも広範囲に影響を及ぼします; 隠されたチュートリアル コードやライブラリ コントラクトも多数ありますインターネット上で流通しています。しかし、「入力仮名」の脆弱性は明らかに検出が難しく、遅延が長く、より多くの背景知識 (複雑な楕円曲線や暗号理論を含む) が必要であることは明らかです。 SECBIT Lab は、zkSNARK、ゼロ知識証明アプリケーション、およびプライバシー技術の台頭により、より多くの新しいアプリケーションがコミュニティに登場し、より多くの隠れたセキュリティ脅威がさらに露出される可能性があると考えています。この新しいテクノロジーの波の中で、コミュニティが過去の痛ましい教訓を十分に吸収し、セキュリティ問題に注意を払うことができることを願っています。
参考文献
