Grant Application - Batch-vs-Single Verification Equivalence: Continuous Soundness Fuzzing for Zcash Shielded Verification (incl. Ironwood)

Hello everyone, I am submitting a proposal to Zcash Community Grants (ZCG) to build a continuous batch-verification soundness oracle for Zebra — a differential fuzzing harness that asserts Zebra’s shielded-proof and signature batch verification accepts a set of items if and only if every item also verifies individually. This is a direct continuation of ZCG #234 (Zebra Coverage-Guided Fuzzing Infrastructure) , reusing its corpus and harness scaffolding.

Why This Matters

Zebra verifies shielded proofs and signatures in batches for performance. A batching-layer bug that accepts a batch containing one invalid item — a false-accept — is a silent soundness failure, the same threat class that underlies counterfeiting. Today it’s asserted by neither place you’d expect: production uses a batch-first, single-fallback pattern (tower-fallback ) that only retries items after a batch fails — self-correcting false-rejects but blind to false-accepts ; and the existing fuzz harness checks only for panics, not soundness . Upstream Zebra ships no batch-vs-single equivalence test . The June 5 Orchard incident showed a shielded-verification soundness break can hide for years — that bug was in the circuit ; the batch-verification glue is a distinct, equally-unguarded surface (this oracle is complementary to circuit analysis, not a substitute). With NU6.2 just activated and Ironwood next, the area is actively changing.

Project Overview

A continuous differential oracle that runs both real paths — batch (BatchValidator ) and single (Item::verify_single ) — and asserts they agree, across all four Zebra batch verifiers (Orchard halo2, Sapling/Sprout Groth16, Orchard RedPallas, Sapling RedJubjub), driven by adversarial corpora that hide one invalid item among valid ones, and extended to the new Ironwood pool + turnstile migration, integrated into continuous CI.

Technical Approach

Built on the cargo-fuzz / libFuzzer + ASan scaffolding from #234. Adversarial corpus = real mainnet V5 valid bases + single-element tampering (corrupt a proof / swap a nullifier / perturb a signature scalar / replace a public input) + batch-composition fuzzing (size, ordering, duplicates, empty/singleton) — batching bugs live in the aggregation glue, not the per-item math.

Deliverables and Milestones (3 milestones, ~3 months)

  • M1 — Dual-path equivalence framework + Orchard
  • M2 — Adversarial corpus + all four verifiers + coverage reporting
  • M3 — Ironwood pool + turnstile soundness target + continuous CI (ClusterFuzzLite / OSS-Fuzz)

Budget

  • Startup Funding: $3,000
  • Milestones 1–3: $42,000 ($15,000 / $15,000 / $12,000)
  • Total: $45,000

Design Principles

  • Standalone / non-invasive: drives Zebra through public APIs; no consensus code changes.
  • Sustainable: CI / OSS-Fuzz keeps the assertion running after the grant — even at zero findings, the machine is a durable ecosystem asset.
  • Community-oriented: open repo + corpus, reusable by ZF, Zebra maintainers, and future auditors.

Track Record

Continues ZCG #234, whose M1/M2 work surfaced several Zebra security issues credited to the project lead — including CVE-2026-34202 (Critical, V5 transaction DoS), GHSA-c8w6-x74f-vmg3 (Moderate, Sapling-receiver DoS), and issues #10534 and #10544 . Full proposal details: Grant Application - Batch-vs-Single Verification Equivalence: Continuous Soundness Fuzzing for Zcash Shielded Verification (incl. Ironwood) · Issue #332 · ZcashCommunityGrants/zcashcommunitygrants · GitHub

Thank you for your time and feedback.

1 Like