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,