Автор: експерти Beosin з дослідження безпеки Saya & Bryce
1. Що таке доказ нульового знання
Підтвердження нульового знання (ZKP) — це криптографічна концепція, яка може бути використана для підтвердження автентичності заяви без розкриття будь-якої конкретної інформації про заяву. У доказі з нульовим знанням перевіряючий може довести верифікатору, що певне твердження є істинним, і верифікатор отримує лише один результат: або приймає твердження як істинне, або відхиляє його, не знаючи конкретних деталей доказу.
Цю концепцію можна пояснити на простому прикладі. Припустимо, що є двоє людей: один перевіряє, а другий верифікує. Той, хто перевіряє, хоче довести перевіряючому, що він знає секретний пароль, не розкриваючи сам пароль. Традиційно перевіряльник може повідомити верифікатору, який пароль, але в доказі з нульовим знанням перевіряльник може використовувати спеціальний протокол, щоб довести верифікатору, що він знає правильність пароля, не розкриваючи сам пароль.
Наразі поширені системні алгоритми з нульовим розпізнаванням включають zk-SNARK, zk-STARK, BulletProof тощо.
№ 2. Застосування ЗКП в блокчейні
У технології блокчейн ZKP має різноманітні застосування, такі як покращення конфіденційності, покращення масштабованості та безпеки тощо. Ось кілька ключових застосувань ZKP в блокчейні:
1 Захист конфіденційності:
Блокчейн є загальнодоступним, тобто кожен може переглядати всі транзакції в ланцюжку. Однак іноді користувачі можуть забажати зберегти інформацію про свою транзакцію конфіденційною. ZKP дозволяє користувачам довести, що вони мають достатньо коштів для торгівлі, не розкриваючи загальну суму своїх коштів. Це значно покращує захист конфіденційності користувачів. Наприклад, Zcash — це криптовалюта, яка використовує технологію підтвердження нульового знання, яка дозволяє користувачам приховувати відправника, одержувача та суму транзакції.
2 Обчислювальне стиснення та розширення блокчейна:
Масштабованість блокчейна є проблемою, особливо у великомасштабних програмах. ZKP можна використовувати для зменшення навантаження на вузли та покращення масштабованості всієї системи. Використовуючи ZKP для перевірки дійсності транзакцій, вузлам не потрібно переглядати повну історію транзакцій, що зменшує навантаження на зберігання та обробку.ZK Rollup, наразі найбільш широко використовуваний, є рішенням масштабованості, призначеним для покращення Ethereum та інших областей Пропускна здатність та ефективність мереж блокчейн. Він поєднує в собі переваги технологій Rollup і ZKP для забезпечення високопродуктивних рішень для розширення децентралізованих програм (DApps). У традиційній мережі Ethereum кожну транзакцію необхідно перевірити та записати в блокчейн, що призводить до затримок і високих витрат на обробку транзакцій. ZK Rollup групує та стискає велику кількість транзакцій в один блок, а ZKP використовується для підтвердження дійсності пакетних транзакцій, щоб забезпечити коректність і безпеку транзакцій.
3 Автентифікація:
Підтвердження нульової інформації можна використовувати для підтвердження особи користувача без розкриття конфіденційної особистої інформації. Наприклад, особа може використовувати докази нульового знання, щоб довести мережі, що вона відповідає певним віковим вимогам або має певний сертифікат, не розкриваючи свій точний вік чи іншу ідентифікаційну інформацію.
4 Децентралізоване сховище:
Сервер може довести користувачам, що їхні дані зберігаються надійно і що вміст даних не витікає.
Загалом, **підтвердження нульового знання блокчейну має широке застосування для захисту конфіденційності, стиснення та розширення обчислень, перевірки ідентичності, децентралізованого зберігання тощо. Він надає більше функцій і опцій для технології блокчейн і сприяє розвитку та застосуванню блокчейну в різних сферах. **
3. Атака подвійного витрачання в додатках ZKP
zk-SNARK (короткий неінтерактивний аргумент знань з нульовим знанням) — це технологія, заснована на доказі з нульовим знанням, яка може довести автентичність твердження, не розкриваючи реальної інформації. Це дуже ефективна технологія нульових знань, яка може генерувати та перевіряти докази за дуже короткий час, захищаючи конфіденційність і безпеку, тому вона широко використовується. Однак із розширенням додатків його безпека привертає все більше уваги. Нещодавно ми виявили його загальну вразливість: якщо діапазон значень параметра, введеного у функцію перевірки, неправильно перевірено в проекті ZKP, зловмисник може підробити кілька вхідних даних, щоб пройти перевірку, викликаючи атаку подвійного витрачання. Вплив цієї атаки дуже широкий, залучаючи кілька алгоритмів zk-SNARK, включаючи: groth16, plonk тощо, і ця вразливість існує в багатьох мовах розробки, таких як solidity та js. Ця вразливість була вперше виявлена компанією poma в проекті з нульовим знанням Semaphore, і було наведено два приклади успішно реалізованих транзакцій, як показано на малюнку нижче:
Конкретний принцип атаки цієї вразливості полягає в тому, що якщо ви хочете згенерувати та перевірити доказ zk-SNARK в Ethereum, вам потрібно використовувати схему еліптичної кривої кінцевого поля F_p-арифметики, де значення p використовується для визначення діапазону скінченного поля еліптичної кривої, тому схема Діапазон вхідних значень [0,1,…,p-1]. Різні криві мають різні значення p:
Крива BN254, визначена в EIP-196 (також відома як крива ALT_BN128):
p = 21888242871839275222246405745257275088548364400416034343698204186575808495617
circom2 представляє два нових простих числа, криві BLS12-381:
p = 52435875175126190479447740508185965837690552500527637822603658699938581184513
і plink2:
18446744069414584321
Пізніше Semaphore підтвердив і виправив уразливість, а бібліотеки zk, такі як ZoKrates і snarkjs, також виконали екстрений ремонт одночасно. Проте дослідники безпеки Beosin виявили, що наразі не існує єдиного рішення цієї проблеми. Наприклад, протокол Semaphore записує обмеження в пару. бібліотека. Дійсний діапазон даних явно не перевіряється в зовнішній бізнес-логіці; код контракту, згенерований circom і Tornado.Cash, явно перевіряє SNARK_SCALAR_FIELD у функції перевірки. Це заплутане та суперечливе рішення. Це може спричинити проблеми та ризики для безпеки для багатьох нових учасників проекту zk DApp, тому ми сподіваємося використати стандартизований спосіб вирішення цієї проблеми.
4. Подвійна атака в ERC-1922
Наразі Ethereum має пов’язаний з zk стандарт EIP-1922, який представляє стандартний інтерфейс Verify contract для перевірки zk-SNARK. Конкретний код виглядає наступним чином:
pragma solidity ^0.5.6;/// @title EIP-XXXX zk-SNARK Verifier Standard/// @dev Див. /// Примітка: ідентифікатор ERC-165 для цього інтерфейсу – 0xXXXXXXXX./// ⚠️ ЗАВДАННЯ: Розрахувати інтерфейс identifierinterface ERC1922 /* це ERC165 */ { /// @notice Перевіряє аргументи Proof за допомогою еліптичної кривої /// функцій поєднання. /// @dev /// ПОВИНЕН повернути істину, якщо Доказ проходить усі перевірки (тобто Доказ є /// дійсним). /// ПОВИНЕН повернути false, якщо доказ не пройшов усі перевірки (тобто якщо /// доказ недійсний). /// @param proof A zk-SNARK. /// @param inputs Публічні входи, які супроводжують Proof. /// @param verificationKeyId Унікальний ідентифікатор (відомий цьому верифікатору /// контракту) для ключа перевірки, якому відповідає Proof. /// @return result Результат обчислення перевірки. Істина /// якщо доказ дійсний; false інакше. функція verify(uint256[] calldata proof, uint256[] calldata inputs, bytes32 verificationKeyId) зовнішні повернення (результат bool);}
Серед них типи змінних для підтвердження з нульовим знанням і вхідних даних — це uint256[]. Цей тип змінної наразі є найпоширенішою операцією еліптичної кривої в алгоритмі ZKP. Однак відповідний захист безпеки не додається до цього інтерфейсу, тому подвійний - також існують атаки витрат Величезна загроза безпеці.
5. Рішення ERC-7520
Виходячи з вищезазначених проблем, Beosin запропонував EIP-7520 для запобігання цьому ризику безпеки. Зокрема, усі проекти DApp, що використовують технологію zk в екосистемі Ethereum, повинні реалізувати цей інтерфейс у сумісному контракті верифікатора для використання уніфікованих і безпечних стандартів. Метод виконує дійсний діапазон перевірка на всіх входах Конкретний інтерфейс виглядає наступним чином:
pragma solidity ^0.5.6;/// @title EIP-XXXX zk-SNARK public inputs Verifier Standard/// Примітка: ідентифікатор ERC-165 для цього інтерфейсу – 0xXXXXXXXX./// ⚠️ ЗАВДАННЯ: обчислити ідентифікатор інтерфейсуinterface EIP7520 /* is ERC165 & ERC1922 */ { /// @notice Перевіряє аргументи вхідних даних у межах скалярного поля /// @dev /// ПОВИННО повертати істину, якщо вхідні дані проходять перевірку діапазону (тобто вхідні дані є /// дійсними). /// ПОВИНЕН повернути false, якщо вхідні дані не проходять перевірку діапазону (тобто якщо /// вхідні дані недійсні). /// @param inputs Публічні входи, які супроводжують Proof. /// @param p Відкритий вхід, який супроводжує криву. функція verifyPublicInput(uint256[] inputs,uint256 p) зовнішні повернення (результат bool);}
Функція verifyPublicInput є ядром цього стандарту. Конкретні значення залучених параметрів такі:
входи: визначено як тип uint256[], що представляє параметри публічного сигналу, залучені до функції перевірки в проекті ZKP
p: визначене як тип uint256, це значення відповідає значенню p еліптичної кривої, що використовується в алгоритмі
Нижче буде порівняно дві ситуації впровадження та нереалізації інтерфейсу EIP-7520, спрямовані на різні прояви цієї атаки, щоб вказати на ризики для сторін проекту:
1 Припустімо, що ми безпосередньо використовуємо код контракту verify для перевірки без виклику verifyPublicInput цього інтерфейсу eip. Конкретний код такий:
функція verify(uint[] введення пам’яті, Proof memory proof) внутрішній вигляд повертає (uint) { VerifyingKey memory vk = verifyingKey(); require(input.length + 1 == vk.IC.length,"verifier-bad-input"); // Обчислення лінійної комбінації vk_x Pairing.G1Point memory vk_x = Pairing.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 = Pairing.addition(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 )) повертає 1; повернути 0;}
Скріншот оригінальних експериментальних результатів, які доводять, що перевірка пройшла:
У той же час наступні чотири сертифікати можуть бути підробленими та також можуть пройти перевірку, спричиняючи атаку подвійного витрачання:
Використовуючи одне з підроблених доказів, результати перевірки наведені нижче:
2 Якщо в цьому eip буде викликано інтерфейс verifyPublicInput, підроблене підтвердження вище не вдасться перевірити. Частина коду контракту така. Щоб отримати решту деталей, зверніться до еталонної реалізації:
функція verifyx(uint[] входи пам’яті, перевірка пам’яті доказ, bytes32 verificationKeyId,uint256 p) публічні повернення (uint){ require(verifyPublicInput(inputs,p),"verifier-over-snark-scalar-field"); require(verify(inputs,proof,verificationKeyId),"перевірити не вдалося"); return true;}function verifyPublicInput(uint256[] inputs,uint256 p) внутрішній вигляд повертає (bool) { for (uint i = 0; i < input.length; i++) { require(input < p,"verifier-gte-snark -скалярне поле"); } повертає істину;}
Результати експерименту показані на малюнку нижче:
Підводячи підсумок, можна виявити, що якщо цей інтерфейс не використовуватиметься для перевірки дійсності загальнодоступного діапазону значень сигналу, може виникнути ризик атак подвійного витрачання. **
Переглянути оригінал
Ця сторінка може містити контент третіх осіб, який надається виключно в інформаційних цілях (не в якості запевнень/гарантій) і не повинен розглядатися як схвалення його поглядів компанією Gate, а також як фінансова або професійна консультація. Див. Застереження для отримання детальної інформації.
Детальне пояснення чернетки ERC-7520: zk-SNARK публічний захист від атак переповнення
Автор: експерти Beosin з дослідження безпеки Saya & Bryce
1. Що таке доказ нульового знання
Підтвердження нульового знання (ZKP) — це криптографічна концепція, яка може бути використана для підтвердження автентичності заяви без розкриття будь-якої конкретної інформації про заяву. У доказі з нульовим знанням перевіряючий може довести верифікатору, що певне твердження є істинним, і верифікатор отримує лише один результат: або приймає твердження як істинне, або відхиляє його, не знаючи конкретних деталей доказу.
Цю концепцію можна пояснити на простому прикладі. Припустимо, що є двоє людей: один перевіряє, а другий верифікує. Той, хто перевіряє, хоче довести перевіряючому, що він знає секретний пароль, не розкриваючи сам пароль. Традиційно перевіряльник може повідомити верифікатору, який пароль, але в доказі з нульовим знанням перевіряльник може використовувати спеціальний протокол, щоб довести верифікатору, що він знає правильність пароля, не розкриваючи сам пароль.
Наразі поширені системні алгоритми з нульовим розпізнаванням включають zk-SNARK, zk-STARK, BulletProof тощо.
№ 2. Застосування ЗКП в блокчейні
У технології блокчейн ZKP має різноманітні застосування, такі як покращення конфіденційності, покращення масштабованості та безпеки тощо. Ось кілька ключових застосувань ZKP в блокчейні:
1 Захист конфіденційності:
Блокчейн є загальнодоступним, тобто кожен може переглядати всі транзакції в ланцюжку. Однак іноді користувачі можуть забажати зберегти інформацію про свою транзакцію конфіденційною. ZKP дозволяє користувачам довести, що вони мають достатньо коштів для торгівлі, не розкриваючи загальну суму своїх коштів. Це значно покращує захист конфіденційності користувачів. Наприклад, Zcash — це криптовалюта, яка використовує технологію підтвердження нульового знання, яка дозволяє користувачам приховувати відправника, одержувача та суму транзакції.
2 Обчислювальне стиснення та розширення блокчейна:
Масштабованість блокчейна є проблемою, особливо у великомасштабних програмах. ZKP можна використовувати для зменшення навантаження на вузли та покращення масштабованості всієї системи. Використовуючи ZKP для перевірки дійсності транзакцій, вузлам не потрібно переглядати повну історію транзакцій, що зменшує навантаження на зберігання та обробку.ZK Rollup, наразі найбільш широко використовуваний, є рішенням масштабованості, призначеним для покращення Ethereum та інших областей Пропускна здатність та ефективність мереж блокчейн. Він поєднує в собі переваги технологій Rollup і ZKP для забезпечення високопродуктивних рішень для розширення децентралізованих програм (DApps). У традиційній мережі Ethereum кожну транзакцію необхідно перевірити та записати в блокчейн, що призводить до затримок і високих витрат на обробку транзакцій. ZK Rollup групує та стискає велику кількість транзакцій в один блок, а ZKP використовується для підтвердження дійсності пакетних транзакцій, щоб забезпечити коректність і безпеку транзакцій.
3 Автентифікація:
Підтвердження нульової інформації можна використовувати для підтвердження особи користувача без розкриття конфіденційної особистої інформації. Наприклад, особа може використовувати докази нульового знання, щоб довести мережі, що вона відповідає певним віковим вимогам або має певний сертифікат, не розкриваючи свій точний вік чи іншу ідентифікаційну інформацію.
4 Децентралізоване сховище:
Сервер може довести користувачам, що їхні дані зберігаються надійно і що вміст даних не витікає.
Загалом, **підтвердження нульового знання блокчейну має широке застосування для захисту конфіденційності, стиснення та розширення обчислень, перевірки ідентичності, децентралізованого зберігання тощо. Він надає більше функцій і опцій для технології блокчейн і сприяє розвитку та застосуванню блокчейну в різних сферах. **
3. Атака подвійного витрачання в додатках ZKP
zk-SNARK (короткий неінтерактивний аргумент знань з нульовим знанням) — це технологія, заснована на доказі з нульовим знанням, яка може довести автентичність твердження, не розкриваючи реальної інформації. Це дуже ефективна технологія нульових знань, яка може генерувати та перевіряти докази за дуже короткий час, захищаючи конфіденційність і безпеку, тому вона широко використовується. Однак із розширенням додатків його безпека привертає все більше уваги. Нещодавно ми виявили його загальну вразливість: якщо діапазон значень параметра, введеного у функцію перевірки, неправильно перевірено в проекті ZKP, зловмисник може підробити кілька вхідних даних, щоб пройти перевірку, викликаючи атаку подвійного витрачання. Вплив цієї атаки дуже широкий, залучаючи кілька алгоритмів zk-SNARK, включаючи: groth16, plonk тощо, і ця вразливість існує в багатьох мовах розробки, таких як solidity та js. Ця вразливість була вперше виявлена компанією poma в проекті з нульовим знанням Semaphore, і було наведено два приклади успішно реалізованих транзакцій, як показано на малюнку нижче:
Конкретний принцип атаки цієї вразливості полягає в тому, що якщо ви хочете згенерувати та перевірити доказ zk-SNARK в Ethereum, вам потрібно використовувати схему еліптичної кривої кінцевого поля F_p-арифметики, де значення p використовується для визначення діапазону скінченного поля еліптичної кривої, тому схема Діапазон вхідних значень [0,1,…,p-1]. Різні криві мають різні значення p:
Крива BN254, визначена в EIP-196 (також відома як крива ALT_BN128):
p = 21888242871839275222246405745257275088548364400416034343698204186575808495617
circom2 представляє два нових простих числа, криві BLS12-381:
p = 52435875175126190479447740508185965837690552500527637822603658699938581184513
і plink2:
18446744069414584321
Пізніше Semaphore підтвердив і виправив уразливість, а бібліотеки zk, такі як ZoKrates і snarkjs, також виконали екстрений ремонт одночасно. Проте дослідники безпеки Beosin виявили, що наразі не існує єдиного рішення цієї проблеми. Наприклад, протокол Semaphore записує обмеження в пару. бібліотека. Дійсний діапазон даних явно не перевіряється в зовнішній бізнес-логіці; код контракту, згенерований circom і Tornado.Cash, явно перевіряє SNARK_SCALAR_FIELD у функції перевірки. Це заплутане та суперечливе рішення. Це може спричинити проблеми та ризики для безпеки для багатьох нових учасників проекту zk DApp, тому ми сподіваємося використати стандартизований спосіб вирішення цієї проблеми.
4. Подвійна атака в ERC-1922
Наразі Ethereum має пов’язаний з zk стандарт EIP-1922, який представляє стандартний інтерфейс Verify contract для перевірки zk-SNARK. Конкретний код виглядає наступним чином:
pragma solidity ^0.5.6;/// @title EIP-XXXX zk-SNARK Verifier Standard/// @dev Див. /// Примітка: ідентифікатор ERC-165 для цього інтерфейсу – 0xXXXXXXXX./// ⚠️ ЗАВДАННЯ: Розрахувати інтерфейс identifierinterface ERC1922 /* це ERC165 */ { /// @notice Перевіряє аргументи Proof за допомогою еліптичної кривої /// функцій поєднання. /// @dev /// ПОВИНЕН повернути істину, якщо Доказ проходить усі перевірки (тобто Доказ є /// дійсним). /// ПОВИНЕН повернути false, якщо доказ не пройшов усі перевірки (тобто якщо /// доказ недійсний). /// @param proof A zk-SNARK. /// @param inputs Публічні входи, які супроводжують Proof. /// @param verificationKeyId Унікальний ідентифікатор (відомий цьому верифікатору /// контракту) для ключа перевірки, якому відповідає Proof. /// @return result Результат обчислення перевірки. Істина /// якщо доказ дійсний; false інакше. функція verify(uint256[] calldata proof, uint256[] calldata inputs, bytes32 verificationKeyId) зовнішні повернення (результат bool);}
Серед них типи змінних для підтвердження з нульовим знанням і вхідних даних — це uint256[]. Цей тип змінної наразі є найпоширенішою операцією еліптичної кривої в алгоритмі ZKP. Однак відповідний захист безпеки не додається до цього інтерфейсу, тому подвійний - також існують атаки витрат Величезна загроза безпеці.
5. Рішення ERC-7520
Виходячи з вищезазначених проблем, Beosin запропонував EIP-7520 для запобігання цьому ризику безпеки. Зокрема, усі проекти DApp, що використовують технологію zk в екосистемі Ethereum, повинні реалізувати цей інтерфейс у сумісному контракті верифікатора для використання уніфікованих і безпечних стандартів. Метод виконує дійсний діапазон перевірка на всіх входах Конкретний інтерфейс виглядає наступним чином:
pragma solidity ^0.5.6;/// @title EIP-XXXX zk-SNARK public inputs Verifier Standard/// Примітка: ідентифікатор ERC-165 для цього інтерфейсу – 0xXXXXXXXX./// ⚠️ ЗАВДАННЯ: обчислити ідентифікатор інтерфейсуinterface EIP7520 /* is ERC165 & ERC1922 */ { /// @notice Перевіряє аргументи вхідних даних у межах скалярного поля /// @dev /// ПОВИННО повертати істину, якщо вхідні дані проходять перевірку діапазону (тобто вхідні дані є /// дійсними). /// ПОВИНЕН повернути false, якщо вхідні дані не проходять перевірку діапазону (тобто якщо /// вхідні дані недійсні). /// @param inputs Публічні входи, які супроводжують Proof. /// @param p Відкритий вхід, який супроводжує криву. функція verifyPublicInput(uint256[] inputs,uint256 p) зовнішні повернення (результат bool);}
Функція verifyPublicInput є ядром цього стандарту. Конкретні значення залучених параметрів такі:
Нижче буде порівняно дві ситуації впровадження та нереалізації інтерфейсу EIP-7520, спрямовані на різні прояви цієї атаки, щоб вказати на ризики для сторін проекту:
1 Припустімо, що ми безпосередньо використовуємо код контракту verify для перевірки без виклику verifyPublicInput цього інтерфейсу eip. Конкретний код такий:
функція verify(uint[] введення пам’яті, Proof memory proof) внутрішній вигляд повертає (uint) { VerifyingKey memory vk = verifyingKey(); require(input.length + 1 == vk.IC.length,"verifier-bad-input"); // Обчислення лінійної комбінації vk_x Pairing.G1Point memory vk_x = Pairing.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 = Pairing.addition(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 )) повертає 1; повернути 0;}
Скріншот оригінальних експериментальних результатів, які доводять, що перевірка пройшла:
У той же час наступні чотири сертифікати можуть бути підробленими та також можуть пройти перевірку, спричиняючи атаку подвійного витрачання:
Використовуючи одне з підроблених доказів, результати перевірки наведені нижче:
2 Якщо в цьому eip буде викликано інтерфейс verifyPublicInput, підроблене підтвердження вище не вдасться перевірити. Частина коду контракту така. Щоб отримати решту деталей, зверніться до еталонної реалізації:
функція verifyx(uint[] входи пам’яті, перевірка пам’яті доказ, bytes32 verificationKeyId,uint256 p) публічні повернення (uint){ require(verifyPublicInput(inputs,p),"verifier-over-snark-scalar-field"); require(verify(inputs,proof,verificationKeyId),"перевірити не вдалося"); return true;}function verifyPublicInput(uint256[] inputs,uint256 p) внутрішній вигляд повертає (bool) { for (uint i = 0; i < input.length; i++) { require(input < p,"verifier-gte-snark -скалярне поле"); } повертає істину;}
Результати експерименту показані на малюнку нижче:
Підводячи підсумок, можна виявити, що якщо цей інтерфейс не використовуватиметься для перевірки дійсності загальнодоступного діапазону значень сигналу, може виникнути ризик атак подвійного витрачання. **