Разработка Zero-Knowledge Proof приложений под ключ

Когда бизнесу нужно доказать факт, не раскрывая данные, или перенести тяжёлые вычисления off-chain, стандартные решения не подходят. Мы разрабатываем zero-knowledge proof приложения под ключ, помогая выбрать правильную proof-систему и стек. Наша команда берёт на себя весь цикл — от аудита до внедрения и последующей поддержки, обеспечивая надёжное решение, которое масштабируется вместе с вашим проектом.
Часто задаваемые вопросы

Большинство проектов, которые приходят к нам с запросом на ZKP, столкнулись с одной из двух проблем: либо нужно доказать факт без раскрытия данных (возраст, баланс, принадлежность к множеству), либо нужно перенести тяжёлые вычисления off-chain с верификацией on-chain. Это разные задачи с разными инструментальными стеками, и путать их — первая и самая дорогостоящая ошибка на старте. Мы поможем не ошибиться: оценим проект, подберём стек и реализуем под ключ за 6–12 недель. Свяжитесь с нами для консультации.

Как правильно выбрать proof-систему?

Выбор между Groth16, PLONK, STARK, Halo2 и FRI определяет всё: размер proof, время генерации, наличие trusted setup, стоимость верификации on-chain. Ниже — таблица для сравнения.

Система Trusted setup Proof size Verification cost (EVM) Prover time Рекурсия
Groth16 Да (per-circuit) ~200 bytes ~270k gas Быстрый Сложная
PLONK (KZG) Да (универсальный) ~800 bytes ~400k gas Средний Проще
PLONK (IPA) Нет ~1.5KB Дороже Медленный Хорошая
STARK Нет 40–200KB Очень дорого в EVM Медленный Отличная
Halo2 Нет ~1–5KB Не нативный Средний Встроена

Groth16 — выбор для production систем с фиксированной схемой и требованиями к минимальному газу. Используют: Tornado Cash (был), Zcash Sapling, большинство zkSNARK мостов. Минус: каждое изменение circuit требует новой ceremony. PLONK с KZG — де-факто стандарт для zkRollup-подобных систем. Gnosis, zkSync Lite, Polygon Hermez используют варианты PLONK. Универсальный trusted setup (Powers of Tau) переиспользуется — не нужна ceremony под каждую схему. STARKs — выбор для задач, где нет trusted setup и нужна рекурсия: StarkNet, Cairo VM. Огромный proof размер — верификация в EVM нативно нецелесообразна, нужен отдельный verifier контракт или L3-подход. Halo2 — используют Zcash Orchard, Scroll. Не требует trusted setup, встроенная рекурсия. Tooling менее зрелый, экосистема меньше, но активно развивается.

Для большинства практических задач (приватное голосование, proof of membership, zkKYC, age verification) — Groth16 через circom/snarkjs или PLONK через gnark/noir — правильная отправная точка. При газе 20 gwei одна верификация Groth16 обходится ~$2-5 на Ethereum mainnet, а на Arbitrum — ~$0.02-0.05, что делает L2-деплой экономически оправданным.

Что уязвимо в ZK circuits? Разбираем на circom

Circom — DSL для написания arithmetic circuits. Circuit компилируется в R1CS, затем через snarkjs или rapidsnark генерируется proof.

Базовая схема для доказательства знания preim хэша:

pragma circom 2.1.4;
include "circomlib/circuits/poseidon.circom";
include "circomlib/circuits/comparators.circom";

template ProveBalance() {
    signal input balance; // private
    signal input salt; // private
    signal input commitment; // public
    signal input threshold; // public

    component hasher = Poseidon(2);
    hasher.inputs[0] <== balance;
    hasher.inputs[1] <== salt;
    hasher.out === commitment;

    component rangeCheck = Num2Bits(64);
    rangeCheck.in <== balance;

    component gte = GreaterEqThan(64);
    gte.in[0] <== balance;
    gte.in[1] <== threshold;
    gte.out === 1;
}

component main {public [commitment, threshold]} = ProveBalance();

«Under-constrained signals — наиболее частый класс багов в ZK circuits» (документация circom, раздел безопасности). Если сигнал используется в вычислении, но не имеет достаточного количества constraints — прувер может передать произвольное значение, и верификатор примет proof.

Пример уязвимого кода:

// УЯЗВИМО: нет constraint что out это bit
template IsZero() {
  signal input in;
  signal output out;
  signal inv;
  inv <-- in != 0 ? 1/in : 0;
  out <-- in == 0 ? 1 : 0;
  // ЗАБЫЛИ: in * out === 0 и (in * inv - 1 + out) === 0
}

Верификатор принимает любой out, потому что нет constraints, связывающих out с in.

Overflow в field arithmetic: Circom работает в простом поле p = 21888242871839275222246405745257275088548364400416034343698204186575808495617. Любая операция выполняется по модулю p. Если входные данные — числа из реального мира (возраст, timestamp) — диапазон безопасен. Но при умножении больших чисел нужен явный range check через Num2Bits, как показано в примере.

