Skip to main content

Maller's optimization for Kimchi

This document proposes a protocol change for kimchi.

What is Maller's optimization?

See the section on Maller's optimization for background.

Overview

We want the verifier to form commitment to the following polynomial:

L(x)=f(x)ZH(ζ)t(x)L(x) = f(x) - Z_H(\zeta) \cdot t(x)

They could do this like so:

com(L)=com(f)ZH(ζ)com(t)\mathsf{com}(L) = \mathsf{com}(f) - Z_H(\zeta) \cdot \mathsf{com}(t)

Since they already know ff, they can produce com(f)\mathsf{com}(f), the only thing they need is com(t)\mathsf{com}(t). So the protocol looks like that:

maller 15 1

In the rest of this document, we review the details and considerations needed to implement this change in kimchi.

How to deal with a chunked tt?

There's one challenge that prevents us from directly using this approach: com(t)\mathsf{com}(t) is typically sent and received in several commitments (called chunks or segments throughout the codebase). As tt is the largest polynomial, usually exceeding the size of the SRS (which is by default set to be the size of the domain).

The verifier side

Thus, the verifier will have to produce split commitments of LL and combine them with powers of ζn\zeta^n to verify an evaluation proof. Let's define LL as:

L=L0+xnL1+x2nL1+L = L_0 + x^n L_1 + x^{2n} L_1 + \cdots

where every LiL_i is of degree n1n-1 at most. Then we have that

com(L)=com(L0)+com(xnL1)+com(x2nL2)+\mathsf{com}(L) = \mathsf{com}(L_0) + \mathsf{com}(x^n \cdot L_1) + \mathsf{com}(x^{2n} \cdot L_2) + \cdots

Which the verifier can't produce because of the powers of xnx^n, but we can linearize it as we already know which xx we're going to evaluate that polynomial with:

com(L~)=com(L0)+ζncom(L1)+ζ2ncom(L2)+\mathsf{com}(\tilde L) = \mathsf{com}(L_0) + \zeta^n \cdot \mathsf{com}(L_1) + \zeta^{2n} \cdot \mathsf{com}(L_2) + \cdots

The prover side

This means that the prover will produce evaluation proofs on the following linearized polynomial:

L~(x)=1L0(x)+ζnL1(x)+ζ2nL2(x)+\tilde L(x) = 1 \cdot L_0(x) + \zeta^n \cdot L_1(x) + \zeta^{2n} \cdot L_2(x) + \cdots

which is the same as L(x)L(x) only if evaluated at ζ\zeta. As the previous section pointed out, we will need L~(ζω)\tilde L(\zeta \omega) and L~(ζω)L(ζω)\tilde L(\zeta \omega) \neq L(\zeta \omega).

Evaluation proof and blinding factors

To create an evaluation proof, the prover also needs to produce the blinding factor rLr_{L} associated with the chunked commitment of:

L~=f~(ζn1)t~\tilde L = \tilde f - (\zeta^n - 1) \tilde t

To compute it, there are two rules to follow:

  • when two commitment are added together, their associated blinding factors get added as well: com(a)+com(b)    ra+rb\mathsf{com}(a) + \mathsf{com}(b) \implies r_a + r_b
  • when scaling a commitment, its blinding factor gets scaled too: ncom(a)    nran \cdot \mathsf{com}(a) \implies n \cdot r_a

As such, if we know rfr_f and rtr_t, we can compute:

rL~=rf~+(ζn1)rt~r_{\tilde L} = r_{\tilde f} + (\zeta^n-1) \cdot r_{\tilde t}

The prover knows the blinding factor of the commitment to tt, as they committed to it. But what about ff? They never commit to it really, and the verifier recreates it from scratch using:

  1. The commitments we sent them. In the linearization process, the verifier actually gets rid of most prover commitments, except for the commitment to the last sigma commitment Sσ6S_{\sigma6}. (TODO: link to the relevant part in the spec) As this commitment is public, it is not blinded.
  2. The public commitments. Think commitment to selector polynomials or the public input polynomial. These commitments are not blinded, and thus do not impact the calculation of the blinding factor.
  3. The evaluations we sent them. Instead of using commitments to the wires when recreating ff, the verifier uses the (verified) evaluations of these in ζ\zeta. If we scale our commitment com(z)\mathsf{com}(z) with any of these scalars, we will have to do the same with rzr_z.

Thus, the blinding factor of L~\tilde L is (ζn1)rt~(\zeta^n-1) \cdot r_{\tilde t}.

The evaluation of L~\tilde L

The prover actually does not send a commitment to the full ff polynomial. As described in the last check section. The verifier will have to compute the evaluation of L~(ζ)\tilde L(\zeta) because it won't be zero. It should be equal to the following:

