Supported Proof Types & Choosing the Right One

The choice happens before zkVerify

By the time you submit a proof to zkVerify, you have already made the most important decision: which proof system generated it. zkVerify does not change your proof. It verifies it natively, exactly as produced.

This means the proof type question is really a question about your toolchain, your circuit language, and what tradeoffs matter for your application. This lesson maps out what zkVerify supports and how to reason about which one fits your use case.

What is currently supported

zkVerify supports the following proof types natively on mainnet:

Groth16 — pairing-based SNARK. Supported across three elliptic curves: BN128, BN254, and BLS12-381. Works with proofs generated by snarkjs, arkworks, and gnark.

FFlonk — Polygon's optimized PLONK variant. Used by the Polygon CDK prover and Polygon zkEVM.

RISC Zero — STARK-based zkVM. Supports versions V2_1, V2_2, V2_3, and V3_0. Lets you write guest programs in Rust and prove their execution.

Plonky2 — recursive PLONK with FRI commitments. Requires specifying the hash function used: Poseidon or Keccak with Goldilocks field.

SP1 — Succinct's zkVM for arbitrary computation. Accepts shrunk STARK proofs in compressed form.

UltraPlonk — Barretenberg-based PLONK for Noir. Deprecated as of Barretenberg v0.87.0. Still supported but new Noir projects should use UltraHonk.

UltraHonk — current Noir proof type via Barretenberg. Two variants: Plain and ZK. From runtime v1.3.0 onward the variant must be specified explicitly.

EZKL — for verifiable machine learning inference proofs. Added natively in November 2025. Two variants: Plain and ZK.

💡
All of these are verified natively, meaning no conversion or wrapping is required. You generate the proof with your existing toolchain and submit it directly.

How to think about choosing

The proof system you use is usually determined by three things: the language you write circuits in, the kind of computation you are proving, and how much you care about proof size versus proving speed.

If you are writing circuits in Circom, you are generating Groth16 proofs via snarkjs. That maps directly to the Groth16 pallet. No changes needed.

If you are writing circuits in Noir, you are using Barretenberg. Use UltraHonk. UltraPlonk is still supported but Aztec has officially moved to UltraHonk and UltraPlonk will not receive further development.

If you are writing general computation in Rust and want to prove program execution rather than arithmetic circuits, you are in zkVM territory. RISC Zero and SP1 are both strong options here. RISC Zero uses STARK natively and is well suited for recursive proving workflows. SP1 has growing adoption in rollup and coprocessor applications and integrates cleanly with Succinct's prover network.

If you are working with Polygon's stack, FFlonk is likely already your output format if you are using Polygon CDK. It maps directly to the FFlonk pallet.

If you are building ML inference verification, EZKL is the only dedicated option and it is natively supported. EZKL converts ONNX models into ZK circuits and generates proofs of correct inference.

The trusted setup question

Some proof systems require a trusted setup ceremony to generate the structured reference string used in verification. Others do not.

Require trusted setup: Groth16 (circuit-specific), FFlonk, UltraPlonk, UltraHonk.

Transparent, no trusted setup: RISC Zero, SP1, Plonky2, EZKL.

For most production applications this distinction matters less than it used to, because Groth16 setups are now routinely done through large public ceremonies with many participants. But if your application requires provably transparent verification with no ceremony assumptions, the STARK-based systems are the right direction.

Proof size tradeoffs

Elliptic curve SNARKs produce very small proofs. A Groth16 proof is a few hundred bytes regardless of circuit complexity. This makes them cheap to store and transmit.

STARK-based proofs are larger, often in the hundreds of kilobytes range before any compression. SP1 and RISC Zero apply compression and shrinking passes to reduce this, but the proofs are still larger than their SNARK counterparts.

On zkVerify this tradeoff matters less than it would on Ethereum, because you are not paying EVM gas to store the proof on-chain. You pay a flat verification fee in VFY regardless of proof size. But proof size still affects the transaction weight on zkVerify and therefore the fee, so it is not completely irrelevant.

Quick reference

| Your toolchain | Proof type to use | |---|---| | Circom + snarkjs | Groth16 (BN128 or BN254) | | Circom + gnark | Groth16 (BLS12-381) | | Noir + Barretenberg | UltraHonk | | RISC Zero | RISC Zero (specify version) | | SP1 | SP1 | | Polygon CDK | FFlonk | | Plonky2 | Plonky2 (specify hash function) | | EZKL | EZKL (specify Plain or ZK variant) |

💡
If you are unsure which version or curve your toolchain produces, check the proof artifacts. The verification key format and proof byte length will match the pallet documentation exactly. When in doubt, the zkVerify documentation has a dedicated generating proofs guide for each supported type.

Answer the quiz correctly to continue →

Quiz · Multiple Choice1 / 3

You are writing circuits in Noir using Barretenberg. Which proof type should you submit to zkVerify?