Большинство проектов, которые приходят к нам с запросом на 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 — обязательна. Процесс:
- Универсальный Powers of Tau (берём готовый от Hermez/EthSnarks — это публично верифицированные параметры)
- Phase 2 ceremony специфична для вашей схемы: каждый участник добавляет свою рандомность
- 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 шагов
- Спецификация схемы: формализация задачи, выбор proof-системы, определение public/private inputs.
- Circuit разработка: написание кода на circom/gnark/noir, unit тесты constraints.
- Аудит circuits: поиск under-constrained сигналов, проверка soundness с помощью формальной верификации.
- Verifier контракт: генерация Solidity verifier, добавление nullifier логики, интеграция с протоколом.
- 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 для общего понимания технологии. Обращайтесь к нам за консультацией.







