# Understanding Ligerito: A Fast, Recursive Polynomial Commitment Scheme This note explains the paper > Ligerito: A Small and Concretely Fast Polynomial Commitment Scheme > Andrija Novakovic, Guillermo Angeris, May 2025 > Link: https://eprint.iacr.org/2025/1187 in a way that is suitable for engineers who know basic linear algebra, finite fields, and are at least somewhat familiar with polynomial commitment schemes and sumcheck-type protocols. Roughly speaking, Ligerito is: * A polynomial commitment scheme and inner product argument. * Designed for univariate and multilinear polynomial evaluations. * Flexible in the choice of code and field. * Asymptotically small: proof size about \begin{equation} O\left(\frac{\log(N)^2}{\log\log(N)}\right) \end{equation} where $N$ is the number of coefficients (the input size). * Fast in practice on consumer hardware. For example, the paper reports: * Polynomial with $2^{24}$ coefficients over a 32-bit binary field (about 64 MiB of data). * Julia implementation running on an M1 MacBook Pro. * Proving time about 1.3 seconds. * Proof size about 255 KiB. The goal is not to reproduce every line of the paper but to give you a clear mental model of what the protocol is doing and why it works. ## Notation and tricks We follow the paper’s notation, but in a slightly more informal style. * Let $\mathbb{F}$ be a finite field. Sometimes a subfield $\mathbb{F}' \subseteq \mathbb{F}$ is also used. * Vectors are column vectors in $\mathbb{F}^n$. * Matrices are in $\mathbb{F}^{m \times n}$. We often interpret vectors of length $2^k$ as evaluation tables of multilinear polynomials in $k$ variables. ### vec and Mat Given a matrix $\tilde{X} \in \mathbb{F}^{m \times n}$: * $\operatorname{vec}(\tilde{X})$ is the $mn$-vector obtained by stacking the columns of $\tilde{X}$ into a single column. * Given a vector $v \in \mathbb{F}^{mn}$, $\operatorname{Mat}(v)$ is the matrix obtained by reshaping $v$ into an $m \times n$ matrix in column-major order. We will often omit explicit dimensions and rely on context. When there is any ambiguity, the paper makes the dimensions explicit; in this note, we will mention them when needed. :::info ### Example: column-major reshaping Let \begin{equation} \tilde{X} = \begin{pmatrix} x_{11} & x_{12} & x_{13} \\ x_{21} & x_{22} & x_{23} \end{pmatrix} \in \mathbb{F}^{2 \times 3}. \end{equation} Then $\operatorname{vec}(\tilde{X})$ stacks the columns of $\tilde{X}$ into one long vector: \begin{equation} \operatorname{vec}(\tilde{X}) = \begin{pmatrix} x_{11} \\ x_{21} \\ x_{12} \\ x_{22} \\ x_{13} \\ x_{23} \end{pmatrix} \in \mathbb{F}^{6}. \end{equation} Conversely, if we start from \begin{equation} v = \begin{pmatrix} x_{11} \\ x_{21} \\ x_{12} \\ x_{22} \\ x_{13} \\ x_{23} \end{pmatrix} \end{equation} and apply $\operatorname{Mat}(v)$ with shape $2 \times 3$, we recover \begin{equation} \operatorname{Mat}(v) = \begin{pmatrix} x_{11} & x_{12} & x_{13} \\ x_{21} & x_{22} & x_{23} \end{pmatrix}. \end{equation} So $\operatorname{Mat}(\operatorname{vec}(\tilde{X})) = \tilde{X}$ and $\operatorname{vec}(\operatorname{Mat}(v)) = v$. ::: ### Kronecker product and barred vectors The Kronecker product of matrices $A \in \mathbb{F}^{m\times n}$ and $B \in \mathbb{F}^{m'\times n'}$ is: \begin{equation} A \otimes B = \begin{bmatrix} A_{11} B & A_{12} B & \dots & A_{1n} B \\ A_{21} B & A_{22} B & \dots & A_{2n} B \\ \vdots & \vdots & \ddots & \vdots \\ A_{m1} B & A_{m2} B & \dots & A_{mn} B \end{bmatrix} \end{equation} The resulting matrix is of size $mm' \times nn'$. For a vector $r \in \mathbb{F}^k$, the paper defines the “barred” vector \begin{equation} \bar{r} = (1 - r_1, r_1) \otimes \dots \otimes (1 - r_k, r_k), \end{equation} which is a vector in $\mathbb{F}^{2^k}$. This will be the core object for multilinear interpolation. :::info ### Example: small Kronecker products and a barred vector 1. Kronecker product of two $2 \times 2$ matrices. Let \begin{equation} A = \begin{pmatrix} a & b \\ c & d \end{pmatrix}, \quad B = \begin{pmatrix} e & f \\ g & h \end{pmatrix}. \end{equation} Then $A \otimes B$ is a $4 \times 4$ matrix: \begin{equation} A \otimes B = \begin{pmatrix} aB & bB \\ cB & dB \end{pmatrix}= \begin{pmatrix} a e & a f & b e & b f \\ a g & a h & b g & b h \\ c e & c f & d e & d f \\ c g & c h & d g & d h \end{pmatrix}. \end{equation} So each entry of $A$ scales an entire copy of $B$, and these blocks are placed in a grid. 2. Barred vector for $k = 2$. Let $r = (r_1, r_2) \in \mathbb{F}^2$. Then \begin{equation} \bar{r} = (1 - r_1, r_1) \otimes (1 - r_2, r_2). \end{equation} Writing this out explicitly: \begin{equation} \bar{r} = \begin{pmatrix} (1 - r_1)(1 - r_2) \\ (1 - r_1) r_2 \\ r_1 (1 - r_2) \\ r_1 r_2 \end{pmatrix} \in \mathbb{F}^4. \end{equation} This 4-entry vector will be used to evaluate a 2-variable multilinear polynomial at the point $(r_1, r_2)$ via a simple inner product with its coefficient vector. ::: ### Interpreting vectors as multilinear polynomials Let $v \in \mathbb{F}^{2^k}$ be any vector. For $z \in \mathbb{F}^k$, the paper writes \begin{equation} v(z) = v^T \bar{z} = v^T\big((1 - z_1, z_1) \otimes \dots \otimes (1 - z_k, z_k)\big). \end{equation} This means: * We interpret $v$ as the coefficient vector of a multilinear polynomial in $k$ variables. * Evaluating the polynomial at $z$ is equivalent to taking the inner product $v^T \bar{z}$. So “writing $v$ as a function” means “interpreting $v$ as a polynomial and evaluating it via the barred vector”. :::info ### Example: $k = 2$ variables Let \begin{equation} v = \begin{pmatrix} v_0 \\ v_1 \\ v_2 \\ v_3 \end{pmatrix}= \begin{pmatrix} P(0,0) \\ P(0,1) \\ P(1,0) \\ P(1,1) \end{pmatrix} \in \mathbb{F}^4. \end{equation} Then for $z = (z_1, z_2) \in \mathbb{F}^2$, the barred vector is \begin{equation} \bar{z} = \begin{pmatrix} (1 - z_1)(1 - z_2) \\ (1 - z_1) z_2 \\ z_1 (1 - z_2) \\ z_1 z_2 \end{pmatrix}. \end{equation} Taking the inner product gives \begin{aligned} v(z) &= v^T \bar{z} \\ &= v_0(1 - z_1)(1 - z_2) +v_1(1 - z_1)z_2 +v_2 z_1(1 - z_2)+v_3 z_1 z_2. \end{aligned} This is exactly the multilinear interpolation formula for a bivariate polynomial $P(z_1, z_2)$ defined by its values at the Boolean cube $\{0,1\}^2$. ::: ### Partial evaluation as a matrix–vector product Now we want to fix some of the variables and obtain a smaller polynomial. Let $v \in \mathbb{F}^{2^k}$, and suppose we want to fix the first $k' \le k$ variables at a point $r \in \mathbb{F}^{k'}$. We define \begin{equation} y = \operatorname{Mat}(v)\bar{r}. \end{equation} By construction: * $\bar{r}$ has length $2^{k'}$. * So $\operatorname{Mat}(v)$ must be a matrix of size $2^{k-k'} \times 2^{k'}$, reshaping $v$ in column-major order. * Therefore $y \in \mathbb{F}^{2^{k-k'}}$. The key interpretation is: \begin{equation} y(z) = v(r, z) \quad \text{for all } z \in \mathbb{F}^{k-k'}. \end{equation} So $y$ is exactly the coefficient vector of the partially evaluated polynomial where the first $k'$ variables are fixed to $r$. :::info ### Example: $k = 3$ variables, fix the first $k' = 2$ Let $v \in \mathbb{F}^{2^3}$ correspond to a polynomial $P(z_1, z_2, z_3)$ with coefficients ordered as \begin{equation} v = \begin{pmatrix} v_0 \\ v_1 \\ v_2 \\ v_3 \\ v_4 \\ v_5 \\ v_6 \\ v_7 \end{pmatrix} \begin{pmatrix} P(0,0,0) \\ P(0,0,1) \\ P(0,1,0) \\ P(0,1,1) \\ P(1,0,0) \\ P(1,0,1) \\ P(1,1,0) \\ P(1,1,1) \end{pmatrix}. \end{equation} We reshape this vector in column-major order into a $2^{k - k'} \times 2^{k'} = 2 \times 4$ matrix: \begin{equation} \operatorname{Mat}(v) = \begin{pmatrix} v_0 & v_2 & v_4 & v_6 \\ v_1 & v_3 & v_5 & v_7 \end{pmatrix}. \end{equation} Now fix $r = (r_1, r_2) \in \mathbb{F}^2$, and form the barred vector \begin{equation} \bar{r} = \begin{pmatrix} (1 - r_1)(1 - r_2) \\ (1 - r_1) r_2 \\ r_1 (1 - r_2) \\ r_1 r_2 \end{pmatrix}. \end{equation} Then multiply: \begin{aligned} y &= \operatorname{Mat}(v)\bar{r} \\ &= \begin{pmatrix} v_0(1 - r_1)(1 - r_2) + v_2(1 - r_1)r_2 + v_4 r_1(1 - r_2) + v_6 r_1 r_2 \\ v_1(1 - r_1)(1 - r_2) + v_3(1 - r_1)r_2 + v_5 r_1(1 - r_2) + v_7 r_1 r_2 \end{pmatrix}. \end{aligned} This result $y = (y_0, y_1)^T \in \mathbb{F}^2$ is exactly the coefficient vector of the univariate polynomial \begin{equation} z_3 \mapsto P(r_1, r_2, z_3). \end{equation} So multiplying by $\bar{r}$ corresponds to “plugging in” the first two variables $(z_1,z_2) = (r_1,r_2)$ and leaving only $z_3$ free. ::: We will use this vector–matrix–polynomial dictionary repeatedly in what follows. ## Tool 1: The Ligero-style Matrix–Vector Product (MVP) The first building block of Ligerito is a Ligero-style matrix–vector product check. It allows one party (the prover) to convince another (the verifier) that they know a hidden matrix $\tilde{X}$ such that \begin{equation} y_r = \tilde{X} \bar{r}, \end{equation} without revealing $\tilde{X}$ itself. At a high level, this is a *consistency check* between a committed matrix and a claimed linear operation on it. The verifier never sees $\tilde{X}$ directly; they only see a cryptographic commitment to it and a few selectively opened rows. ### Setting We begin with three objects: 1. A matrix $\tilde{X} \in \mathbb{F}^{n \times n'}$ known only to the prover. 2. A linear error-correcting code with generator matrix \begin{equation} G \in \mathbb{F}^{m \times n}, \quad d(G) = d > 0, \end{equation} which defines how data is *encoded* into a larger redundancy space. 3. A challenge vector $\bar{r} \in \mathbb{F}^{n'}$, typically derived from a random point $r$ via \begin{equation} \bar{r} = (1 - r_1, r_1) \otimes \dots \otimes (1 - r_{k'}, r_{k'}). \end{equation} Each column of $\tilde{X}$ can be thought of as a small message, and multiplying by $G$ encodes it into a longer, redundant form. ### Encoding and Commitment To commit to its hidden matrix, the prover *encodes* every column of $\tilde{X}$ using the code $G$: \begin{equation} X = G \tilde{X}. \end{equation} This $X \in \mathbb{F}^{m \times n'}$ is a *codeword matrix*: every column of $X$ lies in the code generated by $G$. The prover then commits to all rows of $X$ by constructing a Merkle tree over the rows and sending the root $C$ to the verifier. This ensures the prover cannot later modify individual rows without detection. ### The Random Linear Check After receiving $C$, the verifier challenges the prover with a random vector $r$ (and hence $\bar{r}$). Intuitively, this challenge defines one random linear combination of the columns of $\tilde{X}$. The prover computes \begin{equation} y_r = \tilde{X} \bar{r} \end{equation} and sends $y_r$ back to the verifier. This $y_r$ is the claimed result of multiplying the hidden matrix $\tilde{X}$ by the known vector $\bar{r}$. The verifier now wants to be convinced that $y_r$ really was computed from the committed $\tilde{X}$ — without seeing $\tilde{X}$ directly. ### The Core Check To verify, the verifier samples a random subset $S$ of row indices and asks the prover to open those rows of $X$, along with their Merkle proofs. From these opened rows, the verifier computes \begin{equation} X_S \bar{r} \end{equation} and compares it to the corresponding encoded version of $y_r$: \begin{equation} G_S y_r. \end{equation} The verifier accepts if and only if \begin{equation} \underbrace{X_S \bar{r}}_{\substack{\text{Apply the challenge } \bar{r} \\ \text{to opened rows of } X}}= \underbrace{G_S y_r}_{\substack{\text{Encode the claimed result } y_r \\ \text{using the same code rows}}}. \end{equation} ### Why This Works If the prover is honest, both quantities match exactly: \begin{equation} \begin{aligned} X_S\bar{r} &= (G\tilde{X})_S \bar{r} \\ &= (G_S \tilde{X}) \bar{r} \\ &= G_S (\tilde{X} \bar{r}) \\ &= G_S y_r. \end{aligned} \end{equation} If the prover cheats—by committing to an $X$ that does not correspond to any $\tilde{X}$ under $G$, or by sending an incorrect $y_r$—then the equality is violated for most random choices of $S$ and $r$. Coding theory ensures that the probability of passing the check by accident is negligible. :::info ### Example: A MVP check with redundancy Let the prover’s secret matrix be \begin{equation} \tilde{X} = \begin{pmatrix} x_{11} & x_{12} \\ x_{21} & x_{22} \end{pmatrix} \in \mathbb{F}^{2\times 2}. \end{equation} We use a small redundant code matrix \begin{equation} G = \begin{pmatrix} 1 & 0 \\ 0 & 1 \\ 1 & 1 \end{pmatrix} \in \mathbb{F}^{3\times 2}. \end{equation} Each column of $\tilde{X}$ is now encoded into a 3-dimensional codeword, producing \begin{equation} X = G \tilde{X} = \begin{pmatrix} x_{11} & x_{12} \\ x_{21} & x_{22} \\ x_{11}+x_{21} & x_{12}+x_{22} \end{pmatrix} \in \mathbb{F}^{3\times 2}. \end{equation} The prover commits to the rows of $X$ (for example via a Merkle tree). When the verifier samples a random challenge vector \begin{equation} \bar{r} = \begin{pmatrix} r_1 \\ r_2 \end{pmatrix}, \end{equation} the prover computes \begin{equation} y_r = \tilde{X}\,\bar{r} = \begin{pmatrix} x_{11} r_1 + x_{12} r_2 \\ x_{21} r_1 + x_{22} r_2 \end{pmatrix} \in \mathbb{F}^{2}. \end{equation} Now the verifier wants to check the key consistency equation \begin{equation} X\,\bar{r} \stackrel{?}{=} G\,y_r. \end{equation} Let’s expand both sides. **Left-hand side (computed from $X$):** \begin{equation} X\,\bar{r} = \begin{pmatrix} x_{11}r_1 + x_{12}r_2 \\ x_{21}r_1 + x_{22}r_2 \\ (x_{11}+x_{21})r_1 + (x_{12}+x_{22})r_2 \end{pmatrix}. \end{equation} **Right-hand side (computed from $G$ and $y_r$):** \begin{equation} G\,y_r = \begin{pmatrix} 1 & 0 \\ 0 & 1 \\ 1 & 1 \end{pmatrix} \begin{pmatrix} x_{11}r_1 + x_{12}r_2 \\ x_{21}r_1 + x_{22}r_2 \end{pmatrix} = \begin{pmatrix} x_{11}r_1 + x_{12}r_2 \\ x_{21}r_1 + x_{22}r_2 \\ (x_{11}+x_{21})r_1 + (x_{12}+x_{22})r_2 \end{pmatrix}. \end{equation} The two sides match exactly. But now, because $G$ has more rows than columns, the commitment $X = G\tilde{X}$ includes redundant information. If the prover tried to cheat by changing one entry of $\tilde{X}$, some subset of the queried rows of $X$ would almost certainly fail the equality check. This is the core idea of the MVP protocol: the verifier checks a small random subset of rows of $X$ against the expected linear relation, and with a well-chosen code $G$, soundness follows from its distance properties. ::: ### Short summary The Ligero-style MVP check provides a reusable primitive: $$ \text{Commit to } X = G\tilde{X} \quad \text{and prove } y_r = \tilde{X}\bar{r}. $$ It guarantees: * **Completeness:** If the prover is honest, the verifier always accepts. * **Soundness:** If the verifier accepts, then (except with small probability) the commitment corresponds to a unique $\tilde{X}$ such that $y_r = \tilde{X}\bar{r}$. ## Tool 2: Partial Sumcheck The second building block is a variant of the classic sumcheck protocol. The standard sumcheck protocol allows a verifier to be convinced that \begin{equation} \sum_{z \in \{0,1\}^k} f(z) = \alpha \end{equation} for some low-degree polynomial $f$, known to the prover. In Ligerito, we apply this idea to *inner products* between two multilinear functions. ### From sums to inner products Let $w(z)$ and $\tilde{X}(z)$ be two multilinear functions defined over $\{0,1\}^k$. We want to verify that \begin{equation} \sum_{z \in \{0,1\}^k} w(z)\tilde{X}(z) = \alpha. \end{equation} If we flatten these functions into vectors of length $2^k$: \begin{equation} w = \begin{pmatrix} w(z_1) \\ \vdots \\ w(z_{2^k}) \end{pmatrix}, \qquad \operatorname{vec}(\tilde{X}) = \begin{pmatrix} \tilde{X}(z_1) \\ \vdots \\ \tilde{X}(z_{2^k}) \end{pmatrix}, \end{equation} then this sum is exactly the standard inner product \begin{equation} w^T \operatorname{vec}(\tilde{X}) = \alpha. \end{equation} Hence, sumcheck can be understood as a protocol for verifying a large inner product over the Boolean cube. :::info ### Example: inner product as a Boolean sum For $k = 2$, the Boolean hypercube $\{0,1\}^2$ consists of the points $(0,0), (0,1), (1,0), (1,1)$. The claim $$ \sum_{z \in {0,1}^2} w(z)\tilde{X}(z) = \alpha $$ is simply \begin{aligned} &w(0,0)\tilde{X}(0,0) * w(0,1)\tilde{X}(0,1) \\ &* w(1,0)\tilde{X}(1,0) * w(1,1)\tilde{X}(1,1) = \alpha, \end{aligned} which is the inner product of two 4-dimensional vectors. ::: ### Classical sumcheck In the standard sumcheck protocol, the verifier checks the claim \begin{equation} \sum_{z \in {0,1}^k} f(z) = \alpha \end{equation} through an iterative process that folds one variable at a time. At round $i$: 1. The prover sends a univariate polynomial $s_i(t)$ defined as \begin{equation} s_i(t) = \sum_{z_{i+1},\dots,z_k \in \{0,1\}} f(r_1,\dots,r_{i-1}, t, z_{i+1},\dots,z_k), \end{equation} where $r_1,\dots,r_{i-1}$ are the random field elements chosen in the previous rounds. 2. The verifier checks the consistency condition \begin{equation} s_i(0) + s_i(1) \stackrel{?}{=} s_{i-1}(r_{i-1}), \end{equation} where $s_0(t)$ is defined as the constant polynomial $\alpha$. 3. The verifier samples a new random field element $r_i$ and continues to the next round. After $k$ rounds, all variables are fixed. The verifier is left with a single point check of $f$ at the random point $(r_1,\dots,r_k)$. If $f$ has degree at most $2$ in each variable, the soundness error is about $k / |\mathbb{F}|$. ### Partial sumcheck: stopping early In Ligerito, we often do not need to fold all variables. Instead, we start from a sum over $k + k'$ variables and only fold the first $k'$ variables, leaving the last $k$ variables “alive”. Formally: \begin{equation} \underbrace{ \sum_{z \in \{0,1\}^{k+k'}} w(z)\,\tilde{X}(z) }_{\text{full sum over } 2^{k+k'} \text{ points}} \;\xrightarrow[\text{fold first } k']{r = (r_1,\dots,r_{k'})}\; \underbrace{ \sum_{z' \in \{0,1\}^k} w(r,z')\,\tilde{X}(r,z') }_{\text{reduced sum over } 2^{k} \text{ points}}. \end{equation} ### How the protocol unfolds Partial sumcheck proceeds for $k'$ rounds—one per variable to be folded. At round $i$ ($1 \le i \le k'$): 1. The prover constructs a polynomial \begin{aligned} s_i(t) = \sum_{z_{i+1},\dots,z_{k+k'} \in \{0,1\}^{k+k'-i}} w(r_1,\dots,r_{i-1}, t, z_{i+1},\dots,z_{k+k'}) \\ \tilde{X}(r_1,\dots,r_{i-1}, t, z_{i+1},\dots,z_{k+k'}). \end{aligned} The polynomial $s_i(t)$ encodes the partial sum when the first $i-1$ variables are fixed and the $i$-th is symbolic. 2. The verifier checks the consistency condition \begin{equation} s_i(0) + s_i(1) = s_{i-1}(r_{i-1}), \end{equation} with $s_0 = \alpha$. 3. The verifier samples a random $r_i \in \mathbb{F}$ and continues. After $k'$ rounds, all first $k'$ variables have been fixed to $(r_1,\dots,r_{k'})$, and the verifier holds: * A polynomial $s_{k'}$, * The challenges $r_1,\dots,r_{k'}$, * A final equality to check: \begin{equation} s_{k'}(r_{k'}) = \alpha', \end{equation} where \begin{equation} \alpha' = \underbrace{ \sum_{z' \in \{0,1\}^k} w(r,z')\,\tilde{X}(r,z') }_{\text{reduced sum over } 2^{k} \text{ points}}. \end{equation} Hence, the sum over $2^{k+k'}$ Boolean points has been reduced to a smaller sum over only $2^k$ points. The soundness error is approximately $2k' / |\mathbb{F}|$, which is negligible for large fields. :::info ### Example: partial sumcheck with $k' = 1$ Suppose we have three variables $z = (z_1, z_2, z_3)$, and we wish to check $$ \sum_{z_1,z_2,z_3 \in \{0,1\}} w(z),\tilde{X}(z) = \alpha, $$ but we only want to fold the first variable $z_1$. 1. The prover defines $$ s_1(t) = \sum_{z_2,z_3 \in \{0,1\}} w(t,z_2,z_3),\tilde{X}(t,z_2,z_3), $$ which is a degree-2 polynomial. 2. The verifier checks $$ s_1(0) + s_1(1) \stackrel{?}{=} \alpha. $$ 3. The verifier samples a random $r_1 \in \mathbb{F}$. Now the remaining claim is $$ \sum_{z_2,z_3 \in \{0,1\}} w(r_1,z_2,z_3),\tilde{X}(r_1,z_2,z_3) = \alpha', $$ where $\alpha' = s_1(r_1)$. We have reduced a sum over 3 Boolean variables to a sum over 2 variables, evaluated at a random $r_1$. ::: ### Matrix viewpoint Using the vector–matrix notation developed earlier, we can restate the partial sumcheck transformation compactly. We start with a vectorized claim \begin{equation} w^T \operatorname{vec}(\tilde{X}) = \alpha, \end{equation} where $w, \operatorname{vec}(\tilde{X}) \in \mathbb{F}^{2^{k+k'}}$. After folding the first $k'$ variables, we obtain: $$ \text{Random point } r = (r_1,\dots,r_{k'}) \in \mathbb{F}^{k'}. $$ We then define the partial evaluations: \begin{equation} w_r = \operatorname{Mat}(w)\bar{r}, \qquad y_r = \tilde{X}\bar{r}, \end{equation} where $\bar{r}$ is the barred vector \begin{equation} \bar{r} = (1 - r_1, r_1) \otimes \cdots \otimes (1 - r_{k'}, r_{k'}), \end{equation} and $\operatorname{Mat}(w)$ reshapes $w$ into a $2^k \times 2^{k'}$ matrix in column-major order. Both $w_r$ and $y_r$ lie in $\mathbb{F}^{2^k}$. The resulting smaller claim is then \begin{equation} \alpha' = w_r^T y_r. \end{equation} The final equality that the verifier checks is \begin{equation} s_{k'}(r_{k'}) = w_r^T y_r. \end{equation} Thus, partial sumcheck transforms a large inner product of length $2^{k+k'}$ into a smaller one of length $2^k$, while preserving correctness through a sequence of consistency checks. ### Batching and gluing The sumcheck protocol is linear in $w$. This enables two optimizations used throughout Ligerito. #### Batching multiple inner products Suppose we want to verify several inner product claims simultaneously: \begin{equation} w_1^T \operatorname{vec}(\tilde{X}) = \alpha_1, \quad w_2^T \operatorname{vec}(\tilde{X}) = \alpha_2, \quad \dots, \quad w_q^T \operatorname{vec}(\tilde{X}) = \alpha_q. \end{equation} We can combine them into a single batched claim using random coefficients $\beta_1,\dots,\beta_q \in \mathbb{F}$: \begin{equation} \tilde{w} = \sum_{j=1}^q \beta_j w_j, \qquad \tilde{\alpha} = \sum_{j=1}^q \beta_j \alpha_j. \end{equation} If any one of the original claims is false, the combined claim will also be false except with probability $1/|\mathbb{F}|$. Thus, only one sumcheck run is needed for all $q$ claims. :::info ### Example. For two claims $w_1^T x = \alpha_1$ and $w_2^T x = \alpha_2$, the verifier samples a random $\beta$, and the prover proves \begin{equation} (w_1 + \beta w_2)^T x = \alpha_1 + \beta \alpha_2. \end{equation} If either of the original equalities is false, this new one fails with probability at least $1 - 1/|\mathbb{F}|$. ::: #### Gluing multiple sumchecks We can also “glue” multiple sumcheck instances that fold different sets of variables. For example, we might first fold from $(k + k')$ variables down to $k$, then from $k$ to $k''$. Because sumcheck is linear, these two stages can be merged into a single longer sumcheck that folds all $k + k' - k''$ variables in one run. This ability to batch and glue sumchecks allows Ligerito to verify many algebraic relations together efficiently, with only negligible loss in soundness. ### Short summary Partial sumcheck provides a recursive mechanism for compressing large inner products into smaller ones: $$ \underbrace{w^T \operatorname{vec}(\tilde{X})}_{\text{size }2^{k+k'}} \quad \Longrightarrow \quad \underbrace{w_r^T y_r}_{\text{size }2^k}. $$ Each round folds one variable by interpolation and random evaluation, maintaining a consistency polynomial $s_i(t)$ whose checks ensure correctness. At the end, the verifier only needs to check \begin{equation} s_{k'}(r_{k'}) = w_r^T y_r, \end{equation} with negligible soundness error. Combined with the Ligero-style matrix–vector product protocol, this gives Ligerito its core recursive structure: sumcheck folds the problem down to smaller dimensions, and the MVP check ensures that each folded evaluation is consistent with the committed matrix. ## Combining MVP and partial sumcheck (base protocol) We now combine the two ingredients—the Ligero-style matrix–vector product (MVP) and the partial sumcheck—into a single protocol. This base protocol allows a prover to convince a verifier that \begin{equation} w^T \operatorname{vec}(\tilde{X}) = \alpha, \end{equation} for a matrix $\tilde{X}$ that the prover has committed to, but the verifier never sees directly. ### Intuition - The prover holds a secret matrix $\tilde{X} \in \mathbb{F}^{n \times n'}$. - The verifier wants to be convinced that the inner product between $w$ and $\operatorname{vec}(\tilde{X})$ equals $\alpha$. The protocol combines both tools as follows: 1. **Commit to $\tilde{X}$** using the MVP commitment phase, producing a Merkle root $C$. This binds the prover to all entries of $\tilde{X}$. 2. **Run a partial sumcheck** to reduce the global inner product $$ w^T \operatorname{vec}(\tilde{X}) = \alpha $$ to a smaller inner product $$ w_r^T y_r = \alpha', $$ where $$ w_r = \operatorname{Mat}(w)\bar{r}, \qquad y_r = \tilde{X}\bar{r}. $$ The vector $w_r$ is public and computable by the verifier, while $y_r$ is known only to the prover. 3. **Verify $y_r$ via MVP.** The prover sends $y_r$, and the verifier checks its correctness by querying random rows of the committed encoding $X = G\tilde{X}$: $$ X_S\bar{r} \stackrel{?}{=} G_S y_r. $$ 4. **Final consistency check.** Once $y_r$ is verified, the verifier checks that $$ s_{k'}(r_{k'}) = w_r^T y_r, $$ where $s_{k'}(t)$ is the last polynomial sent in the sumcheck. If both the MVP and sumcheck checks pass, the verifier is convinced that the original inner product claim holds. :::info ### Example: two-variable case Suppose $\tilde{X}$ depends on two Boolean variables $(z_1, z_2)$, and we want to check that $$ \sum_{z_1,z_2 \in \{0,1\}} w(z_1,z_2)\tilde{X}(z_1,z_2) = \alpha. $$ The verifier and prover run a one-round partial sumcheck (folding $z_1$): 1. The prover defines $$ s_1(t) = \sum_{z_2 \in \{0,1\}} w(t,z_2)\tilde{X}(t,z_2), $$ sends it to the verifier, and the verifier checks $$ s_1(0) + s_1(1) = \alpha. $$ 2. The verifier samples $r_1 \in \mathbb{F}$, fixing the first variable. 3. The new claim is $$ \sum_{z_2 \in \{0,1\}} w(r_1,z_2)\tilde{X}(r_1,z_2) = s_1(r_1), $$ or equivalently $$ w_r^T y_r = s_1(r_1), $$ with $y_r = \tilde{X}\bar{r_1}$. 4. The prover sends $y_r$, and the verifier checks it using MVP and the final equality. This small case illustrates the general pattern: each round of partial sumcheck produces a new “folded” vector $y_r$, verified by MVP. ::: ### Bottleneck and recursion The above protocol is sound and complete, but has a major cost: * The vector $y_r$ has length $2^k$, which can be very large. Sending it directly becomes the communication bottleneck. Ligerito’s idea is to avoid sending $y_r$ explicitly. Instead, it treats $y_r$ itself as a new matrix, commits to it via MVP, and reuses the same protocol recursively on this smaller instance. Each recursion level reduces the dimension, eventually producing a logarithmic-depth proof with only small vectors ever transmitted. This recursive folding–verification structure is what makes Ligerito both succinct and efficient. ## The Ligerito protocol (recursive version) The base protocol we just saw is sound, but it has a major communication bottleneck. At the end of the partial sumcheck, the prover must send the entire vector $y_r = \tilde{X}\bar{r}$. If we fold $k'$ variables from a total of $k+k'$, this $y_r$ is a vector of length $2^k$. If $k$ is large (e.g., $k=20$, $y_r$ has $\sim 1$ million elements), this is far too expensive. This is where Ligerito's core recursive idea comes in. **The Main Idea:** Instead of *sending* the large vector $y_r$, the prover will *commit* to it and start a *new* instance of the protocol. This creates a chain of smaller and smaller problems: 1. The prover starts with a big matrix $\tilde{X}_1$ and a claim about it. 2. They run one step of the protocol, which reduces the claim to a new, smaller vector $y_{r_1}$. 3. Instead of sending $y_{r_1}$, the prover reshapes it into a new, smaller matrix $\tilde{X}_2 = \operatorname{Mat}(y_{r_1})$. 4. They *commit* to $\tilde{X}_2$ and use the protocol *recursively* to prove two things: * (a) The original claim, which has now been "folded" onto $\tilde{X}_2$. * (b) That $\tilde{X}_2$ is *consistent* with the $\tilde{X}_1$ they committed to in the previous step. 5. This process repeats $\ell$ times, creating a chain $\tilde{X}_1 \to \tilde{X}_2 \to \dots \to \tilde{X}_\ell$. 6. The final matrix $\tilde{X}_\ell$ is so small that the prover can just send it directly, ending the recursion. ### The Recursive "Glue": Batching Two Claims At any step $i$ (for $i \ge 2$), the verifier has just received a commitment to $\tilde{X}_i$. They need to be convinced of two distinct types of claims: 1. **The Sumcheck Claim (from round $i-1$):** The partial sumcheck from the previous round $i-1$ ended with a final check: $$ s_{i-1}(r_{i-1}) = \underbrace{w_{r_{i-1}}^T y_{r_{i-1}}}_{\text{inner product from round } i-1} $$ Since $y_{r_{i-1}}$ *is* $\operatorname{vec}(\tilde{X}_i)$ by definition, this is an inner product claim about $\tilde{X}_i$: $$ \underbrace{(\operatorname{Mat}(\tilde{w}_{i-1})\bar{r}_{i-1})^T}_{\text{call this } \tilde{w}_i^{(\text{sumcheck})}} \operatorname{vec}(\tilde{X}_i) = \underbrace{s_{i-1}(r_{i-1})}_{\text{call this } \tilde{\alpha}_i^{(\text{sumcheck})}} $$ 2. **The MVP Claims (new for round $i$):** The verifier must also check that $\tilde{X}_i$ is *consistent* with the *previous* commitment $X_{i-1}$. They do this by running the MVP check on $X_{i-1}$: they sample a set $S_{i-1}$ of rows and challenge the prover. The prover must prove that for *every* row $j \in S_{i-1}$: $$ (X_{i-1})_j \bar{r}_{i-1} = (G_{i-1})_j y_{r_{i-1}} $$ Let $g_j^T$ be the $j$-th row of $G_{i-1}$. This is another inner product claim about $\tilde{X}_i$: $$ \underbrace{(g_j^T)^T}_{\text{call this } \tilde{w}_{ij}^{(\text{mvp})}} \operatorname{vec}(\tilde{X}_i) = \underbrace{(X_{i-1})_j \bar{r}_{i-1}}_{\text{call this } \tilde{\alpha}_{ij}^{(\text{mvp})}} $$ The prover sends the claimed values $\tilde{\alpha}_{ij}^{(\text{mvp})}$, which the verifier checks against the $X_{i-1}$ openings. The prover now has $1 + |S_{i-1}|$ inner product claims to prove about $\tilde{X}_i$. They prove them all at once using batched sumcheck. The verifier generates random batching coefficients $\beta_j \in \mathbb{F}$ and forms a single, combined claim: $$ \underbrace{ \left( \tilde{w}_i^{(\text{sumcheck})} + \sum_{j \in S_{i-1}} \beta_j \tilde{w}_{ij}^{(\text{mvp})} \right)^T }_{\text{This is the new batched vector } \tilde{w}_i^T} \operatorname{vec}(\tilde{X}_i) = \underbrace{ \tilde{\alpha}_i^{(\text{sumcheck})} + \sum_{j \in S_{i-1}} \beta_j \tilde{\alpha}_{ij}^{(\text{mvp})} }_{\text{This is the new batched scalar } \tilde{\alpha}_i} $$ This new, single claim $\tilde{w}_i^T \operatorname{vec}(\tilde{X}_i) = \tilde{\alpha}_i$ is the invariant that gets passed to the *next* partial sumcheck for round $i$. :::info ### Example: The Batched Claim Let's simplify. At round $i$, the prover must prove: 1. **Sumcheck consistency:** $w_A^T \operatorname{vec}(\tilde{X}_i) = \alpha_A$ 2. **MVP consistency (row 1):** $w_B^T \operatorname{vec}(\tilde{X}_i) = \alpha_B$ 3. **MVP consistency (row 2):** $w_C^T \operatorname{vec}(\tilde{X}_i) = \alpha_C$ ...and so on for all $|S_{i-1}|$ sampled rows. The verifier samples random $\beta_B, \beta_C, \dots \in \mathbb{F}$ and asks the prover to prove the *single* combined claim: $$ (w_A + \beta_B w_B + \beta_C w_C + \dots)^T \operatorname{vec}(\tilde{X}_i) = \alpha_A + \beta_B \alpha_B + \beta_C \alpha_C + \dots $$ The prover now runs the partial sumcheck protocol (Tool 2) on *this* batched claim, folding it down to a new, even smaller claim for round $i+1$. This is the "glue" that holds the recursion together. ::: ### The Ligerito Protocol (Formalized) Let's set up the recursion parameters: * **Rounds:** $\ell \ge 2$. * **Dimensions:** A sequence of dimensions $(k_i, k'_i)$ for $i=1, \dots, \ell$. * The matrix $\tilde{X}_i$ will be $\mathbb{F}^{2^{k_i} \times 2^{k'_i}}$. * The total number of coefficients is $2^{k_i + k'_i}$. * The folding step reduces the problem size, so we require $k_i + k'_i = k_{i-1}$. * **Codes:** A set of generator matrices $G_i \in \mathbb{F}^{m_i \times 2^{k_i}}$ for $i=1, \dots, \ell-1$. The protocol proceeds in rounds $i = 1, \dots, \ell$. #### Round $i$ ($1 \le i < \ell$): 1. **Prover: Commit.** The prover holds $\tilde{X}_i$. They compute $X_i = G_i \tilde{X}_i$ and commit to its rows via a Merkle tree, sending the root $C_i$ to the verifier. 2. **Prover/Verifier: Form Batched Claim.** * **If $i=1$:** The initial claim is just $\tilde{w}_1^T \operatorname{vec}(\tilde{X}_1) = \tilde{\alpha}_1$, where $\tilde{w}_1 = w$ and $\tilde{\alpha}_1 = \alpha$. * **If $i > 1$:** The prover and verifier perform the "Recursive Glue" step described above. The verifier samples $S_{i-1}$, challenges the prover, and they form the batched claim $\tilde{w}_i^T \operatorname{vec}(\tilde{X}_i) = \tilde{\alpha}_i$. 3. **Prover/Verifier: Partial Sumcheck.** * They run the partial sumcheck protocol on the claim $\tilde{w}_i^T \operatorname{vec}(\tilde{X}_i) = \tilde{\alpha}_i$ to fold the first $k'_i$ variables. * This involves the prover sending $k'_i$ polynomials $s_j(t)$. * The verifier supplies $k'_i$ random challenges, forming the vector $r_i \in \mathbb{F}^{k'_i}$. * This reduces the claim to a final check: $$ s_i(r_i) = (\operatorname{Mat}(\tilde{w}_i)\bar{r}_i)^T (\tilde{X}_i \bar{r}_i) $$ * The prover defines $y_{r_i} = \tilde{X}_i \bar{r}_i$. 4. **Prover: Define Next Problem.** The prover reshapes this resulting vector $y_{r_i}$ (which has length $2^{k_i}$) into the matrix for the next round: $$ \tilde{X}_{i+1} = \operatorname{Mat}(y_{r_i}) \in \mathbb{F}^{2^{k_{i+1}} \times 2^{k'_{i+1}}} $$ ...and loops back to step 1 for round $i+1$. #### Final Round ($\ell$): The recursion "bottoms out". The prover has the final, small matrix $\tilde{X}_\ell$. 1. **Prover: Send Final Vector.** The matrix $\tilde{X}_\ell$ is small enough (e.g., $N^{1/\ell}$, which is $\operatorname{polylog}(N)$) that the prover just sends $y_\ell = \operatorname{vec}(\tilde{X}_\ell)$ *in the clear*. No more commitments. 2. **Verifier: Final Checks.** The verifier now holds the vector $y_\ell$ and can *directly* run the final checks that were "pending" from round $\ell-1$: * **Final MVP Check:** The verifier samples $S_{\ell-1}$, opens the corresponding rows of $X_{\ell-1}$, and directly verifies: $$ (X_{\ell-1})_{S_{\ell-1}} \bar{r}_{\ell-1} \stackrel{?}{=} (G_{\ell-1})_{S_{\ell-1}} y_\ell $$ * **Final Sumcheck Check:** The verifier forms the final batched claim $\tilde{w}_\ell^T \operatorname{vec}(\tilde{X}_\ell) = \tilde{\alpha}_\ell$ (just as in the "Recursive Glue" step). Since $y_\ell = \operatorname{vec}(\tilde{X}_\ell)$, they check: $$ \tilde{w}_\ell^T y_\ell \stackrel{?}{=} \tilde{\alpha}_\ell $$ (Note: the paper simplifies this by combining the final sumcheck's $\tilde{\alpha}_\ell$ with the $s_{\ell-1}(r_{\ell-1})$ value, but the logic is the same). If all checks pass, the verifier accepts. ### The Telescoping Guarantee Why does this work? Because all the partial evaluations chain together perfectly. The final vector $y_\ell$ that the verifier checks is: $$ \begin{align} y_\ell &= \operatorname{vec}(\tilde{X}_\ell) \\ &= y_{r_{\ell-1}} \\ &= \tilde{X}_{\ell-1} \bar{r}_{\ell-1} \\ &= \operatorname{Mat}(y_{r_{\ell-2}}) \bar{r}_{\ell-1} = \operatorname{Mat}(\tilde{X}_{\ell-2} \bar{r}_{\ell-2}) \bar{r}_{\ell-1} \\ &= \dots \\ &= \operatorname{Mat}(\tilde{X}_1) (\bar{r}_1 \otimes \bar{r}_2 \otimes \cdots \otimes \bar{r}_{\ell-1}) \end{align} $$ The final $y_\ell$ is a partial evaluation of the *original* matrix $\tilde{X}_1$ at a single point $(\bar{r}_1 \otimes \dots \otimes \bar{r}_{\ell-1})$ derived from all the verifier's challenges. Because the batched sumcheck at each step *proves* that the inner product claim is consistent *and* that the MVP (folding) step was done correctly, the final check on $y_\ell$ transitively guarantees the correctness of the original claim $w^T \operatorname{vec}(\tilde{X}_1) = \alpha$. ## Making the verifier succinct: tensorizable codes There is one last, problem to solve. Look at the verifier's "Final Check": $$ \tilde{w}_\ell^T y_\ell \stackrel{?}{=} \tilde{\alpha}_\ell $$ The vector $y_\ell$ is small (polylog size, $N^{1/\ell}$) and sent by the prover. That's fine. But what is $\tilde{w}_\ell$? $\tilde{w}_\ell$ is the result of a long chain of batching and partial evaluations: * It starts with $w$ (size $N$). * Then we add in rows from $G_1$ (each size $2^{k_1} \approx N^{1/2}$). * Then we partially evaluate that, add in rows from $G_2$, and so on. Naively, just to *compute* the vector $\tilde{w}_\ell$ so they can perform the inner product, the verifier would need to do $O(N)$ work. This would make the verifier "fast" (linear time) but not "succinct" (polylog time). The solution is to choose codes $G_i$ that have a special structure, allowing for *succinct evaluation*. The verifier will *never* build the full $\tilde{w}_\ell$ vector. Instead, they will compute the inner product $\tilde{w}_\ell^T y_\ell$ "on the fly," entry by entry. ### The Verifier's Final Task (Revisited) The verifier's final task is to compute the sum: $$ \tilde{w}_\ell^T y_\ell = \sum_{j=1}^{N^{1/\ell}} \tilde{w}_\ell[j] \cdot y_\ell[j] $$ The verifier knows $y_\ell$ (it was sent by the prover). To make this check succinct, they need a way to compute any *single entry* $\tilde{w}_\ell[j]$ in polylog time (e.g., $O(\log N)$). If they can do that, the total time for the final check is: $$ (\text{Size of } y_\ell) \times (\text{Time to compute one entry of } \tilde{w}_\ell) = O(N^{1/\ell}) \times O(\log N) = O(\operatorname{polylog}(N)) $$ This achieves succinctness. The tool that enables this is tensorizable codes. ### Tensorizable codes A code matrix $G \in \mathbb{F}^{m \times 2^k}$ is tensorizable if each row $g_i^T$ can be written as a tensor (Kronecker) product of $k$ tiny vectors: $$ g_i = v_{i1} \otimes v_{i2} \otimes \cdots \otimes v_{ik}, \qquad v_{ij} \in \mathbb{F}^2 $$ Instead of storing $2^k$ entries for the row $g_i$, we only need to store the $2k$ entries of its factors. Many important codes (like Reed-Solomon and Reed-Muller) have this property. ### Fast inner products with tensor products The mixed-product property of the Kronecker product allows for extremely fast computations. If we have two tensorizable vectors: $$ v = v_1 \otimes \cdots \otimes v_k, \qquad u = u_1 \otimes \cdots \otimes u_k $$ Their inner product, naively a sum of $2^k$ terms, becomes a product of $k$ tiny inner products: $$ \boxed{ v^T u = (v_1^T u_1) \cdot (v_2^T u_2) \cdot \cdots \cdot (v_k^T u_k) } $$ This costs $O(k)$ operations, not $O(2^k)$. :::info ### Example: $k = 2$ Let $v = \begin{pmatrix} a_0 \\ a_1 \end{pmatrix} \otimes \begin{pmatrix} b_0 \\ b_1 \end{pmatrix} = \begin{pmatrix} a_0 b_0 \\ a_0 b_1 \\ a_1 b_0 \\ a_1 b_1 \end{pmatrix}$ and $u = \begin{pmatrix} c_0 \\ c_1 \end{pmatrix} \otimes \begin{pmatrix} d_0 \\ d_1 \end{pmatrix} = \begin{pmatrix} c_0 d_0 \\ c_0 d_1 \\ c_1 d_0 \\ c_1 d_1 \end{pmatrix}$. **Naive inner product ($O(2^k)$):** $$ v^T u = (a_0 b_0 c_0 d_0) + (a_0 b_1 c_0 d_1) + (a_1 b_0 c_1 d_0) + (a_1 b_1 c_1 d_1) $$ **Fast inner product ($O(k)$):** $$ \begin{align} v^T u &= \left( \begin{pmatrix} a_0 \\ a_1 \end{pmatrix}^T \begin{pmatrix} c_0 \\ c_1 \end{pmatrix} \right) \cdot \left( \begin{pmatrix} b_0 \\ b_1 \end{pmatrix}^T \begin{pmatrix} d_0 \\ d_1 \end{pmatrix} \right) \\ &= (a_0 c_0 + a_1 c_1) \cdot (b_0 d_0 + b_1 d_1) \end{align} $$ Both expressions are identical, but the second one is exponentially faster to compute. ::: ### Fast partial evaluation This is the most important property. Recall that partially evaluating a vector $v \in \mathbb{F}^{2^k}$ (as a multilinear polynomial) at a point $r = (r_1, \dots, r_{k'})$ is done by: $$ y = \operatorname{Mat}(v)\bar{r} $$ If $v$ is tensorizable ($v = v_1 \otimes \cdots \otimes v_k$), this operation is also incredibly fast. The resulting vector $y \in \mathbb{F}^{2^{k-k'}}$ is *also* tensorizable: $$ \begin{align} y &= \operatorname{Mat}(v) \left( (1-r_1, r_1) \otimes \cdots \otimes (1-r_{k'}, r_{k'}) \right) \\ &= \underbrace{ \left( (1-r_1, r_1)^T v_1 \right) }_{\text{scalar}} \cdot \cdots \cdot \underbrace{ \left( (1-r_{k'}, r_{k'})^T v_{k'} \right) }_{\text{scalar}} \cdot \underbrace{ \left( v_{k'+1} \otimes \cdots \otimes v_k \right) }_{\text{tensor product}} \end{align} $$ The first $k'$ factors are "folded" into scalars, and the remaining $k-k'$ factors form a new, smaller tensor product. This computation takes $O(k)$ time, not $O(2^k)$. ### Putting It All Together: The Succinct Verifier This is the final piece of the puzzle. 1. The verifier's final task is computing $\tilde{w}_\ell^T y_\ell$. 2. The vector $\tilde{w}_\ell$ is a linear combination of (a) the original $w$ and (b) rows from $G_1, \dots, G_{\ell-1}$, all partially evaluated at the challenge points $r_1, \dots, r_{\ell-1}$. 3. We *require* that the initial $w$ is structured (e.g., sparse or tensorizable) and that all code matrices $G_i$ are tensorizable. 4. Because of the "Fast partial evaluation" property, *every term* that makes up $\tilde{w}_\ell$ can be represented in $O(\log N)$ space and evaluated at any point $j$ in $O(\log N)$ time. 5. Therefore, the verifier can compute any entry $\tilde{w}_\ell[j]$ in $O(\log N)$ time. 6. To compute the full inner product $\sum \tilde{w}_\ell[j] \cdot y_\ell[j]$, the verifier loops from $j=1$ to $N^{1/\ell}$: * Compute $\tilde{w}_\ell[j]$ (takes $O(\log N)$ time using the tensor properties). * Get $y_\ell[j]$ (from the prover's message). * Multiply and add to the sum. 7. The verifier's total work is $O(N^{1/\ell} \cdot \log N)$, which is $O(\operatorname{polylog}(N))$.