pub struct ZipPlus<Zt: ZipTypes, Lc: LinearCode<Zt>>(/* private fields */);Expand description
Zip is a Polynomial Commitment Scheme (PCS) that supports committing to multilinear polynomials.
Implementations§
Source§impl<Zt: ZipTypes, Lc: LinearCode<Zt>> ZipPlus<Zt, Lc>
impl<Zt: ZipTypes, Lc: LinearCode<Zt>> ZipPlus<Zt, Lc>
Sourcepub fn commit(
pp: &ZipPlusParams<Zt, Lc>,
polys: &[DenseMultilinearExtension<Zt::Eval>],
) -> Result<(ZipPlusHint<Zt::Cw>, ZipPlusCommitment), ZipError>
pub fn commit( pp: &ZipPlusParams<Zt, Lc>, polys: &[DenseMultilinearExtension<Zt::Eval>], ) -> Result<(ZipPlusHint<Zt::Cw>, ZipPlusCommitment), ZipError>
Creates a commitment to one or more multilinear polynomials using the ZIP PCS scheme.
This function implements the commitment phase of the ZIP polynomial commitment scheme. It encodes each polynomial’s evaluations using a linear error-correcting code and then creates a single Merkle tree commitment over the interleaved columns.
§Algorithm
- Validates that each polynomial’s number of variables matches the parameters.
- Arranges each polynomial’s evaluations into a matrix with
pp.num_rowsrows. - Encodes each row using the specified linear code, expanding its
length from
row_lentocodeword_len. - Constructs a single Merkle tree where
leaf_j = H(poly_1_col_j || poly_2_col_j || ...). - Returns the full commitment data (for the prover) and a compact commitment (for the verifier).
§Parameters
pp: Public parameters (ZipPlusParams) containing the configuration for the commitment scheme.polys: Slice of multilinear polynomials to be committed to.
§Returns
A Result containing a tuple of:
ZipPlusHint: Per-polynomial encoded rows and the shared Merkle tree, kept by the prover for the opening phase.ZipPlusCommitment: The compact commitment (Merkle root and batch size), to be sent to the verifier.
§Errors
- Returns
Error::InvalidPcsParamif any polynomial has more variables than the parameters support.
§Panics
- Panics if any polynomial’s evaluation count does not match
pp.num_rows * pp.linear_code.row_len().
Sourcepub fn commit_no_merkle(
pp: &ZipPlusParams<Zt, Lc>,
poly: &DenseMultilinearExtension<Zt::Eval>,
) -> Result<DenseRowMatrix<Zt::Cw>, ZipError>
pub fn commit_no_merkle( pp: &ZipPlusParams<Zt, Lc>, poly: &DenseMultilinearExtension<Zt::Eval>, ) -> Result<DenseRowMatrix<Zt::Cw>, ZipError>
Creates a commitment without constructing Merkle trees.
This function performs the encoding step of the commitment phase but deliberately skips the computationally intensive step of building Merkle trees. It is intended for testing and benchmarking purposes only, where the full commitment structure is not required.
§Parameters
pp: Public parameters (ZipPlusParams).poly: The multilinear polynomial to commit to.
§Returns
A Result containing ZipPlusHint with the encoded rows but
empty Merkle trees, and a ZipPlusCommitment with an empty
vector of roots.
pub fn commit_single( pp: &ZipPlusParams<Zt, Lc>, poly: &DenseMultilinearExtension<Zt::Eval>, ) -> Result<(ZipPlusHint<Zt::Cw>, ZipPlusCommitment), ZipError>
Sourcepub fn encode_rows(
pp: &ZipPlusParams<Zt, Lc>,
evals: &[Zt::Eval],
) -> DenseRowMatrix<Zt::Cw>
pub fn encode_rows( pp: &ZipPlusParams<Zt, Lc>, evals: &[Zt::Eval], ) -> DenseRowMatrix<Zt::Cw>
Encodes the evaluations of a polynomial by arranging them into rows and applying a linear code.
This function treats the polynomial’s flat evaluation vector as a matrix
with pp.num_rows and encodes each row individually. The resulting
encoded rows are concatenated into a single flat vector. This
operation can be parallelized if the parallel feature is enabled.
§Parameters
pp: Public parameters containing matrix dimensions and the linear code.codeword_len: The length of an encoded row.poly: The polynomial whose evaluations are to be encoded.
§Returns
A Vec<Int<K>> containing all the encoded rows concatenated together.
Source§impl<Zt: ZipTypes, Lc: LinearCode<Zt>> ZipPlus<Zt, Lc>
impl<Zt: ZipTypes, Lc: LinearCode<Zt>> ZipPlus<Zt, Lc>
Sourcepub fn prove<F, const CHECK_FOR_OVERFLOW: bool>(
transcript: &mut PcsProverTranscript,
pp: &ZipPlusParams<Zt, Lc>,
polys: &[DenseMultilinearExtension<Zt::Eval>],
point: &[Zt::Pt],
commit_hint: &ZipPlusHint<Zt::Cw>,
field_cfg: &F::Config,
) -> Result<F, ZipError>where
F: PrimeField + for<'a> FromWithConfig<&'a Zt::CombR> + for<'a> FromWithConfig<&'a Zt::Pt> + for<'a> MulByScalar<&'a F> + FromRef<F>,
F::Inner: Transcribable,
F::Modulus: Transcribable,
pub fn prove<F, const CHECK_FOR_OVERFLOW: bool>(
transcript: &mut PcsProverTranscript,
pp: &ZipPlusParams<Zt, Lc>,
polys: &[DenseMultilinearExtension<Zt::Eval>],
point: &[Zt::Pt],
commit_hint: &ZipPlusHint<Zt::Cw>,
field_cfg: &F::Config,
) -> Result<F, ZipError>where
F: PrimeField + for<'a> FromWithConfig<&'a Zt::CombR> + for<'a> FromWithConfig<&'a Zt::Pt> + for<'a> MulByScalar<&'a F> + FromRef<F>,
F::Inner: Transcribable,
F::Modulus: Transcribable,
Generates an opening proof for one or more committed multilinear polynomials at an evaluation point, using the Zip+ protocol.
This replaces the old two-phase (test + evaluate) approach with a single
merged phase. The key idea: alpha-projection (Eval → CombR) is used for
both the proximity argument and the evaluation claim, eliminating the
separate field-domain projection via projecting_element γ.
§Algorithm
- Computes points:
(q_0, q_1) = point_to_tensor(point)whereq_0(lengthnum_rows) combines rows andq_1(lengthrow_len) combines columns. - Per polynomial, samples random challenges
alphas([α_0, …, α_d]). For each decoded roww_jtakes the inner product<entry, alphas>of every entry in the row, producingw'_j— a row ofCombRintegers. - Computes
b(lengthnum_rows), accumulated across all polys:b_j += <w'_j, q_1>for each rowj. - Writes
bto the transcript and computeseval = <q_0, b>. - Samples combination coefficients
betas(or hardcodes[1]whennum_rows == 1) and computescombined_row(CombR, lengthrow_len) =sum_i(sum_j(s_j * w'_ij)), accumulated across all polynomials - Writes
combined_rowto the transcript. - Opens
NUM_COLUMN_OPENINGSMerkle columns: for each, squeezes a column index, writes per-polynomial column values (Cw entries), and appends the Merkle proof.
§Transcript layout
[field_cfg sampled]
[per-poly alphas sampled]
[b written as F elements]
[coeffs s sampled (or hardcoded [1])]
[combined_row written as CombR]
[column openings: idx, per-poly column values, merkle proof] × NUM_COLUMN_OPENINGS§Parameters
pp: Public parameters containingnum_vars,num_rows, and the linear code configuration.polys: Slice of multilinear polynomials (batch). All must havenum_varsvariables matchingpp.point: The evaluation point (inZt::Ptcoordinates, lengthnum_vars).commit_hint: TheZipPlusHintreturned bycommit, containing per-polynomial codeword matrices and the shared Merkle tree.
§Returns
A Result containing:
F: The combined evaluation<q_0, b>, which equalssum_i(alpha_projected_eval_i(point))across all batched polys.ZipPlusProof: The serialized transcript (b, combined_row, column openings + Merkle proofs) for the verifier.
§Errors
- Returns
ZipError::InvalidPcsParamif any polynomial has more variables thanppsupports. - Returns
ZipError::OverflowError(whenCHECK_FOR_OVERFLOWis true) if intermediate CombR sums exceed the integer precision.
Sourcepub fn prove_f<F, const CHECK_FOR_OVERFLOW: bool>(
transcript: &mut PcsProverTranscript,
pp: &ZipPlusParams<Zt, Lc>,
polys: &[DenseMultilinearExtension<Zt::Eval>],
point: &[F],
commit_hint: &ZipPlusHint<Zt::Cw>,
field_cfg: &F::Config,
) -> Result<F, ZipError>where
F: PrimeField + for<'a> FromWithConfig<&'a Zt::CombR> + for<'a> MulByScalar<&'a F> + FromRef<F>,
F::Inner: Transcribable,
F::Modulus: Transcribable,
pub fn prove_f<F, const CHECK_FOR_OVERFLOW: bool>(
transcript: &mut PcsProverTranscript,
pp: &ZipPlusParams<Zt, Lc>,
polys: &[DenseMultilinearExtension<Zt::Eval>],
point: &[F],
commit_hint: &ZipPlusHint<Zt::Cw>,
field_cfg: &F::Config,
) -> Result<F, ZipError>where
F: PrimeField + for<'a> FromWithConfig<&'a Zt::CombR> + for<'a> MulByScalar<&'a F> + FromRef<F>,
F::Inner: Transcribable,
F::Modulus: Transcribable,
See Self::prove for details.
This version takes the evaluation point already mapped to the field
Sourcepub fn prove_single<F, const CHECK_FOR_OVERFLOW: bool>(
transcript: &mut PcsProverTranscript,
pp: &ZipPlusParams<Zt, Lc>,
poly: &DenseMultilinearExtension<Zt::Eval>,
point: &[Zt::Pt],
commit_hint: &ZipPlusHint<Zt::Cw>,
field_cfg: &F::Config,
) -> Result<F, ZipError>where
F: PrimeField + for<'a> FromWithConfig<&'a Zt::CombR> + for<'a> FromWithConfig<&'a Zt::Chal> + for<'a> FromWithConfig<&'a Zt::Pt> + for<'a> MulByScalar<&'a F> + FromRef<F>,
F::Inner: Transcribable,
F::Modulus: FromRef<Zt::Fmod> + Transcribable,
pub fn prove_single<F, const CHECK_FOR_OVERFLOW: bool>(
transcript: &mut PcsProverTranscript,
pp: &ZipPlusParams<Zt, Lc>,
poly: &DenseMultilinearExtension<Zt::Eval>,
point: &[Zt::Pt],
commit_hint: &ZipPlusHint<Zt::Cw>,
field_cfg: &F::Config,
) -> Result<F, ZipError>where
F: PrimeField + for<'a> FromWithConfig<&'a Zt::CombR> + for<'a> FromWithConfig<&'a Zt::Chal> + for<'a> FromWithConfig<&'a Zt::Pt> + for<'a> MulByScalar<&'a F> + FromRef<F>,
F::Inner: Transcribable,
F::Modulus: FromRef<Zt::Fmod> + Transcribable,
See Self::prove for details.
Source§impl<Zt: ZipTypes, Lc: LinearCode<Zt>> ZipPlus<Zt, Lc>
impl<Zt: ZipTypes, Lc: LinearCode<Zt>> ZipPlus<Zt, Lc>
Sourcepub fn verify<F, const CHECK_FOR_OVERFLOW: bool>(
transcript: &mut PcsVerifierTranscript,
vp: &ZipPlusParams<Zt, Lc>,
comm: &ZipPlusCommitment,
field_cfg: &F::Config,
point_f: &[F],
eval_f: &F,
) -> Result<(), ZipError>where
F: FromPrimitiveWithConfig + FromRef<F> + for<'a> FromWithConfig<&'a Zt::CombR> + for<'a> FromWithConfig<&'a Zt::Chal> + for<'a> MulByScalar<&'a F>,
F::Inner: Transcribable,
F::Modulus: FromRef<Zt::Fmod> + Transcribable,
pub fn verify<F, const CHECK_FOR_OVERFLOW: bool>(
transcript: &mut PcsVerifierTranscript,
vp: &ZipPlusParams<Zt, Lc>,
comm: &ZipPlusCommitment,
field_cfg: &F::Config,
point_f: &[F],
eval_f: &F,
) -> Result<(), ZipError>where
F: FromPrimitiveWithConfig + FromRef<F> + for<'a> FromWithConfig<&'a Zt::CombR> + for<'a> FromWithConfig<&'a Zt::Chal> + for<'a> MulByScalar<&'a F>,
F::Inner: Transcribable,
F::Modulus: FromRef<Zt::Fmod> + Transcribable,
Verifies an opening proof for one or more committed multilinear polynomials at an evaluation point, using the Zip+ protocol.
This replaces the old two-phase (verify_testing + verify_evaluation)
approach. The old protocol performed two proximity checks (one in CombR,
one in F via a separate projecting_element γ) and one eval consistency
check. The merged protocol eliminates the F-domain proximity check
entirely, replacing it with a coherence check between b and w
that ties the single CombR proximity check to the evaluation claim.
§Verification checks (4 total)
-
Eval consistency:
<q_0, b> == eval_f. Ensures the claimed evaluation matches thebvector written by the prover, whereb_j = sum_i(<w'_ij, q_1>)andw'_ijis the j-th decoded row of poly i after taking the random linear combination<entry, alphas_i>of every entry. -
Coherence (b-w):
<w, q_1> == <s, b>. Ensuresbandware derived from the same underlying rowsw'_j, tying the proximity-testedwto the eval-testedb. -
Proximity (per opened column, batched across polys):
Enc(w)[col] == sum_i(sum_j(s_j * <v_ij[col], alphas_i>)). For each poly i and row j, takes the random linear combination<v_ij[col], alphas_i>of the Cw column entry to get a CombR value, combines rows with coefficientss, sums across polys. Compares against the encoded combined row. -
Merkle proof (per opened column): verifies the column values against
comm.root, ensuring that the data matches what was committed.
Chain of trust: Merkle (check 4) → column data authentic → proximity
(check 3) → w is a valid codeword consistent with columns →
coherence (check 2) → b is consistent with w →
eval consistency (check 1) → eval_f is correct.
§Algorithm
- Computes
(q_0, q_1) = point_to_tensor(point_f). - Per polynomial, re-derives
alphasfrom the transcript. - Reads
b(lengthnum_rows) from the transcript. - Check 1: asserts
<q_0, b> == eval_f. - Re-derives combination coefficients
s(or[1]whennum_rows == 1). - Reads combined row
w(CombR, lengthrow_len) and encodes it. - Check 2: asserts
<w, q_1> == <s, b>. - For each of
NUM_COLUMN_OPENINGS: a. Squeezes column index, reads per-poly column values + Merkle proof. b. Check 3:verify_column_testing_batched. c. Check 4:proof.verify(comm.root, column_values, col).
§Parameters
vp: Public parameters (same as prover’spp).comm: TheZipPlusCommitment(Merkle root + batch size) from the commit phase.point_f: The evaluation point in fieldF(lengthnum_vars).eval_f: The claimed combined evaluation<q_0, b>.proof: TheZipPlusProofproduced byprove.
§Returns
Ok(()) if all four checks pass.
§Errors
ZipError::InvalidPcsParamif inputs are malformed.ZipError::InvalidPcsOpen("Evaluation consistency failure")if check 1 fails.ZipError::InvalidPcsOpen("Coherence failure")if check 2 fails.ZipError::InvalidPcsOpen("Proximity failure")if check 3 fails.ZipError::InvalidPcsOpen("Column opening verification failed: ...")if check 4 (Merkle) fails.
Sourcepub fn verify_with_alphas<F, const CHECK_FOR_OVERFLOW: bool>(
transcript: &mut PcsVerifierTranscript,
vp: &ZipPlusParams<Zt, Lc>,
comm: &ZipPlusCommitment,
field_cfg: &F::Config,
point_f: &[F],
eval_f: &F,
per_poly_alphas: &[Vec<Zt::Chal>],
) -> Result<(), ZipError>where
F: FromPrimitiveWithConfig + FromRef<F> + for<'a> FromWithConfig<&'a Zt::CombR> + for<'a> FromWithConfig<&'a Zt::Chal> + for<'a> MulByScalar<&'a F>,
F::Inner: Transcribable,
F::Modulus: FromRef<Zt::Fmod> + Transcribable,
pub fn verify_with_alphas<F, const CHECK_FOR_OVERFLOW: bool>(
transcript: &mut PcsVerifierTranscript,
vp: &ZipPlusParams<Zt, Lc>,
comm: &ZipPlusCommitment,
field_cfg: &F::Config,
point_f: &[F],
eval_f: &F,
per_poly_alphas: &[Vec<Zt::Chal>],
) -> Result<(), ZipError>where
F: FromPrimitiveWithConfig + FromRef<F> + for<'a> FromWithConfig<&'a Zt::CombR> + for<'a> FromWithConfig<&'a Zt::Chal> + for<'a> MulByScalar<&'a F>,
F::Inner: Transcribable,
F::Modulus: FromRef<Zt::Fmod> + Transcribable,
Like Self::verify, but accepts pre-sampled alpha challenges.
The caller is responsible for sampling per_poly_alphas from the
transcript before calling this (typically via Self::sample_alphas).
This allows computing eval_f externally from the alphas (e.g. via
alpha-projection of polynomial MLE evaluations in the lift-and-project
flow).
Sourcepub fn sample_alphas(
transcript: &mut Blake3Transcript,
batch_size: usize,
) -> Vec<Vec<Zt::Chal>>
pub fn sample_alphas( transcript: &mut Blake3Transcript, batch_size: usize, ) -> Vec<Vec<Zt::Chal>>
Samples per-polynomial alpha challenges from the transcript.
This is the same sampling logic used internally by Self::verify.
Exposed so that callers (e.g. the Zinc+ PIOP verifier) can sample
alphas, perform alpha-projection externally, and then call
Self::verify_with_alphas.
Source§impl<Zt, Lc> ZipPlus<Zt, Lc>where
Zt: ZipTypes,
Lc: LinearCode<Zt>,
impl<Zt, Lc> ZipPlus<Zt, Lc>where
Zt: ZipTypes,
Lc: LinearCode<Zt>,
pub fn setup(poly_size: usize, linear_code: Lc) -> ZipPlusParams<Zt, Lc>
Auto Trait Implementations§
impl<Zt, Lc> Freeze for ZipPlus<Zt, Lc>
impl<Zt, Lc> RefUnwindSafe for ZipPlus<Zt, Lc>where
Zt: RefUnwindSafe,
Lc: RefUnwindSafe,
impl<Zt, Lc> Send for ZipPlus<Zt, Lc>
impl<Zt, Lc> Sync for ZipPlus<Zt, Lc>
impl<Zt, Lc> Unpin for ZipPlus<Zt, Lc>
impl<Zt, Lc> UnsafeUnpin for ZipPlus<Zt, Lc>
impl<Zt, Lc> UnwindSafe for ZipPlus<Zt, Lc>where
Zt: UnwindSafe,
Lc: UnwindSafe,
Blanket Implementations§
§impl<T> AsMaybeUninit for T
impl<T> AsMaybeUninit for T
§type Uninit = MaybeUninit<T>
type Uninit = MaybeUninit<T>
§fn as_ref_uninit(&self) -> &<T as AsMaybeUninit>::Uninit
fn as_ref_uninit(&self) -> &<T as AsMaybeUninit>::Uninit
&self to its maybe-initialized equivalent.§unsafe fn as_mut_uninit(&mut self) -> &mut <T as AsMaybeUninit>::Uninit
unsafe fn as_mut_uninit(&mut self) -> &mut <T as AsMaybeUninit>::Uninit
&mut T to its maybe-initialized equivalent. Read more§unsafe fn raw_as_uninit<'a>(raw: *const T) -> &'a <T as AsMaybeUninit>::Uninit
unsafe fn raw_as_uninit<'a>(raw: *const T) -> &'a <T as AsMaybeUninit>::Uninit
§unsafe fn raw_mut_as_uninit<'a>(
raw: *mut T,
) -> &'a mut <T as AsMaybeUninit>::Uninit
unsafe fn raw_mut_as_uninit<'a>( raw: *mut T, ) -> &'a mut <T as AsMaybeUninit>::Uninit
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more