Introduction
Spartan is a transparent proof system that achieves something previously thought to require tradeoffs: no trusted setup (no toxic waste), general-purpose (works for any NP statement via R1CS), and sub-linear verification (verifier doesn’t read the entire statement). Zero-knowledge can be added on top.
Before Spartan (2019), you had to pick your poison:
- Groth16: Fast verification, tiny proofs, but requires a trusted setup ceremony per circuit
- Bulletproofs: Transparent, but verification scales linearly with circuit size
- STARKs: Transparent and sub-linear verification, but large proofs and use a different constraint model (AIR, not R1CS)
Spartan breaks this tradeoff by combining two ingredients:
- Sum-check protocol applied directly to R1CS constraints
- Polynomial commitments to achieve succinctness
The result is the first transparent SNARK with sub-linear verification for arbitrary R1CS circuits.
This article explains how Spartan works. We’ll start with the basic protocol where the verifier runs in linear time, then show how polynomial commitments compress this into a SNARK with sub-linear verification. Zero-knowledge can be layered on top—we cover that briefly at the end. We treat the polynomial commitment scheme as a blackbox—Spartan works with any PCS that supports committing to multilinear polynomials and opening them at arbitrary points.
What you’ll need: Familiarity with R1CS, multilinear extensions (MLEs), and the sum-check protocol. We provide brief refreshers below, with links to deeper resources.
What we won’t cover: The SPARK protocol (Spartan’s technique for committing to sparse matrices) gets its own article. We also skip security proofs and implementation details—the paper and code are there for that.
Background
R1CS: The Language of Constraints
R1CS (Rank-1 Constraint System) is a standard format for representing computations as a system of constraints. Most ZK proof systems that work with general computations use R1CS as their intermediate representation.
An R1CS instance consists of three sparse matrices of size , where is the number of constraints and is the number of variables. A witness vector of length satisfies the R1CS if:
where denotes element-wise (Hadamard) multiplication. In other words, for each constraint :
The witness vector has structure: where:
- : private witness (the secret the prover knows)
- : a constant term (always 1)
- : public inputs/outputs (known to both prover and verifier)
The matrices are public—they define the computation. The prover’s job is to convince the verifier that they know a such that the full satisfies all constraints.
Example: The constraint is encoded as a single row where picks out , picks out , and picks out .
For a deeper dive into R1CS, see RareSkills’ R1CS explainer or Vitalik’s QAP article.
Multilinear Extensions: Turning Data into Polynomials
The key to Spartan (and many modern proof systems) is viewing data structures—vectors and matrices—as polynomials. This lets us use polynomial techniques like the sum-check protocol.
The idea: Any function (mapping -bit binary strings to field elements) has a unique multilinear extension that:
- Agrees with on all boolean inputs: for all
- Is multilinear: linear in each variable individually
Vectors as polynomials: A vector of length can be viewed as a function where (interpreting the binary string as an index). Its MLE is a polynomial that “encodes” the entire vector.
Matrices as polynomials: Similarly, an matrix (with , ) becomes a polynomial in variables, where:
- indexes the row
- indexes the column
- for boolean inputs
Why this matters for Spartan: The R1CS matrices , , and witness vector all become polynomials. The constraint equation becomes a polynomial identity that we can check using sum-check.
The eq polynomial: A building block you’ll see often is , which evaluates to 1 when (on boolean inputs) and 0 otherwise. It’s defined as:
This polynomial lets us “select” a specific point—crucial for combining multiple constraints into one.
For more on MLEs, see Chapter 3 of Thaler’s “Proofs, Arguments, and Zero-Knowledge”.
Sum-check Protocol: The Workhorse
The sum-check protocol is the engine that powers Spartan. It lets a prover convince a verifier about the sum of a polynomial over the boolean hypercube—without the verifier evaluating all points.
The claim: Given an -variate polynomial , the prover claims:
Naively, verifying this requires evaluations. Sum-check reduces it to a single evaluation at a random point.
The protocol (interactive, rounds):
-
Round 0 (Setup):
- Prover computes the sum
- Prover sends claimed sum to verifier
-
Round 1: Prover sends univariate polynomial
- Verifier checks:
- Verifier sends random challenge
-
Round 2: Prover sends
- Verifier checks:
- Verifier sends random challenge
-
… continue for all variables …
-
Final step: After round , verifier has random point
- Verifier checks:
- This requires one evaluation of at the random point
Why it works: Each round “binds” one variable to a random value. A cheating prover would need to guess the verifier’s random challenges to produce consistent polynomials—Schwartz-Zippel lemma makes this negligibly probable.
Cost:
- Prover: work (must touch all terms)
- Verifier: field operations + one evaluation of at random point
- Communication: field elements (for multilinear , each round sends a degree-1 polynomial)
The catch: The verifier still needs to evaluate at the end. For some polynomials (like MLEs of sparse matrices), this can be expensive—this is where Spartan’s cleverness comes in.
For a complete treatment, see Chapter 4 of Thaler’s book.
The Core Idea: R1CS as a Polynomial Equation
Here’s Spartan’s key insight: R1CS satisfiability can be expressed as a polynomial equation, which we can verify using sum-check.
Recall the R1CS condition: for a valid witness , we need:
Let’s rewrite this using MLEs. Define:
- , , : MLEs of matrices , ,
- : MLE of witness vector
The matrix-vector product becomes a sum over the MLE:
Now, R1CS satisfaction means: for every row :
The problem: We have equations to check (one per constraint). Checking each individually is too expensive.
The trick: Instead of checking all equations, the verifier picks a random and we check a random linear combination:
Here acts as a “random weight” for each constraint. If the R1CS is satisfied, every term in the brackets is zero, so the sum is zero. If any constraint is violated, the sum is non-zero with high probability (by Schwartz-Zippel).
What we’ve achieved: Checking constraints reduces to checking one sum equals zero—exactly what sum-check is designed for.
The polynomial inside the sum has degree 3 overall (but still multilinear in , one from , and the product of two linear terms). This is the polynomial we’ll apply sum-check to in Phase 1.
Phase 1: Checking All Constraints at Once
We now have a sum to verify:
where and we define:
- — the MLE of vector
- and defined similarly
- where is the witness length
This is exactly a sum-check claim. The prover claims the sum is 0, and we run sum-check on the polynomial .
What happens during Phase 1:
- Prover sends the claimed sum:
- Over rounds, prover and verifier run sum-check on
- Each round, verifier sends a random challenge
- After rounds, all variables are bound to random values
At the end of Phase 1, the verifier needs to check:
The verifier can compute easily (it’s a product of terms). But to compute , , and , they need:
This is another sum over the boolean hypercube—with terms!
The problem: Computing directly requires work (summing over all ). If the verifier does this for , , and , we’re back to linear verification time.
The solution: We run another sum-check (Phase 2) to reduce this to a single evaluation.
Phase 2: Ensuring Consistency
At the end of Phase 1, the verifier needs , , and . The prover sends these as claims:
But why should the verifier believe these values? We need to verify that:
(and similarly for and ).
Combining three claims into one: Instead of running three separate sum-checks, the verifier sends random challenges and we verify a single combined claim:
This is another sum-check! Let’s define:
What happens during Phase 2:
- Verifier sends random to combine the three claims
- Prover and verifier run sum-check on for rounds
- Each round, verifier sends random challenge
- After rounds, all variables are bound to
At the end of Phase 2, the verifier needs to check:
What the verifier now needs:
- , , — evaluations of the R1CS matrices at random point
- — evaluation of the witness polynomial at random point
We’ve reduced everything to four point evaluations. This is the final check.
The Complete Protocol (Linear Verifier)
Let’s put the pieces together. Here’s the full Spartan protocol with linear-time verification:
Setup:
- Public: R1CS matrices , , (size )
- Public: input
- Prover’s private input: witness
- Prover constructs:
Protocol:
| Step | Prover | Verifier |
|---|---|---|
| 1 | Sends random | |
| 2 | Phase 1 Sum-check: Proves | Participates in sum-check, obtains |
| 3 | Sends claimed values | |
| 4 | Sends random | |
| 5 | Phase 2 Sum-check: Proves | Participates in sum-check, obtains |
| 6 | Final check (see below) |
Final Check:
The verifier must verify from Phase 2. This requires:
- Matrix evaluations: , ,
- Witness evaluation:
For the witness: the verifier can split . The public part they know, so they can compute the contribution from public inputs. For the private part , the prover sends and proves it’s correct (using a polynomial commitment—more on this in the SNARK section).
For the matrices: the verifier computes , , directly. This takes time where is the number of non-zero entries in the matrices.
Making it non-interactive: The protocol above is interactive—the verifier sends random challenges. In practice, we use the Fiat-Shamir transform: replace verifier’s random challenges with hashes of the transcript so far. The Spartan implementation uses merlin for this. The result is a single proof message from prover to verifier.
Complexity:
| Prover | Verifier | Proof Size | |
|---|---|---|---|
| Time | field elements |
(where is the number of non-zero entries in the R1CS matrices)
The takeaway: The proof is succinct (logarithmic size), but verification is linear. The verifier must read the entire R1CS instance to compute those matrix evaluations.
This is not yet a SNARK (Succinct Non-interactive ARgument of Knowledge). The “succinct” in SNARK refers to sub-linear verification—which we don’t have yet.
Can we do better?
The Verifier’s Bottleneck
Yes. The bottleneck is clear: the verifier needs to compute , , and .
For a sparse matrix with non-zero entries, evaluating its MLE at a random point takes time. The verifier must touch every non-zero entry to compute the evaluation. There’s no shortcut—unless the verifier already knows the answer.
The insight: What if the prover just tells the verifier what , , are?
The problem is trust. The prover could lie. We need a way for the prover to commit to the matrices beforehand, and then prove that the claimed evaluations are correct.
This is exactly what polynomial commitment schemes do.
Achieving Sub-linear Verification
The SNARK variant adds a preprocessing phase and uses polynomial commitments to eliminate the linear-time matrix evaluation.
Preprocessing (done once per circuit):
Before any proofs are generated, we commit to the R1CS matrices:
- Compute commitments: , ,
- Publish these commitments as part of the public parameters
This preprocessing takes time where is the number of non-zero entries, but it’s done only once.
Modified Protocol:
The SNARK protocol is almost identical to the basic protocol, with one key difference at the end:
| Linear Verifier | Succinct Verifier (SNARK) |
|---|---|
| Verifier computes directly | Prover sends claimed value |
| (takes time) | Prover provides proof that via PCS |
| Verifier checks proof against commitment |
What the verifier needs from PCS:
The polynomial commitment scheme must support:
- Commit: Given polynomial , output commitment
- Open: Given point , prove that
- Verify: Given commitment , point , claimed value , and proof , check correctness
The verification must be faster than evaluating the polynomial directly—otherwise there’s no point.
The result:
| Linear Verifier | Succinct Verifier | |
|---|---|---|
| Matrix evals | — compute directly | — verify PCS proof |
| Witness eval | — compute directly | — verify PCS proof |
| Total |
The verifier now runs in polylogarithmic time in the circuit size. This is the “succinct” in SNARK.
Trade-off:
| Linear Verifier | Succinct Verifier (SNARK) | |
|---|---|---|
| Preprocessing | None | one-time |
| Prover time | (includes PCS proofs) | |
| Verifier time | ||
| Proof size |
The linear-verifier variant is better when you have a small circuit or don’t want preprocessing. The SNARK is better when verification cost matters (e.g., on-chain verification).
A Note on Zero-Knowledge
Everything we’ve described so far is an argument of knowledge—the prover convinces the verifier that they know a valid witness. But it’s not yet zero-knowledge: the proof might leak information about the witness.
To make Spartan zero-knowledge, two modifications are needed:
1. Blind the witness commitment
When committing to the witness polynomial , add randomness:
- Instead of
- Use with random blinding factor
This ensures the commitment reveals nothing about .
2. Blind the sum-check polynomials
During each round of sum-check, the prover sends a univariate polynomial. These polynomials depend on the witness and could leak information.
The fix: add random “masking” polynomials that cancel out in expectation but hide the true values. The prover also provides zero-knowledge proofs (using sigma protocols) that the masked values are consistent.
The Spartan paper and implementation use:
- Pedersen commitments for hiding values
- Sigma protocols (knowledge proofs, equality proofs, product proofs) for proving relationships between committed values
We won’t go deeper here—the key point is that zero-knowledge is achievable with standard techniques, adding only constant overhead to each sum-check round.
See Section 6 of the Spartan paper for the full zero-knowledge construction.
What We Didn’t Cover
SPARK: Committing to Sparse Matrices
We glossed over a critical detail: how do you efficiently commit to the sparse matrices , , ?
Standard polynomial commitments work on dense polynomials. But R1CS matrices are sparse—they have non-zero entries in an matrix. Committing naively would require work.
SPARK is Spartan’s solution. It’s a specialized commitment scheme for sparse multilinear polynomials that:
- Commits in time where is the number of non-zero entries
- Opens at any point in time
- Verification is
SPARK uses memory-checking techniques and product arguments. It deserves its own article—coming soon.
Polynomial Commitment Schemes
We treated PCS as a blackbox. Spartan can work with different PCS backends:
- Hyrax-style (used in the original implementation): Based on Pedersen commitments and inner product arguments
- KZG/Kate: Requires trusted setup but gives constant-size proofs
- FRI-based: Transparent, used in STARKs
The choice of PCS affects proof size, verification time, and whether you need a trusted setup.
Security Analysis
We skipped all security proofs. The paper proves:
- Completeness: Honest prover always convinces verifier
- Soundness: Cheating prover fails with high probability (via Schwartz-Zippel)
- Zero-knowledge: Proof reveals nothing beyond statement validity (via simulation)
Conclusion
Spartan achieves transparent SNARKs through a clean insight: view R1CS as a polynomial identity and verify it using sum-check.
The core ideas:
- Express R1CS satisfaction as
- Apply sum-check twice: first to eliminate constraint variables, then to reduce to point evaluations
- Use polynomial commitments to make verification sub-linear
What makes Spartan significant:
- First transparent SNARK with sub-linear verification for general R1CS
- No trusted setup (unlike Groth16)
- Works with any PCS (modular design)
- Efficient prover (no FFTs required)
The techniques pioneered in Spartan—applying sum-check directly to R1CS, the two-phase structure—have influenced subsequent proof systems like HyperPlonk and others.
If you want to go deeper:
- Read the paper for formal definitions and security proofs
- Study the implementation to see how sum-check is realized in code
- Look at
r1csproof.rsfor Phase 1 and Phase 2 implementation - Look at
sumcheck.rsfor the sum-check protocol details
References
-
Spartan Paper: Setty, S. (2020). “Spartan: Efficient and general-purpose zkSNARKs without trusted setup.” CRYPTO 2020. https://eprint.iacr.org/2019/550.pdf
-
Implementation: Microsoft Spartan. https://github.com/microsoft/Spartan
-
Proofs, Arguments, and Zero-Knowledge: Thaler, J. https://people.cs.georgetown.edu/jthaler/ProofsArgsAndZK.pdf — Excellent resource for sum-check and MLEs
-
Vitalik’s QAP Explainer: https://medium.com/@VitalikButerin/quadratic-arithmetic-programs-from-zero-to-hero-f6d558cea649 — Background on R1CS/QAPs