Sources:

Use-case: In Spartan, we need to commit to the sparse R1CS matrices, which are of size , but only have non-zero entries. They achieve a quadratic speed-up over using a dense commitment scheme.

Representing sparse polynomials with dense polynomials: Any -variate multilinear polynomial can be written as:

where is the unique multi-linear extension of the equality function on the boolean hypercube:

is the Lagrange polynomial on . We can factor it into two Langrange polynomials over :

Let be the function that maps a field element to its bit representation. Then, we can write:

for some -variate polynomials , , and .

Note how can be seen as an indexed lookup into the vector :

Commitment phase: The prover commits to dense polynomials , , and .

Evaluation proof:

  • The prover sends the claimed evaluation of
  • The prover commits to two -variate helper polynomials and , such that:
  • Prover and verifier run the Multivariate Sum-Check Protocol to check that:
  • To show that and are well-formed, the prover and verifier run the an interactive protocol derived from the Offline Memory Checking technique.
    • For example, to show that is well-formed, we show that it corresponds to the vector obtained by reading from a memory described by using addresses described by .
    • Note how any other indexed lookup (e.g. LogUp & cq) would also work!

Generalizing: The reason we factored the Lagrange polynomials over into two Lagrange polynomials over is because . In general, we could split it into any number of polynomials where .

PIL sketch

// Description of the sparse matrix
col fixed row, col, value;
 
// These polynomials are not actually committed
// at setup time, but the verifier knows how
// to evaluate the underlying polynomials cheaply.
// In fact, eq_r_x and eq_r_y depend on r_x and r_y,
// which are challenges only known at runtime.
col fixed index(i) {i};
col fixed eq_r_x, eq_r_y;
 
// Commit to helper polynomials & prove they are
// well formed.
col witness E_x, E_y;
[row, E_x] in [index, eq_r_x];
[col, E_y] in [index, eq_r_x];
 
// For each non-zero entry in the sparse matrix,
// this is contribution of that entry to the
// evaluation of the polynomial at (r_x, y_x).
col entry = value * E_x * E_y;

The final result is the sum of all entries.