Gnark (Go) для более сложных схем

Отметим: когда схема слишком сложна для circom (рекурсивные доказательства, BLS signature verification, zkEVM-подобные компоненты) — gnark:

type Circuit struct {
    PreImage frontend.Variable `gnark:",secret"`
    Hash     frontend.Variable `gnark:",public"`
}

func (c *Circuit) Define(api frontend.API) error {
    mimc, err := mimc.NewMiMC(api)
    if err != nil {
        return err
    }
    mimc.Write(c.PreImage)
    result := mimc.Sum()
    api.AssertIsEqual(result, c.Hash)
    return nil
}

gnark в 10–30x быстрее snarkjs в prover time для одинаковых схем. Для production с реальными пользователями это важно: генерация proof в браузере через WASM занимает 3–15 секунд на Groth16 схеме умеренной сложности, в Go сервере — 0.1–1 секунду.

On-chain верификация

Solidity verifier генерируется автоматически — snarkjs делает это через snarkjs zkey export solidityverifier. Но в production контракт нужно адаптировать:

contract BalanceProofVerifier {
    IGroth16Verifier public immutable verifier;
    mapping(bytes32 => bool) public usedNullifiers;

    function verifyAndExecute(
        uint[2] calldata a,
        uint[2][2] calldata b,
        uint[2] calldata c,
        uint[2] calldata publicInputs // [commitment, threshold]
    ) external {
        bytes32 nullifier = keccak256(abi.encodePacked(a, b, c));
        require(!usedNullifiers[nullifier], "Proof already used");
        require(verifier.verifyProof(a, b, c, publicInputs), "Invalid proof");
        usedNullifiers[nullifier] = true;
        // ... основная логика
    }
}

Gas cost верификации Groth16 — около 270k gas. На Ethereum mainnet при 20 gwei это ~$2–5 за верификацию. Для систем с высокой частотой — деплой на L2 (Arbitrum, Base) снижает стоимость в 10–50x.

Инфраструктура для proof generation

Подробнее о trusted setup ceremony

Для Groth16 — обязательна. Процесс:

  1. Универсальный Powers of Tau (берём готовый от Hermez/EthSnarks — это публично верифицированные параметры)
  2. Phase 2 ceremony специфична для вашей схемы: каждый участник добавляет свою рандомность
  3. Final beacon — публичный рандомный источник (Bitcoin block hash)

Если хотя бы один участник честен — параметры безопасны. Для production проектов: минимум 10–20 участников, публичная верификация транскрипта.

Клиентская генерация (браузер)

Для wallet-уровневых операций используется WebAssembly сборка snarkjs. .zkey файл для сложных схем весит 10–500MB — решение: разбить на части (chunked zkey) или использовать streaming загрузку. Для production нагрузок эффективнее серверный prover на Go с gnark.

Серверная генерация (proving service)

Архитектура: Client → API → Queue (Bull/RabbitMQ) → Prover Worker → S3 → Webhook. Prover worker — Go сервис с gnark. Горизонтальное масштабирование: каждый worker независим, задачи идемпотентны. Для zkEVM-уровневых схем (миллиарды constraints) — GPU proving через CUDA с ускорением 100–1000x.

Как начать разработку ZK-приложения: 5 шагов

  1. Спецификация схемы: формализация задачи, выбор proof-системы, определение public/private inputs.
  2. Circuit разработка: написание кода на circom/gnark/noir, unit тесты constraints.
  3. Аудит circuits: поиск under-constrained сигналов, проверка soundness с помощью формальной верификации.
  4. Verifier контракт: генерация Solidity verifier, добавление nullifier логики, интеграция с протоколом.
  5. Prover инфраструктура: настройка WASM сборки или серверного прувера, API для вызова.

Сроки и объём работ

Фаза Содержание Срок
Спецификация схемы Формализация задачи, выбор proof-системы, проектирование public/private inputs 1 нед
Circuit разработка Написание circom/gnark/noir, unit тесты constraints 2–4 нед
Аудит circuits Поиск under-constrained сигналов, проверка soundness 1–2 нед
Verifier контракт Solidity verifier + nullifier логика + интеграция с основным протоколом 1–2 нед
Prover инфраструктура WASM сборка или серверный прувер, API 1–2 нед
Trusted setup Организация ceremony (если Groth16/PLONK-KZG) 1 нед

Итого для типового ZKP приложения (proof of membership, zkKYC, приватные транзакции): 6–12 недель от спецификации до mainnet. Сложные zkRollup-подобные системы — 6–18 месяцев команды.

Хотите обсудить ваш проект? Закажите разработку ZK-приложения — мы оценим задачу и предложим архитектуру. Перейдите на Wikipedia для общего понимания технологии. Обращайтесь к нам за консультацией.

Направления блокчейн-разработки

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1542
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1393
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1368
  • Разработка логотипа компании B2B Advance
    Разработка логотипа компании B2B Advance
    815
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1139