ERC-7520 ドラフトの詳細説明: zk-SNARK パブリック入力オーバーフロー攻撃保護

著者: Beosin セキュリティ研究専門家 Saya & Bryce

1. ゼロ知識証明とは

Zero-Knowledge Proof (ZKP) は、発言に関する特定の情報を明らかにすることなく、発言の信頼性を証明するために使用できる暗号概念です。ゼロ知識証明では、証明者は特定のステートメントが真であることを検証者に証明できますが、検証者は証明の具体的な詳細を知らずに、そのステートメントを真として受け入れるか拒否するかの 1 つの結果しか得られません。

この概念は、簡単な例で説明できます。 2 人がいて、1 人が証明者、もう 1 人が検証者であるとします。証明者は、パスワード自体を明らかにすることなく、秘密のパスワードを知っていることを検証者に証明したいと考えています。従来の方法では、証明者は検証者にパスワードが何であるかを伝える可能性がありますが、ゼロ知識証明では、証明者は特別なプロトコルを使用して、パスワード自体を明らかにすることなく、パスワードの正しさを知っていることを検証者に証明できます。

現在、一般的なゼロ知識証明システム アルゴリズムには、zk-SNARK、zk-STARK、BulletProof などが含まれます。

2. ブロックチェーンにおける ZKP の適用

ブロックチェーン技術において、ZKP はプライバシーの向上、スケーラビリティとセキュリティの向上など、さまざまな用途に利用できます。ブロックチェーンにおける ZKP の主な用途をいくつか示します。

1 プライバシー保護:

ブロックチェーンはパブリックであるため、誰でもチェーン上のすべてのトランザクションを閲覧できます。ただし、場合によっては、ユーザーが自分の取引情報を非公開にしたい場合もあります。 ZKP を使用すると、ユーザーは総資金を開示することなく、取引に十分な資金があることを証明できます。これにより、ユーザーのプライバシー保護が大幅に強化されます。たとえば、Zcash はゼロ知識証明技術を使用した暗号通貨で、ユーザーは送信者、受信者、取引金額を隠すことができます。

2 計算圧縮とブロックチェーン拡張:

ブロックチェーンのスケーラビリティは、特に大規模なアプリケーションにおいて課題となります。 ZKP を使用すると、ノードの負担が軽減され、システム全体のスケーラビリティが向上します。 ZKP を使用してトランザクションの正当性を検証することにより、ノードは完全なトランザクション履歴を表示する必要がなくなり、ストレージと処理の負担が軽減されます。現在最も広く使用されている ZK Rollup は、イーサリアムおよびその他の領域を改善するために設計されたスケーラビリティ ソリューションです. ブロックチェーンネットワークのスループットと効率。 Rollup テクノロジーと ZKP テクノロジーの利点を組み合わせて、高性能の分散アプリケーション (DApps) 拡張ソリューションを提供します。従来のイーサリアム ネットワークでは、各トランザクションを検証してブロックチェーンに記録する必要があるため、トランザクション処理に遅延とコストがかかります。 ZK Rollup は、多数のトランザクションをバッチ化して 1 つのブロックに圧縮し、ZKP はバッチ トランザクションの正当性を証明してトランザクションの正確性とセキュリティを保証するために使用されます。

3 認証:

ゼロ知識証明を使用すると、機密の個人情報を明らかにすることなくユーザーの身元を確認できます。たとえば、人はゼロ知識証明を使用して、正確な年齢やその他の識別情報を明かさずに、特定の年齢要件を満たしていること、または特定の資格を所有していることをネットワークに証明できます。

4 分散ストレージ:

サーバーは、ユーザーのデータが安全に保管されていること、およびデータの内容が漏洩していないことをユーザーに証明できます。

一般に、**ブロックチェーンのゼロ知識証明は、プライバシー保護、コンピューティングの圧縮と拡張、本人確認、分散ストレージなどに幅広い用途があります。ブロックチェーン技術により多くの機能とオプションを提供し、さまざまな分野でのブロックチェーンの開発と応用を促進します。 **

3. ZKP アプリケーションでの二重支払い攻撃

zk-SNARK (Zero-Knowledge Succinct Non-Interactive Argument of Knowledge) は、実際の情報を明らかにすることなく発言の信頼性を証明できる、ゼロ知識証明に基づくテクノロジーです。プライバシーとセキュリティを保護しながら、非常に短時間で証明の生成と検証ができる、非常に効率的なゼロ知識証明技術であるため、広く使用されています。しかし、用途の拡大に伴い、そのセキュリティに対する注目も高まっています。私たちは、この一般的な脆弱性を少し前に発見しました。verify 関数のパラメーター入力の値の範囲が ZKP プロジェクトで正しく検証されていない場合、攻撃者は検証に合格するために複数の入力を偽造し、二重支払い攻撃を引き起こす可能性があります。この攻撃の影響は非常に広範囲に及び、groth16、plonk などの複数の zk-SNARK アルゴリズムが関与しており、この脆弱性は Solidity や js などの多くの開発言語に存在します。この脆弱性は、ゼロ知識証明プロジェクト Semaphore で poma によって最初に発見され、以下の図に示すように、正常に実装されたトランザクションの 2 つの例が示されています。

この脆弱性の具体的な攻撃原理は、イーサリアムで zk-SNARK 証明を生成して検証したい場合、F_p 算術有限体楕円曲線回路を使用する必要があるというもので、範囲を決定するために p 値が使用されます。楕円曲線有限体の値であるため、回路の入力値の範囲は [0,1,…,p-1] です。曲線が異なれば、p 値も異なります。

EIP-196 で定義された BN254 曲線 (ALT_BN128 曲線とも呼ばれます):

p = 21888242871839275222246405745257275088548364400416034343698204186575808495617

circom2 は 2 つの新しい素数、BLS12-381 曲線を導入します。

p = 52435875175126190479447740508185965837690552500527637822603658699938581184513

そして plink2:

18446744069414584321

YkMsUbmKFjMsTG6nLSo6mdggbsABtGXrkBJb8GxQ.png

その後、Semaphore がこの脆弱性を確認して修正し、ZoKrates や snarkjs などの zk ライブラリも同時に緊急修復を行いましたが、Beosin のセキュリティ研究者らは、現時点ではこの問題に対する統一された解決策がないことを発見しました。たとえば、Semaphore プロトコルはペアリングに制約を書き込みます。ライブラリ。データの有効な範囲は、外部のビジネス ロジックでは明示的に検証されません。circom と Tornado.Cash によって生成されたコントラクト コードは、verify 関数で SNARK_SCALAR_FIELD を明示的に検証します。これは、混乱を招く一貫性のないソリューションです。多くの新しい zk DApp プロジェクト関係者にとってトラブルとセキュリティ リスクが発生するため、この問題を解決するために標準化された方法を使用したいと考えています。

4. ERC-1922 における二重支出攻撃

現在、イーサリアムには、zk-SNARK を検証するための Verify コントラクト標準インターフェイスを導入する zk 関連標準 EIP-1922 があり、その具体的なコードは次のとおりです。

pragma Solidity ^0.5.6;/// @title EIP-XXXX zk-SNARK Verifier Standard/// @dev 参照 /// 注: このインターフェイスの ERC-165 識別子は 0xXXXXXXXX です。/// ⚠️ TODO: インターフェイスを計算するidentifierinterface ERC1922 /* は ERC165 */ { /// @notice 楕円曲線ペア関数 /// を通じて Proof の引数をチェックします。 /// @dev /// Proof がすべてのチェックに合格した場合 (つまり、Proof が /// 有効である場合)、true を返さなければなりません。 /// Proof がすべてのチェックに合格しない場合 (つまり、 /// Proof が無効な場合)、 false を返さなければなりません。 /// @param 証明 zk-SNARK。 /// @param inputs Proof に付随するパブリック入力。 /// @param verifyKeyId Proof が対応する検証キーの一意の識別子 (この検証者が /// コントラクトに既知)。 /// @return result 検証計算の結果。 True /// Proof が有効な場合。それ以外の場合は false。 function verify(uint256[] calldataproof, uint256[] calldata inputs, bytes32 verifyKeyId) external returns (bool result);}

その中で、ゼロ知識証明証明と入力変数タイプは uint256[] です。この変数タイプは、現在 ZKP アルゴリズムで最も一般的に使用されている楕円曲線演算です。ただし、対応するセキュリティ保護がこのインターフェイスには追加されていないため、二重-浪費攻撃も存在し、安全上の大きな危険があります。

5. ERC-7520 ソリューション

上記の問題を踏まえ、Beosin はこの種のセキュリティリスクを防ぐために EIP-7520 を提案しました. 具体的には、イーサリアムエコシステムで zk テクノロジーを使用するすべての DApp プロジェクトは、統一された安全な標準を使用するために、準拠した検証者コントラクトにこのインターフェイスを実装する必要があります。すべての入力に対する有効範囲の検証特定のインターフェイスは次のとおりです。

pragma Solidity ^0.5.6;/// @title EIP-XXXX zk-SNARK public inputs Verifier Standard/// 注: このインターフェイスの ERC-165 識別子は 0xXXXXXXXX です。/// ⚠️ TODO: インターフェイス識別子インターフェイス EIP7520 を計算する /* is ERC165 & ERC1922 */ { /// @notice 入力の引数がスカラー フィールド内にあるかどうかを確認します /// @dev /// 入力が範囲チェックに合格した場合 (つまり、入力が /// 有効である場合)、true を返さなければなりません。 /// 入力が範囲チェックに合格しない場合 (つまり、 /// 入力が無効な場合)、 false を返さなければなりません。 /// @param inputs Proof に付随するパブリック入力。 /// @param p カーブに付随するパブリック入力。関数 verifyPublicInput(uint256[] 入力,uint256 p) 外部戻り値 (bool 結果);}

verifyPublicInput 関数はこの標準の中核であり、関係するパラメータの具体的な意味は次のとおりです。

  • 入力: uint256[] タイプとして定義され、ZKP プロジェクトの検証関数に含まれるパブリック信号パラメーターを表します。
  • p: uint256 型として定義され、この値はアルゴリズムで使用される楕円曲線の p 値に対応します

以下では、プロジェクト関係者に対するリスクを示すために、この攻撃のさまざまな発現を目的として、EIP-7520 インターフェイスを実装する場合と実装しない場合の 2 つの状況を比較します。

1 この eip インターフェイスの verifyPublicInput を呼び出さずに、検証コントラクト コードを直接検証に使用すると仮定します。具体的なコードは次のとおりです。

function verify(uint[] メモリ入力, Proof メモリproof) 内部ビューは (uint) を返します { VerifyingKey メモリ vk = verifyingKey(); require(input.length + 1 == vk.IC.length,"verifier-bad-input"); // 線形結合を計算します vk_xペアリング.G1Pointメモリ vk_x = ペアリング.G1Point(0, 0); for (uint i = 0; i < input.length; i++) vk_x =pairing.addition(vk_x,pairing.scalar_mul(vk.IC[i + 1], input) [i] )); vk_x = ペアリング.加算(vk_x, vk.IC [0] ); if (!Pairing.pairingProd4(Pairing.negate(proof.A),proof.B, vk.alfa1, vk.beta2, vk_x, vk.gamma2,proof.C, vk.delta2 )) return 1; 0 を返します;}

検証に合格したことを証明する元の実験結果のスクリーンショット:

同時に、次の 4 つの証明書は偽造され、検証に合格する可能性があり、二重支払い攻撃を引き起こす可能性があります。

偽造証明の 1 つを使用した検証結果は次のとおりです。

2 この EIP の verifyPublicInput インターフェイスが呼び出された場合、上記の偽造証明は検証に失敗します。コントラクト コードの一部は次のとおりです。残りの詳細については、リファレンス実装を参照してください。

function verifyx(uint[] メモリ入力、プルーフメモリプルーフ、bytes32 verifyKeyId、uint256 p) public returns (uint){ require(verifyPublicInput(inputs,p),"verifier-over-snark-scalar-field"); require(verify(inputs,proof,verificationKeyId),"検証失敗"); true を返す;}関数 verifyPublicInput(uint256[] inputs,uint256 p) 内部ビューは (bool) { for (uint i = 0; i < input.length; i++) { require(input < p,"verifier-gte-snark) を返します-スカラーフィールド"); true を返します;}

実験結果を以下の図に示します。

要約すると、このインターフェイスをパブリック信号値範囲の有効性の検証に使用しない場合、二重支払い攻撃のリスクがある可能性があることがわかります。 **

原文表示
このページには第三者のコンテンツが含まれている場合があり、情報提供のみを目的としております(表明・保証をするものではありません)。Gateによる見解の支持や、金融・専門的な助言とみなされるべきものではありません。詳細については免責事項をご覧ください。
  • 報酬
  • コメント
  • 共有
コメント
0/400
コメントなし
いつでもどこでも暗号資産取引
qrCode
スキャンしてGateアプリをダウンロード
コミュニティ
日本語
  • 简体中文
  • English
  • Tiếng Việt
  • 繁體中文
  • Español
  • Русский
  • Français (Afrique)
  • Português (Portugal)
  • Bahasa Indonesia
  • 日本語
  • بالعربية
  • Українська
  • Português (Brasil)