Смарт-контракты
February 3, 2024

Смарт-контракт с использованием zk-SNARKs

Например, у нас есть секретная информация, скажем, пароль. Мы хотим доказать другому человеку, что у нас есть этот пароль, но не хотим раскрывать сам пароль. С использованием zk-SNARKs, мы сможем сгенерировать доказательство, подтверждающее, что у нас есть знание о пароле, но при этом сам пароль будет оставаться скрытым. Это обеспечит доказуемую аутентификацию без необходимости раскрывать секретную информацию.

Поскольку смарт-контракты могут раскрывать значения, а нам необходимо хранить пароль в секрете. Для этого обратимся к ZoKrates.

ZoKrates - набор инструментов которые упрощает разработку и развертывание программ доказательства с нулевым разглашением, специально разработанных для использования на Ethereum.

Варианты использования:

  • Плагин в Remix IDE предоставляет создание и верификацию zk-SNARKs.
  • ZoKrates Playground - веб-игровая площадка, где разработчики могут писать и компилировать программы онлайн. Playground включает в себя редактор кода, компилятор и инструменты для создания и проверки доказательств.
  • Установить ZoKrates локально с помощью менеджеров пакетов, таких как npm, или загрузив двоичный файл непосредственно из репозитория ZoKrates GitHub.
  • Контейнер Docker: ZoKrates также предоставляет контейнер Docker, который можно использовать для запуска программ ZoKrates в виртуализированной среде. Эта опция полезна для разработчиков, которые не хотят устанавливать ZoKrates локально и предпочитают использовать стандартизированную среду. docker run -ti zokrates/zokrates /bin/bash

Технические особенности:

  • ZoKrates — использует программы на предметно-ориентированном языке (DSL) высокого уровня.
  • ZoKrates DSL похож на язык программирования C (Си) включает переменные, циклы и условные операторы.
  • Использует libsnark, библиотеку C++ zkSNARKs, для генерации доказательств и ключей проверки.
  • Поддерживает криптографию на основе эллиптических кривых, модульную арифметику, хеш-функции и другие криптографические операции.
  • Использует систему доказательств Groth16 для быстрого и эффективного создания и проверки ZKP.
  • Имеет лицензию MIT и представляет собой проект с открытым исходным кодом.
Журнал изменений ZoKrates

Рассмотрим пример, где у нас есть секретное значение x а у нашего товарища Жака такое хэш-значение: y = H(x)

При использовании 256-битного хэш, практически нет шансов, что мы когда-либо узнаем значение x, зная только значение y. Таким образом, x может быть паролем. Итак, посмотрим, сможем ли мы доказать x, зная H(x) и запустить смарт-контракт.

1) В ZoKrates Playground напишем следующий код:

import "hashes/sha256/512bitPacked" as sha256packed;

def main(private field a, private field b, private field c, private field d) -> field[2] {
    field[2] h = sha256packed([a, b, c, d]);
    return h;
}
Первая строка импортирует sha256packedфункцию из стандартной библиотеки ZoKrates.sha256packed— это реализация SHA256, оптимизированная для использования в ZoKrates DSL. Вот как это работает: мы хотим передать 512 бит входных данных в SHA256. Однакоfieldзначение может содержать только 254 бита из-за размера основного поля, которое мы используем. Как следствие, мы используем четыре элемента поля, каждый из которых кодирует 128 бит, для представления наших входных данных. Затем четыре элемента объединяются в ZoKrates и передаются в SHA256. Учитывая, что длина полученного хеша составляет 256 бит, то он делится на две части и возвращает каждое значение как 128-битное число.

Вычисление хеша с помощью ZoKrates.

Переходим во вкладку Execute и нажимаем Run

[ "71860681579908444993719277659355514616", "203894998809118867442052767119280883826" ]

2) Создадим доказательство с нулевым разглашением.

2.1) В Remix IDE cоздадим фаил main.zok и напишем следующий код:

import "hashes/sha256/512bitPacked" as sha256packed;

