What is SPARK?
SPARK (Scalable Polynomial Argument of Knowledge) is a zkSNARK for efficiently committing to and proving evaluations of sparse polynomials and matrices. It was introduced as an optimization to the Spartan protocol, specifically targeting scenarios where constraint system matrices are sparse.
In the zkSNARK pipeline:
- Spartan proves R1CS satisfaction:
- This requires committing to and evaluating sparse matrices , ,
- Standard polynomial commitments treat matrices densely
- SPARK provides a commitment scheme optimized for sparsity, achieving complexity
Key property: SPARK’s prover and commitment costs scale with the number of non-zero entries (nnz), not the total matrix dimensions ().
Why SPARK?
The Dense Evaluation Bottleneck:
In standard approaches to proving R1CS, evaluating matrix MLEs at random points requires iterating over all positions:
- Dense approach cost:
- Problem: For sparse matrices, most
- Example: A matrix with 4096 non-zeros processes 1M positions when only 4K are meaningful
SPARK’s Improvement:
SPARK processes only the non-zero entries, trading dense iteration for sparse memory checking:
- Iterate over nnz entries (not )
- Use memory-checking protocol to prove correctness
- Polynomial commitment overhead scales with padded nnz
Use SPARK when matrices are sufficiently sparse that the memory-checking overhead is worthwhile compared to dense evaluation.
High-Level Intuition
The Core Insight:
Instead of iterating over all positions to compute the sum, SPARK treats the eq polynomial evaluations as a virtual memory:
- Addresses: row and column indices
- Values: and
- Operations: “read” the eq value for each non-zero entry’s position
The Trade:
- Only process nnz entries (not )
- Must prove we read the correct memory values
- Use offline memory checking with timestamps
Memory Checking in One Sentence:
Prove that every memory read corresponds to a valid write by tracking access timestamps and using a grand product argument to verify consistency.
Protocol Flow Overview:
- Sumcheck: Prove over non-zeros
- Memory Check: Prove the memory_row and memory_col values are correct using timestamps
- Grand Product Argument: Verify read-write consistency through fingerprint products
The magic: we’ve replaced dense iteration with sparse lookups + memory checking overhead.
Prerequisites & Notation
Assumed Knowledge:
- Multilinear Extensions (MLEs)
- Sumcheck Protocol
- Equality polynomial ()
- Polynomial commitments
- Fiat-Shamir transform
Notation:
- R1CS:
- Matrix dimensions: constraints variables
- nnz: number of non-zero entries
- Coordinate format (COO): tuples
The Core Problem: Sparse Matrix-Vector Multiplication
What We Need to Prove:
For a matrix evaluated at random point :
Why Dense Evaluation is Expensive:
- Requires iterating over all positions
- Most are zeros in sparse matrices
- Prover cost: field operations
SPARK’s Approach:
- Only process non-zero entries:
- Use memory-checking to prove correctness
- Trade dense iteration for timestamp management
Offline Memory Checking Primitive
The Memory Checking Abstraction
Think of a virtual memory with addresses and values. We define:
- Read-set (RS): all memory reads performed
- Write-set (WS): all memory writes performed
- Invariant: every read must have a prior write
Fingerprinting Technique
Each memory access is encoded as a fingerprint:
where are random challenges from Fiat-Shamir. This encoding prevents forgery — a cheating prover would need to find collisions in the fingerprint polynomial, which happens with negligible probability by Schwartz-Zippel.
Product Argument
The core claim:
- Init: all timestamps = 0 (memory starts fresh)
- Final: timestamps = total access count per address
- This equation proves read-write consistency
SPARK Protocol: Step-by-Step
Setup Phase
- Convert R1CS matrices to COO (coordinate) format
- Pad to power-of-2 length
- Compute timestamps for each access
Memory Structure
- Row memory: addresses = row indices, values = evaluations
- Column memory: addresses = column indices, values = evaluations
Timestamp Calculation
- = number of times that row was accessed before entry
- = number of times that column was accessed before entry
- = total times row addr was accessed
- = total times column addr was accessed
Main Protocol Flow
Phase 1 — Matrix Sumcheck:
Prove:
This evaluates the sparse matrix at .
Phase 2 — Row Memory Checking:
- Init-Final GPA: Prove row memory consistency
- RS-WS GPA: Prove each read has a corresponding write
Phase 3 — Column Memory Checking:
- Init-Final GPA: Prove column memory consistency
- RS-WS GPA: Prove each read has a corresponding write
Detailed Protocol Components
Matrix Sumcheck
This works because the sparse representation (summing only over non-zeros) computes the same result as the dense sum. Implemented as a cubic sumcheck with Lasso optimization.
Grand Product Argument (GPA)
The GPA proves product equality via multilinear extensions. It uses a binary tree construction:
- Build layers:
- Prove each layer via sumcheck
- Output: random evaluation point for final check
Init-Final Memory Check
Row side:
- Init fingerprints:
- Final fingerprints:
- GPA proves the relationship
Column side: similar, with and .
Read-Set / Write-Set Check
- Read-Set:
- Write-Set:
- Invariant: WS timestamp = RS timestamp + 1
- GPA proves:
The Equality Polynomial Trick
Why eq_rx and eq_ry?
acts as a selector for row index — it’s the eq polynomial evaluated over the boolean hypercube of row addresses. In the fingerprints, it serves as the “memory value” that we’re reading.
Column Dimension Mismatch
The column index space has dimensions vs the row’s dimensions. This is handled by:
The first bit acts as an enable/disable selector.
Optimizations
Matrix Batching
Instead of running SPARK separately for , , , we combine them with a random linear combination :
This proves all three matrix evaluations in a single sumcheck, saving two full sumcheck protocols.
Further Optimizations
- Row-Column GPA batching with random linear combinations
- Commitment merging strategies
- Batched polynomial openings
- Expected savings: 25–35% constraint reduction
Security
Soundness relies on:
- Schwartz-Zippel lemma for polynomial identity checks
- Fingerprint collision probability (negligible in field size)
- Fiat-Shamir security in the random oracle model
Why timestamps prevent cheating:
- Temporal ordering enforcement — each access gets a unique timestamp
- No reuse without detection — replaying a read would create a timestamp gap
- Product argument binding — any inconsistency breaks the product equality
Comparison with Alternatives
| Approach | Prover Time | Verifier Time | Proof Size |
|---|---|---|---|
| Dense Evaluation | |||
| SPARK | |||
| Lasso (lookup) |
References
- Spartan Paper: Setty, S. (2020). “Spartan: Efficient and general-purpose zkSNARKs without trusted setup.” CRYPTO 2020. https://eprint.iacr.org/2019/550.pdf
- Lasso Paper: Setty, S. et al. (2023). “Unlocking the lookup singularity with Lasso.” https://eprint.iacr.org/2023/1216.pdf
- WHIR Paper: Arnon, G. et al. (2024). “WHIR: Reed-Solomon Proximity Testing with Super-Fast Verification.” https://eprint.iacr.org/2024/1586.pdf