ByAUJay
I’m Designing a Bridge: Best Way to Aggregate Thousands of Plonk Proofs With BLS for One On-Chain Attest?
Summary: The fastest, cheapest way in 2026 to collapse thousands of PLONK proofs into a single on‑chain attestation on Ethereum is: verify proofs off‑chain, have a BLS12‑381 committee co‑sign one batch root, and verify that aggregate signature on‑chain using the Pectra-era BLS precompiles (EIP‑2537). For fully trustless settlement, combine this with periodic or continuous recursive aggregation (e.g., Halo2‑KZG/aPlonK) to produce a cryptographic super‑proof when latency allows. (eips.ethereum.org)
TL;DR for decision‑makers
- If you need sub‑second to low‑seconds latency and you’re cost‑sensitive: use BLS aggregate signatures over a single batch message (FastAggregateVerify) and verify on‑chain via EIP‑2537. Typical gas: ≈103k for the pairing check plus small overhead if you store an aggregated public key. (eips.ethereum.org)
- If you need hard, cryptographic finality with minimal trust in any committee: roll the proofs up off‑chain into one Halo2‑KZG/PLONKish aggregated proof and verify once on‑chain (≈350–420k gas per batch), optionally still gated by a BLS attestation to throttle inclusion. (docs.nebra.one)
Both approaches can be combined: BLS attestation for “fast path” settlement and periodic recursive aggregation for “final settlement.”
What changed since 2025 and why it matters
- Ethereum Pectra (May 7, 2025) activated EIP‑2537: native BLS12‑381 precompiles. You now have seven EC/pairing ops at fixed addresses 0x0b–0x11, with pairing gas 37,700 + 32,600 × k (k = pairs). This makes on‑chain BLS aggregate signature verification practical on L1 and L2s that inherit Pectra. (blog.ethereum.org)
- Cancun/Deneb (March 2024) added the KZG point‑evaluation precompile at 0x0a (exactly 50,000 gas) for blob commitments. You can bind a big batch manifest (hundreds of KB) to a transaction cheaply and refer to it in your attestation. (eips.ethereum.org)
Your design space: three viable aggregation patterns
- BLS-attested off‑chain verification (fastest, cheapest)
- Each prover (or an aggregator) checks many PLONK proofs off‑chain.
- A committee of N BLS signers signs one identical batch message M that commits to “all proofs in batch B verified.”
- On‑chain, verify one aggregate signature via EIP‑2537 using FastAggregateVerify (k = 2 pairings). Gas for the pairing core ≈ 37,700 + 2 × 32,600 = 102,900 gas; store/update an aggregated public key to avoid summing pubkeys on‑chain. (eips.ethereum.org)
- Security depends on your committee/incentives (e.g., restaked operators + slashing), not pure cryptography. Aligned Layer’s verification model is a production example of BLS‑attested off‑chain verification. (blog.alignedlayer.com)
- Cryptographic aggregation (trustless, higher latency)
- Aggregate many proofs into one using PLONKish accumulation/recursion (e.g., Halo2‑KZG, aPlonK). On‑chain verify once (≈350k–420k gas per batch) and let claimants present cheap inclusion proofs. This yields ≈20k–50k amortized gas per included proof for batch sizes in the 32–1,000 range. (docs.nebra.one)
- Prior art: SnarkPack for Groth16 (logarithmic verify), aPlonK for PLONK aggregation; production docs/measurements from Nebra UPA. (eprint.iacr.org)
- Hybrid (what we ship most)
- Submit a BLS‑attested batch immediately to meet latency/SLOs, and roll a cryptographic super‑proof periodically (e.g., every X minutes/blocks) for “hard” finality and auditability. This hedges against committee failures with bounded economic risk.
The BLS‑first architecture that works today
Below is a concrete, production‑grade pattern tuned for Ethereum post‑Pectra and Pectra‑aligned L2s.
1) Choose the BLS ciphersuite and serialization
- Use the IETF CFRG BLS12‑381 “minimal‑pubkey‑size, proof‑of‑possession” ciphersuite:
BLS_SIG_BLS12381G2_XMD:SHA‑256_SSWU_RO_POP_ (pubkeys in G1, signatures in G2; 48‑byte pubkeys, 96‑byte signatures; PoP at registration prevents rogue‑key attacks). This matches Ethereum consensus practice and has mature tooling. (docs.rs) - Hash‑to‑curve per RFC 9380. On‑chain, you can do hash_to_field (SHA‑256) in EVM and use the MAP_FP2_TO_G2 precompile (0x11) to map to G2; or precompute off‑chain and pass uncompressed points. (ietf.org)
Encoding details (EIP‑2537 ABI):
- G1 point: 128 bytes (x||y), G2 point: 256 bytes, big‑endian, uncompressed; infinity is all zeros. The pairing check costs 32,600 × k + 37,700 gas; mapping costs 5,500 (Fp→G1) / 23,800 (Fp2→G2). (eips.ethereum.org)
2) Register a committee with Proof‑of‑Possession
- At setup, each signer submits:
- pk_i (48‑byte compressed public key, expanded off‑chain to 128‑byte uncompressed G1 for precompile),
- PoP_i over a fixed domain string to prevent rogue‑key attacks,
- optional stake/bond to enable slashing.
- Store either:
- the whole validator set and maintain an “aggregated public key” AP = Σ pk_i in state, updated on churn events, or
- a Merkle root of the committee and an on‑chain AP updated only when the set changes.
This avoids adding O(N) G1 additions per verification. (G1ADD = 375 gas each if you ever need it.) (eips.ethereum.org)
3) Define the batch message M precisely
Use one identical message M for all signers (required for FastAggregateVerify). Make it self‑describing, resistant to replay across chains, and tied to the exact proofs you claim to have checked.
A robust byte layout:
M = keccak256(encode({ version: uint16, // protocol message version srcChainId: uint64, dstChainId: uint64, bridgeId: bytes16, // contract identity batchIndex: uint64, // monotonically increasing batchCount: uint32, // number of proofs claimed vkRoot: bytes32, // Merkle root of verifying keys used proofsRoot: bytes32, // Merkle root of per-proof commitments blobHash: bytes32, // OPTIONAL: EIP-4844 versioned-hash bound to manifest blob timeWindow: uint64[2], // [notBefore, notAfter] seconds since epoch dstProgram: bytes32, // what program/contract tuple is authorized to consume domainTag: "7BLK-PLONK-BATCH-v1" // DST for hash_to_curve per RFC 9380 }))
Notes:
- proofsRoot commits to a per‑proof tuple, e.g., (proofId, vkHash, pubInputsHash).
- blobHash, if present, binds a batch manifest in a blob (cheap DA); you can check the 0x0a point‑evaluation precompile or at least the versioned hash via the BLOBHASH opcode in the same transaction. (eips.ethereum.org)
4) Off‑chain workflow
- Aggregator(s) collect proofs, verify each PLONK proof off‑chain (any flavor: PLONK, TurboPLONK, Halo2‑KZG, etc.), and build:
- proofsRoot over proof descriptors,
- vkRoot over registered verifying keys actually used,
- optional 4844 blob carrying the manifest (proof descriptors, inclusion paths, etc.).
- The BLS committee signs M. Aggregate signatures off‑chain into S = Σ sig_i, and compute AP if needed (or use stored AP).
Performance reference: production systems that BLS‑attest off‑chain checks report batches settling on‑chain for ≈350k gas including bookkeeping, with the BLS verification itself ≈100–120k gas. (blog.alignedlayer.com)
5) On‑chain verification function sketch (FastAggregateVerify)
- Compute H = hash_to_field(M, domainTag), then MAP_FP2_TO_G2(H) to get H(M) in G2.
- Call the pairing precompile once with k = 2 pairs:
- Pair 1: (AP, H(M))
- Pair 2: (−G1, S)
- Accept iff e(AP, H(M)) · e(−G1, S) == 1.
Gas for the pairing core: ≈102,900 gas; mapping adds ≈23,800 if done on‑chain; keccak/SHA‑256 adds a few thousand gas. (eips.ethereum.org)
Implementation facts you’ll care about:
- EIP‑2537 performs subgroup checks in MSM/pairing. Don’t pass unvalidated additions into MSM; only store AP you computed from registered pubkeys. (eips.ethereum.org)
- Use the IETF domain‑separation guidance from RFC 9380; tag includes protocol name and version. (ietf.org)
Gas and latency you can actually budget for
- FastAggregateVerify on L1 with pre‑stored AP:
- Pairing: 102,900 gas (k = 2).
- Hash_to_field + map‑to‑curve: ~3k–5k + 23,800 gas if done on‑chain; many teams precompute H(M) off‑chain and pass the point directly.
- Total verification path: ~110k–135k gas, plus event/storage if you store batch metadata. (eips.ethereum.org)
- If instead you sum K pubkeys on‑chain, add ≈375 × (K−1) gas for G1ADD; hence the push to store AP in state. (eips.ethereum.org)
- Cryptographic aggregation reference (Halo2‑KZG batch verify):
- ≈350k gas to verify the aggregated proof + ~7–22k gas per included proof for bookkeeping/queries depending on your contract design; amortized ≈20k–50k gas per proof for reasonable N. (docs.nebra.one)
- Blob linkage (optional): the 0x0a point‑evaluation precompile is a flat 50,000 gas per check. Use it if your bridge contract must verify a value from the blob on‑chain (e.g., a spot consistency check). (eips.ethereum.org)
Security and ops guardrails (don’t skip these)
- Rogue‑key resistance: enforce Proof‑of‑Possession at key registration and re‑registration; reject keys without PoP. Use the POP ciphersuite. (datatracker.ietf.org)
- Replay safety: include src/dst chain IDs, bridge contract ID, and a monotonically increasing batchIndex in M. Expire stale signatures with timeWindow.
- Liveness/redundancy: at least 2 aggregators and an M‑of‑N committee. If you use restaking (e.g., AVSs), slash operators that sign invalid batches or miss deadlines. (blog.alignedlayer.com)
- Anti‑censorship: optionally support both on‑chain and off‑chain proof submission paths. On‑chain submissions cost more but are harder to censor; this is how Nebra UPA balances economics with safety. (docs.nebra.one)
- Blob hygiene: if you use blobHash, record the versioned hash and, if necessary, call the 0x0a precompile on critical values. Never assume application contracts can retrieve blob bytes; reference commitments instead. (eips.ethereum.org)
- Upgradability: keep the verifier behind a timelock or point to an upgradeable verifier target so you can swap BN254↔BLS12‑381 paths without migrating all state. (7blocklabs.com)
Where PLONK‑level aggregation still shines
Even with cheap BLS:
- Compliance/finality: Some counterparties require a cryptographic proof of inclusion/validity, not just a committee signature. Aggregated Halo2‑KZG or aPlonK proofs give you that with one on‑chain verify. (eprint.iacr.org)
- Large‑N economics: At N in the thousands, amortized per‑proof costs via cryptographic aggregation drop below any signature‑per‑proof model, especially when end users need inclusion checks later (~16–22k gas each). (docs.nebra.one)
- Multi‑system compatibility: SnarkPack can aggregate Groth16 proofs from heterogeneous producers; similar lines exist for PLONK variants. If your ecosystem is mixed, “universal” aggregation buys simplicity. (eprint.iacr.org)
A concrete example bridge plan (what we’d ship in 6–8 weeks)
- Committee + contracts
- Deploy CommitteeRegistry with PoP‑verified BLS public keys and keep AP in state.
- Deploy BridgeAttestor with verifyBatch(M, S) using EIP‑2537 precompiles; store batch roots and emit events. (eips.ethereum.org)
- Batch format
- Each proof descriptor d_i = keccak256(vkHash_i || pubInputsHash_i || proofId_i).
- proofsRoot = MerkleRoot(d_1…d_N).
- Optionally embed the manifest in a blob; record blobHash in M. (eips.ethereum.org)
- Off‑chain
- Aggregators verify all proofs, build the manifest, post a blob‑carrying tx, then solicit BLS signatures over the exact M.
- Aggregate signatures S and submit once to BridgeAttestor.verifyBatch.
- Consumption path
- Consumers on destination chain call isBatchValid(batchIndex) and present a Merkle path to d_i to claim.
- For higher assurance windows, schedule a parallel recursive aggregation job every Y minutes; post the aggregated proof to an AggregatedVerifier contract. (docs.nebra.one)
Budget example:
- N = 1,024 PLONK proofs
- BLS verify once: ≈110–135k gas.
- Each claimant’s inclusion check (Merkle path + small bookkeeping): typically 15–25k gas.
- Optional aggregated super‑proof: ≈350–420k gas once per batch if/when produced. (docs.nebra.one)
PLONK‑specific tuning tips
- Use SHPLONK‑style multi‑opening to minimize on‑chain verifier cost if you insist on direct PLONK verifies; otherwise keep everything off‑chain and just commit to vkRoot and proofsRoot. (hackmd.io)
- If your stack already targets BLS12‑381 (KZG), Pectra removed the main obstacle to verifying BLS‑curve proofs natively on EVM. Re‑evaluate any legacy BN254 wrapping purely “for the precompiles.” (eips.ethereum.org)
- For recursion, Halo2‑KZG with modern accumulation schemes and GPU provers can build 32‑way batches in a few seconds; plan batches around your arrival rate λ (N/λ is your fill time). (docs.snarkify.io)
When to pick which (quick rubric)
- Latency SLO ≤ 5s and economic finality is fine: BLS attestation only.
- Latency SLO 5–30s and auditors demand crypto proofs: BLS now, aggregate proof every 1–5 minutes.
- High‑value bridge where courts or counterparties require mathematical finality per batch: aggregated proof every batch; optionally still use BLS for a fast pre‑attestation.
References you can hand to engineering and audit
- EIP‑2537 (BLS12‑381 precompiles): addresses, ABIs, gas (pairing: 37,700 + 32,600·k; map precompiles 0x10/0x11). (eips.ethereum.org)
- EIP‑4844 (KZG point‑evaluation precompile 0x0a, 50,000 gas): for blob‑bound manifests. (eips.ethereum.org)
- Pectra mainnet activation (May 7, 2025; epoch 364032). (blog.ethereum.org)
- IETF RFC 9380 (Hashing to Elliptic Curves) and CFRG BLS signature draft (ciphersuites incl. POP). (ietf.org)
- PLONK/Groth16 aggregation: aPlonK and SnarkPack. (eprint.iacr.org)
- Production aggregation economics and gas numbers (Nebra UPA; verification layers). (docs.nebra.one)
Bottom line
- If your question is “what’s the best way to aggregate thousands of PLONK proofs into one on‑chain attest for a bridge”: do off‑chain verification + one BLS aggregate signature over a carefully designed batch root M, and verify it with EIP‑2537’s pairings. It’s fast, cheap, and now first‑class on Ethereum.
- If you need stronger assurances (or want to compress per‑claim gas further), add a periodic Halo2‑KZG/aPlonK super‑proof. The hybrid gets you the latency of BLS and the cryptographic finality of ZK, with clean operational boundaries.
If you’d like, we can share a hardened Solidity snippet for FastAggregateVerify using the 0x0f pairing precompile, and a tested message encoder/hasher aligned with RFC 9380 and the POP ciphersuite, plus a batch manifest template that plugs into your bridge contracts. (eips.ethereum.org)
Like what you're reading? Let's build together.
Get a free 30‑minute consultation with our engineering team.