def main(private field a, private field b, private field c, private field d) {
    field[2] h = sha256packed([a, b, c, d]);
    assert(h[0] == 71860681579908444993719277659355514616);
    assert(h[1] == 203894998809118867442052767119280883826);
    return;
}
Код использует библиотеку sha256packed для вычисления хеша SHA-256 от четырех приватных полей a, b, c и d. Затем программа проверяет, что вычисленный хеш совпадает с ожидаемыми значениями, и возвращает ошибку, если это не так. В данном случае программа проверяет, что вычисленный хеш (полученный ранее в п.1) равен 71860681579908444993719277659355514616 для h0 и 203894998809118867442052767119280883826 для h1. Если это условие выполняется, то программа завершается успешно, иначе возникает ошибка.

main.zok

2.2) Добавим плагин ZoKrates в Remix IDE

Менеджер плагинов

Активация ZoKrates

ZoKrates

2.3) Компиляция: на левой боковой панели кнопка компиляции. Если ошибки нет, можем двигаться дальше.

Компиляция кода

Скомпилировано успешно

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

Свидетель – представляет собой набор данных, который подтверждает истинность скрытой информации, не раскрывая конфиденциальности. Необходим для доказательства, что держатель этой информации обладает знанием о ней, но не раскрывает саму информацию.

Вычислено успешно

К примеру удаляем одну цифру - Execution failed

Выполнение не удалось

2.5) Run Setup (cоздать доказательство). Используем свидетель для создания доказательства, которое демонстрирует достоверность вычислений без раскрытия частных входных данных. После вычисления мы можем сгенерировать проверочный и подтверждающий ключ. Это может занять больше минуты, но выполняется только один раз. Эти ключи получены из источника случайности, обычно называемого «токсичными отходами». Мы увидим, что создался файл с именем verification_key.json, который содержит все эти данные.

Запустить установку

Изменение ключа проверки

verification_key.json

2.6) Generate Proof - имея ключи верификатора, а также свидетель, мы теперь можем сгенерировать наше доказательство:

Создать доказательство

Теперь у нас есть проверяющее доказательство (proof.js)

Доказательство (proof.js)

{
  "scheme": "g16",
  "curve": "bn128",
  "proof": {
    "a": [
      "0x0ac917308a7b8db29288c028109c8617f910f6b6843c975a736374ddbc276797",
      "0x1960e7c91c4bb774e6308c418615d566280679a5b7c18b45f89ab64098187bdf"
    ],
    "b": [
      [
        "0x2df5af53473f2343c58091e657898f92b5b7f0b88a6ea7514c9952a47e07f444",
        "0x0121a9c22c2abafb7dee637ef4f743a4d62798835350d042d55c708d2481fe3d"
      ],
      [
        "0x1e46763eeacc9f85215740e3d3f7eaddc2fca5c8115c282be1e60157740bcec8",
        "0x23d8a13843a39d8f37b8a0ef6da31281b7ee2c61d16079a48f2620b9f6ef9aa0"
      ]
    ],
    "c": [
      "0x2f990abf7f96daee712f3ca282e7e304370ac70d633b6156a41b91f140e6cb41",
      "0x0e619f6d20fc6c39fa3fa0320c795e57218824f1f11ee90b0d7edf3a306de8fd"
    ]
  },
  "inputs": []
}

Копируем доказательство
[["0x0ac917308a7b8db29288c028109c8617f910f6b6843c975a736374ddbc276797","0x1960e7c91c4bb774e6308c418615d566280679a5b7c18b45f89ab64098187bdf"],[["0x2df5af53473f2343c58091e657898f92b5b7f0b88a6ea7514c9952a47e07f444","0x0121a9c22c2abafb7dee637ef4f743a4d62798835350d042d55c708d2481fe3d"],["0x1e46763eeacc9f85215740e3d3f7eaddc2fca5c8115c282be1e60157740bcec8","0x23d8a13843a39d8f37b8a0ef6da31281b7ee2c61d16079a48f2620b9f6ef9aa0"]],["0x2f990abf7f96daee712f3ca282e7e304370ac70d633b6156a41b91f140e6cb41","0x0e619f6d20fc6c39fa3fa0320c795e57218824f1f11ee90b0d7edf3a306de8fd"]]

Наше доказательство

2.7) Export Verifier - генерирует контракт Solidity, который включает ключ проверки. Этот контракт предоставляет общедоступную функцию для проверки решений скомпилированной программы. Это обеспечивает независимую проверку правильности и повышает прозрачность в системах с нулевым разглашением данных.

