Skip to main content

ZipPlus

Struct ZipPlus 

Source
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>

Source

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
  1. Validates that each polynomial’s number of variables matches the parameters.
  2. Arranges each polynomial’s evaluations into a matrix with pp.num_rows rows.
  3. Encodes each row using the specified linear code, expanding its length from row_len to codeword_len.
  4. Constructs a single Merkle tree where leaf_j = H(poly_1_col_j || poly_2_col_j || ...).
  5. 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::InvalidPcsParam if 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().
Source

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.

Source

pub fn commit_single( pp: &ZipPlusParams<Zt, Lc>, poly: &DenseMultilinearExtension<Zt::Eval>, ) -> Result<(ZipPlusHint<Zt::Cw>, ZipPlusCommitment), ZipError>

Source

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>

Source

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
  1. Computes points: (q_0, q_1) = point_to_tensor(point) where q_0 (length num_rows) combines rows and q_1 (length row_len) combines columns.
  2. Per polynomial, samples random challenges alphas ([α_0, …, α_d]). For each decoded row w_j takes the inner product <entry, alphas> of every entry in the row, producing w'_j — a row of CombR integers.
  3. Computes b (length num_rows), accumulated across all polys: b_j += <w'_j, q_1> for each row j.
  4. Writes b to the transcript and computes eval = <q_0, b>.
  5. Samples combination coefficients betas (or hardcodes [1] when num_rows == 1) and computes combined_row (CombR, length row_len) = sum_i(sum_j(s_j * w'_ij)), accumulated across all polynomials
  6. Writes combined_row to the transcript.
  7. Opens NUM_COLUMN_OPENINGS Merkle 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 containing num_vars, num_rows, and the linear code configuration.
  • polys: Slice of multilinear polynomials (batch). All must have num_vars variables matching pp.
  • point: The evaluation point (in Zt::Pt coordinates, length num_vars).
  • commit_hint: The ZipPlusHint returned by commit, containing per-polynomial codeword matrices and the shared Merkle tree.
§Returns

A Result containing:

  • F: The combined evaluation <q_0, b>, which equals sum_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::InvalidPcsParam if any polynomial has more variables than pp supports.
  • Returns ZipError::OverflowError (when CHECK_FOR_OVERFLOW is true) if intermediate CombR sums exceed the integer precision.
Source

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

Source

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>

Source

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)
  1. Eval consistency: <q_0, b> == eval_f. Ensures the claimed evaluation matches the b vector written by the prover, where b_j = sum_i(<w'_ij, q_1>) and w'_ij is the j-th decoded row of poly i after taking the random linear combination <entry, alphas_i> of every entry.

  2. Coherence (b-w): <w, q_1> == <s, b>. Ensures b and w are derived from the same underlying rows w'_j, tying the proximity-tested w to the eval-tested b.

  3. 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 coefficients s, sums across polys. Compares against the encoded combined row.

  4. 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
  1. Computes (q_0, q_1) = point_to_tensor(point_f).
  2. Per polynomial, re-derives alphas from the transcript.
  3. Reads b (length num_rows) from the transcript.
  4. Check 1: asserts <q_0, b> == eval_f.
  5. Re-derives combination coefficients s (or [1] when num_rows == 1).
  6. Reads combined row w (CombR, length row_len) and encodes it.
  7. Check 2: asserts <w, q_1> == <s, b>.
  8. 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’s pp).
  • comm: The ZipPlusCommitment (Merkle root + batch size) from the commit phase.
  • point_f: The evaluation point in field F (length num_vars).
  • eval_f: The claimed combined evaluation <q_0, b>.
  • proof: The ZipPlusProof produced by prove.
§Returns

Ok(()) if all four checks pass.

§Errors
  • ZipError::InvalidPcsParam if 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.
Source

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).

Source

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>,

Source

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>

§

impl<Zt, Lc> Send for ZipPlus<Zt, Lc>

§

impl<Zt, Lc> Sync for ZipPlus<Zt, Lc>

§

impl<Zt, Lc> Unpin for ZipPlus<Zt, Lc>
where Zt: Unpin, Lc: Unpin,

§

impl<Zt, Lc> UnsafeUnpin for ZipPlus<Zt, Lc>

§

impl<Zt, Lc> UnwindSafe for ZipPlus<Zt, Lc>
where Zt: UnwindSafe, Lc: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<T> AsMaybeUninit for T

§

type Uninit = MaybeUninit<T>

This type in its maybe-uninitialized form.
§

type SizedPart = T

The largest Sized element in Self, used to check for the absence of drop glue via a Copy bound. Read more
§

fn as_ref_uninit(&self) -> &<T as AsMaybeUninit>::Uninit

Converts a &self to its maybe-initialized equivalent.
§

unsafe fn as_mut_uninit(&mut self) -> &mut <T as AsMaybeUninit>::Uninit

Converts a &mut T to its maybe-initialized equivalent. Read more
§

unsafe fn raw_as_uninit<'a>(raw: *const T) -> &'a <T as AsMaybeUninit>::Uninit

Converts a raw pointer to a reference to maybe-uninit. Read more
§

unsafe fn raw_mut_as_uninit<'a>( raw: *mut T, ) -> &'a mut <T as AsMaybeUninit>::Uninit

Converts a raw mutable pointer to a mutable reference to maybe-uninit. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
§

impl<F, T> IntoWithConfig<F> for T
where F: PrimeField + FromWithConfig<T>,

§

fn into_with_cfg(self, cfg: &<F as PrimeField>::Config) -> F

§

impl<T> ManuallyDropMut for T

§

type Ret = ManuallyDrop<T>

§

fn manually_drop_mut<'__>(&'__ mut self) -> &'__ mut ManuallyDrop<T>

§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V