Zero-Knowledge WHIR II: Code-Switching in the Dark

May 30, 2026

Where Part 1 left us

Part 1 built the foundations of an HVZK IOPP for constrained interleaved codes:

  • Zero-knowledge encodings. Randomized encodings EncC ⁣:F×FrΣm\mathsf{Enc}_{\mathcal C} \colon \mathbb F^\ell \times \mathbb F^r \to \Sigma^m where any t\leq t coordinates of the codeword can be simulated from positions alone.
  • The committed sumcheck relation RC,Czk,sl\mathcal R_{\mathcal C, \mathcal C_{\mathsf{zk}}, \mathsf{sl}}. Succinct linear forms to kill the verifier’s Ω()\Omega(\ell) cost, plus small mask oracles folded into a joint constraint to hide the target μ\mu.
  • Composable HVZK for IORs. The standard HVZK definition breaks under composition (Part 1’s IOR1IOR2\mathsf{IOR}_1 \circ \mathsf{IOR}_2 counterexample). Fix: a distinguisher class D\mathcal D that the simulator must additionally handle, and a composition theorem that chains errors ζ1+ζ2\zeta_1 + \zeta_2 across the seam.
  • HVZK sumcheck reduction. Reduces a 2k2^k-interleaved code to its base code via small per-round masks (not a full 2×2\times mask), with mask oracles carried forward through the joint constraint. Drops problem size by a factor of 2k2^k at sublinear masking cost.

We can now test the interleaving of any zero-knowledge code in zero knowledge — by reducing to the base code. But the base code is still big. To get a polylog verifier we need to recursively shrink the code, and the move that does that is code-switching: an IOR from a test for code C\mathcal C to a test for some smaller code C\mathcal C'.

The non-zero-knowledge version is well-trodden ([RR20]; [BCFW25]; WHIR’s recursion shape). The zero-knowledge version breaks in two distinct places. This part fixes both, assembles the HVZK WHIR/Ligerito corollary, and tackles the R1CS reduction.

Code-switching without zero-knowledge

Code-switching follows a clean template. The verifier has an oracle ff that — honestly — equals C(m)\mathcal C(\boldsymbol m) for some message m\boldsymbol m satisfying a predicate Φ\Phi. The prover wants to convince the verifier of this fact using a smaller proximity test.

  1. Prover sends gg. A new oracle g(Σ)mg \in (\Sigma')^{m'}. In the honest case, g=C(m)g = \mathcal C'(\boldsymbol m) — the same message encoded under the new, smaller code C\mathcal C'.
  2. Verifier spot-queries ff. Sample x1,,xt[m]x_1, \dots, x_t \in [m], query f(x1),,f(xt)f(x_1), \dots, f(x_t).
  3. Run a proximity protocol for the new claim ”gg encodes some m\boldsymbol m such that Φ(m)=1\Phi(\boldsymbol m) = 1 and C(m)[xi]=f(xi)\mathcal C(\boldsymbol m)[x_i] = f(x_i) for every ii.”

The added clauses C(m)[xi]=f(xi)\mathcal C(\boldsymbol m)[x_i] = f(x_i) are the consistency check: they tie the new oracle’s message to the old oracle’s message. Without them, the prover could swap m\boldsymbol m at the switch.

This template is everywhere — [RR20], [RR22], [BCFW25], the [BMMS25] family of FICS/FACS protocols, WHIR’s recursion. It has not been applied to zero-knowledge codes outside [RW24], whose construction leans on specific properties of zero-knowledge tensor codes. We need a code-agnostic ZK version.

Why ZK encodings break the template

The first break: the consistency check assumes the codeword is a function of the message alone. With a ZK encoding it isn’t.

Concretely, f=EncC(m,r)f = \mathsf{Enc}_{\mathcal C}(\boldsymbol m, \boldsymbol r) depends on both the message and the randomness. The consistency check C(m)[xi]=f(xi)\mathcal C(\boldsymbol m)[x_i] = f(x_i) doesn’t even type-check anymore — you need r\boldsymbol r to predict ff.

The obvious fix: have gg encode both the message and the randomness under C\mathcal C'. That works, but it requires padding gg‘s message space, which means gg is twice the size, every subsequent sumcheck operates on a 2×2\times-blown object, and we’re back to 2×\geq 2\times overhead. Dead.

The actual fix reuses the committed sumcheck relation. Introduce an additional mask s=EncCzk(r,r)s = \mathsf{Enc}_{\mathcal C_{\mathsf{zk}}}(\boldsymbol r, \boldsymbol r'') encoding the randomness r\boldsymbol r under the ZK mask code Czk\mathcal C_{\mathsf{zk}}. Now write the per-symbol claim by splitting EncC\mathsf{Enc}_{\mathcal C}‘s generator matrix into a message part and a randomness part: GC=[GCmsgGCrnd]G_{\mathcal C} = [G_{\mathcal C}^{\mathrm{msg}} \mid G_{\mathcal C}^{\mathrm{rnd}}] where GCmsgG_{\mathcal C}^{\mathrm{msg}} acts on the message and GCrndG_{\mathcal C}^{\mathrm{rnd}} acts on the randomness. Then

f(x)  =  EncC(m,r)[x]  =  m,GCmsg[x]+r,GCrnd[x],f(x) \;=\; \mathsf{Enc}_{\mathcal C}(\boldsymbol m, \boldsymbol r)[x] \;=\; \langle \boldsymbol m,\, G_{\mathcal C}^{\mathrm{msg}}[x] \rangle + \langle \boldsymbol r,\, G_{\mathcal C}^{\mathrm{rnd}}[x] \rangle,

which is a linear constraint on (m,r)(\boldsymbol m, \boldsymbol r). The first piece accumulates into the existing main-oracle constraint via the succinct linear form sl\mathsf{sl}'; the second piece accumulates as a constraint on the mask ss. Both go into the joint constraint of the next committed sumcheck relation. No padding, no 2×2\times.

That handles the randomness break. But the bigger break is structural: the WHIR-style recursion uses out-of-domain sampling in the list-decoding regime, and OOD’s whole job is to leak information.

OOD sampling and the second tension

Quick recap (see the WHIR post for the proper treatment). In the list-decoding regime — where the verifier picks a proximity parameter δ\delta larger than the unique-decoding radius — multiple codewords in Λ(C,f,δ)\Lambda(\mathcal C, f, \delta) can be close to a malicious oracle ff. The verifier needs a way to force the prover to commit to one codeword, not a list.

OOD sampling does this by an additional constraint. After the prover sends ff, the verifier samples randomness ρDze\rho \leftarrow D_{\mathsf{ze}}, the prover sends a vector y:=ze(ρ)f\boldsymbol y := \mathsf{ze}(\rho) \cdot \boldsymbol f for a fixed function ze ⁣:DzeFtood×\mathsf{ze} \colon D_{\mathsf{ze}} \to \mathbb F^{t_{\mathsf{ood}} \times \ell}, and the verifier subsequently checks ze(ρ)C1(f)=y\mathsf{ze}(\rho) \cdot \mathcal C^{-1}(f) = \boldsymbol y. For appropriate ze\mathsf{ze}, with high probability over ρ\rho at most one codeword in Λ(C,f,δ)\Lambda(\mathcal C, f, \delta) satisfies this constraint. Once a single codeword is pinned, list-decoding-regime soundness becomes manageable.

Now look at y\boldsymbol y. It’s a linear function of the witness message m\boldsymbol m with toodt_{\mathsf{ood}} \cdot \ell public coefficients. The prover sends it in the clear. It leaks information about m\boldsymbol m, hence about the witness.

And the leak is inherent. OOD is designed to uniquely identify the codeword (i.e., the witness). Zero-knowledge forbids revealing the witness. The two cannot literally coexist — you have to weaken one.

The paper weakens neither. It restructures OOD so the leak hits randomness instead of the witness.

Zero-evaders and private zero-evaders

The revised OOD sample is

y  :=  ze(ρ)[mr],\boldsymbol y \;:=\; \mathsf{ze}(\rho) \cdot \begin{bmatrix} \boldsymbol m \\ \boldsymbol r \end{bmatrix},

with the difference being that the linear function ze\mathsf{ze} now mixes both the message and freshly sampled randomness rFr\boldsymbol r \leftarrow \mathbb F^r. The function ze\mathsf{ze} is asked to satisfy two conditions:

  1. It’s still a good OOD sample. Equivalently, ze\mathsf{ze} is a zero-evader [BCFW25]: for every nonzero vector v\boldsymbol v, PrρDze[ze(ρ)v=0]εzero.\Pr_{\rho \leftarrow D_{\mathsf{ze}}}\big[\mathsf{ze}(\rho) \cdot \boldsymbol v = \boldsymbol 0\big] \leq \varepsilon_{\mathsf{zero}}. I.e. the matrix ze(ρ)\mathsf{ze}(\rho) is, in expectation, full-rank enough to detect any nonzero input difference. This is what enables list-decoding-regime soundness.
  2. It leaks no information about m\boldsymbol m. Formalized: ze\mathsf{ze} is an (r,ζze)(r, \zeta_{\mathsf{ze}})-private zero-evader — here rNr \in \mathbb N is the number of fresh randomness coordinates absorbed into the OOD sample — if (y,ρ)(\boldsymbol y, \rho) can be efficiently simulated, with statistical error at most ζze\zeta_{\mathsf{ze}}, without knowing m\boldsymbol m.

The two conditions look like they should pull in opposite directions: condition (1) wants ze(ρ)\mathsf{ze}(\rho) to depend richly on the input; condition (2) wants y\boldsymbol y to look uniform regardless of m\boldsymbol m.

Lemma (informal, Lemma 2.13). They don’t. Any zero-evader ze\mathsf{ze} with error εzero\varepsilon_{\mathsf{zero}} can be extended — by absorbing rr extra randomness columns for any rNr \in \mathbb N — to an (r,0)(r, 0)-private zero-evader with approximately the same error. Perfect privacy is achievable, and private zero-evaders are plentiful.

Intuitively: extra randomness in r\boldsymbol r gives the message-part of y\boldsymbol y a freshly random mask that doesn’t affect zero-evasion. The OOD claim still pins a single message, but the corresponding y\boldsymbol y is uniform over Ftood\mathbb F^{t_{\mathsf{ood}}} from the verifier’s perspective.

Side-by-side comparison: left, non-ZK OOD computes y = ze(ρ) · m and ships y in the clear, leaking a linear function of the witness message; right, private-zero-evader OOD computes y = ze(ρ) · (m, r) by mixing m with freshly sampled randomness r, so y is uniform from the verifier's view while ze still pins a unique message.

The crux: why the unique codeword still gets pinned

Here’s the subtlety that does the actual work — and the part the paper spends real care on.

In the non-ZK OOD lemma of [BCFW25], the consistency ze(ρ)C1(f)=y\mathsf{ze}(\rho) \cdot \mathcal C^{-1}(f) = \boldsymbol y pins a unique codeword near ff. But in the ZK setting, the encoding has redundancy: many distinct (mi,ri)(\boldsymbol m_i, \boldsymbol r_i) pairs encode to nearby codewords. We can no longer hope to pin a unique pair.

The paper’s generalization of the lemma (Lemma 2.14) gives up that hope cleanly:

Lemma (informal, Lemma 2.14). Allow many pairs (f1,s1),(f2,s2)(f_1, s_1), (f_2, s_2) near the original codewords to satisfy the OOD constraint ze(ρ)(fi,si)=ze(ρ)(fj,sj)\mathsf{ze}(\rho) \cdot (\boldsymbol f_i, \boldsymbol s_i)^\top = \mathsf{ze}(\rho) \cdot (\boldsymbol f_j, \boldsymbol s_j)^\top. But enforce that the message parts must be equal: fi=fj\boldsymbol f_i = \boldsymbol f_j (and si=sj\boldsymbol s_i = \boldsymbol s_j) except with probability Λ(C,δ)2Λ(Czk,δzk)2εzero|\Lambda(\mathcal C, \delta)|^2 \cdot |\Lambda(\mathcal C_{\mathsf{zk}}, \delta_{\mathsf{zk}})|^2 \cdot \varepsilon_{\mathsf{zero}}.

This is the moment ZK and list-decoding stop being in tension. In the non-ZK world we needed the codeword to be unique to control soundness. In the ZK world, the codeword can’t be unique (privacy demands it isn’t), but its message can be — and the message is what soundness actually cares about. The OOD constraint, restated against messages instead of codewords, lets us keep list-decoding-regime efficiency while making the actual encoded oracle a uniformly random sample from a large set.

The proof is straightforward once you stare at it. Fix distinct (f1,s1),(f2,s2)(\boldsymbol f_1, \boldsymbol s_1), (\boldsymbol f_2, \boldsymbol s_2). If they agree as messages we’re done. Otherwise the difference (f1f2,s1s2)(\boldsymbol f_1 - \boldsymbol f_2, \boldsymbol s_1 - \boldsymbol s_2) is a nonzero vector, and zero-evasion bounds the probability that ze(ρ)\mathsf{ze}(\rho) kills it by εzero\varepsilon_{\mathsf{zero}}. Union-bound over the pairs in Λ(C,δ)×Λ(Czk,δzk)\Lambda(\mathcal C, \delta) \times \Lambda(\mathcal C_{\mathsf{zk}}, \delta_{\mathsf{zk}}).

Equivalence-class diagram for Lemma 2.14: the product list Λ(C,δ) × Λ(C_zk, δ_zk) of nearby (codeword, mask) pairs is partitioned into colored classes by the underlying message; many distinct (f_i, s_i) pairs may satisfy the OOD constraint, but the lemma forces every satisfying pair into one message class, so soundness still pins the message even though the codeword is no longer unique.

There’s one last knot. The fresh randomness r\boldsymbol r must be included in the code-switch claim too — otherwise the next round won’t know about it. Padding r\boldsymbol r into C\mathcal C' would reintroduce the 2×2\times overhead we were just trying to avoid. The fix: a joint OOD sample of both gg and the mask ss, treating the pair as one object. The committed sumcheck relation, with its accumulating joint constraint, is exactly the right vehicle for this — and the entire reason it was designed the way it was.

The code-switch construction

Putting all four pieces together — ZK-encoding-aware consistency, the joint OOD sample, the private zero-evader, and the committed sumcheck relation — gives the construction. At a high level it does the following.

  1. Prover sends gg and ss. Honestly: g:=EncC(m,r)g := \mathsf{Enc}_{\mathcal C'}(\boldsymbol m, \boldsymbol r') — the same message under the smaller code, with fresh randomness rFr\boldsymbol r' \leftarrow \mathbb F^{r'}. And s:=EncCzk((s,r),r)s := \mathsf{Enc}_{\mathcal C_{\mathsf{zk}}}((\boldsymbol s, \boldsymbol r), \boldsymbol r'') — a mask encoding additional fresh randomness sFzkr\boldsymbol s \in \mathbb F^{\ell_{\mathsf{zk}} - r} concatenated with the original randomness r\boldsymbol r.
  2. Verifier sends OOD randomness ρDze\rho \leftarrow D_{\mathsf{ze}}.
  3. Prover replies with yFtood\boldsymbol y \in \mathbb F^{t_{\mathsf{ood}}}. Honestly: y:=ze(ρ)(m,r,s)\boldsymbol y := \mathsf{ze}(\rho) \cdot (\boldsymbol m, \boldsymbol r, \boldsymbol s)^\top — the joint OOD sample over message and both pieces of mask.
  4. Verifier sends in-domain queries. x1,,xt[m]x_1, \dots, x_t \leftarrow [m] for consistency, plus a batching scalar ε\boldsymbol \varepsilon.
  5. Verifier reads f(x1),,f(xt)f(x_1), \dots, f(x_t) and combines everything into a new target
μ  :=  μ+iεiyi+i,lεf(xi)l,\mu' \;:=\; \mu + \sum_i \varepsilon_i \cdot y_i + \sum_{i, l} \varepsilon_{\dots} \cdot f(x_i)_l,

producing a fresh committed-sumcheck instance over (C,Czk,sl)(\mathcal C', \mathcal C_{\mathsf{zk}}, \mathsf{sl}') whose joint constraint pulls in:

  • the original main-oracle constraint, restated as a succinct linear form sl\mathsf{sl}' evaluating to Fold(sl(st),γ)\mathsf{Fold}(\mathsf{sl}(\mathsf{st}), \boldsymbol \gamma) at the right state,
  • the original mask-oracle constraints ξi,ui\langle \boldsymbol \xi_i, \boldsymbol u_i \rangle,
  • the joint OOD constraint iεi(m,r,s),zei(ρ)\sum_i \varepsilon_i \cdot \langle (\boldsymbol m, \boldsymbol r, \boldsymbol s), \mathsf{ze}_i(\rho) \rangle,
  • the consistency constraints i,lε(m,r),GC[xi,l]\sum_{i, l} \varepsilon_{\dots} \cdot \langle (\boldsymbol m, \boldsymbol r), G_{\mathcal C}[x_{i, l}] \rangle derived from the generator-matrix split.

All four are linear in the underlying messages, so they pack into one joint constraint.

Message-flow diagram for the code-switch IOR: prover sends g = Enc_{C'}(m, r') and mask s = Enc_{C_zk}((s, r), r''); verifier sends OOD randomness ρ; prover replies with joint OOD answer y = ze(ρ) · (m, r, s); verifier issues in-domain consistency queries x_1,…,x_t and batching scalars ε, reads f(x_i), and assembles μ' that bundles the original main-oracle constraint, the mask-oracle constraints, the joint OOD constraint, and the consistency constraints into the next committed sumcheck instance over (C', C_zk, sl').

A counterintuitive efficiency property: the prover and verifier time of this code-switch are independent of the starting code C\mathcal C. The dominant cost is the encoding under C\mathcal C' (the new, smaller code) and the verifier’s computation of μ\mu'. The starting code’s structure pushes through into the next relation’s succinct linear form sl\mathsf{sl}' — captured by a quantity TCT_{\mathcal C} the paper calls the code-switching friendliness of C\mathcal C — but doesn’t show up in this protocol’s local cost. People reach for “the slow code makes the switch slow”; that’s not what happens.

From building blocks to the theorems

Compose the HVZK sumcheck reduction (Part 1) with the code-switch IOR above, all of it under the composable HVZK-for-IORs framework, and three named theorems fall out. The composition is sound exactly because each IOR explicitly handles the “future distinguisher” — namely, the simulator of whatever IOR consumes its output — so HVZK chains end-to-end.

Theorem 1 — sublinear HVZK IOPP