f~(ζ)t~(ζ)(ζn1)=1z(ζ)(ζ1)(ζωnk)[(ζn1)(ζωnk)nαPERM1+ωnk(ζn1)(ζ1)nαPERM2]pub(ζ)  z(ζ)zkpm(ζ)αPERM0  (w[0](ζ)+βshift[0]ζ+γ)  (w[1](ζ)+βshift[1]ζ+γ)  (w[2](ζ)+βshift[2]ζ+γ)  (w[3](ζ)+βshift[3]ζ+γ)  (w[4](ζ)+βshift[4]ζ+γ)  (w[5](ζ)+βshift[5]ζ+γ)  (w[6](ζ)+βshift[6]ζ+γ)  +z(ζω)zkpm(ζ)αPERM0  (w[0](ζ)+βσ[0](ζ)+γ)  (w[1](ζ)+βσ[1](ζ)+γ)  (w[2](ζ)+βσ[2](ζ)+γ)  (w[3](ζ)+βσ[3](ζ)+γ)  (w[4](ζ)+βσ[4](ζ)+γ)  (w[5](ζ)+βσ[5](ζ)+γ)  (w[6](ζ)+γ)+\begin{aligned} & \tilde f(\zeta) - \tilde t(\zeta)(\zeta^n - 1) = \\ & \frac{1 - z(\zeta)}{(\zeta - 1)(\zeta - \omega^{n-k})}\left[ \frac{(\zeta^n - 1)(\zeta - \omega^{n-k})}{n} \alpha^{\mathsf{PERM1}} + \frac{\omega^{n-k}(\zeta^n - 1)(\zeta - 1)}{n} \alpha^{\mathsf{PERM2}} \right] \\ & - \mathsf{pub}(\zeta) \\ & \; - z(\zeta) \cdot \mathsf{zkpm}(\zeta) \cdot \alpha^{\mathsf{PERM0}} \\ & \; \qquad \qquad \cdot (w[0](\zeta) + \beta \cdot \mathsf{shift}[0] \zeta + \gamma) \\ & \; \qquad \qquad \cdot (w[1](\zeta) + \beta \cdot \mathsf{shift}[1] \zeta + \gamma) \\ & \; \qquad \qquad \cdot (w[2](\zeta) + \beta \cdot \mathsf{shift}[2] \zeta + \gamma) \\ & \; \qquad \qquad \cdot (w[3](\zeta) + \beta \cdot \mathsf{shift}[3] \zeta + \gamma) \\ & \; \qquad \qquad \cdot (w[4](\zeta) + \beta \cdot \mathsf{shift}[4] \zeta + \gamma) \\ & \; \qquad \qquad \cdot (w[5](\zeta) + \beta \cdot \mathsf{shift}[5] \zeta + \gamma) \\ & \; \qquad \qquad \cdot (w[6](\zeta) + \beta \cdot \mathsf{shift}[6] \zeta + \gamma) \\ & \; + z(\zeta \omega) \cdot \mathsf{zkpm}(\zeta) \cdot \alpha^{\mathsf{PERM0}} \\ & \; \qquad \qquad \cdot (w[0](\zeta) + \beta \cdot \sigma[0](\zeta) + \gamma) \\ & \; \qquad \qquad \cdot (w[1](\zeta) + \beta \cdot \sigma[1](\zeta) + \gamma) \\ & \; \qquad \qquad \cdot (w[2](\zeta) + \beta \cdot \sigma[2](\zeta) + \gamma) \\ & \; \qquad \qquad \cdot (w[3](\zeta) + \beta \cdot \sigma[3](\zeta) + \gamma) \\ & \; \qquad \qquad \cdot (w[4](\zeta) + \beta \cdot \sigma[4](\zeta) + \gamma) \\ & \; \qquad \qquad \cdot (w[5](\zeta) + \beta \cdot \sigma[5](\zeta) + \gamma) \\ & \; \qquad \qquad \cdot (w[6](\zeta) + \gamma) + \end{aligned}

Because we use the inner product polynomial commitment, we also need:

L~(ζω)=f~(ζω)ZH(ζ)t~(ζω)\tilde L(\zeta \omega) = \tilde f(\zeta \omega) - Z_H(\zeta) \cdot \tilde t(\zeta \omega)

Notice the ZH(ζ)Z_H(\zeta). That evaluation must be sent as part of the proof as well.

The actual protocol changes

Now here's how we need to modify the current protocol:

  1. The evaluations f(ζ),f(ζω),t(ζ),t(ζω)f(\zeta), f(\zeta \omega), t(\zeta), t(\zeta \omega) (and their corresponding evaluation proofs) don't have to be part of the protocol anymore.
  2. The prover must still send the chunked commitments to tt.
  3. The prover must create a linearized polynomial L~\tilde L by creating a linearized polynomial f~\tilde f and a linearized polynomial t~\tilde t and computing: L~=f~+(ζn1)t~\tilde L = \tilde f + (\zeta^n-1) \cdot \tilde t
  4. While the verifier can compute the evaluation of L~(ζ)\tilde L(\zeta) by themselves, they don't know the evaluation of L~(ζω)\tilde L(\zeta \omega), so the prover needs to send that.
  5. The verifier must recreate com(L~)\mathsf{com}(\tilde L), the commitment to L~\tilde L, themselves so that they can verify the evaluation proofs of both L~(ζ)\tilde L(\zeta) and L~(ζω)\tilde L(\zeta\omega).
  6. The evaluation of L~(ζω)\tilde L(\zeta \omega) must be absorbed in both sponges (Fq and Fr).

maller 15 2

The proposal is implemented in #150 with the following details:

  • the L~\tilde L polynomial is called ft.
  • the evaluation of L~(ζ)\tilde L(\zeta) is called ft_eval0.
  • the evaluation L~(ζω)\tilde L(\zeta\omega) is called ft_eval1.