Учебник по JavaScript для доказательств с нулевым разглашением с использованием SnarkJS и Circom

Учебник по JavaScript для доказательств с нулевым разглашением с использованием SnarkJS и Circom

12 января 2023 г.

Технология доказательства с нулевым разглашением и особенно zk-SNARK является одним из самых захватывающих в области криптографии из-за следующих причины:

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

<цитата>

Rollup – это решение для масштабирования блокчейна, в котором вычисления выполняются вне цепочки, и после определенного количества транзакций состояние синхронизируется обратно в цепочку блоков. Это решение обеспечивает безопасность блокчейна (после синхронизации), но для доказательства требуется гораздо меньше места (и меньше газа), чем для исходных транзакций. Таким образом, zk-свертки — это идеальное решение для масштабирования блокчейна.

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

В этой статье я покажу вам, как вы можете использовать zk-SNARK в своем проекте JavaScript.

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

Схема может быть очень сложной, но, к счастью, существуют языки программирования и библиотеки, которые упрощают написание собственных схем. Мы будем использовать Circom. Circom написан на Rust. Чтобы установить его, вам необходимо установить среду Rust с помощью следующей команды:

curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh

После установки Rust клонируйте репозиторий Circom и соберите компилятор:

git clone https://github.com/iden3/circom.git
cd circom
cargo build --release
cargo install --path circom

Если все прошло хорошо, теперь у вас установлен компилятор Circom.

Еще нам понадобится circomlib. Circomlib — это библиотека для программирования со множеством полезных предопределенных схем. Итак, создайте пустой проект и установите circomlib, используя этот код:

npm init
npm i circomlib

Теперь все готово для создания нашей схемы. Вот как это выглядит:

pragma circom 2.0.0;

include "node_modules/circomlib/circuits/poseidon.circom";

template PoseidonHasher() {
    signal input in;
    signal output out;

    component poseidon = Poseidon(1);
    poseidon.inputs[0] <== in;
    out <== poseidon.out;
}

component main = PoseidonHasher();

Эта простая схема имеет отдельный вход и выходной сигнал. Мы используем хэш-код poseidon из circomlib для генерации входного хэша. Используя эту схему, мы можем доказать, что нам известны исходные данные для заданного хэша, не раскрывая их.

На первом этапе мы компилируем схему компилятором circom, который сгенерирует файлы wasm и r1cs.

circom poseidon_hasher.circom --wasm --r1cs -o ./build

Сгенерированные файлы wasm и r1cs доступны в папке сборки. Чтобы создать доказательство, нам нужен файл ключа доказательства, а для создания этого файла нам нужен файл ptau. Этот файл ptau можно сгенерировать с помощью snarkjs или загрузить предварительно сгенерированный файл (вы можете найти ссылки в репозитории snarkjs). Для тестирования нам подойдет сгенерированный файл, но в вашем рабочем приложении рекомендуется провести церемонию и создать собственный файл ptau. (Вы можете прочитать об этом в моем предыдущая статья.)

wget https://hermez.s3-eu-west-1.amazonaws.com/powersOfTau28_hez_final_12.ptau

Теперь мы можем сгенерировать ключ подтверждения (файл zkey), используя схему и файл ptau:

npx snarkjs groth16 setup build/poseidon_hasher.r1cs powersOfTau28_hez_final_12.ptau circuit_0000.zkey

Не рекомендуется использовать этот файл zkey для производства, но для тестирования он будет полезен для нас (для получения дополнительной информации, пожалуйста, проверьте документация по snarkjs).

Теперь все готово для создания доказательства. Мы будем использовать snarkjs, поэтому установите его с помощью этой команды:

npm i snarkjs

Генерация доказательства выглядит так:

const { proof, publicSignals } = await snarkjs.groth16.fullProve(
  { in: 10 }, 
  "build/poseidon_hasher_js/poseidon_hasher.wasm", 
  "circuit_0000.zkey");
console.log(publicSignals);
console.log(proof);

Входные сигналы передаются в первом параметре функции fullProve. Второй параметр — это скомпилированная схема, а последний параметр — сгенерированный ключ проверки. Функция возвращает выходные данные схемы и доказательство.

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

npx snarkjs zkey export verificationkey circuit_0000.zkey verification_key.json

Код подтверждения выглядит следующим образом:

const vKey = JSON.parse(fs.readFileSync("verification_key.json"));
const res = await snarkjs.groth16.verify(vKey, publicSignals, proof);

if (res === true) {
  console.log("Verification OK");
} else {
  console.log("Invalid proof");
}

Ключ проверки — это первый параметр функции verify, а выходные данные и подтверждение — второй и третий параметры. Результатом функции является простое логическое значение.

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

pragma circom 2.0.0;

include "node_modules/circomlib/circuits/poseidon.circom";

template PoseidonHasher() {
    signal input in;
    signal input hash;

    component poseidon = Poseidon(1);
    poseidon.inputs[0] <== in;
    hash === poseidon.out;
}

component main {public [hash]} = PoseidonHasher();

Эта схема не имеет выходов, только два входа. Первый ввод — это данные, а второй — их хэш. В последней строке шаблона мы проверяем хэш. Схема будет работать успешно только в том случае, если данный хеш является посейдоном хэш данных данных. Но как мы можем вычислить хэш посейдона в JS?

Circomlib имеет реализация JS, которую можно использовать для этого. Давайте установим его:

npm i circomlibjs

Теперь мы можем вычислить хэш, используя следующий код:

 const poseidon = await circomlibjs.buildPoseidon();
 const hash = poseidon.F.toString(poseidon([10]));
 console.log(hash);

Результатом функции poseidon является Buffer, который мы должны преобразовать в число. В zk-SNARK все вычисления выполняются в конечном поле, поэтому мы должны использовать poseidon.F.toString для преобразования.

Circomlibjs и snarkjs хорошо работают в Node.js и браузере, поэтому вы можете генерировать или проверять доказательства на стороне клиента. Также можно создать смарт-контракт для проверки, который вы можете использовать в своем коде Solidity для проверки доказательства. (Для получения дополнительной информации см. документацию по snarkjs.)

Circomlibjs также имеет генераторы смарт-контрактов. Например, если вы хотите сгенерировать poseidon hash в цепочке, вы можете сделать это с помощью сгенерированного кода.

Это был мой очень краткий учебник по использованию zk-SNARK в JavaScript. Это не полный курс, и у вас, вероятно, есть много вопросов, но я надеюсь, что помог вам начать свое путешествие. Circom и snarkjs хорошо документированы, и вы также можете многому научиться из существующих проектов, таких как Tornado Cash.

Исходные коды для этого руководства доступны в этом репозитории GitHub.


Также опубликовано Здесь


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE