Skip to content

Feat : added prefold approach#220

Draft
ocdbytes wants to merge 3 commits intoWizardOfMenlo:mainfrom
ocdbytes:aj/prefold
Draft

Feat : added prefold approach#220
ocdbytes wants to merge 3 commits intoWizardOfMenlo:mainfrom
ocdbytes:aj/prefold

Conversation

@ocdbytes
Copy link
Copy Markdown
Contributor

ZK-WHIR Prefolding Protocol (Mixed Arity)

This document describes the full prefolding protocol used to reduce over-sized polynomials to the target arity before entering the main ZK-WHIR flow, while preserving zero-knowledge and soundness.


Phase 0 — Commitment

Each polynomial (native and over-sized) is committed independently at its original arity.

For a polynomial

$$ f : {0,1}^L \to \mathbb{F} $$

the prover samples ZK preprocessing data.

  • Masking polynomial

$$ msk $$

  • Helper polynomials

$$ \hat g_0, \hat g_1, \ldots, \hat g_L, M $$

All helper polynomials are $\ell$-variate, with $\ell < L$.

The prover commits to the masked polynomial

$$ \hat f = f + msk $$

using Interleaved Reed–Solomon (IRS):

  • Evaluate on an RS domain
  • Arrange evaluations into a matrix
  • Merkle-commit to the matrix

Helper polynomials

$$ [M, \hat g_1, \ldots, \hat g_L] $$

are batch-committed via a separate helper-WHIR configuration.

The IRS interleaving depth is

$$ k = 2^d $$

where

$$ d = L - n_{\min} $$

Each Merkle opening reveals a coset of $k$ evaluations, which is exactly what is required for folding in Phase 2.


Phase 1 — ZK Blinding Setup

This phase is shared across all groups (native and prefold) and establishes the Fiat–Shamir challenges that bind the protocol.

Sample

$$ \beta \leftarrow \mathbb{F} $$

from the transcript.

Blinding Polynomial

For each polynomial, construct

$$ g(x) = \hat g_0(x_0,\ldots,x_{\ell-1}) + \sum_i \beta^i \cdot x_{i-1} \cdot \hat g_i(x_0,\ldots,x_{\ell-1}) $$

  • $g$ is a uniformly random $L$-variate polynomial
  • For $i > \ell$, fresh variable slots are used so that $g$ spans all $L$ variables

The prover sends

$$ g(a_i) $$

for each constraint point $a_i$.

Blinded Polynomial

Sample mixing scalar

$$ \rho \leftarrow \mathbb{F} $$

Define

$$ P = \rho \cdot f + g $$

Since $g$ is uniform over $\mathbb{F}^{2^L}$, $P$ is a perfect one-time pad on $\rho \cdot f$.

Modified evaluations are computed as

$$ \tilde v_{i,j} = \rho \cdot v_{i,j} + g_j(a_i) $$

Both prover and verifier can compute these values.


Phase 2 — Prefold

This phase is executed for each group with arity $L > n_{\min}$, starting from the highest arity.


Step 2.1 — Random Linear Combination (RLC)

For polynomials $P_1,\ldots,P_N$ in the group, combine

$$ P_{\mathrm{comb}} = \sum_j \lambda_j \cdot P_j $$

Combine constraints

$$ C(x) = \sum_i c_i \cdot eq(a_i, x) $$

Compute the claimed sum

$$ S = \sum_i c_i \cdot \left( \sum_j \lambda_j \cdot \tilde v_{i,j} \right) $$


Step 2.2 — Partial Sumcheck

Prove

$$ \sum_{x \in {0,1}^L} P_{\mathrm{comb}}(x), C(x) = S $$

Run only

$$ d = L - n_{\min} $$

rounds of sumcheck.

For each round:

  • Prover sends a degree-2 polynomial $s_t(X)$
  • Verifier checks

$$ s_t(0) + s_t(1) = S_{t-1} $$

and samples randomness $r_t$.

After $d$ rounds:

  • Fold randomness

$$ r = (r_1,\ldots,r_d) $$

  • Reduced claim $v'$

If the group has no constraints, $r$ is sampled directly from Fiat–Shamir.


Step 2.3 — Fold

Define the folded polynomial

$$ P'(x_0,\ldots,x_{n-1}) = P_{\mathrm{comb}}(x_0,\ldots,x_{n-1}, r_1,\ldots,r_d) $$

Each coefficient of $P'$ is the multilinear evaluation of a block of $2^d$ coefficients of $P_{\mathrm{comb}}$.


Step 2.4 — Reveal Folded Polynomial

The prover sends all coefficients of $P'$ into the transcript.

Since

$$ P' = \rho \cdot \mathrm{fold}(f, r) + \mathrm{fold}(g, r) $$

and $\mathrm{fold}(g,r)$ is uniformly random, this perfectly hides

$$ \rho \cdot \mathrm{fold}(f,r) $$

while binding the prover to $P'$.


Step 2.5 — Binding Equation Check

Split each evaluation point

$$ a_i = (a_i^{\mathrm{low}}, a_i^{\mathrm{high}}) $$

where

$$ a_i^{\mathrm{low}} \in {0,1}^n \qquad a_i^{\mathrm{high}} \in {0,1}^d $$

Using

$$ eq(a_i,(y,z)) = eq(a_i^{\mathrm{low}},y)\cdot eq(a_i^{\mathrm{high}},z) $$

the verifier checks

$$ v' = \sum_i c_i \cdot eq(a_i^{\mathrm{high}}, r) \cdot P'(a_i^{\mathrm{low}}) $$

Any incorrect evaluation causes this check to fail.


Step 2.6 — STIR Consistency Check

This step ensures $P'$ is the fold of the committed polynomial.

The verifier opens $\hat f$ at $q$ random IRS query points.

Each query reveals a coset

$$ {\hat f(\gamma_0),\ldots,\hat f(\gamma_{k-1})} $$

The prover provides helper evaluations, allowing the verifier to compute

$$ h(\gamma) = m(\gamma,\rho) + \sum_i \beta^i \cdot \gamma^{2^{i-1}} \cdot \hat g_i(\mathrm{pow}(\gamma)) $$

and

$$ L(\gamma) = \rho \cdot \hat f(\gamma) + h(\gamma) $$

By construction, $L(\gamma) = P(\gamma)$ on the evaluation domain.

The verifier:

  1. Verifies helper polynomials via a sub-WHIR proof
  2. Folds each coset using $r$ to obtain $V_\alpha$
  3. Checks

$$ V_\alpha = P'(\mathrm{pow}(\alpha)) $$

A mismatch at any query implies cheating with overwhelming probability (Schwartz–Zippel).


Phase 3 — Main ZK-WHIR

After all prefold groups are verified, the remaining native-arity polynomials enter the standard ZK-WHIR protocol at arity $n_{\min}$.

This includes the full sumcheck, STIR folding, and final coefficient checks.

Unified API

The low-level prefold API requires the caller to manually create configs, sample preprocessings, commit, and wire up group inputs. The new batch_prove_zk / batch_verify_zk API abstracts all of this — the caller just provides polynomials, weights, and evaluations grouped by arity:

// Prover
let groups = vec![
    ProverInput::new(vec![&poly_10var], weights_10, evals_10),
    ProverInput::new(vec![&poly_12var], weights_12, evals_12),
];
let (point, evals) = config.batch_prove_zk(&mut prover, &params, &groups, &mut rng);

// Verifier
let claims: Vec<VerifierInput<_>> = groups.iter().map(|g| g.to_verifier_input()).collect();
let result = config.batch_verify_zk(&mut verifier, &params, &claims);

The library automatically identifies the native group, creates prefold configs for higher arities, samples ZK preprocessing, commits, and routes to the appropriate prove/verify path (falling back to plain prove_zk when all groups share the same arity).

--

Summary

  • Over-sized polynomials are folded down to the target arity
  • Zero-knowledge is preserved via polynomial blinding
  • Partial sumcheck derives folding randomness
  • STIR binds folded polynomials to their commitments
  • Native ZK-WHIR runs unchanged after prefolding

This achieves sound, ZK-secure batching across mixed arities.

- Reduce 16 ZK tests to 5 comprehensive API tests
- Extract shared prove_helper_evaluations/verify_helper_evaluations
- Extract prepare_helper_polynomials utility
- Move build_helper_config to ZkParams method
- Extract separate_by_arity helper in api.rs
- Remove ~240 lines of duplicated code from prefold.rs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant