Securing Zero-Knowledge Implementations

  • Petr Korolev | Co-founder @0xorio

  • Lev Menshchikov | Security Researcher @0xorio

Introduction

В этом конспекте будут рассмотрены шесть типичных уязвимостей, базовые атаки и способы их предотвращения, а также методы обеспечения безопасности, использующиеся при написании безопасного кода.

Under-Constrained and Non-Deterministic circuits

Первое и самое базовое понятие - это Under-Constrained circuits. Это возникает, когда вы создаете circuit. Circuit - это базовый конструктор на Zero-Knowledge (ZK), и часто юзеры не проверяют в них параметры. Важно обеспечить такую настройку, при которой у вас будет только один подтверждающий доказательство proof. Если вы создадите circuit Under-Constrained, то у вас может появиться возможность иметь несколько разных доказательств к одному circuit.

Рассмотрим пример базового кода на языке Circom, который является стандартным языком для написания снарков (zk-SNARKs). Здесь мы просто проверяем, что у вас есть два числа, которые, умноженные друг на друга, дают определенное значение.

У вас есть приватный вход и эти два числа. В данном случае, можно сгенерировать два доказательства (пруфа), поскольку они не проверяются на какие-либо ограничения в данном контексте.

Здесь есть несколько проблем:

  • Первая: Связана с тем, что числа могут быть как "+1" и "-1", и оба варианта будут допустимыми.

  • Вторая: Связана с возможностью переполнения. В данном случае, мы работаем с полями и все умножения выполняются по модулю P. Например, если у нас есть поле с порядком 100 и значение "value" равно 10, то если вы предоставите значение 110, оно просто обнулится согласно порядку поля, и результат снова будет равен 10.

  • Третья: Заключается в возможности подбора дополнительного значения в данном снарке.

Поэтому Under-Constrained circuits - это самая базовая вещь, на которую нужно обращать внимание при написании кода, а также пользоваться различными статическими анализаторами.

Arithmetic over/under flows

Overflow (переполнение) и Underflow (недостаток) - это действительно типичные проблемы, которые могут возникнуть в низкоуровневых языках программирования. В некоторых высокоуровневых языках, таких как Solidity, были введены меры безопасности, например, библиотека "SafeMath", чтобы предотвратить случайные переполнения и подталкивать разработчиков к безопасным практикам.

В Circom постоянно происходит работа с полями, где постоянно возникают переполнения, которые могут привести к некорректным результатам или уязвимостям, таким как "Double spend" (двойные траты).

Роман Семёнов, один из создателей первых приложений на zk-SNARKs TornadoCash, которая получила массовое распространение, нашёл огромную уязвимость которая позволяла делать "Double spand".

Эта уязвимость заафектила огромное количество библиотек, таких как miximus, ZoKrates, snarksjs, которые переводили 256 битные solidity-числа в 254 битные на поле bn254 в снарках.

Чтобы избежать этого, необходимо обязательно следить за тем, чтобы значения не выходили за пределы максимально допустимых значений.

Mismatching bit length

В снарках используются наиболее примитивные операции, такие как умножение, сложение, и сравнение чисел. Однако важно учитывать, что в некоторых случаях преобразование чисел и сравнение может привести к неправильным результатам.

Например, в проверке, которая сравнивает числа на "больше" или "меньше", на вход подаются два числа, которые сначала конвертируются в бинарную форму с помощью стандартной функции Num2Bits() и затем сравниваются. Если, например, на вход подаются 1 (001) и 9 (1001), то они будут обрезаны по битам, и результат будет неверным: 9 < 1.

Для того чтобы избежать такого рода ошибок, нужно установить максимальную разрядность и перевести каждый инпут с помощью Num2Bits() в ту же разрядность, и уже после этого их сравнивать.

Unused public inputs optimized out

Существует еще такой не совсем баг как оптимизация. То есть компилятор может просто убирать неиспользуемые публичные инпуты (signal inThree).

Чтобы этот инпут не вырезался, создается, например, фейковый параметр, в который кладется квадрат его же значения. В таком случае компилятор не будет удалять этот инпут.

Do not use custom cryptography

Опасные ошибки возникают, когда люди сами создают криптографию. Это случилось с реализацией хеширования Fiat-Shamir, которую назвали "Frozen Heart". Сама реализация была базовой и нормальной, но когда ее перенесли ZK, возникло множество проблем в самих снарках, так как они предоставляют не интерактивные доказательства. Алгоритм хеширования был реализован так, что можно было предсказать результат, то есть хеш был предсказуемым. Безопасность снарков полагается на случайные значения, но в данном случае значение можно было вычислить заранее из хеш-функции.

Чтобы этого избежать, нужно смотреть проадуированные имплементации на zkdocs.com, где подробно расписаны принципы реализации.

Trusted setup mechanism

Trust setup - это базовый механизм, необходимый для генерации публичных и приватных параметров при создании снарков с помощью которых прувер потом может создать для верифаера доказательство того что он обладает информацией о секретном полиноме. При "замешивание всех секретов" появляется "toxic waste" (данные, которые знают люди организовавшие церемонию), который обязательно нужно удалить Если этого не сделать, в дальнейшем можно будет подделывать пруфы. Раньше существовали сетапы, которые при каждом обновлении нужно было создавать заново. Сейчас же используют универсальные сетапы, с помошью которых не нужно заново повторять церемонию.

Проблема заключается в том, что "toxic waste", которые должны быть удалены, были записаны в публично доступные транскрипты. Изначально все думали, что в транскриптах безопасные данные, которые никак не связаны с "toxic waste" и их можно публично публиковать. Потом оказалось что есть параметры, которые оказались зависимы друг от друга, и из транскриптов можно было восстановить "toxic waste" и скомпрометировать систему.

Tools and tests

Ниже представлена подборка разных статических анализаторов, тулзов и систем, в которых можно писать тесты.

Conclusion

Для понимания разницы между Solidity и Circom в zk-SNARKs, важно изучать ошибки, математику и функции, понимая их применение и контекст.

Читайте также

Больше мероприятний