Spartan

These are notes on just a small part of Spartan: Efficient and general-purpose zkSNARKs without trusted setup (opens new window).

Spartan offers the first zkSNARKs without a trusted setup for NP, where verifying a proof incurs sub-linear costs—without requiring uniformity in the NP statement’s structure.

The core insight is that the sum-check protocol, when applied to a suitably constructed low-degree polynomial, yields a powerful—but highly inefficient—interactive proof protocol. However, the inefficiency can be tamed with new techniques.

Sum-check protocol

Suppose there is a function f(x1,...,xn)f(x_1, ..., x_n), and a prover wants to prove that

H=(x1,...,xn){0,1}nf(x1,...,xn)H = \sum_{(x_1, ..., x_n) \in \{0, 1\}^n} f(x_1, ..., x_n)

for some value HH. The sum-check protocol enables proving such a statement.

When we want to prove, for example, that the vector vv has the sum of its coefficients equal to HH, we observe vv as a function. Let’s say vv has 88 coefficients:

v=(v0v1v2v3v4v5v6v7)v = \begin{pmatrix} v_0 \\ v_1 \\ v_2 \\ v_3 \\ v_4 \\ v_5 \\ v_6 \\ v_7 \end{pmatrix}

We see vv as a function ff of 33 variables (23=82^3 = 8):

v=(f(0,0,0)f(0,0,1)f(0,1,0)f(0,1,1)f(1,0,0)f(1,0,1)f(1,1,0)f(1,1,1))v = \begin{pmatrix} f(0, 0, 0) \\ f(0, 0, 1) \\ f(0, 1, 0) \\ f(0, 1, 1) \\ f(1, 0, 0) \\ f(1, 0, 1) \\ f(1, 1, 0) \\ f(1, 1, 1) \end{pmatrix}

By using the sum-check protocol, we can prove v0+v1+...+v7=Hv_0 + v_1 + ... + v_7 = H.

In fact, many times it’s needed to prove that each coefficient is equal to zero:

v0=0v_0 = 0

......

v7=0v_7 = 0

This can be achieved by a zero-check protocol, which is an extension of the sum-check protocol.

So, how does Spartan use the sum-check protocol?

Encoding of R1CS instances as low-degree polynomials

Theorem 4.1 from the paper roughly says that for any R1CS instance, there exists a degree-3 log(m)log(m)-variate polynomial GG such that x{0,1}log(m)G(x)=0\sum_{x \in \{0, 1\}^{log(m)}} G(x) = 0 if and only if there exists a witness ww such that SatR1CS(x,w)=1Sat_{R1CS}(x, w) = 1 (the witness ww satisfies the constraint system).

Let’s say we have the following constraint system:

AzBzCz=0A z \circ B z - C z = 0

()()()()()()=0\begin{pmatrix} & & & \\ & & & \\ & & & \\ & & & \end{pmatrix} \begin{pmatrix} \\ \\ \\ \end{pmatrix} \circ \begin{pmatrix} & & & \\ & & & \\ & & & \\ & & & \end{pmatrix} \begin{pmatrix} \\ \\ \\ \end{pmatrix} - \begin{pmatrix} & & & \\ & & & \\ & & & \\ & & & \end{pmatrix} \begin{pmatrix} \\ \\ \\ \end{pmatrix} = 0

How do we transform this system into an equation x{0,1}log(m)G(x)=0\sum_{x \in \{0, 1\}^{log(m)}} G(x) = 0?

We can view matrices A,B,CFm×mA, B, C \in \mathbb{F}^{m \times m} as functions with the following signature: {0,1}s×{0,1}sF\{0, 1\}^s \times \{0, 1\}^s \rightarrow \mathbb{F} where s=log(m)s = log(m).

We view A,B,CA, B, C as vectors of 2s2s coefficients (functions on the hyperboolean cube of dimension 2s2s). The first ss coordinates denote the row, the second ss coordinates denote the column:

A[0][0]=A~(0,...,0,0,...,0)A[0][0] = \tilde A(0, ..., 0, 0, ..., 0)

A[0][1]=A~(0,...,0,0,...,1)A[0][1] = \tilde A(0, ..., 0, 0, ..., 1)

A[0][m]=A~(0,...,0,1,...,1)A[0][m] = \tilde A(0, ..., 0, 1, ..., 1)

......

A~\tilde A, B~\tilde B, C~\tilde C are MLEs of A,B,CA, B, C.

Let’s write z=(io,1,w)z = (io, 1, w), where ioio is the input and ww is the witness. We view zz as a function on the hyperboolean cube of dimension ss, and we take its MLE: z~\tilde z.

Let’s have the following function for x{0,1}sx \in \{0, 1\}^s:

f(x)=y{0,1}sA~(x,y)z~(y)y{0,1}sB~(x,y)z~(y)y{0,1}sC~(x,y)z~(y)f(x) = \sum_{y \in \{0, 1\}^s} \tilde A(x, y) \tilde z(y) \cdot \sum_{y \in \{0, 1\}^s} \tilde B(x, y) \tilde z(y) - \sum_{y \in \{0, 1\}^s} \tilde C(x, y) \tilde z(y)

Using the sum-check protocol, we can now prove:

x{0,1}sf(x)=0\sum_{x \in \{0, 1\}^s} f(x) = 0

But this is not what we need. However, our R1CS can be rewritten as:

f(x)=0foreachx{0,1}sf(x) = 0 \; \text{for} \; \text{each} \; x \in \{0, 1\}^s

And this can be proven by the zero-check protocol, which means running the sum-check protocol for the following polynomial:

g(t)=x{0,1}sf(x)eq(t,x)g(t) = \sum_{x \in \{0, 1\}^s} f(x) \cdot eq(t, x)

where

eq(t,x)=Πi=1s(tixi+(1ti)(1xi))eq(t, x) = \Pi_{i=1}^s (t_i x_i + (1-t_i)(1 - x_i))

In the sum-check protocol, the prover does most of the work, and the verifier is left to compute one evaluation of the function at a random point:

ex=g(rx)e_x = g(r_x)

where exe_x is computed by the prover and rxr_x is a random point from Fs\mathbb{F}^s.

So, the verifier needs to efficiently compute g(rx)g(r_x). The paper proposes the prover to compute:

vA=y{0,1}sA~(rx,y)z~(y)v_A = \sum_{y \in \{0, 1\}^s} \tilde A(r_x, y) \tilde z(y)

vB=y{0,1}sB~(rx,y)z~(y)v_B = \sum_{y \in \{0, 1\}^s} \tilde B(r_x, y) \tilde z(y)

vC=y{0,1}sC~(rx,y)z~(y)v_C = \sum_{y \in \{0, 1\}^s} \tilde C(r_x, y) \tilde z(y)

The verifier then needs to check:

ex=(vAvBvC)eq(τ,rx)e_x = (v_A v_B - v_C) \cdot eq(\tau, r_x)

However, the prover needs to prove that vA,vB,vCv_A, v_B, v_C have been computed correctly, and for this, the sum-checks can be used again (three sum-checks or, better, a random linear combination of three sum-checks). The claims to be checked are:

vA=A~(rx,ry)z(ry)v_A = \tilde A(r_x, r_y) z(r_y)

vB=B~(rx,ry)z(ry)v_B = \tilde B(r_x, r_y) z(r_y)

vC=C~(rx,ry)z(ry)v_C = \tilde C(r_x, r_y) z(r_y)