ByAUJay
How Exactly Does Batching Thousands of Groth16 Proofs Into One Aggregated Proof Get Settled On-Chain?
A Practical Guide for Decision-Makers on Groth16 Proof Aggregation
So, let’s dive into how Groth16 proof aggregation--specifically through something like SnarkPack--can shake things up in terms of what you actually post to a blockchain. We’ll also take a closer look at how your verifier contract behaves after implementing Pectra and break down the real costs involved in gas and latency.
What Does Groth16 Proof Aggregation Change?
When you use Groth16 proof aggregation, it helps you bundle multiple proofs together. This means instead of posting each proof individually, you’re essentially condensing a bunch into a single proof. This streamlined process can lead to significant improvements in how you interact with the blockchain.
Key Changes to Your Chain Posts:
- Reduced Data Footprint: Fewer proofs means you’re using less space on the blockchain, which is great for keeping things efficient.
- Increased Throughput: Letting you pack more transactions in one go can really speed things up.
- Improved Privacy: With fewer proofs published, it makes it harder to reverse-engineer the content of the proofs.
How Your Verifier Contract Works After Pectra
After integrating Pectra into your system, your verifier contract might behave a bit differently. Here’s what you can expect:
- Simplified Logic: The verifier contract can become much cleaner and easier to understand since it's now verifying aggregated proofs.
- Faster Verification: Aggregation can speed up the verification process, making everything run smoother and quicker.
- Lower Error Rate: With simpler logic, you’re potentially reducing the chances of issues during verification.
Costs in Gas and Latency
Let’s break down what all this means in terms of costs. Here’s how gas and latency might stack up when you switch to Groth16 proof aggregation:
Gas Costs
- Lower Gas Fees: Since you’re posting fewer items to the blockchain, you’ll likely see a drop in gas costs.
- Cost Efficiency: The savings could be significant, especially if you’re operating at scale.
Latency
- Quicker Responses: Thanks to the aggregated proofs, you can expect faster response times for your transactions.
- Improved User Experience: With lower latency, users will enjoy a smoother experience interacting with your applications.
So, in a nutshell, adopting Groth16 proof aggregation through tools like SnarkPack can really transform the way you engage with blockchain technology--from what you post to how your contracts operate, not to mention the savings in gas and time.
TL;DR for startup and enterprise leaders
- Aggregation takes k independent Groth16 proofs and combines them into one single proof. Along with that, you get a compact “manifest” of all the instances it covers. When you're on-chain, you only need to verify one object and commit to the statements included using hashes or Merkle roots. You can find more about this here.
- Since May 7, 2025 (that's when Pectra launched), you have the option to verify pairing-based proofs on Ethereum - you can choose either the BN254 (the legacy option) or the shiny new BLS12-381 precompiles (thanks to EIP-2537). This new option brings modern security and competitive gas costs for each pairing. For more details, check out the Ethereum blog.
- Here are some real numbers to keep in mind:
- For verifying a single Groth16 proof, it usually takes around 200k-220k gas for BN254, plus about 7k for each public input. You can read more about it here.
- When it comes to SnarkPack off-chain, you can aggregate 8,192 Groth16 proofs in roughly 8-9 seconds. Once aggregated, the proof verifies off-chain in about 33 milliseconds, and the proof size is around 40-41 KiB. More info can be found here.
- For on-chain verification of an aggregated proof, the process is mainly influenced by O(log n) pairings, along with the calldata for that ~40 KiB proof. You'll need about 16-40 gas per byte, depending on the EIP‑7623 thresholds. Plan on budgeting around 0.45-1.1 million gas for the pairings and overhead, plus 0.65-1.64 million gas for calldata, based on the curve, the number of pairings, and whether the calldata floor applies. Check out the specifics here.
What does “aggregating Groth16 proofs” really do?
- Baseline Groth16: So, when you’ve got a proof π = (A ∈ G1, B ∈ G2, C ∈ G1), the verification process is pretty straightforward. You just need to check one pairing product equation, which involves a constant number of pairings on the verifier’s curve (think BN254 or BLS12‑381). Generally, if you’re using Solidity verifiers on BN254, expect to run about 3-4 pairings for each proof. You can find more details here.
- Aggregation (SnarkPack): Now, if you're looking to streamline things a bit, check out this cool technique called SnarkPack. It uses an inner-product pairing argument (GIPA) to merge k Groth16 proofs into one single argument, which ends up being way more compact--both in terms of size and verification time, coming in at O(log k). The best part? You don’t have to bother with a new trusted setup; SnarkPack cleverly reuses Groth16’s existing “powers of tau” transcripts. For a deeper dive, click here.
What You'll Get:
- Just one proof to verify on-chain instead of juggling multiple proofs.
- A logarithmic number of pairings along with a few extra scalar multiplications for the verifier.
- A neat and tidy commitment (manifest) that clearly shows which original statements and proofs are included. (research.protocol.ai)
What lands on-chain when you batch thousands of Groth16s?
A usual settlement transaction includes:
- Aggregated proof bytes
- You’re looking at about ~40-41 KiB when k is around 8,192. These figures come from Protocol Labs’ implementation, which uses a pairing-friendly curve that’s pretty similar to BLS12‑381/BN254 encodings. (research.protocol.ai)
- Public IO Commitments for the Batch
- Rather than sharing all public inputs for every single k instance, you can just post a compact digest. This could be something like a Merkle root for the public IO specific to each instance or a domain-separated transcript hash. This way, it looks like a small set of public inputs to the aggregated verifier. Later on, downstream contracts can verify inclusion using a Merkle proof. (research.protocol.ai)
3) Verifying Key (VK) Reference
- In your verifier contract, you'll typically see the VK hardcoded, stored just once, or saved as a hash. To avoid any issues with “VK drift,” most production setups go for hardcoding or immutably storing the VK. If you're using tools like snarkjs or gnark, they can help you export Solidity or Rust verifiers that are linked to a specific VK. Check out the details here: (docs.gnark.consensys.io)
4) Optional: a per-batch “manifest”
- This gets sent out as an event to keep storage writes at bay. It includes the batch ID, Merkle root(s), the VK hashes of the circuits, and any replay-protection details like chainId and programId. Consumers typically index this info off-chain and can request inclusion proofs whenever they need them. (7blocklabs.com)
How the verifier contract actually works now (Ethereum, Jan 2026)
There are two options for on-chain pairing checks:
- BN254 Precompiles (alt_bn128): EIP‑196 and EIP‑197 introduced some cool features like EC addition and multiplication, along with pairing. Then, EIP‑1108 came along and adjusted gas prices to make pairings more budget-friendly. Now, the gas cost for pairing is about 34,000·k + 45,000 for k pairs. This is pretty crucial for most of the historical Groth16 verifiers. Check out the details here.
- BLS12‑381 Precompiles (post‑Pectra, EIP‑2537): This upgrade brings in some nifty 128‑bit security curve operations, including a pairing precompile with a gas cost of around 32,600·k + 37,700. Plus, it introduces MSM precompiles that significantly speed up multi-scalar multiplications. Best of all, this will be fully usable on the mainnet starting May 7, 2025. Dive into the specifics here.
Implication: You can set up an aggregated Groth16 verifier on either curve. If your team is moving from BN254 to BLS12‑381, you're in for some nice perks--better security and slightly lower costs for pairing checks per pair. Just keep in mind that you'll be dealing with larger point encodings, which will affect your calldata. Check out more details here.
Cost model: turning cryptography into gas you can budget
This model is designed to help you get a better grip on cost estimates. Feel free to tweak the constants to match your library's specific pairing count and proof size.
- For pairing costs, if you’re looking at BN254, it’s: gas_pair = 45,000 + 34,000·k. You can dive deeper into it here.
- If BLS12‑381 is more your speed, the pairing cost is a bit different: gas_pair = 37,700 + 32,600·k. Check out the details here.
- And for calldata post‑EIP‑7623, you're looking at 4/16 gas/byte for regular transactions. But if you're dealing with data-heavy calls that are light on EVM execution compared to calldata, a minimum 10/40 gas/byte kicks in. This helps keep the worst-case block size under control as blobs increase. More info can be found here.
Worked example (for planning):
- Let’s say we have k = 8,192 individual Groth16s all packed into one proof that’s about 41,000 bytes (which is roughly 40.98 KiB). The off-chain aggregation takes around 8-9 seconds, while off-chain verification is super quick at about 33 milliseconds. You can check out more about this here.
- When it comes to aggregated verifier pairings, it's a bit dependent on the protocol and scales like O(log k). A lot of teams tend to estimate a pairing count in the low dozens for this size, but it’s a good idea to double-check the exact number based on your aggregator library. For planning purposes, it’s safe to use k_pair = 12 as a conservative estimate. Just remember, this is an engineering assumption, so verify against your implementation! More info can be found here.
- Looking at the costs on BN254: you’re looking at about 45,000 gas plus 34,000·12, which totals up to roughly 453,000 gas. For BLS12-381, it’s around 37,700 plus 32,600·12, giving you a total of about 429,900 gas. And don’t forget, EVM “scaffolding” along with ECADD/ECMUL for IC accumulation will add some extra thousand gas on top. For more details, check this out: EIP-1108.
- Now for the calldata:
- If your transaction is considered “normal” (meaning it has enough EVM work compared to the data), then you’ll be looking at 41,000 bytes × 16 = approximately 656,000 gas.
- If you fall under the EIP-7623 minimum, that would be 41,000 × 40 = around 1,640,000 gas. Get the specifics here.
When you're looking to verify and settle a “thousands-batched” Groth16 aggregation on Ethereum, you're typically looking at an all-in gas cost somewhere between ≈1.1M and 2.1M. This really hinges on the pricing of calldata and the curve you’re working with, and it doesn't even include any storage writes. To put it in perspective, that's a massive reduction compared to k × 200k if you were to post and verify each one individually. Check out more details in this medium.com article.
Tip: Send out batch metadata as events (logs) and keep only the commitments on-chain to dodge those pesky SSTORE costs. You can always prove the specifics for each instance later using inclusion proofs. (7blocklabs.com)
What the Solidity/Rust verifier actually checks in an aggregated flow
At a Glance:
- Let's go ahead and recalculate the VK-linearized accumulator for the batch public inputs:
- vk_x = IC[0] + Σ public_input[i] · IC[i]. This involves doing some elliptic curve multiplication on G1. If you’re working with BN254, you’ll want to use ECADD/ECMUL (EIP‑196) and then run the pairing precompile (EIP‑197). For those on BLS12‑381, you can also take advantage of the G1/G2 MSM precompiles (EIP‑2537). Check out more details here.
- Verify the aggregated pairing equation(s):
- The Groth16 check, e(A,B) = e(α,β) · e(vk_x,γ) · e(C,δ), is nicely condensed into a logarithmic-size argument through SnarkPack’s inner-product reduction. In your on-chain code, you’ll likely end up running one or a few multi-pairing checks, with the number of pairs increasing at a rate of O(log k). (deepwiki.com)
3) Check Transcript Binding:
- When a verifier binds, it connects to several important elements: the circuit/VK hash, batch ID, chainId, the manifest root(s), and frequently the block number or domain separators used in Fiat-Shamir. This setup helps to guard against “mix-and-match” attacks that could happen across different circuits or chains. (This is a solid design pattern--make sure your library makes these fields public inputs.) (research.protocol.ai)
- Keep commitments light and trigger events:
- Save the manifest root(s) and batch ID; fire off an event with handy fields so that downstream contracts or indexers can easily link statements to a specific aggregated proof. (7blocklabs.com)
- Curves and keys:
- Go with BN254 if you need to work with older Groth16 circuits made by circom/snarkjs. If you've got control over both the prover and verifier and you’re looking for 128-bit security along with decent gas costs per pairing, then BLS12‑381 is your best bet. (docs.circom.io)
- Calldata layout:
- Keep it structured like this: [A_agg | B_agg | C_agg | manifest_root | vk_hash | domain_seps | small aux scalars]. It’s smart to keep public inputs small; try rolling up the per-instance IO into one or two Merkle roots. (deepwiki.com)
- Verification:
- Gather up the IC coefficients along with your public inputs, make that pairing precompile call just once with the necessary pairs, and you’ll get back a true or false.
- When it comes to gas planning, assume you're dealing with O(log k) pairs; use the EIP‑1108 or EIP‑2537 formula to keep track of your budget. (eips.ethereum.org)
- Post‑verify:
- For SSTORE: map batchId → manifest_root (this is optional if you’re only using logs).
- When it comes to events, don’t forget to emit
BatchSettled(batchId, manifest_root, vk_hash, k, curveId). (7blocklabs.com)
Operational SLOs you can actually hit
- Aggregation latency: SnarkPack pulls together 8,192 Groth16 proofs in about 8 to 9 seconds on a 32-core CPU. If you’re working with fewer proofs, keep in mind that it scales sub-linearly. For a range of 256 to 1,024 proofs, you can expect it to take just a few seconds on a single server. (research.protocol.ai)
- Off-chain verify time: It takes roughly 33 milliseconds to verify an aggregate of 8,192 proofs off-chain. When it comes to on-chain verification, you’ll mainly be looking at a few pairings and the size of the calldata, rather than the computational load. (research.protocol.ai)
- Throughput architecture:
- Set up several aggregation workers and close off batches based on either size or time limits (like “close every 2 seconds or at 2,048 proofs, whichever comes first”) to keep tail latency in check for downstream chains. (7blocklabs.com)
- If you’re aiming for Ethereum L1 after Pectra, it’s a good idea to go with BLS12‑381 verifiers for any new deployments; they’re a bit cheaper per pair, plus they offer stronger security. (eips.ethereum.org)
Best emerging practices for 2026 deployments
- Keep public inputs small
- Use hash or Merkle commits for big per-instance data; just pass the root as a public input in the aggregated proof. This way, the verification gas costs are mainly driven by a couple of pairings instead of calldata. (deepwiki.com)
- Bind everything in the transcript
- Make sure to throw in chainId, programId, vk_hash, and manifest_root(s) into the Fiat-Shamir transcript. This helps to prevent any replay attacks across different contracts or chains. (research.protocol.ai)
- Opt for BLS12‑381 when possible
- EIP‑2537 is up and running; each pairing gas is 32,600, starting with a base of 37,700, giving you about 128-bit security. BN254 is still a solid choice for older circuits and interoperability. (eips.ethereum.org)
- Emit, don’t save
- Just emit batch metadata as events; hang on to only what future on-chain users need to read right away (which is often nothing). (7blocklabs.com)
- Be mindful of proof sizing and gas
- If your aggregated proof is around 40 KiB, take into account EIP‑7623’s floor for data-heavy transactions. Design your settlement function to do enough work in the EVM (think verification, domain checks) to keep it within that 4/16 gas/byte range when you can; if not, plan for about 10/40. (eips.ethereum.org)
- Safely version and rotate VKs
- Hardcode the vk_hash in the verifier and provide an upgrade path only through a fresh contract address approved by governance to avoid any "VK drift." Tools like gnark/snarkjs produce VK-tied verifiers for you. (docs.gnark.consensys.io)
Pitfalls we see in audits
- VK drift or mixed circuits in one batch
- When aggregating proofs, stick to the same verification key (VK) unless your aggregator can handle different VKs and ties each one to its instance in the transcript. If you don’t, there’s a chance you’ll end up accepting “foreign” statements. Check out more about this here.
- Over-sharing public inputs
- If you post all public inputs for k proofs, you’ll end up inflating the calldata. Instead, commit to those inputs and keep your on-chain IO at a constant size. You can read more about it here.
- Ignoring EIP‑7623 in budgets
- Just a heads up: a 40 KiB aggregated proof can chew through 0.65-1.64 million gas just to get onto L1. Make sure you crunch the numbers based on your batch size and block targets. More details can be found here.
- Under‑estimating pairing count constants
- Keep in mind that O(log k) is a complexity class; your real-world constant will vary depending on the library choices and optimizations you make. It’s a good idea to validate this with your actual verifier before settling on SLAs. More insight is available here.
When aggregation is not the right hammer
- If you’ve got your proving stack all buttoned up from start to finish and you’re already diving into recursion (think STARK→SNARK, Halo2, and the like), then going for a single wrapped proof for each batch might actually save you some bucks (less proof size, similar pairing counts). On the other hand, aggregation really shines when you need to handle a bunch of separate Groth16s from different parties or circuits and you want to wrap it all up in one neat settlement transaction. (7blocklabs.com)
Implementation references you can adopt today
- Check out the SnarkPack paper and get the lowdown on the engineering side of things, including the inner-product pairing argument, an O(log n) verifier, and benchmarks that match Filecoin's standards. You can find it here.
- Let's talk about BN254 pairing and repricing, which are super important for most Groth16 verifiers (shoutout to EIPs 196/197/1108). If you want to dive deeper, head over to the details here.
- Don't miss the BLS12-381 precompiles (EIP-2537) and the Pectra meta-EIP list. These babies are essential for ensuring 128-bit security and making MSM/pairings a breeze. Check it out here.
- Lastly, if you're looking to work with Solidity verifiers, gnark and snarkjs have got exporters for you (BN254 and, with some backend updates, BLS12-381). Find the details here.
Decision checklist for your roadmap
- Target curve:
- Are we going with BN254 for legacy interop, or should we jump into BLS12‑381 (EIP‑2537) for the new systems? Check it out here: (eips.ethereum.org)
- Batch size targets:
- What’s our steady-state k and max k for each settlement window? Let's double-check those aggregation and calldata budgets with EIP‑7623. (eips.ethereum.org)
- Public IO handling:
- We need to commit using Merkle roots and keep the on-chain public inputs at a constant size. More info here: (deepwiki.com)
- Transcript binding:
- Make sure to include chainId, vk_hash, manifest_root(s), and batchId in the Fiat-Shamir transcript. Check this out: (research.protocol.ai)
- Ops SLOs:
- We need to budget aggregation latency (like, under 10 seconds for 8k proofs) and make sure we have parallel workers ready to roll. Get more details here: (research.protocol.ai)
If you're looking for us to create a concrete verifier contract and a gas/cost model that fits your circuits, we can prototype both the BN254 and BLS12‑381 paths for you. This way, you'll get a clear budget comparison based on the current EIP‑7623 rules and your specific calldata footprint. Check it out here: (eips.ethereum.org)
Footnotes and sources:
- For a deep dive into SnarkPack's performance and design, check out the research posts and project pages from Protocol Labs. (research.protocol.ai)
- If you're curious about Ethereum precompiles and gas formulas, you'll find the details in EIPs 196, 197, 1108, 2537, and the Pectra meta EIP. (eips.ethereum.org)
- The change to EIP‑7623 regarding calldata pricing, which is set to hit the mainnet on May 7, 2025, is covered in the Ethereum Foundation's blogs and the EIP text. (blog.ethereum.org)
- For some context on the Groth16 verification equation and proof structure, take a look here. (deepwiki.com)
Description
When you bring together thousands of Groth16 proofs, it simplifies on-chain verification down to just one O(log n) check. Now, the real costs mainly come from a few pairings and the size of the calldata as outlined in EIP-7623. After the Pectra update, the BLS12-381 precompiles (EIP-2537) ensure that aggregated verification is not just secure but also gas-efficient for real-world use. Check out more details on this here.
Like what you're reading? Let's build together.
Get a free 30-minute consultation with our engineering team.
Related Posts
ByAUJay
Building 'Private Social Networks' with Onchain Keys
Creating Private Social Networks with Onchain Keys
ByAUJay
Tokenizing Intellectual Property for AI Models: A Simple Guide
## How to Tokenize “Intellectual Property” for AI Models ### Summary: A lot of AI teams struggle to show what their models have been trained on or what licenses they comply with. With the EU AI Act set to kick in by 2026 and new publisher standards like RSL 1.0 making things more transparent, it's becoming more crucial than ever to get this right.
ByAUJay
Creating 'Meme-Utility' Hybrids on Solana: A Simple Guide
## How to Create “Meme‑Utility” Hybrids on Solana Dive into this handy guide on how to blend Solana’s Token‑2022 extensions, Actions/Blinks, Jito bundles, and ZK compression. We’ll show you how to launch a meme coin that’s not just fun but also packs a punch with real utility, slashes distribution costs, and gets you a solid go-to-market strategy.

