Documentation Index
Fetch the complete documentation index at: https://mintlify.com/risc0/risc0/llms.txt
Use this file to discover all available pages before exploring further.
risc0-groth16
The risc0-groth16 crate implements a Groth16 SNARK verifier over the BN254 elliptic curve and provides functionality to convert RISC Zero STARK proofs into Groth16 SNARKs for efficient on-chain verification.
Installation
[dependencies]
risc0-groth16 = "1.3.0"
Overview
Groth16 proofs are much smaller and faster to verify than STARK proofs, making them ideal for blockchain applications. This crate allows you to:
- Verify existing Groth16 proofs
- Convert STARK proofs to Groth16 SNARKs (“shrink wrap”)
The prove feature requires an x86 architecture and Docker installation. See the installation guide for setup.
Feature Flags
Enables STARK-to-SNARK transformation.
- Implies:
std
- Requirements: x86 architecture, Docker
Enables CUDA GPU acceleration for proof generation.
Enables standard library support (enabled by default).
Types
Verifier
Groth16 proof verifier.pub struct Verifier {
// ...
}
impl Verifier {
pub fn from_json(
proof: ProofJson,
public_inputs: PublicInputsJson,
verifying_key: VerifyingKeyJson,
) -> Result<Self>;
pub fn verify(&self) -> Result<()>;
}
ProofJson
JSON representation of a Groth16 proof.#[derive(Serialize, Deserialize)]
pub struct ProofJson {
pub a: Vec<String>,
pub b: Vec<Vec<String>>,
pub c: Vec<String>,
}
Format: Ethereum-compatible JSON with hex-encoded field elements
VerifyingKeyJson
JSON representation of a Groth16 verifying key.#[derive(Serialize, Deserialize)]
pub struct VerifyingKeyJson {
pub alpha: Vec<String>,
pub beta: Vec<Vec<String>>,
pub gamma: Vec<Vec<String>>,
pub delta: Vec<Vec<String>>,
pub ic: Vec<Vec<String>>,
}
JSON representation of public inputs.#[derive(Serialize, Deserialize)]
pub struct PublicInputsJson {
pub values: Vec<String>,
}
Seal
Binary Groth16 seal for efficient verification.pub struct Seal {
pub a: G1Affine,
pub b: G2Affine,
pub c: G1Affine,
}
VerifyingKey
Binary Groth16 verifying key.pub struct VerifyingKey {
pub alpha: G1Affine,
pub beta: G2Affine,
pub gamma: G2Affine,
pub delta: G2Affine,
pub ic: Vec<G1Affine>,
}
Verification Functions
verifying_key
Get the RISC Zero Groth16 verifying key.pub fn verifying_key() -> &'static VerifyingKey
Returns: The global RISC Zero Groth16 verifying key
Proving Functions (with prove feature)
prove::shrink_wrap
Convert a STARK receipt to a Groth16 SNARK.#[cfg(feature = "prove")]
pub fn shrink_wrap(
receipt: &Receipt,
) -> Result<Groth16Receipt>
Parameters:
receipt: RISC Zero STARK receipt
Returns: Groth16 receipt with compressed proofRequirements:
- Docker must be installed and running
- x86_64 architecture
- ~16GB RAM
- Several minutes of proving time
Examples
Verifying a Groth16 Proof
use risc0_groth16::{ProofJson, PublicInputsJson, Verifier, VerifyingKeyJson};
fn verify_proof() -> Result<()> {
// Load JSON data
let vk_json: VerifyingKeyJson = serde_json::from_str(&vk_data)?;
let proof_json: ProofJson = serde_json::from_str(&proof_data)?;
let inputs_json = PublicInputsJson {
values: serde_json::from_str(&inputs_data)?,
};
// Create verifier and verify
let verifier = Verifier::from_json(
proof_json,
inputs_json,
vk_json,
)?;
verifier.verify()?;
println!("Proof verified successfully!");
Ok(())
}
STARK to SNARK Conversion
use risc0_zkvm::{default_prover, ExecutorEnv, ProverOpts, ReceiptKind};
use risc0_groth16::prove::shrink_wrap;
fn prove_groth16() -> Result<()> {
// Generate STARK receipt
let env = ExecutorEnv::builder()
.write(&input)?
.build()?;
let prover = default_prover();
let stark_receipt = prover.prove(env, elf)?;
// Convert to Groth16
let groth16_receipt = shrink_wrap(&stark_receipt)?;
// Much smaller proof!
println!("STARK size: {} bytes", stark_receipt.journal.bytes.len());
println!("Groth16 size: {} bytes", groth16_receipt.seal.len());
Ok(())
}
Direct Groth16 Generation
use risc0_zkvm::{default_prover, ExecutorEnv, ProverOpts, ReceiptKind};
fn prove_groth16_directly() -> Result<()> {
let env = ExecutorEnv::builder()
.write(&input)?
.build()?;
// Specify Groth16 receipt kind
let opts = ProverOpts::groth16();
let prover = default_prover();
let receipt = prover.prove_with_opts(env, elf, &opts)?;
// Receipt is already Groth16
println!("Generated Groth16 receipt");
Ok(())
}
On-Chain Verification (Solidity)
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;
import {Groth16Verifier} from "risc0-groth16-verifier.sol";
contract MyContract {
Groth16Verifier public verifier;
function verify(
uint256[2] memory a,
uint256[2][2] memory b,
uint256[2] memory c,
uint256[] memory publicInputs
) public view returns (bool) {
return verifier.verify(a, b, c, publicInputs);
}
}
| Proof Type | Size | Verification Time | Generation Time |
|---|
| STARK | ~200 KB | ~10-50 ms | Seconds |
| Groth16 | ~1 KB | ~1-2 ms | Minutes |
Groth16 takes longer to generate but is much smaller and faster to verify.
Elliptic Curve
The crate uses the BN254 (alt_bn128) elliptic curve:
- Field: 254-bit prime field
- Pairing-friendly: Supports efficient pairing operations
- EVM-compatible: Native support in Ethereum via precompiles
The JSON formats are compatible with Ethereum:
{
"proof": {
"a": ["0x...", "0x..."],
"b": [["0x...", "0x..."], ["0x...", "0x..."]],
"c": ["0x...", "0x..."]
},
"publicInputs": {
"values": ["0x...", "0x..."]
}
}
Docker Requirements
For STARK-to-SNARK conversion, ensure Docker is configured:
# Check Docker installation
docker --version
# Pull the required image (done automatically)
# docker pull risc0/groth16-prover:latest
Installation for Proving
See the detailed installation guide for setting up the Groth16 prover.
Links