# Spartan: Full Protocol Description
_This doc is a work in progress. Do not recommend reading._
_Reference implementation: [Hoplite](https://github.com/personaelabs/Hoplite)_
## Public Setup
- Compute the Pedersen commitment generators using [hash-to-curve](https://github.com/personaelabs/spartan-ecdsa/blob/main/packages/secq256k1/src/hashtocurve.rs).
## Building blocks
$Fp$: The finite field used in the protocol.
### Pedersen commitment
Commitment
Multi-commitments
### proof-of-dot-prod
TBD
### proof-of-equality
TBD
### proof-of-opening
TBD
### zk-sum-check
The details of the zk-sum-check protocol isn't provided in the Spartan paper (it only mentions that it uses methods form prior constructions). The following is a description of the zk-sum-check protocol used in the [original Spartan implementation](https://github.com/microsoft/Spartan).
_Required prior knowledge: [The sum-check protocol](https://zkproof.org/2020/03/16/sum-checkprotocol/)_
**Notations**
- $g$: The polynomial which the sum is proven. We assume that $g$ is a multilinear polynomial (i.e. degree = 1) for simplicity.
- $H$: The sum of evaluates of $g$ over the boolean hypercube.
- $m$: The number of variables in $g$.
- $s$: $\lfloor{log_2{m}}\rfloor$
The protocol consists of $m$ rounds.
**Prover: First round**
In the first round, the prover computes
$$g_1(X) = \sum_{i\in\{0, 1\}^{s-1}} g(X, x_2, ... x_m)$$
In the standard sum-check protocol $g_1$ is sent to the verifier and the verifier checks
$$g_1(0) + g_1(1) \stackrel{?}{=} H$$
and
$$g_1(r_1) \stackrel{?}{=} \sum_{i\in\{0, 1\}^{s-1}} g(r_1, x_2, ... x_m)$$
where $r_1$ is a challenge.
The evaluation of $g$ in the second check is proven in the successive sum-check protocol.
In zk-sum-check, we instead provide the proof of evaluation of $g_1(0)$ $g_1(1)$ and $g_1(r_1)$ without revealing the coefficients of $g_1$, using proof-of-dot-product. For efficiency, we combine the evaluations into a single proof as follows.
First, since we assume $g$ is a multilinear polynomial, we can write
$$g_1(X) = p_1X + p_0$$
where $p_0, p_1 \in Fp$ . $p_1$ is the coefficient and $p_0$ is the y-intercept.
Before running proof-of-dot-prod, the prover must send commitments
$$C_{g1} = \mathrm{multicom}((p_1, p_2), r_{g1})$$
$$C_{eval} = \mathrm{com}(g_1(r), r_{eval})$$
$$C_{sum} = \mathrm{com}((g_1(0) + g_1(1), r_{sum}))$$
to the verifier.
The prover computes the weighted sum of and $g_1(0) + g_1(1)$ and $g(r_1)$ using weights $w_0, w_1 \in F_p$ sent from the verifier as
$$(g_1(0) + g_1(1)) * w_0 + g_1(r_1) * w_1$$
$$= p_1w_0 + 2p_0w_0 + p_1w_1r_1 + p_0w_1$$
$$= p_1(w_0 + r_1w_1) + p_0(2w_0 + w_1)$$
Thus, we use proof-of-dot-prod to prove
$$(w_0 + r_1w_1, 2w_0 + w_1) \cdot (p_1, p_0) = (g_1(0) + g_1(1)) * w_0 + g_1(r_1) * w_1$$
Now we proceed to the rest of the rounds
### Prover: Rest of the rounds
The rest of the rounds proceed similary as the first round except that prover proves the evaluations of the polynomial
$$g_i(X) = \sum_{b\in \{0, 1\}^{s-1-i}}g(r_1, ...r_{i-1}, X, x_{i+1},...,{x_m})$$
### Prover: Last round
In the standard sum-check protocol, the verifier queries $g(r_1, ... ,r_m)$ using the oracle of $g$. and checks the result is equal to $g_m(r_m)$. In the Spartan's version of zk-sum-check, the prover instead provides the proof of evaluation of $g(r_1, ... ,r_m)$ **doing another zk-sum-check**. The details of this second zk-sum-check protocol is described later in this doc.
### Verification
The verifier receives
- Claimed sum $H$
- proof-of-dot-products $\{dp_1, dp_2, ... dp_m\}$
Recall that the dot-product relation is
$$(w_0 + r_1w_1, 2w_0 + w_1) \cdot (p_1, p_0) = (g_1(0) + g_1(1)) * w_0 + g_1(r_1) * w_1$$
The verifier have access to $r_1, w_0, w_1$ and the commitments $Cy, Cx, C_{eval}$..
The verifier computes the **target commitment**
$$Ct = C_{sum} * w_0 + C_{eval} * w_1$$
and checks the dot product proof
$$
TBD
$$
## Main Protocol
Now we'll see how Spartan (_SpartanNIZK to be precise!_) uses the above building blocks to construct an NIZK for R1CS satisfiability.
---
**Below this is especially WIP! A lot of incomplete stuff!**
1.$P$ Commit the witness polynomial
- $P: C = PC.commit(pp, \bar{w}, S)$
send $C$ to the verifier 2.$V$ Randomly sample a challenge $\tau$ to query $\mathbb{g}$
- $\tau \in \mathbb{F^{log_m}}$ and send $\tau$ to the prover
4. Let $T_1 = 0$,
5. $V: sample r_x \in \mathbb{F^{u1}}$
6. $G_{io},\tau(x) = (\sum_{y \in \{0, 1\}^s} \widetilde{A}(x, y)\widetilde{Z}(y) + \sum_{y \in \{0, 1\}^s}\widetilde{B}(x, y)\widetilde{Z}(y) - \sum_{y \in \{0, 1\}^s}\widetilde{C}(x, y)\widetilde{Z}(y))\widetilde{eq}(x, \tau)$
$\sum_{x \in \{0, 1\}^s} G_{io},\tau(x) = 0$ for a random $\tau$ iff all the constraints are satisfied
- Run sumcheck on $G_{io},\tau(x)$
- At the last step of the sum check where the verifier queries $G_{io}, \tau(x)$, we use the following sub-protocol.
Define
- $\bar{A}(x) = \sum_{y \in \{0, 1\}^s} \widetilde{A}(x, y)$
- $\bar{B}(x) = \sum_{y \in \{0, 1\}^s} \widetilde{B}(x, y)$
- $\bar{C}(x) = \sum_{y \in \{0, 1\}^s} \widetilde{C}(x, y)$
- $M_{r_x}(y) = r_A * \widetilde{A}(x, y)\widetilde{Z}(y) + r_B * \widetilde{B}(x, y)\widetilde{Z}(y) + r_C * \widetilde{C}(x, y)\widetilde{Z}(y)$
Run the sum-check protocol to verify $M_{r_x}(y)$
- $P$
- Send evaluations $v_A = \bar{A}(r_x), v_B = \bar{B}(r_x), v_C = \bar{C}(r_x)$ to the verifier.
- Send the opening $v_Z = Z(r_x)$ to the verifier
- $V$
- Check $(v_A + v_B - v_C) * eq(r_x, \tau) = e_x$
The last part of the second sum-check protocol
- $v_1 = \widetilde{A}(r_x, r_y)$
- $v_2 = \widetilde{B}(r_x, r_y)$
- $v_3 = \widetilde{C}(r_x, r_y)$
- check taht $(r_A * v_1 + r_B * v_2 + r_C * v_3) * v_z = e_y$
In the last round, the verifier needs to query $g(x)$. We will construct a protocol that is specific to Spartan that allows us to query $g(x)$ in zero-knowledge.
### The second zk-sum-check
Instead of constructing a generic method to evalute $g(X)$ in zk, we focus on $g(X)$ which is specific to Spartan. Recall that we want to prove the sum of
$$G_{io},\tau(x) = (\sum_{y \in \{0, 1\}^s} \widetilde{A}(x, y)\widetilde{Z}(y) + \sum_{y \in \{0, 1\}^s}\widetilde{B}(x, y)\widetilde{Z}(y) - \sum_{y \in \{0, 1\}^s}\widetilde{C}(x, y)\widetilde{Z}(y))\widetilde{eq}(x, \tau)$$
By looking at the terms of $\widetilde{F}(x)$, each term is in a form that is suitable to apply the SumCheck protocol. Assume for now that we can check the validity of each term (i.e each sum of $\widetilde{A}(x, y)\widetilde{Z}$, $\widetilde{B}(x, y)\widetilde{Z}$ and $\widetilde{C}(x, y)\widetilde{Z}$), we can check the relation of the sums as follows.
Define
- $\bar{A}(x) = \sum_{y \in \{0, 1\}^s} \widetilde{A}(x, y)$
- $\bar{B}(x) = \sum_{y \in \{0, 1\}^s} \widetilde{B}(x, y)$
- $\bar{C}(x) = \sum_{y \in \{0, 1\}^s} \widetilde{C}(x, y)$
Now, recall that we want to evaluate $G_{io},\tau(x)$ only at the last round of the zk-sum-check over the all round_challenges $r_x = \{r_1, r_2, ... r_m\}$.
Hence the prover can provide the evaluations $v_A, v_B$ and $v_C$ to the verifier.
$$v_A = \bar{A}(r_x), v_B = \bar{B}(r_x), v_C = \bar{C}(r_x)$$
The verifier checks that the evaluation of $G_{io}$ is equal to the evaluation of $g_m(r_m)$
$$g_m(r_m) \stackrel{?}{=} (v_A + v_B - v_C)\widetilde{eq}(r_x, \tau)$$
The verifier also needs to check the validity of $\bar{A}(x), \bar{B}(x), \bar{C}(x)$.
This is where the second zk-sum-check comes in.
We can check each term individually, but for efficiency, we use a random linear combination of the three terms.
and sample challnges $r_A, r_B, r_C \in_R F_p$ to compute the random linear combination
$$
\widetilde{M}(x) \\ = r_A \bar{A}(r_x) + r_B\bar{B}(r_x) + r_C\bar{C}(r_x) \\
= (r_A\widetilde{A}(r_x, r_y) + r_B\widetilde{B}(r_x, r_y) + r_C\widetilde{C}(r_x, r_y))\widetilde{Z}(r_x, r_y)
$$
At the end of the second zk-sum-check, the verifier needs to evaluate $\widetilde{Z}(r_x, r_y)$. In order to evaluate without knowing the coefficients, we use the proof_log-of-dot-prod protocol. Note that the prover needs to commit to $Z(x)$ at the beginning so it cannot just come up with a $Z(x)$ that passes the final check of the second zk-sum-check.