Compose two things: the HVZK sumcheck reduction (Part 1’s §6), reducing RC2k,Czk,sl\mathcal R_{\mathcal C^{\equiv 2^k}, \mathcal C_{\mathsf{zk}}, \mathsf{sl}} to RC,Czk,sl\mathcal R_{\mathcal C, \mathcal C_{\mathsf{zk}}, \mathsf{sl}'}; followed by a non-succinct base-case HVZK IOPP (a generalization of the simple 2×2\times-overhead protocol from §2.2 of the paper, applied at a much smaller scale).

The sublinear regime comes from picking 2kmC2^k \approx m_{\mathcal C} — i.e. setting the interleaving factor to roughly the codeword block length. Then the encoded message in C2k\mathcal C^{\equiv 2^k} has size =2k\ell = 2^k \cdot \ell' with \ell' \approx \sqrt{\ell}, the post-reduction instance is \sqrt{\ell}-sized, and the base-case IOPP (which does pay 2×2\times overhead) runs on a N\sqrt{N}-size sub-instance. Total proof length: O(N)\approx O(\sqrt{N}) alphabet symbols. Verifier time: sublinear. Overhead vs the non-private IOPP: o(1)o(1) — because the 2×2\times from the base case is amortized over a N\sqrt{N}-size piece of the original NN-size problem.

The full mask in the base case is affordable only because it runs on the small piece. That asymmetry is how this paper buys sublinear masking globally.

Theorem 2 — HVZK code-switching

The full reduction from RC12k,Czk,sl1\mathcal R_{\mathcal C_1^{\equiv 2^k}, \mathcal C_{\mathsf{zk}}, \mathsf{sl}_1} to RC2,Czk,sl2\mathcal R_{\mathcal C_2, \mathcal C_{\mathsf{zk}}, \mathsf{sl}_2}, for arbitrary codes C1,C2\mathcal C_1, \mathcal C_2 that can themselves be interleaved. Composition: run the HVZK sumcheck reduction first (drops interleaving), then run the code-switch IOR (drops to C2\mathcal C_2). HVZK with respect to a bounded distinguisher class; RBR knowledge soundness with error 2λ\leq 2^{-\lambda} at suitable field size.

This is the engine of the polylog-verifier theorem.

Theorem 4 — polylogarithmic HVZK verifier

Iterate Theorem 2 along a chain of codes C1,C2,,Cn\mathcal C_1, \mathcal C_2, \dots, \mathcal C_n, picked so that the 2k2^k-interleaving of Ci+1\mathcal C_{i+1} has the same message size as Ci\mathcal C_i (non-interleaved). Each application of Theorem 2 reduces the problem size by a factor of 2k2^k; after nn steps the problem is small enough to finish with a small variant of the §2.2 base case. Theorem 4 is parametrized over an arbitrary chain length; specific instantiations (next subsection) pin nn.

This is the WHIR/Ligerito recursion shape — same idea, ZK-augmented. (See the WHIR post for the non-ZK version of this recursion.)

Corollary 3 — HVZK Reed–Solomon ⇒ HVZK WHIR/Ligerito

Instantiate Theorem 4’s chain with Reed–Solomon codes:

  • k:=O(loglog)k := O(\log \log \ell) (folding factor per step).
  • Each Ci\mathcal C_i is Reed–Solomon over an evaluation domain of size 2im\approx 2^{-i} m.
  • Czk\mathcal C_{\mathsf{zk}} instantiated with Reed–Solomon at rate 1/logλ1/\log \lambda, mask size O~(λ)\widetilde O(\lambda).

This is the parameter regime of WHIR ([ACFY25]) and Ligerito ([NA25]), with ZK encodings substituted for the plain encodings throughout. The result:

  • O(m)+O~(λ)O(m) + \widetilde O(\lambda) alphabet symbols sent by the prover; verifier makes O(λ)O(\lambda) queries.
  • RBR knowledge soundness error 2λ\leq 2^{-\lambda}.
  • Perfect honest-verifier zero-knowledge (ζ=0\zeta = 0, thanks to RS having perfect ZK encodings with appended randomness).
  • Prover time and verifier time match the non-private WHIR/Ligerito up to o(1)o(1).

This is the headline. Theorem 2 plus the building blocks above directly yield an HVZK variant of WHIR and Ligerito — a drop-in zero-knowledge replacement for the code-agnostic IOP family at 1+o(1)1 + o(1) overhead, in the list-decoding regime, with negligible RBR soundness error. The first such result.

Comparison

ProtocolOverheadSoundness regimeCode familyVerifier
[BCL22]O(1)O(1)Unique decodingAny ZK code (tensor-style)Polylog
[RW24]1+o(1)1 + o(1)Constant error onlyZK tensor codes (concrete: RS or tensor)Polylog
Naive ZK WHIR / Ligero-style2×\geq 2\timesList decodingReed–Solomon onlySublinear / polylog
HVZK WHIR (this paper)1+o(1)\mathbf{1 + o(1)}List decodingAny F\mathbb F-additive ZK codePolylog

The two rows that previously each owned one of these properties no longer dominate. This work is the first to put all four boxes ticked at once.

R1CS reduction with sublinear masking

The IOPP above tests proximity to constrained interleaved codes. To turn it into an end-to-end HVZK argument for NP, you reduce R1CS to that proximity test. The paper does this with 1+o(1)1 + o(1) overhead by reusing the same masking idea.

Backbone: an interleaved variant of [ACFY25]‘s Σ\Sigma-IOP for R1CS. Standard R1CS-to-sumcheck-to-codeword pipeline, but with two types of sublinear masks plugged in:

  • R1CS witness masks. Protect the matrix-vector products AzA \cdot z, BzB \cdot z, CzC \cdot z from leaking. [BCL22] handles this by padding the R1CS instance with full-size random witness — O(1)O(1) overhead. This paper uses sublinear masks instead — o(1)o(1).
  • Sumcheck masks. Same as Part 1’s §6 — small per-round masks accumulated into the joint constraint.

Both mask types are syntactically identical from the relation’s perspective — they propagate into an instance of RC,Czk,sl\mathcal R_{\mathcal C, \mathcal C_{\mathsf{zk}}, \mathsf{sl}} which our protocols can test in zero-knowledge end-to-end. Compose with Theorem 1 or Theorem 4 and you get an HVZK IOP for NP with linear-time prover, list-decoding soundness, and o(1)o(1) overhead relative to the witness size — strictly improving on [BCL22]‘s constant-overhead linear-prover protocol.

One honest caveat: the verifier here is non-succinct on R1CS-side cost, because this paper deliberately does not employ holographic preprocessing (the way [BCL22] and [RW24] do). The IOPP itself remains polylog-verifier.

If you want background on the R1CS-to-sumcheck step, Spartan and SPARK cover it.

What we didn’t cover

A few honest cuts.

High-distance codes from dispersers (Section 12 of the paper). The protocols here are code-agnostic, so you can buy more distance via the ABNNR construction [ABNNR92] — distance amplification through bipartite-disperser graphs. Plugged into Reed–Solomon, this gives amplified Reed–Solomon (ARS): RS at a low-cost base distance, then distance-boosted by gathering disperser neighbors. ARS shaves encoding time in the regime where plain RS pays O(/γlog(/γ))O(\ell/\gamma \cdot \log(\ell/\gamma)) for FFT-based evaluation, replacing it with O(/γ+log)O(\ell/\gamma + \ell \log \ell). Cost: alphabet inflates by a factor of d=O(1/γ)d = O(1/\gamma), so spot-checks cost more bytes per opening. Under reasonable parameters the paper reports a ≈ 30% argument-size win. Orthogonal to the ZK story and worth a separate read.

Round-by-round knowledge soundness proofs. We stated the errors qualitatively but skipped the full mutual-correlated-agreement accounting (the paper’s §6 and §9). WHIR treats MCA and list-decoding-regime soundness analysis for the non-ZK case; the ZK accounting is structurally similar but adds extra terms for the mask oracles.

Memory-efficient streaming prover. The paper notes that Theorem 1 is plausibly amenable to space-efficient streaming proving (à la [BBHV22], [CTY11]) — the encoding of CK\mathcal C^{\equiv K} can be done in space proportional to a single base encoding, and the sumcheck can stream too. Not pursued in the paper but flagged as future work.

Malicious-verifier ZK. Out of scope. Fiat–Shamir turns HVZK into malicious-verifier ZK for free in the non-interactive setting, which is what all deployed hash-based SNARKs care about.

Conclusion

The construction lands on five interlocking moves:

  1. The committed sumcheck relation — succinct linear forms plus mask oracles folded into a joint constraint, set up so the protocol can carry mask state through composition.
  2. Composable HVZK for IORs — the distinguisher class D\mathcal D, the composition theorem, and the discipline of making “future queries” explicit so naive composition stops shipping the witness.
  3. HVZK sumcheck via interleaved folding — small per-round masks, encode-then-fold = fold-then-encode, and correlated queries over the bigger alphabet to keep list-decoding-regime soundness affordable.
  4. Private zero-evaders for ZK-compatible OOD — randomized OOD samples that still pin a unique message while looking uniform to the verifier, plus the joint OOD sample over the message and an extra mask piece.
  5. Code-agnostic assembly — Theorems 1/2/4 plus the RS instantiation give the first HVZK variant of WHIR and Ligerito.

The practical upshot is concrete. Anonymous-credential stacks like [Fs24], built on the sublinear hash-based zkSNARK in [AHIV17], pay 2×\geq 2\times overhead today because the underlying IOP is private but old. The corresponding non-private IOPs are no longer state of the art. This work gives a drop-in path: swap the old private IOP for an HVZK WHIR/Ligerito built from the protocols above, eat 1+o(1)1 + o(1) overhead instead of 2×\geq 2\times, and the effect compounds because we’re measuring against the modern non-private state of the art rather than the 2017 baseline.

The longer-term effect is structural. The code-agnostic IOP family was the wrong place to look for ZK because the existing zero-knowledge moves were tied to polynomial codes. This paper unties them. Once the framework is in place — ZK encodings, composable HVZK-for-IORs, sublinear masking, private OOD — the next ZK variant of the next code-agnostic IOP is a much shorter walk.

References

  • This paper — Chiesa, A., Fenzi, G., & Weissenberg, G. (Feb 2026). Zero-Knowledge IOPPs for Constrained Interleaved Codes.
  • WHIR — Arnon, G., Chiesa, A., Fenzi, G., & Yogev, E. (2025). WHIR: Reed–Solomon Proximity Testing with Super-Fast Verification. EUROCRYPT ‘25.
  • Ligerito — Novakovic, A., & Angeris, G. (2025). Ligerito: A Small and Concretely Fast Polynomial Commitment Scheme. eprint 2025/1187
  • BCFW25 — Bünz, B., Chiesa, A., Fenzi, G., & Wang, W. (2025). Linear-Time Accumulation Schemes. TCC ‘25.
  • BCL22 — Bootle, J., Chiesa, A., & Liu, S. (2022). Zero-Knowledge IOPs with Linear-Time Prover and Polylogarithmic-Time Verifier. EUROCRYPT ‘22.
  • RW24 — Ron-Zewi, N., & Weiss, M. (2024). Zero-knowledge IOPs Approaching Witness Length. CRYPTO ‘24.
  • RR20 — Ron-Zewi, N., & Rothblum, R. (2020). Local Proofs Approaching the Witness Length. FOCS ‘20.
  • RR22 — Ron-Zewi, N., & Rothblum, R.D. (2022). Proving as Fast as Computing: Succinct Arguments with Constant Prover Overhead. STOC ‘22.
  • BMMS25 — Baweja, A., Mishra, P., Mopuri, T., & Shtepel, M. (2025). FICS and FACS: Fast IOPPs and Accumulation via Code-Switching. eprint 2025/737
  • ABNNR92 — Alon, N., Bruck, J., Naor, J., Naor, M., & Roth, R.M. (1992). Construction of asymptotically good low-rate error-correcting codes through pseudo-random graphs. IEEE TIT 38(2).
  • AHIV17 (Ligero) — Ames, S., Hazay, C., Ishai, Y., & Venkitasubramaniam, M. (2017). Ligero: Lightweight Sublinear Arguments Without a Trusted Setup. CCS ‘17.
  • Fs24 — Frigo, M., & Shelat, A. (2024). Anonymous credentials from ECDSA. eprint 2024/2010
  • BBHV22 — Bangalore, L., Bhadauria, R., Hazay, C., & Venkitasubramaniam, M. (2022). On Black-Box Constructions of Time and Space Efficient Sublinear Arguments from Symmetric-Key Primitives. TCC ‘22.
  • CTY11 — Cormode, G., Thaler, J., & Yi, K. (2011). Verifying computations with streaming interactive proofs. VLDB.
  • ACFY25 — Arnon, G., Chiesa, A., Fenzi, G., & Yogev, E. (2025). WHIR: Reed–Solomon Proximity Testing with Super-Fast Verification. EUROCRYPT ‘25.
  • Companion blogs. WHIR, TensorSwitch I, TensorSwitch II, Spartan, SPARK, Part 1 of this series.