From 116eef06be3991fa03482425780715e6f78791ea Mon Sep 17 00:00:00 2001 From: iakovenkos <105737703+iakovenkos@users.noreply.github.com> Date: Wed, 15 May 2024 13:05:17 +0200 Subject: [PATCH] docs: sumcheck documentation (#5841) Re-organized docs for pow, sumcheck, and sumcheck_round. - Added detailed Sumcheck Outline which contains the ZK techniques to be implemented - SumcheckProver/Verifier, SumcheckProver/VerifierRound got detailed descriptions, where steps in the implementations match mathematical descriptions. Detailed descriptions of main methods. - PowPolynomial struct: cleaned up and moved confusing parts explaining the computation of round univariates to the detailed description of SumcheckProver. - General: made notation in docs consistent with the objects in the code, got rid of several inconsistencies, mostly in SumcheckVerifier and SumcheckVerifierRound. Remark1. Made docs easy to find via search in doxygen. E.g. one could type PowPolynomial and go to the page where it's documented. Remark2. In the case of pow, since it is a struct, the docs have to be placed after the the code to be rendered correctly by doxygen --------- Co-authored-by: maramihali --- barretenberg/cpp/docs/src/sumcheck-outline.md | 457 ++++++++++++++++++ .../cpp/src/barretenberg/polynomials/pow.hpp | 195 ++++---- .../src/barretenberg/sumcheck/sumcheck.hpp | 271 +++++++++-- .../barretenberg/sumcheck/sumcheck_output.hpp | 12 +- .../barretenberg/sumcheck/sumcheck_round.hpp | 242 ++++++---- 5 files changed, 954 insertions(+), 223 deletions(-) create mode 100644 barretenberg/cpp/docs/src/sumcheck-outline.md diff --git a/barretenberg/cpp/docs/src/sumcheck-outline.md b/barretenberg/cpp/docs/src/sumcheck-outline.md new file mode 100644 index 00000000000..3685b6c8d29 --- /dev/null +++ b/barretenberg/cpp/docs/src/sumcheck-outline.md @@ -0,0 +1,457 @@ +# Sumcheck Implementation +We implement a Zero-Knowledge Sumcheck protocol for relations of a very general form. + +The implementation consists of several components. +- [Non-ZK Sumcheck:](#NonZKSumcheck) + We sketch an implementation of the non-zero-knowledge Sumcheck, introduce the main abstractions and the components of the proof system. In [Witness Information Leakage](#NonZKSumcheckLeakage), we determine the sources allowing the verifier to learn the witness information during Sumcheck. + +- [Masking Round Univariates with Libra:](#LibraTechnique) + To prevent the witness values from leaking through the coefficients of Sumcheck round univariates, we apply a technique introduced in Libra: Succinct Zero-Knowledge Proofs with Optimal Prover Computation. + Being represented in Lagrange basis, Libra masking polynomials lead to very simple formulas for contributions to Sumcheck round univariates, see [the following section](#LibraRoundUnivariates). + In section [Libra Costs](#LibraCosts), we assess the overhead caused by adding the Libra technique. + Although the contribution in field operations is almost negligible, it adds non-trivial expenses during the opening procedure. + +- [Masking Evaluations of Multilinear Witnesses:](#MaskingEvalsOfWitnesses) + At the stage of proving their evaluations at the challenge point, the multilinear witness polynomials fed to Sumcheck must not reveal any private information. + We use a modification of Construction 3 described in Libra allowing the prover to open a new multilinear polynomial in \f$d\f$ variables, where \f$2^d\f$ is the circuit size, which is derived from the witnesses by adding a product of a random scalar and a public quadratic polynomial in \f$d\f$ variables + +- [Total Costs:](#ZKCosts) The effect of adding Libra technique and masking evaluations of multilinear witnesses is assessed, and the theoretical upper bound on prover's work is compared to the implemenation costs. + +Non ZK-Sumcheck Outline {#NonZKSumcheck} +======== +- - - + ### Sumcheck Relation {#SumcheckRelation} + + Given multilinear polynomials \f$ P_1,\ldots, P_N \in \mathbb{F}[X_0,\ldots, X_{d-1}] \f$ and a polynomial \f$ F \f$ in \f$ N \f$ variables, we run Sumcheck over the polynomial + \f{align}{ + \tilde{F} + (X_0,\ldots, X_{d-1}) = + pow_{\beta}(X_0,\ldots, X_{d-1}) \cdot F\left( P_1 (X_0,\ldots, X_{d-1}), \ldots, P_N (X_0,\ldots, X_{d-1}) \right) + \f} +to establish that \f$ F(P_1(\vec \ell),\ldots, P_N(\vec \ell) ) = 0 \f$, i.e. that \f$ F \f$ is satisfied at every +point \f$\vec \ell \{0,1\}^d\f$. + + In the implementation, the relation polynomial \f$ F \f$ is specified by the Flavor. + \todo Docs for Flavors and Relations. + + ### Main Parameters {#MainParameters} + +The following constants are used in this exposition. + + | Notation | | \f$ \sim \f$ Upper Bound | + --------------------|---------------|-----------| + | \f$ d \f$ | \ref multivariate_d "number of variables" in multilinear polynomials \f$ P_1,\ldots, P_N\f$ | \f$ 20 \f$ | + | \f$ N \f$ | number of Prover Polynomials specified by Flavor's parameter \p NUM_ALL_ENTITIES | \f$ 60 \f$ | + | \f$ N_w \f$ | number of Witness Polynomials specified by Flavor's parameter \p NUM_WITNESS_ENTITIES | \f$ 17 \f$ | + | \f$ n \f$ | \ref multivariate_n "size of the hypercube", i.e. \f$ 2^d\f$. | \f$ 2^{20} \f$ | + | \f$ D \f$ | \ref bb::SumcheckProverRound< Flavor >::BATCHED_RELATION_PARTIAL_LENGTH "total degree of" \f$\tilde{F}\f$ as a polynomial in \f$P_1,\ldots, P_N\f$ incremented by 1 | \f$ 12 \f$ | + | \f$ D_w\f$ | [maximum witness degree](#MaximumWitnessDegree) of \f$ F \f$ | \f$ 5 \f$ | + +\todo Compute precise upper bounds. + +#### Maximum Witness Degree {#MaximumWitnessDegree} +The significance of this parameter becomes apparent in Section [Masking Evaluations of Multilinear Witnesses](#MaskingEvalsOfWitnesses). It is formally defined as follows +\f{align}{ + D_w = \deg_{P_1, \ldots, P_{N_w}} F(P_1,\ldots, P_{N}) +\f} +where by \f$ \deg_{P_1, \ldots, P_{N_w}} \f$ we mean the total degree of the relation polynomial \f$ F \f$ in the witness polynomials \f$ P_1,\ldots, P_{N_w}\f$ considered as variables. + +For example, given a polynomial \f$P_1 + P_{N_w+1} \cdot P_{N_w + 2} \cdot P_{1}^2 \cdot P_{2}\f$ in prover polynomials, where \f$N_w>2\f$, its witness degree \f$ D_w \f$ is \f$3\f$, whereas its total degree \f$D\f$ is equal to \f$ 6 \f$. + +## Sumcheck Prover Algorithm {#NonZKSumcheckProver} +- - - +We remark that prior to running Sumcheck, the prover commits to multilinear polynomials \f$P_1,\ldots, P_{N_w}\f$, and sends the commitments to the verifier and that the total sum and the relation polynomial \f$ \tilde F \f$ are public. + +The prover algorithm is implemented in the \ref bb::SumcheckProver< Flavor > "Sumcheck Prover" class. See its documentation for a more detailed description of methods described below. The Sumcheck Round routine is abstracted into \ref bb::SumcheckProverRound< Flavor > "Sumcheck Prover Round" class, which contains most computational steps. + + + +#### Set up Prover Polynomials {#ProverPolynomialsSetup} + +The polynomials \f$P_1,\ldots, P_N\f$ are abstracted in the class ProverPolynomials specific to a Flavor, e.g. \ref bb::GoblinUltraFlavor::ProverPolynomials "Goblin Ultra Flavor". +Sumcheck Prover algorithm takes a reference to an object of this class. + +#### Compute Round Univariates and add them to Transcript {#ComputeRoundUnivariates} +The prover evaluates the round univariate +\f{align}{ + \tilde{S}^i = \sum_{\vec \ell \in \{0,1\}^{d-1-i}} \tilde{F}\left(P_1(u_0,\ldots, u_{i-1}, X_i,\vec \ell), \ldots, P_N(u_0,\ldots, u_{i-1}, X_i,\vec \ell)\right) +\f} +over the domain \f$ 0,\ldots, D \f$. In fact, it is more efficient to perform this computation sub-relation-wise, because the degrees of individual subrelations as polynomials in \f$ P_1,\ldots, P_N\f$ are generally smaller than \f$D\f$ defined in [Main Parameters](#MainParameters). Taking this into account, for a given subrelation of \f$F\f$, we perform expensive subrelation evaluations at points \f$(u_0,\ldots, u_{i-1}, k, \vec \ell)\f$ for \f$\ell \in \{0,1\}^{d-1-i} \f$ and \f$k\f$ from \f$0\f$ only up to the degree of the subrelation as a polynomial in \f$P_1,\ldots,P_N\f$ incremented by \f$1\f$. + +At the implementation level, the evaluations of \f$\tilde{S}^i\f$ are obtained using the method \ref bb::SumcheckProverRound< Flavor >::compute_univariate "compute univariate" consisting of the following sub-methods: + + - \ref bb::SumcheckProverRound::extend_edges "Extend evaluations" of linear univariate +polynomials \f$ P_j(u_0,\ldots, u_{i-1}, X_i, \vec \ell) \f$ to the domain \f$0,\ldots, D\f$. It is a cheap operation applied only once for every \f$\vec \ell \in \{0,1\}^d\f$ which allows to compute subrelations of \f$ F \f$ at such arguments. + - \ref bb::SumcheckProverRound::accumulate_relation_univariates "Accumulate per-relation contributions" of the extended +polynomials to auxiliary univariates \f$ T^i(X_i)\f$ defined in \ref SumcheckProverContributionsofPow "this section" + - \ref bb::SumcheckProverRound::extend_and_batch_univariates "Extend and batch the subrelation contributions" +multiplying by the constants \f$c_i\f$ and the evaluations of \f$ ( (1−X_i) + X_i\cdot \beta_i ) \f$ stemming from \f$F\f$ being multiplied by \f$pow_{\beta}\f$. + +#### Get Round Challenge {#GetRoundChallenge} + +After computing Round Univariate and adding its evaluations \f$\tilde{S}^i(0),\ldots, \tilde{S}^i(D)\f$ to the transcript, the prover generates Round Challenge \f$ u_i \f$ by hashing the transcript. + +#### Populate/Update Book-keeping Table {#BookKeepingTable} +To keep prover's work linear in the number of coefficients of \f$P_1,\ldots, P_N\f$, we \ref bb::SumcheckProver< Flavor >::partially_evaluate "populate" a table of \f$\texttt{partially_evaluated_polynomials}\f$ after getting the first challenge \f$ u_0 \f$ with the values \f$P_j(u_0,\vec \ell )\f$, namely +\f{align}{ + \texttt{partially_evaluated_polynomials}_{\ell,j} \gets P_j(0, \ell) + u_{0} \cdot \left(P_j(1, \vec \ell) - P_j(0, \ell)\right) \f} +for \f$ \vec \ell \in \{0,1\}^{d-1}\f$ identified with the binary representation of \f$ 0\leq \ell \leq 2^{d-1}-1\f$. + +In Round \f$0< i \leq d-1\f$, the prover algorithm \ref bb::SumcheckProver< Flavor >::partially_evaluate "updates" the top \f$ 2^{d-1 - i}\f$ values in the book-keeping table +\f{align}{ + \texttt{partially_evaluated_polynomials}_{\ell,j} \gets \texttt{partially_evaluated_polynomials}_{2 \ell,j} + u_{i} \cdot (\texttt{partially_evaluated_polynomials}_{2\ell+1,j} - \texttt{partially_evaluated_polynomials}_{2\ell,j}) \f} + where \f$\vec \ell \in \{0,1\}^{d-1-i}\f$. + After the final update, i.e. when \f$ i = d-1 \f$, the upper row of the table contains the evaluations of Prover Polynomials at the challenge point \f$ (u_0,\ldots, u_{d-1}) \f$. + + +#### Add Claimed Evaluations to Transcript {#ClaimedEvaluations} +After computing the last challenge \f$ u_{d-1} \f$ in Round \f$ d-1 \f$ and updating \f$ +\texttt{partially_evaluated_polynomials} \f$, the prover looks into the top row of the table containing evaluations +\f$P_1(u_0,\ldots, u_{d-1}), \ldots, P_N(u_0,\ldots, u_{d-1})\f$ and concatenates these values with the last challenge +to the transcript. + + + + +## Sumcheck Verifier Algorithm {#NonZKSumcheckVerifier} +- - - + +The verifier algorithm is implemented in the \ref bb::SumcheckVerifier< Flavor > "Sumcheck Verifier" class. See its documentation for a more detailed description of methods described below. The Sumcheck Round verification routine is abstracted into \ref bb::SumcheckVerifierRound< Flavor > "Sumcheck Verifier Round" class. + +The verifier's work reduces to the following. + +For \f$ i = 0,\ldots, d-1\f$: + - Using \ref bb::BaseTranscript::receive_from_prover "receive_from_prover" method from \ref bb::BaseTranscript< TranscriptParams > "Base Transcript Class", extract the evaluations of Round Univariate \f$ \tilde{S}^i(0),\ldots, \tilde{S}^i(D) \f$ from the transcript. + - \ref bb::SumcheckVerifierRound< Flavor >::check_sum "Check target sum": \f$\quad \sigma_{ + i } \stackrel{?}{=} \tilde{S}^i(0) + \tilde{S}^i(1) \f$. + - \ref bb::BaseTranscript::get_challenge "Get the next challenge" \f$u_i\f$ by hashing the transcript. + method. + - \ref bb::SumcheckVerifierRound< Flavor >::compute_next_target_sum "Compute next target sum" :\f$ \quad \sigma_{i+1} + \gets \tilde{S}^i(u_i) \f$ + +### Verifier's Data before Final Step {#SumcheckVerifierData} +Entering the final round, the verifier has already checked that +\f$\quad \sigma_{ d-1 } = \tilde{S}^{d-1}(0) + \tilde{S}^{d-1}(1) \f$ +and computed \f$\sigma_d = \tilde{S}^{d-1}(u_{d-1})\f$. + +### Final Verification Step {#NonZKSumcheckVerification} +- Extract claimed evaluations of prover polynomials \f$P_1,\ldots, P_N\f$ at the challenge point \f$ + (u_0,\ldots,u_{d-1}) \f$ from the transcript and \ref bb::SumcheckVerifierRound< Flavor >::compute_full_honk_relation_purported_value "compute evaluation:" + \f{align}{\tilde{F}\left( P_1(u_0,\ldots, u_{d-1}), \ldots, P_N(u_0,\ldots, u_{d-1}) \right)\f} + +- Compare \f$ \sigma_d \f$ against the evaluation of \f$ \tilde{F} \f$ at \f$P_1(u_0,\ldots, u_{d-1}), \ldots, + P_N(u_0,\ldots, u_{d-1})\f$: + \f{align}{\quad \sigma_{ d } \stackrel{?}{=} \tilde{F}\left(P_1(u_{0}, \ldots, u_{d-1}),\ldots, P_N(u_0,\ldots, + u_{d-1})\right)\f} + + +## Witness Information Leakage {#NonZKSumcheckLeakage} + +-------- + +As explained in Section 13.3 of Proofs, Arguments, and Zero-Knowledge, there are two main sources that leak prover's private information: +- Evaluations of Round Univariates \f$ \tilde{S}^i\f$ +- Evaluations of witness polynomials \f$P_1,\ldots, P_{N_w}\f$ that the prover sends and proves at the last step of Sumcheck. + +These issues are resolved by enhancing Sumcheck with a technique that randomizes any given number of evaluations of \f$\tilde{S}^{i} \f$ and a technique that randomizes evaluations of witness polynomials \f$ P_1,\ldots, P_{N_w} \f$ at the challenge point \f$(u_0,\ldots, u_{d-1})\f$ obtained in Sumcheck. + +------- + +Masking Round Univariates with Libra {#LibraTechnique} +======== +----- + +## Main Idea of Libra {#LibraMainIdea} + +To prevent the witness information leakage through the Round Univariates determined by their evaluations over the domain \f$ \{0,\ldots, \tilde{D}\}\f$, where \f$\tilde{D} \geq D\f$, the Sumcheck Prover masks them using a low-degree multivariate polynomial +\f{align}{ + G \gets \sum_{i=0}^{d-1} g_{i}(X_i), +\f} +where +\f{align}{ + g_{i} = \sum_{j=0}^{\tilde{D}} g_{i,j} \cdot L_{j,\{0,\ldots, D\}}(X_i) \quad \text{for } (g_{i,j}) \gets_{\$} \mathbb{F}^{d\cdot (\tilde{D}+1)} +\f} +and \f$L_{j, \{0,\ldots, \tilde{D}\}}\f$ is the \f$j\f$th univariate Lagrange polynomial for the domain \f$\{0,\ldots, \tilde{D}\}\f$. Recall that \f$\deg_{X_i} \left(L_{j, \{0,\ldots, \tilde{D}\}} (X_i)\right) = \tilde{D}\f$. + +Set +\f{align}{ + \gamma \gets \sum_{\vec \ell \in \{0,1\}^{d}} G(\vec \ell) +\f} +as the value that the honest prover sends to the verifier, and let \f$\rho\f$ be the verifier's challenge. +Then instead of proving that \f$\sum \tilde{F}\left(\vec \ell\right) =\sigma\f$ as in [Non-ZK Sumcheck](\ref NonZKSumcheck), we run the protocol that establishes that +\f{align}{ + \sum_{\vec \ell \in\{0,1\}^{d}} \left(\tilde{F}(P_1(\vec \ell), \ldots, P_N(\vec \ell)) + \rho \cdot G(\vec \ell)\right) = \sigma + \rho \cdot \gamma. +\f} +### Properties of Libra Masking Polynomial {#PropertiesOfTheMaskingPolynomial} + +Observe that \f$ G \f$ has several important properties +- For \f$ i = 0,\ldots, d-1\f$, the partial degrees \f$ \deg_{X_i} G = \tilde{D}\f$. +- The coefficients of \f$ G \f$ are independent and uniformly distributed. +- Evaluations of \f$ G \f$ at \f$ \vec \ell \in \{0,1\}^d\f$ and related Sumcheck Round Univariates are efficiently computable. + +The first two properties imply that the evaluations over the domain \f$ \{0,\ldots, \tilde{D}\}\f$ defining Libra Round Univariates , i.e. round univariates for \f$ G \f$, are independent and uniformly distributed. +Moreover, since Round Univariates for \f$ \tilde{F} + \rho\cdot G\f$ are the sums of respective unvariates, the second property and the condition \f$ \tilde{D}\geq D \f$ ensure that the evaluations \f$ \tilde{S}^i(0),\ldots,\tilde{S}^i(\tilde D)\f$ defined in [Compute Round Univariates](#ComputeRoundUnivariates) are hidden by random scalars obtained as evaluations of Libra Round Univariates, which are described explicitly [below](#LibraRoundUnivariates). + +### Example {#LibraPolynomialExample} +If in every round of Sumcheck, the prover aims to hide only \f$2\f$ evaluations the Round Univariate, i.e. if \f$\tilde{D} = 1\f$, the masking polynomial \f$ G \f$ has the following form +\f{align}{ + G = \left( g_{0,0} (1- X_0) + g_{0,1} X_0 \right) + \ldots + \left( g_{d-1,0} (1- X_{d-1}) + g_{d-1,1} X_{d-1} \right). +\f} +## Implementation {#LibraImplementation} + +### Committing to Libra Masking Polynomial {#LibraCommitments} + +To commit to multivariate polynomial \f$ G \f$, the prover commits to the tuple of univariate polynomials \f$ (g_0,\ldots, g_{d-1})\f$. + +### Computing Target Sum {#LibraTargetSum} +Since \f$G\f$ is a polynomial of a very special form, the computation of \f$\gamma\f$ reduces to the following +\f{align}{ + \sum_{\vec \ell \in \{0,1\}^{d}} G(\vec \ell) = \sum_{i=0}^{d-1} \sum_{\vec \ell \in \{0,1\}^{d}} g_{i}(\ell_i) = 2^{d-1} \sum_{i = 0}^{d-1} \left( g_i(0) + g_i(1) \right), +\f} +since the evaluations of \f$ g_i \f$ at \f$\vec \ell \in \{0,1\}^{d}\f$ depend only on \f$ \ell_i \f$, and therefore, there are \f$2^{d-1}\f$ summands \f$ g_i(0) \f$ corresponding to the points \f$\vec \ell\f$ with \f$\ell_i=0\f$ and \f$2^{d-1}\f$ summands \f$ g_i(1) \f$ corresponding to \f$\vec \ell\f$ with \f$\ell_i=1\f$. + +We set +\f{align}{ + \texttt{libra_total_sum} \gets 2^{d-1} \sum_{i = 0}^{d-1} \left( g_i(0) + g_i(1) \right) +\f} + +### Pre-computed Data and Book-Keeping {#LibraBookKeeping} +As in [Sumcheck Book-keeping](#BookKeepingTable), we use a table of evaluations of Libra univariates to avoid extra computational costs. +Namely, before Round \f$ i \f$, the prover needs the table of values +\f{align}{ + \texttt{libra_table}_{j,k} \gets \rho \cdot 2^{d-1-i} \cdot g_{j,k} \text{ for } j= i,\ldots, d-1, \text{ and } k=0,\ldots, \tilde{D} +\f} +and the term +\f{align}{ + \texttt{libra_running_sum} \gets \rho \cdot 2^{d-1-i}\left( \sum_{j=0}^{i-1}g_j(u_j) + \sum_{j = i+1}^{d-1} ( g_{j,0} + g_{j,1}) \right). +\f} + +### First Round {#LibraFirstRound} + +The prover computes first Libra round univariate +\f{align}{ + \texttt{libra_univariate}_0(X_0) = \rho \cdot \sum_{\vec \ell \in \{0,1\}^{d-1}} G(X_0,\vec \ell) = + 2^{d-1} \rho\cdot g_0(X_0) + 2^{d-1} \rho \cdot \sum_{i=1}^{d-1}\left(g_i(0)+g_i(1)\right) +\f} +which could be expressed as follows +\f{align}{ + \texttt{libra_univariate}_0 (k) \gets \texttt{libra_table}_{0,k} + \texttt{libra_running_sum} +\f} +for \f$k=0,\ldots, \tilde{D}\f$. + +When the prover receives the challenge \f$u_0\f$, it computes the value \f$g_0(u_0)\f$ using \ref bb::Univariate::evaluate "evaluate" method, updates the running sum +\f{align}{ + \texttt{libra_running_sum} \gets 2^{-1} \cdot \left( (g_0(u_0) + \texttt{libra_running_sum}) - (\texttt{libra_table}_{1,0} + \texttt{libra_table}_{1,1})\right) +\f} +and updates the libra table by releasing the first column and multiplying reamining terms by \f$1/2\f$. + +### Round Univariates in Subsequent Rounds {#LibraRoundUnivariates} +Similarly, to compute the contribution of Libra masking polynomial \f$G\f$ to the round univariates \f$\tilde{S}_i\f$ defined in [Compute Round Univariates](#ComputeRoundUnivariates), consider +\f{align}{ + \texttt{libra_univariate}_i(X_i) = \rho \cdot \sum_{\vec \ell \in \{0,1\}^{d-1 - i}} G(u_0,\ldots, u_{i-1}, X_{i}, \vec \ell) = + \rho \cdot 2^{d-1 - i} \left( \sum_{j = 0}^{i-1} g_j(u_{j}) + g_{i}(X_i) + \sum_{j=i+1}^{d-1} \left(g_{j,0} + g_{j,1}\right) \right) +\f} +Therefore, the contribution of the \f$\texttt{libra_univariate}_{i}(X_{i})\f$ at \f$X_{i} = k\f$ to \f$\tilde{S}^i(k)\f$, where \f$k=0,\ldots, \tilde{D}\f$, is given by the formula +\f{align}{ + \texttt{libra_univariate}_i(k) = \rho \cdot 2^{d-1-i} \left(\sum_{j = 0}^{i-1} g_j(u_{j}) + g_{i,k}+ \sum_{j=i+1}^{d-1}\left(g_{j,0}+g_{j,1}\right)\right) = \texttt{libra_table}_{i,k} + \texttt{libra_running_sum}. +\f} + +### Updating Partial Evaluations {#LibraUpdatePartialEvaluations} +In Rounds \f$ i = 1,\ldots d-2\f$, after correcting Sumcheck round univariate \f$S_{i}(X_{i})\f$ by \f$ \texttt{libra_univariate}_i(X_i)\f$, the prover gets the challenge \f$u_{i}\f$, computes the value \f$\texttt{libra_univariate}_{i}(u_{i})\f$ and updates the running sum +\f{align}{ + \texttt{libra_running_sum} \gets 2^{-1} \cdot \left( (g_i(u_i) + \texttt{libra_running_sum}) - (\texttt{libra_table}_{i+1,0} + \texttt{libra_table}_{i+1,1})\right) +\f} + + + +### Final Round {#LibraFinalRound} +After sending the evaluations of \f$\texttt{libra_univariate}_{d-1}\f$ at over the domain \f$\{0,\ldots, \tilde{D}\}\f$, the prover gets the last challenge \f$u_{d-1}\f$ and has to send the claimed evaluation \f$G(u_0,\ldots, u_{d-1})\f$. It boils down to sending and proving the evaluations +\f{align}{ + v_i = g_i(u_i) \text{ for } i = 0,\ldots, d-1. +\f} +## Libra Costs {#LibraCosts} + +The overhead in prover's field operations is linear in \f$ d\cdot \tilde D \f$ with a small constant and therefore, is negligible compared to the number of field operations performed during the main Sumcheck routine. + +The main expenses are caused by proving the evaluations of \f$ g_i (u_i) = v_i\f$ in the [Final Round](\ref LibraFinalRound). +Using the PCS introduced in Section 4 of Efficient polynomial commitment schemes for multiple points and polynomials also known as Shplonk, we reduce the costs of opening \f$ d \f$ univariate polynomials \f$ g_i \f$, each at different \f$ u_i \f$ to the following: + + + + + + + + + + + + + + + + + + + + +
Prover Verifier +
Group Operations \f$ 2 \cdot \tilde D+1\f$ \f$ d + 3 \f$
Field Operations \f$ O\left(d\cdot (\tilde{D} +1) + \tilde{D} \log(\tilde{D})\right)\f$
Pairings 2
Proof Size 2 group elements
+ +Masking Evaluations of Multilinear Witnesses {#MaskingEvalsOfWitnesses} +======== +- - - + +At the last step of Sumcheck, the Prover adds the evaluations of multilinear polynomials \f$P_1,\ldots, P_N \f$ at the challenge point \f$\vec u = (u_0,\ldots, u_{d-1})\f$ to the trasncript. + +Let \f$ N_w\leq N\f$ and assume that \f$ P_1,\ldots, P_{N_w}\f$ are witness polynomials. +To mask their evaluations at the challenge point\f$\vec u\f$, the prover samples +\f{align}{\rho_1,\ldots \rho_{N_w} \gets_{\$} \mathbb{F}^{N_w}\f} +and sets +\f{align}{ + \texttt{masked_witness_polynomial}_j(X_0,\ldots, X_{d-1}) = \widehat{P}_j \gets P_j(X_0,\ldots, X_{d-1}) + \rho_j \cdot \left(\sum_{k=0}^{d-1} X_k(1-X_k) \right). +\f} + + +Note that for any relation \f$F\f$, we have +\f{align}{ + \sum_{\ell \in \{0,1\}^d} pow_{\beta}(X_0,\ldots, X_{d-1}) \cdot F\left(P_1(\ell), \ldots, P_N(\ell)\right) + = pow_{\beta}(X_0,\ldots, X_{d-1}) \sum_{\ell \in \{0,1\}^d} F\left(\widehat{P}_1(\ell), \ldots, \widehat{P}_{N_w}(\ell), P_{N_w+1}(\ell), \ldots, P_{N}(\ell)\right) +\f} +as \f$P_j\f$ and \f$\widehat{P}_j\f$ agree on the hypercube \f$\{0,1\}^d\f$ for \f$j=1,\ldots, N_w\f$. + +### Committing to Prover Polynomials {#CommittingToMaskedWitnesses} + +The prover commits to \f$P_j\f$ for \f$j=1,\ldots, N\f$ and to \f$\rho_j\f$ for \f$ j=1, \ldots, N_w\f$ as multilinear polynomials and sends the commitments to the verifier. + +### Evaluation Phase {#MaskedEvaluationProtocol} +At the end of Sumcheck, instead of proving evaluations of witness polynomials \f$P_j\f$ at \f$\vec u\f$ for \f$j=1,\ldots, N_w\f$, the prover opens multilinear polynomials +\f{align}{ + \widehat{P}_j^{\vec u} \gets P_j(X_0,\ldots, X_{d-1}) + \rho_j \cdot \left(\sum_{k=0}^{d-1} u_k(1-u_k) \right). +\f} +It is important to notice that the verifier could evaluate public polynomial \f$\sum_{k=0}^{d-1} X_k(1-X_k)\f$ and derive the commitments to \f$\widehat{P}_j^{\vec u}\f$ on its own. + +The remaining prover polynomials \f$P_{N_w+1}, \ldots, P_{N}\f$ are evaluated at \f$ \vec u \f$ and their evaluations are proved without any modifications. + +### Security Check {#SecurityCheck} +Before proving the evaluations of \f$\widehat{P}_j^{\vec u} \f$, the prover checks that \f$\vec u\f$ does not satisfy the equation \f$\sum_{k=0}^{d-1} X_k(1-X_k) = 0\f$, which generally has many solutions outside of the hypercube \f$\{0,1\}^d\f$. + +### Degrees of Round Univariates {#DegreesRoundUnivariatesZK} + +Since masked witness polynomials \f$\widehat{P}_j\f$ are of degree \f$2\f$ in every variable, the degree of Sumcheck round univariates is also affected. +Namely, we set +\f{align}{ + \tilde{D} = \max_{i\in\{0,\ldots,d-1\}} \left\{\deg_{X_i} F\left(\widehat{P}_1(X_0,\ldots,X_{d-1}),\ldots, \widehat{P}_{N_w}(X_0,\ldots, X_{d-1}),\widehat{P}_{N_w+1}(X_0,\ldots, X_{d-1}), \ldots, \widehat{P}_{N}(X_0,\ldots, X_{d-1}) \right) \right\} \leq D + D_{w} +\f} +for \f$D\f$ and \f$ D_w \f$ defined in [Parameters](\ref MainParameters). + +In every round of Sumcheck, the Prover sends univariate polynomials \f$\tilde{S}^i(X_i)\f$ represented by their evaluations at \f$X_i = 0,\ldots, \tilde{D}\f$. + +Note that \f$ \tilde{D} \f$ sets up the corresponding parameter of [Libra](#LibraImplementation) + +### Book-keeping Tables {#BookKeepingMaskingWitnesses} +To reduce the computation costs, the prover precomputes the table +\f{align}{ + \texttt{masking_terms_evaluations}_{k,j}\gets \rho_j \cdot (1-k) k +\f} +for \f$j=1, \ldots, N_w\f$ and \f$ k=2,\ldots, \tilde{D} \f$ and stores the vector of running quadratic terms +\f{align}{ + \texttt{running_quadratic_term}_j \gets \rho_j \cdot \sum_{k=0}^{i-1} (1-u_k) u_k. +\f} + + +### Computing Evaluations of Round Univariates {#RoundUnivariatesMaskedEval} +In Round \f$i \in \{0,\ldots, d-1\}\f$, the prover computes univariate polynomials +\f{align}{ + \widehat{S}^i(X_i) = \sum_{\vec\ell \in \{0,1\}^{d-1-i}} F\left(\widehat{P}_1(u_0,\ldots, u_{i-1}, X_i, \vec \ell),\ldots,\widehat{P}_{N_w}(u_0,\ldots, u_{i-1}, X_i, \vec \ell), P_{N_w+1}(u_0,\ldots, u_{i-1}, X_i, \vec \ell), \ldots, P_{N}(u_0,\ldots, u_{i-1}, X_i, \vec \ell) \right) +\f} +which reduces to computing at most \f$ (D+ D_w + 1) \times N \times 2^{d-1 - i}\f$ values +\f{align}{ + &\ P_j(u_0,\ldots, u_{i-1}, k, \vec \ell) + \rho_j \cdot \sum_{k=0}^{i-1} u_k(1-u_k) + \rho_j\cdot (1-k) k \quad \text{ for } j=1,\ldots, N_w\\ + &\ P_j(u_0,\ldots, u_{i-1}, k, \vec \ell) \quad \text { for } j= N_w+1,\ldots, N +\f} +The values \f$ \texttt{running_quadratic_term}_j = \rho_j \cdot \sum_{k=0}^{i-1} u_k(1-u_k)\f$ are available from Round \f$i-1\f$. +The products \f$ \rho_j \cdot (1-k) k\f$ are taken from the table \f$ \texttt{masking_terms_evaluations}\f$. + +The prover performs an extra addition per evaluation \f$\widehat{P}_j(u_0,\ldots, u_{i-1}, k, \vec \ell)\f$ for \f$k=0,1\f$ and two extra additions per evaluation for \f$k=2,\ldots, D+D_w\f$ compared to evaluating the original witness polynomials \f$P_j\f$. +It results in \f$2 (D+D_w) N_w (2^d-1) \f$ extra additions compared to [Non-ZK-Sumcheck](#NonZKSumcheck). + +Upon receiving the round challenge \f$ u_i\f$, the prover prepares the correcting term for the next round +\f{align}{ + \texttt{running_quadratic_terms}_j \gets \texttt{running_quadratic_terms}_j + \rho_j \cdot (1-u_i) u_i . +\f} + +### Witness Evaluation Masking Costs {#MaskingCosts} +In contrast to non-ZK-Sumcheck, the prover needs to compute \f$\tilde{D} \sim D+D_w \f$ evaluations of round univariates \f$S_i\f$, which results in +\f{align}{ + ((D+D_w)\cdot N + C_a \cdot (D+D_w) + 2\cdot N + 2\cdot (D+D_w) N_w ) (2^d - 1) +\f} +addditions and +\f{align}{ + (C_m\cdot (D+D_w) + N) \cdot (2^d -1) +\f} +multiplications, where \f$C_a\f$ and \f$C_m\f$ are constants corresponding to the number of additions and multiplications required to evaluate the relation polynomial \f$F\f$. + +The overhead is summarized in the following table. + + + + + + + + + + + + + + + +
Prover Verifier +
Group Operations \f$ + N_w\f$ MSMs of size \f$2^d\f$ (same group element) \f$ + N_w\f$ MSMs of size 2
Field Operations \f$\times(1+ D_w/D) \f$ \f$\times(1+D_w/D) \f$
Communication \f$ + N_w\f$ group elements; \f$ +D_w\cdot d\f$ field elements
+ +ZK Costs {#ZKCosts} +======== +- - - + +The total costs of ZK Sumcheck are obtained from [Libra Costs](#LibraCosts) and [Witness Evaluation Masking Costs](#MaskingCosts). + + + + + + + + + + + + + + + + + + + + +
Prover Verifier +
Group Operations

\f$+ d\f$ MSMs of size \f$(D+D_w)\f$ = [Libra Commitments](#LibraCommitments)

+

\f$+ \left(2 \cdot (D+D_w) D+1\right)\f$ group ops = shplonk

+

\f$+ N_w\f$ MSMs of size \f$2^d\f$ (same group element multiplied by \f$\rho_1,\ldots,\rho_{N_w}\f$)

+

\f$ + (d + 3) \f$ group ops

+

\f$ + N_w\f$ MSMs of size \f$2\f$

+
Field Operations \f$ \times D_w/D \f$ \f$ \times D_w/D \f$
Pairings + 2
Communication

\f$+ (d+ 2)\f$ group elements for Libra; \f$+N_w\f$ group elements for witness masking

+

\f$+ D_w \cdot d \f$ field elements

+ +## Theoretic Field Operations vs. Implementation + +The table above sets a reasonable upper bound on the amount of prover's field operations. +However, in the implementation, the relation \f$ F \f$ is computed as a vector of its subrelations, which allows us to decrease the costs of computing the round univariates. Namely, for a given subrelation \f$ F_j \f$, its maximum partial degree \f$D_j\f$ and its witness degree \f$D_{w,j} \f$ are generally less than \f$ D\f$ and \f$ D_w \f$, respectively. +Therefore, we compute \f$ F_j \f$'s contribution to Sumcheck Round Univariates by evaluating the univariate polynomial +\f{align}{ + \sum_{\vec \ell\in \{0,1\}^{d-1-i}} pow_{\beta}(u_0,\ldots, u_{i-1}, X_i, \vec \ell) \cdot F_j(u_0,\ldots, u_{i-1}, X_i,\vec \ell) +\f} +at \f$ X_i = 0,\ldots, D_i + D_{w,i}\f$ and extend the resulting univariate of degree \f$D_j+D_{w,j}\f$ to the entire domain \f$\{ 0,\ldots, D+D_w\}\f$, which is way cheaper than evaluating the sum above at \f$ X_i = D_{j}+ D_{w,j}+1, \ldots, D+ D_w \f$ + diff --git a/barretenberg/cpp/src/barretenberg/polynomials/pow.hpp b/barretenberg/cpp/src/barretenberg/polynomials/pow.hpp index 3ab59ad5705..583a9d3ddf1 100644 --- a/barretenberg/cpp/src/barretenberg/polynomials/pow.hpp +++ b/barretenberg/cpp/src/barretenberg/polynomials/pow.hpp @@ -7,109 +7,67 @@ #include namespace bb { -/** - * @brief Succinct representation of the `pow` polynomial that can be partially evaluated variable-by-variable. - * pow_{\vec{β}}(X_0,X_1,..,X_{d-1}) = \prod_{0≤l struct PowPolynomial { - // \vec{β} = {β_0, β_1,.., β_{d-1}} + /** + * @brief The challenges \f$(\beta_0,\ldots, \beta_{d-1}) \f$ + * + */ std::vector betas; - // The values of pow_\vec{β}(i) for i=0,..,2^d - 1 for the given \vec{β} + /** + * @brief The consecutive evaluations \f$ pow_{\ell}(\beta) = pow_{\beta}(\vec \ell) \f$ for \f$\vec \ell\f$ + * identified with the integers \f$\ell = 0,\ldots, 2^d-1\f$ + * + */ std::vector pow_betas; - - // At round l of sumcheck this will point to the l-th element in \vec{β} + /** + * @brief In Round \f$ i\f$ of Sumcheck, it points to the \f$ i \f$-th element in \f$ \vec \beta \f$ + * + */ size_t current_element_idx = 0; - - // At round l of sumcheck, the periodicity represents the fixed interval at which elements not containing either of - // β_0,..,β_l appear in pow_betas + /** + * @brief In Round \f$ i\f$ of Sumcheck, the periodicity equals to \f$ 2^{i+1}\f$ and represents the fixed interval + * at which elements not containing either of \f$ (\beta_0,\ldots ,β_i)\f$ appear in #pow_betas. + * + */ size_t periodicity = 2; - - // The value c_l obtained by partially evaluating one variable in the power polynomial at each round. At the - // end of round l in the sumcheck protocol, variable X_l is replaced by a verifier challenge u_l. The partial - // evaluation result is updated to represent pow(u_0,.., u_{l-1}) = \prod_{0 ≤ k < l} ( (1-u_k) + u_k⋅β_k). + /** + * @brief The value \f$c_i\f$ obtained by partially evaluating one variable in the power polynomial at each round. + * At the end of Round \f$ i \f$ in the sumcheck protocol, variable \f$X_i\f$ is replaced by the challenge \f$u_i + * \f$. The partial evaluation result is updated to represent \f$ pow_{\beta}(u_0,.., u_{i}) = \prod_{k=0}^{i} ( + * (1-u_k) + u_k\cdot \beta_k) \f$. + * + */ FF partial_evaluation_result = FF(1); explicit PowPolynomial(const std::vector& betas) : betas(betas) {} - + /** + * @brief Retruns the element in #pow_betas at place #idx. + * + * @param idx + * @return FF const& + */ FF const& operator[](size_t idx) const { return pow_betas[idx]; } - + /** + * @brief Computes the component at index #current_element_idx in #betas. + * + * @return FF + */ FF current_element() const { return betas[current_element_idx]; } /** - * @brief Evaluate the monomial ((1−X_l) + X_l⋅β_l) in the challenge point X_l=u_l. + * @brief Evaluate \f$ ((1−X_{i}) + X_{i}\cdot \beta_{i})\f$ at the challenge point \f$ X_{i}=u_{i} \f$. */ FF univariate_eval(FF challenge) const { return (FF(1) + (challenge * (betas[current_element_idx] - FF(1)))); }; /** - * @brief Parially evaluate the pow polynomial in X_l and updating the value c_l -> c_{l+1}. - * - * @param challenge l-th verifier challenge u_l + * @brief Partially evaluate the \f$pow_{\beta} \f$-polynomial at the new challenge and update \f$ c_i \f$ + * @details Update the constant \f$c_{i} \to c_{i+1} \f$ multiplying it by \f$pow_{\beta}\f$'s factor \f$\left( + * (1-X_i) + X_i\cdot \beta_i\right)\vert_{X_i = u_i}\f$ computed by \ref univariate_eval. + * @param challenge \f$ i \f$-th verifier challenge \f$ u_{i}\f$ */ void partially_evaluate(FF challenge) { @@ -120,7 +78,8 @@ template struct PowPolynomial { } /** - * @brief Given \vec{β} = {β_0,...,β_{d-1}} compute pow_\vec{β}(i) for i=0,...,2^{d}-1 + * @brief Given \f$ \vec\beta = (\beta_0,...,\beta_{d-1})\f$ compute \f$ pow_{\ell}(\vec \beta) = pow_{\beta}(\vec + * \ell)\f$ for \f$ \ell =0,\ldots,2^{d}-1\f$. * */ BB_PROFILE void compute_values() @@ -158,4 +117,72 @@ template struct PowPolynomial { }); } }; +/**< + * @struct PowPolynomial + * @brief Implementation of the methods for the \f$pow_{\ell}\f$-polynomials used in ProtoGalaxy and +\f$pow_{\beta}\f$-polynomials used in Sumcheck. + * + * @details + * ## PowPolynomial in Protogalaxy + * + * \todo Expand this while completing PG docs. + * + * For \f$0\leq \ell \leq 2^d-1 \f$, the \f$pow_{\ell} \f$-polynomials used in Protogalaxy is a multilinear polynomial +defined by the formula + * \f{align} pow_{\ell}(X_0,\ldots, X_{d-1}) + = \prod_{k=0}^{d-1} ( ( 1-\ell_k ) + \ell_k \cdot X_k ) + = \prod_{k=0}^{d-1} X_{k}^{ \ell_k } + \f} + *where \f$(\ell_0,\ldots, \ell_{d-1})\f$ is the binary representation of \f$\ell \f$. + * + * + ## Pow-contributions to Round Univariates in Sumcheck {#PowContributions} + * For a fixed \f$ \vec \beta \in \mathbb{F}^d\f$, the map \f$ \ell \mapsto pow_{\ell} (\vec \beta)\f$ defines a + polynomial \f{align}{ pow_{\beta} (X_0,\ldots, X_{d-1}) = \prod_{k=0}^{d-1} (1- X_k + X_k \cdot \beta_k) + \f} +such that \f$ pow_{\beta} (\vec \ell) = pow_{\ell} (\vec \beta) \f$ for any \f$0\leq \ell \leq 2^d-1 \f$ and any vector +\f$(\beta_0,\ldots, \beta_{d-1}) \in \mathbb{F} ^d\f$. + + * Let \f$ i \f$ be the current Sumcheck round, \f$ i \in \{0, …, d-1\}\f$ and \f$ u_{0}, ..., u_{i-1} \f$ be the +challenges generated in Rounds \f$ 0 \f$ to \f$ i-1\f$. + * + * In Round \f$ i \f$, we iterate over the points \f$ (\ell_{i+1}, \ldots, \ell_{d-1}) \in +\{0,1\}^{d-1-i}\f$. +Define a univariate polynomial \f$pow_{\beta}^i(X_i, \vec \ell) \f$ as follows + * \f{align}{ pow_{\beta}^i(X_i, \vec \ell) = pow_{\beta} ( u_{0}, ..., u_{i-1}, X_i, \ell_{i+1}, \ldots, +\ell_{d-1}) = c_i \cdot ( (1−X_i) + X_i \cdot \beta_i ) \cdot \beta_{i+1}^{\ell_{i+1}}\cdot \cdots \cdot +\beta_{d-1}^{\ell_{d-1}}, \f} where \f$ c_i = \prod_{k=0}^{i-1} (1- u_k + u_k \cdot \beta_k) \f$. It will be used below +to simplify the computation of Sumcheck round univariates. + + ### Computing Sumcheck Round Univariates + * We identify \f$ \vec \ell = (\ell_{i+1}, \ldots, \ell_{d-1}) \in \{0,1\}^{d-1 - i}\f$ with the binary representation +of the integer \f$ \ell \in \{0,\ldots, 2^{d-1-i}-1 \}\f$. + * + * Set + \f{align}{S^i_{\ell}( X_i ) = F( u_{0}, ..., u_{i-1}, X_{i}, \vec \ell ), \f} + * i.e. \f$ S^{i}_{\ell}( X_i ) \f$ is the univariate of the full relation \f$ F \f$ defined by its partial evaluation +at \f$(u_0,\ldots,u_{i-1}, \ell_{i+1},\ldots, \ell_{d-1}) \f$ + * which is an alpha-linear-combination of the subrelations evaluated at this point. + * + * In Round \f$i\f$, the prover + * \ref bb::SumcheckProverRound< Flavor >::compute_univariate "computes the univariate polynomial" for the relation +defined by \f$ \tilde{F} (X_0,\ldots, X_{d-1}) = pow_{\beta}(X_0,\ldots, X_{d-1}) \cdot F\f$, namely + * \f{align}{ + \tilde{S}^{i}(X_i) = \sum_{ \ell = 0} ^{2^{d-i-1}-1} pow^i_\beta ( X_i, \ell_{i+1}, \ldots, \ell_{d-1} ) +S^i_{\ell}( X_i ) + * = c_i \cdot ( (1−X_i) + X_i\cdot \beta_i ) \cdot \sum_{ \ell = 0} ^{2^{d-i-1}-1} \beta_{i+1}^{\ell_{i+1}} +\cdot \ldots \cdot \beta_{d-1}^{\ell_{d-1}} \cdot S^i_{\ell}( X_i ) \f} + * + * Define + \f{align} T^{i}( X_i ) = \sum_{\ell = 0}^{2^{d-i-1}-1} \beta_{i+1}^{\ell_{i+1}} \cdot \ldots \cdot +\beta_{d-1}^{\ell_{d-1}} \cdot S^{i}_{\ell}( X_i ) \f} then \f$ \deg_{X_i} (T^i) \leq \deg_{X_i} S^i \f$. + ### Features of PowPolynomial used by Sumcheck Prover + - The factor \f$ c_i \f$ is the #partial_evaluation_result, it is updated by \ref partially_evaluate. + - The challenges \f$(\beta_0,\ldots, \beta_{d-1}) \f$ are recorded in #betas. + - The consecutive evaluations \f$ pow_{\ell}(\vec \beta) = pow_{\beta}(\vec \ell) \f$ for \f$\vec \ell\f$ identified +with the integers \f$\ell = 0,\ldots, 2^d-1\f$ represented in binary are pre-computed by \ref compute_values and stored +in #pow_betas. + * + */ + } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp index 56a4fc3e9b1..5a78502f149 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp @@ -7,6 +7,112 @@ namespace bb { +/*! \brief The implementation of the sumcheck Prover for statements of the form \f$\sum_{\vec \ell \in \{0,1\}^d} +pow_{\beta}(\vec \ell) \cdot F \left(P_1(\vec \ell),\ldots, P_N(\vec \ell) \right) = 0 \f$ for multilinear polynomials +\f$P_1, \ldots, P_N \f$. + + \details + \section SumcheckProverNotation Notation and Setup + + \subsection SumcheckProverObtainingPolynomials Obtaining Prover/Honk Polynomials + The Sumcheck is applied to multivariate polynomials +\f$P_1, \ldots, P_N\f$ that are specidied by \p Flavor. Namely, \ref prove "prove method" obtains \p full_polynomials by +reference from \p Flavor 's \ref ProverPolynomials "prover polynomials". In particular, their number \f$N\f$ is +specified by the \p Flavor. + + ### Sumcheck Relation + Given multilinear polynomials \f$ P_1,\ldots, P_N \in \mathbb{F}[X_0,\ldots, X_{d-1}] \f$ and a relation \f$ F \f$ +which is a polynomial in \f$ N \f$ variables, we use Sumcheck over the polynomial + * \f{align}{ + \tilde{F} + (X_0,\ldots, X_{d-1}) = + pow_{\beta}(X_0,\ldots, X_{d-1}) \cdot F\left( P_1 (X_0,\ldots, X_{d-1}), \ldots, P_N (X_0,\ldots, X_{d-1}) \right) + \f} +to establish that \f$ F(P_1(\vec \ell),\ldots, P_N(\vec \ell) ) = 0 \f$, i.e. that \f$ F \f$ is satisfied, at every +point of \f$\{0,1\}^d\f$. + + In the implementation, the relation polynomial \f$ F \f$ is determined by \p Flavor::Relations which is fed to \ref +bb::SumcheckProverRound "Sumcheck Round Prover". + + ## Input and Parameters + The following constants are used: + - \f$ d \f$ \ref multivariate_d "the number of variables" in the multilinear polynomials + - \f$ n \f$ \ref multivariate_n "the size of the hypercube", i.e. \f$ 2^d\f$. + - \f$ D = \f$ \ref bb::SumcheckProverRound< Flavor >::BATCHED_RELATION_PARTIAL_LENGTH "total degree of" +\f$\tilde{F}\f$ as a polynomial in \f$P_1,\ldots, P_N\f$ incremented by 1. + + + ## Honk Polynomials and Partially Evaluated Polynomials + + Given \f$ N \f$ Honk \ref ProverPolynomials "Prover Polynomials" \f$ P_1, \ldots, P_N \f$, i.e. multilinear polynomials +in \f$ d \f$ variables. + +### Round 0 +At initialization, \ref ProverPolynomials "Prover Polynomials" +are submitted by reference into \p full_polynomials, which is a two-dimensional array with \f$N\f$ columns and \f$2^d\f$ +rows, whose entries are defined as follows \f$\texttt{full_polynomials}_{i,j} = P_j(\vec i) \f$. Here, \f$ \vec i \in +\{0,1\}^d \f$ is identified with the binary representation of the integer \f$ 0 \leq i \leq 2^d-1 \f$. + +When the first challenge \f$ u_0 \f$ is computed, the method \ref partially_evaluate "partially evaluate" takes as input +\p full_polynomials and populates \ref partially_evaluated_polynomials "a new book-keeping table" denoted by +\f$\texttt{partially_evaluated_polynomials} \f$. Its \f$ n/2 = 2^{d-1} \f$ rows will represent the evaluations +\f$ P_i(u_0, X_1, ..., X_{d-1}) \f$, which are multilinear polynomials in \f$ d-1 \f$ variables. + + +More precisely, it is a table with \f$ 2^{d-1} \f$ rows and \f$ N \f$ columns, such that + \f{align}{ \texttt{partially_evaluated_polynomials}_{i,j} = &\ P_j(0, i_1,\ldots, i_{d-1}) + u_0 \cdot +(P_j(1,i_1,\ldots, i_{d-1})) - P_j(0, i_1,\ldots, i_{d-1})) \\ = &\ \texttt{full_polynomials}_{2 i,j} + u_0 \cdot +(\texttt{full_polynomials}_{2i+1,j} - \texttt{full_polynomials}_{2 i,j}) \f} + +### Updating Partial Evaluations in Subsequent Rounds +In Round \f$ i < d-1\f$, \ref partially_evaluate "partially evaluate" updates the first \f$ 2^{d-1 - i} \f$ rows of +\f$\texttt{partially_evaluated_polynomials}\f$ with the evaluations \f$ P_1(u_0,\ldots, u_i, \vec \ell),\ldots, +P_N(u_0,\ldots, u_i, \vec \ell)\f$ for \f$\vec \ell \in \{0,1\}^{d-1-i}\f$. +The details are specified in \ref partially_evaluate "the corresponding docs." + +### Final Step +After computing the last challenge \f$ u_{d-1} \f$ in Round \f$ d-1 \f$ and updating \f$ +\texttt{partially_evaluated_polynomials} \f$, the prover looks into the 'top' row of the table containing evaluations +\f$P_1(u_0,\ldots, u_{d-1}), \ldots, P_N(u_0,\ldots, u_{d-1})\f$ and concatenates these values with the last challenge +to the transcript. + +## Round Univariates + +\subsubsection SumcheckProverContributionsofPow Contributions of PowPolynomial + + * Let \f$ \vec \beta = (\beta_0,\ldots, \beta_{d-1}) \in \mathbb{F}\f$ be a vector of challenges. + * + * In Round \f$i\f$, a univariate polynomial \f$ \tilde S^{i}(X_{i}) \f$ for the relation defined by \f$ \tilde{F}(X)\f$ +is computed as follows. First, we introduce notation + - \f$ c_i = pow_{\beta}(u_0,\ldots, u_{i-1}) \f$ + - \f$ T^{i}( X_i ) = \sum_{ \ell = 0} ^{2^{d-i-1}-1} \beta_{i+1}^{\ell_{i+1}} \cdot \ldots \cdot +\beta_{d-1}^{\ell_{d-1}} \cdot S^i_{\ell}( X_i ) \f$ + - \f$ S^i_{\ell} (X_i) = F \left(P_1(u_0,\ldots, u_{i-1}, X_i, \vec \ell), \ldots, P_1(u_0,\ldots, u_{i-1}, X_i, \vec +\ell) \right) \f$ + + As explained in \ref bb::PowPolynomial "PowPolynomial", + \f{align}{ + \tilde{S}^{i}(X_i) = \sum_{ \ell = 0} ^{2^{d-i-1}-1} pow^i_\beta ( X_i, \ell_{i+1}, \ldots, \ell_{d-1} ) \cdot +S^i_{\ell}( X_i ) = c_i\cdot ( (1−X_i) + X_i\cdot \beta_i ) \cdot \sum_{\ell = 0}^{2^{d-i-1}-1} \beta_{i+1}^{\ell_{i+1}} +\cdot \ldots \cdot \beta_{d-1}^{\ell_{d-1}} \cdot S^{i}_{\ell}( X_i ). \f} + * +### Computing Round Univariates +The evaluations of the round univariate \f$ \tilde{S}^i \f$ over the domain \f$0,\ldots, D \f$ are obtained by the +method \ref bb::SumcheckProverRound< Flavor >::compute_univariate "compute_univariate". The +implementation consists of the following sub-methods: + + - \ref bb::SumcheckProverRound::extend_edges "Extend evaluations" of linear univariate +polynomials \f$ P_j(u_0,\ldots, u_{i-1}, X_i, \vec \ell) \f$ to the domain \f$0,\ldots, D\f$. + - \ref bb::SumcheckProverRound::accumulate_relation_univariates "Accumulate per-relation contributions" of the extended +polynomials to \f$ T^i(X_i)\f$ + - \ref bb::SumcheckProverRound::extend_and_batch_univariates "Extend and batch the subrelation contibutions" +multiplying by the constants \f$c_i\f$ and the evaluations of \f$ ( (1−X_i) + X_i\cdot \beta_i ) \f$. +## Transcript Operations +After computing Round univariates and adding them to the transcript, the prover generates round challenge by hashing the +transcript. These operations are taken care of by \ref bb::BaseTranscript "Transcript Class" methods. +## Output +The Sumcheck output is specified by \ref bb::SumcheckOutput< Flavor >. + */ template class SumcheckProver { public: @@ -18,7 +124,15 @@ template class SumcheckProver { using Instance = ProverInstance_; using RelationSeparator = typename Flavor::RelationSeparator; + /** + * @brief The size of the hypercube, i.e. \f$ 2^d\f$. + * + */ const size_t multivariate_n; + /** + * @brief The number of variables + * + */ const size_t multivariate_d; std::shared_ptr transcript; @@ -26,37 +140,14 @@ template class SumcheckProver { /** * - * @brief (partially_evaluated_polynomials) Suppose the Honk polynomials (multilinear in d variables) are called P_1, - ..., P_N. - * At initialization, - * we think of these as lying in a two-dimensional array, where each column records the value of one P_i on H^d. - * After the first round, the array will be updated (partially evaluated), so that the first n/2 rows will represent - the - * evaluations P_i(u0, X1, ..., X_{d-1}) as a low-degree extension on H^{d-1}. In reality, we elude copying all - * of the polynomial-defining data by only populating partially_evaluated_polynomials after the first round. I.e.: - - We imagine all of the defining polynomial data in a matrix like this: - | P_1 | P_2 | P_3 | P_4 | ... | P_N | N = number of multivariatesk - |-----------------------------------| - group 0 --| * | * | * | * | ... | * | vertex 0 - \-| * | * | * | * | ... | * | vertex 1 - group 1 --| * | * | * | * | ... | * | vertex 2 - \-| * | * | * | * | ... | * | vertex 3 - | * | * | * | * | ... | * | - group m-1 --| * | * | * | * | ... | * | vertex n-2 - \-| * | * | * | * | ... | * | vertex n-1 - m = n/2 - * - Each group consists of N edges |, and our construction of univariates and partial evaluation - * - operations naturally operate on these groups of edges - + * @brief Container for partially evaluated Prover Polynomials at a current challenge. Upon computing challenge \f$ + u_i \f$, the first \f$2^{d-1-i}\f$ rows are updated using \ref bb::SumcheckProver< Flavor >::partially_evaluate + "partially evaluate" method. * * NOTE: With ~40 columns, prob only want to allocate 256 EdgeGroup's at once to keep stack under 1MB? * TODO(#224)(Cody): might want to just do C-style multidimensional array? for guaranteed adjacency? */ PartiallyEvaluatedMultivariates partially_evaluated_polynomials; - // prover instantiates sumcheck with circuit size and a prover transcript SumcheckProver(size_t multivariate_n, const std::shared_ptr& transcript) : multivariate_n(multivariate_n) @@ -66,8 +157,8 @@ template class SumcheckProver { , partially_evaluated_polynomials(multivariate_n){}; /** - * @brief Compute univariate restriction place in transcript, generate challenge, partially evaluate,... repeat - * until final round, then compute multivariate evaluations and place in transcript. + * @brief Compute round univariate, place it in transcript, compute challenge, partially evaluate. Repeat + * until final round, then get full evaluations of prover polynomials, and place them in transcript. */ SumcheckOutput prove(std::shared_ptr instance) { @@ -78,11 +169,16 @@ template class SumcheckProver { }; /** - * @brief Compute univariate restriction place in transcript, generate challenge, partially evaluate,... repeat - * until final round, then compute multivariate evaluations and place in transcript. - * - * @details + * @brief Compute round univariate, place it in transcript, compute challenge, partially evaluate. Repeat + * until final round, then get full evaluations of prover polynomials, and place them in transcript. + * @details See Detailed description of \ref bb::SumcheckProver< Flavor > "Sumcheck Prover . + * @param full_polynomials Container for ProverPolynomials + * @param relation_parameters + * @param alpha Batching challenge for subrelations. + * @param gate_challenges + * @return SumcheckOutput */ + SumcheckOutput prove(ProverPolynomials& full_polynomials, const bb::RelationParameters& relation_parameters, const RelationSeparator alpha, @@ -95,8 +191,8 @@ template class SumcheckProver { std::vector multivariate_challenge; multivariate_challenge.reserve(multivariate_d); - // First round - // This populates partially_evaluated_polynomials. + // In the first round, we compute the first univariate polynomial and populate the book-keeping table of + // #partially_evaluated_polynomials, which has \f$ n/2 \f$ rows and \f$ N \f$ columns. auto round_univariate = round.compute_univariate(full_polynomials, relation_parameters, pow_univariate, alpha); transcript->send_to_verifier("Sumcheck:univariate_0", round_univariate); FF round_challenge = transcript->template get_challenge("Sumcheck:u_0"); @@ -118,7 +214,7 @@ template class SumcheckProver { round.round_size = round.round_size >> 1; } - // Final round: Extract multivariate evaluations from partially_evaluated_polynomials and add to transcript + // Final round: Extract multivariate evaluations from #partially_evaluated_polynomials and add to transcript ClaimedEvaluations multivariate_evaluations; for (auto [eval, poly] : zip_view(multivariate_evaluations.get_all(), partially_evaluated_polynomials.get_all())) { @@ -130,19 +226,38 @@ template class SumcheckProver { }; /** - * @brief Evaluate at the round challenge and prepare class for next round. - * Illustration of layout in example of first round when d==3 (showing just one Honk polynomial, - * i.e., what happens in just one column of our two-dimensional array): * - * groups vertex terms collected vertex terms groups after partial evaluation - * g0 -- v0 (1-X0)(1-X1)(1-X2) --- (v0(1-X0) + v1 X0) (1-X1)(1-X2) ---- (v0(1-u0) + v1 u0) (1-X1)(1-X2) - * \- v1 X0 (1-X1)(1-X2) --/ --- (v2(1-u0) + v3 u0) X1 (1-X2) - * g1 -- v2 (1-X0) X1 (1-X2) --- (v2(1-X0) + v3 X0) X1 (1-X2)-/ -- (v4(1-u0) + v5 u0) (1-X1) X2 - * \- v3 X0 X1 (1-X2) --/ / - (v6(1-u0) + v7 u0) X1 X2 - * g2 -- v4 (1-X0)(1-X1) X2 --- (v4(1-X0) + v5 X0) (1-X1) X2 -/ / - * \- v5 X0 (1-X1) X2 --/ / - * g3 -- v6 (1-X0) X1 X2 --- (v6(1-X0) + v7 X0) X1 X2 -/ - * \- v7 X0 X1 X2 --/ + @brief Evaluate Honk polynomials at the round challenge and prepare class for next round. + @details At initialization, \ref ProverPolynomials "Prover Polynomials" + are submitted by reference into \p full_polynomials, which is a two-dimensional array defined as \f{align}{ + \texttt{full_polynomials}_{i,j} = P_j(\vec i). \f} Here, \f$ \vec i \in \{0,1\}^d \f$ is identified with the binary + representation of the integer \f$ 0 \leq i \leq 2^d-1 \f$. + + * When the first challenge \f$ u_0 \f$ is computed, the method \ref partially_evaluate "partially evaluate" takes + as input \p full_polynomials and populates \ref partially_evaluated_polynomials "a new book-keeping table" denoted + \f$\texttt{partially_evaluated_polynomials}\f$. Its \f$ n/2 = 2^{d-1} \f$ rows represent the evaluations \f$ + P_i(u_0, X_1, ..., X_{d-1}) \f$, which are multilinear polynomials in \f$ d-1 \f$ variables. + * More precisely, it is a table \f$ 2^{d-1} \f$ rows and \f$ N \f$ columns, such that + \f{align}{ \texttt{partially_evaluated_polynomials}_{i,j} = &\ P_j(0, i_1,\ldots, i_{d-1}) + u_0 \cdot (P_j(1, + i_1,\ldots, i_{d-1})) - P_j(0, i_1,\ldots, i_{d-1})) \\ = &\ \texttt{full_polynomials}_{2 i,j} + u_0 \cdot + (\texttt{full_polynomials}_{2i+1,j} - \texttt{full_polynomials}_{2 i,j}) \f} + * We elude copying all of the polynomial-defining data by only populating \ref partially_evaluated_polynomials + after the first round. + + * In Round \f$0 class SumcheckProver { }; /** * @brief Evaluate at the round challenge and prepare class for next round. - * Specialization for array, see generic version above. + * Specialization for array, see \ref bb::SumcheckProver::partially_evaluate "generic version". */ template void partially_evaluate(std::array& polynomials, size_t round_size, FF round_challenge) @@ -171,20 +286,72 @@ template class SumcheckProver { }); }; }; - +/*! \brief Implementation of the sumcheck Verifier for statements of the form \f$\sum_{\vec \ell \in \{0,1\}^d} + pow_{\beta}(\vec \ell) \cdot F \left(P_1(\vec \ell),\ldots, P_N(\vec \ell) \right) = 0 \f$ for multilinear + polynomials \f$P_1, \ldots, P_N \f$. + * + \class SumcheckVerifier + \details + * Init: + * - Claimed Sumcheck sum: \f$\quad \sigma_{ 0 } \gets 0 \f$ + * + * For \f$ i = 0,\ldots, d-1\f$: + * - Extract Round Univariate's \f$\tilde{F}\f$ evaluations at \f$0,\ldots, D \f$ from the transcript using \ref + bb::BaseTranscript::receive_from_prover "receive_from_prover" method from \ref bb::BaseTranscript< TranscriptParams > + "Base Transcript Class". + * - \ref bb::SumcheckVerifierRound< Flavor >::check_sum "Check target sum": \f$\quad \sigma_{ + i } \stackrel{?}{=} \tilde{S}^i(0) + \tilde{S}^i(1) \f$ + * - Compute the challenge \f$u_i\f$ from the transcript using \ref bb::BaseTranscript::get_challenge "get_challenge" + method. + * - \ref bb::SumcheckVerifierRound< Flavor >::compute_next_target_sum "Compute next target sum" :\f$ \quad \sigma_{i+1} + \gets \tilde{S}^i(u_i) \f$ + * ### Verifier's Data before Final Step + * Entering the final round, the Verifier has already checked that \f$\quad \sigma_{ d-1 } = \tilde{S}^{d-2}(u_{d-2}) + \stackrel{?}{=} \tilde{S}^{d-1}(0) + \tilde{S}^{d-1}(1) \f$ and computed \f$\sigma_d = \tilde{S}^{d-1}(u_{d-1})\f$. + * ### Final Verification Step + * - Extract \ref ClaimedEvaluations of prover polynomials \f$P_1,\ldots, P_N\f$ at the challenge point \f$ + (u_0,\ldots,u_{d-1}) \f$ from the transcript and \ref bb::SumcheckVerifierRound< Flavor + >::compute_full_honk_relation_purported_value "compute evaluation:" + \f{align}{\tilde{F}\left( P_1(u_0,\ldots, u_{d-1}), \ldots, P_N(u_0,\ldots, u_{d-1}) \right)\f} + and store it at \f$ \texttt{full_honk_relation_purported_value} \f$. + * - Compare \f$ \sigma_d \f$ against the evaluation of \f$ \tilde{F} \f$ at \f$P_1(u_0,\ldots, u_{d-1}), \ldots, + P_N(u_0,\ldots, u_{d-1})\f$: + * \f{align}{\quad \sigma_{ d } \stackrel{?}{=} \tilde{F}\left(P_1(u_{0}, \ldots, u_{d-1}),\ldots, P_N(u_0,\ldots, + u_{d-1})\right)\f} + + \snippet cpp/src/barretenberg/sumcheck/sumcheck.hpp Final Verification Step + + */ template class SumcheckVerifier { public: using Utils = bb::RelationUtils; using FF = typename Flavor::FF; + /** + * @brief Container type for the evaluations of Prover Polynomials \f$P_1,\ldots,P_N\f$ at the challenge point + * \f$(u_0,\ldots, u_{d-1}) \f$. + * + */ using ClaimedEvaluations = typename Flavor::AllValues; using Transcript = typename Flavor::Transcript; using RelationSeparator = typename Flavor::RelationSeparator; + /** + * @brief Maximum partial algebraic degree of the relation \f$\tilde F = pow_{\beta} \cdot F \f$, i.e. \ref + * MAX_PARTIAL_RELATION_LENGTH "MAX_PARTIAL_RELATION_LENGTH + 1". + */ static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH; + /** + * @brief The number of Prover Polynomials \f$ P_1, \ldots, P_N \f$ specified by the Flavor. + * + */ static constexpr size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; - + /** + * @brief Number of variables in Prover Polynomials. + * + */ const size_t multivariate_d; + std::shared_ptr transcript; SumcheckVerifierRound round; @@ -193,7 +360,6 @@ template class SumcheckVerifier { : multivariate_d(multivariate_d) , transcript(transcript) , round(target_sum){}; - /** * @brief Extract round univariate, check sum, generate challenge, compute next target sum..., repeat until * final round, then use purported evaluations to generate purported full Honk relation value and check against @@ -249,13 +415,14 @@ template class SumcheckVerifier { purported_evaluations, relation_parameters, pow_univariate, alpha); bool checked = false; + //! [Final Verification Step] if constexpr (IsRecursiveFlavor) { checked = (full_honk_relation_purported_value == round.target_total_sum).get_value(); } else { checked = (full_honk_relation_purported_value == round.target_total_sum); } verified = verified && checked; - + //! [Final Verification Step] return SumcheckOutput{ multivariate_challenge, purported_evaluations, verified }; }; }; diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp index 65624855545..9abd4a2feb0 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp @@ -7,17 +7,19 @@ namespace bb { /** - * @brief Contains the multi-linear evaluations of the polynomials at the challenge point 'u'. - * These are computed by the prover and need to be checked using a multi-linear PCS like Gemini. + * @brief Contains the evaluations of multilinear polynomials \f$ P_1, \ldots, P_N\f$ at the challenge point \f$\vec u + * =(u_0,\ldots, u_{d-1})\f$. These are computed by \ref bb::SumcheckProver< Flavor > "Sumcheck Prover" and need to be + * checked using Zeromorph. */ template struct SumcheckOutput { using FF = typename Flavor::FF; using ClaimedEvaluations = typename Flavor::AllValues; - // u = (u_0, ..., u_{d-1}) + // \f$ \vec u = (u_0, ..., u_{d-1}) \f$ std::vector challenge; - // Evaluations in `u` of the polynomials used in Sumcheck + // Evaluations in \f$ \vec u \f$ of the polynomials used in Sumcheck ClaimedEvaluations claimed_evaluations; - // Whether or not the claimed multilinear evaluations and final sumcheck evaluation have been confirmed + // Whether or not the evaluations of multilinear polynomials \f$ P_1, \ldots, P_N \f$ and final Sumcheck evaluation + // have been confirmed std::optional verified = false; // optional b/c this struct is shared by the Prover/Verifier }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_round.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_round.hpp index 51bdf446605..0cbed010cf4 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_round.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_round.hpp @@ -8,40 +8,19 @@ namespace bb { -/* - Notation: The polynomial P(X0, X1) that is the low-degree extension of its values vij = P(i,j) - for i,j ∈ H = {0,1} is conveniently recorded as follows: - (0,1)-----(1,1) v01 ------ v11 - | | | | P(X0,X1) = (v00 * (1-X0) + v10 * X0) * (1-X1) - X1 | H^2 | | P(X0,X1) | + (v01 * (1-X0) + v11 * X0) * X1 - | | | | - (0,0) ---- (1,0) v00 -------v10 - X0 -*/ - -/* - Example: There are two low-degree extensions Y1, Y2 over the square H^2 in the Cartesian plane. - - 3 -------- 7 4 -------- 8 - | | | | Let F(X0, X1) = G(Y1, Y2) = G0(Y1(X0, X1), Y2(X0, X1)) - | Y1 | | Y2 | + α G1(Y1(X0, X1), Y2(X0, X1)), - | | | | where the relations are G0(Y1, Y2) = Y1 * Y2 - 1 -------- 5 2 -------- 6 and G1(Y1, Y2) = Y1 + Y2. - - G1, G2 together comprise the Relations. - - In the first round, the computations will relate elements along horizontal lines. As a mnemonic, we - use the term "edge" for the linear, univariate polynomials corresponding to the four lines - 1 - 5 - 2 - 6 - 3 - 7 - 4 - 8 - - The polynomials Y1, Y2 are stored in an array in Multivariates. In the first round, these are arrays - of spans living outside of the Multivariates object, and in sebsequent rounds these are arrays of field - elements that are stored in the Multivariates. The rationale for adopting this model is to - avoid copying the full-length polynomials; this way, the largest polynomial array stores in a - Multivariates class is multivariates_n/2. +/*! \brief Imlementation of the Sumcheck prover round. + \class SumcheckProverRound + \details +The evaluations of the round univariate \f$ \tilde{S}^i \f$ over the domain \f$0,\ldots, D \f$ are obtained by the +method \ref bb::SumcheckProverRound< Flavor >::compute_univariate "compute univariate". The +implementation consists of the following sub-methods: + + - \ref bb::SumcheckProverRound::extend_edges "Extend evaluations" of linear univariate + polynomials \f$ P_j(u_0,\ldots, u_{i-1}, X_i, \vec \ell) \f$ to the domain \f$0,\ldots, D\f$. + - \ref bb::SumcheckProverRound::accumulate_relation_univariates "Accumulate per-relation contributions" of the extended +polynomials to \f$ T^i(X_i)\f$ + - \ref bb::SumcheckProverRound::extend_and_batch_univariates "Extend and batch the subrelation contibutions" + multiplying by the constants \f$c_i\f$ and the evaluations of \f$ ( (1−X_i) + X_i\cdot \beta_i ) \f$. Note: This class uses recursive function calls with template parameters. This is a common trick that is used to force the compiler to unroll loops. The idea is that a function that is only called once will always be inlined, and since @@ -59,11 +38,25 @@ template class SumcheckProverRound { public: using FF = typename Flavor::FF; using ExtendedEdges = typename Flavor::ExtendedEdges; - - size_t round_size; // a power of 2 - + /** + * @brief In Round \f$i = 0,\ldots, d-1\f$, equals \f$2^{d-i}\f$. + */ + size_t round_size; + /** + * @brief Number of batched sub-relations in \f$F\f$ specified by Flavor. + * + */ static constexpr size_t NUM_RELATIONS = Flavor::NUM_RELATIONS; + /** + * @brief The total algebraic degree of the Sumcheck relation \f$ F \f$ as a polynomial in Prover Polynomials + * \f$P_1,\ldots, P_N\f$. + */ static constexpr size_t MAX_PARTIAL_RELATION_LENGTH = Flavor::MAX_PARTIAL_RELATION_LENGTH; + /** + * @brief The total algebraic degree of the Sumcheck relation \f$ F \f$ as a polynomial in Prover Polynomials + * \f$P_1,\ldots, P_N\f$ incremented by 1, i.e. it is equal \ref MAX_PARTIAL_RELATION_LENGTH + * "MAX_PARTIAL_RELATION_LENGTH + 1". + */ static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH; SumcheckTupleOfTuplesOfUnivariates univariate_accumulators; @@ -77,11 +70,30 @@ template class SumcheckProverRound { } /** - * @brief Extend each edge in the edge group at to max-relation-length-many values. + * @brief To compute the round univariate in Round \f$i\f$, the prover first computes the values of Honk + polynomials \f$ P_1,\ldots, P_N \f$ at the points of the form \f$ (u_0,\ldots, u_{i-1}, k, \vec \ell)\f$ for \f$ + k=0,\ldots, D \f$, where \f$ D \f$ is defined as + * \ref BATCHED_RELATION_PARTIAL_LENGTH "partial algebraic degree of the relation multiplied by pow-polynomial" * - * @details Should only be called externally with relation_idx equal to 0. - * In practice, multivariates is one of ProverPolynomials or FoldedPolynomials. + * @details In the first round, \ref extend_edges "extend edges" method receives required evaluations from the + prover polynomials. + * In the subsequent rounds, the method receives partially evaluated polynomials. * + * In both cases, in Round \f$ i \f$, \ref extend_edges "the method" receives \f$(0, \vec \ell) \in + \{0,1\}\times\{0,1\}^{d-1 - i} \f$, accesses the evaluations \f$ P_j\left(u_0,\ldots, u_{i-1}, 0, \vec \ell\right) + \f$ and \f$ P_j\left(u_0,\ldots, u_{i-1}, 1, \vec \ell\right) \f$ of \f$ N \f$ linear polynomials \f$ + P_j\left(u_0,\ldots, u_{i-1}, X_{i}, \vec \ell \right) \f$ that are already available either from the prover's + input in the first round, or from the \ref multivariates table. Using general method + \ref bb::Univariate::extend_to "extend_to", the evaluations of these polynomials are extended from the + domain \f$ \{0,1\} \f$ to the domain \f$ \{0,\ldots, D\} \f$ required for the computation of the round univariate. + + * Should only be called externally with relation_idx equal to 0. + * In practice, #multivariates is either ProverPolynomials or PartiallyEvaluatedMultivariates. + * + * @param edge_idx A point \f$(0, \vec \ell) \in \{0,1\}^{d-i} \f$, where \f$ i\in \{0,\ldots, d-1\}\f$ is Round + number. + * @param extended_edges Container for the evaluations of \f$P_j(u_0,\ldots, u_{i-1}, k, \vec \ell) \f$ for + \f$k=0,\ldots, D\f$ and \f$j=1,\ldots,N\f$. */ template void extend_edges(ExtendedEdges& extended_edges, @@ -95,9 +107,26 @@ template class SumcheckProverRound { } /** - * @brief Return the evaluations of the univariate restriction (S_l(X_l) in the thesis) at num_multivariates-many - * values. Most likely this will end up being S_l(0), ... , S_l(t-1) where t is around 12. At the end, reset all + * @brief Return the evaluations of the univariate round polynomials \f$ \tilde{S}_{i} (X_{i}) \f$ at \f$ X_{i } = + 0,\ldots, D \f$. Most likely, \f$ D \f$ is around \f$ 12 \f$. At the + * end, reset all * univariate accumulators to be zero. + * @details First, the vector of \ref pow_challenges "pow challenges" is computed. + * Then, multi-threading is being set up. + * Compute the evaluations of partially evaluated Honk polynomials \f$ P_j\left(u_0,\ldots, u_{i-1}, X_{i} , \vec + \ell \right) \f$ + * for \f$ X_{i} = 2, \ldots, D \f$ using \ref extend_edges "extend edges" method. + * This method invokes more general \ref bb::Univariate::extend_to "extend_to" method that in this case + reduces to a very simple expression \f{align}{ P_j\left( u_0,\ldots, u_{i-1}, k, \vec \ell \right) = P_j\left( + u_0,\ldots, u_{i-1}, k-1, \vec \ell \right) + P_j\left( u_0,\ldots, u_{i-1}, 1, \vec \ell \right) - P_j\left( + u_0,\ldots, u_{i-1}, 0, \vec \ell \right) \f}, + * where \f$ k=2,\ldots, D \f$. + * For a given \f$ \vec \ell \in \{0,1\}^{d -1 -i} \f$, + * we invoke \ref accumulate_relation_univariates "accumulate relation univariates" to compute the contributions of + \f$ P_1\left(u_0,\ldots, u_{i-1}, k, \vec \ell \right) \f$, + ..., \f$ P_N\left(u_0,\ldots, u_{i-1}, k, \vec \ell \right) \f$ to every sub-relation. + * Finally, the accumulators for individual relations' contributions are summed with appropriate factors using + method \ref extend_and_batch_univariates "extend and batch univariates". */ template bb::Univariate compute_univariate( @@ -134,9 +163,11 @@ template class SumcheckProverRound { for (size_t edge_idx = start; edge_idx < end; edge_idx += 2) { extend_edges(extended_edges[thread_idx], polynomials, edge_idx); - // Compute the i-th edge's univariate contribution, - // scale it by the corresponding pow contribution and add it to the accumulators for Sˡ(Xₗ). The pow - // contribution represents the elements of pow(\vec{β}) not containing β_0,..., β_l + // Compute the \f$ \ell \f$-th edge's univariate contribution, + // scale it by the corresponding \f$ pow_{\beta} \f$ contribution and add it to the accumulators for \f$ + // \tilde{S}^i(X_i) \f$. If \f$ \ell \f$'s binary representation is given by \f$ (\ell_{i+1},\ldots, + // \ell_{d-1})\f$, the \f$ pow_{\beta}\f$-contribution is \f$\beta_{i+1}^{\ell_{i+1}} \cdot \ldots \cdot + // \beta_{d-1}^{\ell_{d-1}}\f$. accumulate_relation_univariates(thread_univariate_accumulators[thread_idx], extended_edges[thread_idx], relation_parameters, @@ -155,8 +186,20 @@ template class SumcheckProverRound { } /** - * @brief Given a tuple t = (t_0, t_1, ..., t_{NUM_SUBRELATIONS-1}) and a challenge α, - * return t_0 + αt_1 + ... + α^{NUM_SUBRELATIONS-1}t_{NUM_SUBRELATIONS-1}). + * @brief Given a tuple of tuples of extended per-relation contributions, \f$ (t_0, t_1, \ldots, + * t_{\text{NUM_SUBRELATIONS}-1}) \f$ and a challenge \f$ \alpha \f$, scale them by the relation separator + * \f$\alpha\f$, extend to the correct degree, and take the sum multiplying by \f$pow_{\beta}\f$-contributions. + * + * @details This method receives as input the univariate accumulators computed by \ref + * accumulate_relation_univariates "accumulate relation univariates" after passing through the entire hypercube and + * applying \ref bb::RelationUtils::add_nested_tuples "add_nested_tuples" method to join the threads. The + * accumulators are scaled using the method \ref bb::RelationUtils< Flavor >::scale_univariates "scale univariates", + * extended to the degree \f$ D \f$ and summed with appropriate \f$pow_{\beta}\f$-factors using \ref + * extend_and_batch_univariates "extend and batch univariates method" to return a vector \f$(\tilde{S}^i(0), \ldots, + * \tilde{S}^i(D))\f$. + * + * @param challenge Challenge \f$\alpha\f$. + * @param pow_polynomial Round \f$pow_{\beta}\f$-factor given by \f$ ( (1−u_i) + u_i\cdot \beta_i )\f$. */ template static ExtendedUnivariate batch_over_relations(ContainerOverSubrelations& univariate_accumulators, @@ -175,12 +218,17 @@ template class SumcheckProverRound { } /** - * @brief Extend Univariates to specified size then sum them - * + * @brief Extend Univariates then sum them multiplying by the current \f$ pow_{\beta} \f$-contributions. + * @details Since the sub-relations comprising full Honk relation are of different degrees, the computation of the + * evaluations of round univariate \f$ \tilde{S}_{i}(X_{i}) \f$ at points \f$ X_{i} = 0,\ldots, D \f$ requires to + * extend evaluations of individual relations to the domain \f$ 0,\ldots, D\f$. Moreover, linearly independent + * sub-relations, i.e. whose validity is being checked at every point of the hypercube, are multiplied by the + * constant \f$ c_i = pow_\beta(u_0,\ldots, u_{i-1}) \f$ and the current \f$pow_{\beta}\f$-factor \f$ ( (1−X_i) + + * X_i\cdot \beta_i ) \vert_{X_i = k} \f$ for \f$ k = 0,\ldots, D\f$. * @tparam extended_size Size after extension * @param tuple A tuple of tuples of Univariates - * @param result A Univariate of length extended_size - * @param pow_polynomial Power polynomial univariate + * @param result Round univariate \f$ \tilde{S}^i\f$ represented by its evaluations over \f$ \{0,\ldots, D\} \f$. + * @param pow_polynomial Round \f$pow_{\beta}\f$-factor \f$ ( (1−X_i) + X_i\cdot \beta_i )\f$. */ template static void extend_and_batch_univariates(const TupleOfTuplesOfUnivariates& tuple, @@ -188,7 +236,7 @@ template class SumcheckProverRound { const bb::PowPolynomial& pow_polynomial) { ExtendedUnivariate extended_random_polynomial; - // Random poly R(X) = (1-X) + X.zeta_pow + // Pow-Factor \f$ (1-X) + X\beta_i \f$ auto random_polynomial = bb::Univariate({ 1, pow_polynomial.current_element() }); extended_random_polynomial = random_polynomial.template extend_to(); @@ -201,13 +249,13 @@ template class SumcheckProverRound { // Except from the log derivative subrelation, each other subrelation in part is required to be 0 hence we // multiply by the power polynomial. As the sumcheck prover is required to send a univariate to the // verifier, we additionally need a univariate contribution from the pow polynomial which is the - // extended_random_polynomial. + // extended_random_polynomial which is the if (!is_subrelation_linearly_independent) { result += extended; } else { // Multiply by the pow polynomial univariate contribution and the partial - // evaluation result c_l (i.e. pow(u_0,...,u_{l-1})) where u_0,...,u_{l-1} are the verifier challenges - // from previous rounds) + // evaluation result c_i (i.e. \f$ pow(u_0,...,u_{l-1})) \f$ where \f$(u_0,...,u_{i-1})\f$ are the + // verifier challenges from previous rounds. result += extended * extended_random_polynomial * pow_polynomial.partial_evaluation_result; } }; @@ -216,19 +264,28 @@ template class SumcheckProverRound { private: /** - * @brief For a given edge, calculate the contribution of each relation to the prover round univariate (S_l in the - * thesis). - * - * @details In Round l, the univariate S_l computed by the prover is computed as follows: - * - Outer loop: iterate through the points on the boolean hypercube of dimension = log(round_size), skipping - * every other point. On each iteration, create a Univariate (an 'edge') for each - * multivariate. - * - Inner loop: iterate through the relations, feeding each relation the present collection of edges. Each - * relation adds a contribution + * @brief In Round \f$ i \f$, for a given point \f$ \vec \ell \in \{0,1\}^{d-1 - i}\f$, calculate the contribution + * of each sub-relation to \f$ T^i(X_i) \f$. * - * Result: for each relation, a univariate of some degree is computed by accumulating the contributions of each - * group of edges. These are stored in `univariate_accumulators`. Adding these univariates together, with - * appropriate scaling factors, produces S_l. + * @details In Round \f$ i \f$, this method computes the univariate \f$ T^i(X_i) \f$ deined in \ref + *SumcheckProverContributionsofPow "this section". It is done as follows: + * - Outer loop: iterate through the "edge" points \f$ (0,\vec \ell) \f$ on the boolean hypercube \f$\{0,1\}\times + * \{0,1\}^{d-1 - i}\f$, i.e. skipping every other point. On each iteration, apply \ref extend_edges "extend edges". + * - Inner loop: iterate through the sub-relations, feeding each relation the "the group of edges", i.e. the + * evaluations \f$ P_1(u_0,\ldots, u_{i-1}, k, \vec \ell), \ldots, P_N(u_0,\ldots, u_{i-1}, k, \vec \ell) \f$. Each + * relation Flavor is endowed with \p accumulate method that computes its contribution to \f$ + * T^i(X_{i}) \f$ + *\ref extend_and_batch_univariates "Adding these univariates together", with appropriate scaling factors, produces + *required evaluations of \f$ \tilde S^i \f$. + * @param univariate_accumulators The container for per-thread-per-relation univariate contributions output by \ref + *accumulate_relation_univariates "accumulate relation univariates" for the previous "groups of edges". + * @param extended_edges Contains tuples of evaluations of \f$ P_j\left(u_0,\ldots, u_{i-1}, k, \vec \ell \right) + *\f$, for \f$ j=1,\ldots, N \f$, \f$ k \in \{0,\ldots, D\} \f$ and fixed \f$\vec \ell \in \{0,1\}^{d-1 - i} \f$. + * @param scaling_factor In Round \f$ i \f$, for \f$ (\ell_{i+1}, \ldots, \ell_{d-1}) \in \{0,1\}^{d-1-i}\f$ takes + *an element of \ref bb::PowPolynomial< FF >::pow_betas "vector of powers of challenges" at index \f$ 2^{i+1} + *(\ell_{i+1} 2^{i+1} +\ldots + \ell_{d-1} 2^{d-1})\f$. + * @result #univariate_accumulators are updated with the contribution from the current group of edges. For each + * relation, a univariate of some degree is computed by accumulating the contributions of each group of edges. */ template void accumulate_relation_univariates(SumcheckTupleOfTuplesOfUnivariates& univariate_accumulators, @@ -261,6 +318,18 @@ template class SumcheckProverRound { } }; +/*!\brief Implementation of the Sumcheck Verifier Round + \class SumcheckVerifierRound + \details This Flavor contains the methods + * - \ref bb::SumcheckVerifierRound< Flavor >::check_sum "Check target sum": \f$\quad \sigma_{ + i } \stackrel{?}{=} \tilde{S}^i(0) + \tilde{S}^i(1) \f$ + * - \ref bb::SumcheckVerifierRound< Flavor >::compute_next_target_sum "Compute next target + sum" :\f$ \quad \sigma_{i+1} \gets \tilde{S}^i(u_i) \f$ required in Round \f$ i = 0,\ldots, d-1 \f$. + * + * The last step of the verifification requires to compute the value \f$ pow(u_0,\ldots, u_{d-1}) \cdot F + \left(P_1(u_0,\ldots, u_{d-1}), \ldots, P_N(u_0,\ldots, u_{d-1}) \right) \f$ implemented as + * - \ref compute_full_honk_relation_purported_value method needed at the last verification step. + */ template class SumcheckVerifierRound { using Utils = bb::RelationUtils; using Relations = typename Flavor::Relations; @@ -272,27 +341,37 @@ template class SumcheckVerifierRound { using ClaimedEvaluations = typename Flavor::AllValues; bool round_failed = false; - + /** + * @brief Number of batched sub-relations in \f$F\f$ specified by Flavor. + * + */ static constexpr size_t NUM_RELATIONS = Flavor::NUM_RELATIONS; + /** + * @brief The partial algebraic degree of the relation \f$\tilde F = pow \cdot F \f$, i.e. \ref + * MAX_PARTIAL_RELATION_LENGTH "MAX_PARTIAL_RELATION_LENGTH + 1". + */ static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH; FF target_total_sum = 0; TupleOfArraysOfValues relation_evaluations; - // Verifier constructor explicit SumcheckVerifierRound(FF target_total_sum = 0) : target_total_sum(target_total_sum) { Utils::zero_elements(relation_evaluations); }; - + /** + * @brief Check that the round target sum is correct + * @details The verifier receives the claimed evaluations of the round univariate \f$ \tilde{S}^i \f$ at \f$X_i = + * 0,\ldots, D \f$ and checks \f$\sigma_i = \tilde{S}^{i-1}(u_{i-1}) \stackrel{?}{=} \tilde{S}^i(0) + \tilde{S}^i(1) + * \f$ + * @param univariate Round univariate \f$\tilde{S}^{i}\f$ represented by its evaluations over \f$0,\ldots,D\f$. + * + */ bool check_sum(bb::Univariate& univariate) { - // S^{l}(0) = ( (1−0) + 0⋅ζ^{ 2^l } ) ⋅ T^{l}(0) = T^{l}(0) - // S^{l}(1) = ( (1−1) + 1⋅ζ^{ 2^l } ) ⋅ T^{l}(1) = ζ^{ 2^l } ⋅ T^{l}(1) FF total_sum = univariate.value_at(0) + univariate.value_at(1); - // target_total_sum = sigma_{l} = // TODO(#673): Conditionals like this can go away once native verification is is just recursive verification // with a simulated builder. bool sumcheck_round_failed(false); @@ -310,27 +389,26 @@ template class SumcheckVerifierRound { /** * @brief After checking that the univariate is good for this round, compute the next target sum. * - * @param univariate T^l(X), given by its evaluations over {0,1,2,...}, - * equal to S^{l}(X)/( (1−X) + X⋅ζ^{ 2^l } ) - * @param round_challenge u_l - * @return FF sigma_{l+1} = S^l(u_l) + * @param univariate \f$ \tilde{S}^i(X) \f$, given by its evaluations over \f$ \{0,1,2,\ldots, D\}\f$. + * @param round_challenge \f$ u_i\f$ + * @return FF \f$ \sigma_{i+1} = \tilde{S}^i(u_i)\f$ */ FF compute_next_target_sum(bb::Univariate& univariate, FF& round_challenge) { - // Evaluate T^{l}(u_{l}) + // Evaluate \f$\tilde{S}^{i}(u_{i}) \f$ target_total_sum = univariate.evaluate(round_challenge); return target_total_sum; } /** - * @brief General purpose method for applying a tuple of arrays (of FFs) + * @brief Given the evaluations \f$P_1(u_0,\ldots, u_{d-1}), \ldots, P_N(u_0,\ldots, u_{d-1}) \f$ of the + * ProverPolynomials at the challenge point \f$(u_0,\ldots, u_{d-1})\f$ stored in \p purported_evaluations, this + * method computes the evaluation of \f$ \tilde{F} \f$ taking these values as arguments. * - * @tparam Operation Any operation valid on elements of the inner arrays (FFs) - * @param tuple Tuple of arrays (of FFs) */ // also copy paste in PG // so instead of having claimed evaluations of each relation in part you have the actual evaluations - // kill the pow_univariat + // kill the pow_univariate FF compute_full_honk_relation_purported_value(ClaimedEvaluations purported_evaluations, const bb::RelationParameters& relation_parameters, const bb::PowPolynomial& pow_polynomial,