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

**URL:** <https://forum.zcashcommunity.com/t/grant-application-batch-vs-single-verification-equivalence-continuous-soundness-fuzzing-for-zcash-shielded-verification-incl-ironwood/56308>\
**Category:** Community Grants\
**Created:** [June 21, 2026, 2:51pm UTC](https://forum.zcashcommunity.com/t/grant-application-batch-vs-single-verification-equivalence-continuous-soundness-fuzzing-for-zcash-shielded-verification-incl-ironwood/56308 "2026-06-21T14:51:56Z")\
**Posts on this page:** 1\
**Showing post:** 7

<div class="post-metadata">

**Author:** ![robustfengbin](https://sea2.discourse-cdn.com/zcash/user_avatar/forum.zcashcommunity.com/robustfengbin/32/42095_2.png) [@robustfengbin](https://forum.zcashcommunity.com/u/robustfengbin)\
**Post date:** [September 24, 2026, 4:34am UTC](https://forum.zcashcommunity.com/t/grant-application-batch-vs-single-verification-equivalence-continuous-soundness-fuzzing-for-zcash-shielded-verification-incl-ironwood/56308/7 "2026-09-24T04:34:15Z")

</div>

Hi all — Milestone 3, the last milestone of the batch-verification equivalence grant (#332), is delivered.  
Repo: [GitHub - robustfengbin/zebra-batch-equivalence · GitHub](https://github.com/robustfengbin/zebra-batch-equivalence) — `git clone --branch m3` → `cargo test` reproduces the test results, and the report’s _Reproducing this_ gives the command for every number. `reports/m3-final-security-report.md` is the final security report: each deliverable mapped to the grant text, the findings of all three milestones, the limitations, and what keeps running after the grant. Base: Zebra v6.3.0 (f5c5277f). This post is also the September update.

**What M3 adds**

1. **Ironwood under the oracle, on real mainnet traffic.** The NU6.3 corpus is 172 post-activation mainnet transactions (249 verification items), extracted from a standing node rather than built from the spec, so the spec-adapter fallback the grant allowed was not needed. Ironwood is covered on all five surfaces — base equivalence, deep invariants, adversarial batches, the turnstile and fuzzing — including mixed Orchard/Ironwood batches taken from a single v6 transaction, and adversarial batches that straddle the pool boundary. The two paths agreed throughout.

2. **The turnstile target.** The grant names three properties: conservation, no double-migration, no forged residual value crossing. The obvious reading of conservation — a migration’s two pool balances cancel — fails on all 77 real two-pool transactions, so the check is the fee identity instead, which holds on 172 of 172 with every fee a positive multiple of 5,000 zatoshi. Replaying the corpus is caught as double-migration, nullifier for nullifier. The third property cannot be read from a window in the middle of the chain, because what the pools held before it is unknown; it is checked in both directions on constructed runs from an empty chain, and the report says so rather than counting it as tested on mainnet.

3. **Continuous fuzzing on a schedule.** Nine fuzz targets — every batch verifier, Zebra’s batching middleware and the turnstile — run under ClusterFuzzLite in the repository: every day it prunes the corpus, fuzzes each target, and checks per target that it got past its stored corpus into new inputs; a weekly job publishes coverage ([https://robustfengbin.github.io/zebra-batch-equivalence-corpora/coverage/latest/report/linux/report.html](https://robustfengbin.github.io/zebra-batch-equivalence-corpora/coverage/latest/report/linux/report.html)). The regression corpus is kept in a dedicated repository, `zebra-batch-equivalence-corpora`.  
Since 2026-09-23 it has run on its schedule: one scheduled run so far at delivery, green, with all nine targets past their stored corpus. The runs before that were started by hand.

**Findings**

No disagreement between the two paths about Zcash, in any milestone: zero divergences in either direction across every real corpus. The behaviour reported in M2 — a rejected Sapling bundle leaving residue in a shared batch — stands as written there.

M3’s three findings are about the instrument. Two share a shape worth naming: each produced _no answer_, which looks exactly like a correct one. The fuzz seeds for the four core targets were chosen by filename, and for the pre-NU6.2 era — the circuit the June 5 incident lived in — the six seeds shipped for it reached the verifier zero times, while nine targets were green with healthy execution counts. And the turnstile’s fuzz assertion compared something no input order could change, so it could not fail. The third is the inverse: on its first day the continuous run raised a critical that was the harness misreading a mutated control byte, not a verifier accepting anything. All three are fixed, with tests that fail if they come back.

**Cost of the check**

Batch verification is 5.1–5.8× faster than single verification on the same machine (40 alternating runs across two build profiles) — which is why the batch path exists, and why its agreement with the single path is worth asserting continuously. M2’s 4.5–7.8× across two machines stands alongside it.

**Tests and reproduction**

`cargo test --workspace --locked` on the `m3` tree, 2026-09-23: 113 passed · 0 failed · 1 ignored, exit code 0 — 22 test harnesses, 19 of them carrying tests.

```auto
git clone --branch m3 https://github.com/robustfengbin/zebra-batch-equivalence
cd zebra-batch-equivalence
cargo test

```

**After the grant**

The daily ClusterFuzzLite run keeps going in this repository; its storage token is on the grantee’s account, so for now it is “self-running”, not yet “no further involvement from the grantee”. Moving the targets into `zebra-fuzz/` and OSS-Fuzz is the hand-off, and it waits on #11492. If a run ever shows the batch path accepting what the single path rejects, that is a possible soundness bug in shipping verification code: it should go privately to [security@zfnd.org](mailto:security@zfnd.org) with the crash file, not to a public issue.

Thanks to ZCG for funding this, and to the Zebra maintainers for reviewing and merging the upstream fuzzing work along the way.

---

_[View the full topic](https://forum.zcashcommunity.com/t/grant-application-batch-vs-single-verification-equivalence-continuous-soundness-fuzzing-for-zcash-shielded-verification-incl-ironwood/56308)._