Экспорт верификатора
Верификатор экспортирован
Файл verifier.sol

3) Проверка доказательства с нулевым разглашением.

3.1) Компилируем verifier.sol После развертывания контракт верификатора можно использовать для проверки решений скомпилированной программы.

Solidity компилятор

Компиляция файла verifier.sol

3.2) Развертывание смарт-контракта verifier.sol

Deploy verifier.sol

Контракт Verifier

[["0x0ac917308a7b8db29288c028109c8617f910f6b6843c975a736374ddbc276797","0x1960e7c91c4bb774e6308c418615d566280679a5b7c18b45f89ab64098187bdf"],[["0x2df5af53473f2343c58091e657898f92b5b7f0b88a6ea7514c9952a47e07f444","0x0121a9c22c2abafb7dee637ef4f743a4d62798835350d042d55c708d2481fe3d"],["0x1e46763eeacc9f85215740e3d3f7eaddc2fca5c8115c282be1e60157740bcec8","0x23d8a13843a39d8f37b8a0ef6da31281b7ee2c61d16079a48f2620b9f6ef9aa0"]],["0x2f990abf7f96daee712f3ca282e7e304370ac70d633b6156a41b91f140e6cb41","0x0e619f6d20fc6c39fa3fa0320c795e57218824f1f11ee90b0d7edf3a306de8fd"]]

Наше доказательство

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

3.3) Вставляем доказательство в поле, а затем протестируем: должно быть написано «0»: «bool: r true». Это означает, что транзакция успешно подтверждена.

Доказательство истинно

Но если мы воспользуемся неверным доказательством, мы получим ложный результат: errored: Error occured: invalid opcode.

4) Развернем смарт-контракт в тестовой сети и проверим наше доказательство.

4.1) Создан новый смарт-контракт в сети Sepolia:

https://sepolia.etherscan.io/tx/0x0a555af118bc0961984947432ee28e20ff33e8f8525cf0b9fc31080a45c61566

4.2) Переходим в контракт:

4.3) Контракт необходимо верифицировать.

4.3.1) Заполняем поля:

4.3.2) В новом окне необходимо вставить код нашего контракта verifier.sol

4.3.3) Подтверждаем верификацию.

4.3.4) Верификация пройдена.

4.4) Переходим в Read Contract

4.5) В строку proof (tuple) вставляем наше доказательство.

[["0x0ac917308a7b8db29288c028109c8617f910f6b6843c975a736374ddbc276797","0x1960e7c91c4bb774e6308c418615d566280679a5b7c18b45f89ab64098187bdf"],[["0x2df5af53473f2343c58091e657898f92b5b7f0b88a6ea7514c9952a47e07f444","0x0121a9c22c2abafb7dee637ef4f743a4d62798835350d042d55c708d2481fe3d"],["0x1e46763eeacc9f85215740e3d3f7eaddc2fca5c8115c282be1e60157740bcec8","0x23d8a13843a39d8f37b8a0ef6da31281b7ee2c61d16079a48f2620b9f6ef9aa0"]],["0x2f990abf7f96daee712f3ca282e7e304370ac70d633b6156a41b91f140e6cb41","0x0e619f6d20fc6c39fa3fa0320c795e57218824f1f11ee90b0d7edf3a306de8fd"]]

Доказательство

Доказательство истинно

https://sepolia.etherscan.io/address/0xe38f6eebf205303e417525bf52638290ffee7d08#readContract

Вывод:

При помощи инструментов ZoKrates сгенерировали доказательство zk-SNARKs и подтвердили истинность нашего значения х которое было сохранено в хеш и разделено на две части. Как видим смарт-контракты с нулевым разглашением (ZK) предполагают внедрение системы, которая позволяет сторонам доказывать подлинность определенной информации, не раскрывая деталей этой информации.

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

ZoKrates делает создание zk-SNARKs доступным, предоставляя простой язык для написания функций. Также существует обширный набор примеров, демонстрирующий все возможности языка. Потенциал использования: в системах идентификации, сохраняя конфиденциальность, в различных голосованиях, финансах, оракулах, приложениях DeFi и т.д.