diff --git a/barretenberg/cpp/docs/Doxyfile b/barretenberg/cpp/docs/Doxyfile index 9727453b25c5..2bdf7d08b706 100644 --- a/barretenberg/cpp/docs/Doxyfile +++ b/barretenberg/cpp/docs/Doxyfile @@ -1355,7 +1355,7 @@ HTML_EXTRA_FILES = # The default value is: AUTO_LIGHT. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_COLORSTYLE = AUTO_LIGHT +HTML_COLORSTYLE = TOGGLE # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to diff --git a/barretenberg/cpp/docs/src/sumcheck-outline.md b/barretenberg/cpp/docs/src/sumcheck-outline.md index 6a78eddad0b5..c141e96446eb 100644 --- a/barretenberg/cpp/docs/src/sumcheck-outline.md +++ b/barretenberg/cpp/docs/src/sumcheck-outline.md @@ -24,11 +24,11 @@ The implementation consists of several components. ### 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 +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) +(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$. @@ -55,9 +55,9 @@ The following constants are used in this exposition. 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}) +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. +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$. @@ -78,18 +78,18 @@ Sumcheck Prover algorithm takes a reference to an object of this class. 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) +\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$. +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::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$. +- \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} @@ -97,22 +97,22 @@ After computing Round Univariate and adding its evaluations \f$\tilde{S}^i(0),\l #### 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 +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} +\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 +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} +\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$. +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$ +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 +\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} @@ -126,11 +126,11 @@ 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*{ +- \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} +- \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} @@ -142,13 +142,13 @@ 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} + (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} +- 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} @@ -159,129 +159,144 @@ As explained in Section 13.3 of ::setup_zk_sumcheck_data "setup_zk_sumcheck_data", which also adds the Libra sum to the transcript. ### 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 +As in [Sumcheck Book-keeping](#BookKeepingTable), we use a table of evaluations of Libra univariates that is being updated in each round. +Namely, before entering the first round, the prover updates the vector of Libra univariates in place \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 + \texttt{libra_univariates}_{j}(k) \gets \texttt{libra_challenge} \cdot 2^{d-1} \cdot g_{j}(k) \text{ for } j= i,\ldots, d-1, \text{ and } k=0,\ldots, \tilde{D} +\f} +and computes 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). + \texttt{libra_running_sum} \gets 2^{-1} \left( \texttt{libra_challenge} \cdot \texttt{libra_total_sum} - \left(\texttt{libra_univariates}_{0}(0) + \texttt{libra_univariates}_{0}(1)\right) \right). \f} + +These entities are created inside \ref bb::SumcheckProver< Flavor >::setup_zk_sumcheck_data "setup_zk_sumcheck_data" and stored in a \ref bb::SumcheckProverRound< Flavor >::ZKSumcheckData "ZKSumcheckData structure" zk_sumcheck_data. +All the modifications between the Sumcheck rounds are performed by the method \ref bb::SumcheckProver< Flavor >::update_libra_data "update Libra data" that is called by \ref bb::SumcheckProver< Flavor >::update_zk_sumcheck_data "update_zk_sumcheck_data". + ### First Round {#LibraFirstRound} -The prover computes first Libra round univariate +The prover computes the 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) + \texttt{libra_round_univariate}_0(X_0) = \texttt{libra_challenge} \cdot \sum_{\vec \ell \in \{0,1\}^{d-1}} G(X_0,\vec \ell) = + 2^{d-1} \texttt{libra_challenge}\cdot g_0(X_0) + 2^{d-2} \texttt{libra_challenge} \cdot \sum_{i=1}^{d-1}\left(g_i(0)+g_i(1)\right). \f} -which could be expressed as follows +By design of the method \ref bb::SumcheckProver< Flavor >::setup_zk_sumcheck_data "setup_zk_sumcheck_data", the latter could be expressed as follows \f{align}{ -\texttt{libra_univariate}\_0 (k) \gets \texttt{libra_table}*{0,k} + \texttt{libra_running_sum} + \texttt{libra_round_univariate}_0 (k) \gets \texttt{libra_univariates}_{0}(k) + \texttt{libra_running_sum} \f} -for \f$k=0,\ldots, \tilde{D}\f$. +for \f$k=0,\ldots, \tilde{D}\f$. It is done by the method \ref bb::SumcheckProverRound< Flavor >::compute_libra_round_univariate "compute_libra_round_univariate" called inside \ref bb::SumcheckProverRound< Flavor >::compute_univariate "Sumcheck Round Univariate computation", which also takes care of adding \f$\texttt{libra_round_univariate}\f$ to the \f$\texttt{round_unviariate}\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 +When the prover receives the challenge \f$u_0\f$, it \ref bb::SumcheckProver< Flavor >::update_libra_data "updates Libra data": + +- updates the table of Libra univariates by multiplying every term by \f$1/2\f$. +- computes the value \f$2^{d-2} \cdot \texttt{libra_challenge} \cdot g_0(u_0)\f$ applying \ref bb::Univariate::evaluate "evaluate" method to the first univariate in the table \f$\texttt{libra_univariates}\f$ +- places the value \f$ g_0(u_0)\f$ to the vector \f$ \texttt{libra_evaluations}\f$ +- 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) + \texttt{libra_running_sum} \gets 2^{d-2} \cdot \texttt{libra_challenge} \cdot g_0(u_0) + 2^{-1} \cdot \left( \texttt{libra_running_sum} - (\texttt{libra_univariates}_{1}(0) + \texttt{libra_univariates}_{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 +In Round \f$ i \f$, the prover computes \f$ i \f$-th Libra round univariate \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) +\texttt{libra_univariate}_i(X_i) = \texttt{libra_challenge} \cdot \sum_{\vec \ell \in \{0,1\}^{d-1 - i}} G(u_0,\ldots, u_{i-1}, X_{i}, \vec \ell) = +\texttt{libra_challenge} \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 + +By design of the method \ref bb::SumcheckProver< Flavor >::update_zk_sumcheck_data "update_zk_sumcheck_data", the latter could be expressed as follows \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}. + \texttt{libra_round_univariate}_i (k) \gets \texttt{libra_univariates}_{i}(k) + \texttt{libra_running_sum} \f} +for \f$k=0,\ldots, \tilde{D}\f$. This computation is done by the method \ref bb::SumcheckProverRound< Flavor >::compute_libra_round_univariate "compute_libra_round_univariate" called inside \ref bb::SumcheckProverRound< Flavor >::compute_univariate "Sumcheck Round Univariate computation", which also adds \f$\texttt{libra_round_univariate}\f$ to the \f$\texttt{round_unviariate}\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} +### Updating Libra Data in Subsequent Rounds {#UpdateLibraData} -### Final Round {#LibraFinalRound} +When the prover receives new challenge \f$u_i\f$, it \ref bb::SumcheckProver< Flavor >::update_libra_data "updates Libra data". If \f$ i < d-1\f$, the prover -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 +- updates the table of Libra univariates by multiplying every term by \f$1/2\f$. +- computes the value \f$2^{d-i - 2} \cdot \texttt{libra_challenge} \cdot g_0(u_0)\f$ applying \ref bb::Univariate::evaluate "evaluate" method to the first univariate in the table \f$\texttt{libra_univariates}\f$ +- places the value \f$ g_0(u_0)\f$ to the vector \f$ \texttt{libra_evaluations}\f$ +- updates the running sum \f{align}{ -v_i = g_i(u_i) \text{ for } i = 0,\ldots, d-1. + \texttt{libra_running_sum} \gets 2^{d-i-2} \cdot \texttt{libra_challenge} \cdot g_0(u_0) + 2^{-1} \cdot \left( \texttt{libra_running_sum} - (\texttt{libra_univariates}_{i+1}(0) + \texttt{libra_univariates}_{i+1}(1)) \right) \f} +If \f$ i = d-1\f$, the prover +- computes the value \f$ g_{d-1}(u_{d-1})\f$ applying \ref bb::Univariate::evaluate "evaluate" method to the last univariate in the table \f$\texttt{libra_univariates}\f$ and dividing the result by \f$ \texttt{libra_challenge} \f$. +- updates the table of Libra univariates by multiplying every term by \f$\texttt{libra_challenge}^{-1}\f$. + +### Proving the Evaluations of Libra Univariates {#ProvingLibraEvaluations} +Libra claimed evaluations \f$ g_0(u_0), \ldots, g_{d-1}(u_d-1)\f$ have to proved using shplonk . + ## Libra Costs {#LibraCosts} @@ -318,18 +333,18 @@ Using the PCS introduced in Section 4 of ::create_evaluation_masking_table "creates the vector" of univariates \f{align}{ -\texttt{masking*terms_evaluations}*{k,j}\gets \rho*j \cdot (1-k) k +\texttt{masking_terms_evaluations}_j(k)\gets \texttt{eval_masking_scalars}_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 +of the same size as the ExtendedEdges created by the ZK Flavor running Sumcheck. + +When the prover receives the challenge \f$ u_i \f$, this vector is \ref bb::SumcheckProver< Flavor >::update_masking_terms_evaluations "updated" as follows + \f{align}{ -\texttt{running_quadratic_term}\_j \gets \rho_j \cdot \sum*{k=0}^{i-1} (1-u_k) u_k. + \texttt{masking_terms_evaluations}_j(k) \gets \texttt{eval_masking_scalars}_j \cdot u_i \cdot (1-u_i) \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) +\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 +&\ 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} +By design, we have +\f{align}{ + \texttt{masking_terms_evaluations}_j(k) = \rho_j \cdot \sum_{k=0}^{i-1} u_k(1-u_k) + \rho_j\cdot (1-k) k. \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). +Then the method \ref bb::SumcheckProverRound< Flavor >::extend_zk_edges "extend_zk_edges" gets the \f$j\f$-th edge corresponding to the witness polynomial and corrects it with the univariate \f$ \texttt{masking_terms_evaluations}_j\f$. The non-witness polynomials are treated as in \ref bb::SumcheckProverRound< Flavor >::extend_edges "extend_edges" used in non-ZK Flavors. -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} +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). 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}{ @@ -465,9 +486,9 @@ The total costs of ZK Sumcheck are obtained from [Libra Costs](#LibraCosts) and ## 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. +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) +\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$ +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/pil/avm/gas.pil b/barretenberg/cpp/pil/avm/gas.pil index ec344c393ee5..ef680830f783 100644 --- a/barretenberg/cpp/pil/avm/gas.pil +++ b/barretenberg/cpp/pil/avm/gas.pil @@ -1,6 +1,7 @@ include "fixed/gas.pil"; -// Gas is a "virtual" trace. Things are only in a separate file for modularity. +// This is a "virtual" trace. Things are only in a separate file for modularity. +// That is, this trace is expected to be in 1-1 relation with the main trace. // However, the columns and relations are set on the "main" namespace. namespace main(256); //===== GAS ACCOUNTING ======================================================== diff --git a/barretenberg/cpp/pil/avm/kernel.pil b/barretenberg/cpp/pil/avm/kernel.pil index 9cc48c6da6c2..9763bcaaa428 100644 --- a/barretenberg/cpp/pil/avm/kernel.pil +++ b/barretenberg/cpp/pil/avm/kernel.pil @@ -1,9 +1,14 @@ -include "main.pil"; include "constants_gen.pil"; -namespace kernel(256); - pol public kernel_inputs; +// The kernel trace is divided into two parts: +// - A 1-1 virtual trace +// - The public inputs which are looked up from the virtual trace +// This is a "virtual" trace. Things are only in a separate file for modularity. +// That is, this trace is expected to be in 1-1 relation with the main trace. +// However, the columns and relations are set on the "main" namespace. +namespace main(256); + pol public kernel_inputs; pol public kernel_value_out; pol public kernel_side_effect_out; pol public kernel_metadata_out; @@ -12,10 +17,9 @@ namespace kernel(256); pol commit kernel_in_offset; pol commit kernel_out_offset; - // Note: in the future, with some codegen adjustments, this column will not be needed - // as we can just add every entry in the public kernel_inputs to the lookup table - pol commit q_public_input_kernel_add_to_table; - pol commit q_public_input_kernel_out_add_to_table; + // These are selectors for the lookups on the public inputs. + pol commit sel_kernel_inputs; + pol commit sel_kernel_out; // Kernel Outputs // @@ -24,7 +28,8 @@ namespace kernel(256); // Global side effect counter; incremented after each side effect is produced. pol commit side_effect_counter; - // TODO(https://github.com/AztecProtocol/aztec-packages/issues/6465): Must constrain write_offset counters to be less than side effect MAX + // TODO(https://github.com/AztecProtocol/aztec-packages/issues/6465): Must constrain write_offset + // counters to be less than side effect MAX // Current write offsets for each opcode pol commit note_hash_exist_write_offset; pol commit nullifier_exists_write_offset; @@ -39,30 +44,146 @@ namespace kernel(256); pol commit emit_unencrypted_log_write_offset; pol commit emit_l2_to_l1_msg_write_offset; - - pol NOT_LAST = (1 - main.sel_last); - // Constraints to increase the offsets when the opcodes are found #[NOTE_HASH_EXISTS_INC_CONSISTENCY_CHECK] - NOT_LAST * (note_hash_exist_write_offset' - (note_hash_exist_write_offset + main.sel_op_note_hash_exists)) = 0; + sel_execution_row * (note_hash_exist_write_offset' - (note_hash_exist_write_offset + sel_op_note_hash_exists)) = 0; #[EMIT_NOTE_HASH_INC_CONSISTENCY_CHECK] - NOT_LAST * (emit_note_hash_write_offset' - (emit_note_hash_write_offset + main.sel_op_emit_note_hash)) = 0; - // if main.ib is set on op_nullifier_exists, then the nullifier_exists_write_offset will be incremented by 1, otherwise non_exists will be incremented + sel_execution_row * (emit_note_hash_write_offset' - (emit_note_hash_write_offset + sel_op_emit_note_hash)) = 0; + + // if ib is set on op_nullifier_exists, then the nullifier_exists_write_offset + // will be incremented by 1, otherwise non_exists will be incremented. #[NULLIFIER_EXISTS_INC_CONSISTENCY_CHECK] - NOT_LAST * (nullifier_exists_write_offset' - (nullifier_exists_write_offset + (main.sel_op_nullifier_exists * main.ib))) = 0; + sel_execution_row * (nullifier_exists_write_offset' - (nullifier_exists_write_offset + (sel_op_nullifier_exists * ib))) = 0; #[NULLIFIER_NON_EXISTS_INC_CONSISTENCY_CHECK] - NOT_LAST * (nullifier_non_exists_write_offset' - (nullifier_non_exists_write_offset + (main.sel_op_nullifier_exists * (1 - main.ib)))) = 0; + sel_execution_row * (nullifier_non_exists_write_offset' - (nullifier_non_exists_write_offset + (sel_op_nullifier_exists * (1 - ib)))) = 0; + #[EMIT_NULLIFIER_INC_CONSISTENCY_CHECK] - NOT_LAST * (emit_nullifier_write_offset' - (emit_nullifier_write_offset + main.sel_op_emit_nullifier)) = 0; + sel_execution_row * (emit_nullifier_write_offset' - (emit_nullifier_write_offset + sel_op_emit_nullifier)) = 0; + #[L1_TO_L2_MSG_EXISTS_INC_CONSISTENCY_CHECK] - NOT_LAST * (l1_to_l2_msg_exists_write_offset' - (l1_to_l2_msg_exists_write_offset + main.sel_op_l1_to_l2_msg_exists)) = 0; + sel_execution_row * (l1_to_l2_msg_exists_write_offset' - (l1_to_l2_msg_exists_write_offset + sel_op_l1_to_l2_msg_exists)) = 0; + #[EMIT_UNENCRYPTED_LOG_INC_CONSISTENCY_CHECK] - NOT_LAST * (emit_unencrypted_log_write_offset' - (emit_unencrypted_log_write_offset + main.sel_op_emit_unencrypted_log)) = 0; - #[EMIT_L2_TO_L1_MSG_INC_CONSISTENCY_CHECK] - NOT_LAST * (emit_l2_to_l1_msg_write_offset' - (emit_l2_to_l1_msg_write_offset + main.sel_op_emit_l2_to_l1_msg)) = 0; + sel_execution_row * (emit_unencrypted_log_write_offset' - (emit_unencrypted_log_write_offset + sel_op_emit_unencrypted_log)) = 0; + #[EMIT_L2_TO_L1_MSG_INC_CONSISTENCY_CHECK] + sel_execution_row * (emit_l2_to_l1_msg_write_offset' - (emit_l2_to_l1_msg_write_offset + sel_op_emit_l2_to_l1_msg)) = 0; #[SLOAD_INC_CONSISTENCY_CHECK] - NOT_LAST * (sload_write_offset' - (sload_write_offset + main.sel_op_sload)) = 0; + sel_execution_row * (sload_write_offset' - (sload_write_offset + sel_op_sload)) = 0; + #[SSTORE_INC_CONSISTENCY_CHECK] - NOT_LAST * (sstore_write_offset' - (sstore_write_offset + main.sel_op_sstore)) = 0; + sel_execution_row * (sstore_write_offset' - (sstore_write_offset + sel_op_sstore)) = 0; + + //===== KERNEL INPUTS CONSTRAINTS =========================================== + // The general pattern for environment lookups is as follows: + // Each kernel opcode related to some fixed positions in the `public kernel_inputs` polynomial + // We can lookup into a fixed index of this polynomial by including constraints that force the value + // of kernel_in_offset to the value relevant to the given opcode that is active + + // TODO: I think we can replace all these (IN) with a single lookup. + // CONTEXT - ENVIRONMENT + #[ADDRESS_KERNEL] + sel_op_address * (kernel_in_offset - constants.ADDRESS_SELECTOR) = 0; + + #[STORAGE_ADDRESS_KERNEL] + sel_op_storage_address * (kernel_in_offset - constants.STORAGE_ADDRESS_SELECTOR) = 0; + + #[SENDER_KERNEL] + sel_op_sender * (kernel_in_offset - constants.SENDER_SELECTOR) = 0; + + #[FUNCTION_SELECTOR_KERNEL] + sel_op_function_selector * (kernel_in_offset - constants.FUNCTION_SELECTOR_SELECTOR) = 0; + + #[FEE_TRANSACTION_FEE_KERNEL] + sel_op_transaction_fee * (kernel_in_offset - constants.TRANSACTION_FEE_SELECTOR) = 0; + + // CONTEXT - ENVIRONMENT - GLOBALS + #[CHAIN_ID_KERNEL] + sel_op_chain_id * (kernel_in_offset - constants.CHAIN_ID_SELECTOR) = 0; + + #[VERSION_KERNEL] + sel_op_version * (kernel_in_offset - constants.VERSION_SELECTOR) = 0; + + #[BLOCK_NUMBER_KERNEL] + sel_op_block_number * (kernel_in_offset - constants.BLOCK_NUMBER_SELECTOR) = 0; + + #[TIMESTAMP_KERNEL] + sel_op_timestamp * (kernel_in_offset - constants.TIMESTAMP_SELECTOR) = 0; + + #[COINBASE_KERNEL] + sel_op_coinbase * (kernel_in_offset - constants.COINBASE_SELECTOR) = 0; + + // CONTEXT - ENVIRONMENT - GLOBALS - FEES + #[FEE_DA_GAS_KERNEL] + sel_op_fee_per_da_gas * (kernel_in_offset - constants.FEE_PER_DA_GAS_SELECTOR) = 0; + + #[FEE_L2_GAS_KERNEL] + sel_op_fee_per_l2_gas * (kernel_in_offset - constants.FEE_PER_L2_GAS_SELECTOR) = 0; + + // OUTPUTS LOOKUPS + // Constrain the value of kernel_out_offset to be the correct offset for the operation being performed + #[NOTE_HASH_KERNEL_OUTPUT] + sel_op_note_hash_exists * (kernel_out_offset - (constants.START_NOTE_HASH_EXISTS_WRITE_OFFSET + note_hash_exist_write_offset)) = 0; + sel_first * note_hash_exist_write_offset = 0; + + #[EMIT_NOTE_HASH_KERNEL_OUTPUT] + sel_op_emit_note_hash * (kernel_out_offset - (constants.START_EMIT_NOTE_HASH_WRITE_OFFSET + emit_note_hash_write_offset)) = 0; + sel_first * emit_note_hash_write_offset = 0; + + #[NULLIFIER_EXISTS_KERNEL_OUTPUT] + sel_op_nullifier_exists * (kernel_out_offset - ((ib * (constants.START_NULLIFIER_EXISTS_OFFSET + nullifier_exists_write_offset)) + ((1 - ib) * (constants.START_NULLIFIER_NON_EXISTS_OFFSET + nullifier_non_exists_write_offset)))) = 0; + sel_first * nullifier_exists_write_offset = 0; + sel_first * nullifier_non_exists_write_offset = 0; + + #[EMIT_NULLIFIER_KERNEL_OUTPUT] + sel_op_emit_nullifier * (kernel_out_offset - (constants.START_EMIT_NULLIFIER_WRITE_OFFSET + emit_nullifier_write_offset)) = 0; + sel_first * emit_nullifier_write_offset = 0; + + #[L1_TO_L2_MSG_EXISTS_KERNEL_OUTPUT] + sel_op_l1_to_l2_msg_exists * (kernel_out_offset - (constants.START_L1_TO_L2_MSG_EXISTS_WRITE_OFFSET + l1_to_l2_msg_exists_write_offset)) = 0; + sel_first * l1_to_l2_msg_exists_write_offset = 0; + + #[EMIT_UNENCRYPTED_LOG_KERNEL_OUTPUT] + sel_op_emit_unencrypted_log * (kernel_out_offset - (constants.START_EMIT_UNENCRYPTED_LOG_WRITE_OFFSET + emit_unencrypted_log_write_offset)) = 0; + sel_first * emit_unencrypted_log_write_offset = 0; + + // TODO: Add the equivalent for GETCONTRACTINSTANCE? + + #[EMIT_L2_TO_L1_MSGS_KERNEL_OUTPUT] + sel_op_emit_l2_to_l1_msg * (kernel_out_offset - (constants.START_EMIT_L2_TO_L1_MSG_WRITE_OFFSET + emit_l2_to_l1_msg_write_offset)) = 0; + sel_first * emit_l2_to_l1_msg_write_offset = 0; + + #[SLOAD_KERNEL_OUTPUT] + sel_op_sload * (kernel_out_offset - (constants.START_SLOAD_WRITE_OFFSET + sload_write_offset)) = 0; + sel_first * sload_write_offset = 0; + + #[SSTORE_KERNEL_OUTPUT] + sel_op_sstore * (kernel_out_offset - (constants.START_SSTORE_WRITE_OFFSET + sstore_write_offset)) = 0; + sel_first * sstore_write_offset = 0; + + // When we encounter a state writing opcode + // We increment the side effect counter by 1 + #[SIDE_EFFECT_COUNTER_INCREMENT] + KERNEL_OUTPUT_SELECTORS * (side_effect_counter' - (side_effect_counter + 1)) = 0; + + //===== LOOKUPS INTO THE PUBLIC INPUTS =========================================== + pol KERNEL_INPUT_SELECTORS = sel_op_address + sel_op_storage_address + sel_op_sender + + sel_op_function_selector + sel_op_transaction_fee + sel_op_chain_id + + sel_op_version + sel_op_block_number + sel_op_coinbase + sel_op_timestamp + + sel_op_fee_per_l2_gas + sel_op_fee_per_da_gas; + // Ensure that only one kernel lookup is active when the kernel_in_offset is active + #[KERNEL_INPUT_ACTIVE_CHECK] + KERNEL_INPUT_SELECTORS * (1 - sel_q_kernel_lookup) = 0; + + pol KERNEL_OUTPUT_SELECTORS = sel_op_note_hash_exists + sel_op_emit_note_hash + sel_op_nullifier_exists + + sel_op_emit_nullifier + sel_op_l1_to_l2_msg_exists + sel_op_emit_unencrypted_log + + sel_op_emit_l2_to_l1_msg + sel_op_sload + sel_op_sstore; + #[KERNEL_OUTPUT_ACTIVE_CHECK] + KERNEL_OUTPUT_SELECTORS * (1 - sel_q_kernel_output_lookup) = 0; + + #[KERNEL_OUTPUT_LOOKUP] + sel_q_kernel_output_lookup {kernel_out_offset, ia, side_effect_counter, ib} in sel_kernel_out {clk, kernel_value_out, kernel_side_effect_out, kernel_metadata_out}; + + #[LOOKUP_INTO_KERNEL] + sel_q_kernel_lookup { main.ia, kernel_in_offset } in sel_kernel_inputs { kernel_inputs, clk }; diff --git a/barretenberg/cpp/pil/avm/main.pil b/barretenberg/cpp/pil/avm/main.pil index 634f53bd7fa3..f1b03e37c3a1 100644 --- a/barretenberg/cpp/pil/avm/main.pil +++ b/barretenberg/cpp/pil/avm/main.pil @@ -370,21 +370,6 @@ namespace main(256); // This works in combination with op_fdiv_err * (sel_op_fdiv - 1) = 0; // Drawback is the need to paralllelize the latter. - //===== KERNEL LOOKUPS ======================================================= - pol KERNEL_INPUT_SELECTORS = sel_op_address + sel_op_storage_address + sel_op_sender - + sel_op_function_selector + sel_op_transaction_fee + sel_op_chain_id - + sel_op_version + sel_op_block_number + sel_op_coinbase + sel_op_timestamp - + sel_op_fee_per_l2_gas + sel_op_fee_per_da_gas; - // Ensure that only one kernel lookup is active when the kernel_in_offset is active - #[KERNEL_INPUT_ACTIVE_CHECK] - KERNEL_INPUT_SELECTORS * (1 - sel_q_kernel_lookup) = 0; - - pol KERNEL_OUTPUT_SELECTORS = sel_op_note_hash_exists + sel_op_emit_note_hash + sel_op_nullifier_exists - + sel_op_emit_nullifier + sel_op_l1_to_l2_msg_exists + sel_op_emit_unencrypted_log - + sel_op_emit_l2_to_l1_msg + sel_op_sload + sel_op_sstore; - #[KERNEL_OUTPUT_ACTIVE_CHECK] - KERNEL_OUTPUT_SELECTORS * (1 - sel_q_kernel_output_lookup) = 0; - //===== CONTROL FLOW ======================================================= // pol commit sel_halted; // sel_halted * (1 - sel_halted) = 0; @@ -517,97 +502,6 @@ namespace main(256); #[DAGASLEFT] sel_op_dagasleft * (ia - da_gas_remaining') = 0; - //===== KERNEL INPUTS CONSTRAINTS =========================================== - // The general pattern for environment lookups is as follows: - // Each kernel opcode related to some fixed positions in the `public kernel_inputs` polynomial - // We can lookup into a fixed index of this polynomial by including constraints that force the value - // of kernel_in_offset to the value relevant to the given opcode that is active - - // CONTEXT - ENVIRONMENT - #[ADDRESS_KERNEL] - sel_op_address * (kernel.kernel_in_offset - constants.ADDRESS_SELECTOR) = 0; - - #[STORAGE_ADDRESS_KERNEL] - sel_op_storage_address * (kernel.kernel_in_offset - constants.STORAGE_ADDRESS_SELECTOR) = 0; - - #[SENDER_KERNEL] - sel_op_sender * (kernel.kernel_in_offset - constants.SENDER_SELECTOR) = 0; - - #[FUNCTION_SELECTOR_KERNEL] - sel_op_function_selector * (kernel.kernel_in_offset - constants.FUNCTION_SELECTOR_SELECTOR) = 0; - - #[FEE_TRANSACTION_FEE_KERNEL] - sel_op_transaction_fee * (kernel.kernel_in_offset - constants.TRANSACTION_FEE_SELECTOR) = 0; - - // CONTEXT - ENVIRONMENT - GLOBALS - #[CHAIN_ID_KERNEL] - sel_op_chain_id * (kernel.kernel_in_offset - constants.CHAIN_ID_SELECTOR) = 0; - - #[VERSION_KERNEL] - sel_op_version * (kernel.kernel_in_offset - constants.VERSION_SELECTOR) = 0; - - #[BLOCK_NUMBER_KERNEL] - sel_op_block_number * (kernel.kernel_in_offset - constants.BLOCK_NUMBER_SELECTOR) = 0; - - #[TIMESTAMP_KERNEL] - sel_op_timestamp * (kernel.kernel_in_offset - constants.TIMESTAMP_SELECTOR) = 0; - - #[COINBASE_KERNEL] - sel_op_coinbase * (kernel.kernel_in_offset - constants.COINBASE_SELECTOR) = 0; - - // CONTEXT - ENVIRONMENT - GLOBALS - FEES - #[FEE_DA_GAS_KERNEL] - sel_op_fee_per_da_gas * (kernel.kernel_in_offset - constants.FEE_PER_DA_GAS_SELECTOR) = 0; - - #[FEE_L2_GAS_KERNEL] - sel_op_fee_per_l2_gas * (kernel.kernel_in_offset - constants.FEE_PER_L2_GAS_SELECTOR) = 0; - - // OUTPUTS LOOKUPS - // Constrain the value of kernel_out_offset to be the correct offset for the operation being performed - #[NOTE_HASH_KERNEL_OUTPUT] - sel_op_note_hash_exists * (kernel.kernel_out_offset - (constants.START_NOTE_HASH_EXISTS_WRITE_OFFSET + kernel.note_hash_exist_write_offset)) = 0; - sel_first * kernel.note_hash_exist_write_offset = 0; - - - #[EMIT_NOTE_HASH_KERNEL_OUTPUT] - sel_op_emit_note_hash * (kernel.kernel_out_offset - (constants.START_EMIT_NOTE_HASH_WRITE_OFFSET + kernel.emit_note_hash_write_offset)) = 0; - sel_first * kernel.emit_note_hash_write_offset = 0; - - #[NULLIFIER_EXISTS_KERNEL_OUTPUT] - sel_op_nullifier_exists * (kernel.kernel_out_offset - ((ib * (constants.START_NULLIFIER_EXISTS_OFFSET + kernel.nullifier_exists_write_offset)) + ((1 - ib) * (constants.START_NULLIFIER_NON_EXISTS_OFFSET + kernel.nullifier_non_exists_write_offset)))) = 0; - sel_first * kernel.nullifier_exists_write_offset = 0; - sel_first * kernel.nullifier_non_exists_write_offset = 0; - - #[EMIT_NULLIFIER_KERNEL_OUTPUT] - sel_op_emit_nullifier * (kernel.kernel_out_offset - (constants.START_EMIT_NULLIFIER_WRITE_OFFSET + kernel.emit_nullifier_write_offset)) = 0; - sel_first * kernel.emit_nullifier_write_offset = 0; - - #[L1_TO_L2_MSG_EXISTS_KERNEL_OUTPUT] - sel_op_l1_to_l2_msg_exists * (kernel.kernel_out_offset - (constants.START_L1_TO_L2_MSG_EXISTS_WRITE_OFFSET + kernel.l1_to_l2_msg_exists_write_offset)) = 0; - sel_first * kernel.l1_to_l2_msg_exists_write_offset = 0; - - #[EMIT_UNENCRYPTED_LOG_KERNEL_OUTPUT] - sel_op_emit_unencrypted_log * (kernel.kernel_out_offset - (constants.START_EMIT_UNENCRYPTED_LOG_WRITE_OFFSET + kernel.emit_unencrypted_log_write_offset)) = 0; - sel_first * kernel.emit_unencrypted_log_write_offset = 0; - - // TODO: Add the equivalent for GETCONTRACTINSTANCE? - - #[EMIT_L2_TO_L1_MSGS_KERNEL_OUTPUT] - sel_op_emit_l2_to_l1_msg * (kernel.kernel_out_offset - (constants.START_EMIT_L2_TO_L1_MSG_WRITE_OFFSET + kernel.emit_l2_to_l1_msg_write_offset)) = 0; - sel_first * kernel.emit_l2_to_l1_msg_write_offset = 0; - - #[SLOAD_KERNEL_OUTPUT] - sel_op_sload * (kernel.kernel_out_offset - (constants.START_SLOAD_WRITE_OFFSET + kernel.sload_write_offset)) = 0; - sel_first * kernel.sload_write_offset = 0; - - #[SSTORE_KERNEL_OUTPUT] - sel_op_sstore * (kernel.kernel_out_offset - (constants.START_SSTORE_WRITE_OFFSET + kernel.sstore_write_offset)) = 0; - sel_first * kernel.sstore_write_offset = 0; - - // When we encounter a state writing opcode - // We increment the side effect counter by 1 - KERNEL_OUTPUT_SELECTORS * (kernel.side_effect_counter' - (kernel.side_effect_counter + 1)) = 0; - //===== Memory Slice Constraints ============================================ pol commit sel_slice_gadget; // Selector to activate a slice gadget operation in the gadget (#[PERM_MAIN_SLICE]). @@ -616,12 +510,6 @@ namespace main(256); //====== Inter-table Constraints ============================================ - #[KERNEL_OUTPUT_LOOKUP] - sel_q_kernel_output_lookup {kernel.kernel_out_offset, ia, kernel.side_effect_counter, ib} in kernel.q_public_input_kernel_out_add_to_table {clk, kernel.kernel_value_out, kernel.kernel_side_effect_out, kernel.kernel_metadata_out}; - - #[LOOKUP_INTO_KERNEL] - sel_q_kernel_lookup { main.ia, kernel.kernel_in_offset } in kernel.q_public_input_kernel_add_to_table { kernel.kernel_inputs, clk }; - #[INCL_MAIN_TAG_ERR] mem.tag_err {mem.clk} in tag_err {clk}; diff --git a/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp index db63d9cb0cdf..0c2845a3021c 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp @@ -443,6 +443,8 @@ template concept IsFoldingFlavor = IsAnyOf, MegaRecursiveFlavor_, MegaRecursiveFlavor_, MegaRecursiveFlavor_>; +template +concept FlavorHasZK = T::HasZK; template inline std::string flavor_get_label(Container&& container, const Element& element) { diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_keccak.hpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_keccak.hpp index 7f28be204a26..ecb74ee54943 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_keccak.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_keccak.hpp @@ -33,6 +33,8 @@ class UltraKeccakFlavor { using CommitmentKey = bb::CommitmentKey; using VerifierCommitmentKey = bb::VerifierCommitmentKey; + // Indicates that this flavor runs with non-ZK Sumcheck. + static constexpr bool HasZK = false; static constexpr size_t NUM_WIRES = CircuitBuilder::NUM_WIRES; // The number of multivariate polynomials on which a sumcheck prover sumcheck operates (including shifts). We often // need containers of this size to hold related data, so we choose a name more agnostic than `NUM_POLYNOMIALS`. @@ -42,6 +44,8 @@ class UltraKeccakFlavor { static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 25; // The total number of witness entities not including shifts. static constexpr size_t NUM_WITNESS_ENTITIES = 8; + // The total number of witnesses including shifts and derived entities. + static constexpr size_t NUM_ALL_WITNESS_ENTITIES = 13; // Total number of folded polynomials, which is just all polynomials except the shifts static constexpr size_t NUM_FOLDED_ENTITIES = NUM_PRECOMPUTED_ENTITIES + NUM_WITNESS_ENTITIES; diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp index d5f71eec3c17..a25bf3f8d818 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp @@ -1,5 +1,6 @@ #pragma once #include "barretenberg/plonk_honk_shared/library/grand_product_delta.hpp" +#include "barretenberg/polynomials/polynomial_arithmetic.hpp" #include "barretenberg/sumcheck/instance/prover_instance.hpp" #include "barretenberg/sumcheck/sumcheck_output.hpp" #include "barretenberg/transcript/transcript.hpp" @@ -120,23 +121,44 @@ template class SumcheckProver { using ProverPolynomials = typename Flavor::ProverPolynomials; using PartiallyEvaluatedMultivariates = typename Flavor::PartiallyEvaluatedMultivariates; using ClaimedEvaluations = typename Flavor::AllValues; + using Transcript = typename Flavor::Transcript; using Instance = ProverInstance_; using RelationSeparator = typename Flavor::RelationSeparator; + /** + * @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; + // this constant specifies the number of coefficients of libra polynomials, and evaluations of round univariate + static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH; + // Specify the number of all witnesses including shifts and derived witnesses from flavors that have ZK, + // otherwise, set this constant to 0 + static constexpr size_t NUM_ALL_WITNESS_ENTITIES = Flavor::NUM_ALL_WITNESS_ENTITIES; /** * @brief The size of the hypercube, i.e. \f$ 2^d\f$. * */ + + using SumcheckRoundUnivariate = typename bb::Univariate; + using EvaluationMaskingTable = + std::array, NUM_ALL_WITNESS_ENTITIES>; const size_t multivariate_n; /** * @brief The number of variables * */ const size_t multivariate_d; + using EvalMaskingScalars = std::array; + // Define the length of Libra Univariates. For non-ZK Flavors: set to 0. + static constexpr size_t LIBRA_UNIVARIATES_LENGTH = Flavor::HasZK ? Flavor::BATCHED_RELATION_PARTIAL_LENGTH : 0; + using LibraUnivariates = std::vector>; std::shared_ptr transcript; SumcheckProverRound round; + // Declare a container for ZK Sumcheck data + ZKSumcheckData zk_sumcheck_data; /** * @@ -178,57 +200,94 @@ template class SumcheckProver { * @param gate_challenges * @return SumcheckOutput */ - SumcheckOutput prove(ProverPolynomials& full_polynomials, const bb::RelationParameters& relation_parameters, const RelationSeparator alpha, const std::vector& gate_challenges) { - + // In case the Flavor has ZK, we populate sumcheck data structure with randomness, compute correcting term for + // the total sum, etc. + if constexpr (Flavor::HasZK) { + setup_zk_sumcheck_data(zk_sumcheck_data); + }; bb::PowPolynomial pow_univariate(gate_challenges); pow_univariate.compute_values(); - std::vector multivariate_challenge; multivariate_challenge.reserve(multivariate_d); - + size_t round_idx = 0; // 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); + // #partially_evaluated_polynomials, which has \f$ n/2 \f$ rows and \f$ N \f$ columns. When the Flavor has ZK, + // compute_univariate also takes into account the zk_sumcheck_data. + auto round_univariate = round.compute_univariate( + round_idx, full_polynomials, relation_parameters, pow_univariate, alpha, zk_sumcheck_data); + // Place the evaluations of the round univariate into transcript. transcript->send_to_verifier("Sumcheck:univariate_0", round_univariate); FF round_challenge = transcript->template get_challenge("Sumcheck:u_0"); multivariate_challenge.emplace_back(round_challenge); + // Prepare sumcheck book-keeping table for the next round partially_evaluate(full_polynomials, multivariate_n, round_challenge); + // Prepare ZK Sumcheck data for the next round + if constexpr (Flavor::HasZK) { + update_zk_sumcheck_data(zk_sumcheck_data, round_challenge, round_idx); + }; pow_univariate.partially_evaluate(round_challenge); round.round_size = round.round_size >> 1; // TODO(#224)(Cody): Maybe partially_evaluate should do this and // release memory? // All but final round // We operate on partially_evaluated_polynomials in place. for (size_t round_idx = 1; round_idx < multivariate_d; round_idx++) { // Write the round univariate to the transcript - round_univariate = - round.compute_univariate(partially_evaluated_polynomials, relation_parameters, pow_univariate, alpha); + round_univariate = round.compute_univariate(round_idx, + partially_evaluated_polynomials, + relation_parameters, + pow_univariate, + alpha, + zk_sumcheck_data); + // Place evaluations of Sumcheck Round Univariate in the transcript transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(round_idx), round_univariate); FF round_challenge = transcript->template get_challenge("Sumcheck:u_" + std::to_string(round_idx)); multivariate_challenge.emplace_back(round_challenge); + // Prepare sumcheck book-keeping table for the next round partially_evaluate(partially_evaluated_polynomials, round.round_size, round_challenge); + // Prepare evaluation masking and libra structures for the next round (for ZK Flavors) + if constexpr (Flavor::HasZK) { + update_zk_sumcheck_data(zk_sumcheck_data, round_challenge, round_idx); + }; + pow_univariate.partially_evaluate(round_challenge); round.round_size = round.round_size >> 1; } + // Check that the challenges \f$ u_0,\ldots, u_{d-1} \f$ do not satisfy the equation \f$ u_0(1-u_0) + \ldots + + // u_{d-1} (1 - u_{d-1}) = 0 \f$. This equation is satisfied with probability ~ 1/|FF|, in such cases the prover + // has to abort and start ZK Sumcheck anew. + if constexpr (Flavor::HasZK) { + check_that_evals_do_not_leak_witness_data(multivariate_challenge); + }; + // Zero univariates are used to pad the proof to the fixed size CONST_PROOF_SIZE_LOG_N. auto zero_univariate = bb::Univariate::zero(); for (size_t idx = multivariate_d; idx < CONST_PROOF_SIZE_LOG_N; idx++) { transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(idx), zero_univariate); FF round_challenge = transcript->template get_challenge("Sumcheck:u_" + std::to_string(idx)); multivariate_challenge.emplace_back(round_challenge); } - - // Final round: Extract multivariate evaluations from #partially_evaluated_polynomials and add to transcript + // The evaluations of Libra uninvariates at \f$ g_0(u_0), \ldots, g_{d-1} (u_{d-1}) \f$ are added to the + // transcript. + if constexpr (Flavor::HasZK) { + transcript->send_to_verifier("Libra:evaluations", zk_sumcheck_data.libra_evaluations); + }; + + // Claimed evaluations of Prover polynomials are extracted and added to the transcript. When Flavor has ZK, the + // evaluations of all witnesses are masked. ClaimedEvaluations multivariate_evaluations; - for (auto [eval, poly] : - zip_view(multivariate_evaluations.get_all(), partially_evaluated_polynomials.get_all())) { - eval = poly[0]; - } + multivariate_evaluations = extract_claimed_evaluations(partially_evaluated_polynomials); transcript->send_to_verifier("Sumcheck:evaluations", multivariate_evaluations.get_all()); - - return { multivariate_challenge, multivariate_evaluations }; + // For ZK Flavors: the evaluations of Libra univariates are included in the Sumcheck Output + if constexpr (!Flavor::HasZK) { + return SumcheckOutput{ multivariate_challenge, multivariate_evaluations }; + } else { + return SumcheckOutput{ multivariate_challenge, + multivariate_evaluations, + zk_sumcheck_data.libra_evaluations }; + } }; /** @@ -291,6 +350,278 @@ template class SumcheckProver { } }); }; + + /** + * @brief This method takes the book-keeping table containing partially evaluated prover polynomials and creates a + * vector containing the evaluations of all prover polynomials at the point \f$ (u_0, \ldots, u_{d-1} )\f$. + * For ZK Flavors: this method takes the book-keeping table containing partially evaluated prover polynomials +and creates a vector containing the evaluations of all witness polynomials at the point \f$ (u_0, \ldots, u_{d-1} )\f$ +masked by the terms \f$ \texttt{eval_masking_scalars}_j\cdot \sum u_i(1-u_i)\f$ and the evaluations of all non-witness +polynomials that are sent in clear. + * + * @param partially_evaluated_polynomials + * @param multivariate_evaluations + */ + ClaimedEvaluations extract_claimed_evaluations(PartiallyEvaluatedMultivariates& partially_evaluated_polynomials) + { + ClaimedEvaluations multivariate_evaluations; + if constexpr (!Flavor::HasZK) { + for (auto [eval, poly] : + zip_view(multivariate_evaluations.get_all(), partially_evaluated_polynomials.get_all())) { + eval = poly[0]; + }; + } else { + // Extract claimed evaluations of non-witness polynomials + for (auto [eval, poly] : zip_view(multivariate_evaluations.get_non_witnesses(), + partially_evaluated_polynomials.get_non_witnesses())) { + eval = poly[0]; + }; + // Extract claimed evaluations of all witness polynomials + for (auto [eval, poly, masking_term] : zip_view(multivariate_evaluations.get_all_witnesses(), + partially_evaluated_polynomials.get_all_witnesses(), + zk_sumcheck_data.masking_terms_evaluations)) { + eval = poly[0] + masking_term.value_at(0); + } + } + return multivariate_evaluations; + }; + + /** + * @brief Create and populate the structure required for the ZK Sumcheck. + + * @details This method creates an array of random field elements \f$ \rho_1,\ldots, \rho_{N_w}\f$ aimed to mask the + evaluations of witness polynomials, these are contained in \f$ \texttt{eval_masking_scalars} \f$. In order to + optimize the computation of Sumcheck Round Univariates, it populates a table of univariates \f$ + \texttt{masking_terms_evaluations} \f$ which contains at the beginning the evaluations of polynomials \f$ \rho_j + \cdot (1-X)\cdot X \f$ at \f$ 0,\ldots, \text{MAX_PARTIAL_RELATION_LENGTH} - 1\f$. This method also creates Libra + univariates, computes the Libra total sum and adds it to the transcript, and sets up all auxiliary objects. + * + * @param zk_sumcheck_data + */ + void setup_zk_sumcheck_data(ZKSumcheckData& zk_sumcheck_data) + { + + EvalMaskingScalars eval_masking_scalars; + + for (size_t k = 0; k < NUM_ALL_WITNESS_ENTITIES; ++k) { + eval_masking_scalars[k] = FF::random_element(); + }; + // Generate random scalars \f$ \rho_1,\ldots, \rho_{N_w}\f$ to mask the evaluations of witness polynomials and + // populate the table masking_terms_evaluations with the terms \f$ \rho_j \cdot (1-k) \cdot k \f$ + auto masking_terms_evaluations = create_evaluation_masking_table(eval_masking_scalars); + // Generate random Libra Polynomials to mask Round Univariates. + LibraUnivariates libra_univariates = generate_libra_polynomials(multivariate_d); + // have to commit to libra_univariates here + auto libra_scaling_factor = FF(1); + FF libra_total_sum = compute_libra_total_sum(libra_univariates, libra_scaling_factor); + transcript->send_to_verifier("Libra:Sum", libra_total_sum); + // get the challenge for the zk-sumcheck claim \sigma + \rho \cdot libra_total_sum + FF libra_challenge = transcript->template get_challenge("Libra:Challenge"); + // Initialize Libra running sum by multiplpying it by Libra challenge \f$\rho\f$; + auto libra_running_sum = libra_total_sum * libra_challenge; + // Multiply the column-univariates of the array of libra polynomials by libra challenge and power of \f$ 2\f$, + // modify libra running_sum subtracting the contribution from the first univariate + setup_libra_data(libra_univariates, libra_scaling_factor, libra_challenge, libra_running_sum); + + std::vector libra_evaluations; + libra_evaluations.reserve(multivariate_d); + zk_sumcheck_data = ZKSumcheckData(eval_masking_scalars, + masking_terms_evaluations, + libra_univariates, + libra_scaling_factor, + libra_challenge, + libra_running_sum, + libra_evaluations); + }; + + /** + * @brief Given number of univariate polynomials and the number of their evaluations meant to be hidden, this method + * produces a vector of univariate polynomials of degree \ref ZK_BATCHED_LENGTH "ZK_BATCHED_LENGTH - 1" with + * independent uniformly random coefficients. + * + */ + static LibraUnivariates generate_libra_polynomials(size_t number_of_polynomials) + { + LibraUnivariates libra_full_polynomials(number_of_polynomials); + for (auto& libra_polynomial : libra_full_polynomials) { + // generate random polynomial of required size + libra_polynomial = bb::Univariate::get_random(); + }; + + return libra_full_polynomials; + }; + /** + * @brief Generate an array of random scalars of size equal to the number of all witness polynomials and populate a + * table of evaluations of the quadratic terms needed for masking evaluations of witnesses. + * + * @param evaluations + */ + static EvaluationMaskingTable create_evaluation_masking_table(EvalMaskingScalars eval_masking_scalars) + { + EvaluationMaskingTable output_table; + for (size_t column_idx = 0; column_idx < NUM_ALL_WITNESS_ENTITIES; ++column_idx) { + for (size_t row_idx = 0; row_idx < MAX_PARTIAL_RELATION_LENGTH; ++row_idx) { + auto scalar = FF(row_idx); + output_table[column_idx].value_at(row_idx) = + scalar * (FF(1) - scalar) * eval_masking_scalars[column_idx]; + }; + }; + return output_table; + }; + + /** + * @brief Update the table of masking quadratic terms by adding a contribution from a current challenge. + * + @details At initialization, \f$j\f$'th column of the masking terms evaluations table is a vector \f$(0, 0, \rho_2 + \cdot 2, \ldots, \rho_j \cdot k (1-k), \ldots, \rho_j \cdot (D-1) (1-(D-1)))\f$. Upon getting current round + challenge, the prover adds the term \f$ \rho_j \cdot u_i \cdot (1-u_i)\f$ to each entry in the table. + + It is useful at the stage of evaluating the relation \f$ \tilde{F} \f$ at the arguments given by the values of + \f$(\widehat{P}_1, \ldots, \widehat{P}_{N_w})\f$ at the points \f$u_0,\ldots, u_{i}, k, \vec \ell)\f$. + * @param evaluations + * @param masking_scalars + * @param round_challenge + */ + void update_masking_terms_evaluations(ZKSumcheckData& zk_sumcheck_data, FF round_challenge) + { + for (auto [masking_term, masking_scalar] : + zip_view(zk_sumcheck_data.masking_terms_evaluations, zk_sumcheck_data.eval_masking_scalars)) { + for (size_t k = 0; k < MAX_PARTIAL_RELATION_LENGTH; ++k) { + masking_term.value_at(k) += round_challenge * (FF(1) - round_challenge) * masking_scalar; + } + } + } + /** + * @brief Compute the sum of the randomly sampled multivariate polynomial \f$ G = \sum_{i=0}^{n-1} g_i(X_i) \f$ over + * the Boolean hypercube. + * + * @param libra_univariates + * @param scaling_factor + * @return FF + */ + static FF compute_libra_total_sum(auto libra_univariates, FF& scaling_factor) + { + FF total_sum = 0; + scaling_factor = scaling_factor / 2; + + for (auto univariate : libra_univariates) { + total_sum += univariate.value_at(0) + univariate.value_at(1); + scaling_factor *= 2; + } + total_sum *= scaling_factor; + + return total_sum; + } + /** + * @brief Set up Libra book-keeping table that simplifies the computation of Libra Round Univariates + * + * @details The array of Libra univariates is getting scaled + * \f{align}{ + \texttt{libra_univariates} \gets \texttt{libra_univariates}\cdot \rho \cdot 2^{d-1} + \f} + * We also initialize + * \f{align}{ + \texttt{libra_running_sum} \gets \texttt{libra_total_sum} - \texttt{libra_univariates}_{0,0} - + \texttt{libra_univariates}_{0,1} \f}. + * @param libra_table + * @param libra_round_factor + * @param libra_challenge + */ + void setup_libra_data(auto& libra_univariates, + FF& libra_scaling_factor, + const FF libra_challenge, + FF& libra_running_sum) + { + libra_scaling_factor *= libra_challenge; // \rho * 2^{d-1} + for (auto& univariate : libra_univariates) { + univariate *= libra_scaling_factor; + }; + // subtract the contribution of the first libra univariate from libra total sum + libra_running_sum += -libra_univariates[0].value_at(0) - libra_univariates[0].value_at(1); + libra_running_sum *= FF(1) / FF(2); + } + + /** + * @brief Upon receiving the challenge \f$u_i\f$, the prover updates Libra data. If \f$ i < d-1\f$ + + - update the table of Libra univariates by multiplying every term by \f$1/2\f$. + - computes the value \f$2^{d-i - 2} \cdot \texttt{libra_challenge} \cdot g_0(u_0)\f$ applying \ref + bb::Univariate::evaluate "evaluate" method to the first univariate in the table \f$\texttt{libra_univariates}\f$ + - places the value \f$ g_0(u_0)\f$ to the vector \f$ \texttt{libra_evaluations}\f$ + - update the running sum + \f{align}{ + \texttt{libra_running_sum} \gets 2^{d-i-2} \cdot \texttt{libra_challenge} \cdot g_0(u_0) + 2^{-1} + \cdot \left( \texttt{libra_running_sum} - (\texttt{libra_univariates}_{i+1}(0) + + \texttt{libra_univariates}_{i+1}(1)) \right) \f} If \f$ i = d-1\f$ + - compute the value \f$ g_{d-1}(u_{d-1})\f$ applying \ref bb::Univariate::evaluate "evaluate" method to the + last univariate in the table \f$\texttt{libra_univariates}\f$ and dividing the result by \f$ + \texttt{libra_challenge} \f$. + - update the table of Libra univariates by multiplying every term by \f$\texttt{libra_challenge}^{-1}\f$. + @todo Refactor once the Libra univariates are extracted from the Proving Key. Then the prover does not need to + update the first round_idx - 1 univariates and could release the memory. Also, use batch_invert / reduce + the number of divisions by 2. + * @param libra_univariates + * @param round_challenge + * @param round_idx + * @param libra_running_sum + * @param libra_evaluations + */ + void update_libra_data(ZKSumcheckData& zk_sumcheck_data, const FF round_challenge, size_t round_idx) + { + // when round_idx = d - 1, the update is not needed + if (round_idx < zk_sumcheck_data.libra_univariates.size() - 1) { + for (auto& univariate : zk_sumcheck_data.libra_univariates) { + univariate *= FF(1) / FF(2); + }; + // compute the evaluation \f$ \rho \cdot 2^{d-2-i} \çdot g_i(u_i) \f$ + auto libra_evaluation = zk_sumcheck_data.libra_univariates[round_idx].evaluate(round_challenge); + auto next_libra_univariate = zk_sumcheck_data.libra_univariates[round_idx + 1]; + // update the running sum by adding g_i(u_i) and subtracting (g_i(0) + g_i(1)) + zk_sumcheck_data.libra_running_sum += + -next_libra_univariate.value_at(0) - next_libra_univariate.value_at(1); + zk_sumcheck_data.libra_running_sum *= FF(1) / FF(2); + + zk_sumcheck_data.libra_running_sum += libra_evaluation; + zk_sumcheck_data.libra_scaling_factor *= FF(1) / FF(2); + + zk_sumcheck_data.libra_evaluations.emplace_back(libra_evaluation / zk_sumcheck_data.libra_scaling_factor); + } else { + // compute the evaluation of the last Libra univariate at the challenge u_{d-1} + auto libra_evaluation = zk_sumcheck_data.libra_univariates[round_idx].evaluate(round_challenge) / + zk_sumcheck_data.libra_scaling_factor; + // place the evalution into the vector of Libra evaluations + zk_sumcheck_data.libra_evaluations.emplace_back(libra_evaluation); + for (auto univariate : zk_sumcheck_data.libra_univariates) { + univariate *= FF(1) / zk_sumcheck_data.libra_challenge; + } + }; + } + + void update_zk_sumcheck_data(ZKSumcheckData& zk_sumcheck_data, FF round_challenge, size_t round_idx) + { + update_libra_data(zk_sumcheck_data, round_challenge, round_idx); + update_masking_terms_evaluations(zk_sumcheck_data, round_challenge); + } + /** + * @brief By the design of ZK Sumcheck, instead of claimed evaluations of witness polynomials \f$ P_1, \ldots, + P_{N_w} \f$, the prover sends the evaluations of the witness polynomials masked by the terms \f$ \rho_j + \sum_{i=0}^{d-1} u_i(1-u_i) \f$ for \f$ j= 1, \ldots N_w\f$. If the challenges satisfy the equation + \f$\sum_{i=0}^{d-1} u_i(1-u_i) = 0\f$, each masking term is \f$0 \f$, which could lead to the leakage of witness + information. The challenges satisfy this equation with probability \f$ \sim 1/|\mathbb{F}|\f$. + * + * @param multivariate_challenge + */ + void check_that_evals_do_not_leak_witness_data(std::vector multivariate_challenge) + { + auto masking_term = FF(0); + for (auto challenge : multivariate_challenge) { + masking_term += challenge * (FF(1) - challenge); + } + if (masking_term == FF(0)) { + throw_or_abort("The evaluations of witness polynomials are not masked, because u_0(1-u_0)+...+u_{d-1} " + "(1-u_{d-1}) = 0 "); + }; + } }; /*! \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 @@ -339,6 +670,9 @@ template class SumcheckVerifier { * */ using ClaimedEvaluations = typename Flavor::AllValues; + // For ZK Flavors: the verifier obtains a vector of evaluations of \f$ d \f$ univariate polynomials and uses them to + // compute full_honk_relation_purported_value + using ClaimedLibraEvaluations = typename std::vector; using Transcript = typename Flavor::Transcript; using RelationSeparator = typename Flavor::RelationSeparator; @@ -389,8 +723,21 @@ template class SumcheckVerifier { throw_or_abort("Number of variables in multivariate is 0."); } + FF libra_challenge; + FF libra_total_sum; + if constexpr (Flavor::HasZK) { + // get the claimed sum of libra masking multivariate over the hypercube + libra_total_sum = transcript->template receive_from_prover("Libra:Sum"); + // get the challenge for the ZK Sumcheck claim + libra_challenge = transcript->template get_challenge("Libra:Challenge"); + } std::vector multivariate_challenge; multivariate_challenge.reserve(multivariate_d); + // if Flavor has ZK, the target total sum is corrected by Libra total sum multiplied by the Libra + // challenge + if constexpr (Flavor::HasZK) { + round.target_total_sum += libra_total_sum * libra_challenge; + }; for (size_t round_idx = 0; round_idx < CONST_PROOF_SIZE_LOG_N; round_idx++) { // Obtain the round univariate from the transcript std::string round_univariate_label = "Sumcheck:univariate_" + std::to_string(round_idx); @@ -417,7 +764,6 @@ template class SumcheckVerifier { bool checked = round.check_sum(round_univariate); verified = verified && checked; multivariate_challenge.emplace_back(round_challenge); - round.compute_next_target_sum(round_univariate, round_challenge); pow_univariate.partially_evaluate(round_challenge); } else { @@ -425,29 +771,42 @@ template class SumcheckVerifier { } } } - + // Extract claimed evaluations of Libra univariates and compute their sum multiplied by the Libra challenge + ClaimedLibraEvaluations libra_evaluations(multivariate_d); + FF full_libra_purported_value = FF(0); + if constexpr (Flavor::HasZK) { + for (size_t idx = 0; idx < multivariate_d; idx++) { + libra_evaluations[idx] = + transcript->template receive_from_prover("libra_evaluation" + std::to_string(idx)); + full_libra_purported_value += libra_evaluations[idx]; + }; + full_libra_purported_value *= libra_challenge; + }; // Final round ClaimedEvaluations purported_evaluations; auto transcript_evaluations = transcript->template receive_from_prover>("Sumcheck:evaluations"); - for (auto [eval, transcript_eval] : zip_view(purported_evaluations.get_all(), transcript_evaluations)) { eval = transcript_eval; } - - FF full_honk_relation_purported_value = round.compute_full_honk_relation_purported_value( - purported_evaluations, relation_parameters, pow_univariate, alpha); - - bool checked = false; + // Evaluate the Honk relation at the point (u_0, ..., u_{d-1}) using claimed evaluations of prover polynomials. + // In ZK Flavors, the evaluation is corrected by full_libra_purported_value + FF full_honk_purported_value = round.compute_full_honk_relation_purported_value( + purported_evaluations, relation_parameters, pow_univariate, alpha, full_libra_purported_value); + bool final_check(false); //! [Final Verification Step] if constexpr (IsRecursiveFlavor) { - checked = (full_honk_relation_purported_value.get_value() == round.target_total_sum.get_value()); + final_check = (full_honk_purported_value.get_value() == round.target_total_sum.get_value()); } else { - checked = (full_honk_relation_purported_value == round.target_total_sum); + final_check = (full_honk_purported_value == round.target_total_sum); + } + verified = final_check && verified; + // For ZK Flavors: the evaluations of Libra univariates are included in the Sumcheck Output + if constexpr (!Flavor::HasZK) { + return SumcheckOutput{ multivariate_challenge, purported_evaluations, verified }; + } else { + return SumcheckOutput{ multivariate_challenge, purported_evaluations, libra_evaluations, verified }; } - verified = verified && checked; - //! [Final Verification Step] - return SumcheckOutput{ multivariate_challenge, purported_evaluations, verified }; }; }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.test.cpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.test.cpp index ebbb6b4e1917..cc38be1383a0 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.test.cpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.test.cpp @@ -7,189 +7,179 @@ #include "barretenberg/relations/permutation_relation.hpp" #include "barretenberg/relations/ultra_arithmetic_relation.hpp" #include "barretenberg/stdlib_circuit_builders/plookup_tables/fixed_base/fixed_base.hpp" +#include "barretenberg/stdlib_circuit_builders/ultra_flavor.hpp" +#include "barretenberg/stdlib_circuit_builders/ultra_zk_flavor.hpp" #include "barretenberg/transcript/transcript.hpp" - #include using namespace bb; namespace { -using Flavor = UltraFlavor; -using FF = typename Flavor::FF; -using Polynomial = Polynomial; -using ProverPolynomials = typename Flavor::ProverPolynomials; -using RelationSeparator = Flavor::RelationSeparator; -const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; - -Polynomial random_poly(size_t size) -{ - auto poly = Polynomial(size); - for (auto& coeff : poly) { - coeff = FF::random_element(); +template class SumcheckTests : public ::testing::Test { + public: + using FF = typename Flavor::FF; + using ProverPolynomials = typename Flavor::ProverPolynomials; + using RelationSeparator = Flavor::RelationSeparator; + const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; + static void SetUpTestSuite() { bb::srs::init_crs_factory("../srs_db/ignition"); } + + Polynomial random_poly(size_t size) + { + auto poly = bb::Polynomial(size); + for (auto& coeff : poly) { + coeff = FF::random_element(); + } + return poly; } - return poly; -} -ProverPolynomials construct_ultra_full_polynomials(auto& input_polynomials) -{ - ProverPolynomials full_polynomials; - for (auto [full_poly, input_poly] : zip_view(full_polynomials.get_all(), input_polynomials)) { - full_poly = input_poly.share(); + ProverPolynomials construct_ultra_full_polynomials(auto& input_polynomials) + { + ProverPolynomials full_polynomials; + for (auto [full_poly, input_poly] : zip_view(full_polynomials.get_all(), input_polynomials)) { + full_poly = input_poly.share(); + } + return full_polynomials; } - return full_polynomials; -} -} // namespace -class SumcheckTests : public ::testing::Test { - protected: - static void SetUpTestSuite() { bb::srs::init_crs_factory("../srs_db/ignition"); } -}; + void test_polynomial_normalization() + { + // TODO(#225)(Cody): We should not use real constants like this in the tests, at least not in so many of them. + const size_t multivariate_d(3); + const size_t multivariate_n(1 << multivariate_d); -TEST_F(SumcheckTests, PolynomialNormalization) -{ - // TODO(#225)(Cody): We should not use real constants like this in the tests, at least not in so many of them. - const size_t multivariate_d(3); - const size_t multivariate_n(1 << multivariate_d); - - // Randomly construct the prover polynomials that are input to Sumcheck. - // Note: ProverPolynomials are defined as spans so the polynomials they point to need to exist in memory. - std::array, NUM_POLYNOMIALS> random_polynomials; - for (auto& poly : random_polynomials) { - poly = random_poly(multivariate_n); - } - auto full_polynomials = construct_ultra_full_polynomials(random_polynomials); + // Randomly construct the prover polynomials that are input to Sumcheck. + // Note: ProverPolynomials are defined as spans so the polynomials they point to need to exist in memory. + std::vector> random_polynomials(NUM_POLYNOMIALS); + for (auto& poly : random_polynomials) { + poly = random_poly(multivariate_n); + } + auto full_polynomials = construct_ultra_full_polynomials(random_polynomials); - info(full_polynomials.w_l[0]); - info(full_polynomials.w_l[1]); - info(full_polynomials.w_l[2]); - info(full_polynomials.w_l[3]); + auto transcript = Flavor::Transcript::prover_init_empty(); - auto transcript = Flavor::Transcript::prover_init_empty(); + auto sumcheck = SumcheckProver(multivariate_n, transcript); + RelationSeparator alpha; + for (size_t idx = 0; idx < alpha.size(); idx++) { + alpha[idx] = transcript->template get_challenge("Sumcheck:alpha_" + std::to_string(idx)); + } - auto sumcheck = SumcheckProver(multivariate_n, transcript); - RelationSeparator alpha; - for (size_t idx = 0; idx < alpha.size(); idx++) { - alpha[idx] = transcript->template get_challenge("Sumcheck:alpha_" + std::to_string(idx)); - } + std::vector gate_challenges(multivariate_d); + for (size_t idx = 0; idx < multivariate_d; idx++) { + gate_challenges[idx] = + transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + } + auto output = sumcheck.prove(full_polynomials, {}, alpha, gate_challenges); + + FF u_0 = output.challenge[0]; + FF u_1 = output.challenge[1]; + FF u_2 = output.challenge[2]; + + /* sumcheck.prove() terminates with sumcheck.multivariates.folded_polynoimals as an array such that + * sumcheck.multivariates.folded_polynoimals[i][0] is the evaluatioin of the i'th multivariate at the vector of + challenges u_i. What does this mean? + + Here we show that if the multivariate is F(X0, X1, X2) defined as above, then what we get is F(u0, u1, u2) and + not, say F(u2, u1, u0). This is in accordance with Adrian's thesis (cf page 9). + */ + + // Get the values of the Lagrange basis polys L_i defined + // by: L_i(v) = 1 if i = v, 0 otherwise, for v from 0 to 7. + FF one{ 1 }; + // clang-format off + FF l_0 = (one - u_0) * (one - u_1) * (one - u_2); + FF l_1 = (u_0) * (one - u_1) * (one - u_2); + FF l_2 = (one - u_0) * (u_1) * (one - u_2); + FF l_3 = (u_0) * (u_1) * (one - u_2); + FF l_4 = (one - u_0) * (one - u_1) * (u_2); + FF l_5 = (u_0) * (one - u_1) * (u_2); + FF l_6 = (one - u_0) * (u_1) * (u_2); + FF l_7 = (u_0) * (u_1) * (u_2); + // clang-format on + FF hand_computed_value; + for (auto [full_poly, partial_eval_poly] : + zip_view(full_polynomials.get_all(), sumcheck.partially_evaluated_polynomials.get_all())) { + // full_polynomials[0][0] = w_l[0], full_polynomials[1][1] = w_r[1], and so on. + hand_computed_value = l_0 * full_poly[0] + l_1 * full_poly[1] + l_2 * full_poly[2] + l_3 * full_poly[3] + + l_4 * full_poly[4] + l_5 * full_poly[5] + l_6 * full_poly[6] + l_7 * full_poly[7]; + EXPECT_EQ(hand_computed_value, partial_eval_poly[0]); + } - std::vector gate_challenges(multivariate_d); - for (size_t idx = 0; idx < multivariate_d; idx++) { - gate_challenges[idx] = transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); - } - auto output = sumcheck.prove(full_polynomials, {}, alpha, gate_challenges); - - FF u_0 = output.challenge[0]; - FF u_1 = output.challenge[1]; - FF u_2 = output.challenge[2]; - - /* sumcheck.prove() terminates with sumcheck.multivariates.folded_polynoimals as an array such that - * sumcheck.multivariates.folded_polynoimals[i][0] is the evaluatioin of the i'th multivariate at the vector of - challenges u_i. What does this mean? - - Here we show that if the multivariate is F(X0, X1, X2) defined as above, then what we get is F(u0, u1, u2) and - not, say F(u2, u1, u0). This is in accordance with Adrian's thesis (cf page 9). - */ - - // Get the values of the Lagrange basis polys L_i defined - // by: L_i(v) = 1 if i = v, 0 otherwise, for v from 0 to 7. - FF one{ 1 }; - // clang-format off - FF l_0 = (one - u_0) * (one - u_1) * (one - u_2); - FF l_1 = ( u_0) * (one - u_1) * (one - u_2); - FF l_2 = (one - u_0) * ( u_1) * (one - u_2); - FF l_3 = ( u_0) * ( u_1) * (one - u_2); - FF l_4 = (one - u_0) * (one - u_1) * ( u_2); - FF l_5 = ( u_0) * (one - u_1) * ( u_2); - FF l_6 = (one - u_0) * ( u_1) * ( u_2); - FF l_7 = ( u_0) * ( u_1) * ( u_2); - // clang-format on - FF hand_computed_value; - for (auto [full_poly, partial_eval_poly] : - zip_view(full_polynomials.get_all(), sumcheck.partially_evaluated_polynomials.get_all())) { - // full_polynomials[0][0] = w_l[0], full_polynomials[1][1] = w_r[1], and so on. - hand_computed_value = l_0 * full_poly[0] + l_1 * full_poly[1] + l_2 * full_poly[2] + l_3 * full_poly[3] + - l_4 * full_poly[4] + l_5 * full_poly[5] + l_6 * full_poly[6] + l_7 * full_poly[7]; - EXPECT_EQ(hand_computed_value, partial_eval_poly[0]); + // We can also check the correctness of the multilinear evaluations produced by Sumcheck by directly evaluating + // the full polynomials at challenge u via the evaluate_mle() function + std::vector u_challenge = { u_0, u_1, u_2 }; + for (auto [full_poly, claimed_eval] : + zip_view(full_polynomials.get_all(), output.claimed_evaluations.get_all())) { + Polynomial poly(full_poly); + auto v_expected = poly.evaluate_mle(u_challenge); + EXPECT_EQ(v_expected, claimed_eval); + } } - // We can also check the correctness of the multilinear evaluations produced by Sumcheck by directly evaluating the - // full polynomials at challenge u via the evaluate_mle() function - std::vector u_challenge = { u_0, u_1, u_2 }; - for (auto [full_poly, claimed_eval] : zip_view(full_polynomials.get_all(), output.claimed_evaluations.get_all())) { - bb::Polynomial poly(full_poly); - auto v_expected = poly.evaluate_mle(u_challenge); - EXPECT_EQ(v_expected, claimed_eval); - } -} + void test_prover() + { + const size_t multivariate_d(2); + const size_t multivariate_n(1 << multivariate_d); -TEST_F(SumcheckTests, Prover) -{ - const size_t multivariate_d(2); - const size_t multivariate_n(1 << multivariate_d); - - // Randomly construct the prover polynomials that are input to Sumcheck. - // Note: ProverPolynomials are defined as spans so the polynomials they point to need to exist in memory. - std::array, NUM_POLYNOMIALS> random_polynomials; - for (auto& poly : random_polynomials) { - poly = random_poly(multivariate_n); - } - auto full_polynomials = construct_ultra_full_polynomials(random_polynomials); + // Randomly construct the prover polynomials that are input to Sumcheck. + // Note: ProverPolynomials are defined as spans so the polynomials they point to need to exist in memory. + std::vector> random_polynomials(NUM_POLYNOMIALS); + for (auto& poly : random_polynomials) { + poly = random_poly(multivariate_n); + } + auto full_polynomials = construct_ultra_full_polynomials(random_polynomials); - auto transcript = Flavor::Transcript::prover_init_empty(); + auto transcript = Flavor::Transcript::prover_init_empty(); - auto sumcheck = SumcheckProver(multivariate_n, transcript); + auto sumcheck = SumcheckProver(multivariate_n, transcript); - RelationSeparator alpha; - for (size_t idx = 0; idx < alpha.size(); idx++) { - alpha[idx] = transcript->template get_challenge("Sumcheck:alpha_" + std::to_string(idx)); - } + RelationSeparator alpha; + for (size_t idx = 0; idx < alpha.size(); idx++) { + alpha[idx] = transcript->template get_challenge("Sumcheck:alpha_" + std::to_string(idx)); + } - std::vector gate_challenges(multivariate_d); - for (size_t idx = 0; idx < gate_challenges.size(); idx++) { - gate_challenges[idx] = transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); - } - auto output = sumcheck.prove(full_polynomials, {}, alpha, gate_challenges); - FF u_0 = output.challenge[0]; - FF u_1 = output.challenge[1]; - std::vector expected_values; - for (auto& polynomial_ptr : full_polynomials.get_all()) { - auto& polynomial = polynomial_ptr; - // using knowledge of inputs here to derive the evaluation - FF expected_lo = polynomial[0] * (FF(1) - u_0) + polynomial[1] * u_0; - expected_lo *= (FF(1) - u_1); - FF expected_hi = polynomial[2] * (FF(1) - u_0) + polynomial[3] * u_0; - expected_hi *= u_1; - expected_values.emplace_back(expected_lo + expected_hi); - } + std::vector gate_challenges(multivariate_d); + for (size_t idx = 0; idx < gate_challenges.size(); idx++) { + gate_challenges[idx] = + transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + } + auto output = sumcheck.prove(full_polynomials, {}, alpha, gate_challenges); + FF u_0 = output.challenge[0]; + FF u_1 = output.challenge[1]; + std::vector expected_values; + for (auto& polynomial_ptr : full_polynomials.get_all()) { + auto& polynomial = polynomial_ptr; + // using knowledge of inputs here to derive the evaluation + FF expected_lo = polynomial[0] * (FF(1) - u_0) + polynomial[1] * u_0; + expected_lo *= (FF(1) - u_1); + FF expected_hi = polynomial[2] * (FF(1) - u_0) + polynomial[3] * u_0; + expected_hi *= u_1; + expected_values.emplace_back(expected_lo + expected_hi); + } - for (auto [eval, expected] : zip_view(output.claimed_evaluations.get_all(), expected_values)) { - eval = expected; + for (auto [eval, expected] : zip_view(output.claimed_evaluations.get_all(), expected_values)) { + eval = expected; + } } -} -// TODO(#225): make the inputs to this test more interesting, e.g. non-trivial permutations -TEST_F(SumcheckTests, ProverAndVerifierSimple) -{ - auto run_test = [](bool expect_verified) { + // TODO(#225): make the inputs to this test more interesting, e.g. non-trivial permutations + void test_prover_verifier_flow() + { const size_t multivariate_d(2); const size_t multivariate_n(1 << multivariate_d); // Construct prover polynomials where each is the zero polynomial. // Note: ProverPolynomials are defined as spans so the polynomials they point to need to exist in memory. - std::array, NUM_POLYNOMIALS> zero_polynomials; + std::vector> zero_polynomials(NUM_POLYNOMIALS); for (auto& poly : zero_polynomials) { poly = bb::Polynomial(multivariate_n); } auto full_polynomials = construct_ultra_full_polynomials(zero_polynomials); // Add some non-trivial values to certain polynomials so that the arithmetic relation will have non-trivial - // contribution. Note: since all other polynomials are set to 0, all other relations are trivially satisfied. + // contribution. Note: since all other polynomials are set to 0, all other relations are trivially + // satisfied. std::array w_l; - if (expect_verified) { - w_l = { 0, 1, 2, 0 }; - } else { - w_l = { 0, 0, 2, 0 }; - } + w_l = { 0, 1, 2, 0 }; std::array w_r = { 0, 1, 2, 0 }; std::array w_o = { 0, 2, 4, 0 }; std::array w_4 = { 0, 0, 0, 0 }; @@ -218,7 +208,87 @@ TEST_F(SumcheckTests, ProverAndVerifierSimple) .gamma = FF::random_element(), .public_input_delta = FF::one(), }; + auto prover_transcript = Flavor::Transcript::prover_init_empty(); + auto sumcheck_prover = SumcheckProver(multivariate_n, prover_transcript); + + RelationSeparator prover_alpha; + for (size_t idx = 0; idx < prover_alpha.size(); idx++) { + prover_alpha[idx] = prover_transcript->template get_challenge("Sumcheck:alpha_" + std::to_string(idx)); + } + std::vector prover_gate_challenges(multivariate_d); + for (size_t idx = 0; idx < multivariate_d; idx++) { + prover_gate_challenges[idx] = + prover_transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + } + auto output = + sumcheck_prover.prove(full_polynomials, relation_parameters, prover_alpha, prover_gate_challenges); + + auto verifier_transcript = Flavor::Transcript::verifier_init_empty(prover_transcript); + + auto sumcheck_verifier = SumcheckVerifier(multivariate_d, verifier_transcript); + RelationSeparator verifier_alpha; + for (size_t idx = 0; idx < verifier_alpha.size(); idx++) { + verifier_alpha[idx] = + verifier_transcript->template get_challenge("Sumcheck:alpha_" + std::to_string(idx)); + } + std::vector verifier_gate_challenges(multivariate_d); + for (size_t idx = 0; idx < multivariate_d; idx++) { + verifier_gate_challenges[idx] = + verifier_transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + } + auto verifier_output = sumcheck_verifier.verify(relation_parameters, verifier_alpha, verifier_gate_challenges); + + auto verified = verifier_output.verified.value(); + + EXPECT_EQ(verified, true); + }; + + void test_failure_prover_verifier_flow() + { + const size_t multivariate_d(2); + const size_t multivariate_n(1 << multivariate_d); + + // Construct prover polynomials where each is the zero polynomial. + // Note: ProverPolynomials are defined as spans so the polynomials they point to need to exist in memory. + std::vector> zero_polynomials(NUM_POLYNOMIALS); + for (auto& poly : zero_polynomials) { + poly = bb::Polynomial(multivariate_n); + } + auto full_polynomials = construct_ultra_full_polynomials(zero_polynomials); + // Add some non-trivial values to certain polynomials so that the arithmetic relation will have non-trivial + // contribution. Note: since all other polynomials are set to 0, all other relations are trivially + // satisfied. + std::array w_l; + w_l = { 0, 0, 2, 0 }; // this witness value makes the circuit from previous test invalid + std::array w_r = { 0, 1, 2, 0 }; + std::array w_o = { 0, 2, 4, 0 }; + std::array w_4 = { 0, 0, 0, 0 }; + std::array q_m = { 0, 0, 1, 0 }; + std::array q_l = { 0, 1, 0, 0 }; + std::array q_r = { 0, 1, 0, 0 }; + std::array q_o = { 0, -1, -1, 0 }; + std::array q_c = { 0, 0, 0, 0 }; + std::array q_arith = { 0, 1, 1, 0 }; + // Setting all of these to 0 ensures the GrandProductRelation is satisfied + + full_polynomials.w_l = bb::Polynomial(w_l); + full_polynomials.w_r = bb::Polynomial(w_r); + full_polynomials.w_o = bb::Polynomial(w_o); + full_polynomials.w_4 = bb::Polynomial(w_4); + full_polynomials.q_m = bb::Polynomial(q_m); + full_polynomials.q_l = bb::Polynomial(q_l); + full_polynomials.q_r = bb::Polynomial(q_r); + full_polynomials.q_o = bb::Polynomial(q_o); + full_polynomials.q_c = bb::Polynomial(q_c); + full_polynomials.q_arith = bb::Polynomial(q_arith); + + // Set aribitrary random relation parameters + RelationParameters relation_parameters{ + .beta = FF::random_element(), + .gamma = FF::random_element(), + .public_input_delta = FF::one(), + }; auto prover_transcript = Flavor::Transcript::prover_init_empty(); auto sumcheck_prover = SumcheckProver(multivariate_n, prover_transcript); @@ -231,7 +301,8 @@ TEST_F(SumcheckTests, ProverAndVerifierSimple) prover_gate_challenges[idx] = prover_transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); } - auto output = sumcheck_prover.prove(full_polynomials, {}, prover_alpha, prover_gate_challenges); + auto output = + sumcheck_prover.prove(full_polynomials, relation_parameters, prover_alpha, prover_gate_challenges); auto verifier_transcript = Flavor::Transcript::verifier_init_empty(prover_transcript); @@ -250,9 +321,38 @@ TEST_F(SumcheckTests, ProverAndVerifierSimple) auto verified = verifier_output.verified.value(); - EXPECT_EQ(verified, expect_verified); + EXPECT_EQ(verified, false); }; +}; + +// Define the FlavorTypes +using FlavorTypes = testing::Types; - run_test(/* expect_verified=*/true); - run_test(/* expect_verified=*/false); +TYPED_TEST_SUITE(SumcheckTests, FlavorTypes); + +#define SKIP_IF_ZK() \ + if (std::is_same::value) { \ + GTEST_SKIP() << "Skipping test for UltraFlavorWithZK"; \ + } + +TYPED_TEST(SumcheckTests, PolynomialNormalization) +{ + SKIP_IF_ZK(); + this->test_polynomial_normalization(); } +// Test the prover +TYPED_TEST(SumcheckTests, Prover) +{ + this->test_prover(); +} +// Tests the prover-verifier flow +TYPED_TEST(SumcheckTests, ProverAndVerifierSimple) +{ + this->test_prover_verifier_flow(); +} +// This tests is fed an invalid circuit and checks that the verifier would output false. +TYPED_TEST(SumcheckTests, ProverAndVerifierSimpleFailure) +{ + this->test_failure_prover_verifier_flow(); +} +} // namespace diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp index 9abd4a2feb02..da4b98ce43ba 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_output.hpp @@ -1,5 +1,5 @@ #pragma once - +#include "barretenberg/flavor/flavor.hpp" #include #include #include @@ -11,15 +11,34 @@ namespace bb { * =(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 { +template struct SumcheckOutput { using FF = typename Flavor::FF; using ClaimedEvaluations = typename Flavor::AllValues; // \f$ \vec u = (u_0, ..., u_{d-1}) \f$ std::vector challenge; - // Evaluations in \f$ \vec u \f$ of the polynomials used in Sumcheck + // Evaluations at \f$ \vec u \f$ of the polynomials used in Sumcheck ClaimedEvaluations claimed_evaluations; // 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 }; +/** + * @brief A modification of SumcheckOutput required by ZK Flavors where a vector of evaluations of Libra univariates is + * included. + * + * @tparam Flavor + */ +template struct SumcheckOutput>> { + using FF = typename Flavor::FF; + using ClaimedEvaluations = typename Flavor::AllValues; + // \f$ \vec u = (u_0, ..., u_{d-1}) \f$ + std::vector challenge; + // Evaluations at \f$ \vec u \f$ of the polynomials used in Sumcheck + ClaimedEvaluations claimed_evaluations; + // Include ClaimedLibraEvaluations conditioned on FlavorHasZK concept + std::vector claimed_libra_evaluations; + // 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 6b014b663789..14ccd07c72fc 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_round.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck_round.hpp @@ -6,6 +6,7 @@ #include "barretenberg/relations/relation_types.hpp" #include "barretenberg/relations/utils.hpp" #include "barretenberg/stdlib/primitives/bool/bool.hpp" +#include "zk_sumcheck_data.hpp" namespace bb { @@ -59,9 +60,8 @@ template class SumcheckProverRound { * "MAX_PARTIAL_RELATION_LENGTH + 1". */ static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH; - + using SumcheckRoundUnivariate = bb::Univariate; SumcheckTupleOfTuplesOfUnivariates univariate_accumulators; - // Prover constructor SumcheckProverRound(size_t initial_round_size) : round_size(initial_round_size) @@ -87,7 +87,9 @@ template class SumcheckProverRound { 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. - + * In the case when witness polynomials are masked (ZK Flavors), this method has to distinguish between witness and + * non-witness polynomials. The witness univariates obtained from witness multilinears are corrected by a masking + * quadratic term extended to the same length MAX_PARTIAL_RELATION_LENGTH. * Should only be called externally with relation_idx equal to 0. * In practice, #multivariates is either ProverPolynomials or PartiallyEvaluatedMultivariates. * @@ -98,13 +100,33 @@ template class SumcheckProverRound { */ template void extend_edges(ExtendedEdges& extended_edges, - const ProverPolynomialsOrPartiallyEvaluatedMultivariates& multivariates, - size_t edge_idx) + ProverPolynomialsOrPartiallyEvaluatedMultivariates& multivariates, + size_t edge_idx, + std::optional> zk_sumcheck_data = std::nullopt) { - for (auto [extended_edge, multivariate] : zip_view(extended_edges.get_all(), multivariates.get_all())) { - bb::Univariate edge({ multivariate[edge_idx], multivariate[edge_idx + 1] }); - extended_edge = edge.template extend_to(); - } + + if constexpr (!Flavor::HasZK) { + for (auto [extended_edge, multivariate] : zip_view(extended_edges.get_all(), multivariates.get_all())) { + bb::Univariate edge({ multivariate[edge_idx], multivariate[edge_idx + 1] }); + extended_edge = edge.template extend_to(); + } + } else { + // extend edges of witness polynomials and add correcting terms + for (auto [extended_edge, multivariate, masking_univariate] : + zip_view(extended_edges.get_all_witnesses(), + multivariates.get_all_witnesses(), + zk_sumcheck_data.value().masking_terms_evaluations)) { + bb::Univariate edge({ multivariate[edge_idx], multivariate[edge_idx + 1] }); + extended_edge = edge.template extend_to(); + extended_edge += masking_univariate; + }; + // extend edges of public polynomials + for (auto [extended_edge, multivariate] : + zip_view(extended_edges.get_non_witnesses(), multivariates.get_non_witnesses())) { + bb::Univariate edge({ multivariate[edge_idx], multivariate[edge_idx + 1] }); + extended_edge = edge.template extend_to(); + }; + }; } /** @@ -130,11 +152,13 @@ template class SumcheckProverRound { method \ref extend_and_batch_univariates "extend and batch univariates". */ template - bb::Univariate compute_univariate( + SumcheckRoundUnivariate compute_univariate( + const size_t round_idx, ProverPolynomialsOrPartiallyEvaluatedMultivariates& polynomials, const bb::RelationParameters& relation_parameters, const bb::PowPolynomial& pow_polynomial, - const RelationSeparator alpha) + const RelationSeparator alpha, + std::optional> zk_sumcheck_data = std::nullopt) // only submitted when Flavor HasZK { BB_OP_COUNT_TIME(); @@ -162,8 +186,11 @@ template class SumcheckProverRound { size_t end = (thread_idx + 1) * iterations_per_thread; for (size_t edge_idx = start; edge_idx < end; edge_idx += 2) { - extend_edges(extended_edges[thread_idx], polynomials, edge_idx); - + if constexpr (!Flavor::HasZK) { + extend_edges(extended_edges[thread_idx], polynomials, edge_idx); + } else { + extend_edges(extended_edges[thread_idx], polynomials, edge_idx, zk_sumcheck_data); + } // 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, @@ -180,10 +207,19 @@ template class SumcheckProverRound { for (auto& accumulators : thread_univariate_accumulators) { Utils::add_nested_tuples(univariate_accumulators, accumulators); } - + // For ZK Flavors: The evaluations of the round univariates are masked by the evaluations of Libra univariates + if constexpr (Flavor::HasZK) { + auto libra_round_univariate = compute_libra_round_univariate(zk_sumcheck_data.value(), round_idx); + // Batch the univariate contributions from each sub-relation to obtain the round univariate + auto round_univariate = + batch_over_relations(univariate_accumulators, alpha, pow_polynomial); + // Mask the round univariate + return round_univariate + libra_round_univariate; + } // Batch the univariate contributions from each sub-relation to obtain the round univariate - return batch_over_relations>( - univariate_accumulators, alpha, pow_polynomial); + else { + return batch_over_relations(univariate_accumulators, alpha, pow_polynomial); + } } /** @@ -263,6 +299,32 @@ template class SumcheckProverRound { Utils::apply_to_tuple_of_tuples(tuple, extend_and_sum); } + /** + * @brief Compute Libra round univariate expressed given by the formula + \f{align}{ + \texttt{libra_round_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_univariates}_{i}(k) + \texttt{libra_running_sum} + \f}. + * + * @param zk_sumcheck_data + * @param round_idx + */ + static SumcheckRoundUnivariate compute_libra_round_univariate(ZKSumcheckData zk_sumcheck_data, + size_t round_idx) + { + SumcheckRoundUnivariate libra_round_univariate; + // select the i'th column of Libra book-keeping table + auto current_column = zk_sumcheck_data.libra_univariates[round_idx]; + // the evaluation of Libra round univariate at k=0...D are equal to \f$\texttt{libra_univariates}_{i}(k)\f$ + // corrected by the Libra running sum + for (size_t idx = 0; idx < BATCHED_RELATION_PARTIAL_LENGTH; ++idx) { + libra_round_univariate.value_at(idx) = current_column.value_at(idx) + zk_sumcheck_data.libra_running_sum; + }; + return libra_round_univariate; + } + private: /** * @brief In Round \f$ i \f$, for a given point \f$ \vec \ell \in \{0,1\}^{d-1 - i}\f$, calculate the contribution @@ -295,7 +357,6 @@ template class SumcheckProverRound { const FF& scaling_factor) { using Relation = std::tuple_element_t; - // Check if the relation is skippable to speed up accumulation if constexpr (!isSkippable) { // If not, accumulate normally @@ -310,7 +371,6 @@ template class SumcheckProverRound { scaling_factor); } } - // Repeat for the next relation. if constexpr (relation_idx + 1 < NUM_RELATIONS) { accumulate_relation_univariates( @@ -340,6 +400,7 @@ template class SumcheckVerifierRound { public: using FF = typename Flavor::FF; using ClaimedEvaluations = typename Flavor::AllValues; + using ClaimedLibraEvaluations = typename std::vector; bool round_failed = false; /** @@ -352,6 +413,7 @@ template class SumcheckVerifierRound { * MAX_PARTIAL_RELATION_LENGTH "MAX_PARTIAL_RELATION_LENGTH + 1". */ static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH; + using SumcheckRoundUnivariate = bb::Univariate; FF target_total_sum = 0; @@ -370,7 +432,7 @@ template class SumcheckVerifierRound { * @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) + bool check_sum(SumcheckRoundUnivariate& univariate) { FF total_sum = univariate.value_at(0) + univariate.value_at(1); // TODO(#673): Conditionals like this can go away once native verification is is just recursive verification @@ -437,7 +499,7 @@ template class SumcheckVerifierRound { * @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) + FF compute_next_target_sum(SumcheckRoundUnivariate& univariate, FF& round_challenge) { // Evaluate \f$\tilde{S}^{i}(u_{i}) \f$ target_total_sum = univariate.evaluate(round_challenge); @@ -473,7 +535,8 @@ template class SumcheckVerifierRound { FF compute_full_honk_relation_purported_value(ClaimedEvaluations purported_evaluations, const bb::RelationParameters& relation_parameters, const bb::PowPolynomial& pow_polynomial, - const RelationSeparator alpha) + const RelationSeparator alpha, + std::optional full_libra_purported_value = std::nullopt) { // The verifier should never skip computation of contributions from any relation Utils::template accumulate_relation_evaluations_without_skipping<>( @@ -482,6 +545,9 @@ template class SumcheckVerifierRound { FF running_challenge{ 1 }; FF output{ 0 }; Utils::scale_and_batch_elements(relation_evaluations, alpha, running_challenge, output); + if constexpr (Flavor::HasZK) { + output += full_libra_purported_value.value(); + }; return output; } }; diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/zk_sumcheck_data.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/zk_sumcheck_data.hpp new file mode 100644 index 000000000000..f438ab379162 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/sumcheck/zk_sumcheck_data.hpp @@ -0,0 +1,53 @@ +#pragma once + +#include +#include +#include + +namespace bb { + +/** + * @brief This structure is created to contain various polynomials and constants required by ZK Sumcheck. + * + */ +template struct ZKSumcheckData { + using FF = typename Flavor::FF; + /** + * @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; + // The number of all witnesses including shifts and derived witnesses from flavors that have ZK, + // otherwise, set this constant to 0. + /** + * @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; + // Initialize the length of the array of evaluation masking scalars as 0 for non-ZK Flavors and as + // NUM_ALL_WITNESS_ENTITIES for ZK FLavors + static constexpr size_t MASKING_SCALARS_LENGTH = Flavor::HasZK ? Flavor::NUM_ALL_WITNESS_ENTITIES : 0; + // Array of random scalars used to hide the witness info from leaking through the claimed evaluations + using EvalMaskingScalars = std::array; + // Auxiliary table that represents the evaluations of quadratic polynomials r_j * X(1-X) at 0,..., + // MAX_PARTIAL_RELATION_LENGTH - 1 + using EvaluationMaskingTable = std::array, MASKING_SCALARS_LENGTH>; + // The size of the LibraUnivariates. We ensure that they do not take extra space when Flavor runs non-ZK + // Sumcheck. + static constexpr size_t LIBRA_UNIVARIATES_LENGTH = Flavor::HasZK ? Flavor::BATCHED_RELATION_PARTIAL_LENGTH : 0; + // Container for the Libra Univariates. Their number depends on the size of the circuit. + using LibraUnivariates = std::vector>; + // Container for the evaluations of Libra Univariates that have to be proven. + using ClaimedLibraEvaluations = std::vector; + + EvalMaskingScalars eval_masking_scalars; + EvaluationMaskingTable masking_terms_evaluations; + LibraUnivariates libra_univariates; + FF libra_scaling_factor{ 1 }; + FF libra_challenge; + FF libra_running_sum; + ClaimedLibraEvaluations libra_evaluations; +}; + +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/generated/circuit_builder.cpp b/barretenberg/cpp/src/barretenberg/vm/avm/generated/circuit_builder.cpp index 5ddd018b6d69..7db313939c46 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/generated/circuit_builder.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/generated/circuit_builder.cpp @@ -40,10 +40,10 @@ AvmCircuitBuilder::ProverPolynomials AvmCircuitBuilder::compute_polynomials() co polys.main_sel_first[i] = rows[i].main_sel_first; polys.main_zeroes[i] = rows[i].main_zeroes; polys.powers_power_of_2[i] = rows[i].powers_power_of_2; - polys.kernel_kernel_inputs[i] = rows[i].kernel_kernel_inputs; - polys.kernel_kernel_value_out[i] = rows[i].kernel_kernel_value_out; - polys.kernel_kernel_side_effect_out[i] = rows[i].kernel_kernel_side_effect_out; - polys.kernel_kernel_metadata_out[i] = rows[i].kernel_kernel_metadata_out; + polys.main_kernel_inputs[i] = rows[i].main_kernel_inputs; + polys.main_kernel_value_out[i] = rows[i].main_kernel_value_out; + polys.main_kernel_side_effect_out[i] = rows[i].main_kernel_side_effect_out; + polys.main_kernel_metadata_out[i] = rows[i].main_kernel_metadata_out; polys.main_calldata[i] = rows[i].main_calldata; polys.main_returndata[i] = rows[i].main_returndata; polys.alu_a_hi[i] = rows[i].alu_a_hi; @@ -151,21 +151,6 @@ AvmCircuitBuilder::ProverPolynomials AvmCircuitBuilder::compute_polynomials() co polys.keccakf1600_input[i] = rows[i].keccakf1600_input; polys.keccakf1600_output[i] = rows[i].keccakf1600_output; polys.keccakf1600_sel_keccakf1600[i] = rows[i].keccakf1600_sel_keccakf1600; - polys.kernel_emit_l2_to_l1_msg_write_offset[i] = rows[i].kernel_emit_l2_to_l1_msg_write_offset; - polys.kernel_emit_note_hash_write_offset[i] = rows[i].kernel_emit_note_hash_write_offset; - polys.kernel_emit_nullifier_write_offset[i] = rows[i].kernel_emit_nullifier_write_offset; - polys.kernel_emit_unencrypted_log_write_offset[i] = rows[i].kernel_emit_unencrypted_log_write_offset; - polys.kernel_kernel_in_offset[i] = rows[i].kernel_kernel_in_offset; - polys.kernel_kernel_out_offset[i] = rows[i].kernel_kernel_out_offset; - polys.kernel_l1_to_l2_msg_exists_write_offset[i] = rows[i].kernel_l1_to_l2_msg_exists_write_offset; - polys.kernel_note_hash_exist_write_offset[i] = rows[i].kernel_note_hash_exist_write_offset; - polys.kernel_nullifier_exists_write_offset[i] = rows[i].kernel_nullifier_exists_write_offset; - polys.kernel_nullifier_non_exists_write_offset[i] = rows[i].kernel_nullifier_non_exists_write_offset; - polys.kernel_q_public_input_kernel_add_to_table[i] = rows[i].kernel_q_public_input_kernel_add_to_table; - polys.kernel_q_public_input_kernel_out_add_to_table[i] = rows[i].kernel_q_public_input_kernel_out_add_to_table; - polys.kernel_side_effect_counter[i] = rows[i].kernel_side_effect_counter; - polys.kernel_sload_write_offset[i] = rows[i].kernel_sload_write_offset; - polys.kernel_sstore_write_offset[i] = rows[i].kernel_sstore_write_offset; polys.main_abs_da_rem_gas_hi[i] = rows[i].main_abs_da_rem_gas_hi; polys.main_abs_da_rem_gas_lo[i] = rows[i].main_abs_da_rem_gas_lo; polys.main_abs_l2_rem_gas_hi[i] = rows[i].main_abs_l2_rem_gas_hi; @@ -180,6 +165,10 @@ AvmCircuitBuilder::ProverPolynomials AvmCircuitBuilder::compute_polynomials() co polys.main_dyn_da_gas_op_cost[i] = rows[i].main_dyn_da_gas_op_cost; polys.main_dyn_gas_multiplier[i] = rows[i].main_dyn_gas_multiplier; polys.main_dyn_l2_gas_op_cost[i] = rows[i].main_dyn_l2_gas_op_cost; + polys.main_emit_l2_to_l1_msg_write_offset[i] = rows[i].main_emit_l2_to_l1_msg_write_offset; + polys.main_emit_note_hash_write_offset[i] = rows[i].main_emit_note_hash_write_offset; + polys.main_emit_nullifier_write_offset[i] = rows[i].main_emit_nullifier_write_offset; + polys.main_emit_unencrypted_log_write_offset[i] = rows[i].main_emit_unencrypted_log_write_offset; polys.main_ia[i] = rows[i].main_ia; polys.main_ib[i] = rows[i].main_ib; polys.main_ic[i] = rows[i].main_ic; @@ -191,12 +180,18 @@ AvmCircuitBuilder::ProverPolynomials AvmCircuitBuilder::compute_polynomials() co polys.main_ind_addr_d[i] = rows[i].main_ind_addr_d; polys.main_internal_return_ptr[i] = rows[i].main_internal_return_ptr; polys.main_inv[i] = rows[i].main_inv; + polys.main_kernel_in_offset[i] = rows[i].main_kernel_in_offset; + polys.main_kernel_out_offset[i] = rows[i].main_kernel_out_offset; + polys.main_l1_to_l2_msg_exists_write_offset[i] = rows[i].main_l1_to_l2_msg_exists_write_offset; polys.main_l2_gas_remaining[i] = rows[i].main_l2_gas_remaining; polys.main_l2_out_of_gas[i] = rows[i].main_l2_out_of_gas; polys.main_mem_addr_a[i] = rows[i].main_mem_addr_a; polys.main_mem_addr_b[i] = rows[i].main_mem_addr_b; polys.main_mem_addr_c[i] = rows[i].main_mem_addr_c; polys.main_mem_addr_d[i] = rows[i].main_mem_addr_d; + polys.main_note_hash_exist_write_offset[i] = rows[i].main_note_hash_exist_write_offset; + polys.main_nullifier_exists_write_offset[i] = rows[i].main_nullifier_exists_write_offset; + polys.main_nullifier_non_exists_write_offset[i] = rows[i].main_nullifier_non_exists_write_offset; polys.main_op_err[i] = rows[i].main_op_err; polys.main_opcode_val[i] = rows[i].main_opcode_val; polys.main_pc[i] = rows[i].main_pc; @@ -209,6 +204,8 @@ AvmCircuitBuilder::ProverPolynomials AvmCircuitBuilder::compute_polynomials() co polys.main_sel_bin[i] = rows[i].main_sel_bin; polys.main_sel_calldata[i] = rows[i].main_sel_calldata; polys.main_sel_execution_row[i] = rows[i].main_sel_execution_row; + polys.main_sel_kernel_inputs[i] = rows[i].main_sel_kernel_inputs; + polys.main_sel_kernel_out[i] = rows[i].main_sel_kernel_out; polys.main_sel_last[i] = rows[i].main_sel_last; polys.main_sel_mem_op_a[i] = rows[i].main_sel_mem_op_a; polys.main_sel_mem_op_b[i] = rows[i].main_sel_mem_op_b; @@ -284,7 +281,10 @@ AvmCircuitBuilder::ProverPolynomials AvmCircuitBuilder::compute_polynomials() co polys.main_sel_rng_16[i] = rows[i].main_sel_rng_16; polys.main_sel_rng_8[i] = rows[i].main_sel_rng_8; polys.main_sel_slice_gadget[i] = rows[i].main_sel_slice_gadget; + polys.main_side_effect_counter[i] = rows[i].main_side_effect_counter; + polys.main_sload_write_offset[i] = rows[i].main_sload_write_offset; polys.main_space_id[i] = rows[i].main_space_id; + polys.main_sstore_write_offset[i] = rows[i].main_sstore_write_offset; polys.main_tag_err[i] = rows[i].main_tag_err; polys.main_w_in_tag[i] = rows[i].main_w_in_tag; polys.mem_addr[i] = rows[i].mem_addr; @@ -634,10 +634,10 @@ AvmCircuitBuilder::ProverPolynomials AvmCircuitBuilder::compute_polynomials() co polys.range_check_l2_gas_lo_counts[i] = rows[i].range_check_l2_gas_lo_counts; polys.range_check_da_gas_hi_counts[i] = rows[i].range_check_da_gas_hi_counts; polys.range_check_da_gas_lo_counts[i] = rows[i].range_check_da_gas_lo_counts; - polys.lookup_cd_value_counts[i] = rows[i].lookup_cd_value_counts; - polys.lookup_ret_value_counts[i] = rows[i].lookup_ret_value_counts; polys.kernel_output_lookup_counts[i] = rows[i].kernel_output_lookup_counts; polys.lookup_into_kernel_counts[i] = rows[i].lookup_into_kernel_counts; + polys.lookup_cd_value_counts[i] = rows[i].lookup_cd_value_counts; + polys.lookup_ret_value_counts[i] = rows[i].lookup_ret_value_counts; polys.incl_main_tag_err_counts[i] = rows[i].incl_main_tag_err_counts; polys.incl_mem_tag_err_counts[i] = rows[i].incl_mem_tag_err_counts; polys.lookup_mem_rng_chk_lo_counts[i] = rows[i].lookup_mem_rng_chk_lo_counts; @@ -710,16 +710,20 @@ bool AvmCircuitBuilder::check_circuit() const r = 0; } + std::array subrelation_failed = { false }; for (size_t r = 0; r < num_rows; ++r) { Relation::accumulate(result, polys.get_row(r), {}, 1); for (size_t j = 0; j < result.size(); ++j) { - if (result[j] != 0) { + if (!subrelation_failed[j] && result[j] != 0) { signal_error(format("Relation ", Relation::NAME, ", subrelation ", Relation::get_subrelation_label(j), " failed at row ", r)); + // We will not check this subrelation for any other rows. + // Since the accumulation will keep being != 0. + subrelation_failed[j] = true; } } } diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/generated/flavor.cpp b/barretenberg/cpp/src/barretenberg/vm/avm/generated/flavor.cpp index da053ff63384..9cf8f248f46b 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/generated/flavor.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/generated/flavor.cpp @@ -21,10 +21,10 @@ AvmFlavor::AllConstRefValues::AllConstRefValues( , main_sel_first(il[13]) , main_zeroes(il[14]) , powers_power_of_2(il[15]) - , kernel_kernel_inputs(il[16]) - , kernel_kernel_value_out(il[17]) - , kernel_kernel_side_effect_out(il[18]) - , kernel_kernel_metadata_out(il[19]) + , main_kernel_inputs(il[16]) + , main_kernel_value_out(il[17]) + , main_kernel_side_effect_out(il[18]) + , main_kernel_metadata_out(il[19]) , main_calldata(il[20]) , main_returndata(il[21]) , alu_a_hi(il[22]) @@ -132,140 +132,140 @@ AvmFlavor::AllConstRefValues::AllConstRefValues( , keccakf1600_input(il[124]) , keccakf1600_output(il[125]) , keccakf1600_sel_keccakf1600(il[126]) - , kernel_emit_l2_to_l1_msg_write_offset(il[127]) - , kernel_emit_note_hash_write_offset(il[128]) - , kernel_emit_nullifier_write_offset(il[129]) - , kernel_emit_unencrypted_log_write_offset(il[130]) - , kernel_kernel_in_offset(il[131]) - , kernel_kernel_out_offset(il[132]) - , kernel_l1_to_l2_msg_exists_write_offset(il[133]) - , kernel_note_hash_exist_write_offset(il[134]) - , kernel_nullifier_exists_write_offset(il[135]) - , kernel_nullifier_non_exists_write_offset(il[136]) - , kernel_q_public_input_kernel_add_to_table(il[137]) - , kernel_q_public_input_kernel_out_add_to_table(il[138]) - , kernel_side_effect_counter(il[139]) - , kernel_sload_write_offset(il[140]) - , kernel_sstore_write_offset(il[141]) - , main_abs_da_rem_gas_hi(il[142]) - , main_abs_da_rem_gas_lo(il[143]) - , main_abs_l2_rem_gas_hi(il[144]) - , main_abs_l2_rem_gas_lo(il[145]) - , main_alu_in_tag(il[146]) - , main_base_da_gas_op_cost(il[147]) - , main_base_l2_gas_op_cost(il[148]) - , main_bin_op_id(il[149]) - , main_call_ptr(il[150]) - , main_da_gas_remaining(il[151]) - , main_da_out_of_gas(il[152]) - , main_dyn_da_gas_op_cost(il[153]) - , main_dyn_gas_multiplier(il[154]) - , main_dyn_l2_gas_op_cost(il[155]) - , main_ia(il[156]) - , main_ib(il[157]) - , main_ic(il[158]) - , main_id(il[159]) - , main_id_zero(il[160]) - , main_ind_addr_a(il[161]) - , main_ind_addr_b(il[162]) - , main_ind_addr_c(il[163]) - , main_ind_addr_d(il[164]) - , main_internal_return_ptr(il[165]) - , main_inv(il[166]) - , main_l2_gas_remaining(il[167]) - , main_l2_out_of_gas(il[168]) - , main_mem_addr_a(il[169]) - , main_mem_addr_b(il[170]) - , main_mem_addr_c(il[171]) - , main_mem_addr_d(il[172]) - , main_op_err(il[173]) - , main_opcode_val(il[174]) - , main_pc(il[175]) - , main_r_in_tag(il[176]) - , main_rwa(il[177]) - , main_rwb(il[178]) - , main_rwc(il[179]) - , main_rwd(il[180]) - , main_sel_alu(il[181]) - , main_sel_bin(il[182]) - , main_sel_calldata(il[183]) - , main_sel_execution_row(il[184]) - , main_sel_last(il[185]) - , main_sel_mem_op_a(il[186]) - , main_sel_mem_op_b(il[187]) - , main_sel_mem_op_c(il[188]) - , main_sel_mem_op_d(il[189]) - , main_sel_mov_ia_to_ic(il[190]) - , main_sel_mov_ib_to_ic(il[191]) - , main_sel_op_add(il[192]) - , main_sel_op_address(il[193]) - , main_sel_op_and(il[194]) - , main_sel_op_block_number(il[195]) - , main_sel_op_calldata_copy(il[196]) - , main_sel_op_cast(il[197]) - , main_sel_op_chain_id(il[198]) - , main_sel_op_cmov(il[199]) - , main_sel_op_coinbase(il[200]) - , main_sel_op_dagasleft(il[201]) - , main_sel_op_div(il[202]) - , main_sel_op_ecadd(il[203]) - , main_sel_op_emit_l2_to_l1_msg(il[204]) - , main_sel_op_emit_note_hash(il[205]) - , main_sel_op_emit_nullifier(il[206]) - , main_sel_op_emit_unencrypted_log(il[207]) - , main_sel_op_eq(il[208]) - , main_sel_op_external_call(il[209]) - , main_sel_op_external_return(il[210]) - , main_sel_op_external_revert(il[211]) - , main_sel_op_fdiv(il[212]) - , main_sel_op_fee_per_da_gas(il[213]) - , main_sel_op_fee_per_l2_gas(il[214]) - , main_sel_op_function_selector(il[215]) - , main_sel_op_get_contract_instance(il[216]) - , main_sel_op_internal_call(il[217]) - , main_sel_op_internal_return(il[218]) - , main_sel_op_jump(il[219]) - , main_sel_op_jumpi(il[220]) - , main_sel_op_keccak(il[221]) - , main_sel_op_l1_to_l2_msg_exists(il[222]) - , main_sel_op_l2gasleft(il[223]) - , main_sel_op_lt(il[224]) - , main_sel_op_lte(il[225]) - , main_sel_op_mov(il[226]) - , main_sel_op_msm(il[227]) - , main_sel_op_mul(il[228]) - , main_sel_op_not(il[229]) - , main_sel_op_note_hash_exists(il[230]) - , main_sel_op_nullifier_exists(il[231]) - , main_sel_op_or(il[232]) - , main_sel_op_pedersen(il[233]) - , main_sel_op_pedersen_commit(il[234]) - , main_sel_op_poseidon2(il[235]) - , main_sel_op_radix_le(il[236]) - , main_sel_op_sender(il[237]) - , main_sel_op_set(il[238]) - , main_sel_op_sha256(il[239]) - , main_sel_op_shl(il[240]) - , main_sel_op_shr(il[241]) - , main_sel_op_sload(il[242]) - , main_sel_op_sstore(il[243]) - , main_sel_op_storage_address(il[244]) - , main_sel_op_sub(il[245]) - , main_sel_op_timestamp(il[246]) - , main_sel_op_transaction_fee(il[247]) - , main_sel_op_version(il[248]) - , main_sel_op_xor(il[249]) - , main_sel_q_kernel_lookup(il[250]) - , main_sel_q_kernel_output_lookup(il[251]) - , main_sel_resolve_ind_addr_a(il[252]) - , main_sel_resolve_ind_addr_b(il[253]) - , main_sel_resolve_ind_addr_c(il[254]) - , main_sel_resolve_ind_addr_d(il[255]) - , main_sel_returndata(il[256]) - , main_sel_rng_16(il[257]) - , main_sel_rng_8(il[258]) - , main_sel_slice_gadget(il[259]) - , main_space_id(il[260]) + , main_abs_da_rem_gas_hi(il[127]) + , main_abs_da_rem_gas_lo(il[128]) + , main_abs_l2_rem_gas_hi(il[129]) + , main_abs_l2_rem_gas_lo(il[130]) + , main_alu_in_tag(il[131]) + , main_base_da_gas_op_cost(il[132]) + , main_base_l2_gas_op_cost(il[133]) + , main_bin_op_id(il[134]) + , main_call_ptr(il[135]) + , main_da_gas_remaining(il[136]) + , main_da_out_of_gas(il[137]) + , main_dyn_da_gas_op_cost(il[138]) + , main_dyn_gas_multiplier(il[139]) + , main_dyn_l2_gas_op_cost(il[140]) + , main_emit_l2_to_l1_msg_write_offset(il[141]) + , main_emit_note_hash_write_offset(il[142]) + , main_emit_nullifier_write_offset(il[143]) + , main_emit_unencrypted_log_write_offset(il[144]) + , main_ia(il[145]) + , main_ib(il[146]) + , main_ic(il[147]) + , main_id(il[148]) + , main_id_zero(il[149]) + , main_ind_addr_a(il[150]) + , main_ind_addr_b(il[151]) + , main_ind_addr_c(il[152]) + , main_ind_addr_d(il[153]) + , main_internal_return_ptr(il[154]) + , main_inv(il[155]) + , main_kernel_in_offset(il[156]) + , main_kernel_out_offset(il[157]) + , main_l1_to_l2_msg_exists_write_offset(il[158]) + , main_l2_gas_remaining(il[159]) + , main_l2_out_of_gas(il[160]) + , main_mem_addr_a(il[161]) + , main_mem_addr_b(il[162]) + , main_mem_addr_c(il[163]) + , main_mem_addr_d(il[164]) + , main_note_hash_exist_write_offset(il[165]) + , main_nullifier_exists_write_offset(il[166]) + , main_nullifier_non_exists_write_offset(il[167]) + , main_op_err(il[168]) + , main_opcode_val(il[169]) + , main_pc(il[170]) + , main_r_in_tag(il[171]) + , main_rwa(il[172]) + , main_rwb(il[173]) + , main_rwc(il[174]) + , main_rwd(il[175]) + , main_sel_alu(il[176]) + , main_sel_bin(il[177]) + , main_sel_calldata(il[178]) + , main_sel_execution_row(il[179]) + , main_sel_kernel_inputs(il[180]) + , main_sel_kernel_out(il[181]) + , main_sel_last(il[182]) + , main_sel_mem_op_a(il[183]) + , main_sel_mem_op_b(il[184]) + , main_sel_mem_op_c(il[185]) + , main_sel_mem_op_d(il[186]) + , main_sel_mov_ia_to_ic(il[187]) + , main_sel_mov_ib_to_ic(il[188]) + , main_sel_op_add(il[189]) + , main_sel_op_address(il[190]) + , main_sel_op_and(il[191]) + , main_sel_op_block_number(il[192]) + , main_sel_op_calldata_copy(il[193]) + , main_sel_op_cast(il[194]) + , main_sel_op_chain_id(il[195]) + , main_sel_op_cmov(il[196]) + , main_sel_op_coinbase(il[197]) + , main_sel_op_dagasleft(il[198]) + , main_sel_op_div(il[199]) + , main_sel_op_ecadd(il[200]) + , main_sel_op_emit_l2_to_l1_msg(il[201]) + , main_sel_op_emit_note_hash(il[202]) + , main_sel_op_emit_nullifier(il[203]) + , main_sel_op_emit_unencrypted_log(il[204]) + , main_sel_op_eq(il[205]) + , main_sel_op_external_call(il[206]) + , main_sel_op_external_return(il[207]) + , main_sel_op_external_revert(il[208]) + , main_sel_op_fdiv(il[209]) + , main_sel_op_fee_per_da_gas(il[210]) + , main_sel_op_fee_per_l2_gas(il[211]) + , main_sel_op_function_selector(il[212]) + , main_sel_op_get_contract_instance(il[213]) + , main_sel_op_internal_call(il[214]) + , main_sel_op_internal_return(il[215]) + , main_sel_op_jump(il[216]) + , main_sel_op_jumpi(il[217]) + , main_sel_op_keccak(il[218]) + , main_sel_op_l1_to_l2_msg_exists(il[219]) + , main_sel_op_l2gasleft(il[220]) + , main_sel_op_lt(il[221]) + , main_sel_op_lte(il[222]) + , main_sel_op_mov(il[223]) + , main_sel_op_msm(il[224]) + , main_sel_op_mul(il[225]) + , main_sel_op_not(il[226]) + , main_sel_op_note_hash_exists(il[227]) + , main_sel_op_nullifier_exists(il[228]) + , main_sel_op_or(il[229]) + , main_sel_op_pedersen(il[230]) + , main_sel_op_pedersen_commit(il[231]) + , main_sel_op_poseidon2(il[232]) + , main_sel_op_radix_le(il[233]) + , main_sel_op_sender(il[234]) + , main_sel_op_set(il[235]) + , main_sel_op_sha256(il[236]) + , main_sel_op_shl(il[237]) + , main_sel_op_shr(il[238]) + , main_sel_op_sload(il[239]) + , main_sel_op_sstore(il[240]) + , main_sel_op_storage_address(il[241]) + , main_sel_op_sub(il[242]) + , main_sel_op_timestamp(il[243]) + , main_sel_op_transaction_fee(il[244]) + , main_sel_op_version(il[245]) + , main_sel_op_xor(il[246]) + , main_sel_q_kernel_lookup(il[247]) + , main_sel_q_kernel_output_lookup(il[248]) + , main_sel_resolve_ind_addr_a(il[249]) + , main_sel_resolve_ind_addr_b(il[250]) + , main_sel_resolve_ind_addr_c(il[251]) + , main_sel_resolve_ind_addr_d(il[252]) + , main_sel_returndata(il[253]) + , main_sel_rng_16(il[254]) + , main_sel_rng_8(il[255]) + , main_sel_slice_gadget(il[256]) + , main_side_effect_counter(il[257]) + , main_sload_write_offset(il[258]) + , main_space_id(il[259]) + , main_sstore_write_offset(il[260]) , main_tag_err(il[261]) , main_w_in_tag(il[262]) , mem_addr(il[263]) @@ -615,10 +615,10 @@ AvmFlavor::AllConstRefValues::AllConstRefValues( , range_check_l2_gas_lo_counts(il[607]) , range_check_da_gas_hi_counts(il[608]) , range_check_da_gas_lo_counts(il[609]) - , lookup_cd_value_counts(il[610]) - , lookup_ret_value_counts(il[611]) - , kernel_output_lookup_counts(il[612]) - , lookup_into_kernel_counts(il[613]) + , kernel_output_lookup_counts(il[610]) + , lookup_into_kernel_counts(il[611]) + , lookup_cd_value_counts(il[612]) + , lookup_ret_value_counts(il[613]) , incl_main_tag_err_counts(il[614]) , incl_mem_tag_err_counts(il[615]) , lookup_mem_rng_chk_lo_counts(il[616]) @@ -681,10 +681,10 @@ AvmFlavor::AllConstRefValues::AllConstRefValues( , range_check_l2_gas_lo_inv(il[673]) , range_check_da_gas_hi_inv(il[674]) , range_check_da_gas_lo_inv(il[675]) - , lookup_cd_value_inv(il[676]) - , lookup_ret_value_inv(il[677]) - , kernel_output_lookup_inv(il[678]) - , lookup_into_kernel_inv(il[679]) + , kernel_output_lookup_inv(il[676]) + , lookup_into_kernel_inv(il[677]) + , lookup_cd_value_inv(il[678]) + , lookup_ret_value_inv(il[679]) , incl_main_tag_err_inv(il[680]) , incl_mem_tag_err_inv(il[681]) , lookup_mem_rng_chk_lo_inv(il[682]) @@ -717,81 +717,81 @@ AvmFlavor::AllConstRefValues::AllConstRefValues( , lookup_div_u16_5_inv(il[709]) , lookup_div_u16_6_inv(il[710]) , lookup_div_u16_7_inv(il[711]) - , alu_div_u16_r1_shift(il[712]) - , slice_clk_shift(il[713]) - , alu_div_u16_r6_shift(il[714]) - , kernel_nullifier_exists_write_offset_shift(il[715]) - , mem_tsp_shift(il[716]) - , main_internal_return_ptr_shift(il[717]) - , main_sel_execution_row_shift(il[718]) - , alu_sel_rng_chk_shift(il[719]) + , alu_a_hi_shift(il[712]) + , alu_a_lo_shift(il[713]) + , alu_b_hi_shift(il[714]) + , alu_b_lo_shift(il[715]) + , alu_cmp_rng_ctr_shift(il[716]) + , alu_div_u16_r0_shift(il[717]) + , alu_div_u16_r1_shift(il[718]) + , alu_div_u16_r2_shift(il[719]) , alu_div_u16_r3_shift(il[720]) - , kernel_emit_note_hash_write_offset_shift(il[721]) - , alu_p_sub_b_hi_shift(il[722]) - , slice_sel_return_shift(il[723]) - , kernel_side_effect_counter_shift(il[724]) + , alu_div_u16_r4_shift(il[721]) + , alu_div_u16_r5_shift(il[722]) + , alu_div_u16_r6_shift(il[723]) + , alu_div_u16_r7_shift(il[724]) , alu_op_add_shift(il[725]) , alu_op_cast_shift(il[726]) - , kernel_emit_nullifier_write_offset_shift(il[727]) - , slice_cnt_shift(il[728]) - , alu_sel_cmp_shift(il[729]) - , alu_u16_r1_shift(il[730]) - , binary_acc_ia_shift(il[731]) - , alu_div_u16_r0_shift(il[732]) - , kernel_l1_to_l2_msg_exists_write_offset_shift(il[733]) - , alu_a_hi_shift(il[734]) - , alu_div_u16_r5_shift(il[735]) - , kernel_emit_unencrypted_log_write_offset_shift(il[736]) - , mem_val_shift(il[737]) - , slice_sel_start_shift(il[738]) - , binary_acc_ic_shift(il[739]) - , alu_sel_div_rng_chk_shift(il[740]) - , alu_u16_r6_shift(il[741]) - , alu_op_shr_shift(il[742]) - , slice_space_id_shift(il[743]) - , mem_tag_shift(il[744]) - , alu_op_mul_shift(il[745]) - , binary_mem_tag_ctr_shift(il[746]) - , kernel_emit_l2_to_l1_msg_write_offset_shift(il[747]) - , alu_sel_alu_shift(il[748]) - , mem_rw_shift(il[749]) - , mem_glob_addr_shift(il[750]) - , alu_u16_r3_shift(il[751]) - , kernel_sstore_write_offset_shift(il[752]) - , mem_sel_mem_shift(il[753]) - , slice_sel_mem_active_shift(il[754]) - , alu_op_shl_shift(il[755]) - , alu_b_hi_shift(il[756]) - , alu_cmp_rng_ctr_shift(il[757]) - , alu_op_cast_prev_shift(il[758]) - , alu_sel_rng_chk_lookup_shift(il[759]) - , slice_sel_cd_cpy_shift(il[760]) - , main_pc_shift(il[761]) - , alu_u8_r1_shift(il[762]) - , alu_p_sub_a_lo_shift(il[763]) - , main_da_gas_remaining_shift(il[764]) - , alu_b_lo_shift(il[765]) - , alu_u8_r0_shift(il[766]) - , alu_p_sub_b_lo_shift(il[767]) - , kernel_nullifier_non_exists_write_offset_shift(il[768]) - , alu_u16_r4_shift(il[769]) - , binary_acc_ib_shift(il[770]) - , alu_u16_r0_shift(il[771]) - , alu_div_u16_r2_shift(il[772]) - , alu_op_div_shift(il[773]) - , alu_a_lo_shift(il[774]) - , alu_op_sub_shift(il[775]) - , alu_div_u16_r7_shift(il[776]) - , alu_u16_r5_shift(il[777]) - , alu_u16_r2_shift(il[778]) - , kernel_note_hash_exist_write_offset_shift(il[779]) - , main_l2_gas_remaining_shift(il[780]) - , kernel_sload_write_offset_shift(il[781]) - , slice_addr_shift(il[782]) - , binary_op_id_shift(il[783]) - , alu_p_sub_a_hi_shift(il[784]) - , slice_col_offset_shift(il[785]) - , alu_div_u16_r4_shift(il[786]) + , alu_op_cast_prev_shift(il[727]) + , alu_op_div_shift(il[728]) + , alu_op_mul_shift(il[729]) + , alu_op_shl_shift(il[730]) + , alu_op_shr_shift(il[731]) + , alu_op_sub_shift(il[732]) + , alu_p_sub_a_hi_shift(il[733]) + , alu_p_sub_a_lo_shift(il[734]) + , alu_p_sub_b_hi_shift(il[735]) + , alu_p_sub_b_lo_shift(il[736]) + , alu_sel_alu_shift(il[737]) + , alu_sel_cmp_shift(il[738]) + , alu_sel_div_rng_chk_shift(il[739]) + , alu_sel_rng_chk_shift(il[740]) + , alu_sel_rng_chk_lookup_shift(il[741]) + , alu_u16_r0_shift(il[742]) + , alu_u16_r1_shift(il[743]) + , alu_u16_r2_shift(il[744]) + , alu_u16_r3_shift(il[745]) + , alu_u16_r4_shift(il[746]) + , alu_u16_r5_shift(il[747]) + , alu_u16_r6_shift(il[748]) + , alu_u8_r0_shift(il[749]) + , alu_u8_r1_shift(il[750]) + , binary_acc_ia_shift(il[751]) + , binary_acc_ib_shift(il[752]) + , binary_acc_ic_shift(il[753]) + , binary_mem_tag_ctr_shift(il[754]) + , binary_op_id_shift(il[755]) + , main_da_gas_remaining_shift(il[756]) + , main_emit_l2_to_l1_msg_write_offset_shift(il[757]) + , main_emit_note_hash_write_offset_shift(il[758]) + , main_emit_nullifier_write_offset_shift(il[759]) + , main_emit_unencrypted_log_write_offset_shift(il[760]) + , main_internal_return_ptr_shift(il[761]) + , main_l1_to_l2_msg_exists_write_offset_shift(il[762]) + , main_l2_gas_remaining_shift(il[763]) + , main_note_hash_exist_write_offset_shift(il[764]) + , main_nullifier_exists_write_offset_shift(il[765]) + , main_nullifier_non_exists_write_offset_shift(il[766]) + , main_pc_shift(il[767]) + , main_sel_execution_row_shift(il[768]) + , main_side_effect_counter_shift(il[769]) + , main_sload_write_offset_shift(il[770]) + , main_sstore_write_offset_shift(il[771]) + , mem_glob_addr_shift(il[772]) + , mem_rw_shift(il[773]) + , mem_sel_mem_shift(il[774]) + , mem_tag_shift(il[775]) + , mem_tsp_shift(il[776]) + , mem_val_shift(il[777]) + , slice_addr_shift(il[778]) + , slice_clk_shift(il[779]) + , slice_cnt_shift(il[780]) + , slice_col_offset_shift(il[781]) + , slice_sel_cd_cpy_shift(il[782]) + , slice_sel_mem_active_shift(il[783]) + , slice_sel_return_shift(il[784]) + , slice_sel_start_shift(il[785]) + , slice_space_id_shift(il[786]) {} AvmFlavor::ProverPolynomials::ProverPolynomials(ProvingKey& proving_key) @@ -824,10 +824,10 @@ AvmFlavor::AllConstRefValues AvmFlavor::ProverPolynomials::get_row(size_t row_id main_sel_first[row_idx], main_zeroes[row_idx], powers_power_of_2[row_idx], - kernel_kernel_inputs[row_idx], - kernel_kernel_value_out[row_idx], - kernel_kernel_side_effect_out[row_idx], - kernel_kernel_metadata_out[row_idx], + main_kernel_inputs[row_idx], + main_kernel_value_out[row_idx], + main_kernel_side_effect_out[row_idx], + main_kernel_metadata_out[row_idx], main_calldata[row_idx], main_returndata[row_idx], alu_a_hi[row_idx], @@ -935,21 +935,6 @@ AvmFlavor::AllConstRefValues AvmFlavor::ProverPolynomials::get_row(size_t row_id keccakf1600_input[row_idx], keccakf1600_output[row_idx], keccakf1600_sel_keccakf1600[row_idx], - kernel_emit_l2_to_l1_msg_write_offset[row_idx], - kernel_emit_note_hash_write_offset[row_idx], - kernel_emit_nullifier_write_offset[row_idx], - kernel_emit_unencrypted_log_write_offset[row_idx], - kernel_kernel_in_offset[row_idx], - kernel_kernel_out_offset[row_idx], - kernel_l1_to_l2_msg_exists_write_offset[row_idx], - kernel_note_hash_exist_write_offset[row_idx], - kernel_nullifier_exists_write_offset[row_idx], - kernel_nullifier_non_exists_write_offset[row_idx], - kernel_q_public_input_kernel_add_to_table[row_idx], - kernel_q_public_input_kernel_out_add_to_table[row_idx], - kernel_side_effect_counter[row_idx], - kernel_sload_write_offset[row_idx], - kernel_sstore_write_offset[row_idx], main_abs_da_rem_gas_hi[row_idx], main_abs_da_rem_gas_lo[row_idx], main_abs_l2_rem_gas_hi[row_idx], @@ -964,6 +949,10 @@ AvmFlavor::AllConstRefValues AvmFlavor::ProverPolynomials::get_row(size_t row_id main_dyn_da_gas_op_cost[row_idx], main_dyn_gas_multiplier[row_idx], main_dyn_l2_gas_op_cost[row_idx], + main_emit_l2_to_l1_msg_write_offset[row_idx], + main_emit_note_hash_write_offset[row_idx], + main_emit_nullifier_write_offset[row_idx], + main_emit_unencrypted_log_write_offset[row_idx], main_ia[row_idx], main_ib[row_idx], main_ic[row_idx], @@ -975,12 +964,18 @@ AvmFlavor::AllConstRefValues AvmFlavor::ProverPolynomials::get_row(size_t row_id main_ind_addr_d[row_idx], main_internal_return_ptr[row_idx], main_inv[row_idx], + main_kernel_in_offset[row_idx], + main_kernel_out_offset[row_idx], + main_l1_to_l2_msg_exists_write_offset[row_idx], main_l2_gas_remaining[row_idx], main_l2_out_of_gas[row_idx], main_mem_addr_a[row_idx], main_mem_addr_b[row_idx], main_mem_addr_c[row_idx], main_mem_addr_d[row_idx], + main_note_hash_exist_write_offset[row_idx], + main_nullifier_exists_write_offset[row_idx], + main_nullifier_non_exists_write_offset[row_idx], main_op_err[row_idx], main_opcode_val[row_idx], main_pc[row_idx], @@ -993,6 +988,8 @@ AvmFlavor::AllConstRefValues AvmFlavor::ProverPolynomials::get_row(size_t row_id main_sel_bin[row_idx], main_sel_calldata[row_idx], main_sel_execution_row[row_idx], + main_sel_kernel_inputs[row_idx], + main_sel_kernel_out[row_idx], main_sel_last[row_idx], main_sel_mem_op_a[row_idx], main_sel_mem_op_b[row_idx], @@ -1068,7 +1065,10 @@ AvmFlavor::AllConstRefValues AvmFlavor::ProverPolynomials::get_row(size_t row_id main_sel_rng_16[row_idx], main_sel_rng_8[row_idx], main_sel_slice_gadget[row_idx], + main_side_effect_counter[row_idx], + main_sload_write_offset[row_idx], main_space_id[row_idx], + main_sstore_write_offset[row_idx], main_tag_err[row_idx], main_w_in_tag[row_idx], mem_addr[row_idx], @@ -1418,10 +1418,10 @@ AvmFlavor::AllConstRefValues AvmFlavor::ProverPolynomials::get_row(size_t row_id range_check_l2_gas_lo_counts[row_idx], range_check_da_gas_hi_counts[row_idx], range_check_da_gas_lo_counts[row_idx], - lookup_cd_value_counts[row_idx], - lookup_ret_value_counts[row_idx], kernel_output_lookup_counts[row_idx], lookup_into_kernel_counts[row_idx], + lookup_cd_value_counts[row_idx], + lookup_ret_value_counts[row_idx], incl_main_tag_err_counts[row_idx], incl_mem_tag_err_counts[row_idx], lookup_mem_rng_chk_lo_counts[row_idx], @@ -1484,10 +1484,10 @@ AvmFlavor::AllConstRefValues AvmFlavor::ProverPolynomials::get_row(size_t row_id range_check_l2_gas_lo_inv[row_idx], range_check_da_gas_hi_inv[row_idx], range_check_da_gas_lo_inv[row_idx], - lookup_cd_value_inv[row_idx], - lookup_ret_value_inv[row_idx], kernel_output_lookup_inv[row_idx], lookup_into_kernel_inv[row_idx], + lookup_cd_value_inv[row_idx], + lookup_ret_value_inv[row_idx], incl_main_tag_err_inv[row_idx], incl_mem_tag_err_inv[row_idx], lookup_mem_rng_chk_lo_inv[row_idx], @@ -1520,81 +1520,81 @@ AvmFlavor::AllConstRefValues AvmFlavor::ProverPolynomials::get_row(size_t row_id lookup_div_u16_5_inv[row_idx], lookup_div_u16_6_inv[row_idx], lookup_div_u16_7_inv[row_idx], + alu_a_hi_shift[row_idx], + alu_a_lo_shift[row_idx], + alu_b_hi_shift[row_idx], + alu_b_lo_shift[row_idx], + alu_cmp_rng_ctr_shift[row_idx], + alu_div_u16_r0_shift[row_idx], alu_div_u16_r1_shift[row_idx], - slice_clk_shift[row_idx], - alu_div_u16_r6_shift[row_idx], - kernel_nullifier_exists_write_offset_shift[row_idx], - mem_tsp_shift[row_idx], - main_internal_return_ptr_shift[row_idx], - main_sel_execution_row_shift[row_idx], - alu_sel_rng_chk_shift[row_idx], + alu_div_u16_r2_shift[row_idx], alu_div_u16_r3_shift[row_idx], - kernel_emit_note_hash_write_offset_shift[row_idx], - alu_p_sub_b_hi_shift[row_idx], - slice_sel_return_shift[row_idx], - kernel_side_effect_counter_shift[row_idx], + alu_div_u16_r4_shift[row_idx], + alu_div_u16_r5_shift[row_idx], + alu_div_u16_r6_shift[row_idx], + alu_div_u16_r7_shift[row_idx], alu_op_add_shift[row_idx], alu_op_cast_shift[row_idx], - kernel_emit_nullifier_write_offset_shift[row_idx], - slice_cnt_shift[row_idx], - alu_sel_cmp_shift[row_idx], - alu_u16_r1_shift[row_idx], - binary_acc_ia_shift[row_idx], - alu_div_u16_r0_shift[row_idx], - kernel_l1_to_l2_msg_exists_write_offset_shift[row_idx], - alu_a_hi_shift[row_idx], - alu_div_u16_r5_shift[row_idx], - kernel_emit_unencrypted_log_write_offset_shift[row_idx], - mem_val_shift[row_idx], - slice_sel_start_shift[row_idx], - binary_acc_ic_shift[row_idx], - alu_sel_div_rng_chk_shift[row_idx], - alu_u16_r6_shift[row_idx], - alu_op_shr_shift[row_idx], - slice_space_id_shift[row_idx], - mem_tag_shift[row_idx], + alu_op_cast_prev_shift[row_idx], + alu_op_div_shift[row_idx], alu_op_mul_shift[row_idx], - binary_mem_tag_ctr_shift[row_idx], - kernel_emit_l2_to_l1_msg_write_offset_shift[row_idx], - alu_sel_alu_shift[row_idx], - mem_rw_shift[row_idx], - mem_glob_addr_shift[row_idx], - alu_u16_r3_shift[row_idx], - kernel_sstore_write_offset_shift[row_idx], - mem_sel_mem_shift[row_idx], - slice_sel_mem_active_shift[row_idx], alu_op_shl_shift[row_idx], - alu_b_hi_shift[row_idx], - alu_cmp_rng_ctr_shift[row_idx], - alu_op_cast_prev_shift[row_idx], - alu_sel_rng_chk_lookup_shift[row_idx], - slice_sel_cd_cpy_shift[row_idx], - main_pc_shift[row_idx], - alu_u8_r1_shift[row_idx], + alu_op_shr_shift[row_idx], + alu_op_sub_shift[row_idx], + alu_p_sub_a_hi_shift[row_idx], alu_p_sub_a_lo_shift[row_idx], - main_da_gas_remaining_shift[row_idx], - alu_b_lo_shift[row_idx], - alu_u8_r0_shift[row_idx], + alu_p_sub_b_hi_shift[row_idx], alu_p_sub_b_lo_shift[row_idx], - kernel_nullifier_non_exists_write_offset_shift[row_idx], - alu_u16_r4_shift[row_idx], - binary_acc_ib_shift[row_idx], + alu_sel_alu_shift[row_idx], + alu_sel_cmp_shift[row_idx], + alu_sel_div_rng_chk_shift[row_idx], + alu_sel_rng_chk_shift[row_idx], + alu_sel_rng_chk_lookup_shift[row_idx], alu_u16_r0_shift[row_idx], - alu_div_u16_r2_shift[row_idx], - alu_op_div_shift[row_idx], - alu_a_lo_shift[row_idx], - alu_op_sub_shift[row_idx], - alu_div_u16_r7_shift[row_idx], - alu_u16_r5_shift[row_idx], + alu_u16_r1_shift[row_idx], alu_u16_r2_shift[row_idx], - kernel_note_hash_exist_write_offset_shift[row_idx], + alu_u16_r3_shift[row_idx], + alu_u16_r4_shift[row_idx], + alu_u16_r5_shift[row_idx], + alu_u16_r6_shift[row_idx], + alu_u8_r0_shift[row_idx], + alu_u8_r1_shift[row_idx], + binary_acc_ia_shift[row_idx], + binary_acc_ib_shift[row_idx], + binary_acc_ic_shift[row_idx], + binary_mem_tag_ctr_shift[row_idx], + binary_op_id_shift[row_idx], + main_da_gas_remaining_shift[row_idx], + main_emit_l2_to_l1_msg_write_offset_shift[row_idx], + main_emit_note_hash_write_offset_shift[row_idx], + main_emit_nullifier_write_offset_shift[row_idx], + main_emit_unencrypted_log_write_offset_shift[row_idx], + main_internal_return_ptr_shift[row_idx], + main_l1_to_l2_msg_exists_write_offset_shift[row_idx], main_l2_gas_remaining_shift[row_idx], - kernel_sload_write_offset_shift[row_idx], + main_note_hash_exist_write_offset_shift[row_idx], + main_nullifier_exists_write_offset_shift[row_idx], + main_nullifier_non_exists_write_offset_shift[row_idx], + main_pc_shift[row_idx], + main_sel_execution_row_shift[row_idx], + main_side_effect_counter_shift[row_idx], + main_sload_write_offset_shift[row_idx], + main_sstore_write_offset_shift[row_idx], + mem_glob_addr_shift[row_idx], + mem_rw_shift[row_idx], + mem_sel_mem_shift[row_idx], + mem_tag_shift[row_idx], + mem_tsp_shift[row_idx], + mem_val_shift[row_idx], slice_addr_shift[row_idx], - binary_op_id_shift[row_idx], - alu_p_sub_a_hi_shift[row_idx], + slice_clk_shift[row_idx], + slice_cnt_shift[row_idx], slice_col_offset_shift[row_idx], - alu_div_u16_r4_shift[row_idx] }; + slice_sel_cd_cpy_shift[row_idx], + slice_sel_mem_active_shift[row_idx], + slice_sel_return_shift[row_idx], + slice_sel_start_shift[row_idx], + slice_space_id_shift[row_idx] }; } AvmFlavor::CommitmentLabels::CommitmentLabels() @@ -1615,10 +1615,10 @@ AvmFlavor::CommitmentLabels::CommitmentLabels() Base::main_sel_first = "MAIN_SEL_FIRST"; Base::main_zeroes = "MAIN_ZEROES"; Base::powers_power_of_2 = "POWERS_POWER_OF_2"; - Base::kernel_kernel_inputs = "KERNEL_KERNEL_INPUTS"; - Base::kernel_kernel_value_out = "KERNEL_KERNEL_VALUE_OUT"; - Base::kernel_kernel_side_effect_out = "KERNEL_KERNEL_SIDE_EFFECT_OUT"; - Base::kernel_kernel_metadata_out = "KERNEL_KERNEL_METADATA_OUT"; + Base::main_kernel_inputs = "MAIN_KERNEL_INPUTS"; + Base::main_kernel_value_out = "MAIN_KERNEL_VALUE_OUT"; + Base::main_kernel_side_effect_out = "MAIN_KERNEL_SIDE_EFFECT_OUT"; + Base::main_kernel_metadata_out = "MAIN_KERNEL_METADATA_OUT"; Base::main_calldata = "MAIN_CALLDATA"; Base::main_returndata = "MAIN_RETURNDATA"; Base::alu_a_hi = "ALU_A_HI"; @@ -1726,21 +1726,6 @@ AvmFlavor::CommitmentLabels::CommitmentLabels() Base::keccakf1600_input = "KECCAKF1600_INPUT"; Base::keccakf1600_output = "KECCAKF1600_OUTPUT"; Base::keccakf1600_sel_keccakf1600 = "KECCAKF1600_SEL_KECCAKF1600"; - Base::kernel_emit_l2_to_l1_msg_write_offset = "KERNEL_EMIT_L2_TO_L1_MSG_WRITE_OFFSET"; - Base::kernel_emit_note_hash_write_offset = "KERNEL_EMIT_NOTE_HASH_WRITE_OFFSET"; - Base::kernel_emit_nullifier_write_offset = "KERNEL_EMIT_NULLIFIER_WRITE_OFFSET"; - Base::kernel_emit_unencrypted_log_write_offset = "KERNEL_EMIT_UNENCRYPTED_LOG_WRITE_OFFSET"; - Base::kernel_kernel_in_offset = "KERNEL_KERNEL_IN_OFFSET"; - Base::kernel_kernel_out_offset = "KERNEL_KERNEL_OUT_OFFSET"; - Base::kernel_l1_to_l2_msg_exists_write_offset = "KERNEL_L1_TO_L2_MSG_EXISTS_WRITE_OFFSET"; - Base::kernel_note_hash_exist_write_offset = "KERNEL_NOTE_HASH_EXIST_WRITE_OFFSET"; - Base::kernel_nullifier_exists_write_offset = "KERNEL_NULLIFIER_EXISTS_WRITE_OFFSET"; - Base::kernel_nullifier_non_exists_write_offset = "KERNEL_NULLIFIER_NON_EXISTS_WRITE_OFFSET"; - Base::kernel_q_public_input_kernel_add_to_table = "KERNEL_Q_PUBLIC_INPUT_KERNEL_ADD_TO_TABLE"; - Base::kernel_q_public_input_kernel_out_add_to_table = "KERNEL_Q_PUBLIC_INPUT_KERNEL_OUT_ADD_TO_TABLE"; - Base::kernel_side_effect_counter = "KERNEL_SIDE_EFFECT_COUNTER"; - Base::kernel_sload_write_offset = "KERNEL_SLOAD_WRITE_OFFSET"; - Base::kernel_sstore_write_offset = "KERNEL_SSTORE_WRITE_OFFSET"; Base::main_abs_da_rem_gas_hi = "MAIN_ABS_DA_REM_GAS_HI"; Base::main_abs_da_rem_gas_lo = "MAIN_ABS_DA_REM_GAS_LO"; Base::main_abs_l2_rem_gas_hi = "MAIN_ABS_L2_REM_GAS_HI"; @@ -1755,6 +1740,10 @@ AvmFlavor::CommitmentLabels::CommitmentLabels() Base::main_dyn_da_gas_op_cost = "MAIN_DYN_DA_GAS_OP_COST"; Base::main_dyn_gas_multiplier = "MAIN_DYN_GAS_MULTIPLIER"; Base::main_dyn_l2_gas_op_cost = "MAIN_DYN_L2_GAS_OP_COST"; + Base::main_emit_l2_to_l1_msg_write_offset = "MAIN_EMIT_L2_TO_L1_MSG_WRITE_OFFSET"; + Base::main_emit_note_hash_write_offset = "MAIN_EMIT_NOTE_HASH_WRITE_OFFSET"; + Base::main_emit_nullifier_write_offset = "MAIN_EMIT_NULLIFIER_WRITE_OFFSET"; + Base::main_emit_unencrypted_log_write_offset = "MAIN_EMIT_UNENCRYPTED_LOG_WRITE_OFFSET"; Base::main_ia = "MAIN_IA"; Base::main_ib = "MAIN_IB"; Base::main_ic = "MAIN_IC"; @@ -1766,12 +1755,18 @@ AvmFlavor::CommitmentLabels::CommitmentLabels() Base::main_ind_addr_d = "MAIN_IND_ADDR_D"; Base::main_internal_return_ptr = "MAIN_INTERNAL_RETURN_PTR"; Base::main_inv = "MAIN_INV"; + Base::main_kernel_in_offset = "MAIN_KERNEL_IN_OFFSET"; + Base::main_kernel_out_offset = "MAIN_KERNEL_OUT_OFFSET"; + Base::main_l1_to_l2_msg_exists_write_offset = "MAIN_L1_TO_L2_MSG_EXISTS_WRITE_OFFSET"; Base::main_l2_gas_remaining = "MAIN_L2_GAS_REMAINING"; Base::main_l2_out_of_gas = "MAIN_L2_OUT_OF_GAS"; Base::main_mem_addr_a = "MAIN_MEM_ADDR_A"; Base::main_mem_addr_b = "MAIN_MEM_ADDR_B"; Base::main_mem_addr_c = "MAIN_MEM_ADDR_C"; Base::main_mem_addr_d = "MAIN_MEM_ADDR_D"; + Base::main_note_hash_exist_write_offset = "MAIN_NOTE_HASH_EXIST_WRITE_OFFSET"; + Base::main_nullifier_exists_write_offset = "MAIN_NULLIFIER_EXISTS_WRITE_OFFSET"; + Base::main_nullifier_non_exists_write_offset = "MAIN_NULLIFIER_NON_EXISTS_WRITE_OFFSET"; Base::main_op_err = "MAIN_OP_ERR"; Base::main_opcode_val = "MAIN_OPCODE_VAL"; Base::main_pc = "MAIN_PC"; @@ -1784,6 +1779,8 @@ AvmFlavor::CommitmentLabels::CommitmentLabels() Base::main_sel_bin = "MAIN_SEL_BIN"; Base::main_sel_calldata = "MAIN_SEL_CALLDATA"; Base::main_sel_execution_row = "MAIN_SEL_EXECUTION_ROW"; + Base::main_sel_kernel_inputs = "MAIN_SEL_KERNEL_INPUTS"; + Base::main_sel_kernel_out = "MAIN_SEL_KERNEL_OUT"; Base::main_sel_last = "MAIN_SEL_LAST"; Base::main_sel_mem_op_a = "MAIN_SEL_MEM_OP_A"; Base::main_sel_mem_op_b = "MAIN_SEL_MEM_OP_B"; @@ -1859,7 +1856,10 @@ AvmFlavor::CommitmentLabels::CommitmentLabels() Base::main_sel_rng_16 = "MAIN_SEL_RNG_16"; Base::main_sel_rng_8 = "MAIN_SEL_RNG_8"; Base::main_sel_slice_gadget = "MAIN_SEL_SLICE_GADGET"; + Base::main_side_effect_counter = "MAIN_SIDE_EFFECT_COUNTER"; + Base::main_sload_write_offset = "MAIN_SLOAD_WRITE_OFFSET"; Base::main_space_id = "MAIN_SPACE_ID"; + Base::main_sstore_write_offset = "MAIN_SSTORE_WRITE_OFFSET"; Base::main_tag_err = "MAIN_TAG_ERR"; Base::main_w_in_tag = "MAIN_W_IN_TAG"; Base::mem_addr = "MEM_ADDR"; @@ -2232,10 +2232,10 @@ AvmFlavor::CommitmentLabels::CommitmentLabels() Base::range_check_l2_gas_lo_inv = "RANGE_CHECK_L2_GAS_LO_INV"; Base::range_check_da_gas_hi_inv = "RANGE_CHECK_DA_GAS_HI_INV"; Base::range_check_da_gas_lo_inv = "RANGE_CHECK_DA_GAS_LO_INV"; - Base::lookup_cd_value_inv = "LOOKUP_CD_VALUE_INV"; - Base::lookup_ret_value_inv = "LOOKUP_RET_VALUE_INV"; Base::kernel_output_lookup_inv = "KERNEL_OUTPUT_LOOKUP_INV"; Base::lookup_into_kernel_inv = "LOOKUP_INTO_KERNEL_INV"; + Base::lookup_cd_value_inv = "LOOKUP_CD_VALUE_INV"; + Base::lookup_ret_value_inv = "LOOKUP_RET_VALUE_INV"; Base::incl_main_tag_err_inv = "INCL_MAIN_TAG_ERR_INV"; Base::incl_mem_tag_err_inv = "INCL_MEM_TAG_ERR_INV"; Base::lookup_mem_rng_chk_lo_inv = "LOOKUP_MEM_RNG_CHK_LO_INV"; @@ -2275,10 +2275,10 @@ AvmFlavor::CommitmentLabels::CommitmentLabels() Base::range_check_l2_gas_lo_counts = "RANGE_CHECK_L2_GAS_LO_COUNTS"; Base::range_check_da_gas_hi_counts = "RANGE_CHECK_DA_GAS_HI_COUNTS"; Base::range_check_da_gas_lo_counts = "RANGE_CHECK_DA_GAS_LO_COUNTS"; - Base::lookup_cd_value_counts = "LOOKUP_CD_VALUE_COUNTS"; - Base::lookup_ret_value_counts = "LOOKUP_RET_VALUE_COUNTS"; Base::kernel_output_lookup_counts = "KERNEL_OUTPUT_LOOKUP_COUNTS"; Base::lookup_into_kernel_counts = "LOOKUP_INTO_KERNEL_COUNTS"; + Base::lookup_cd_value_counts = "LOOKUP_CD_VALUE_COUNTS"; + Base::lookup_ret_value_counts = "LOOKUP_RET_VALUE_COUNTS"; Base::incl_main_tag_err_counts = "INCL_MAIN_TAG_ERR_COUNTS"; Base::incl_mem_tag_err_counts = "INCL_MEM_TAG_ERR_COUNTS"; Base::lookup_mem_rng_chk_lo_counts = "LOOKUP_MEM_RNG_CHK_LO_COUNTS"; diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/generated/flavor.hpp b/barretenberg/cpp/src/barretenberg/vm/avm/generated/flavor.hpp index 739a85d4cefc..a88d98f21a2b 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/generated/flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/generated/flavor.hpp @@ -10,7 +10,6 @@ #include "barretenberg/flavor/flavor.hpp" #include "barretenberg/flavor/flavor_macros.hpp" #include "barretenberg/polynomials/evaluation_domain.hpp" -#include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/transcript/transcript.hpp" #include "barretenberg/vm/avm/generated/flavor_settings.hpp" @@ -103,10 +102,10 @@ template using tuple_cat_t = decltype(std::tuple_cat(std:: // The entities that will be used in the flavor. // clang-format off #define PRECOMPUTED_ENTITIES byte_lookup_sel_bin, byte_lookup_table_byte_lengths, byte_lookup_table_in_tags, byte_lookup_table_input_a, byte_lookup_table_input_b, byte_lookup_table_op_id, byte_lookup_table_output, gas_base_da_gas_fixed_table, gas_base_l2_gas_fixed_table, gas_dyn_da_gas_fixed_table, gas_dyn_l2_gas_fixed_table, gas_sel_gas_cost, main_clk, main_sel_first, main_zeroes, powers_power_of_2 -#define WIRE_ENTITIES kernel_kernel_inputs, kernel_kernel_value_out, kernel_kernel_side_effect_out, kernel_kernel_metadata_out, main_calldata, main_returndata, alu_a_hi, alu_a_lo, alu_b_hi, alu_b_lo, alu_borrow, alu_cf, alu_clk, alu_cmp_rng_ctr, alu_div_u16_r0, alu_div_u16_r1, alu_div_u16_r2, alu_div_u16_r3, alu_div_u16_r4, alu_div_u16_r5, alu_div_u16_r6, alu_div_u16_r7, alu_divisor_hi, alu_divisor_lo, alu_ff_tag, alu_ia, alu_ib, alu_ic, alu_in_tag, alu_op_add, alu_op_cast, alu_op_cast_prev, alu_op_div, alu_op_div_a_lt_b, alu_op_div_std, alu_op_eq, alu_op_eq_diff_inv, alu_op_lt, alu_op_lte, alu_op_mul, alu_op_not, alu_op_shl, alu_op_shr, alu_op_sub, alu_p_a_borrow, alu_p_b_borrow, alu_p_sub_a_hi, alu_p_sub_a_lo, alu_p_sub_b_hi, alu_p_sub_b_lo, alu_partial_prod_hi, alu_partial_prod_lo, alu_quotient_hi, alu_quotient_lo, alu_remainder, alu_res_hi, alu_res_lo, alu_sel_alu, alu_sel_cmp, alu_sel_div_rng_chk, alu_sel_rng_chk, alu_sel_rng_chk_lookup, alu_sel_shift_which, alu_shift_lt_bit_len, alu_t_sub_s_bits, alu_two_pow_s, alu_two_pow_t_sub_s, alu_u128_tag, alu_u16_r0, alu_u16_r1, alu_u16_r10, alu_u16_r11, alu_u16_r12, alu_u16_r13, alu_u16_r14, alu_u16_r2, alu_u16_r3, alu_u16_r4, alu_u16_r5, alu_u16_r6, alu_u16_r7, alu_u16_r8, alu_u16_r9, alu_u16_tag, alu_u32_tag, alu_u64_tag, alu_u8_r0, alu_u8_r1, alu_u8_tag, binary_acc_ia, binary_acc_ib, binary_acc_ic, binary_clk, binary_ia_bytes, binary_ib_bytes, binary_ic_bytes, binary_in_tag, binary_mem_tag_ctr, binary_mem_tag_ctr_inv, binary_op_id, binary_sel_bin, binary_start, conversion_clk, conversion_input, conversion_num_limbs, conversion_radix, conversion_sel_to_radix_le, keccakf1600_clk, keccakf1600_input, keccakf1600_output, keccakf1600_sel_keccakf1600, kernel_emit_l2_to_l1_msg_write_offset, kernel_emit_note_hash_write_offset, kernel_emit_nullifier_write_offset, kernel_emit_unencrypted_log_write_offset, kernel_kernel_in_offset, kernel_kernel_out_offset, kernel_l1_to_l2_msg_exists_write_offset, kernel_note_hash_exist_write_offset, kernel_nullifier_exists_write_offset, kernel_nullifier_non_exists_write_offset, kernel_q_public_input_kernel_add_to_table, kernel_q_public_input_kernel_out_add_to_table, kernel_side_effect_counter, kernel_sload_write_offset, kernel_sstore_write_offset, main_abs_da_rem_gas_hi, main_abs_da_rem_gas_lo, main_abs_l2_rem_gas_hi, main_abs_l2_rem_gas_lo, main_alu_in_tag, main_base_da_gas_op_cost, main_base_l2_gas_op_cost, main_bin_op_id, main_call_ptr, main_da_gas_remaining, main_da_out_of_gas, main_dyn_da_gas_op_cost, main_dyn_gas_multiplier, main_dyn_l2_gas_op_cost, main_ia, main_ib, main_ic, main_id, main_id_zero, main_ind_addr_a, main_ind_addr_b, main_ind_addr_c, main_ind_addr_d, main_internal_return_ptr, main_inv, main_l2_gas_remaining, main_l2_out_of_gas, main_mem_addr_a, main_mem_addr_b, main_mem_addr_c, main_mem_addr_d, main_op_err, main_opcode_val, main_pc, main_r_in_tag, main_rwa, main_rwb, main_rwc, main_rwd, main_sel_alu, main_sel_bin, main_sel_calldata, main_sel_execution_row, main_sel_last, main_sel_mem_op_a, main_sel_mem_op_b, main_sel_mem_op_c, main_sel_mem_op_d, main_sel_mov_ia_to_ic, main_sel_mov_ib_to_ic, main_sel_op_add, main_sel_op_address, main_sel_op_and, main_sel_op_block_number, main_sel_op_calldata_copy, main_sel_op_cast, main_sel_op_chain_id, main_sel_op_cmov, main_sel_op_coinbase, main_sel_op_dagasleft, main_sel_op_div, main_sel_op_ecadd, main_sel_op_emit_l2_to_l1_msg, main_sel_op_emit_note_hash, main_sel_op_emit_nullifier, main_sel_op_emit_unencrypted_log, main_sel_op_eq, main_sel_op_external_call, main_sel_op_external_return, main_sel_op_external_revert, main_sel_op_fdiv, main_sel_op_fee_per_da_gas, main_sel_op_fee_per_l2_gas, main_sel_op_function_selector, main_sel_op_get_contract_instance, main_sel_op_internal_call, main_sel_op_internal_return, main_sel_op_jump, main_sel_op_jumpi, main_sel_op_keccak, main_sel_op_l1_to_l2_msg_exists, main_sel_op_l2gasleft, main_sel_op_lt, main_sel_op_lte, main_sel_op_mov, main_sel_op_msm, main_sel_op_mul, main_sel_op_not, main_sel_op_note_hash_exists, main_sel_op_nullifier_exists, main_sel_op_or, main_sel_op_pedersen, main_sel_op_pedersen_commit, main_sel_op_poseidon2, main_sel_op_radix_le, main_sel_op_sender, main_sel_op_set, main_sel_op_sha256, main_sel_op_shl, main_sel_op_shr, main_sel_op_sload, main_sel_op_sstore, main_sel_op_storage_address, main_sel_op_sub, main_sel_op_timestamp, main_sel_op_transaction_fee, main_sel_op_version, main_sel_op_xor, main_sel_q_kernel_lookup, main_sel_q_kernel_output_lookup, main_sel_resolve_ind_addr_a, main_sel_resolve_ind_addr_b, main_sel_resolve_ind_addr_c, main_sel_resolve_ind_addr_d, main_sel_returndata, main_sel_rng_16, main_sel_rng_8, main_sel_slice_gadget, main_space_id, main_tag_err, main_w_in_tag, mem_addr, mem_clk, mem_diff_hi, mem_diff_lo, mem_diff_mid, mem_glob_addr, mem_last, mem_lastAccess, mem_one_min_inv, mem_r_in_tag, mem_rw, mem_sel_mem, mem_sel_mov_ia_to_ic, mem_sel_mov_ib_to_ic, mem_sel_op_a, mem_sel_op_b, mem_sel_op_c, mem_sel_op_cmov, mem_sel_op_d, mem_sel_op_poseidon_read_a, mem_sel_op_poseidon_read_b, mem_sel_op_poseidon_read_c, mem_sel_op_poseidon_read_d, mem_sel_op_poseidon_write_a, mem_sel_op_poseidon_write_b, mem_sel_op_poseidon_write_c, mem_sel_op_poseidon_write_d, mem_sel_op_slice, mem_sel_resolve_ind_addr_a, mem_sel_resolve_ind_addr_b, mem_sel_resolve_ind_addr_c, mem_sel_resolve_ind_addr_d, mem_sel_rng_chk, mem_skip_check_tag, mem_space_id, mem_tag, mem_tag_err, mem_tsp, mem_val, mem_w_in_tag, pedersen_clk, pedersen_input, pedersen_output, pedersen_sel_pedersen, poseidon2_B_10_0, poseidon2_B_10_1, poseidon2_B_10_2, poseidon2_B_10_3, poseidon2_B_11_0, poseidon2_B_11_1, poseidon2_B_11_2, poseidon2_B_11_3, poseidon2_B_12_0, poseidon2_B_12_1, poseidon2_B_12_2, poseidon2_B_12_3, poseidon2_B_13_0, poseidon2_B_13_1, poseidon2_B_13_2, poseidon2_B_13_3, poseidon2_B_14_0, poseidon2_B_14_1, poseidon2_B_14_2, poseidon2_B_14_3, poseidon2_B_15_0, poseidon2_B_15_1, poseidon2_B_15_2, poseidon2_B_15_3, poseidon2_B_16_0, poseidon2_B_16_1, poseidon2_B_16_2, poseidon2_B_16_3, poseidon2_B_17_0, poseidon2_B_17_1, poseidon2_B_17_2, poseidon2_B_17_3, poseidon2_B_18_0, poseidon2_B_18_1, poseidon2_B_18_2, poseidon2_B_18_3, poseidon2_B_19_0, poseidon2_B_19_1, poseidon2_B_19_2, poseidon2_B_19_3, poseidon2_B_20_0, poseidon2_B_20_1, poseidon2_B_20_2, poseidon2_B_20_3, poseidon2_B_21_0, poseidon2_B_21_1, poseidon2_B_21_2, poseidon2_B_21_3, poseidon2_B_22_0, poseidon2_B_22_1, poseidon2_B_22_2, poseidon2_B_22_3, poseidon2_B_23_0, poseidon2_B_23_1, poseidon2_B_23_2, poseidon2_B_23_3, poseidon2_B_24_0, poseidon2_B_24_1, poseidon2_B_24_2, poseidon2_B_24_3, poseidon2_B_25_0, poseidon2_B_25_1, poseidon2_B_25_2, poseidon2_B_25_3, poseidon2_B_26_0, poseidon2_B_26_1, poseidon2_B_26_2, poseidon2_B_26_3, poseidon2_B_27_0, poseidon2_B_27_1, poseidon2_B_27_2, poseidon2_B_27_3, poseidon2_B_28_0, poseidon2_B_28_1, poseidon2_B_28_2, poseidon2_B_28_3, poseidon2_B_29_0, poseidon2_B_29_1, poseidon2_B_29_2, poseidon2_B_29_3, poseidon2_B_30_0, poseidon2_B_30_1, poseidon2_B_30_2, poseidon2_B_30_3, poseidon2_B_31_0, poseidon2_B_31_1, poseidon2_B_31_2, poseidon2_B_31_3, poseidon2_B_32_0, poseidon2_B_32_1, poseidon2_B_32_2, poseidon2_B_32_3, poseidon2_B_33_0, poseidon2_B_33_1, poseidon2_B_33_2, poseidon2_B_33_3, poseidon2_B_34_0, poseidon2_B_34_1, poseidon2_B_34_2, poseidon2_B_34_3, poseidon2_B_35_0, poseidon2_B_35_1, poseidon2_B_35_2, poseidon2_B_35_3, poseidon2_B_36_0, poseidon2_B_36_1, poseidon2_B_36_2, poseidon2_B_36_3, poseidon2_B_37_0, poseidon2_B_37_1, poseidon2_B_37_2, poseidon2_B_37_3, poseidon2_B_38_0, poseidon2_B_38_1, poseidon2_B_38_2, poseidon2_B_38_3, poseidon2_B_39_0, poseidon2_B_39_1, poseidon2_B_39_2, poseidon2_B_39_3, poseidon2_B_40_0, poseidon2_B_40_1, poseidon2_B_40_2, poseidon2_B_40_3, poseidon2_B_41_0, poseidon2_B_41_1, poseidon2_B_41_2, poseidon2_B_41_3, poseidon2_B_42_0, poseidon2_B_42_1, poseidon2_B_42_2, poseidon2_B_42_3, poseidon2_B_43_0, poseidon2_B_43_1, poseidon2_B_43_2, poseidon2_B_43_3, poseidon2_B_44_0, poseidon2_B_44_1, poseidon2_B_44_2, poseidon2_B_44_3, poseidon2_B_45_0, poseidon2_B_45_1, poseidon2_B_45_2, poseidon2_B_45_3, poseidon2_B_46_0, poseidon2_B_46_1, poseidon2_B_46_2, poseidon2_B_46_3, poseidon2_B_47_0, poseidon2_B_47_1, poseidon2_B_47_2, poseidon2_B_47_3, poseidon2_B_48_0, poseidon2_B_48_1, poseidon2_B_48_2, poseidon2_B_48_3, poseidon2_B_49_0, poseidon2_B_49_1, poseidon2_B_49_2, poseidon2_B_49_3, poseidon2_B_4_0, poseidon2_B_4_1, poseidon2_B_4_2, poseidon2_B_4_3, poseidon2_B_50_0, poseidon2_B_50_1, poseidon2_B_50_2, poseidon2_B_50_3, poseidon2_B_51_0, poseidon2_B_51_1, poseidon2_B_51_2, poseidon2_B_51_3, poseidon2_B_52_0, poseidon2_B_52_1, poseidon2_B_52_2, poseidon2_B_52_3, poseidon2_B_53_0, poseidon2_B_53_1, poseidon2_B_53_2, poseidon2_B_53_3, poseidon2_B_54_0, poseidon2_B_54_1, poseidon2_B_54_2, poseidon2_B_54_3, poseidon2_B_55_0, poseidon2_B_55_1, poseidon2_B_55_2, poseidon2_B_55_3, poseidon2_B_56_0, poseidon2_B_56_1, poseidon2_B_56_2, poseidon2_B_56_3, poseidon2_B_57_0, poseidon2_B_57_1, poseidon2_B_57_2, poseidon2_B_57_3, poseidon2_B_58_0, poseidon2_B_58_1, poseidon2_B_58_2, poseidon2_B_58_3, poseidon2_B_59_0, poseidon2_B_59_1, poseidon2_B_59_2, poseidon2_B_59_3, poseidon2_B_5_0, poseidon2_B_5_1, poseidon2_B_5_2, poseidon2_B_5_3, poseidon2_B_6_0, poseidon2_B_6_1, poseidon2_B_6_2, poseidon2_B_6_3, poseidon2_B_7_0, poseidon2_B_7_1, poseidon2_B_7_2, poseidon2_B_7_3, poseidon2_B_8_0, poseidon2_B_8_1, poseidon2_B_8_2, poseidon2_B_8_3, poseidon2_B_9_0, poseidon2_B_9_1, poseidon2_B_9_2, poseidon2_B_9_3, poseidon2_EXT_LAYER_4, poseidon2_EXT_LAYER_5, poseidon2_EXT_LAYER_6, poseidon2_EXT_LAYER_7, poseidon2_T_0_4, poseidon2_T_0_5, poseidon2_T_0_6, poseidon2_T_0_7, poseidon2_T_1_4, poseidon2_T_1_5, poseidon2_T_1_6, poseidon2_T_1_7, poseidon2_T_2_4, poseidon2_T_2_5, poseidon2_T_2_6, poseidon2_T_2_7, poseidon2_T_3_4, poseidon2_T_3_5, poseidon2_T_3_6, poseidon2_T_3_7, poseidon2_T_60_4, poseidon2_T_60_5, poseidon2_T_60_6, poseidon2_T_60_7, poseidon2_T_61_4, poseidon2_T_61_5, poseidon2_T_61_6, poseidon2_T_61_7, poseidon2_T_62_4, poseidon2_T_62_5, poseidon2_T_62_6, poseidon2_T_62_7, poseidon2_T_63_4, poseidon2_T_63_5, poseidon2_T_63_6, poseidon2_T_63_7, poseidon2_a_0, poseidon2_a_1, poseidon2_a_2, poseidon2_a_3, poseidon2_b_0, poseidon2_b_1, poseidon2_b_2, poseidon2_b_3, poseidon2_clk, poseidon2_input_addr, poseidon2_mem_addr_read_a, poseidon2_mem_addr_read_b, poseidon2_mem_addr_read_c, poseidon2_mem_addr_read_d, poseidon2_mem_addr_write_a, poseidon2_mem_addr_write_b, poseidon2_mem_addr_write_c, poseidon2_mem_addr_write_d, poseidon2_output_addr, poseidon2_sel_poseidon_perm, sha256_clk, sha256_input, sha256_output, sha256_sel_sha256_compression, sha256_state, slice_addr, slice_clk, slice_cnt, slice_col_offset, slice_one_min_inv, slice_sel_cd_cpy, slice_sel_mem_active, slice_sel_return, slice_sel_start, slice_space_id, slice_val, lookup_byte_lengths_counts, lookup_byte_operations_counts, lookup_opcode_gas_counts, range_check_l2_gas_hi_counts, range_check_l2_gas_lo_counts, range_check_da_gas_hi_counts, range_check_da_gas_lo_counts, lookup_cd_value_counts, lookup_ret_value_counts, kernel_output_lookup_counts, lookup_into_kernel_counts, incl_main_tag_err_counts, incl_mem_tag_err_counts, lookup_mem_rng_chk_lo_counts, lookup_mem_rng_chk_mid_counts, lookup_mem_rng_chk_hi_counts, lookup_pow_2_0_counts, lookup_pow_2_1_counts, lookup_u8_0_counts, lookup_u8_1_counts, lookup_u16_0_counts, lookup_u16_1_counts, lookup_u16_2_counts, lookup_u16_3_counts, lookup_u16_4_counts, lookup_u16_5_counts, lookup_u16_6_counts, lookup_u16_7_counts, lookup_u16_8_counts, lookup_u16_9_counts, lookup_u16_10_counts, lookup_u16_11_counts, lookup_u16_12_counts, lookup_u16_13_counts, lookup_u16_14_counts, lookup_div_u16_0_counts, lookup_div_u16_1_counts, lookup_div_u16_2_counts, lookup_div_u16_3_counts, lookup_div_u16_4_counts, lookup_div_u16_5_counts, lookup_div_u16_6_counts, lookup_div_u16_7_counts -#define DERIVED_WITNESS_ENTITIES perm_pos_mem_read_a_inv, perm_pos_mem_read_b_inv, perm_pos_mem_read_c_inv, perm_pos_mem_read_d_inv, perm_pos_mem_write_a_inv, perm_pos_mem_write_b_inv, perm_pos_mem_write_c_inv, perm_pos_mem_write_d_inv, perm_slice_mem_inv, perm_main_alu_inv, perm_main_bin_inv, perm_main_conv_inv, perm_main_pos2_perm_inv, perm_main_pedersen_inv, perm_main_slice_inv, perm_main_mem_a_inv, perm_main_mem_b_inv, perm_main_mem_c_inv, perm_main_mem_d_inv, perm_main_mem_ind_addr_a_inv, perm_main_mem_ind_addr_b_inv, perm_main_mem_ind_addr_c_inv, perm_main_mem_ind_addr_d_inv, lookup_byte_lengths_inv, lookup_byte_operations_inv, lookup_opcode_gas_inv, range_check_l2_gas_hi_inv, range_check_l2_gas_lo_inv, range_check_da_gas_hi_inv, range_check_da_gas_lo_inv, lookup_cd_value_inv, lookup_ret_value_inv, kernel_output_lookup_inv, lookup_into_kernel_inv, incl_main_tag_err_inv, incl_mem_tag_err_inv, lookup_mem_rng_chk_lo_inv, lookup_mem_rng_chk_mid_inv, lookup_mem_rng_chk_hi_inv, lookup_pow_2_0_inv, lookup_pow_2_1_inv, lookup_u8_0_inv, lookup_u8_1_inv, lookup_u16_0_inv, lookup_u16_1_inv, lookup_u16_2_inv, lookup_u16_3_inv, lookup_u16_4_inv, lookup_u16_5_inv, lookup_u16_6_inv, lookup_u16_7_inv, lookup_u16_8_inv, lookup_u16_9_inv, lookup_u16_10_inv, lookup_u16_11_inv, lookup_u16_12_inv, lookup_u16_13_inv, lookup_u16_14_inv, lookup_div_u16_0_inv, lookup_div_u16_1_inv, lookup_div_u16_2_inv, lookup_div_u16_3_inv, lookup_div_u16_4_inv, lookup_div_u16_5_inv, lookup_div_u16_6_inv, lookup_div_u16_7_inv -#define SHIFTED_ENTITIES alu_div_u16_r1_shift, slice_clk_shift, alu_div_u16_r6_shift, kernel_nullifier_exists_write_offset_shift, mem_tsp_shift, main_internal_return_ptr_shift, main_sel_execution_row_shift, alu_sel_rng_chk_shift, alu_div_u16_r3_shift, kernel_emit_note_hash_write_offset_shift, alu_p_sub_b_hi_shift, slice_sel_return_shift, kernel_side_effect_counter_shift, alu_op_add_shift, alu_op_cast_shift, kernel_emit_nullifier_write_offset_shift, slice_cnt_shift, alu_sel_cmp_shift, alu_u16_r1_shift, binary_acc_ia_shift, alu_div_u16_r0_shift, kernel_l1_to_l2_msg_exists_write_offset_shift, alu_a_hi_shift, alu_div_u16_r5_shift, kernel_emit_unencrypted_log_write_offset_shift, mem_val_shift, slice_sel_start_shift, binary_acc_ic_shift, alu_sel_div_rng_chk_shift, alu_u16_r6_shift, alu_op_shr_shift, slice_space_id_shift, mem_tag_shift, alu_op_mul_shift, binary_mem_tag_ctr_shift, kernel_emit_l2_to_l1_msg_write_offset_shift, alu_sel_alu_shift, mem_rw_shift, mem_glob_addr_shift, alu_u16_r3_shift, kernel_sstore_write_offset_shift, mem_sel_mem_shift, slice_sel_mem_active_shift, alu_op_shl_shift, alu_b_hi_shift, alu_cmp_rng_ctr_shift, alu_op_cast_prev_shift, alu_sel_rng_chk_lookup_shift, slice_sel_cd_cpy_shift, main_pc_shift, alu_u8_r1_shift, alu_p_sub_a_lo_shift, main_da_gas_remaining_shift, alu_b_lo_shift, alu_u8_r0_shift, alu_p_sub_b_lo_shift, kernel_nullifier_non_exists_write_offset_shift, alu_u16_r4_shift, binary_acc_ib_shift, alu_u16_r0_shift, alu_div_u16_r2_shift, alu_op_div_shift, alu_a_lo_shift, alu_op_sub_shift, alu_div_u16_r7_shift, alu_u16_r5_shift, alu_u16_r2_shift, kernel_note_hash_exist_write_offset_shift, main_l2_gas_remaining_shift, kernel_sload_write_offset_shift, slice_addr_shift, binary_op_id_shift, alu_p_sub_a_hi_shift, slice_col_offset_shift, alu_div_u16_r4_shift -#define TO_BE_SHIFTED(e) e.alu_div_u16_r1, e.slice_clk, e.alu_div_u16_r6, e.kernel_nullifier_exists_write_offset, e.mem_tsp, e.main_internal_return_ptr, e.main_sel_execution_row, e.alu_sel_rng_chk, e.alu_div_u16_r3, e.kernel_emit_note_hash_write_offset, e.alu_p_sub_b_hi, e.slice_sel_return, e.kernel_side_effect_counter, e.alu_op_add, e.alu_op_cast, e.kernel_emit_nullifier_write_offset, e.slice_cnt, e.alu_sel_cmp, e.alu_u16_r1, e.binary_acc_ia, e.alu_div_u16_r0, e.kernel_l1_to_l2_msg_exists_write_offset, e.alu_a_hi, e.alu_div_u16_r5, e.kernel_emit_unencrypted_log_write_offset, e.mem_val, e.slice_sel_start, e.binary_acc_ic, e.alu_sel_div_rng_chk, e.alu_u16_r6, e.alu_op_shr, e.slice_space_id, e.mem_tag, e.alu_op_mul, e.binary_mem_tag_ctr, e.kernel_emit_l2_to_l1_msg_write_offset, e.alu_sel_alu, e.mem_rw, e.mem_glob_addr, e.alu_u16_r3, e.kernel_sstore_write_offset, e.mem_sel_mem, e.slice_sel_mem_active, e.alu_op_shl, e.alu_b_hi, e.alu_cmp_rng_ctr, e.alu_op_cast_prev, e.alu_sel_rng_chk_lookup, e.slice_sel_cd_cpy, e.main_pc, e.alu_u8_r1, e.alu_p_sub_a_lo, e.main_da_gas_remaining, e.alu_b_lo, e.alu_u8_r0, e.alu_p_sub_b_lo, e.kernel_nullifier_non_exists_write_offset, e.alu_u16_r4, e.binary_acc_ib, e.alu_u16_r0, e.alu_div_u16_r2, e.alu_op_div, e.alu_a_lo, e.alu_op_sub, e.alu_div_u16_r7, e.alu_u16_r5, e.alu_u16_r2, e.kernel_note_hash_exist_write_offset, e.main_l2_gas_remaining, e.kernel_sload_write_offset, e.slice_addr, e.binary_op_id, e.alu_p_sub_a_hi, e.slice_col_offset, e.alu_div_u16_r4 +#define WIRE_ENTITIES main_kernel_inputs, main_kernel_value_out, main_kernel_side_effect_out, main_kernel_metadata_out, main_calldata, main_returndata, alu_a_hi, alu_a_lo, alu_b_hi, alu_b_lo, alu_borrow, alu_cf, alu_clk, alu_cmp_rng_ctr, alu_div_u16_r0, alu_div_u16_r1, alu_div_u16_r2, alu_div_u16_r3, alu_div_u16_r4, alu_div_u16_r5, alu_div_u16_r6, alu_div_u16_r7, alu_divisor_hi, alu_divisor_lo, alu_ff_tag, alu_ia, alu_ib, alu_ic, alu_in_tag, alu_op_add, alu_op_cast, alu_op_cast_prev, alu_op_div, alu_op_div_a_lt_b, alu_op_div_std, alu_op_eq, alu_op_eq_diff_inv, alu_op_lt, alu_op_lte, alu_op_mul, alu_op_not, alu_op_shl, alu_op_shr, alu_op_sub, alu_p_a_borrow, alu_p_b_borrow, alu_p_sub_a_hi, alu_p_sub_a_lo, alu_p_sub_b_hi, alu_p_sub_b_lo, alu_partial_prod_hi, alu_partial_prod_lo, alu_quotient_hi, alu_quotient_lo, alu_remainder, alu_res_hi, alu_res_lo, alu_sel_alu, alu_sel_cmp, alu_sel_div_rng_chk, alu_sel_rng_chk, alu_sel_rng_chk_lookup, alu_sel_shift_which, alu_shift_lt_bit_len, alu_t_sub_s_bits, alu_two_pow_s, alu_two_pow_t_sub_s, alu_u128_tag, alu_u16_r0, alu_u16_r1, alu_u16_r10, alu_u16_r11, alu_u16_r12, alu_u16_r13, alu_u16_r14, alu_u16_r2, alu_u16_r3, alu_u16_r4, alu_u16_r5, alu_u16_r6, alu_u16_r7, alu_u16_r8, alu_u16_r9, alu_u16_tag, alu_u32_tag, alu_u64_tag, alu_u8_r0, alu_u8_r1, alu_u8_tag, binary_acc_ia, binary_acc_ib, binary_acc_ic, binary_clk, binary_ia_bytes, binary_ib_bytes, binary_ic_bytes, binary_in_tag, binary_mem_tag_ctr, binary_mem_tag_ctr_inv, binary_op_id, binary_sel_bin, binary_start, conversion_clk, conversion_input, conversion_num_limbs, conversion_radix, conversion_sel_to_radix_le, keccakf1600_clk, keccakf1600_input, keccakf1600_output, keccakf1600_sel_keccakf1600, main_abs_da_rem_gas_hi, main_abs_da_rem_gas_lo, main_abs_l2_rem_gas_hi, main_abs_l2_rem_gas_lo, main_alu_in_tag, main_base_da_gas_op_cost, main_base_l2_gas_op_cost, main_bin_op_id, main_call_ptr, main_da_gas_remaining, main_da_out_of_gas, main_dyn_da_gas_op_cost, main_dyn_gas_multiplier, main_dyn_l2_gas_op_cost, main_emit_l2_to_l1_msg_write_offset, main_emit_note_hash_write_offset, main_emit_nullifier_write_offset, main_emit_unencrypted_log_write_offset, main_ia, main_ib, main_ic, main_id, main_id_zero, main_ind_addr_a, main_ind_addr_b, main_ind_addr_c, main_ind_addr_d, main_internal_return_ptr, main_inv, main_kernel_in_offset, main_kernel_out_offset, main_l1_to_l2_msg_exists_write_offset, main_l2_gas_remaining, main_l2_out_of_gas, main_mem_addr_a, main_mem_addr_b, main_mem_addr_c, main_mem_addr_d, main_note_hash_exist_write_offset, main_nullifier_exists_write_offset, main_nullifier_non_exists_write_offset, main_op_err, main_opcode_val, main_pc, main_r_in_tag, main_rwa, main_rwb, main_rwc, main_rwd, main_sel_alu, main_sel_bin, main_sel_calldata, main_sel_execution_row, main_sel_kernel_inputs, main_sel_kernel_out, main_sel_last, main_sel_mem_op_a, main_sel_mem_op_b, main_sel_mem_op_c, main_sel_mem_op_d, main_sel_mov_ia_to_ic, main_sel_mov_ib_to_ic, main_sel_op_add, main_sel_op_address, main_sel_op_and, main_sel_op_block_number, main_sel_op_calldata_copy, main_sel_op_cast, main_sel_op_chain_id, main_sel_op_cmov, main_sel_op_coinbase, main_sel_op_dagasleft, main_sel_op_div, main_sel_op_ecadd, main_sel_op_emit_l2_to_l1_msg, main_sel_op_emit_note_hash, main_sel_op_emit_nullifier, main_sel_op_emit_unencrypted_log, main_sel_op_eq, main_sel_op_external_call, main_sel_op_external_return, main_sel_op_external_revert, main_sel_op_fdiv, main_sel_op_fee_per_da_gas, main_sel_op_fee_per_l2_gas, main_sel_op_function_selector, main_sel_op_get_contract_instance, main_sel_op_internal_call, main_sel_op_internal_return, main_sel_op_jump, main_sel_op_jumpi, main_sel_op_keccak, main_sel_op_l1_to_l2_msg_exists, main_sel_op_l2gasleft, main_sel_op_lt, main_sel_op_lte, main_sel_op_mov, main_sel_op_msm, main_sel_op_mul, main_sel_op_not, main_sel_op_note_hash_exists, main_sel_op_nullifier_exists, main_sel_op_or, main_sel_op_pedersen, main_sel_op_pedersen_commit, main_sel_op_poseidon2, main_sel_op_radix_le, main_sel_op_sender, main_sel_op_set, main_sel_op_sha256, main_sel_op_shl, main_sel_op_shr, main_sel_op_sload, main_sel_op_sstore, main_sel_op_storage_address, main_sel_op_sub, main_sel_op_timestamp, main_sel_op_transaction_fee, main_sel_op_version, main_sel_op_xor, main_sel_q_kernel_lookup, main_sel_q_kernel_output_lookup, main_sel_resolve_ind_addr_a, main_sel_resolve_ind_addr_b, main_sel_resolve_ind_addr_c, main_sel_resolve_ind_addr_d, main_sel_returndata, main_sel_rng_16, main_sel_rng_8, main_sel_slice_gadget, main_side_effect_counter, main_sload_write_offset, main_space_id, main_sstore_write_offset, main_tag_err, main_w_in_tag, mem_addr, mem_clk, mem_diff_hi, mem_diff_lo, mem_diff_mid, mem_glob_addr, mem_last, mem_lastAccess, mem_one_min_inv, mem_r_in_tag, mem_rw, mem_sel_mem, mem_sel_mov_ia_to_ic, mem_sel_mov_ib_to_ic, mem_sel_op_a, mem_sel_op_b, mem_sel_op_c, mem_sel_op_cmov, mem_sel_op_d, mem_sel_op_poseidon_read_a, mem_sel_op_poseidon_read_b, mem_sel_op_poseidon_read_c, mem_sel_op_poseidon_read_d, mem_sel_op_poseidon_write_a, mem_sel_op_poseidon_write_b, mem_sel_op_poseidon_write_c, mem_sel_op_poseidon_write_d, mem_sel_op_slice, mem_sel_resolve_ind_addr_a, mem_sel_resolve_ind_addr_b, mem_sel_resolve_ind_addr_c, mem_sel_resolve_ind_addr_d, mem_sel_rng_chk, mem_skip_check_tag, mem_space_id, mem_tag, mem_tag_err, mem_tsp, mem_val, mem_w_in_tag, pedersen_clk, pedersen_input, pedersen_output, pedersen_sel_pedersen, poseidon2_B_10_0, poseidon2_B_10_1, poseidon2_B_10_2, poseidon2_B_10_3, poseidon2_B_11_0, poseidon2_B_11_1, poseidon2_B_11_2, poseidon2_B_11_3, poseidon2_B_12_0, poseidon2_B_12_1, poseidon2_B_12_2, poseidon2_B_12_3, poseidon2_B_13_0, poseidon2_B_13_1, poseidon2_B_13_2, poseidon2_B_13_3, poseidon2_B_14_0, poseidon2_B_14_1, poseidon2_B_14_2, poseidon2_B_14_3, poseidon2_B_15_0, poseidon2_B_15_1, poseidon2_B_15_2, poseidon2_B_15_3, poseidon2_B_16_0, poseidon2_B_16_1, poseidon2_B_16_2, poseidon2_B_16_3, poseidon2_B_17_0, poseidon2_B_17_1, poseidon2_B_17_2, poseidon2_B_17_3, poseidon2_B_18_0, poseidon2_B_18_1, poseidon2_B_18_2, poseidon2_B_18_3, poseidon2_B_19_0, poseidon2_B_19_1, poseidon2_B_19_2, poseidon2_B_19_3, poseidon2_B_20_0, poseidon2_B_20_1, poseidon2_B_20_2, poseidon2_B_20_3, poseidon2_B_21_0, poseidon2_B_21_1, poseidon2_B_21_2, poseidon2_B_21_3, poseidon2_B_22_0, poseidon2_B_22_1, poseidon2_B_22_2, poseidon2_B_22_3, poseidon2_B_23_0, poseidon2_B_23_1, poseidon2_B_23_2, poseidon2_B_23_3, poseidon2_B_24_0, poseidon2_B_24_1, poseidon2_B_24_2, poseidon2_B_24_3, poseidon2_B_25_0, poseidon2_B_25_1, poseidon2_B_25_2, poseidon2_B_25_3, poseidon2_B_26_0, poseidon2_B_26_1, poseidon2_B_26_2, poseidon2_B_26_3, poseidon2_B_27_0, poseidon2_B_27_1, poseidon2_B_27_2, poseidon2_B_27_3, poseidon2_B_28_0, poseidon2_B_28_1, poseidon2_B_28_2, poseidon2_B_28_3, poseidon2_B_29_0, poseidon2_B_29_1, poseidon2_B_29_2, poseidon2_B_29_3, poseidon2_B_30_0, poseidon2_B_30_1, poseidon2_B_30_2, poseidon2_B_30_3, poseidon2_B_31_0, poseidon2_B_31_1, poseidon2_B_31_2, poseidon2_B_31_3, poseidon2_B_32_0, poseidon2_B_32_1, poseidon2_B_32_2, poseidon2_B_32_3, poseidon2_B_33_0, poseidon2_B_33_1, poseidon2_B_33_2, poseidon2_B_33_3, poseidon2_B_34_0, poseidon2_B_34_1, poseidon2_B_34_2, poseidon2_B_34_3, poseidon2_B_35_0, poseidon2_B_35_1, poseidon2_B_35_2, poseidon2_B_35_3, poseidon2_B_36_0, poseidon2_B_36_1, poseidon2_B_36_2, poseidon2_B_36_3, poseidon2_B_37_0, poseidon2_B_37_1, poseidon2_B_37_2, poseidon2_B_37_3, poseidon2_B_38_0, poseidon2_B_38_1, poseidon2_B_38_2, poseidon2_B_38_3, poseidon2_B_39_0, poseidon2_B_39_1, poseidon2_B_39_2, poseidon2_B_39_3, poseidon2_B_40_0, poseidon2_B_40_1, poseidon2_B_40_2, poseidon2_B_40_3, poseidon2_B_41_0, poseidon2_B_41_1, poseidon2_B_41_2, poseidon2_B_41_3, poseidon2_B_42_0, poseidon2_B_42_1, poseidon2_B_42_2, poseidon2_B_42_3, poseidon2_B_43_0, poseidon2_B_43_1, poseidon2_B_43_2, poseidon2_B_43_3, poseidon2_B_44_0, poseidon2_B_44_1, poseidon2_B_44_2, poseidon2_B_44_3, poseidon2_B_45_0, poseidon2_B_45_1, poseidon2_B_45_2, poseidon2_B_45_3, poseidon2_B_46_0, poseidon2_B_46_1, poseidon2_B_46_2, poseidon2_B_46_3, poseidon2_B_47_0, poseidon2_B_47_1, poseidon2_B_47_2, poseidon2_B_47_3, poseidon2_B_48_0, poseidon2_B_48_1, poseidon2_B_48_2, poseidon2_B_48_3, poseidon2_B_49_0, poseidon2_B_49_1, poseidon2_B_49_2, poseidon2_B_49_3, poseidon2_B_4_0, poseidon2_B_4_1, poseidon2_B_4_2, poseidon2_B_4_3, poseidon2_B_50_0, poseidon2_B_50_1, poseidon2_B_50_2, poseidon2_B_50_3, poseidon2_B_51_0, poseidon2_B_51_1, poseidon2_B_51_2, poseidon2_B_51_3, poseidon2_B_52_0, poseidon2_B_52_1, poseidon2_B_52_2, poseidon2_B_52_3, poseidon2_B_53_0, poseidon2_B_53_1, poseidon2_B_53_2, poseidon2_B_53_3, poseidon2_B_54_0, poseidon2_B_54_1, poseidon2_B_54_2, poseidon2_B_54_3, poseidon2_B_55_0, poseidon2_B_55_1, poseidon2_B_55_2, poseidon2_B_55_3, poseidon2_B_56_0, poseidon2_B_56_1, poseidon2_B_56_2, poseidon2_B_56_3, poseidon2_B_57_0, poseidon2_B_57_1, poseidon2_B_57_2, poseidon2_B_57_3, poseidon2_B_58_0, poseidon2_B_58_1, poseidon2_B_58_2, poseidon2_B_58_3, poseidon2_B_59_0, poseidon2_B_59_1, poseidon2_B_59_2, poseidon2_B_59_3, poseidon2_B_5_0, poseidon2_B_5_1, poseidon2_B_5_2, poseidon2_B_5_3, poseidon2_B_6_0, poseidon2_B_6_1, poseidon2_B_6_2, poseidon2_B_6_3, poseidon2_B_7_0, poseidon2_B_7_1, poseidon2_B_7_2, poseidon2_B_7_3, poseidon2_B_8_0, poseidon2_B_8_1, poseidon2_B_8_2, poseidon2_B_8_3, poseidon2_B_9_0, poseidon2_B_9_1, poseidon2_B_9_2, poseidon2_B_9_3, poseidon2_EXT_LAYER_4, poseidon2_EXT_LAYER_5, poseidon2_EXT_LAYER_6, poseidon2_EXT_LAYER_7, poseidon2_T_0_4, poseidon2_T_0_5, poseidon2_T_0_6, poseidon2_T_0_7, poseidon2_T_1_4, poseidon2_T_1_5, poseidon2_T_1_6, poseidon2_T_1_7, poseidon2_T_2_4, poseidon2_T_2_5, poseidon2_T_2_6, poseidon2_T_2_7, poseidon2_T_3_4, poseidon2_T_3_5, poseidon2_T_3_6, poseidon2_T_3_7, poseidon2_T_60_4, poseidon2_T_60_5, poseidon2_T_60_6, poseidon2_T_60_7, poseidon2_T_61_4, poseidon2_T_61_5, poseidon2_T_61_6, poseidon2_T_61_7, poseidon2_T_62_4, poseidon2_T_62_5, poseidon2_T_62_6, poseidon2_T_62_7, poseidon2_T_63_4, poseidon2_T_63_5, poseidon2_T_63_6, poseidon2_T_63_7, poseidon2_a_0, poseidon2_a_1, poseidon2_a_2, poseidon2_a_3, poseidon2_b_0, poseidon2_b_1, poseidon2_b_2, poseidon2_b_3, poseidon2_clk, poseidon2_input_addr, poseidon2_mem_addr_read_a, poseidon2_mem_addr_read_b, poseidon2_mem_addr_read_c, poseidon2_mem_addr_read_d, poseidon2_mem_addr_write_a, poseidon2_mem_addr_write_b, poseidon2_mem_addr_write_c, poseidon2_mem_addr_write_d, poseidon2_output_addr, poseidon2_sel_poseidon_perm, sha256_clk, sha256_input, sha256_output, sha256_sel_sha256_compression, sha256_state, slice_addr, slice_clk, slice_cnt, slice_col_offset, slice_one_min_inv, slice_sel_cd_cpy, slice_sel_mem_active, slice_sel_return, slice_sel_start, slice_space_id, slice_val, lookup_byte_lengths_counts, lookup_byte_operations_counts, lookup_opcode_gas_counts, range_check_l2_gas_hi_counts, range_check_l2_gas_lo_counts, range_check_da_gas_hi_counts, range_check_da_gas_lo_counts, kernel_output_lookup_counts, lookup_into_kernel_counts, lookup_cd_value_counts, lookup_ret_value_counts, incl_main_tag_err_counts, incl_mem_tag_err_counts, lookup_mem_rng_chk_lo_counts, lookup_mem_rng_chk_mid_counts, lookup_mem_rng_chk_hi_counts, lookup_pow_2_0_counts, lookup_pow_2_1_counts, lookup_u8_0_counts, lookup_u8_1_counts, lookup_u16_0_counts, lookup_u16_1_counts, lookup_u16_2_counts, lookup_u16_3_counts, lookup_u16_4_counts, lookup_u16_5_counts, lookup_u16_6_counts, lookup_u16_7_counts, lookup_u16_8_counts, lookup_u16_9_counts, lookup_u16_10_counts, lookup_u16_11_counts, lookup_u16_12_counts, lookup_u16_13_counts, lookup_u16_14_counts, lookup_div_u16_0_counts, lookup_div_u16_1_counts, lookup_div_u16_2_counts, lookup_div_u16_3_counts, lookup_div_u16_4_counts, lookup_div_u16_5_counts, lookup_div_u16_6_counts, lookup_div_u16_7_counts +#define DERIVED_WITNESS_ENTITIES perm_pos_mem_read_a_inv, perm_pos_mem_read_b_inv, perm_pos_mem_read_c_inv, perm_pos_mem_read_d_inv, perm_pos_mem_write_a_inv, perm_pos_mem_write_b_inv, perm_pos_mem_write_c_inv, perm_pos_mem_write_d_inv, perm_slice_mem_inv, perm_main_alu_inv, perm_main_bin_inv, perm_main_conv_inv, perm_main_pos2_perm_inv, perm_main_pedersen_inv, perm_main_slice_inv, perm_main_mem_a_inv, perm_main_mem_b_inv, perm_main_mem_c_inv, perm_main_mem_d_inv, perm_main_mem_ind_addr_a_inv, perm_main_mem_ind_addr_b_inv, perm_main_mem_ind_addr_c_inv, perm_main_mem_ind_addr_d_inv, lookup_byte_lengths_inv, lookup_byte_operations_inv, lookup_opcode_gas_inv, range_check_l2_gas_hi_inv, range_check_l2_gas_lo_inv, range_check_da_gas_hi_inv, range_check_da_gas_lo_inv, kernel_output_lookup_inv, lookup_into_kernel_inv, lookup_cd_value_inv, lookup_ret_value_inv, incl_main_tag_err_inv, incl_mem_tag_err_inv, lookup_mem_rng_chk_lo_inv, lookup_mem_rng_chk_mid_inv, lookup_mem_rng_chk_hi_inv, lookup_pow_2_0_inv, lookup_pow_2_1_inv, lookup_u8_0_inv, lookup_u8_1_inv, lookup_u16_0_inv, lookup_u16_1_inv, lookup_u16_2_inv, lookup_u16_3_inv, lookup_u16_4_inv, lookup_u16_5_inv, lookup_u16_6_inv, lookup_u16_7_inv, lookup_u16_8_inv, lookup_u16_9_inv, lookup_u16_10_inv, lookup_u16_11_inv, lookup_u16_12_inv, lookup_u16_13_inv, lookup_u16_14_inv, lookup_div_u16_0_inv, lookup_div_u16_1_inv, lookup_div_u16_2_inv, lookup_div_u16_3_inv, lookup_div_u16_4_inv, lookup_div_u16_5_inv, lookup_div_u16_6_inv, lookup_div_u16_7_inv +#define SHIFTED_ENTITIES alu_a_hi_shift, alu_a_lo_shift, alu_b_hi_shift, alu_b_lo_shift, alu_cmp_rng_ctr_shift, alu_div_u16_r0_shift, alu_div_u16_r1_shift, alu_div_u16_r2_shift, alu_div_u16_r3_shift, alu_div_u16_r4_shift, alu_div_u16_r5_shift, alu_div_u16_r6_shift, alu_div_u16_r7_shift, alu_op_add_shift, alu_op_cast_shift, alu_op_cast_prev_shift, alu_op_div_shift, alu_op_mul_shift, alu_op_shl_shift, alu_op_shr_shift, alu_op_sub_shift, alu_p_sub_a_hi_shift, alu_p_sub_a_lo_shift, alu_p_sub_b_hi_shift, alu_p_sub_b_lo_shift, alu_sel_alu_shift, alu_sel_cmp_shift, alu_sel_div_rng_chk_shift, alu_sel_rng_chk_shift, alu_sel_rng_chk_lookup_shift, alu_u16_r0_shift, alu_u16_r1_shift, alu_u16_r2_shift, alu_u16_r3_shift, alu_u16_r4_shift, alu_u16_r5_shift, alu_u16_r6_shift, alu_u8_r0_shift, alu_u8_r1_shift, binary_acc_ia_shift, binary_acc_ib_shift, binary_acc_ic_shift, binary_mem_tag_ctr_shift, binary_op_id_shift, main_da_gas_remaining_shift, main_emit_l2_to_l1_msg_write_offset_shift, main_emit_note_hash_write_offset_shift, main_emit_nullifier_write_offset_shift, main_emit_unencrypted_log_write_offset_shift, main_internal_return_ptr_shift, main_l1_to_l2_msg_exists_write_offset_shift, main_l2_gas_remaining_shift, main_note_hash_exist_write_offset_shift, main_nullifier_exists_write_offset_shift, main_nullifier_non_exists_write_offset_shift, main_pc_shift, main_sel_execution_row_shift, main_side_effect_counter_shift, main_sload_write_offset_shift, main_sstore_write_offset_shift, mem_glob_addr_shift, mem_rw_shift, mem_sel_mem_shift, mem_tag_shift, mem_tsp_shift, mem_val_shift, slice_addr_shift, slice_clk_shift, slice_cnt_shift, slice_col_offset_shift, slice_sel_cd_cpy_shift, slice_sel_mem_active_shift, slice_sel_return_shift, slice_sel_start_shift, slice_space_id_shift +#define TO_BE_SHIFTED(e) e.alu_a_hi, e.alu_a_lo, e.alu_b_hi, e.alu_b_lo, e.alu_cmp_rng_ctr, e.alu_div_u16_r0, e.alu_div_u16_r1, e.alu_div_u16_r2, e.alu_div_u16_r3, e.alu_div_u16_r4, e.alu_div_u16_r5, e.alu_div_u16_r6, e.alu_div_u16_r7, e.alu_op_add, e.alu_op_cast, e.alu_op_cast_prev, e.alu_op_div, e.alu_op_mul, e.alu_op_shl, e.alu_op_shr, e.alu_op_sub, e.alu_p_sub_a_hi, e.alu_p_sub_a_lo, e.alu_p_sub_b_hi, e.alu_p_sub_b_lo, e.alu_sel_alu, e.alu_sel_cmp, e.alu_sel_div_rng_chk, e.alu_sel_rng_chk, e.alu_sel_rng_chk_lookup, e.alu_u16_r0, e.alu_u16_r1, e.alu_u16_r2, e.alu_u16_r3, e.alu_u16_r4, e.alu_u16_r5, e.alu_u16_r6, e.alu_u8_r0, e.alu_u8_r1, e.binary_acc_ia, e.binary_acc_ib, e.binary_acc_ic, e.binary_mem_tag_ctr, e.binary_op_id, e.main_da_gas_remaining, e.main_emit_l2_to_l1_msg_write_offset, e.main_emit_note_hash_write_offset, e.main_emit_nullifier_write_offset, e.main_emit_unencrypted_log_write_offset, e.main_internal_return_ptr, e.main_l1_to_l2_msg_exists_write_offset, e.main_l2_gas_remaining, e.main_note_hash_exist_write_offset, e.main_nullifier_exists_write_offset, e.main_nullifier_non_exists_write_offset, e.main_pc, e.main_sel_execution_row, e.main_side_effect_counter, e.main_sload_write_offset, e.main_sstore_write_offset, e.mem_glob_addr, e.mem_rw, e.mem_sel_mem, e.mem_tag, e.mem_tsp, e.mem_val, e.slice_addr, e.slice_clk, e.slice_cnt, e.slice_col_offset, e.slice_sel_cd_cpy, e.slice_sel_mem_active, e.slice_sel_return, e.slice_sel_start, e.slice_space_id #define ALL_ENTITIES PRECOMPUTED_ENTITIES, WIRE_ENTITIES, DERIVED_WITNESS_ENTITIES, SHIFTED_ENTITIES // clang-format on @@ -128,6 +127,9 @@ class AvmFlavor { using VerifierCommitmentKey = AvmFlavorSettings::VerifierCommitmentKey; using RelationSeparator = AvmFlavorSettings::RelationSeparator; + // This flavor would not be used with ZK Sumcheck + static constexpr bool HasZK = false; + static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 16; static constexpr size_t NUM_WITNESS_ENTITIES = 696; static constexpr size_t NUM_SHIFTED_ENTITIES = 75; @@ -135,6 +137,8 @@ class AvmFlavor { // We have two copies of the witness entities, so we subtract the number of fixed ones (they have no shift), one for // the unshifted and one for the shifted static constexpr size_t NUM_ALL_ENTITIES = 787; + // The total number of witnesses including shifts and derived entities. + static constexpr size_t NUM_ALL_WITNESS_ENTITIES = NUM_WITNESS_ENTITIES + NUM_SHIFTED_ENTITIES; using MainRelations = std::tuple< // Relations @@ -337,7 +341,7 @@ class AvmFlavor { ProverPolynomials(ProvingKey& proving_key); - [[nodiscard]] size_t get_polynomial_size() const { return kernel_kernel_inputs.size(); } + [[nodiscard]] size_t get_polynomial_size() const { return main_kernel_inputs.size(); } /** * @brief Returns the evaluations of all prover polynomials at one point on the boolean hypercube, which * represents one row in the execution trace. @@ -415,4 +419,4 @@ class AvmFlavor { }; }; -} // namespace bb \ No newline at end of file +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/generated/full_row.cpp b/barretenberg/cpp/src/barretenberg/vm/avm/generated/full_row.cpp index b06fa434c4da..8a9e2d32c814 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/generated/full_row.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/generated/full_row.cpp @@ -35,10 +35,10 @@ template std::vector AvmFullRow::names() "main_sel_first", "main_zeroes", "powers_power_of_2", - "kernel_kernel_inputs", - "kernel_kernel_value_out", - "kernel_kernel_side_effect_out", - "kernel_kernel_metadata_out", + "main_kernel_inputs", + "main_kernel_value_out", + "main_kernel_side_effect_out", + "main_kernel_metadata_out", "main_calldata", "main_returndata", "alu_a_hi", @@ -146,21 +146,6 @@ template std::vector AvmFullRow::names() "keccakf1600_input", "keccakf1600_output", "keccakf1600_sel_keccakf1600", - "kernel_emit_l2_to_l1_msg_write_offset", - "kernel_emit_note_hash_write_offset", - "kernel_emit_nullifier_write_offset", - "kernel_emit_unencrypted_log_write_offset", - "kernel_kernel_in_offset", - "kernel_kernel_out_offset", - "kernel_l1_to_l2_msg_exists_write_offset", - "kernel_note_hash_exist_write_offset", - "kernel_nullifier_exists_write_offset", - "kernel_nullifier_non_exists_write_offset", - "kernel_q_public_input_kernel_add_to_table", - "kernel_q_public_input_kernel_out_add_to_table", - "kernel_side_effect_counter", - "kernel_sload_write_offset", - "kernel_sstore_write_offset", "main_abs_da_rem_gas_hi", "main_abs_da_rem_gas_lo", "main_abs_l2_rem_gas_hi", @@ -175,6 +160,10 @@ template std::vector AvmFullRow::names() "main_dyn_da_gas_op_cost", "main_dyn_gas_multiplier", "main_dyn_l2_gas_op_cost", + "main_emit_l2_to_l1_msg_write_offset", + "main_emit_note_hash_write_offset", + "main_emit_nullifier_write_offset", + "main_emit_unencrypted_log_write_offset", "main_ia", "main_ib", "main_ic", @@ -186,12 +175,18 @@ template std::vector AvmFullRow::names() "main_ind_addr_d", "main_internal_return_ptr", "main_inv", + "main_kernel_in_offset", + "main_kernel_out_offset", + "main_l1_to_l2_msg_exists_write_offset", "main_l2_gas_remaining", "main_l2_out_of_gas", "main_mem_addr_a", "main_mem_addr_b", "main_mem_addr_c", "main_mem_addr_d", + "main_note_hash_exist_write_offset", + "main_nullifier_exists_write_offset", + "main_nullifier_non_exists_write_offset", "main_op_err", "main_opcode_val", "main_pc", @@ -204,6 +199,8 @@ template std::vector AvmFullRow::names() "main_sel_bin", "main_sel_calldata", "main_sel_execution_row", + "main_sel_kernel_inputs", + "main_sel_kernel_out", "main_sel_last", "main_sel_mem_op_a", "main_sel_mem_op_b", @@ -279,7 +276,10 @@ template std::vector AvmFullRow::names() "main_sel_rng_16", "main_sel_rng_8", "main_sel_slice_gadget", + "main_side_effect_counter", + "main_sload_write_offset", "main_space_id", + "main_sstore_write_offset", "main_tag_err", "main_w_in_tag", "mem_addr", @@ -652,10 +652,10 @@ template std::vector AvmFullRow::names() "range_check_l2_gas_lo_inv", "range_check_da_gas_hi_inv", "range_check_da_gas_lo_inv", - "lookup_cd_value_inv", - "lookup_ret_value_inv", "kernel_output_lookup_inv", "lookup_into_kernel_inv", + "lookup_cd_value_inv", + "lookup_ret_value_inv", "incl_main_tag_err_inv", "incl_mem_tag_err_inv", "lookup_mem_rng_chk_lo_inv", @@ -695,10 +695,10 @@ template std::vector AvmFullRow::names() "range_check_l2_gas_lo_counts", "range_check_da_gas_hi_counts", "range_check_da_gas_lo_counts", - "lookup_cd_value_counts", - "lookup_ret_value_counts", "kernel_output_lookup_counts", "lookup_into_kernel_counts", + "lookup_cd_value_counts", + "lookup_ret_value_counts", "incl_main_tag_err_counts", "incl_mem_tag_err_counts", "lookup_mem_rng_chk_lo_counts", @@ -752,10 +752,10 @@ template RefVector AvmFullRow::as_vector() const main_sel_first, main_zeroes, powers_power_of_2, - kernel_kernel_inputs, - kernel_kernel_value_out, - kernel_kernel_side_effect_out, - kernel_kernel_metadata_out, + main_kernel_inputs, + main_kernel_value_out, + main_kernel_side_effect_out, + main_kernel_metadata_out, main_calldata, main_returndata, alu_a_hi, @@ -863,21 +863,6 @@ template RefVector AvmFullRow::as_vector() const keccakf1600_input, keccakf1600_output, keccakf1600_sel_keccakf1600, - kernel_emit_l2_to_l1_msg_write_offset, - kernel_emit_note_hash_write_offset, - kernel_emit_nullifier_write_offset, - kernel_emit_unencrypted_log_write_offset, - kernel_kernel_in_offset, - kernel_kernel_out_offset, - kernel_l1_to_l2_msg_exists_write_offset, - kernel_note_hash_exist_write_offset, - kernel_nullifier_exists_write_offset, - kernel_nullifier_non_exists_write_offset, - kernel_q_public_input_kernel_add_to_table, - kernel_q_public_input_kernel_out_add_to_table, - kernel_side_effect_counter, - kernel_sload_write_offset, - kernel_sstore_write_offset, main_abs_da_rem_gas_hi, main_abs_da_rem_gas_lo, main_abs_l2_rem_gas_hi, @@ -892,6 +877,10 @@ template RefVector AvmFullRow::as_vector() const main_dyn_da_gas_op_cost, main_dyn_gas_multiplier, main_dyn_l2_gas_op_cost, + main_emit_l2_to_l1_msg_write_offset, + main_emit_note_hash_write_offset, + main_emit_nullifier_write_offset, + main_emit_unencrypted_log_write_offset, main_ia, main_ib, main_ic, @@ -903,12 +892,18 @@ template RefVector AvmFullRow::as_vector() const main_ind_addr_d, main_internal_return_ptr, main_inv, + main_kernel_in_offset, + main_kernel_out_offset, + main_l1_to_l2_msg_exists_write_offset, main_l2_gas_remaining, main_l2_out_of_gas, main_mem_addr_a, main_mem_addr_b, main_mem_addr_c, main_mem_addr_d, + main_note_hash_exist_write_offset, + main_nullifier_exists_write_offset, + main_nullifier_non_exists_write_offset, main_op_err, main_opcode_val, main_pc, @@ -921,6 +916,8 @@ template RefVector AvmFullRow::as_vector() const main_sel_bin, main_sel_calldata, main_sel_execution_row, + main_sel_kernel_inputs, + main_sel_kernel_out, main_sel_last, main_sel_mem_op_a, main_sel_mem_op_b, @@ -996,7 +993,10 @@ template RefVector AvmFullRow::as_vector() const main_sel_rng_16, main_sel_rng_8, main_sel_slice_gadget, + main_side_effect_counter, + main_sload_write_offset, main_space_id, + main_sstore_write_offset, main_tag_err, main_w_in_tag, mem_addr, @@ -1369,10 +1369,10 @@ template RefVector AvmFullRow::as_vector() const range_check_l2_gas_lo_inv, range_check_da_gas_hi_inv, range_check_da_gas_lo_inv, - lookup_cd_value_inv, - lookup_ret_value_inv, kernel_output_lookup_inv, lookup_into_kernel_inv, + lookup_cd_value_inv, + lookup_ret_value_inv, incl_main_tag_err_inv, incl_mem_tag_err_inv, lookup_mem_rng_chk_lo_inv, @@ -1412,10 +1412,10 @@ template RefVector AvmFullRow::as_vector() const range_check_l2_gas_lo_counts, range_check_da_gas_hi_counts, range_check_da_gas_lo_counts, - lookup_cd_value_counts, - lookup_ret_value_counts, kernel_output_lookup_counts, lookup_into_kernel_counts, + lookup_cd_value_counts, + lookup_ret_value_counts, incl_main_tag_err_counts, incl_mem_tag_err_counts, lookup_mem_rng_chk_lo_counts, diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/generated/full_row.hpp b/barretenberg/cpp/src/barretenberg/vm/avm/generated/full_row.hpp index 5b4b63b6b26a..07e82e9798fe 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/generated/full_row.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/generated/full_row.hpp @@ -26,10 +26,10 @@ template struct AvmFullRow { FF main_sel_first{}; FF main_zeroes{}; FF powers_power_of_2{}; - FF kernel_kernel_inputs{}; - FF kernel_kernel_value_out{}; - FF kernel_kernel_side_effect_out{}; - FF kernel_kernel_metadata_out{}; + FF main_kernel_inputs{}; + FF main_kernel_value_out{}; + FF main_kernel_side_effect_out{}; + FF main_kernel_metadata_out{}; FF main_calldata{}; FF main_returndata{}; FF alu_a_hi{}; @@ -137,21 +137,6 @@ template struct AvmFullRow { FF keccakf1600_input{}; FF keccakf1600_output{}; FF keccakf1600_sel_keccakf1600{}; - FF kernel_emit_l2_to_l1_msg_write_offset{}; - FF kernel_emit_note_hash_write_offset{}; - FF kernel_emit_nullifier_write_offset{}; - FF kernel_emit_unencrypted_log_write_offset{}; - FF kernel_kernel_in_offset{}; - FF kernel_kernel_out_offset{}; - FF kernel_l1_to_l2_msg_exists_write_offset{}; - FF kernel_note_hash_exist_write_offset{}; - FF kernel_nullifier_exists_write_offset{}; - FF kernel_nullifier_non_exists_write_offset{}; - FF kernel_q_public_input_kernel_add_to_table{}; - FF kernel_q_public_input_kernel_out_add_to_table{}; - FF kernel_side_effect_counter{}; - FF kernel_sload_write_offset{}; - FF kernel_sstore_write_offset{}; FF main_abs_da_rem_gas_hi{}; FF main_abs_da_rem_gas_lo{}; FF main_abs_l2_rem_gas_hi{}; @@ -166,6 +151,10 @@ template struct AvmFullRow { FF main_dyn_da_gas_op_cost{}; FF main_dyn_gas_multiplier{}; FF main_dyn_l2_gas_op_cost{}; + FF main_emit_l2_to_l1_msg_write_offset{}; + FF main_emit_note_hash_write_offset{}; + FF main_emit_nullifier_write_offset{}; + FF main_emit_unencrypted_log_write_offset{}; FF main_ia{}; FF main_ib{}; FF main_ic{}; @@ -177,12 +166,18 @@ template struct AvmFullRow { FF main_ind_addr_d{}; FF main_internal_return_ptr{}; FF main_inv{}; + FF main_kernel_in_offset{}; + FF main_kernel_out_offset{}; + FF main_l1_to_l2_msg_exists_write_offset{}; FF main_l2_gas_remaining{}; FF main_l2_out_of_gas{}; FF main_mem_addr_a{}; FF main_mem_addr_b{}; FF main_mem_addr_c{}; FF main_mem_addr_d{}; + FF main_note_hash_exist_write_offset{}; + FF main_nullifier_exists_write_offset{}; + FF main_nullifier_non_exists_write_offset{}; FF main_op_err{}; FF main_opcode_val{}; FF main_pc{}; @@ -195,6 +190,8 @@ template struct AvmFullRow { FF main_sel_bin{}; FF main_sel_calldata{}; FF main_sel_execution_row{}; + FF main_sel_kernel_inputs{}; + FF main_sel_kernel_out{}; FF main_sel_last{}; FF main_sel_mem_op_a{}; FF main_sel_mem_op_b{}; @@ -270,7 +267,10 @@ template struct AvmFullRow { FF main_sel_rng_16{}; FF main_sel_rng_8{}; FF main_sel_slice_gadget{}; + FF main_side_effect_counter{}; + FF main_sload_write_offset{}; FF main_space_id{}; + FF main_sstore_write_offset{}; FF main_tag_err{}; FF main_w_in_tag{}; FF mem_addr{}; @@ -643,10 +643,10 @@ template struct AvmFullRow { FF range_check_l2_gas_lo_inv{}; FF range_check_da_gas_hi_inv{}; FF range_check_da_gas_lo_inv{}; - FF lookup_cd_value_inv{}; - FF lookup_ret_value_inv{}; FF kernel_output_lookup_inv{}; FF lookup_into_kernel_inv{}; + FF lookup_cd_value_inv{}; + FF lookup_ret_value_inv{}; FF incl_main_tag_err_inv{}; FF incl_mem_tag_err_inv{}; FF lookup_mem_rng_chk_lo_inv{}; @@ -686,10 +686,10 @@ template struct AvmFullRow { FF range_check_l2_gas_lo_counts{}; FF range_check_da_gas_hi_counts{}; FF range_check_da_gas_lo_counts{}; - FF lookup_cd_value_counts{}; - FF lookup_ret_value_counts{}; FF kernel_output_lookup_counts{}; FF lookup_into_kernel_counts{}; + FF lookup_cd_value_counts{}; + FF lookup_ret_value_counts{}; FF incl_main_tag_err_counts{}; FF incl_mem_tag_err_counts{}; FF lookup_mem_rng_chk_lo_counts{}; diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/generated/prover.cpp b/barretenberg/cpp/src/barretenberg/vm/avm/generated/prover.cpp index d5cbab1767e0..41e801b4c83d 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/generated/prover.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/generated/prover.cpp @@ -8,7 +8,6 @@ #include "barretenberg/honk/proof_system/logderivative_library.hpp" #include "barretenberg/honk/proof_system/permutation_library.hpp" #include "barretenberg/plonk_honk_shared/library/grand_product_library.hpp" -#include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/relations/permutation_relation.hpp" #include "barretenberg/sumcheck/sumcheck.hpp" diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/generated/relations/kernel.hpp b/barretenberg/cpp/src/barretenberg/vm/avm/generated/relations/kernel.hpp index b75bec675d73..6fa15bbad85b 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/generated/relations/kernel.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/generated/relations/kernel.hpp @@ -10,7 +10,9 @@ template class kernelImpl { public: using FF = FF_; - static constexpr std::array SUBRELATION_PARTIAL_LENGTHS = { 3, 3, 4, 4, 3, 3, 3, 3, 3, 3 }; + static constexpr std::array SUBRELATION_PARTIAL_LENGTHS = { 3, 3, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }; template void static accumulate(ContainerOverSubrelations& evals, @@ -18,88 +20,366 @@ template class kernelImpl { [[maybe_unused]] const RelationParameters&, [[maybe_unused]] const FF& scaling_factor) { - const auto kernel_NOT_LAST = (FF(1) - new_term.main_sel_last); + const auto constants_SENDER_SELECTOR = FF(0); + const auto constants_ADDRESS_SELECTOR = FF(1); + const auto constants_STORAGE_ADDRESS_SELECTOR = FF(1); + const auto constants_FUNCTION_SELECTOR_SELECTOR = FF(2); + const auto constants_CHAIN_ID_SELECTOR = FF(29); + const auto constants_VERSION_SELECTOR = FF(30); + const auto constants_BLOCK_NUMBER_SELECTOR = FF(31); + const auto constants_TIMESTAMP_SELECTOR = FF(33); + const auto constants_COINBASE_SELECTOR = FF(34); + const auto constants_FEE_PER_DA_GAS_SELECTOR = FF(36); + const auto constants_FEE_PER_L2_GAS_SELECTOR = FF(37); + const auto constants_TRANSACTION_FEE_SELECTOR = FF(41); + const auto constants_START_NOTE_HASH_EXISTS_WRITE_OFFSET = FF(0); + const auto constants_START_NULLIFIER_EXISTS_OFFSET = FF(16); + const auto constants_START_NULLIFIER_NON_EXISTS_OFFSET = FF(32); + const auto constants_START_L1_TO_L2_MSG_EXISTS_WRITE_OFFSET = FF(48); + const auto constants_START_SSTORE_WRITE_OFFSET = FF(64); + const auto constants_START_SLOAD_WRITE_OFFSET = FF(96); + const auto constants_START_EMIT_NOTE_HASH_WRITE_OFFSET = FF(128); + const auto constants_START_EMIT_NULLIFIER_WRITE_OFFSET = FF(144); + const auto constants_START_EMIT_L2_TO_L1_MSG_WRITE_OFFSET = FF(160); + const auto constants_START_EMIT_UNENCRYPTED_LOG_WRITE_OFFSET = FF(162); + const auto main_KERNEL_INPUT_SELECTORS = + (((((((((((new_term.main_sel_op_address + new_term.main_sel_op_storage_address) + + new_term.main_sel_op_sender) + + new_term.main_sel_op_function_selector) + + new_term.main_sel_op_transaction_fee) + + new_term.main_sel_op_chain_id) + + new_term.main_sel_op_version) + + new_term.main_sel_op_block_number) + + new_term.main_sel_op_coinbase) + + new_term.main_sel_op_timestamp) + + new_term.main_sel_op_fee_per_l2_gas) + + new_term.main_sel_op_fee_per_da_gas); + const auto main_KERNEL_OUTPUT_SELECTORS = + ((((((((new_term.main_sel_op_note_hash_exists + new_term.main_sel_op_emit_note_hash) + + new_term.main_sel_op_nullifier_exists) + + new_term.main_sel_op_emit_nullifier) + + new_term.main_sel_op_l1_to_l2_msg_exists) + + new_term.main_sel_op_emit_unencrypted_log) + + new_term.main_sel_op_emit_l2_to_l1_msg) + + new_term.main_sel_op_sload) + + new_term.main_sel_op_sstore); { using Accumulator = typename std::tuple_element_t<0, ContainerOverSubrelations>; - auto tmp = (kernel_NOT_LAST * - (new_term.kernel_note_hash_exist_write_offset_shift - - (new_term.kernel_note_hash_exist_write_offset + new_term.main_sel_op_note_hash_exists))); + auto tmp = (new_term.main_sel_execution_row * + (new_term.main_note_hash_exist_write_offset_shift - + (new_term.main_note_hash_exist_write_offset + new_term.main_sel_op_note_hash_exists))); tmp *= scaling_factor; std::get<0>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<1, ContainerOverSubrelations>; - auto tmp = (kernel_NOT_LAST * - (new_term.kernel_emit_note_hash_write_offset_shift - - (new_term.kernel_emit_note_hash_write_offset + new_term.main_sel_op_emit_note_hash))); + auto tmp = (new_term.main_sel_execution_row * + (new_term.main_emit_note_hash_write_offset_shift - + (new_term.main_emit_note_hash_write_offset + new_term.main_sel_op_emit_note_hash))); tmp *= scaling_factor; std::get<1>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<2, ContainerOverSubrelations>; - auto tmp = (kernel_NOT_LAST * (new_term.kernel_nullifier_exists_write_offset_shift - - (new_term.kernel_nullifier_exists_write_offset + - (new_term.main_sel_op_nullifier_exists * new_term.main_ib)))); + auto tmp = + (new_term.main_sel_execution_row * (new_term.main_nullifier_exists_write_offset_shift - + (new_term.main_nullifier_exists_write_offset + + (new_term.main_sel_op_nullifier_exists * new_term.main_ib)))); tmp *= scaling_factor; std::get<2>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<3, ContainerOverSubrelations>; - auto tmp = (kernel_NOT_LAST * (new_term.kernel_nullifier_non_exists_write_offset_shift - - (new_term.kernel_nullifier_non_exists_write_offset + - (new_term.main_sel_op_nullifier_exists * (FF(1) - new_term.main_ib))))); + auto tmp = (new_term.main_sel_execution_row * + (new_term.main_nullifier_non_exists_write_offset_shift - + (new_term.main_nullifier_non_exists_write_offset + + (new_term.main_sel_op_nullifier_exists * (FF(1) - new_term.main_ib))))); tmp *= scaling_factor; std::get<3>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<4, ContainerOverSubrelations>; - auto tmp = (kernel_NOT_LAST * - (new_term.kernel_emit_nullifier_write_offset_shift - - (new_term.kernel_emit_nullifier_write_offset + new_term.main_sel_op_emit_nullifier))); + auto tmp = (new_term.main_sel_execution_row * + (new_term.main_emit_nullifier_write_offset_shift - + (new_term.main_emit_nullifier_write_offset + new_term.main_sel_op_emit_nullifier))); tmp *= scaling_factor; std::get<4>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<5, ContainerOverSubrelations>; - auto tmp = - (kernel_NOT_LAST * - (new_term.kernel_l1_to_l2_msg_exists_write_offset_shift - - (new_term.kernel_l1_to_l2_msg_exists_write_offset + new_term.main_sel_op_l1_to_l2_msg_exists))); + auto tmp = (new_term.main_sel_execution_row * + (new_term.main_l1_to_l2_msg_exists_write_offset_shift - + (new_term.main_l1_to_l2_msg_exists_write_offset + new_term.main_sel_op_l1_to_l2_msg_exists))); tmp *= scaling_factor; std::get<5>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<6, ContainerOverSubrelations>; auto tmp = - (kernel_NOT_LAST * - (new_term.kernel_emit_unencrypted_log_write_offset_shift - - (new_term.kernel_emit_unencrypted_log_write_offset + new_term.main_sel_op_emit_unencrypted_log))); + (new_term.main_sel_execution_row * + (new_term.main_emit_unencrypted_log_write_offset_shift - + (new_term.main_emit_unencrypted_log_write_offset + new_term.main_sel_op_emit_unencrypted_log))); tmp *= scaling_factor; std::get<6>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<7, ContainerOverSubrelations>; - auto tmp = (kernel_NOT_LAST * - (new_term.kernel_emit_l2_to_l1_msg_write_offset_shift - - (new_term.kernel_emit_l2_to_l1_msg_write_offset + new_term.main_sel_op_emit_l2_to_l1_msg))); + auto tmp = (new_term.main_sel_execution_row * + (new_term.main_emit_l2_to_l1_msg_write_offset_shift - + (new_term.main_emit_l2_to_l1_msg_write_offset + new_term.main_sel_op_emit_l2_to_l1_msg))); tmp *= scaling_factor; std::get<7>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<8, ContainerOverSubrelations>; - auto tmp = (kernel_NOT_LAST * (new_term.kernel_sload_write_offset_shift - - (new_term.kernel_sload_write_offset + new_term.main_sel_op_sload))); + auto tmp = + (new_term.main_sel_execution_row * (new_term.main_sload_write_offset_shift - + (new_term.main_sload_write_offset + new_term.main_sel_op_sload))); tmp *= scaling_factor; std::get<8>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<9, ContainerOverSubrelations>; - auto tmp = (kernel_NOT_LAST * (new_term.kernel_sstore_write_offset_shift - - (new_term.kernel_sstore_write_offset + new_term.main_sel_op_sstore))); + auto tmp = + (new_term.main_sel_execution_row * (new_term.main_sstore_write_offset_shift - + (new_term.main_sstore_write_offset + new_term.main_sel_op_sstore))); tmp *= scaling_factor; std::get<9>(evals) += typename Accumulator::View(tmp); } + { + using Accumulator = typename std::tuple_element_t<10, ContainerOverSubrelations>; + auto tmp = (new_term.main_sel_op_address * (new_term.main_kernel_in_offset - constants_ADDRESS_SELECTOR)); + tmp *= scaling_factor; + std::get<10>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<11, ContainerOverSubrelations>; + auto tmp = (new_term.main_sel_op_storage_address * + (new_term.main_kernel_in_offset - constants_STORAGE_ADDRESS_SELECTOR)); + tmp *= scaling_factor; + std::get<11>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<12, ContainerOverSubrelations>; + auto tmp = (new_term.main_sel_op_sender * (new_term.main_kernel_in_offset - constants_SENDER_SELECTOR)); + tmp *= scaling_factor; + std::get<12>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<13, ContainerOverSubrelations>; + auto tmp = (new_term.main_sel_op_function_selector * + (new_term.main_kernel_in_offset - constants_FUNCTION_SELECTOR_SELECTOR)); + tmp *= scaling_factor; + std::get<13>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<14, ContainerOverSubrelations>; + auto tmp = (new_term.main_sel_op_transaction_fee * + (new_term.main_kernel_in_offset - constants_TRANSACTION_FEE_SELECTOR)); + tmp *= scaling_factor; + std::get<14>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<15, ContainerOverSubrelations>; + auto tmp = (new_term.main_sel_op_chain_id * (new_term.main_kernel_in_offset - constants_CHAIN_ID_SELECTOR)); + tmp *= scaling_factor; + std::get<15>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<16, ContainerOverSubrelations>; + auto tmp = (new_term.main_sel_op_version * (new_term.main_kernel_in_offset - constants_VERSION_SELECTOR)); + tmp *= scaling_factor; + std::get<16>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<17, ContainerOverSubrelations>; + auto tmp = (new_term.main_sel_op_block_number * + (new_term.main_kernel_in_offset - constants_BLOCK_NUMBER_SELECTOR)); + tmp *= scaling_factor; + std::get<17>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<18, ContainerOverSubrelations>; + auto tmp = + (new_term.main_sel_op_timestamp * (new_term.main_kernel_in_offset - constants_TIMESTAMP_SELECTOR)); + tmp *= scaling_factor; + std::get<18>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<19, ContainerOverSubrelations>; + auto tmp = (new_term.main_sel_op_coinbase * (new_term.main_kernel_in_offset - constants_COINBASE_SELECTOR)); + tmp *= scaling_factor; + std::get<19>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<20, ContainerOverSubrelations>; + auto tmp = (new_term.main_sel_op_fee_per_da_gas * + (new_term.main_kernel_in_offset - constants_FEE_PER_DA_GAS_SELECTOR)); + tmp *= scaling_factor; + std::get<20>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<21, ContainerOverSubrelations>; + auto tmp = (new_term.main_sel_op_fee_per_l2_gas * + (new_term.main_kernel_in_offset - constants_FEE_PER_L2_GAS_SELECTOR)); + tmp *= scaling_factor; + std::get<21>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<22, ContainerOverSubrelations>; + auto tmp = (new_term.main_sel_op_note_hash_exists * + (new_term.main_kernel_out_offset - + (constants_START_NOTE_HASH_EXISTS_WRITE_OFFSET + new_term.main_note_hash_exist_write_offset))); + tmp *= scaling_factor; + std::get<22>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<23, ContainerOverSubrelations>; + auto tmp = (new_term.main_sel_first * new_term.main_note_hash_exist_write_offset); + tmp *= scaling_factor; + std::get<23>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<24, ContainerOverSubrelations>; + auto tmp = (new_term.main_sel_op_emit_note_hash * + (new_term.main_kernel_out_offset - + (constants_START_EMIT_NOTE_HASH_WRITE_OFFSET + new_term.main_emit_note_hash_write_offset))); + tmp *= scaling_factor; + std::get<24>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<25, ContainerOverSubrelations>; + auto tmp = (new_term.main_sel_first * new_term.main_emit_note_hash_write_offset); + tmp *= scaling_factor; + std::get<25>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<26, ContainerOverSubrelations>; + auto tmp = (new_term.main_sel_op_nullifier_exists * + (new_term.main_kernel_out_offset - + ((new_term.main_ib * + (constants_START_NULLIFIER_EXISTS_OFFSET + new_term.main_nullifier_exists_write_offset)) + + ((FF(1) - new_term.main_ib) * (constants_START_NULLIFIER_NON_EXISTS_OFFSET + + new_term.main_nullifier_non_exists_write_offset))))); + tmp *= scaling_factor; + std::get<26>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<27, ContainerOverSubrelations>; + auto tmp = (new_term.main_sel_first * new_term.main_nullifier_exists_write_offset); + tmp *= scaling_factor; + std::get<27>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<28, ContainerOverSubrelations>; + auto tmp = (new_term.main_sel_first * new_term.main_nullifier_non_exists_write_offset); + tmp *= scaling_factor; + std::get<28>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<29, ContainerOverSubrelations>; + auto tmp = (new_term.main_sel_op_emit_nullifier * + (new_term.main_kernel_out_offset - + (constants_START_EMIT_NULLIFIER_WRITE_OFFSET + new_term.main_emit_nullifier_write_offset))); + tmp *= scaling_factor; + std::get<29>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<30, ContainerOverSubrelations>; + auto tmp = (new_term.main_sel_first * new_term.main_emit_nullifier_write_offset); + tmp *= scaling_factor; + std::get<30>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<31, ContainerOverSubrelations>; + auto tmp = (new_term.main_sel_op_l1_to_l2_msg_exists * + (new_term.main_kernel_out_offset - (constants_START_L1_TO_L2_MSG_EXISTS_WRITE_OFFSET + + new_term.main_l1_to_l2_msg_exists_write_offset))); + tmp *= scaling_factor; + std::get<31>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<32, ContainerOverSubrelations>; + auto tmp = (new_term.main_sel_first * new_term.main_l1_to_l2_msg_exists_write_offset); + tmp *= scaling_factor; + std::get<32>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<33, ContainerOverSubrelations>; + auto tmp = (new_term.main_sel_op_emit_unencrypted_log * + (new_term.main_kernel_out_offset - (constants_START_EMIT_UNENCRYPTED_LOG_WRITE_OFFSET + + new_term.main_emit_unencrypted_log_write_offset))); + tmp *= scaling_factor; + std::get<33>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<34, ContainerOverSubrelations>; + auto tmp = (new_term.main_sel_first * new_term.main_emit_unencrypted_log_write_offset); + tmp *= scaling_factor; + std::get<34>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<35, ContainerOverSubrelations>; + auto tmp = (new_term.main_sel_op_emit_l2_to_l1_msg * + (new_term.main_kernel_out_offset - (constants_START_EMIT_L2_TO_L1_MSG_WRITE_OFFSET + + new_term.main_emit_l2_to_l1_msg_write_offset))); + tmp *= scaling_factor; + std::get<35>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<36, ContainerOverSubrelations>; + auto tmp = (new_term.main_sel_first * new_term.main_emit_l2_to_l1_msg_write_offset); + tmp *= scaling_factor; + std::get<36>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<37, ContainerOverSubrelations>; + auto tmp = + (new_term.main_sel_op_sload * (new_term.main_kernel_out_offset - (constants_START_SLOAD_WRITE_OFFSET + + new_term.main_sload_write_offset))); + tmp *= scaling_factor; + std::get<37>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<38, ContainerOverSubrelations>; + auto tmp = (new_term.main_sel_first * new_term.main_sload_write_offset); + tmp *= scaling_factor; + std::get<38>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<39, ContainerOverSubrelations>; + auto tmp = + (new_term.main_sel_op_sstore * (new_term.main_kernel_out_offset - (constants_START_SSTORE_WRITE_OFFSET + + new_term.main_sstore_write_offset))); + tmp *= scaling_factor; + std::get<39>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<40, ContainerOverSubrelations>; + auto tmp = (new_term.main_sel_first * new_term.main_sstore_write_offset); + tmp *= scaling_factor; + std::get<40>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<41, ContainerOverSubrelations>; + auto tmp = (main_KERNEL_OUTPUT_SELECTORS * + (new_term.main_side_effect_counter_shift - (new_term.main_side_effect_counter + FF(1)))); + tmp *= scaling_factor; + std::get<41>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<42, ContainerOverSubrelations>; + auto tmp = (main_KERNEL_INPUT_SELECTORS * (FF(1) - new_term.main_sel_q_kernel_lookup)); + tmp *= scaling_factor; + std::get<42>(evals) += typename Accumulator::View(tmp); + } + { + using Accumulator = typename std::tuple_element_t<43, ContainerOverSubrelations>; + auto tmp = (main_KERNEL_OUTPUT_SELECTORS * (FF(1) - new_term.main_sel_q_kernel_output_lookup)); + tmp *= scaling_factor; + std::get<43>(evals) += typename Accumulator::View(tmp); + } } }; @@ -130,6 +410,54 @@ template class kernel : public Relation> { return "SLOAD_INC_CONSISTENCY_CHECK"; case 9: return "SSTORE_INC_CONSISTENCY_CHECK"; + case 10: + return "ADDRESS_KERNEL"; + case 11: + return "STORAGE_ADDRESS_KERNEL"; + case 12: + return "SENDER_KERNEL"; + case 13: + return "FUNCTION_SELECTOR_KERNEL"; + case 14: + return "FEE_TRANSACTION_FEE_KERNEL"; + case 15: + return "CHAIN_ID_KERNEL"; + case 16: + return "VERSION_KERNEL"; + case 17: + return "BLOCK_NUMBER_KERNEL"; + case 18: + return "TIMESTAMP_KERNEL"; + case 19: + return "COINBASE_KERNEL"; + case 20: + return "FEE_DA_GAS_KERNEL"; + case 21: + return "FEE_L2_GAS_KERNEL"; + case 22: + return "NOTE_HASH_KERNEL_OUTPUT"; + case 24: + return "EMIT_NOTE_HASH_KERNEL_OUTPUT"; + case 26: + return "NULLIFIER_EXISTS_KERNEL_OUTPUT"; + case 29: + return "EMIT_NULLIFIER_KERNEL_OUTPUT"; + case 31: + return "L1_TO_L2_MSG_EXISTS_KERNEL_OUTPUT"; + case 33: + return "EMIT_UNENCRYPTED_LOG_KERNEL_OUTPUT"; + case 35: + return "EMIT_L2_TO_L1_MSGS_KERNEL_OUTPUT"; + case 37: + return "SLOAD_KERNEL_OUTPUT"; + case 39: + return "SSTORE_KERNEL_OUTPUT"; + case 41: + return "SIDE_EFFECT_COUNTER_INCREMENT"; + case 42: + return "KERNEL_INPUT_ACTIVE_CHECK"; + case 43: + return "KERNEL_OUTPUT_ACTIVE_CHECK"; } return std::to_string(index); } diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/generated/relations/kernel_output_lookup.hpp b/barretenberg/cpp/src/barretenberg/vm/avm/generated/relations/kernel_output_lookup.hpp index e64c3dbb75b9..27ab2deb718a 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/generated/relations/kernel_output_lookup.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/generated/relations/kernel_output_lookup.hpp @@ -21,7 +21,7 @@ class kernel_output_lookup_lookup_settings { template static inline auto inverse_polynomial_is_computed_at_row(const AllEntities& in) { - return (in.main_sel_q_kernel_output_lookup == 1 || in.kernel_q_public_input_kernel_out_add_to_table == 1); + return (in.main_sel_q_kernel_output_lookup == 1 || in.main_sel_kernel_out == 1); } template @@ -29,7 +29,7 @@ class kernel_output_lookup_lookup_settings { { using View = typename Accumulator::View; const auto is_operation = View(in.main_sel_q_kernel_output_lookup); - const auto is_table_entry = View(in.kernel_q_public_input_kernel_out_add_to_table); + const auto is_table_entry = View(in.main_sel_kernel_out); return (is_operation + is_table_entry - is_operation * is_table_entry); } @@ -38,15 +38,15 @@ class kernel_output_lookup_lookup_settings { return std::forward_as_tuple(in.kernel_output_lookup_inv, in.kernel_output_lookup_counts, in.main_sel_q_kernel_output_lookup, - in.kernel_q_public_input_kernel_out_add_to_table, - in.kernel_kernel_out_offset, + in.main_sel_kernel_out, + in.main_kernel_out_offset, in.main_ia, - in.kernel_side_effect_counter, + in.main_side_effect_counter, in.main_ib, in.main_clk, - in.kernel_kernel_value_out, - in.kernel_kernel_side_effect_out, - in.kernel_kernel_metadata_out); + in.main_kernel_value_out, + in.main_kernel_side_effect_out, + in.main_kernel_metadata_out); } template static inline auto get_nonconst_entities(AllEntities& in) @@ -54,15 +54,15 @@ class kernel_output_lookup_lookup_settings { return std::forward_as_tuple(in.kernel_output_lookup_inv, in.kernel_output_lookup_counts, in.main_sel_q_kernel_output_lookup, - in.kernel_q_public_input_kernel_out_add_to_table, - in.kernel_kernel_out_offset, + in.main_sel_kernel_out, + in.main_kernel_out_offset, in.main_ia, - in.kernel_side_effect_counter, + in.main_side_effect_counter, in.main_ib, in.main_clk, - in.kernel_kernel_value_out, - in.kernel_kernel_side_effect_out, - in.kernel_kernel_metadata_out); + in.main_kernel_value_out, + in.main_kernel_side_effect_out, + in.main_kernel_metadata_out); } }; diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/generated/relations/lookup_into_kernel.hpp b/barretenberg/cpp/src/barretenberg/vm/avm/generated/relations/lookup_into_kernel.hpp index a2d199b598f5..0de10ad7e32c 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/generated/relations/lookup_into_kernel.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/generated/relations/lookup_into_kernel.hpp @@ -21,7 +21,7 @@ class lookup_into_kernel_lookup_settings { template static inline auto inverse_polynomial_is_computed_at_row(const AllEntities& in) { - return (in.main_sel_q_kernel_lookup == 1 || in.kernel_q_public_input_kernel_add_to_table == 1); + return (in.main_sel_q_kernel_lookup == 1 || in.main_sel_kernel_inputs == 1); } template @@ -29,7 +29,7 @@ class lookup_into_kernel_lookup_settings { { using View = typename Accumulator::View; const auto is_operation = View(in.main_sel_q_kernel_lookup); - const auto is_table_entry = View(in.kernel_q_public_input_kernel_add_to_table); + const auto is_table_entry = View(in.main_sel_kernel_inputs); return (is_operation + is_table_entry - is_operation * is_table_entry); } @@ -38,10 +38,10 @@ class lookup_into_kernel_lookup_settings { return std::forward_as_tuple(in.lookup_into_kernel_inv, in.lookup_into_kernel_counts, in.main_sel_q_kernel_lookup, - in.kernel_q_public_input_kernel_add_to_table, + in.main_sel_kernel_inputs, in.main_ia, - in.kernel_kernel_in_offset, - in.kernel_kernel_inputs, + in.main_kernel_in_offset, + in.main_kernel_inputs, in.main_clk); } @@ -50,10 +50,10 @@ class lookup_into_kernel_lookup_settings { return std::forward_as_tuple(in.lookup_into_kernel_inv, in.lookup_into_kernel_counts, in.main_sel_q_kernel_lookup, - in.kernel_q_public_input_kernel_add_to_table, + in.main_sel_kernel_inputs, in.main_ia, - in.kernel_kernel_in_offset, - in.kernel_kernel_inputs, + in.main_kernel_in_offset, + in.main_kernel_inputs, in.main_clk); } }; diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/generated/relations/main.hpp b/barretenberg/cpp/src/barretenberg/vm/avm/generated/relations/main.hpp index c9be4eb33fd6..0c62e3d4004e 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/generated/relations/main.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/generated/relations/main.hpp @@ -10,11 +10,11 @@ template class mainImpl { public: using FF = FF_; - static constexpr std::array SUBRELATION_PARTIAL_LENGTHS = { - 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 5, 4, 4, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 3, 3, 4, 4, 3, 3, 3, 3, 3, 4, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 2, 2 + static constexpr std::array SUBRELATION_PARTIAL_LENGTHS = { + 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 4, 4, 3, 3, 3, 3, 4, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 3, 3, 4, 4, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 4, 2, 2 }; template @@ -23,28 +23,6 @@ template class mainImpl { [[maybe_unused]] const RelationParameters&, [[maybe_unused]] const FF& scaling_factor) { - const auto constants_SENDER_SELECTOR = FF(0); - const auto constants_ADDRESS_SELECTOR = FF(1); - const auto constants_STORAGE_ADDRESS_SELECTOR = FF(1); - const auto constants_FUNCTION_SELECTOR_SELECTOR = FF(2); - const auto constants_CHAIN_ID_SELECTOR = FF(29); - const auto constants_VERSION_SELECTOR = FF(30); - const auto constants_BLOCK_NUMBER_SELECTOR = FF(31); - const auto constants_TIMESTAMP_SELECTOR = FF(33); - const auto constants_COINBASE_SELECTOR = FF(34); - const auto constants_FEE_PER_DA_GAS_SELECTOR = FF(36); - const auto constants_FEE_PER_L2_GAS_SELECTOR = FF(37); - const auto constants_TRANSACTION_FEE_SELECTOR = FF(41); - const auto constants_START_NOTE_HASH_EXISTS_WRITE_OFFSET = FF(0); - const auto constants_START_NULLIFIER_EXISTS_OFFSET = FF(16); - const auto constants_START_NULLIFIER_NON_EXISTS_OFFSET = FF(32); - const auto constants_START_L1_TO_L2_MSG_EXISTS_WRITE_OFFSET = FF(48); - const auto constants_START_SSTORE_WRITE_OFFSET = FF(64); - const auto constants_START_SLOAD_WRITE_OFFSET = FF(96); - const auto constants_START_EMIT_NOTE_HASH_WRITE_OFFSET = FF(128); - const auto constants_START_EMIT_NULLIFIER_WRITE_OFFSET = FF(144); - const auto constants_START_EMIT_L2_TO_L1_MSG_WRITE_OFFSET = FF(160); - const auto constants_START_EMIT_UNENCRYPTED_LOG_WRITE_OFFSET = FF(162); const auto constants_misc_INTERNAL_CALL_SPACE_ID = FF(255); const auto main_KERNEL_INPUT_SELECTORS = (((((((((((new_term.main_sel_op_address + new_term.main_sel_op_storage_address) + @@ -608,448 +586,213 @@ template class mainImpl { } { using Accumulator = typename std::tuple_element_t<82, ContainerOverSubrelations>; - auto tmp = (main_KERNEL_INPUT_SELECTORS * (FF(1) - new_term.main_sel_q_kernel_lookup)); + auto tmp = (new_term.main_sel_op_jump * (new_term.main_pc_shift - new_term.main_ia)); tmp *= scaling_factor; std::get<82>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<83, ContainerOverSubrelations>; - auto tmp = (main_KERNEL_OUTPUT_SELECTORS * (FF(1) - new_term.main_sel_q_kernel_output_lookup)); + auto tmp = (new_term.main_sel_op_jumpi * + (((FF(1) - new_term.main_id_zero) * (new_term.main_pc_shift - new_term.main_ia)) + + (new_term.main_id_zero * ((new_term.main_pc_shift - new_term.main_pc) - FF(1))))); tmp *= scaling_factor; std::get<83>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<84, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_jump * (new_term.main_pc_shift - new_term.main_ia)); + auto tmp = (new_term.main_sel_op_internal_call * + (new_term.main_internal_return_ptr_shift - (new_term.main_internal_return_ptr + FF(1)))); tmp *= scaling_factor; std::get<84>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<85, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_jumpi * - (((FF(1) - new_term.main_id_zero) * (new_term.main_pc_shift - new_term.main_ia)) + - (new_term.main_id_zero * ((new_term.main_pc_shift - new_term.main_pc) - FF(1))))); + auto tmp = + (new_term.main_sel_op_internal_call * (new_term.main_internal_return_ptr - new_term.main_mem_addr_b)); tmp *= scaling_factor; std::get<85>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<86, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_internal_call * - (new_term.main_internal_return_ptr_shift - (new_term.main_internal_return_ptr + FF(1)))); + auto tmp = (new_term.main_sel_op_internal_call * (new_term.main_pc_shift - new_term.main_ia)); tmp *= scaling_factor; std::get<86>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<87, ContainerOverSubrelations>; - auto tmp = - (new_term.main_sel_op_internal_call * (new_term.main_internal_return_ptr - new_term.main_mem_addr_b)); + auto tmp = (new_term.main_sel_op_internal_call * ((new_term.main_pc + FF(1)) - new_term.main_ib)); tmp *= scaling_factor; std::get<87>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<88, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_internal_call * (new_term.main_pc_shift - new_term.main_ia)); + auto tmp = (new_term.main_sel_op_internal_call * (new_term.main_rwb - FF(1))); tmp *= scaling_factor; std::get<88>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<89, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_internal_call * ((new_term.main_pc + FF(1)) - new_term.main_ib)); + auto tmp = (new_term.main_sel_op_internal_call * (new_term.main_sel_mem_op_b - FF(1))); tmp *= scaling_factor; std::get<89>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<90, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_internal_call * (new_term.main_rwb - FF(1))); + auto tmp = (new_term.main_sel_op_internal_return * + (new_term.main_internal_return_ptr_shift - (new_term.main_internal_return_ptr - FF(1)))); tmp *= scaling_factor; std::get<90>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<91, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_internal_call * (new_term.main_sel_mem_op_b - FF(1))); + auto tmp = (new_term.main_sel_op_internal_return * + ((new_term.main_internal_return_ptr - FF(1)) - new_term.main_mem_addr_a)); tmp *= scaling_factor; std::get<91>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<92, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_internal_return * - (new_term.main_internal_return_ptr_shift - (new_term.main_internal_return_ptr - FF(1)))); + auto tmp = (new_term.main_sel_op_internal_return * (new_term.main_pc_shift - new_term.main_ia)); tmp *= scaling_factor; std::get<92>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<93, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_internal_return * - ((new_term.main_internal_return_ptr - FF(1)) - new_term.main_mem_addr_a)); + auto tmp = (new_term.main_sel_op_internal_return * new_term.main_rwa); tmp *= scaling_factor; std::get<93>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<94, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_internal_return * (new_term.main_pc_shift - new_term.main_ia)); + auto tmp = (new_term.main_sel_op_internal_return * (new_term.main_sel_mem_op_a - FF(1))); tmp *= scaling_factor; std::get<94>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<95, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_internal_return * new_term.main_rwa); + auto tmp = ((main_CUR_AND_NEXT_ARE_MAIN * (FF(1) - main_SEL_ALL_CTRL_FLOW)) * + (new_term.main_pc_shift - (new_term.main_pc + FF(1)))); tmp *= scaling_factor; std::get<95>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<96, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_internal_return * (new_term.main_sel_mem_op_a - FF(1))); + auto tmp = ((main_CUR_AND_NEXT_ARE_MAIN * (FF(1) - main_SEL_ALL_CTRL_FLOW)) * + (new_term.main_internal_return_ptr_shift - new_term.main_internal_return_ptr)); tmp *= scaling_factor; std::get<96>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<97, ContainerOverSubrelations>; - auto tmp = ((main_CUR_AND_NEXT_ARE_MAIN * (FF(1) - main_SEL_ALL_CTRL_FLOW)) * - (new_term.main_pc_shift - (new_term.main_pc + FF(1)))); + auto tmp = ((new_term.main_sel_op_internal_call + new_term.main_sel_op_internal_return) * + (new_term.main_space_id - constants_misc_INTERNAL_CALL_SPACE_ID)); tmp *= scaling_factor; std::get<97>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<98, ContainerOverSubrelations>; - auto tmp = ((main_CUR_AND_NEXT_ARE_MAIN * (FF(1) - main_SEL_ALL_CTRL_FLOW)) * - (new_term.main_internal_return_ptr_shift - new_term.main_internal_return_ptr)); + auto tmp = (((FF(1) - new_term.main_sel_op_internal_call) - new_term.main_sel_op_internal_return) * + (new_term.main_call_ptr - new_term.main_space_id)); tmp *= scaling_factor; std::get<98>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<99, ContainerOverSubrelations>; - auto tmp = ((new_term.main_sel_op_internal_call + new_term.main_sel_op_internal_return) * - (new_term.main_space_id - constants_misc_INTERNAL_CALL_SPACE_ID)); + auto tmp = ((new_term.main_sel_op_cmov + new_term.main_sel_op_jumpi) * + (((new_term.main_id * new_term.main_inv) - FF(1)) + new_term.main_id_zero)); tmp *= scaling_factor; std::get<99>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<100, ContainerOverSubrelations>; - auto tmp = (((FF(1) - new_term.main_sel_op_internal_call) - new_term.main_sel_op_internal_return) * - (new_term.main_call_ptr - new_term.main_space_id)); + auto tmp = (((new_term.main_sel_op_cmov + new_term.main_sel_op_jumpi) * new_term.main_id_zero) * + (FF(1) - new_term.main_inv)); tmp *= scaling_factor; std::get<100>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<101, ContainerOverSubrelations>; - auto tmp = ((new_term.main_sel_op_cmov + new_term.main_sel_op_jumpi) * - (((new_term.main_id * new_term.main_inv) - FF(1)) + new_term.main_id_zero)); + auto tmp = (new_term.main_sel_mov_ia_to_ic - + (new_term.main_sel_op_mov + (new_term.main_sel_op_cmov * (FF(1) - new_term.main_id_zero)))); tmp *= scaling_factor; std::get<101>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<102, ContainerOverSubrelations>; - auto tmp = (((new_term.main_sel_op_cmov + new_term.main_sel_op_jumpi) * new_term.main_id_zero) * - (FF(1) - new_term.main_inv)); + auto tmp = (new_term.main_sel_mov_ib_to_ic - (new_term.main_sel_op_cmov * new_term.main_id_zero)); tmp *= scaling_factor; std::get<102>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<103, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_mov_ia_to_ic - - (new_term.main_sel_op_mov + (new_term.main_sel_op_cmov * (FF(1) - new_term.main_id_zero)))); + auto tmp = (new_term.main_sel_mov_ia_to_ic * (new_term.main_ia - new_term.main_ic)); tmp *= scaling_factor; std::get<103>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<104, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_mov_ib_to_ic - (new_term.main_sel_op_cmov * new_term.main_id_zero)); + auto tmp = (new_term.main_sel_mov_ib_to_ic * (new_term.main_ib - new_term.main_ic)); tmp *= scaling_factor; std::get<104>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<105, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_mov_ia_to_ic * (new_term.main_ia - new_term.main_ic)); + auto tmp = ((new_term.main_sel_op_mov + new_term.main_sel_op_cmov) * + (new_term.main_r_in_tag - new_term.main_w_in_tag)); tmp *= scaling_factor; std::get<105>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<106, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_mov_ib_to_ic * (new_term.main_ib - new_term.main_ic)); + auto tmp = (new_term.main_sel_alu - + ((main_SEL_ALL_ALU * (FF(1) - new_term.main_tag_err)) * (FF(1) - new_term.main_op_err))); tmp *= scaling_factor; std::get<106>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<107, ContainerOverSubrelations>; - auto tmp = ((new_term.main_sel_op_mov + new_term.main_sel_op_cmov) * - (new_term.main_r_in_tag - new_term.main_w_in_tag)); + auto tmp = (main_SEL_ALU_R_TAG * (new_term.main_alu_in_tag - new_term.main_r_in_tag)); tmp *= scaling_factor; std::get<107>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<108, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_alu - - ((main_SEL_ALL_ALU * (FF(1) - new_term.main_tag_err)) * (FF(1) - new_term.main_op_err))); + auto tmp = (main_SEL_ALU_W_TAG * (new_term.main_alu_in_tag - new_term.main_w_in_tag)); tmp *= scaling_factor; std::get<108>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<109, ContainerOverSubrelations>; - auto tmp = (main_SEL_ALU_R_TAG * (new_term.main_alu_in_tag - new_term.main_r_in_tag)); + auto tmp = (new_term.main_sel_op_l2gasleft * (new_term.main_ia - new_term.main_l2_gas_remaining_shift)); tmp *= scaling_factor; std::get<109>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<110, ContainerOverSubrelations>; - auto tmp = (main_SEL_ALU_W_TAG * (new_term.main_alu_in_tag - new_term.main_w_in_tag)); + auto tmp = (new_term.main_sel_op_dagasleft * (new_term.main_ia - new_term.main_da_gas_remaining_shift)); tmp *= scaling_factor; std::get<110>(evals) += typename Accumulator::View(tmp); } { using Accumulator = typename std::tuple_element_t<111, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_l2gasleft * (new_term.main_ia - new_term.main_l2_gas_remaining_shift)); - tmp *= scaling_factor; - std::get<111>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<112, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_dagasleft * (new_term.main_ia - new_term.main_da_gas_remaining_shift)); - tmp *= scaling_factor; - std::get<112>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<113, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_address * (new_term.kernel_kernel_in_offset - constants_ADDRESS_SELECTOR)); - tmp *= scaling_factor; - std::get<113>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<114, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_storage_address * - (new_term.kernel_kernel_in_offset - constants_STORAGE_ADDRESS_SELECTOR)); - tmp *= scaling_factor; - std::get<114>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<115, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_sender * (new_term.kernel_kernel_in_offset - constants_SENDER_SELECTOR)); - tmp *= scaling_factor; - std::get<115>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<116, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_function_selector * - (new_term.kernel_kernel_in_offset - constants_FUNCTION_SELECTOR_SELECTOR)); - tmp *= scaling_factor; - std::get<116>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<117, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_transaction_fee * - (new_term.kernel_kernel_in_offset - constants_TRANSACTION_FEE_SELECTOR)); - tmp *= scaling_factor; - std::get<117>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<118, ContainerOverSubrelations>; - auto tmp = - (new_term.main_sel_op_chain_id * (new_term.kernel_kernel_in_offset - constants_CHAIN_ID_SELECTOR)); - tmp *= scaling_factor; - std::get<118>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<119, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_version * (new_term.kernel_kernel_in_offset - constants_VERSION_SELECTOR)); - tmp *= scaling_factor; - std::get<119>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<120, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_block_number * - (new_term.kernel_kernel_in_offset - constants_BLOCK_NUMBER_SELECTOR)); - tmp *= scaling_factor; - std::get<120>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<121, ContainerOverSubrelations>; - auto tmp = - (new_term.main_sel_op_timestamp * (new_term.kernel_kernel_in_offset - constants_TIMESTAMP_SELECTOR)); - tmp *= scaling_factor; - std::get<121>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<122, ContainerOverSubrelations>; - auto tmp = - (new_term.main_sel_op_coinbase * (new_term.kernel_kernel_in_offset - constants_COINBASE_SELECTOR)); - tmp *= scaling_factor; - std::get<122>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<123, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_fee_per_da_gas * - (new_term.kernel_kernel_in_offset - constants_FEE_PER_DA_GAS_SELECTOR)); - tmp *= scaling_factor; - std::get<123>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<124, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_fee_per_l2_gas * - (new_term.kernel_kernel_in_offset - constants_FEE_PER_L2_GAS_SELECTOR)); - tmp *= scaling_factor; - std::get<124>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<125, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_note_hash_exists * - (new_term.kernel_kernel_out_offset - (constants_START_NOTE_HASH_EXISTS_WRITE_OFFSET + - new_term.kernel_note_hash_exist_write_offset))); - tmp *= scaling_factor; - std::get<125>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<126, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_first * new_term.kernel_note_hash_exist_write_offset); - tmp *= scaling_factor; - std::get<126>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<127, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_emit_note_hash * - (new_term.kernel_kernel_out_offset - - (constants_START_EMIT_NOTE_HASH_WRITE_OFFSET + new_term.kernel_emit_note_hash_write_offset))); - tmp *= scaling_factor; - std::get<127>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<128, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_first * new_term.kernel_emit_note_hash_write_offset); - tmp *= scaling_factor; - std::get<128>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<129, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_nullifier_exists * - (new_term.kernel_kernel_out_offset - - ((new_term.main_ib * - (constants_START_NULLIFIER_EXISTS_OFFSET + new_term.kernel_nullifier_exists_write_offset)) + - ((FF(1) - new_term.main_ib) * (constants_START_NULLIFIER_NON_EXISTS_OFFSET + - new_term.kernel_nullifier_non_exists_write_offset))))); - tmp *= scaling_factor; - std::get<129>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<130, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_first * new_term.kernel_nullifier_exists_write_offset); - tmp *= scaling_factor; - std::get<130>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<131, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_first * new_term.kernel_nullifier_non_exists_write_offset); - tmp *= scaling_factor; - std::get<131>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<132, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_emit_nullifier * - (new_term.kernel_kernel_out_offset - - (constants_START_EMIT_NULLIFIER_WRITE_OFFSET + new_term.kernel_emit_nullifier_write_offset))); - tmp *= scaling_factor; - std::get<132>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<133, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_first * new_term.kernel_emit_nullifier_write_offset); - tmp *= scaling_factor; - std::get<133>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<134, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_l1_to_l2_msg_exists * - (new_term.kernel_kernel_out_offset - (constants_START_L1_TO_L2_MSG_EXISTS_WRITE_OFFSET + - new_term.kernel_l1_to_l2_msg_exists_write_offset))); - tmp *= scaling_factor; - std::get<134>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<135, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_first * new_term.kernel_l1_to_l2_msg_exists_write_offset); - tmp *= scaling_factor; - std::get<135>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<136, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_emit_unencrypted_log * - (new_term.kernel_kernel_out_offset - (constants_START_EMIT_UNENCRYPTED_LOG_WRITE_OFFSET + - new_term.kernel_emit_unencrypted_log_write_offset))); - tmp *= scaling_factor; - std::get<136>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<137, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_first * new_term.kernel_emit_unencrypted_log_write_offset); - tmp *= scaling_factor; - std::get<137>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<138, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_emit_l2_to_l1_msg * - (new_term.kernel_kernel_out_offset - (constants_START_EMIT_L2_TO_L1_MSG_WRITE_OFFSET + - new_term.kernel_emit_l2_to_l1_msg_write_offset))); - tmp *= scaling_factor; - std::get<138>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<139, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_first * new_term.kernel_emit_l2_to_l1_msg_write_offset); - tmp *= scaling_factor; - std::get<139>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<140, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_sload * - (new_term.kernel_kernel_out_offset - - (constants_START_SLOAD_WRITE_OFFSET + new_term.kernel_sload_write_offset))); - tmp *= scaling_factor; - std::get<140>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<141, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_first * new_term.kernel_sload_write_offset); - tmp *= scaling_factor; - std::get<141>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<142, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_op_sstore * - (new_term.kernel_kernel_out_offset - - (constants_START_SSTORE_WRITE_OFFSET + new_term.kernel_sstore_write_offset))); - tmp *= scaling_factor; - std::get<142>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<143, ContainerOverSubrelations>; - auto tmp = (new_term.main_sel_first * new_term.kernel_sstore_write_offset); - tmp *= scaling_factor; - std::get<143>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<144, ContainerOverSubrelations>; - auto tmp = (main_KERNEL_OUTPUT_SELECTORS * - (new_term.kernel_side_effect_counter_shift - (new_term.kernel_side_effect_counter + FF(1)))); - tmp *= scaling_factor; - std::get<144>(evals) += typename Accumulator::View(tmp); - } - { - using Accumulator = typename std::tuple_element_t<145, ContainerOverSubrelations>; auto tmp = ((new_term.main_ib * (FF(1) - new_term.main_tag_err)) * ((new_term.main_sel_op_calldata_copy + new_term.main_sel_op_external_return) - new_term.main_sel_slice_gadget)); tmp *= scaling_factor; - std::get<145>(evals) += typename Accumulator::View(tmp); + std::get<111>(evals) += typename Accumulator::View(tmp); } { - using Accumulator = typename std::tuple_element_t<146, ContainerOverSubrelations>; + using Accumulator = typename std::tuple_element_t<112, ContainerOverSubrelations>; auto tmp = (new_term.main_bin_op_id - (new_term.main_sel_op_or + (FF(2) * new_term.main_sel_op_xor))); tmp *= scaling_factor; - std::get<146>(evals) += typename Accumulator::View(tmp); + std::get<112>(evals) += typename Accumulator::View(tmp); } { - using Accumulator = typename std::tuple_element_t<147, ContainerOverSubrelations>; + using Accumulator = typename std::tuple_element_t<113, ContainerOverSubrelations>; auto tmp = (new_term.main_sel_bin - ((new_term.main_sel_op_and + new_term.main_sel_op_or) + new_term.main_sel_op_xor)); tmp *= scaling_factor; - std::get<147>(evals) += typename Accumulator::View(tmp); + std::get<113>(evals) += typename Accumulator::View(tmp); } } }; @@ -1078,84 +821,38 @@ template class main : public Relation> { case 81: return "SUBOP_ERROR_RELEVANT_OP"; case 82: - return "KERNEL_INPUT_ACTIVE_CHECK"; - case 83: - return "KERNEL_OUTPUT_ACTIVE_CHECK"; - case 84: return "PC_JUMP"; - case 85: + case 83: return "PC_JUMPI"; - case 86: + case 84: return "RETURN_POINTER_INCREMENT"; - case 92: + case 90: return "RETURN_POINTER_DECREMENT"; - case 97: + case 95: return "PC_INCREMENT"; - case 98: + case 96: return "INTERNAL_RETURN_POINTER_CONSISTENCY"; - case 99: + case 97: return "SPACE_ID_INTERNAL"; - case 100: + case 98: return "SPACE_ID_STANDARD_OPCODES"; - case 101: + case 99: return "CMOV_CONDITION_RES_1"; - case 102: + case 100: return "CMOV_CONDITION_RES_2"; - case 105: + case 103: return "MOV_SAME_VALUE_A"; - case 106: + case 104: return "MOV_SAME_VALUE_B"; - case 107: + case 105: return "MOV_MAIN_SAME_TAG"; - case 111: + case 109: return "L2GASLEFT"; - case 112: + case 110: return "DAGASLEFT"; - case 113: - return "ADDRESS_KERNEL"; - case 114: - return "STORAGE_ADDRESS_KERNEL"; - case 115: - return "SENDER_KERNEL"; - case 116: - return "FUNCTION_SELECTOR_KERNEL"; - case 117: - return "FEE_TRANSACTION_FEE_KERNEL"; - case 118: - return "CHAIN_ID_KERNEL"; - case 119: - return "VERSION_KERNEL"; - case 120: - return "BLOCK_NUMBER_KERNEL"; - case 121: - return "TIMESTAMP_KERNEL"; - case 122: - return "COINBASE_KERNEL"; - case 123: - return "FEE_DA_GAS_KERNEL"; - case 124: - return "FEE_L2_GAS_KERNEL"; - case 125: - return "NOTE_HASH_KERNEL_OUTPUT"; - case 127: - return "EMIT_NOTE_HASH_KERNEL_OUTPUT"; - case 129: - return "NULLIFIER_EXISTS_KERNEL_OUTPUT"; - case 132: - return "EMIT_NULLIFIER_KERNEL_OUTPUT"; - case 134: - return "L1_TO_L2_MSG_EXISTS_KERNEL_OUTPUT"; - case 136: - return "EMIT_UNENCRYPTED_LOG_KERNEL_OUTPUT"; - case 138: - return "EMIT_L2_TO_L1_MSGS_KERNEL_OUTPUT"; - case 140: - return "SLOAD_KERNEL_OUTPUT"; - case 142: - return "SSTORE_KERNEL_OUTPUT"; - case 146: + case 112: return "BIN_SEL_1"; - case 147: + case 113: return "BIN_SEL_2"; } return std::to_string(index); diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/generated/verifier.cpp b/barretenberg/cpp/src/barretenberg/vm/avm/generated/verifier.cpp index e1375bc8b1b8..d452c718c440 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/generated/verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/generated/verifier.cpp @@ -5,7 +5,6 @@ #include "barretenberg/commitment_schemes/zeromorph/zeromorph.hpp" #include "barretenberg/numeric/bitop/get_msb.hpp" -#include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/transcript/transcript.hpp" namespace bb { @@ -110,22 +109,22 @@ bool AvmVerifier::verify_proof(const HonkProof& proof, std::vector mle_challenge(multivariate_challenge.begin(), multivariate_challenge.begin() + static_cast(log_circuit_size)); - FF kernel_kernel_inputs_evaluation = evaluate_public_input_column(public_inputs[0], circuit_size, mle_challenge); - if (kernel_kernel_inputs_evaluation != claimed_evaluations.kernel_kernel_inputs) { + FF main_kernel_inputs_evaluation = evaluate_public_input_column(public_inputs[0], circuit_size, mle_challenge); + if (main_kernel_inputs_evaluation != claimed_evaluations.main_kernel_inputs) { return false; } - FF kernel_kernel_value_out_evaluation = evaluate_public_input_column(public_inputs[1], circuit_size, mle_challenge); - if (kernel_kernel_value_out_evaluation != claimed_evaluations.kernel_kernel_value_out) { + FF main_kernel_value_out_evaluation = evaluate_public_input_column(public_inputs[1], circuit_size, mle_challenge); + if (main_kernel_value_out_evaluation != claimed_evaluations.main_kernel_value_out) { return false; } - FF kernel_kernel_side_effect_out_evaluation = + FF main_kernel_side_effect_out_evaluation = evaluate_public_input_column(public_inputs[2], circuit_size, mle_challenge); - if (kernel_kernel_side_effect_out_evaluation != claimed_evaluations.kernel_kernel_side_effect_out) { + if (main_kernel_side_effect_out_evaluation != claimed_evaluations.main_kernel_side_effect_out) { return false; } - FF kernel_kernel_metadata_out_evaluation = + FF main_kernel_metadata_out_evaluation = evaluate_public_input_column(public_inputs[3], circuit_size, mle_challenge); - if (kernel_kernel_metadata_out_evaluation != claimed_evaluations.kernel_kernel_metadata_out) { + if (main_kernel_metadata_out_evaluation != claimed_evaluations.main_kernel_metadata_out) { return false; } FF main_calldata_evaluation = evaluate_public_input_column(public_inputs[4], circuit_size, mle_challenge); diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/tests/execution.test.cpp b/barretenberg/cpp/src/barretenberg/vm/avm/tests/execution.test.cpp index e07ef47d37f0..43f95355e80b 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/tests/execution.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/tests/execution.test.cpp @@ -1764,40 +1764,40 @@ TEST_F(AvmExecutionTests, kernelOutputEmitOpcodes) auto emit_note_hash_row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.main_sel_op_emit_note_hash == 1; }); EXPECT_EQ(emit_note_hash_row->main_ia, 1); - EXPECT_EQ(emit_note_hash_row->kernel_side_effect_counter, 0); + EXPECT_EQ(emit_note_hash_row->main_side_effect_counter, 0); // Get the row of the first note hash out uint32_t emit_note_hash_out_offset = START_EMIT_NOTE_HASH_WRITE_OFFSET; auto emit_note_hash_kernel_out_row = std::ranges::find_if( trace.begin(), trace.end(), [&](Row r) { return r.main_clk == emit_note_hash_out_offset; }); - EXPECT_EQ(emit_note_hash_kernel_out_row->kernel_kernel_value_out, 1); - EXPECT_EQ(emit_note_hash_kernel_out_row->kernel_kernel_side_effect_out, 0); + EXPECT_EQ(emit_note_hash_kernel_out_row->main_kernel_value_out, 1); + EXPECT_EQ(emit_note_hash_kernel_out_row->main_kernel_side_effect_out, 0); feed_output(emit_note_hash_out_offset, 1, 0, 0); // CHECK EMIT NULLIFIER auto emit_nullifier_row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.main_sel_op_emit_nullifier == 1; }); EXPECT_EQ(emit_nullifier_row->main_ia, 1); - EXPECT_EQ(emit_nullifier_row->kernel_side_effect_counter, 1); + EXPECT_EQ(emit_nullifier_row->main_side_effect_counter, 1); uint32_t emit_nullifier_out_offset = START_EMIT_NULLIFIER_WRITE_OFFSET; auto emit_nullifier_kernel_out_row = std::ranges::find_if( trace.begin(), trace.end(), [&](Row r) { return r.main_clk == emit_nullifier_out_offset; }); - EXPECT_EQ(emit_nullifier_kernel_out_row->kernel_kernel_value_out, 1); - EXPECT_EQ(emit_nullifier_kernel_out_row->kernel_kernel_side_effect_out, 1); + EXPECT_EQ(emit_nullifier_kernel_out_row->main_kernel_value_out, 1); + EXPECT_EQ(emit_nullifier_kernel_out_row->main_kernel_side_effect_out, 1); feed_output(emit_nullifier_out_offset, 1, 1, 0); // CHECK EMIT UNENCRYPTED LOG auto emit_log_row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.main_sel_op_emit_unencrypted_log == 1; }); EXPECT_EQ(emit_log_row->main_ia, 1); - EXPECT_EQ(emit_log_row->kernel_side_effect_counter, 2); + EXPECT_EQ(emit_log_row->main_side_effect_counter, 2); uint32_t emit_log_out_offset = START_EMIT_UNENCRYPTED_LOG_WRITE_OFFSET; auto emit_log_kernel_out_row = std::ranges::find_if(trace.begin(), trace.end(), [&](Row r) { return r.main_clk == emit_log_out_offset; }); - EXPECT_EQ(emit_log_kernel_out_row->kernel_kernel_value_out, 1); - EXPECT_EQ(emit_log_kernel_out_row->kernel_kernel_side_effect_out, 2); + EXPECT_EQ(emit_log_kernel_out_row->main_kernel_value_out, 1); + EXPECT_EQ(emit_log_kernel_out_row->main_kernel_side_effect_out, 2); feed_output(emit_log_out_offset, 1, 2, 0); // CHECK SEND L2 TO L1 MSG @@ -1805,13 +1805,13 @@ TEST_F(AvmExecutionTests, kernelOutputEmitOpcodes) std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.main_sel_op_emit_l2_to_l1_msg == 1; }); EXPECT_EQ(send_row->main_ia, 1); EXPECT_EQ(send_row->main_ib, 1); - EXPECT_EQ(send_row->kernel_side_effect_counter, 3); + EXPECT_EQ(send_row->main_side_effect_counter, 3); auto msg_out_row = std::ranges::find_if( trace.begin(), trace.end(), [&](Row r) { return r.main_clk == START_EMIT_L2_TO_L1_MSG_WRITE_OFFSET; }); - EXPECT_EQ(msg_out_row->kernel_kernel_value_out, 1); - EXPECT_EQ(msg_out_row->kernel_kernel_side_effect_out, 3); - EXPECT_EQ(msg_out_row->kernel_kernel_metadata_out, 1); + EXPECT_EQ(msg_out_row->main_kernel_value_out, 1); + EXPECT_EQ(msg_out_row->main_kernel_side_effect_out, 3); + EXPECT_EQ(msg_out_row->main_kernel_metadata_out, 1); feed_output(START_EMIT_L2_TO_L1_MSG_WRITE_OFFSET, 1, 3, 1); validate_trace(std::move(trace), public_inputs); @@ -1860,15 +1860,15 @@ TEST_F(AvmExecutionTests, kernelOutputStorageLoadOpcodeSimple) auto sload_row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.main_sel_op_sload == 1; }); EXPECT_EQ(sload_row->main_ia, 42); // Read value EXPECT_EQ(sload_row->main_ib, 9); // Storage slot - EXPECT_EQ(sload_row->kernel_side_effect_counter, 0); + EXPECT_EQ(sload_row->main_side_effect_counter, 0); // Get the row of the first read storage read out uint32_t sload_out_offset = START_SLOAD_WRITE_OFFSET; auto sload_kernel_out_row = std::ranges::find_if(trace.begin(), trace.end(), [&](Row r) { return r.main_clk == sload_out_offset; }); - EXPECT_EQ(sload_kernel_out_row->kernel_kernel_value_out, 42); // value - EXPECT_EQ(sload_kernel_out_row->kernel_kernel_side_effect_out, 0); - EXPECT_EQ(sload_kernel_out_row->kernel_kernel_metadata_out, 9); // slot + EXPECT_EQ(sload_kernel_out_row->main_kernel_value_out, 42); // value + EXPECT_EQ(sload_kernel_out_row->main_kernel_side_effect_out, 0); + EXPECT_EQ(sload_kernel_out_row->main_kernel_metadata_out, 9); // slot feed_output(sload_out_offset, 42, 0, 9); validate_trace(std::move(trace), public_inputs); } @@ -1917,23 +1917,23 @@ TEST_F(AvmExecutionTests, kernelOutputStorageLoadOpcodeComplex) auto sload_row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.main_sel_op_sload == 1; }); EXPECT_EQ(sload_row->main_ia, 42); // Read value EXPECT_EQ(sload_row->main_ib, 9); // Storage slot - EXPECT_EQ(sload_row->kernel_side_effect_counter, 0); + EXPECT_EQ(sload_row->main_side_effect_counter, 0); sload_row++; EXPECT_EQ(sload_row->main_ia, 123); // Read value EXPECT_EQ(sload_row->main_ib, 10); // Storage slot - EXPECT_EQ(sload_row->kernel_side_effect_counter, 1); + EXPECT_EQ(sload_row->main_side_effect_counter, 1); // Get the row of the first read storage read out uint32_t sload_out_offset = START_SLOAD_WRITE_OFFSET; auto sload_kernel_out_row = std::ranges::find_if(trace.begin(), trace.end(), [&](Row r) { return r.main_clk == sload_out_offset; }); - EXPECT_EQ(sload_kernel_out_row->kernel_kernel_value_out, 42); // value - EXPECT_EQ(sload_kernel_out_row->kernel_kernel_side_effect_out, 0); - EXPECT_EQ(sload_kernel_out_row->kernel_kernel_metadata_out, 9); // slot + EXPECT_EQ(sload_kernel_out_row->main_kernel_value_out, 42); // value + EXPECT_EQ(sload_kernel_out_row->main_kernel_side_effect_out, 0); + EXPECT_EQ(sload_kernel_out_row->main_kernel_metadata_out, 9); // slot sload_kernel_out_row++; - EXPECT_EQ(sload_kernel_out_row->kernel_kernel_value_out, 123); // value - EXPECT_EQ(sload_kernel_out_row->kernel_kernel_side_effect_out, 1); - EXPECT_EQ(sload_kernel_out_row->kernel_kernel_metadata_out, 10); // slot + EXPECT_EQ(sload_kernel_out_row->main_kernel_value_out, 123); // value + EXPECT_EQ(sload_kernel_out_row->main_kernel_side_effect_out, 1); + EXPECT_EQ(sload_kernel_out_row->main_kernel_metadata_out, 10); // slot feed_output(sload_out_offset, 42, 0, 9); feed_output(sload_out_offset + 1, 123, 1, 10); @@ -1973,16 +1973,16 @@ TEST_F(AvmExecutionTests, kernelOutputStorageStoreOpcodeSimple) auto sstore_row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.main_sel_op_sstore == 1; }); EXPECT_EQ(sstore_row->main_ia, 42); // Read value EXPECT_EQ(sstore_row->main_ib, 9); // Storage slot - EXPECT_EQ(sstore_row->kernel_side_effect_counter, 0); + EXPECT_EQ(sstore_row->main_side_effect_counter, 0); // Get the row of the first storage write out uint32_t sstore_out_offset = START_SSTORE_WRITE_OFFSET; auto sstore_kernel_out_row = std::ranges::find_if(trace.begin(), trace.end(), [&](Row r) { return r.main_clk == sstore_out_offset; }); - auto value_out = sstore_kernel_out_row->kernel_kernel_value_out; - auto side_effect_out = sstore_kernel_out_row->kernel_kernel_side_effect_out; - auto metadata_out = sstore_kernel_out_row->kernel_kernel_metadata_out; + auto value_out = sstore_kernel_out_row->main_kernel_value_out; + auto side_effect_out = sstore_kernel_out_row->main_kernel_side_effect_out; + auto metadata_out = sstore_kernel_out_row->main_kernel_metadata_out; EXPECT_EQ(value_out, 42); // value EXPECT_EQ(side_effect_out, 0); EXPECT_EQ(metadata_out, 9); // slot @@ -2028,24 +2028,24 @@ TEST_F(AvmExecutionTests, kernelOutputStorageStoreOpcodeComplex) auto sstore_row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.main_sel_op_sstore == 1; }); EXPECT_EQ(sstore_row->main_ia, 42); // Read value EXPECT_EQ(sstore_row->main_ib, 9); // Storage slot - EXPECT_EQ(sstore_row->kernel_side_effect_counter, 0); + EXPECT_EQ(sstore_row->main_side_effect_counter, 0); sstore_row++; EXPECT_EQ(sstore_row->main_ia, 123); // Read value EXPECT_EQ(sstore_row->main_ib, 10); // Storage slot - EXPECT_EQ(sstore_row->kernel_side_effect_counter, 1); + EXPECT_EQ(sstore_row->main_side_effect_counter, 1); // Get the row of the first storage write out uint32_t sstore_out_offset = START_SSTORE_WRITE_OFFSET; auto sstore_kernel_out_row = std::ranges::find_if(trace.begin(), trace.end(), [&](Row r) { return r.main_clk == sstore_out_offset; }); - EXPECT_EQ(sstore_kernel_out_row->kernel_kernel_value_out, 42); // value - EXPECT_EQ(sstore_kernel_out_row->kernel_kernel_side_effect_out, 0); - EXPECT_EQ(sstore_kernel_out_row->kernel_kernel_metadata_out, 9); // slot + EXPECT_EQ(sstore_kernel_out_row->main_kernel_value_out, 42); // value + EXPECT_EQ(sstore_kernel_out_row->main_kernel_side_effect_out, 0); + EXPECT_EQ(sstore_kernel_out_row->main_kernel_metadata_out, 9); // slot sstore_kernel_out_row++; - EXPECT_EQ(sstore_kernel_out_row->kernel_kernel_value_out, 123); // value - EXPECT_EQ(sstore_kernel_out_row->kernel_kernel_side_effect_out, 1); - EXPECT_EQ(sstore_kernel_out_row->kernel_kernel_metadata_out, 10); // slot + EXPECT_EQ(sstore_kernel_out_row->main_kernel_value_out, 123); // value + EXPECT_EQ(sstore_kernel_out_row->main_kernel_side_effect_out, 1); + EXPECT_EQ(sstore_kernel_out_row->main_kernel_metadata_out, 10); // slot feed_output(sstore_out_offset, 42, 0, 9); feed_output(sstore_out_offset + 1, 123, 1, 10); @@ -2102,30 +2102,30 @@ TEST_F(AvmExecutionTests, kernelOutputStorageOpcodes) auto sload_row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.main_sel_op_sload == 1; }); EXPECT_EQ(sload_row->main_ia, 42); // Read value EXPECT_EQ(sload_row->main_ib, 9); // Storage slot - EXPECT_EQ(sload_row->kernel_side_effect_counter, 0); + EXPECT_EQ(sload_row->main_side_effect_counter, 0); // Get the row of the first storage read out uint32_t sload_out_offset = START_SLOAD_WRITE_OFFSET; auto sload_kernel_out_row = std::ranges::find_if(trace.begin(), trace.end(), [&](Row r) { return r.main_clk == sload_out_offset; }); - EXPECT_EQ(sload_kernel_out_row->kernel_kernel_value_out, 42); // value - EXPECT_EQ(sload_kernel_out_row->kernel_kernel_side_effect_out, 0); - EXPECT_EQ(sload_kernel_out_row->kernel_kernel_metadata_out, 9); // slot + EXPECT_EQ(sload_kernel_out_row->main_kernel_value_out, 42); // value + EXPECT_EQ(sload_kernel_out_row->main_kernel_side_effect_out, 0); + EXPECT_EQ(sload_kernel_out_row->main_kernel_metadata_out, 9); // slot feed_output(sload_out_offset, 42, 0, 9); // CHECK SSTORE auto sstore_row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.main_sel_op_sstore == 1; }); EXPECT_EQ(sstore_row->main_ia, 42); // Read value EXPECT_EQ(sstore_row->main_ib, 9); // Storage slot - EXPECT_EQ(sstore_row->kernel_side_effect_counter, 1); + EXPECT_EQ(sstore_row->main_side_effect_counter, 1); // Get the row of the first storage write out uint32_t sstore_out_offset = START_SSTORE_WRITE_OFFSET; auto sstore_kernel_out_row = std::ranges::find_if(trace.begin(), trace.end(), [&](Row r) { return r.main_clk == sstore_out_offset; }); - EXPECT_EQ(sstore_kernel_out_row->kernel_kernel_value_out, 42); // value - EXPECT_EQ(sstore_kernel_out_row->kernel_kernel_side_effect_out, 1); - EXPECT_EQ(sstore_kernel_out_row->kernel_kernel_metadata_out, 9); // slot + EXPECT_EQ(sstore_kernel_out_row->main_kernel_value_out, 42); // value + EXPECT_EQ(sstore_kernel_out_row->main_kernel_side_effect_out, 1); + EXPECT_EQ(sstore_kernel_out_row->main_kernel_metadata_out, 9); // slot feed_output(sstore_out_offset, 42, 1, 9); validate_trace(std::move(trace), public_inputs); @@ -2183,13 +2183,13 @@ TEST_F(AvmExecutionTests, kernelOutputHashExistsOpcodes) std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.main_sel_op_note_hash_exists == 1; }); EXPECT_EQ(note_hash_row->main_ia, 1); // Read value EXPECT_EQ(note_hash_row->main_ib, 1); // Storage slot - EXPECT_EQ(note_hash_row->kernel_side_effect_counter, 0); + EXPECT_EQ(note_hash_row->main_side_effect_counter, 0); auto note_hash_out_row = std::ranges::find_if( trace.begin(), trace.end(), [&](Row r) { return r.main_clk == START_NOTE_HASH_EXISTS_WRITE_OFFSET; }); - EXPECT_EQ(note_hash_out_row->kernel_kernel_value_out, 1); // value - EXPECT_EQ(note_hash_out_row->kernel_kernel_side_effect_out, 0); - EXPECT_EQ(note_hash_out_row->kernel_kernel_metadata_out, 1); // exists + EXPECT_EQ(note_hash_out_row->main_kernel_value_out, 1); // value + EXPECT_EQ(note_hash_out_row->main_kernel_side_effect_out, 0); + EXPECT_EQ(note_hash_out_row->main_kernel_metadata_out, 1); // exists feed_output(START_NOTE_HASH_EXISTS_WRITE_OFFSET, 1, 0, 1); // CHECK NULLIFIEREXISTS @@ -2197,13 +2197,13 @@ TEST_F(AvmExecutionTests, kernelOutputHashExistsOpcodes) std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.main_sel_op_nullifier_exists == 1; }); EXPECT_EQ(nullifier_row->main_ia, 1); // Read value EXPECT_EQ(nullifier_row->main_ib, 1); // Storage slot - EXPECT_EQ(nullifier_row->kernel_side_effect_counter, 1); + EXPECT_EQ(nullifier_row->main_side_effect_counter, 1); auto nullifier_out_row = std::ranges::find_if( trace.begin(), trace.end(), [&](Row r) { return r.main_clk == START_NULLIFIER_EXISTS_OFFSET; }); - EXPECT_EQ(nullifier_out_row->kernel_kernel_value_out, 1); // value - EXPECT_EQ(nullifier_out_row->kernel_kernel_side_effect_out, 1); - EXPECT_EQ(nullifier_out_row->kernel_kernel_metadata_out, 1); // exists + EXPECT_EQ(nullifier_out_row->main_kernel_value_out, 1); // value + EXPECT_EQ(nullifier_out_row->main_kernel_side_effect_out, 1); + EXPECT_EQ(nullifier_out_row->main_kernel_metadata_out, 1); // exists feed_output(START_NULLIFIER_EXISTS_OFFSET, 1, 1, 1); // CHECK L1TOL2MSGEXISTS @@ -2211,13 +2211,13 @@ TEST_F(AvmExecutionTests, kernelOutputHashExistsOpcodes) std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.main_sel_op_l1_to_l2_msg_exists == 1; }); EXPECT_EQ(l1_to_l2_row->main_ia, 1); // Read value EXPECT_EQ(l1_to_l2_row->main_ib, 1); // Storage slot - EXPECT_EQ(l1_to_l2_row->kernel_side_effect_counter, 2); + EXPECT_EQ(l1_to_l2_row->main_side_effect_counter, 2); auto msg_out_row = std::ranges::find_if( trace.begin(), trace.end(), [&](Row r) { return r.main_clk == START_L1_TO_L2_MSG_EXISTS_WRITE_OFFSET; }); - EXPECT_EQ(msg_out_row->kernel_kernel_value_out, 1); // value - EXPECT_EQ(msg_out_row->kernel_kernel_side_effect_out, 2); - EXPECT_EQ(msg_out_row->kernel_kernel_metadata_out, 1); // exists + EXPECT_EQ(msg_out_row->main_kernel_value_out, 1); // value + EXPECT_EQ(msg_out_row->main_kernel_side_effect_out, 2); + EXPECT_EQ(msg_out_row->main_kernel_metadata_out, 1); // exists feed_output(START_L1_TO_L2_MSG_EXISTS_WRITE_OFFSET, 1, 2, 1); validate_trace(std::move(trace), public_inputs); diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/tests/helpers.test.cpp b/barretenberg/cpp/src/barretenberg/vm/avm/tests/helpers.test.cpp index b34585894893..26851bc304e6 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/tests/helpers.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/tests/helpers.test.cpp @@ -41,7 +41,6 @@ void validate_trace(std::vector&& trace, bool with_proof, bool expect_proof_failure) { - setenv("AVM_VERBOSE_ERRORS", "1", 1); const std::string avm_dump_trace_path = std::getenv("AVM_DUMP_TRACE_PATH") != nullptr ? std::getenv("AVM_DUMP_TRACE_PATH") : ""; if (!avm_dump_trace_path.empty()) { diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/tests/kernel.test.cpp b/barretenberg/cpp/src/barretenberg/vm/avm/tests/kernel.test.cpp index 6dc5b273d6a2..15277be8c489 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/tests/kernel.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/tests/kernel.test.cpp @@ -83,7 +83,7 @@ void test_kernel_lookup(bool indirect, void expect_row(auto row, FF selector, FF ia, FF ind_a, FF mem_addr_a, AvmMemoryTag w_in_tag) { // Checks dependent on the opcode - EXPECT_EQ(row->kernel_kernel_in_offset, selector); + EXPECT_EQ(row->main_kernel_in_offset, selector); EXPECT_EQ(row->main_ia, ia); EXPECT_EQ(row->main_mem_addr_a, mem_addr_a); @@ -106,7 +106,7 @@ void expect_output_table_row(auto row, uint32_t rwa = 0) { // Checks dependent on the opcode - EXPECT_EQ(row->kernel_kernel_out_offset, selector); + EXPECT_EQ(row->main_kernel_out_offset, selector); EXPECT_EQ(row->main_ia, ia); EXPECT_EQ(row->main_mem_addr_a, mem_addr_a); @@ -118,7 +118,7 @@ void expect_output_table_row(auto row, EXPECT_EQ(row->main_r_in_tag, static_cast(r_in_tag)); EXPECT_EQ(row->main_sel_q_kernel_output_lookup, FF(1)); - EXPECT_EQ(row->kernel_side_effect_counter, FF(side_effect_counter)); + EXPECT_EQ(row->main_side_effect_counter, FF(side_effect_counter)); } void expect_output_table_row_with_metadata(auto row, @@ -174,9 +174,9 @@ void expect_output_table_row_with_exists_metadata(auto row, void check_kernel_outputs(const Row& row, FF value, FF side_effect_counter, FF metadata) { - EXPECT_EQ(row.kernel_kernel_value_out, value); - EXPECT_EQ(row.kernel_kernel_side_effect_out, side_effect_counter); - EXPECT_EQ(row.kernel_kernel_metadata_out, metadata); + EXPECT_EQ(row.main_kernel_value_out, value); + EXPECT_EQ(row.main_kernel_side_effect_out, side_effect_counter); + EXPECT_EQ(row.main_kernel_metadata_out, metadata); } TEST_F(AvmKernelPositiveTests, kernelSender) @@ -951,12 +951,12 @@ TEST_F(AvmKernelOutputPositiveTests, kernelEmitNoteHash) // We write the note hash into memory auto direct_apply_opcodes = [=](AvmTraceBuilder& trace_builder) { trace_builder.op_set(0, 1234, direct_offset, AvmMemoryTag::FF); - trace_builder.op_emit_note_hash(/*indirect=*/false, direct_offset); + trace_builder.op_emit_note_hash(/*indirect=*/0, direct_offset); }; auto indirect_apply_opcodes = [=](AvmTraceBuilder& trace_builder) { trace_builder.op_set(0, 1234, direct_offset, AvmMemoryTag::FF); trace_builder.op_set(0, direct_offset, indirect_offset, AvmMemoryTag::U32); - trace_builder.op_emit_note_hash(/*indirect=*/true, indirect_offset); + trace_builder.op_emit_note_hash(/*indirect=*/1, indirect_offset); }; auto checks = [=](bool indirect, const std::vector& trace) { @@ -993,12 +993,12 @@ TEST_F(AvmKernelOutputPositiveTests, kernelEmitNullifier) // We write the note hash into memory auto direct_apply_opcodes = [=](AvmTraceBuilder& trace_builder) { trace_builder.op_set(0, 1234, direct_offset, AvmMemoryTag::FF); - trace_builder.op_emit_nullifier(/*indirect=*/false, direct_offset); + trace_builder.op_emit_nullifier(/*indirect=*/0, direct_offset); }; auto indirect_apply_opcodes = [=](AvmTraceBuilder& trace_builder) { trace_builder.op_set(0, 1234, direct_offset, AvmMemoryTag::FF); trace_builder.op_set(0, direct_offset, indirect_offset, AvmMemoryTag::U32); - trace_builder.op_emit_nullifier(/*indirect=*/true, indirect_offset); + trace_builder.op_emit_nullifier(/*indirect=*/1, indirect_offset); }; auto checks = [=](bool indirect, const std::vector& trace) { @@ -1038,11 +1038,11 @@ TEST_F(AvmKernelOutputPositiveTests, kernelEmitL2ToL1Msg) uint32_t recipient = 420; uint32_t output_offset = START_EMIT_L2_TO_L1_MSG_WRITE_OFFSET; - // auto direct_apply_opcodes = [=](AvmTraceBuilder& trace_builder) { - // trace_builder.op_set(0, 1234, msg_offset, AvmMemoryTag::FF); - // trace_builder.op_set(0, 420, recipient_offset, AvmMemoryTag::FF); - // trace_builder.op_emit_l2_to_l1_msg(false, recipient_offset, msg_offset); - // }; + auto direct_apply_opcodes = [=](AvmTraceBuilder& trace_builder) { + trace_builder.op_set(0, 1234, msg_offset, AvmMemoryTag::FF); + trace_builder.op_set(0, 420, recipient_offset, AvmMemoryTag::FF); + trace_builder.op_emit_l2_to_l1_msg(0, recipient_offset, msg_offset); + }; auto indirect_apply_opcodes = [=](AvmTraceBuilder& trace_builder) { trace_builder.op_set(0, 1234, msg_offset, AvmMemoryTag::FF); trace_builder.op_set(0, msg_offset, indirect_msg_offset, AvmMemoryTag::U32); @@ -1071,9 +1071,9 @@ TEST_F(AvmKernelOutputPositiveTests, kernelEmitL2ToL1Msg) check_kernel_outputs(trace.at(output_offset), value, /*side_effect_counter=*/0, /*metadata=*/recipient); }; - // test_kernel_lookup(false, direct_apply_opcodes, checks); VmPublicInputs public_inputs = get_public_inputs_with_output(output_offset, value, /*side_effect_counter=*/0, recipient); + test_kernel_lookup(false, direct_apply_opcodes, checks, std::move(public_inputs)); test_kernel_lookup(true, indirect_apply_opcodes, checks, std::move(public_inputs)); } @@ -1088,12 +1088,12 @@ TEST_F(AvmKernelOutputPositiveTests, kernelEmitUnencryptedLog) // We write the note hash into memory auto direct_apply_opcodes = [=](AvmTraceBuilder& trace_builder) { trace_builder.op_set(0, 1234, direct_offset, AvmMemoryTag::FF); - trace_builder.op_emit_unencrypted_log(/*indirect=*/false, direct_offset, /*log_size_offset=*/0); + trace_builder.op_emit_unencrypted_log(/*indirect=*/0, direct_offset, /*log_size_offset=*/0); }; auto indirect_apply_opcodes = [=](AvmTraceBuilder& trace_builder) { trace_builder.op_set(0, 1234, direct_offset, AvmMemoryTag::FF); trace_builder.op_set(0, direct_offset, indirect_offset, AvmMemoryTag::U32); - trace_builder.op_emit_unencrypted_log(/*indirect=*/true, indirect_offset, /*log_size_offset=*/0); + trace_builder.op_emit_unencrypted_log(/*indirect=*/1, indirect_offset, /*log_size_offset=*/0); }; auto checks = [=](bool indirect, const std::vector& trace) { @@ -1264,7 +1264,7 @@ TEST_F(AvmKernelOutputPositiveTests, kernelNullifierExists) auto apply_opcodes = [=](AvmTraceBuilder& trace_builder) { trace_builder.op_set(0, static_cast(value), value_offset, AvmMemoryTag::FF); - trace_builder.op_nullifier_exists(/*indirect=*/false, value_offset, metadata_offset); + trace_builder.op_nullifier_exists(/*indirect=*/0, value_offset, metadata_offset); }; auto checks = [=](bool indirect, const std::vector& trace) { auto row = std::ranges::find_if( @@ -1303,7 +1303,7 @@ TEST_F(AvmKernelOutputPositiveTests, kernelNullifierNonExists) auto apply_opcodes = [=](AvmTraceBuilder& trace_builder) { trace_builder.op_set(0, static_cast(value), value_offset, AvmMemoryTag::FF); - trace_builder.op_nullifier_exists(/*indirect=*/false, value_offset, metadata_offset); + trace_builder.op_nullifier_exists(/*indirect=*/0, value_offset, metadata_offset); }; auto checks = [=](bool indirect, const std::vector& trace) { auto row = std::ranges::find_if( diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/trace/common.hpp b/barretenberg/cpp/src/barretenberg/vm/avm/trace/common.hpp index 1710120b7dce..18d7019e229b 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/trace/common.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/trace/common.hpp @@ -1,7 +1,6 @@ #pragma once #include "barretenberg/common/throw_or_abort.hpp" -#include "barretenberg/serialize/msgpack.hpp" #include "barretenberg/vm/constants.hpp" #include "barretenberg/vm/avm/generated/flavor_settings.hpp" @@ -9,8 +8,6 @@ #include #include -#include -#include namespace bb::avm_trace { @@ -35,8 +32,6 @@ constexpr size_t L2_LO_GAS_COUNTS_IDX = 1; constexpr size_t DA_HI_GAS_COUNTS_IDX = 2; constexpr size_t DA_LO_GAS_COUNTS_IDX = 3; -// Number of rows -static const size_t AVM_TRACE_SIZE = 1 << 18; enum class IntermRegister : uint32_t { IA = 0, IB = 1, IC = 2, ID = 3 }; enum class IndirectRegister : uint32_t { IND_A = 0, IND_B = 1, IND_C = 2, IND_D = 3 }; @@ -48,159 +43,4 @@ static const size_t NUM_MEM_SPACES = 256; static const uint8_t INTERNAL_CALL_SPACE_ID = 255; static const uint32_t MAX_SIZE_INTERNAL_STACK = 1 << 16; -struct ExternalCallHint { - FF success; - std::vector return_data; - uint32_t l2_gas_used; - uint32_t da_gas_used; - FF end_side_effect_counter; -}; - -// Add support for deserialization of ExternalCallHint. This is implicitly used by serialize::read -// when trying to read std::vector. -inline void read(uint8_t const*& it, ExternalCallHint& hint) -{ - using serialize::read; - read(it, hint.success); - read(it, hint.return_data); - read(it, hint.l2_gas_used); - read(it, hint.da_gas_used); - read(it, hint.end_side_effect_counter); -} - -struct ContractInstanceHint { - FF address; - FF instance_found_in_address; - FF salt; - FF deployer_addr; - FF contract_class_id; - FF initialisation_hash; - FF public_key_hash; -}; - -// Add support for deserialization of ContractInstanceHint. -inline void read(uint8_t const*& it, ContractInstanceHint& hint) -{ - using serialize::read; - read(it, hint.address); - read(it, hint.instance_found_in_address); - read(it, hint.salt); - read(it, hint.deployer_addr); - read(it, hint.contract_class_id); - read(it, hint.initialisation_hash); - read(it, hint.public_key_hash); -} - -struct ExecutionHints { - std::vector> storage_value_hints; - std::vector> note_hash_exists_hints; - std::vector> nullifier_exists_hints; - std::vector> l1_to_l2_message_exists_hints; - std::vector externalcall_hints; - std::map contract_instance_hints; - - ExecutionHints() = default; - - // Builder. - ExecutionHints& with_storage_value_hints(std::vector> storage_value_hints) - { - this->storage_value_hints = std::move(storage_value_hints); - return *this; - } - ExecutionHints& with_note_hash_exists_hints(std::vector> note_hash_exists_hints) - { - this->note_hash_exists_hints = std::move(note_hash_exists_hints); - return *this; - } - ExecutionHints& with_nullifier_exists_hints(std::vector> nullifier_exists_hints) - { - this->nullifier_exists_hints = std::move(nullifier_exists_hints); - return *this; - } - ExecutionHints& with_l1_to_l2_message_exists_hints(std::vector> l1_to_l2_message_exists_hints) - { - this->l1_to_l2_message_exists_hints = std::move(l1_to_l2_message_exists_hints); - return *this; - } - ExecutionHints& with_externalcall_hints(std::vector externalcall_hints) - { - this->externalcall_hints = std::move(externalcall_hints); - return *this; - } - ExecutionHints& with_contract_instance_hints(std::map contract_instance_hints) - { - this->contract_instance_hints = std::move(contract_instance_hints); - return *this; - } - - static void push_vec_into_map(std::unordered_map& into_map, - const std::vector>& from_pair_vec) - { - for (const auto& pair : from_pair_vec) { - into_map[static_cast(pair.first)] = pair.second; - } - } - - // TODO: Cache. - // Side effect counter -> value - std::unordered_map get_side_effect_hints() const - { - std::unordered_map hints_map; - push_vec_into_map(hints_map, storage_value_hints); - push_vec_into_map(hints_map, note_hash_exists_hints); - push_vec_into_map(hints_map, nullifier_exists_hints); - push_vec_into_map(hints_map, l1_to_l2_message_exists_hints); - return hints_map; - } - - static ExecutionHints from(const std::vector& data) - { - std::vector> storage_value_hints; - std::vector> note_hash_exists_hints; - std::vector> nullifier_exists_hints; - std::vector> l1_to_l2_message_exists_hints; - - using serialize::read; - const auto* it = data.data(); - read(it, storage_value_hints); - read(it, note_hash_exists_hints); - read(it, nullifier_exists_hints); - read(it, l1_to_l2_message_exists_hints); - - std::vector externalcall_hints; - read(it, externalcall_hints); - - std::vector contract_instance_hints_vec; - read(it, contract_instance_hints_vec); - std::map contract_instance_hints; - for (const auto& instance : contract_instance_hints_vec) { - contract_instance_hints[instance.address] = instance; - } - - if (it != data.data() + data.size()) { - throw_or_abort("Failed to deserialize ExecutionHints: only read" + std::to_string(it - data.data()) + - " bytes out of " + std::to_string(data.size()) + " bytes"); - } - - return { std::move(storage_value_hints), std::move(note_hash_exists_hints), - std::move(nullifier_exists_hints), std::move(l1_to_l2_message_exists_hints), - std::move(externalcall_hints), std::move(contract_instance_hints) }; - } - - private: - ExecutionHints(std::vector> storage_value_hints, - std::vector> note_hash_exists_hints, - std::vector> nullifier_exists_hints, - std::vector> l1_to_l2_message_exists_hints, - std::vector externalcall_hints, - std::map contract_instance_hints) - : storage_value_hints(std::move(storage_value_hints)) - , note_hash_exists_hints(std::move(note_hash_exists_hints)) - , nullifier_exists_hints(std::move(nullifier_exists_hints)) - , l1_to_l2_message_exists_hints(std::move(l1_to_l2_message_exists_hints)) - , externalcall_hints(std::move(externalcall_hints)) - , contract_instance_hints(std::move(contract_instance_hints)) - {} -}; - } // namespace bb::avm_trace diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/trace/execution_hints.hpp b/barretenberg/cpp/src/barretenberg/vm/avm/trace/execution_hints.hpp new file mode 100644 index 000000000000..df54b770f059 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/avm/trace/execution_hints.hpp @@ -0,0 +1,164 @@ +#pragma once + +#include "barretenberg/vm/avm/generated/flavor_settings.hpp" + +namespace bb::avm_trace { + +using FF = AvmFlavorSettings::FF; + +struct ExternalCallHint { + FF success; + std::vector return_data; + uint32_t l2_gas_used; + uint32_t da_gas_used; + FF end_side_effect_counter; +}; + +// Add support for deserialization of ExternalCallHint. This is implicitly used by serialize::read +// when trying to read std::vector. +inline void read(uint8_t const*& it, ExternalCallHint& hint) +{ + using serialize::read; + read(it, hint.success); + read(it, hint.return_data); + read(it, hint.l2_gas_used); + read(it, hint.da_gas_used); + read(it, hint.end_side_effect_counter); +} + +struct ContractInstanceHint { + FF address; + FF instance_found_in_address; + FF salt; + FF deployer_addr; + FF contract_class_id; + FF initialisation_hash; + FF public_key_hash; +}; + +// Add support for deserialization of ContractInstanceHint. +inline void read(uint8_t const*& it, ContractInstanceHint& hint) +{ + using serialize::read; + read(it, hint.address); + read(it, hint.instance_found_in_address); + read(it, hint.salt); + read(it, hint.deployer_addr); + read(it, hint.contract_class_id); + read(it, hint.initialisation_hash); + read(it, hint.public_key_hash); +} + +struct ExecutionHints { + std::vector> storage_value_hints; + std::vector> note_hash_exists_hints; + std::vector> nullifier_exists_hints; + std::vector> l1_to_l2_message_exists_hints; + std::vector externalcall_hints; + std::map contract_instance_hints; + + ExecutionHints() = default; + + // Builder. + ExecutionHints& with_storage_value_hints(std::vector> storage_value_hints) + { + this->storage_value_hints = std::move(storage_value_hints); + return *this; + } + ExecutionHints& with_note_hash_exists_hints(std::vector> note_hash_exists_hints) + { + this->note_hash_exists_hints = std::move(note_hash_exists_hints); + return *this; + } + ExecutionHints& with_nullifier_exists_hints(std::vector> nullifier_exists_hints) + { + this->nullifier_exists_hints = std::move(nullifier_exists_hints); + return *this; + } + ExecutionHints& with_l1_to_l2_message_exists_hints(std::vector> l1_to_l2_message_exists_hints) + { + this->l1_to_l2_message_exists_hints = std::move(l1_to_l2_message_exists_hints); + return *this; + } + ExecutionHints& with_externalcall_hints(std::vector externalcall_hints) + { + this->externalcall_hints = std::move(externalcall_hints); + return *this; + } + ExecutionHints& with_contract_instance_hints(std::map contract_instance_hints) + { + this->contract_instance_hints = std::move(contract_instance_hints); + return *this; + } + + static void push_vec_into_map(std::unordered_map& into_map, + const std::vector>& from_pair_vec) + { + for (const auto& pair : from_pair_vec) { + into_map[static_cast(pair.first)] = pair.second; + } + } + + // TODO: Cache. + // Side effect counter -> value + std::unordered_map get_side_effect_hints() const + { + std::unordered_map hints_map; + push_vec_into_map(hints_map, storage_value_hints); + push_vec_into_map(hints_map, note_hash_exists_hints); + push_vec_into_map(hints_map, nullifier_exists_hints); + push_vec_into_map(hints_map, l1_to_l2_message_exists_hints); + return hints_map; + } + + static ExecutionHints from(const std::vector& data) + { + std::vector> storage_value_hints; + std::vector> note_hash_exists_hints; + std::vector> nullifier_exists_hints; + std::vector> l1_to_l2_message_exists_hints; + + using serialize::read; + const auto* it = data.data(); + read(it, storage_value_hints); + read(it, note_hash_exists_hints); + read(it, nullifier_exists_hints); + read(it, l1_to_l2_message_exists_hints); + + std::vector externalcall_hints; + read(it, externalcall_hints); + + std::vector contract_instance_hints_vec; + read(it, contract_instance_hints_vec); + std::map contract_instance_hints; + for (const auto& instance : contract_instance_hints_vec) { + contract_instance_hints[instance.address] = instance; + } + + if (it != data.data() + data.size()) { + throw_or_abort("Failed to deserialize ExecutionHints: only read" + std::to_string(it - data.data()) + + " bytes out of " + std::to_string(data.size()) + " bytes"); + } + + return { std::move(storage_value_hints), std::move(note_hash_exists_hints), + std::move(nullifier_exists_hints), std::move(l1_to_l2_message_exists_hints), + std::move(externalcall_hints), std::move(contract_instance_hints) }; + } + + private: + ExecutionHints(std::vector> storage_value_hints, + std::vector> note_hash_exists_hints, + std::vector> nullifier_exists_hints, + std::vector> l1_to_l2_message_exists_hints, + std::vector externalcall_hints, + std::map contract_instance_hints) + : storage_value_hints(std::move(storage_value_hints)) + , note_hash_exists_hints(std::move(note_hash_exists_hints)) + , nullifier_exists_hints(std::move(nullifier_exists_hints)) + , l1_to_l2_message_exists_hints(std::move(l1_to_l2_message_exists_hints)) + , externalcall_hints(std::move(externalcall_hints)) + , contract_instance_hints(std::move(contract_instance_hints)) + {} +}; + +} // namespace bb::avm_trace \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/trace/finalization.hpp b/barretenberg/cpp/src/barretenberg/vm/avm/trace/finalization.hpp new file mode 100644 index 000000000000..52bcde8b638f --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/avm/trace/finalization.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include "barretenberg/common/assert.hpp" +#include "barretenberg/vm/avm/generated/full_row.hpp" +#include "barretenberg/vm/avm/trace/common.hpp" + +#include +#include + +namespace bb::avm_trace { + +/** + * @brief Iterates over the main trace and an event trace and performs an action. + * @details This function iterates on the main trace and an event trace and applies: + * - `func_map` when the main trace clk matches the event trace clk. + * - `func_all` for all rows that are EXECUTION trace rows. + * This function assumes that the clks in the traces are monotonically increasing. + */ +template +void iterate_with_actions(const S& src, std::vector>& main_trace, M&& func_map, A&& func_all) +{ + size_t src_idx = 0; + size_t dst_idx = 0; + while (src_idx < src.size() && dst_idx < main_trace.size()) { + if (FF(src.at(src_idx).clk) == main_trace.at(dst_idx).main_clk) { + func_map(src_idx, dst_idx); + ++src_idx; + } + ++dst_idx; + } + + for (size_t dst_idx = 0; dst_idx < main_trace.size(); ++dst_idx) { + if (main_trace.at(dst_idx).main_sel_execution_row == 1) { + func_all(dst_idx); + } + } +} + +} // namespace bb::avm_trace \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/trace/kernel_trace.cpp b/barretenberg/cpp/src/barretenberg/vm/avm/trace/kernel_trace.cpp index d5b03da2395b..8564a7eed2b3 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/trace/kernel_trace.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/trace/kernel_trace.cpp @@ -1,5 +1,8 @@ #include "barretenberg/vm/avm/trace/kernel_trace.hpp" +#include "barretenberg/common/throw_or_abort.hpp" +#include "barretenberg/vm/avm/generated/full_row.hpp" #include "barretenberg/vm/avm/trace/common.hpp" +#include "barretenberg/vm/avm/trace/finalization.hpp" #include "barretenberg/vm/avm/trace/trace.hpp" #include "barretenberg/vm/constants.hpp" @@ -11,21 +14,13 @@ namespace bb::avm_trace { -AvmKernelTraceBuilder::AvmKernelTraceBuilder(VmPublicInputs public_inputs) - : public_inputs(std::move(public_inputs)) -{} - void AvmKernelTraceBuilder::reset() { + kernel_trace.clear(); kernel_input_selector_counter.clear(); kernel_output_selector_counter.clear(); } -std::vector AvmKernelTraceBuilder::finalize() -{ - return std::move(kernel_trace); -} - FF AvmKernelTraceBuilder::perform_kernel_input_lookup(uint32_t selector) { FF result = std::get<0>(public_inputs)[selector]; @@ -49,62 +44,123 @@ void AvmKernelTraceBuilder::perform_kernel_output_lookup(uint32_t write_offset, // We want to be able to get the return value from the public inputs column // Get the return value, this will be places in ia // We read from the public inputs that were provided to the kernel -FF AvmKernelTraceBuilder::op_address() +FF AvmKernelTraceBuilder::op_address(uint32_t clk) { + KernelTraceEntry entry = { + .clk = clk, + .operation = KernelTraceOpType::ADDRESS, + }; + kernel_trace.push_back(entry); return perform_kernel_input_lookup(ADDRESS_SELECTOR); } -FF AvmKernelTraceBuilder::op_storage_address() + +FF AvmKernelTraceBuilder::op_storage_address(uint32_t clk) { + KernelTraceEntry entry = { + .clk = clk, + .operation = KernelTraceOpType::STORAGE_ADDRESS, + }; + kernel_trace.push_back(entry); return perform_kernel_input_lookup(STORAGE_ADDRESS_SELECTOR); } -FF AvmKernelTraceBuilder::op_sender() +FF AvmKernelTraceBuilder::op_sender(uint32_t clk) { + KernelTraceEntry entry = { + .clk = clk, + .operation = KernelTraceOpType::SENDER, + }; + kernel_trace.push_back(entry); return perform_kernel_input_lookup(SENDER_SELECTOR); } -FF AvmKernelTraceBuilder::op_function_selector() +FF AvmKernelTraceBuilder::op_function_selector(uint32_t clk) { + KernelTraceEntry entry = { + .clk = clk, + .operation = KernelTraceOpType::FUNCTION_SELECTOR, + }; + kernel_trace.push_back(entry); return perform_kernel_input_lookup(FUNCTION_SELECTOR_SELECTOR); } -FF AvmKernelTraceBuilder::op_transaction_fee() +FF AvmKernelTraceBuilder::op_transaction_fee(uint32_t clk) { + KernelTraceEntry entry = { + .clk = clk, + .operation = KernelTraceOpType::TRANSACTION_FEE, + }; + kernel_trace.push_back(entry); return perform_kernel_input_lookup(TRANSACTION_FEE_SELECTOR); } -FF AvmKernelTraceBuilder::op_chain_id() +FF AvmKernelTraceBuilder::op_chain_id(uint32_t clk) { + KernelTraceEntry entry = { + .clk = clk, + .operation = KernelTraceOpType::CHAIN_ID, + }; + kernel_trace.push_back(entry); return perform_kernel_input_lookup(CHAIN_ID_SELECTOR); } -FF AvmKernelTraceBuilder::op_version() +FF AvmKernelTraceBuilder::op_version(uint32_t clk) { + KernelTraceEntry entry = { + .clk = clk, + .operation = KernelTraceOpType::VERSION, + }; + kernel_trace.push_back(entry); return perform_kernel_input_lookup(VERSION_SELECTOR); } -FF AvmKernelTraceBuilder::op_block_number() +FF AvmKernelTraceBuilder::op_block_number(uint32_t clk) { + KernelTraceEntry entry = { + .clk = clk, + .operation = KernelTraceOpType::BLOCK_NUMBER, + }; + kernel_trace.push_back(entry); return perform_kernel_input_lookup(BLOCK_NUMBER_SELECTOR); } -FF AvmKernelTraceBuilder::op_coinbase() +FF AvmKernelTraceBuilder::op_coinbase(uint32_t clk) { + KernelTraceEntry entry = { + .clk = clk, + .operation = KernelTraceOpType::COINBASE, + }; + kernel_trace.push_back(entry); return perform_kernel_input_lookup(COINBASE_SELECTOR); } -FF AvmKernelTraceBuilder::op_timestamp() +FF AvmKernelTraceBuilder::op_timestamp(uint32_t clk) { + KernelTraceEntry entry = { + .clk = clk, + .operation = KernelTraceOpType::TIMESTAMP, + }; + kernel_trace.push_back(entry); return perform_kernel_input_lookup(TIMESTAMP_SELECTOR); } -FF AvmKernelTraceBuilder::op_fee_per_da_gas() +FF AvmKernelTraceBuilder::op_fee_per_da_gas(uint32_t clk) { + KernelTraceEntry entry = { + .clk = clk, + .operation = KernelTraceOpType::FEE_PER_DA_GAS, + }; + kernel_trace.push_back(entry); return perform_kernel_input_lookup(FEE_PER_DA_GAS_SELECTOR); } -FF AvmKernelTraceBuilder::op_fee_per_l2_gas() +FF AvmKernelTraceBuilder::op_fee_per_l2_gas(uint32_t clk) { + KernelTraceEntry entry = { + .clk = clk, + .operation = KernelTraceOpType::FEE_PER_L2_GAS, + }; + kernel_trace.push_back(entry); return perform_kernel_input_lookup(FEE_PER_L2_GAS_SELECTOR); } @@ -123,8 +179,7 @@ void AvmKernelTraceBuilder::op_note_hash_exists(uint32_t clk, KernelTraceEntry entry = { .clk = clk, .kernel_out_offset = offset, - .q_kernel_output_lookup = true, - .op_note_hash_exists = true, + .operation = KernelTraceOpType::NOTE_HASH_EXISTS, }; kernel_trace.push_back(entry); } @@ -138,8 +193,7 @@ void AvmKernelTraceBuilder::op_emit_note_hash(uint32_t clk, uint32_t side_effect KernelTraceEntry entry = { .clk = clk, .kernel_out_offset = offset, - .q_kernel_output_lookup = true, - .op_emit_note_hash = true, + .operation = KernelTraceOpType::EMIT_NOTE_HASH, }; kernel_trace.push_back(entry); } @@ -164,8 +218,7 @@ void AvmKernelTraceBuilder::op_nullifier_exists(uint32_t clk, KernelTraceEntry entry = { .clk = clk, .kernel_out_offset = offset, - .q_kernel_output_lookup = true, - .op_nullifier_exists = true, + .operation = KernelTraceOpType::NULLIFIER_EXISTS, }; kernel_trace.push_back(entry); } @@ -179,8 +232,7 @@ void AvmKernelTraceBuilder::op_emit_nullifier(uint32_t clk, uint32_t side_effect KernelTraceEntry entry = { .clk = clk, .kernel_out_offset = offset, - .q_kernel_output_lookup = true, - .op_emit_nullifier = true, + .operation = KernelTraceOpType::EMIT_NULLIFIER, }; kernel_trace.push_back(entry); } @@ -199,8 +251,7 @@ void AvmKernelTraceBuilder::op_l1_to_l2_msg_exists(uint32_t clk, KernelTraceEntry entry = { .clk = clk, .kernel_out_offset = offset, - .q_kernel_output_lookup = true, - .op_l1_to_l2_msg_exists = true, + .operation = KernelTraceOpType::L1_TO_L2_MSG_EXISTS, }; kernel_trace.push_back(entry); } @@ -214,8 +265,7 @@ void AvmKernelTraceBuilder::op_emit_unencrypted_log(uint32_t clk, uint32_t side_ KernelTraceEntry entry = { .clk = clk, .kernel_out_offset = offset, - .q_kernel_output_lookup = true, - .op_emit_unencrypted_log = true, + .operation = KernelTraceOpType::EMIT_UNENCRYPTED_LOG, }; kernel_trace.push_back(entry); } @@ -232,8 +282,7 @@ void AvmKernelTraceBuilder::op_emit_l2_to_l1_msg(uint32_t clk, KernelTraceEntry entry = { .clk = clk, .kernel_out_offset = offset, - .q_kernel_output_lookup = true, - .op_emit_l2_to_l1_msg = true, + .operation = KernelTraceOpType::EMIT_L2_TO_L1_MSG, }; kernel_trace.push_back(entry); } @@ -247,8 +296,7 @@ void AvmKernelTraceBuilder::op_sload(uint32_t clk, uint32_t side_effect_counter, KernelTraceEntry entry = { .clk = clk, .kernel_out_offset = offset, - .q_kernel_output_lookup = true, - .op_sload = true, + .operation = KernelTraceOpType::SLOAD, }; kernel_trace.push_back(entry); } @@ -262,10 +310,207 @@ void AvmKernelTraceBuilder::op_sstore(uint32_t clk, uint32_t side_effect_counter KernelTraceEntry entry = { .clk = clk, .kernel_out_offset = offset, - .q_kernel_output_lookup = true, - .op_sstore = true, + .operation = KernelTraceOpType::SSTORE, }; kernel_trace.push_back(entry); } +void AvmKernelTraceBuilder::finalize(std::vector>& main_trace) +{ + // Write the kernel trace into the main trace + // 1. The write offsets are constrained to be non changing over the entire trace, so we fill in the values + // until we hit an operation that changes one of the write_offsets (a relevant opcode) + // 2. Upon hitting the clk of each kernel operation we copy the values into the main trace + // 3. When an increment is required, we increment the value in the next row, then continue the process until + // the end + // 4. Whenever we hit the last row, we zero all write_offsets such that the shift relation will succeed + + // Index 0 corresponds here to the first active row of the main execution trace. + // Initialization of side_effect_counter occurs occurs on this row. + main_trace.at(0).main_side_effect_counter = initial_side_effect_counter; + + // This index is required to retrieve the right side effect counter after an external call. + size_t external_call_cnt = 0; + + iterate_with_actions( + kernel_trace, + main_trace, + // Action to be performed on each kernel trace entry + // and its corresponding row in the main trace (clk match) + [&](size_t src_idx, size_t dst_idx) { + const auto& src = kernel_trace.at(src_idx); + auto& dest = main_trace.at(dst_idx); + + switch (src.operation) { + // IN + case KernelTraceOpType::ADDRESS: + dest.main_kernel_in_offset = ADDRESS_SELECTOR; + dest.main_sel_q_kernel_lookup = 1; + break; + case KernelTraceOpType::STORAGE_ADDRESS: + dest.main_kernel_in_offset = STORAGE_ADDRESS_SELECTOR; + dest.main_sel_q_kernel_lookup = 1; + break; + case KernelTraceOpType::SENDER: + dest.main_kernel_in_offset = SENDER_SELECTOR; + dest.main_sel_q_kernel_lookup = 1; + break; + case KernelTraceOpType::FUNCTION_SELECTOR: + dest.main_kernel_in_offset = FUNCTION_SELECTOR_SELECTOR; + dest.main_sel_q_kernel_lookup = 1; + break; + case KernelTraceOpType::TRANSACTION_FEE: + dest.main_kernel_in_offset = TRANSACTION_FEE_SELECTOR; + dest.main_sel_q_kernel_lookup = 1; + break; + case KernelTraceOpType::CHAIN_ID: + dest.main_kernel_in_offset = CHAIN_ID_SELECTOR; + dest.main_sel_q_kernel_lookup = 1; + break; + case KernelTraceOpType::VERSION: + dest.main_kernel_in_offset = VERSION_SELECTOR; + dest.main_sel_q_kernel_lookup = 1; + break; + case KernelTraceOpType::BLOCK_NUMBER: + dest.main_kernel_in_offset = BLOCK_NUMBER_SELECTOR; + dest.main_sel_q_kernel_lookup = 1; + break; + case KernelTraceOpType::COINBASE: + dest.main_kernel_in_offset = COINBASE_SELECTOR; + dest.main_sel_q_kernel_lookup = 1; + break; + case KernelTraceOpType::TIMESTAMP: + dest.main_kernel_in_offset = TIMESTAMP_SELECTOR; + dest.main_sel_q_kernel_lookup = 1; + break; + case KernelTraceOpType::FEE_PER_DA_GAS: + dest.main_kernel_in_offset = FEE_PER_DA_GAS_SELECTOR; + dest.main_sel_q_kernel_lookup = 1; + break; + case KernelTraceOpType::FEE_PER_L2_GAS: + dest.main_kernel_in_offset = FEE_PER_L2_GAS_SELECTOR; + dest.main_sel_q_kernel_lookup = 1; + break; + // OUT + case KernelTraceOpType::NOTE_HASH_EXISTS: + dest.main_kernel_out_offset = src.kernel_out_offset; + dest.main_sel_q_kernel_output_lookup = 1; + break; + case KernelTraceOpType::EMIT_NOTE_HASH: + dest.main_kernel_out_offset = src.kernel_out_offset; + dest.main_sel_q_kernel_output_lookup = 1; + break; + case KernelTraceOpType::NULLIFIER_EXISTS: + dest.main_kernel_out_offset = src.kernel_out_offset; + dest.main_sel_q_kernel_output_lookup = 1; + break; + case KernelTraceOpType::EMIT_NULLIFIER: + dest.main_kernel_out_offset = src.kernel_out_offset; + dest.main_sel_q_kernel_output_lookup = 1; + break; + case KernelTraceOpType::L1_TO_L2_MSG_EXISTS: + dest.main_kernel_out_offset = src.kernel_out_offset; + dest.main_sel_q_kernel_output_lookup = 1; + break; + case KernelTraceOpType::EMIT_UNENCRYPTED_LOG: + dest.main_kernel_out_offset = src.kernel_out_offset; + dest.main_sel_q_kernel_output_lookup = 1; + break; + case KernelTraceOpType::EMIT_L2_TO_L1_MSG: + dest.main_kernel_out_offset = src.kernel_out_offset; + dest.main_sel_q_kernel_output_lookup = 1; + break; + case KernelTraceOpType::SLOAD: + dest.main_kernel_out_offset = src.kernel_out_offset; + dest.main_sel_q_kernel_output_lookup = 1; + break; + case KernelTraceOpType::SSTORE: + dest.main_kernel_out_offset = src.kernel_out_offset; + dest.main_sel_q_kernel_output_lookup = 1; + break; + default: + throw_or_abort("Invalid operation selector"); + } + }, + // Action to be performed on every execution trace row. + [&](size_t dst_idx) { + const auto& curr = main_trace.at(dst_idx); + auto& next = main_trace.at(dst_idx + 1); + + next.main_note_hash_exist_write_offset = + curr.main_note_hash_exist_write_offset + curr.main_sel_op_note_hash_exists; + next.main_emit_note_hash_write_offset = + curr.main_emit_note_hash_write_offset + curr.main_sel_op_emit_note_hash; + next.main_emit_nullifier_write_offset = + curr.main_emit_nullifier_write_offset + curr.main_sel_op_emit_nullifier; + next.main_nullifier_exists_write_offset = + curr.main_nullifier_exists_write_offset + (curr.main_sel_op_nullifier_exists * curr.main_ib); + next.main_nullifier_non_exists_write_offset = curr.main_nullifier_non_exists_write_offset + + (curr.main_sel_op_nullifier_exists * (FF(1) - curr.main_ib)); + next.main_l1_to_l2_msg_exists_write_offset = + curr.main_l1_to_l2_msg_exists_write_offset + curr.main_sel_op_l1_to_l2_msg_exists; + next.main_emit_l2_to_l1_msg_write_offset = + curr.main_emit_l2_to_l1_msg_write_offset + curr.main_sel_op_emit_l2_to_l1_msg; + next.main_emit_unencrypted_log_write_offset = + curr.main_emit_unencrypted_log_write_offset + curr.main_sel_op_emit_unencrypted_log; + next.main_sload_write_offset = curr.main_sload_write_offset + curr.main_sel_op_sload; + next.main_sstore_write_offset = curr.main_sstore_write_offset + curr.main_sel_op_sstore; + + // Adjust side effect counter after an external call + if (curr.main_sel_op_external_call == 1) { + next.main_side_effect_counter = hints.externalcall_hints.at(external_call_cnt).end_side_effect_counter; + external_call_cnt++; + } else { + // The side effect counter will increment regardless of the offset value + // (as long as the operation is an OUTPUT operation). + next.main_side_effect_counter = curr.main_side_effect_counter + curr.main_sel_q_kernel_output_lookup; + } + }); +} + +// Public Input Columns Inclusion ("fixed" part of the trace). +// Crucial to add these columns after the extra row was added. +void AvmKernelTraceBuilder::finalize_columns(std::vector>& main_trace) const +{ + // Copy the kernel input public inputs + for (size_t i = 0; i < KERNEL_INPUTS_LENGTH; i++) { + auto& dest = main_trace.at(i); + dest.main_kernel_inputs = std::get(public_inputs).at(i); + dest.main_sel_kernel_inputs = FF(1); + } + + // Copy the kernel outputs counts into the main trace + for (size_t i = 0; i < KERNEL_OUTPUTS_LENGTH; i++) { + auto& dest = main_trace.at(i); + dest.main_kernel_value_out = std::get(public_inputs).at(i); + dest.main_kernel_side_effect_out = std::get(public_inputs).at(i); + dest.main_kernel_metadata_out = std::get(public_inputs).at(i); + dest.main_sel_kernel_out = FF(1); + } + + // Write lookup counts for inputs + for (auto const& [selector, count] : kernel_input_selector_counter) { + main_trace.at(selector).lookup_into_kernel_counts = FF(count); + } + // for (uint32_t i = 0; i < KERNEL_INPUTS_LENGTH; i++) { + // auto value = kernel_input_selector_counter.find(i); + // if (value != kernel_input_selector_counter.end()) { + // auto& dest = main_trace.at(i); + // dest.lookup_into_kernel_counts = FF(value->second); + // } + // } + + // Write lookup counts for outputs + for (auto const& [selector, count] : kernel_output_selector_counter) { + main_trace.at(selector).kernel_output_lookup_counts = FF(count); + } + // for (uint32_t i = 0; i < KERNEL_OUTPUTS_LENGTH; i++) { + // auto value = kernel_output_selector_counter.find(i); + // if (value != kernel_output_selector_counter.end()) { + // auto& dest = main_trace.at(i); + // dest.kernel_output_lookup_counts = FF(value->second); + // } + // } +} + } // namespace bb::avm_trace diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/trace/kernel_trace.hpp b/barretenberg/cpp/src/barretenberg/vm/avm/trace/kernel_trace.hpp index e5a4b7477446..773d68bba3fe 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/trace/kernel_trace.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/trace/kernel_trace.hpp @@ -2,6 +2,7 @@ #include "barretenberg/numeric/uint128/uint128.hpp" #include "barretenberg/vm/avm/trace/common.hpp" +#include "barretenberg/vm/avm/trace/execution_hints.hpp" #include "barretenberg/vm/constants.hpp" @@ -13,28 +14,42 @@ namespace bb::avm_trace { class AvmKernelTraceBuilder { public: + enum class KernelTraceOpType { + // IN + ADDRESS, + STORAGE_ADDRESS, + SENDER, + FUNCTION_SELECTOR, + TRANSACTION_FEE, + CHAIN_ID, + VERSION, + BLOCK_NUMBER, + COINBASE, + TIMESTAMP, + FEE_PER_DA_GAS, + FEE_PER_L2_GAS, + // OUT + SLOAD, + SSTORE, + NOTE_HASH_EXISTS, + EMIT_NOTE_HASH, + NULLIFIER_EXISTS, + EMIT_NULLIFIER, + L1_TO_L2_MSG_EXISTS, + EMIT_UNENCRYPTED_LOG, + EMIT_L2_TO_L1_MSG + }; + + // While the kernel trace is expected to be 1-1 with the main trace, + // we store it in "compressed form". That is, only actual operations are stored. + // Then, in finalize things are padded for in between clks. struct KernelTraceEntry { - // Clk - to join black onto the main trace uint32_t clk = 0; - uint32_t kernel_in_offset = 0; uint32_t kernel_out_offset = 0; - bool q_kernel_lookup = false; - bool q_kernel_output_lookup = false; - // In finalise, the main trace writes the correct write_offset for each operation based appearing selectors - bool op_note_hash_exists = false; - bool op_emit_note_hash = false; - bool op_nullifier_exists = false; - bool op_emit_nullifier = false; - bool op_l1_to_l2_msg_exists = false; - bool op_emit_unencrypted_log = false; - bool op_emit_l2_to_l1_msg = false; - bool op_sload = false; - bool op_sstore = false; + KernelTraceOpType operation; }; - VmPublicInputs public_inputs; - // Counts the number of accesses into each SELECTOR for the environment selector lookups; std::unordered_map kernel_input_selector_counter; @@ -42,28 +57,32 @@ class AvmKernelTraceBuilder { // optimise this to just hardcode the counter to be the same as the lookup selector value!!! std::unordered_map kernel_output_selector_counter; - // Constructor receives copy of kernel_inputs from the main trace builder - AvmKernelTraceBuilder(VmPublicInputs public_inputs); + AvmKernelTraceBuilder(uint32_t initial_side_effect_counter, VmPublicInputs public_inputs, ExecutionHints hints) + : initial_side_effect_counter(initial_side_effect_counter) + , public_inputs(std::move(public_inputs)) + , hints(std::move(hints)) + {} void reset(); - std::vector finalize(); + void finalize(std::vector>& main_trace); + void finalize_columns(std::vector>& main_trace) const; // Context - FF op_address(); - FF op_storage_address(); - FF op_sender(); - FF op_function_selector(); - FF op_transaction_fee(); + FF op_address(uint32_t clk); + FF op_storage_address(uint32_t clk); + FF op_sender(uint32_t clk); + FF op_function_selector(uint32_t clk); + FF op_transaction_fee(uint32_t clk); // Globals - FF op_chain_id(); - FF op_version(); - FF op_block_number(); - FF op_coinbase(); - FF op_timestamp(); + FF op_chain_id(uint32_t clk); + FF op_version(uint32_t clk); + FF op_block_number(uint32_t clk); + FF op_coinbase(uint32_t clk); + FF op_timestamp(uint32_t clk); // Globals - Gas - FF op_fee_per_da_gas(); - FF op_fee_per_l2_gas(); + FF op_fee_per_da_gas(uint32_t clk); + FF op_fee_per_l2_gas(uint32_t clk); // Outputs // Each returns the selector that was used @@ -80,6 +99,10 @@ class AvmKernelTraceBuilder { private: std::vector kernel_trace; + uint32_t initial_side_effect_counter; + VmPublicInputs public_inputs; + ExecutionHints hints; + // Output index counters uint32_t note_hash_exists_offset = 0; uint32_t emit_note_hash_offset = 0; @@ -89,7 +112,6 @@ class AvmKernelTraceBuilder { uint32_t l1_to_l2_msg_exists_offset = 0; uint32_t emit_unencrypted_log_offset = 0; uint32_t emit_l2_to_l1_msg_offset = 0; - uint32_t sload_write_offset = 0; uint32_t sstore_write_offset = 0; diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/trace/mem_trace.cpp b/barretenberg/cpp/src/barretenberg/vm/avm/trace/mem_trace.cpp index c9f0731757e0..cbe1ef4890bf 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/trace/mem_trace.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/trace/mem_trace.cpp @@ -6,15 +6,6 @@ namespace bb::avm_trace { -/** - * @brief Constructor of a memory trace builder of AVM. Only serves to set the capacity of the - * underlying traces. - */ -AvmMemTraceBuilder::AvmMemTraceBuilder() -{ - mem_trace.reserve(AVM_TRACE_SIZE); -} - /** * @brief Resetting the internal state so that a new memory trace can be rebuilt using the same object. * diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/trace/mem_trace.hpp b/barretenberg/cpp/src/barretenberg/vm/avm/trace/mem_trace.hpp index 0bdd8cc9ed44..56835aa77f53 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/trace/mem_trace.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/trace/mem_trace.hpp @@ -73,7 +73,7 @@ class AvmMemTraceBuilder { POSEIDON2, }; - AvmMemTraceBuilder(); + AvmMemTraceBuilder() = default; void reset(); diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/trace/trace.cpp b/barretenberg/cpp/src/barretenberg/vm/avm/trace/trace.cpp index 680a61995d89..a1bcdb2b3c17 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/trace/trace.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/trace/trace.cpp @@ -286,23 +286,19 @@ void AvmTraceBuilder::finalise_mem_trace_lookup_counts() * underlying traces and initialize gas values. */ AvmTraceBuilder::AvmTraceBuilder(VmPublicInputs public_inputs, - ExecutionHints execution_hints, + ExecutionHints execution_hints_, uint32_t side_effect_counter, std::vector calldata) // NOTE: we initialise the environment builder here as it requires public inputs - : kernel_trace_builder(std::move(public_inputs)) - , calldata(std::move(calldata)) + : calldata(std::move(calldata)) , side_effect_counter(side_effect_counter) - , initial_side_effect_counter(side_effect_counter) - , execution_hints(std::move(execution_hints)) + , execution_hints(std::move(execution_hints_)) + , kernel_trace_builder(side_effect_counter, public_inputs, execution_hints) { - main_trace.reserve(AVM_TRACE_SIZE); - // TODO: think about cast - gas_trace_builder.set_initial_gas(static_cast(std::get( - kernel_trace_builder.public_inputs)[L2_GAS_LEFT_CONTEXT_INPUTS_OFFSET]), - static_cast(std::get( - kernel_trace_builder.public_inputs)[DA_GAS_LEFT_CONTEXT_INPUTS_OFFSET])); + gas_trace_builder.set_initial_gas( + static_cast(std::get(public_inputs)[L2_GAS_LEFT_CONTEXT_INPUTS_OFFSET]), + static_cast(std::get(public_inputs)[DA_GAS_LEFT_CONTEXT_INPUTS_OFFSET])); } /************************************************************************************************** @@ -1259,8 +1255,7 @@ void AvmTraceBuilder::op_cast(uint8_t indirect, uint32_t a_offset, uint32_t dst_ * @param w_tag - The memory tag of the value read * @return Row */ -Row AvmTraceBuilder::create_kernel_lookup_opcode( - uint8_t indirect, uint32_t dst_offset, uint32_t selector, FF value, AvmMemoryTag w_tag) +Row AvmTraceBuilder::create_kernel_lookup_opcode(uint8_t indirect, uint32_t dst_offset, FF value, AvmMemoryTag w_tag) { auto const clk = static_cast(main_trace.size()) + 1; @@ -1270,7 +1265,6 @@ Row AvmTraceBuilder::create_kernel_lookup_opcode( return Row{ .main_clk = clk, - .kernel_kernel_in_offset = selector, .main_call_ptr = call_ptr, .main_ia = value, .main_ind_addr_a = FF(write_dst.indirect_address), @@ -1279,7 +1273,6 @@ Row AvmTraceBuilder::create_kernel_lookup_opcode( .main_pc = pc++, .main_rwa = 1, .main_sel_mem_op_a = 1, - .main_sel_q_kernel_lookup = 1, .main_sel_resolve_ind_addr_a = FF(static_cast(write_dst.is_indirect)), .main_tag_err = FF(static_cast(!write_dst.tag_match)), .main_w_in_tag = static_cast(w_tag), @@ -1288,8 +1281,9 @@ Row AvmTraceBuilder::create_kernel_lookup_opcode( void AvmTraceBuilder::op_address(uint8_t indirect, uint32_t dst_offset) { - FF ia_value = kernel_trace_builder.op_address(); - Row row = create_kernel_lookup_opcode(indirect, dst_offset, ADDRESS_SELECTOR, ia_value, AvmMemoryTag::FF); + auto const clk = static_cast(main_trace.size()) + 1; + FF ia_value = kernel_trace_builder.op_address(clk); + Row row = create_kernel_lookup_opcode(indirect, dst_offset, ia_value, AvmMemoryTag::FF); row.main_sel_op_address = FF(1); // Constrain gas cost @@ -1300,8 +1294,9 @@ void AvmTraceBuilder::op_address(uint8_t indirect, uint32_t dst_offset) void AvmTraceBuilder::op_storage_address(uint8_t indirect, uint32_t dst_offset) { - FF ia_value = kernel_trace_builder.op_storage_address(); - Row row = create_kernel_lookup_opcode(indirect, dst_offset, STORAGE_ADDRESS_SELECTOR, ia_value, AvmMemoryTag::FF); + auto const clk = static_cast(main_trace.size()) + 1; + FF ia_value = kernel_trace_builder.op_storage_address(clk); + Row row = create_kernel_lookup_opcode(indirect, dst_offset, ia_value, AvmMemoryTag::FF); row.main_sel_op_storage_address = FF(1); // Constrain gas cost @@ -1312,8 +1307,9 @@ void AvmTraceBuilder::op_storage_address(uint8_t indirect, uint32_t dst_offset) void AvmTraceBuilder::op_sender(uint8_t indirect, uint32_t dst_offset) { - FF ia_value = kernel_trace_builder.op_sender(); - Row row = create_kernel_lookup_opcode(indirect, dst_offset, SENDER_SELECTOR, ia_value, AvmMemoryTag::FF); + auto const clk = static_cast(main_trace.size()) + 1; + FF ia_value = kernel_trace_builder.op_sender(clk); + Row row = create_kernel_lookup_opcode(indirect, dst_offset, ia_value, AvmMemoryTag::FF); row.main_sel_op_sender = FF(1); // Constrain gas cost @@ -1324,9 +1320,9 @@ void AvmTraceBuilder::op_sender(uint8_t indirect, uint32_t dst_offset) void AvmTraceBuilder::op_function_selector(uint8_t indirect, uint32_t dst_offset) { - FF ia_value = kernel_trace_builder.op_function_selector(); - Row row = - create_kernel_lookup_opcode(indirect, dst_offset, FUNCTION_SELECTOR_SELECTOR, ia_value, AvmMemoryTag::U32); + auto const clk = static_cast(main_trace.size()) + 1; + FF ia_value = kernel_trace_builder.op_function_selector(clk); + Row row = create_kernel_lookup_opcode(indirect, dst_offset, ia_value, AvmMemoryTag::U32); row.main_sel_op_function_selector = FF(1); // Constrain gas cost @@ -1337,8 +1333,9 @@ void AvmTraceBuilder::op_function_selector(uint8_t indirect, uint32_t dst_offset void AvmTraceBuilder::op_transaction_fee(uint8_t indirect, uint32_t dst_offset) { - FF ia_value = kernel_trace_builder.op_transaction_fee(); - Row row = create_kernel_lookup_opcode(indirect, dst_offset, TRANSACTION_FEE_SELECTOR, ia_value, AvmMemoryTag::FF); + auto const clk = static_cast(main_trace.size()) + 1; + FF ia_value = kernel_trace_builder.op_transaction_fee(clk); + Row row = create_kernel_lookup_opcode(indirect, dst_offset, ia_value, AvmMemoryTag::FF); row.main_sel_op_transaction_fee = FF(1); // Constrain gas cost @@ -1353,8 +1350,9 @@ void AvmTraceBuilder::op_transaction_fee(uint8_t indirect, uint32_t dst_offset) void AvmTraceBuilder::op_chain_id(uint8_t indirect, uint32_t dst_offset) { - FF ia_value = kernel_trace_builder.op_chain_id(); - Row row = create_kernel_lookup_opcode(indirect, dst_offset, CHAIN_ID_SELECTOR, ia_value, AvmMemoryTag::FF); + auto const clk = static_cast(main_trace.size()) + 1; + FF ia_value = kernel_trace_builder.op_chain_id(clk); + Row row = create_kernel_lookup_opcode(indirect, dst_offset, ia_value, AvmMemoryTag::FF); row.main_sel_op_chain_id = FF(1); // Constrain gas cost @@ -1365,8 +1363,9 @@ void AvmTraceBuilder::op_chain_id(uint8_t indirect, uint32_t dst_offset) void AvmTraceBuilder::op_version(uint8_t indirect, uint32_t dst_offset) { - FF ia_value = kernel_trace_builder.op_version(); - Row row = create_kernel_lookup_opcode(indirect, dst_offset, VERSION_SELECTOR, ia_value, AvmMemoryTag::FF); + auto const clk = static_cast(main_trace.size()) + 1; + FF ia_value = kernel_trace_builder.op_version(clk); + Row row = create_kernel_lookup_opcode(indirect, dst_offset, ia_value, AvmMemoryTag::FF); row.main_sel_op_version = FF(1); // Constrain gas cost @@ -1377,8 +1376,9 @@ void AvmTraceBuilder::op_version(uint8_t indirect, uint32_t dst_offset) void AvmTraceBuilder::op_block_number(uint8_t indirect, uint32_t dst_offset) { - FF ia_value = kernel_trace_builder.op_block_number(); - Row row = create_kernel_lookup_opcode(indirect, dst_offset, BLOCK_NUMBER_SELECTOR, ia_value, AvmMemoryTag::FF); + auto const clk = static_cast(main_trace.size()) + 1; + FF ia_value = kernel_trace_builder.op_block_number(clk); + Row row = create_kernel_lookup_opcode(indirect, dst_offset, ia_value, AvmMemoryTag::FF); row.main_sel_op_block_number = FF(1); // Constrain gas cost @@ -1389,8 +1389,9 @@ void AvmTraceBuilder::op_block_number(uint8_t indirect, uint32_t dst_offset) void AvmTraceBuilder::op_timestamp(uint8_t indirect, uint32_t dst_offset) { - FF ia_value = kernel_trace_builder.op_timestamp(); - Row row = create_kernel_lookup_opcode(indirect, dst_offset, TIMESTAMP_SELECTOR, ia_value, AvmMemoryTag::U64); + auto const clk = static_cast(main_trace.size()) + 1; + FF ia_value = kernel_trace_builder.op_timestamp(clk); + Row row = create_kernel_lookup_opcode(indirect, dst_offset, ia_value, AvmMemoryTag::U64); row.main_sel_op_timestamp = FF(1); // Constrain gas cost @@ -1401,8 +1402,9 @@ void AvmTraceBuilder::op_timestamp(uint8_t indirect, uint32_t dst_offset) void AvmTraceBuilder::op_coinbase(uint8_t indirect, uint32_t dst_offset) { - FF ia_value = kernel_trace_builder.op_coinbase(); - Row row = create_kernel_lookup_opcode(indirect, dst_offset, COINBASE_SELECTOR, ia_value, AvmMemoryTag::FF); + auto const clk = static_cast(main_trace.size()) + 1; + FF ia_value = kernel_trace_builder.op_coinbase(clk); + Row row = create_kernel_lookup_opcode(indirect, dst_offset, ia_value, AvmMemoryTag::FF); row.main_sel_op_coinbase = FF(1); // Constrain gas cost @@ -1413,8 +1415,9 @@ void AvmTraceBuilder::op_coinbase(uint8_t indirect, uint32_t dst_offset) void AvmTraceBuilder::op_fee_per_l2_gas(uint8_t indirect, uint32_t dst_offset) { - FF ia_value = kernel_trace_builder.op_fee_per_l2_gas(); - Row row = create_kernel_lookup_opcode(indirect, dst_offset, FEE_PER_L2_GAS_SELECTOR, ia_value, AvmMemoryTag::FF); + auto const clk = static_cast(main_trace.size()) + 1; + FF ia_value = kernel_trace_builder.op_fee_per_l2_gas(clk); + Row row = create_kernel_lookup_opcode(indirect, dst_offset, ia_value, AvmMemoryTag::FF); row.main_sel_op_fee_per_l2_gas = FF(1); // Constrain gas cost @@ -1425,8 +1428,9 @@ void AvmTraceBuilder::op_fee_per_l2_gas(uint8_t indirect, uint32_t dst_offset) void AvmTraceBuilder::op_fee_per_da_gas(uint8_t indirect, uint32_t dst_offset) { - FF ia_value = kernel_trace_builder.op_fee_per_da_gas(); - Row row = create_kernel_lookup_opcode(indirect, dst_offset, FEE_PER_DA_GAS_SELECTOR, ia_value, AvmMemoryTag::FF); + auto const clk = static_cast(main_trace.size()) + 1; + FF ia_value = kernel_trace_builder.op_fee_per_da_gas(clk); + Row row = create_kernel_lookup_opcode(indirect, dst_offset, ia_value, AvmMemoryTag::FF); row.main_sel_op_fee_per_da_gas = FF(1); // Constrain gas cost @@ -2005,7 +2009,6 @@ Row AvmTraceBuilder::create_kernel_output_opcode(uint8_t indirect, uint32_t clk, .main_r_in_tag = static_cast(AvmMemoryTag::FF), .main_rwa = 0, .main_sel_mem_op_a = 1, - .main_sel_q_kernel_output_lookup = 1, .main_sel_resolve_ind_addr_a = FF(static_cast(read_a.is_indirect)), .main_tag_err = FF(static_cast(!tag_match)), }; @@ -2054,7 +2057,6 @@ Row AvmTraceBuilder::create_kernel_output_opcode_with_metadata(uint8_t indirect, .main_rwb = 0, .main_sel_mem_op_a = 1, .main_sel_mem_op_b = 1, - .main_sel_q_kernel_output_lookup = 1, .main_sel_resolve_ind_addr_a = FF(static_cast(read_a.is_indirect)), .main_sel_resolve_ind_addr_b = FF(static_cast(read_b.is_indirect)), .main_tag_err = FF(static_cast(!tag_match)), @@ -2218,7 +2220,6 @@ void AvmTraceBuilder::op_sload(uint8_t indirect, uint32_t slot_offset, uint32_t .main_rwa = 1, .main_sel_mem_op_a = 1, .main_sel_op_sload = FF(1), - .main_sel_q_kernel_output_lookup = 1, .main_sel_resolve_ind_addr_a = FF(static_cast(write_a.is_indirect)), .main_tag_err = FF(static_cast(!write_a.tag_match)), .main_w_in_tag = static_cast(AvmMemoryTag::FF), @@ -3440,7 +3441,7 @@ std::vector AvmTraceBuilder::finalize(bool range_check_required) // Range check size is 1 less than it needs to be since we insert a "first row" at the top of the trace at the // end, with clk 0 (this doubles as our range check) size_t const range_check_size = range_check_required ? UINT16_MAX : 0; - std::vector trace_sizes = { mem_trace_size, main_trace_size, alu_trace_size, + std::vector trace_sizes = { mem_trace_size, main_trace_size + 1, alu_trace_size, range_check_size, conv_trace_size, sha256_trace_size, poseidon2_trace_size, pedersen_trace_size, gas_trace_size + 1, KERNEL_INPUTS_LENGTH, KERNEL_OUTPUTS_LENGTH, fixed_gas_table.size(), @@ -3476,14 +3477,14 @@ std::vector AvmTraceBuilder::finalize(bool range_check_required) for (size_t i = 0; i < main_trace_size; i++) { main_trace[i].main_sel_execution_row = FF(1); } + // This selector corresponds to the last row of the EXECUTION trace. + main_trace.back().main_sel_last = FF(1); - // We only need to pad with zeroes to the size to the largest trace here, pow_2 padding is handled in the - // subgroup_size check in bb + // We only need to pad with zeroes to the size to the largest trace here, + // pow_2 padding is handled in the subgroup_size check in BB. // Resize the main_trace to accomodate a potential lookup, filling with default empty rows. main_trace_size = *trace_size; - main_trace.resize(*trace_size, {}); - - main_trace.at(*trace_size - 1).main_sel_last = FF(1); + main_trace.resize(*trace_size); /********************************************************************************************** * MEMORY TRACE INCLUSION @@ -3832,6 +3833,12 @@ std::vector AvmTraceBuilder::finalize(bool range_check_required) gas_trace_builder.finalize(main_trace); const auto& rem_gas_rng_check_counts = gas_trace_builder.rem_gas_rng_check_counts; + /********************************************************************************************** + * KERNEL TRACE INCLUSION + **********************************************************************************************/ + + kernel_trace_builder.finalize(main_trace); + /********************************************************************************************** * ONLY FIXED TABLES FROM HERE ON **********************************************************************************************/ @@ -3951,186 +3958,11 @@ std::vector AvmTraceBuilder::finalize(bool range_check_required) } /********************************************************************************************** - * KERNEL TRACE INCLUSION + * OTHER STUFF **********************************************************************************************/ - // Write the kernel trace into the main trace - // 1. The write offsets are constrained to be non changing over the entire trace, so we fill in the values - // until we - // hit an operation that changes one of the write_offsets (a relevant opcode) - // 2. Upon hitting the clk of each kernel operation we copy the values into the main trace - // 3. When an increment is required, we increment the value in the next row, then continue the process until - // the end - // 4. Whenever we hit the last row, we zero all write_offsets such that the shift relation will succeed - std::vector kernel_trace = kernel_trace_builder.finalize(); - size_t kernel_padding_main_trace_bottom = 1; - - // Index 1 corresponds here to the first active row of the main execution trace, as - // we already prepended the extra row for shifted columns. Therefore, initialization - // of side_effect_counter occurs occurs on this row. - main_trace.at(1).kernel_side_effect_counter = initial_side_effect_counter; - // This index is required to retrieve the right side effect counter after an external call. - size_t external_call_cnt = 0; - - // External loop iterates over the kernel entries which are sorted by increasing clk. - // Internal loop iterates to fill the gap in main trace between each kernel entries. - for (auto const& src : kernel_trace) { - // Check the clock and iterate through the main trace until we hit the clock - auto clk = src.clk; - - // Until the next kernel changing instruction is encountered we set all of the values of the offset - // arrays to be the same as the previous row This satisfies the `offset' - (offset + operation_selector) - // = 0` constraints - for (size_t j = kernel_padding_main_trace_bottom; j < clk; j++) { - auto const& prev = main_trace.at(j); - auto& dest = main_trace.at(j + 1); - - dest.kernel_note_hash_exist_write_offset = prev.kernel_note_hash_exist_write_offset; - dest.kernel_emit_note_hash_write_offset = prev.kernel_emit_note_hash_write_offset; - dest.kernel_nullifier_exists_write_offset = prev.kernel_nullifier_exists_write_offset; - dest.kernel_nullifier_non_exists_write_offset = prev.kernel_nullifier_non_exists_write_offset; - dest.kernel_emit_nullifier_write_offset = prev.kernel_emit_nullifier_write_offset; - dest.kernel_emit_l2_to_l1_msg_write_offset = prev.kernel_emit_l2_to_l1_msg_write_offset; - dest.kernel_emit_unencrypted_log_write_offset = prev.kernel_emit_unencrypted_log_write_offset; - dest.kernel_l1_to_l2_msg_exists_write_offset = prev.kernel_l1_to_l2_msg_exists_write_offset; - dest.kernel_sload_write_offset = prev.kernel_sload_write_offset; - dest.kernel_sstore_write_offset = prev.kernel_sstore_write_offset; - - // Adjust side effect counter after an external call - if (prev.main_sel_op_external_call == 1) { - dest.kernel_side_effect_counter = - execution_hints.externalcall_hints.at(external_call_cnt).end_side_effect_counter; - external_call_cnt++; - } else { - dest.kernel_side_effect_counter = prev.kernel_side_effect_counter; - } - } - - Row& curr = main_trace.at(clk); - - // Read in values from kernel trace - // Lookup values - curr.kernel_kernel_in_offset = src.kernel_in_offset; - curr.kernel_kernel_out_offset = src.kernel_out_offset; - curr.main_sel_q_kernel_lookup = static_cast(src.q_kernel_lookup); - curr.main_sel_q_kernel_output_lookup = static_cast(src.q_kernel_output_lookup); - - // Operation selectors - curr.main_sel_op_note_hash_exists = static_cast(src.op_note_hash_exists); - curr.main_sel_op_emit_note_hash = static_cast(src.op_emit_note_hash); - curr.main_sel_op_nullifier_exists = static_cast(src.op_nullifier_exists); - curr.main_sel_op_emit_nullifier = static_cast(src.op_emit_nullifier); - curr.main_sel_op_l1_to_l2_msg_exists = static_cast(src.op_l1_to_l2_msg_exists); - curr.main_sel_op_emit_unencrypted_log = static_cast(src.op_emit_unencrypted_log); - curr.main_sel_op_emit_l2_to_l1_msg = static_cast(src.op_emit_l2_to_l1_msg); - curr.main_sel_op_sload = static_cast(src.op_sload); - curr.main_sel_op_sstore = static_cast(src.op_sstore); - - if (clk < old_trace_size) { - Row& next = main_trace.at(clk + 1); - - // Increment the write offset counter for the following row - next.kernel_note_hash_exist_write_offset = - curr.kernel_note_hash_exist_write_offset + static_cast(src.op_note_hash_exists); - next.kernel_emit_note_hash_write_offset = - curr.kernel_emit_note_hash_write_offset + static_cast(src.op_emit_note_hash); - next.kernel_emit_nullifier_write_offset = - curr.kernel_emit_nullifier_write_offset + static_cast(src.op_emit_nullifier); - next.kernel_nullifier_exists_write_offset = - curr.kernel_nullifier_exists_write_offset + (static_cast(src.op_nullifier_exists) * curr.main_ib); - next.kernel_nullifier_non_exists_write_offset = - curr.kernel_nullifier_non_exists_write_offset + - (static_cast(src.op_nullifier_exists) * (FF(1) - curr.main_ib)); - next.kernel_l1_to_l2_msg_exists_write_offset = - curr.kernel_l1_to_l2_msg_exists_write_offset + static_cast(src.op_l1_to_l2_msg_exists); - next.kernel_emit_l2_to_l1_msg_write_offset = - curr.kernel_emit_l2_to_l1_msg_write_offset + static_cast(src.op_emit_l2_to_l1_msg); - next.kernel_emit_unencrypted_log_write_offset = - curr.kernel_emit_unencrypted_log_write_offset + static_cast(src.op_emit_unencrypted_log); - next.kernel_sload_write_offset = curr.kernel_sload_write_offset + static_cast(src.op_sload); - next.kernel_sstore_write_offset = curr.kernel_sstore_write_offset + static_cast(src.op_sstore); - - // The side effect counter will increment regardless of the offset value - next.kernel_side_effect_counter = curr.kernel_side_effect_counter + 1; - } - - kernel_padding_main_trace_bottom = clk + 1; - } - - // Pad out the main trace from the bottom of the main trace until the end - for (size_t i = kernel_padding_main_trace_bottom + 1; i < old_trace_size; ++i) { - - Row const& prev = main_trace.at(i - 1); - Row& dest = main_trace.at(i); - - // Setting all of the counters to 0 after the IS_LAST check so we can satisfy the constraints until the - // end - if (i == old_trace_size) { - dest.kernel_note_hash_exist_write_offset = 0; - dest.kernel_emit_note_hash_write_offset = 0; - dest.kernel_nullifier_exists_write_offset = 0; - dest.kernel_nullifier_non_exists_write_offset = 0; - dest.kernel_emit_nullifier_write_offset = 0; - dest.kernel_l1_to_l2_msg_exists_write_offset = 0; - dest.kernel_emit_unencrypted_log_write_offset = 0; - dest.kernel_emit_l2_to_l1_msg_write_offset = 0; - dest.kernel_sload_write_offset = 0; - dest.kernel_sstore_write_offset = 0; - dest.kernel_side_effect_counter = 0; - } else { - dest.kernel_note_hash_exist_write_offset = prev.kernel_note_hash_exist_write_offset; - dest.kernel_emit_note_hash_write_offset = prev.kernel_emit_note_hash_write_offset; - dest.kernel_nullifier_exists_write_offset = prev.kernel_nullifier_exists_write_offset; - dest.kernel_nullifier_non_exists_write_offset = prev.kernel_nullifier_non_exists_write_offset; - dest.kernel_emit_nullifier_write_offset = prev.kernel_emit_nullifier_write_offset; - dest.kernel_l1_to_l2_msg_exists_write_offset = prev.kernel_l1_to_l2_msg_exists_write_offset; - dest.kernel_emit_unencrypted_log_write_offset = prev.kernel_emit_unencrypted_log_write_offset; - dest.kernel_emit_l2_to_l1_msg_write_offset = prev.kernel_emit_l2_to_l1_msg_write_offset; - dest.kernel_sload_write_offset = prev.kernel_sload_write_offset; - dest.kernel_sstore_write_offset = prev.kernel_sstore_write_offset; - dest.kernel_side_effect_counter = prev.kernel_side_effect_counter; - } - } - - // Public Input Columns Inclusion - // Crucial to add these columns after the extra row was added. - - // Write lookup counts for inputs - for (uint32_t i = 0; i < KERNEL_INPUTS_LENGTH; i++) { - auto value = kernel_trace_builder.kernel_input_selector_counter.find(i); - if (value != kernel_trace_builder.kernel_input_selector_counter.end()) { - auto& dest = main_trace.at(i); - dest.lookup_into_kernel_counts = FF(value->second); - dest.kernel_q_public_input_kernel_add_to_table = FF(1); - } - } - - // Copy the kernel input public inputs - for (size_t i = 0; i < KERNEL_INPUTS_LENGTH; i++) { - main_trace.at(i).kernel_kernel_inputs = std::get(kernel_trace_builder.public_inputs).at(i); - } - - // Write lookup counts for outputs - for (uint32_t i = 0; i < KERNEL_OUTPUTS_LENGTH; i++) { - auto value = kernel_trace_builder.kernel_output_selector_counter.find(i); - if (value != kernel_trace_builder.kernel_output_selector_counter.end()) { - auto& dest = main_trace.at(i); - dest.kernel_output_lookup_counts = FF(value->second); - dest.kernel_q_public_input_kernel_out_add_to_table = FF(1); - } - } - - // Copy the kernel outputs counts into the main trace - for (size_t i = 0; i < KERNEL_OUTPUTS_LENGTH; i++) { - main_trace.at(i).kernel_kernel_value_out = - std::get(kernel_trace_builder.public_inputs).at(i); - - main_trace.at(i).kernel_kernel_side_effect_out = - std::get(kernel_trace_builder.public_inputs).at(i); - - main_trace.at(i).kernel_kernel_metadata_out = - std::get(kernel_trace_builder.public_inputs).at(i); - } + // Add the kernel inputs and outputs + kernel_trace_builder.finalize_columns(main_trace); // calldata column inclusion and selector for (size_t i = 0; i < calldata.size(); i++) { diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/trace/trace.hpp b/barretenberg/cpp/src/barretenberg/vm/avm/trace/trace.hpp index 406d840ccf19..5e5c3fdec2e7 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/trace/trace.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/trace/trace.hpp @@ -5,6 +5,7 @@ #include "barretenberg/vm/avm/trace/alu_trace.hpp" #include "barretenberg/vm/avm/trace/binary_trace.hpp" #include "barretenberg/vm/avm/trace/common.hpp" +#include "barretenberg/vm/avm/trace/execution_hints.hpp" #include "barretenberg/vm/avm/trace/gadgets/conversion_trace.hpp" #include "barretenberg/vm/avm/trace/gadgets/ecc.hpp" #include "barretenberg/vm/avm/trace/gadgets/keccak.hpp" @@ -193,6 +194,14 @@ class AvmTraceBuilder { private: std::vector main_trace; + + std::vector calldata; + std::vector returndata; + // Side effect counter will increment when any state writing values are encountered. + uint32_t side_effect_counter = 0; + uint32_t external_call_counter = 0; + ExecutionHints execution_hints; + AvmMemTraceBuilder mem_trace_builder; AvmAluTraceBuilder alu_trace_builder; AvmBinaryTraceBuilder bin_trace_builder; @@ -206,11 +215,7 @@ class AvmTraceBuilder { AvmEccTraceBuilder ecc_trace_builder; AvmSliceTraceBuilder slice_trace_builder; - std::vector calldata{}; - std::vector returndata{}; - - Row create_kernel_lookup_opcode( - uint8_t indirect, uint32_t dst_offset, uint32_t selector, FF value, AvmMemoryTag w_tag); + Row create_kernel_lookup_opcode(uint8_t indirect, uint32_t dst_offset, FF value, AvmMemoryTag w_tag); Row create_kernel_output_opcode(uint8_t indirect, uint32_t clk, uint32_t data_offset); @@ -240,16 +245,6 @@ class AvmTraceBuilder { 0; // After a nested call, it should be initialized with MAX_SIZE_INTERNAL_STACK * call_ptr uint8_t call_ptr = 0; - // Side effect counter will increment when any state writing values are - // encountered - uint32_t side_effect_counter = 0; - uint32_t initial_side_effect_counter; // This one is constant. - uint32_t external_call_counter = 0; - - // Execution hints aid witness solving for instructions that require auxiliary information to construct - // Mapping of side effect counter -> value - ExecutionHints execution_hints; - MemOp constrained_read_from_memory(uint8_t space_id, uint32_t clk, AddressWithMode addr, diff --git a/bb-pilcom/bb-pil-backend/templates/circuit_builder.cpp.hbs b/bb-pilcom/bb-pil-backend/templates/circuit_builder.cpp.hbs index 1762970adc0b..4ac476e2c673 100644 --- a/bb-pilcom/bb-pil-backend/templates/circuit_builder.cpp.hbs +++ b/bb-pilcom/bb-pil-backend/templates/circuit_builder.cpp.hbs @@ -65,16 +65,20 @@ bool {{name}}CircuitBuilder::check_circuit() const { r = 0; } + std::array subrelation_failed = { false }; for (size_t r = 0; r < num_rows; ++r) { Relation::accumulate(result, polys.get_row(r), {}, 1); for (size_t j = 0; j < result.size(); ++j) { - if (result[j] != 0) { + if (!subrelation_failed[j] && result[j] != 0) { signal_error(format("Relation ", Relation::NAME, ", subrelation ", Relation::get_subrelation_label(j), " failed at row ", r)); + // We will not check this subrelation for any other rows. + // Since the accumulation will keep being != 0. + subrelation_failed[j] = true; } } } @@ -106,14 +110,9 @@ bool {{name}}CircuitBuilder::check_circuit() const { std::string errors; std::mutex m; - const bool verbose_errors = std::getenv("AVM_VERBOSE_ERRORS") != nullptr; auto signal_error = [&](const std::string& error) { std::lock_guard lock(m); - if (verbose_errors) { - errors += error + "\n"; - } else if (errors.empty()) { - errors = "Circuit check failed. Use AVM_VERBOSE_ERRORS=1 to see more details."; - } + errors += error + "\n"; }; bb::parallel_for(checks.size(), [&](size_t i) { checks[i](signal_error); }); if (!errors.empty()) { diff --git a/l1-contracts/src/core/FeeJuicePortal.sol b/l1-contracts/src/core/FeeJuicePortal.sol new file mode 100644 index 000000000000..5b899bd577f2 --- /dev/null +++ b/l1-contracts/src/core/FeeJuicePortal.sol @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2024 Aztec Labs. +pragma solidity >=0.8.18; + +import {IERC20} from "@oz/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@oz/token/ERC20/utils/SafeERC20.sol"; +import {Ownable} from "@oz/access/Ownable.sol"; + +// Messaging +import {IRegistry} from "./interfaces/messagebridge/IRegistry.sol"; +import {IInbox} from "./interfaces/messagebridge/IInbox.sol"; +import {IFeeJuicePortal} from "./interfaces/IFeeJuicePortal.sol"; +import {DataStructures} from "./libraries/DataStructures.sol"; +import {Errors} from "./libraries/Errors.sol"; +import {Constants} from "./libraries/ConstantsGen.sol"; +import {Hash} from "./libraries/Hash.sol"; + +contract FeeJuicePortal is IFeeJuicePortal, Ownable { + using SafeERC20 for IERC20; + + IRegistry public registry; + IERC20 public underlying; + bytes32 public l2TokenAddress; + + constructor() Ownable(msg.sender) {} + + /** + * @notice Initialize the FeeJuicePortal + * + * @dev This function is only callable by the owner of the contract and only once + * + * @dev Must be funded with FEE_JUICE_INITIAL_MINT tokens before initialization to + * ensure that the L2 contract is funded and able to pay for its deployment. + * + * @param _registry - The address of the registry contract + * @param _underlying - The address of the underlying token + * @param _l2TokenAddress - The address of the L2 token + */ + function initialize(address _registry, address _underlying, bytes32 _l2TokenAddress) + external + override(IFeeJuicePortal) + onlyOwner + { + if (address(registry) != address(0) || address(underlying) != address(0) || l2TokenAddress != 0) + { + revert Errors.FeeJuicePortal__AlreadyInitialized(); + } + if (_registry == address(0) || _underlying == address(0) || _l2TokenAddress == 0) { + revert Errors.FeeJuicePortal__InvalidInitialization(); + } + + registry = IRegistry(_registry); + underlying = IERC20(_underlying); + l2TokenAddress = _l2TokenAddress; + uint256 balance = underlying.balanceOf(address(this)); + if (balance < Constants.FEE_JUICE_INITIAL_MINT) { + underlying.safeTransferFrom( + msg.sender, address(this), Constants.FEE_JUICE_INITIAL_MINT - balance + ); + } + _transferOwnership(address(0)); + } + + /** + * @notice Deposit funds into the portal and adds an L2 message which can only be consumed publicly on Aztec + * @param _to - The aztec address of the recipient + * @param _amount - The amount to deposit + * @param _secretHash - The hash of the secret consumable message. The hash should be 254 bits (so it can fit in a Field element) + * @return - The key of the entry in the Inbox + */ + function depositToAztecPublic(bytes32 _to, uint256 _amount, bytes32 _secretHash) + external + override(IFeeJuicePortal) + returns (bytes32) + { + // Preamble + IInbox inbox = registry.getRollup().INBOX(); + DataStructures.L2Actor memory actor = DataStructures.L2Actor(l2TokenAddress, 1); + + // Hash the message content to be reconstructed in the receiving contract + bytes32 contentHash = + Hash.sha256ToField(abi.encodeWithSignature("mint_public(bytes32,uint256)", _to, _amount)); + + // Hold the tokens in the portal + underlying.safeTransferFrom(msg.sender, address(this), _amount); + + // Send message to rollup + return inbox.sendL2Message(actor, contentHash, _secretHash); + } + + /** + * @notice Let the rollup distribute fees to an account + * + * Since the assets cannot be exited the usual way, but only paid as fees to sequencers + * we include this function to allow the rollup to do just that, bypassing the usual + * flows. + * + * @param _to - The address to receive the payment + * @param _amount - The amount to pay them + */ + function distributeFees(address _to, uint256 _amount) external override(IFeeJuicePortal) { + if (msg.sender != address(registry.getRollup())) { + revert Errors.FeeJuicePortal__Unauthorized(); + } + underlying.safeTransfer(_to, _amount); + } +} diff --git a/l1-contracts/src/core/Rollup.sol b/l1-contracts/src/core/Rollup.sol index 3f53f193acff..3b4e2b65f662 100644 --- a/l1-contracts/src/core/Rollup.sol +++ b/l1-contracts/src/core/Rollup.sol @@ -9,7 +9,7 @@ import {IInbox} from "./interfaces/messagebridge/IInbox.sol"; import {IOutbox} from "./interfaces/messagebridge/IOutbox.sol"; import {IRegistry} from "./interfaces/messagebridge/IRegistry.sol"; import {IVerifier} from "./interfaces/IVerifier.sol"; -import {IERC20} from "@oz/token/ERC20/IERC20.sol"; +import {IFeeJuicePortal} from "./interfaces/IFeeJuicePortal.sol"; // Libraries import {HeaderLib} from "./libraries/HeaderLib.sol"; @@ -47,7 +47,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup { IInbox public immutable INBOX; IOutbox public immutable OUTBOX; uint256 public immutable VERSION; - IERC20 public immutable FEE_JUICE; + IFeeJuicePortal public immutable FEE_JUICE_PORTAL; IVerifier public verifier; @@ -74,14 +74,14 @@ contract Rollup is Leonidas, IRollup, ITestRollup { constructor( IRegistry _registry, IAvailabilityOracle _availabilityOracle, - IERC20 _fpcJuice, + IFeeJuicePortal _fpcJuicePortal, bytes32 _vkTreeRoot, address _ares ) Leonidas(_ares) { verifier = new MockVerifier(); REGISTRY = _registry; AVAILABILITY_ORACLE = _availabilityOracle; - FEE_JUICE = _fpcJuice; + FEE_JUICE_PORTAL = _fpcJuicePortal; INBOX = new Inbox(address(this), Constants.L1_TO_L2_MSG_SUBTREE_HEIGHT); OUTBOX = new Outbox(address(this)); vkTreeRoot = _vkTreeRoot; @@ -361,10 +361,13 @@ contract Rollup is Leonidas, IRollup, ITestRollup { header.globalVariables.blockNumber, header.contentCommitment.outHash, l2ToL1TreeMinHeight ); - // @todo This should be address at time of proving. Also, this contract should NOT have funds!!! - // pay the coinbase 1 Fee Juice if it is not empty and header.totalFees is not zero + // @note This should be addressed at the time of proving if sequential proving or at the time of + // inclusion into the proven chain otherwise. See #7622. if (header.globalVariables.coinbase != address(0) && header.totalFees > 0) { - FEE_JUICE.transfer(address(header.globalVariables.coinbase), header.totalFees); + // @note This will currently fail if there are insufficient funds in the bridge + // which WILL happen for the old version after an upgrade where the bridge follow. + // Consider allowing a failure. See #7938. + FEE_JUICE_PORTAL.distributeFees(header.globalVariables.coinbase, header.totalFees); } emit L2BlockProcessed(header.globalVariables.blockNumber); diff --git a/l1-contracts/src/core/interfaces/IFeeJuicePortal.sol b/l1-contracts/src/core/interfaces/IFeeJuicePortal.sol new file mode 100644 index 000000000000..19dd38a059ee --- /dev/null +++ b/l1-contracts/src/core/interfaces/IFeeJuicePortal.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2024 Aztec Labs. +pragma solidity >=0.8.18; + +interface IFeeJuicePortal { + function initialize(address _registry, address _underlying, bytes32 _l2TokenAddress) external; + function distributeFees(address _to, uint256 _amount) external; + function depositToAztecPublic(bytes32 _to, uint256 _amount, bytes32 _secretHash) + external + returns (bytes32); +} diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index 7e06064fc7f6..9e3bc20bb901 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -101,6 +101,7 @@ library Constants { uint256 internal constant BLOB_SIZE_IN_BYTES = 126976; uint256 internal constant ETHEREUM_SLOT_DURATION = 12; uint256 internal constant IS_DEV_NET = 1; + uint256 internal constant FEE_JUICE_INITIAL_MINT = 20000000000; uint256 internal constant MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS = 20000; uint256 internal constant MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS = 3000; uint256 internal constant MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS = 3000; diff --git a/l1-contracts/src/core/libraries/Errors.sol b/l1-contracts/src/core/libraries/Errors.sol index 78505c56d467..19be2872e3fb 100644 --- a/l1-contracts/src/core/libraries/Errors.sol +++ b/l1-contracts/src/core/libraries/Errors.sol @@ -84,4 +84,9 @@ library Errors { error Leonidas__InvalidProposer(address expected, address actual); // 0xd02d278e error Leonidas__InsufficientAttestations(uint256 minimumNeeded, uint256 provided); // 0xbf1ca4cb error Leonidas__InsufficientAttestationsProvided(uint256 minimumNeeded, uint256 provided); // 0x2e7debe9 + + // Fee Juice Portal + error FeeJuicePortal__AlreadyInitialized(); // 0xc7a172fe + error FeeJuicePortal__InvalidInitialization(); // 0xfd9b3208 + error FeeJuicePortal__Unauthorized(); // 0x67e3691e } diff --git a/l1-contracts/test/Rollup.t.sol b/l1-contracts/test/Rollup.t.sol index 2d3d349b3570..c47e631adf4f 100644 --- a/l1-contracts/test/Rollup.t.sol +++ b/l1-contracts/test/Rollup.t.sol @@ -2,8 +2,6 @@ // Copyright 2023 Aztec Labs. pragma solidity >=0.8.18; -import {IERC20} from "@oz/token/ERC20/IERC20.sol"; - import {DecoderBase} from "./decoders/Base.sol"; import {DataStructures} from "../src/core/libraries/DataStructures.sol"; @@ -14,6 +12,8 @@ import {Inbox} from "../src/core/messagebridge/Inbox.sol"; import {Outbox} from "../src/core/messagebridge/Outbox.sol"; import {Errors} from "../src/core/libraries/Errors.sol"; import {Rollup} from "../src/core/Rollup.sol"; +import {IFeeJuicePortal} from "../src/core/interfaces/IFeeJuicePortal.sol"; +import {FeeJuicePortal} from "../src/core/FeeJuicePortal.sol"; import {Leonidas} from "../src/core/sequencer_selection/Leonidas.sol"; import {AvailabilityOracle} from "../src/core/availability_oracle/AvailabilityOracle.sol"; import {FrontierMerkle} from "../src/core/messagebridge/frontier_tree/Frontier.sol"; @@ -22,6 +22,7 @@ import {MerkleTestUtil} from "./merkle/TestUtil.sol"; import {PortalERC20} from "./portals/PortalERC20.sol"; import {TxsDecoderHelper} from "./decoders/helpers/TxsDecoderHelper.sol"; +import {IERC20Errors} from "@oz/interfaces/draft-IERC6093.sol"; /** * Blocks are generated using the `integration_l1_publisher.test.ts` tests. @@ -35,6 +36,7 @@ contract RollupTest is DecoderBase { MerkleTestUtil internal merkleTestUtil; TxsDecoderHelper internal txsHelper; PortalERC20 internal portalERC20; + FeeJuicePortal internal feeJuicePortal; AvailabilityOracle internal availabilityOracle; @@ -54,17 +56,23 @@ contract RollupTest is DecoderBase { registry = new Registry(address(this)); availabilityOracle = new AvailabilityOracle(); portalERC20 = new PortalERC20(); + feeJuicePortal = new FeeJuicePortal(); + portalERC20.mint(address(feeJuicePortal), Constants.FEE_JUICE_INITIAL_MINT); + feeJuicePortal.initialize( + address(registry), address(portalERC20), bytes32(Constants.FEE_JUICE_ADDRESS) + ); rollup = new Rollup( - registry, availabilityOracle, IERC20(address(portalERC20)), bytes32(0), address(this) + registry, + availabilityOracle, + IFeeJuicePortal(address(feeJuicePortal)), + bytes32(0), + address(this) ); inbox = Inbox(address(rollup.INBOX())); outbox = Outbox(address(rollup.OUTBOX())); registry.upgrade(address(rollup)); - // mint some tokens to the rollup - portalERC20.mint(address(rollup), 1000000); - merkleTestUtil = new MerkleTestUtil(); txsHelper = new TxsDecoderHelper(); _; @@ -143,6 +151,43 @@ contract RollupTest is DecoderBase { assertNotEq(minHeightEmpty, minHeightMixed, "Invalid min height"); } + function testBlockFee() public setUpFor("mixed_block_1") { + uint256 feeAmount = 2e18; + + DecoderBase.Data memory data = load("mixed_block_1").block; + bytes memory header = data.header; + bytes32 archive = data.archive; + bytes memory body = data.body; + + assembly { + mstore(add(header, add(0x20, 0x0248)), feeAmount) + } + availabilityOracle.publish(body); + + assertEq(portalERC20.balanceOf(address(rollup)), 0, "invalid rollup balance"); + + uint256 portalBalance = portalERC20.balanceOf(address(feeJuicePortal)); + + vm.expectRevert( + abi.encodeWithSelector( + IERC20Errors.ERC20InsufficientBalance.selector, + address(feeJuicePortal), + portalBalance, + feeAmount + ) + ); + rollup.process(header, archive); + + address coinbase = data.decodedHeader.globalVariables.coinbase; + uint256 coinbaseBalance = portalERC20.balanceOf(coinbase); + assertEq(coinbaseBalance, 0, "invalid initial coinbase balance"); + + portalERC20.mint(address(feeJuicePortal), feeAmount - portalBalance); + + rollup.process(header, archive); + assertEq(portalERC20.balanceOf(coinbase), feeAmount, "invalid coinbase balance"); + } + function testMixedBlock(bool _toProve) public setUpFor("mixed_block_1") { _testBlock("mixed_block_1", _toProve); diff --git a/l1-contracts/test/portals/FeeJuicePortal.sol b/l1-contracts/test/portals/FeeJuicePortal.sol deleted file mode 100644 index 75518c743c84..000000000000 --- a/l1-contracts/test/portals/FeeJuicePortal.sol +++ /dev/null @@ -1,55 +0,0 @@ -pragma solidity >=0.8.18; - -import {IERC20} from "@oz/token/ERC20/IERC20.sol"; -import {SafeERC20} from "@oz/token/ERC20/utils/SafeERC20.sol"; - -// Messaging -import {IRegistry} from "../../src/core/interfaces/messagebridge/IRegistry.sol"; -import {IInbox} from "../../src/core/interfaces/messagebridge/IInbox.sol"; -import {DataStructures} from "../../src/core/libraries/DataStructures.sol"; -// docs:start:content_hash_sol_import -import {Hash} from "../../src/core/libraries/Hash.sol"; -// docs:end:content_hash_sol_import - -// docs:start:init -contract FeeJuicePortal { - using SafeERC20 for IERC20; - - IRegistry public registry; - IERC20 public underlying; - bytes32 public l2TokenAddress; - - function initialize(address _registry, address _underlying, bytes32 _l2TokenAddress) external { - registry = IRegistry(_registry); - underlying = IERC20(_underlying); - l2TokenAddress = _l2TokenAddress; - } - // docs:end:init - - // docs:start:deposit_public - /** - * @notice Deposit funds into the portal and adds an L2 message which can only be consumed publicly on Aztec - * @param _to - The aztec address of the recipient - * @param _amount - The amount to deposit - * @param _secretHash - The hash of the secret consumable message. The hash should be 254 bits (so it can fit in a Field element) - * @return - The key of the entry in the Inbox - */ - function depositToAztecPublic(bytes32 _to, uint256 _amount, bytes32 _secretHash) - external - returns (bytes32) - { - // Preamble - IInbox inbox = registry.getRollup().INBOX(); - DataStructures.L2Actor memory actor = DataStructures.L2Actor(l2TokenAddress, 1); - - // Hash the message content to be reconstructed in the receiving contract - bytes32 contentHash = - Hash.sha256ToField(abi.encodeWithSignature("mint_public(bytes32,uint256)", _to, _amount)); - - // Hold the tokens in the portal - underlying.safeTransferFrom(msg.sender, address(this), _amount); - - // Send message to rollup - return inbox.sendL2Message(actor, contentHash, _secretHash); - } -} diff --git a/l1-contracts/test/portals/TokenPortal.t.sol b/l1-contracts/test/portals/TokenPortal.t.sol index 476b72701ad5..411579d3e911 100644 --- a/l1-contracts/test/portals/TokenPortal.t.sol +++ b/l1-contracts/test/portals/TokenPortal.t.sol @@ -14,7 +14,7 @@ import {Errors} from "../../src/core/libraries/Errors.sol"; // Interfaces import {IInbox} from "../../src/core/interfaces/messagebridge/IInbox.sol"; import {IOutbox} from "../../src/core/interfaces/messagebridge/IOutbox.sol"; -import {IERC20} from "@oz/token/ERC20/IERC20.sol"; +import {IFeeJuicePortal} from "../../src/core/interfaces/IFeeJuicePortal.sol"; // Portal tokens import {TokenPortal} from "./TokenPortal.sol"; @@ -25,10 +25,10 @@ import {NaiveMerkle} from "../merkle/Naive.sol"; contract TokenPortalTest is Test { using Hash for DataStructures.L1ToL2Msg; - uint256 internal constant FIRST_REAL_TREE_NUM = Constants.INITIAL_L2_BLOCK_NUM + 1; - event MessageConsumed(bytes32 indexed messageHash, address indexed recipient); + uint256 internal constant FIRST_REAL_TREE_NUM = Constants.INITIAL_L2_BLOCK_NUM + 1; + Registry internal registry; IInbox internal inbox; @@ -62,16 +62,14 @@ contract TokenPortalTest is Test { registry = new Registry(address(this)); portalERC20 = new PortalERC20(); rollup = new Rollup( - registry, new AvailabilityOracle(), IERC20(address(portalERC20)), bytes32(0), address(this) + registry, new AvailabilityOracle(), IFeeJuicePortal(address(0)), bytes32(0), address(this) ); inbox = rollup.INBOX(); outbox = rollup.OUTBOX(); registry.upgrade(address(rollup)); - portalERC20.mint(address(rollup), 1000000); tokenPortal = new TokenPortal(); - tokenPortal.initialize(address(registry), address(portalERC20), l2TokenAddress); // Modify the proven block count diff --git a/l1-contracts/test/portals/UniswapPortal.t.sol b/l1-contracts/test/portals/UniswapPortal.t.sol index 104b76645303..be0144dd0aed 100644 --- a/l1-contracts/test/portals/UniswapPortal.t.sol +++ b/l1-contracts/test/portals/UniswapPortal.t.sol @@ -15,14 +15,12 @@ import {Errors} from "../../src/core/libraries/Errors.sol"; import {IERC20} from "@oz/token/ERC20/IERC20.sol"; import {IOutbox} from "../../src/core/interfaces/messagebridge/IOutbox.sol"; import {NaiveMerkle} from "../merkle/Naive.sol"; +import {IFeeJuicePortal} from "../../src/core/interfaces/IFeeJuicePortal.sol"; // Portals import {TokenPortal} from "./TokenPortal.sol"; import {UniswapPortal} from "./UniswapPortal.sol"; -// Portal tokens -import {PortalERC20} from "./PortalERC20.sol"; - contract UniswapPortalTest is Test { using Hash for DataStructures.L2ToL1Msg; @@ -55,12 +53,10 @@ contract UniswapPortalTest is Test { vm.selectFork(forkId); registry = new Registry(address(this)); - PortalERC20 portalERC20 = new PortalERC20(); rollup = new Rollup( - registry, new AvailabilityOracle(), IERC20(address(portalERC20)), bytes32(0), address(this) + registry, new AvailabilityOracle(), IFeeJuicePortal(address(0)), bytes32(0), address(this) ); registry.upgrade(address(rollup)); - portalERC20.mint(address(rollup), 1000000); daiTokenPortal = new TokenPortal(); daiTokenPortal.initialize(address(registry), address(DAI), l2TokenAddress); diff --git a/l1-contracts/test/sparta/DevNet.t.sol b/l1-contracts/test/sparta/DevNet.t.sol index cb591d3be32f..3e0ec8e76794 100644 --- a/l1-contracts/test/sparta/DevNet.t.sol +++ b/l1-contracts/test/sparta/DevNet.t.sol @@ -2,8 +2,6 @@ // Copyright 2023 Aztec Labs. pragma solidity >=0.8.18; -import {IERC20} from "@oz/token/ERC20/IERC20.sol"; - import {DecoderBase} from "../decoders/Base.sol"; import {DataStructures} from "../../src/core/libraries/DataStructures.sol"; @@ -19,8 +17,8 @@ import {Leonidas} from "../../src/core/sequencer_selection/Leonidas.sol"; import {AvailabilityOracle} from "../../src/core/availability_oracle/AvailabilityOracle.sol"; import {NaiveMerkle} from "../merkle/Naive.sol"; import {MerkleTestUtil} from "../merkle/TestUtil.sol"; -import {PortalERC20} from "../portals/PortalERC20.sol"; import {TxsDecoderHelper} from "../decoders/helpers/TxsDecoderHelper.sol"; +import {IFeeJuicePortal} from "../../src/core/interfaces/IFeeJuicePortal.sol"; /** * We are using the same blocks as from Rollup.t.sol. @@ -35,7 +33,6 @@ contract DevNetTest is DecoderBase { Rollup internal rollup; MerkleTestUtil internal merkleTestUtil; TxsDecoderHelper internal txsHelper; - PortalERC20 internal portalERC20; AvailabilityOracle internal availabilityOracle; @@ -59,18 +56,14 @@ contract DevNetTest is DecoderBase { registry = new Registry(address(this)); availabilityOracle = new AvailabilityOracle(); - portalERC20 = new PortalERC20(); rollup = new Rollup( - registry, availabilityOracle, IERC20(address(portalERC20)), bytes32(0), address(this) + registry, availabilityOracle, IFeeJuicePortal(address(0)), bytes32(0), address(this) ); inbox = Inbox(address(rollup.INBOX())); outbox = Outbox(address(rollup.OUTBOX())); registry.upgrade(address(rollup)); - // mint some tokens to the rollup - portalERC20.mint(address(rollup), 1000000); - merkleTestUtil = new MerkleTestUtil(); txsHelper = new TxsDecoderHelper(); diff --git a/l1-contracts/test/sparta/Sparta.t.sol b/l1-contracts/test/sparta/Sparta.t.sol index eb8638e070ad..01b36aa665df 100644 --- a/l1-contracts/test/sparta/Sparta.t.sol +++ b/l1-contracts/test/sparta/Sparta.t.sol @@ -2,8 +2,6 @@ // Copyright 2023 Aztec Labs. pragma solidity >=0.8.18; -import {IERC20} from "@oz/token/ERC20/IERC20.sol"; - import {DecoderBase} from "../decoders/Base.sol"; import {DataStructures} from "../../src/core/libraries/DataStructures.sol"; @@ -22,13 +20,14 @@ import {NaiveMerkle} from "../merkle/Naive.sol"; import {MerkleTestUtil} from "../merkle/TestUtil.sol"; import {PortalERC20} from "../portals/PortalERC20.sol"; import {TxsDecoderHelper} from "../decoders/helpers/TxsDecoderHelper.sol"; - +import {IFeeJuicePortal} from "../../src/core/interfaces/IFeeJuicePortal.sol"; /** * We are using the same blocks as from Rollup.t.sol. * The tests in this file is testing the sequencer selection * * We will skip these test if we are running with IS_DEV_NET = true */ + contract SpartaTest is DecoderBase { using MessageHashUtils for bytes32; @@ -64,16 +63,13 @@ contract SpartaTest is DecoderBase { availabilityOracle = new AvailabilityOracle(); portalERC20 = new PortalERC20(); rollup = new Rollup( - registry, availabilityOracle, IERC20(address(portalERC20)), bytes32(0), address(this) + registry, availabilityOracle, IFeeJuicePortal(address(0)), bytes32(0), address(this) ); inbox = Inbox(address(rollup.INBOX())); outbox = Outbox(address(rollup.OUTBOX())); registry.upgrade(address(rollup)); - // mint some tokens to the rollup - portalERC20.mint(address(rollup), 1000000); - merkleTestUtil = new MerkleTestUtil(); txsHelper = new TxsDecoderHelper(); diff --git a/noir-projects/noir-contracts/contracts/fee_juice_contract/src/main.nr b/noir-projects/noir-contracts/contracts/fee_juice_contract/src/main.nr index 632516b985ee..6a7cf65b3032 100644 --- a/noir-projects/noir-contracts/contracts/fee_juice_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/fee_juice_contract/src/main.nr @@ -5,7 +5,7 @@ contract FeeJuice { protocol_types::{ contract_class_id::ContractClassId, abis::function_selector::FunctionSelector, address::{AztecAddress, EthAddress}, - constants::{DEPLOYER_CONTRACT_ADDRESS, REGISTERER_CONTRACT_ADDRESS} + constants::{DEPLOYER_CONTRACT_ADDRESS, REGISTERER_CONTRACT_ADDRESS, FEE_JUICE_INITIAL_MINT} }, state_vars::{SharedImmutable, PublicMutable, Map}, oracle::get_contract_instance::get_contract_instance, deploy::deploy_contract @@ -46,8 +46,7 @@ contract FeeJuice { ); // Increase self balance and set as fee payer, and end setup - let deploy_fees = 20000000000; - FeeJuice::at(self)._increase_public_balance(self, deploy_fees).enqueue(&mut context); + FeeJuice::at(self)._increase_public_balance(self, FEE_JUICE_INITIAL_MINT).enqueue(&mut context); context.set_as_fee_payer(); context.end_setup(); diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr index 4be78977dbfa..6c557043be1c 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr @@ -48,14 +48,8 @@ impl NoteInterface for TokenNote { } fn compute_note_hiding_point(self) -> Point { - assert(self.header.storage_slot != 0, "Storage slot must be set before computing note hiding point"); - - // TODO(#7772): decompose amount with from_field_unsafe or constrain it fits into 1 limb - let amount_scalar = Scalar { - lo: self.amount.to_integer(), - hi: 0 - }; // We use the unsafe version because the multi_scalar_mul will constrain the scalars. + let amount_scalar = from_field_unsafe(self.amount.to_integer()); let npk_m_hash_scalar = from_field_unsafe(self.npk_m_hash); let randomness_scalar = from_field_unsafe(self.randomness); let slot_scalar = from_field_unsafe(self.header.storage_slot); @@ -88,9 +82,7 @@ impl TokenNoteHidingPoint { } fn add_amount(&mut self, amount: U128) { - // TODO(#7772): decompose amount with from_field_unsafe or constrain it fits into 1 limb - let amount_scalar = Scalar { lo: amount.to_integer(), hi: 0 }; - self.inner = multi_scalar_mul([G_amt], [amount_scalar]) + self.inner; + self.inner = multi_scalar_mul([G_amt], [from_field_unsafe(amount.to_integer())]) + self.inner; } fn add_npk_m_hash(&mut self, npk_m_hash: Field) { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index b17ce743d1cb..2a4467f8c378 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -133,6 +133,9 @@ global INITIAL_L2_BLOCK_NUM: Field = 1; global BLOB_SIZE_IN_BYTES: Field = 31 * 4096; global ETHEREUM_SLOT_DURATION: u32 = 12; global IS_DEV_NET: bool = true; +// The following and the value in `deploy_l1_contracts´ must match. We should not have the code both places, but +// we are running into circular dependency issues. #3342 +global FEE_JUICE_INITIAL_MINT: Field = 20000000000; // CONTRACT CLASS CONSTANTS global MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS: u32 = 20000; diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index 9d2dfd36cb99..c7a4f0144fe0 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -58,13 +58,7 @@ import { getCanonicalFeeJuice } from '@aztec/protocol-contracts/fee-juice'; import { getCanonicalInstanceDeployer } from '@aztec/protocol-contracts/instance-deployer'; import { getCanonicalKeyRegistryAddress } from '@aztec/protocol-contracts/key-registry'; import { getCanonicalMultiCallEntrypointAddress } from '@aztec/protocol-contracts/multi-call-entrypoint'; -import { - AggregateTxValidator, - DataTxValidator, - type GlobalVariableBuilder, - SequencerClient, - getGlobalVariableBuilder, -} from '@aztec/sequencer-client'; +import { AggregateTxValidator, DataTxValidator, GlobalVariableBuilder, SequencerClient } from '@aztec/sequencer-client'; import { PublicProcessorFactory, WASMSimulator, createSimulationProvider } from '@aztec/simulator'; import { type TelemetryClient } from '@aztec/telemetry-client'; import { NoopTelemetryClient } from '@aztec/telemetry-client/noop'; @@ -202,7 +196,7 @@ export class AztecNodeService implements AztecNode { sequencer, ethereumChain.chainInfo.id, config.version, - getGlobalVariableBuilder(config), + new GlobalVariableBuilder(config), store, txValidator, telemetry, @@ -385,6 +379,10 @@ export class AztecNodeService implements AztecNode { return Promise.resolve(this.p2pClient!.getTxs('pending')); } + public getPendingTxCount() { + return Promise.resolve(this.p2pClient!.getTxs('pending').length); + } + /** * Method to retrieve a single tx from the mempool or unfinalised chain. * @param txHash - The transaction hash to return. @@ -801,6 +799,14 @@ export class AztecNodeService implements AztecNode { return this.contractDataSource.addContractArtifact(address, artifact); } + public flushTxs(): Promise { + if (!this.sequencer) { + throw new Error(`Sequencer is not initialized`); + } + this.sequencer.flush(); + return Promise.resolve(); + } + /** * Returns an instance of MerkleTreeOperations having first ensured the world state is fully synched * @param blockNumber - The block number at which to get the data. diff --git a/yarn-project/aztec/src/cli/cmds/start_bot.ts b/yarn-project/aztec/src/cli/cmds/start_bot.ts index 0888b9dbf638..4d45dd4e0db0 100644 --- a/yarn-project/aztec/src/cli/cmds/start_bot.ts +++ b/yarn-project/aztec/src/cli/cmds/start_bot.ts @@ -1,5 +1,5 @@ import { type BotConfig, BotRunner, botConfigMappings, createBotRunnerRpcServer } from '@aztec/bot'; -import { type PXE } from '@aztec/circuit-types'; +import { type AztecNode, type PXE } from '@aztec/circuit-types'; import { type ServerList } from '@aztec/foundation/json-rpc/server'; import { type LogFn } from '@aztec/foundation/log'; @@ -35,11 +35,11 @@ export function addBot( options: any, services: ServerList, signalHandlers: (() => Promise)[], - deps: { pxe?: PXE } = {}, + deps: { pxe?: PXE; node?: AztecNode } = {}, ) { const config = extractRelevantOptions(options, botConfigMappings); - const botRunner = new BotRunner(config, { pxe: deps.pxe }); + const botRunner = new BotRunner(config, deps); const botServer = createBotRunnerRpcServer(botRunner); if (!config.noStart) { void botRunner.start(); // Do not block since bot setup takes time diff --git a/yarn-project/aztec/src/cli/cmds/start_node.ts b/yarn-project/aztec/src/cli/cmds/start_node.ts index d1e2f1121da7..9748e4f57e13 100644 --- a/yarn-project/aztec/src/cli/cmds/start_node.ts +++ b/yarn-project/aztec/src/cli/cmds/start_node.ts @@ -113,7 +113,7 @@ export const startNode = async ( // Add a txs bot if requested if (options.bot) { const { addBot } = await import('./start_bot.js'); - await addBot(options, services, signalHandlers, { pxe }); + await addBot(options, services, signalHandlers, { pxe, node }); } return services; diff --git a/yarn-project/bot/src/config.ts b/yarn-project/bot/src/config.ts index 4512902f7c15..08c9cc2939e5 100644 --- a/yarn-project/bot/src/config.ts +++ b/yarn-project/bot/src/config.ts @@ -11,6 +11,8 @@ const botFollowChain = ['NONE', 'PENDING', 'PROVEN'] as const; type BotFollowChain = (typeof botFollowChain)[number]; export type BotConfig = { + /** The URL to the Aztec node to check for tx pool status. */ + nodeUrl: string | undefined; /** URL to the PXE for sending txs, or undefined if an in-proc PXE is used. */ pxeUrl: string | undefined; /** Signing private key for the sender account. */ @@ -31,10 +33,17 @@ export type BotConfig = { noStart: boolean; /** How long to wait for a tx to be mined before reporting an error. */ txMinedWaitSeconds: number; + /** Whether to wait for txs to be proven, to be mined, or no wait at all. */ followChain: BotFollowChain; + /** Do not send a tx if the node's tx pool already has this many pending txs. */ + maxPendingTxs: number; }; export const botConfigMappings: ConfigMappingsType = { + nodeUrl: { + env: 'AZTEC_NODE_URL', + description: 'The URL to the Aztec node to check for tx pool status.', + }, pxeUrl: { env: 'BOT_PXE_URL', description: 'URL to the PXE for sending txs, or undefined if an in-proc PXE is used.', @@ -99,6 +108,11 @@ export const botConfigMappings: ConfigMappingsType = { return val as BotFollowChain; }, }, + maxPendingTxs: { + env: 'BOT_MAX_PENDING_TXS', + description: "Do not send a tx if the node's tx pool already has this many pending txs.", + ...numberConfigHelper(128), + }, }; export function getBotConfigFromEnv(): BotConfig { diff --git a/yarn-project/bot/src/runner.ts b/yarn-project/bot/src/runner.ts index 3a5206c7f99c..6159c7c605d4 100644 --- a/yarn-project/bot/src/runner.ts +++ b/yarn-project/bot/src/runner.ts @@ -1,4 +1,4 @@ -import { type PXE, createDebugLogger } from '@aztec/aztec.js'; +import { type AztecNode, type PXE, createAztecNodeClient, createDebugLogger } from '@aztec/aztec.js'; import { RunningPromise } from '@aztec/foundation/running-promise'; import { Bot } from './bot.js'; @@ -8,11 +8,16 @@ export class BotRunner { private log = createDebugLogger('aztec:bot'); private bot?: Promise; private pxe?: PXE; + private node: AztecNode; private runningPromise: RunningPromise; - public constructor(private config: BotConfig, dependencies: { pxe?: PXE } = {}) { + public constructor(private config: BotConfig, dependencies: { pxe?: PXE; node?: AztecNode }) { this.pxe = dependencies.pxe; - this.runningPromise = new RunningPromise(() => this.#safeRun(), config.txIntervalSeconds * 1000); + if (!dependencies.node && !config.nodeUrl) { + throw new Error(`Missing node URL in config or dependencies`); + } + this.node = dependencies.node ?? createAztecNodeClient(config.nodeUrl!); + this.runningPromise = new RunningPromise(() => this.#work(), config.txIntervalSeconds * 1000); } /** Initializes the bot if needed. Blocks until the bot setup is finished. */ @@ -112,7 +117,15 @@ export class BotRunner { } } - async #safeRun() { + async #work() { + if (this.config.maxPendingTxs > 0) { + const pendingTxs = await this.node.getPendingTxs(); + if (pendingTxs.length >= this.config.maxPendingTxs) { + this.log.verbose(`Not sending bot tx since node has ${pendingTxs.length} pending txs`); + return; + } + } + try { await this.run(); } catch (err) { diff --git a/yarn-project/circuit-types/src/interfaces/aztec-node.ts b/yarn-project/circuit-types/src/interfaces/aztec-node.ts index 73fd5f61f8ac..d99d95c9a13f 100644 --- a/yarn-project/circuit-types/src/interfaces/aztec-node.ts +++ b/yarn-project/circuit-types/src/interfaces/aztec-node.ts @@ -283,6 +283,12 @@ export interface AztecNode { */ getPendingTxs(): Promise; + /** + * Retrieves the number of pending txs + * @returns The number of pending txs. + */ + getPendingTxCount(): Promise; + /** * Method to retrieve a single pending tx. * @param txHash - The transaction hash to return. @@ -341,4 +347,7 @@ export interface AztecNode { * @param address - Address of the deployed contract. */ getContract(address: AztecAddress): Promise; + + /** Forces the next block to be built bypassing all time and pending checks. Useful for testing. */ + flushTxs(): Promise; } diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index ea8f98fbe575..0952b7f1a844 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -87,6 +87,7 @@ export const INITIAL_L2_BLOCK_NUM = 1; export const BLOB_SIZE_IN_BYTES = 126976; export const ETHEREUM_SLOT_DURATION = 12; export const IS_DEV_NET = 1; +export const FEE_JUICE_INITIAL_MINT = 20000000000; export const MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS = 20000; export const MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS = 3000; export const MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS = 3000; diff --git a/yarn-project/end-to-end/src/composed/integration_l1_publisher.test.ts b/yarn-project/end-to-end/src/composed/integration_l1_publisher.test.ts index 4497c9e2341e..5516a198777f 100644 --- a/yarn-project/end-to-end/src/composed/integration_l1_publisher.test.ts +++ b/yarn-project/end-to-end/src/composed/integration_l1_publisher.test.ts @@ -41,7 +41,7 @@ import { AvailabilityOracleAbi, OutboxAbi, RollupAbi } from '@aztec/l1-artifacts import { SHA256Trunc, StandardTree } from '@aztec/merkle-tree'; import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types'; import { TxProver } from '@aztec/prover-client'; -import { type L1Publisher, getL1Publisher } from '@aztec/sequencer-client'; +import { L1Publisher } from '@aztec/sequencer-client'; import { NoopTelemetryClient } from '@aztec/telemetry-client/noop'; import { MerkleTrees, ServerWorldStateSynchronizer, type WorldStateConfig } from '@aztec/world-state'; @@ -161,7 +161,7 @@ describe('L1Publisher integration', () => { builder = await TxProver.new(config, new NoopTelemetryClient()); prover = builder.createBlockProver(builderDb.asLatest()); - publisher = getL1Publisher( + publisher = new L1Publisher( { l1RpcUrl: config.l1RpcUrl, requiredConfirmations: 1, diff --git a/yarn-project/end-to-end/src/e2e_fees/account_init.test.ts b/yarn-project/end-to-end/src/e2e_fees/account_init.test.ts index 3288cef82846..45d5b34bde27 100644 --- a/yarn-project/end-to-end/src/e2e_fees/account_init.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/account_init.test.ts @@ -85,7 +85,7 @@ describe('e2e_fees account_init', () => { describe('account pays its own fee', () => { it('pays natively in the Fee Juice after Alice bridges funds', async () => { - await t.feeJuiceContract.methods.mint_public(bobsAddress, t.INITIAL_GAS_BALANCE).send().wait(); + await t.mintFeeJuice(bobsAddress, t.INITIAL_GAS_BALANCE); const [bobsInitialGas] = await t.getGasBalanceFn(bobsAddress); expect(bobsInitialGas).toEqual(t.INITIAL_GAS_BALANCE); @@ -179,7 +179,7 @@ describe('e2e_fees account_init', () => { describe('another account pays the fee', () => { it('pays natively in the Fee Juice', async () => { // mint Fee Juice to alice - await t.feeJuiceContract.methods.mint_public(aliceAddress, t.INITIAL_GAS_BALANCE).send().wait(); + await t.mintFeeJuice(aliceAddress, t.INITIAL_GAS_BALANCE); const [alicesInitialGas] = await t.getGasBalanceFn(aliceAddress); // bob generates the private keys for his account on his own diff --git a/yarn-project/end-to-end/src/e2e_fees/fees_test.ts b/yarn-project/end-to-end/src/e2e_fees/fees_test.ts index 29d838ca1afc..0c02c841bb21 100644 --- a/yarn-project/end-to-end/src/e2e_fees/fees_test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/fees_test.ts @@ -33,10 +33,7 @@ import { getContract } from 'viem'; import { MNEMONIC } from '../fixtures/fixtures.js'; import { type ISnapshotManager, addAccounts, createSnapshotManager } from '../fixtures/snapshot_manager.js'; import { type BalancesFn, deployCanonicalFeeJuice, getBalancesFn, publicDeployAccounts } from '../fixtures/utils.js'; -import { - FeeJuicePortalTestingHarnessFactory, - type IGasBridgingTestHarness, -} from '../shared/gas_portal_test_harness.js'; +import { FeeJuicePortalTestingHarnessFactory, type GasBridgingTestHarness } from '../shared/gas_portal_test_harness.js'; const { E2E_DATA_PATH: dataPath } = process.env; @@ -74,7 +71,7 @@ export class FeesTest { public privateFPC!: PrivateFPCContract; public counterContract!: CounterContract; public subscriptionContract!: AppSubscriptionContract; - public feeJuiceBridgeTestHarness!: IGasBridgingTestHarness; + public feeJuiceBridgeTestHarness!: GasBridgingTestHarness; public getCoinbaseBalance!: () => Promise; public getGasBalanceFn!: BalancesFn; @@ -110,6 +107,14 @@ export class FeesTest { expect(balanceAfter).toEqual(balanceBefore + amount); } + // Mint fee juice AND mint funds to the portal to emulate the L1 -> L2 bridge + async mintFeeJuice(address: AztecAddress, amount: bigint) { + await this.feeJuiceContract.methods.mint_public(address, amount).send().wait(); + // Need to also mint funds to the portal + const portalAddress = EthAddress.fromString(this.feeJuiceBridgeTestHarness.tokenPortal.address); + await this.feeJuiceBridgeTestHarness.mintTokensOnL1(amount, portalAddress); + } + /** Alice mints bananaCoin tokens privately to the target address and redeems them. */ async mintPrivateBananas(amount: bigint, address: AztecAddress) { const balanceBefore = await this.bananaCoin.methods.balance_of_private(address).simulate(); @@ -187,7 +192,6 @@ export class FeesTest { walletClient: walletClient, wallet: this.aliceWallet, logger: this.logger, - mockL1: false, }); }, ); @@ -223,7 +227,6 @@ export class FeesTest { walletClient: walletClient, wallet: this.aliceWallet, logger: this.logger, - mockL1: false, }); }, ); @@ -362,7 +365,7 @@ export class FeesTest { await this.snapshotManager.snapshot( 'fund_alice_with_fee_juice', async () => { - await this.feeJuiceContract.methods.mint_public(this.aliceAddress, this.INITIAL_GAS_BALANCE).send().wait(); + await this.mintFeeJuice(this.aliceAddress, this.INITIAL_GAS_BALANCE); }, () => Promise.resolve(), ); @@ -392,11 +395,7 @@ export class FeesTest { // Mint some Fee Juice to the subscription contract // Could also use bridgeFromL1ToL2 from the harness, but this is more direct - await this.feeJuiceContract.methods - .mint_public(subscriptionContract.address, this.INITIAL_GAS_BALANCE) - .send() - .wait(); - + await this.mintFeeJuice(subscriptionContract.address, this.INITIAL_GAS_BALANCE); return { counterContractAddress: counterContract.address, subscriptionContractAddress: subscriptionContract.address, diff --git a/yarn-project/end-to-end/src/shared/gas_portal_test_harness.ts b/yarn-project/end-to-end/src/shared/gas_portal_test_harness.ts index 12c8f801aec1..d0b76ef852cd 100644 --- a/yarn-project/end-to-end/src/shared/gas_portal_test_harness.ts +++ b/yarn-project/end-to-end/src/shared/gas_portal_test_harness.ts @@ -10,7 +10,7 @@ import { } from '@aztec/aztec.js'; import { FeeJuicePortalAbi, OutboxAbi, PortalERC20Abi } from '@aztec/l1-artifacts'; import { FeeJuiceContract } from '@aztec/noir-contracts.js'; -import { FeeJuiceAddress, getCanonicalFeeJuice } from '@aztec/protocol-contracts/fee-juice'; +import { FeeJuiceAddress } from '@aztec/protocol-contracts/fee-juice'; import { type Account, @@ -47,16 +47,6 @@ export interface FeeJuicePortalTestingHarnessFactoryConfig { export class FeeJuicePortalTestingHarnessFactory { private constructor(private config: FeeJuicePortalTestingHarnessFactoryConfig) {} - private async createMock() { - const wallet = this.config.wallet; - - // In this case we are not using a portal we just yolo it. - const gasL2 = await FeeJuiceContract.deploy(wallet) - .send({ contractAddressSalt: getCanonicalFeeJuice().instance.salt }) - .deployed(); - return Promise.resolve(new MockGasBridgingTestHarness(gasL2, EthAddress.ZERO)); - } - private async createReal() { const { aztecNode, pxeService, publicClient, walletClient, wallet, logger } = this.config; @@ -105,30 +95,9 @@ export class FeeJuicePortalTestingHarnessFactory { ); } - static create(config: FeeJuicePortalTestingHarnessFactoryConfig): Promise { + static create(config: FeeJuicePortalTestingHarnessFactoryConfig): Promise { const factory = new FeeJuicePortalTestingHarnessFactory(config); - if (config.mockL1) { - return factory.createMock(); - } else { - return factory.createReal(); - } - } -} - -class MockGasBridgingTestHarness implements IGasBridgingTestHarness { - constructor(public l2Token: FeeJuiceContract, public l1FeeJuiceAddress: EthAddress) {} - prepareTokensOnL1( - _l1TokenBalance: bigint, - _bridgeAmount: bigint, - _owner: AztecAddress, - ): Promise<{ secret: Fr; secretHash: Fr; msgHash: Fr }> { - throw new Error('Cannot prepare tokens on mocked L1.'); - } - async bridgeFromL1ToL2(_l1TokenBalance: bigint, bridgeAmount: bigint, owner: AztecAddress): Promise { - await this.l2Token.methods.mint_public(owner, bridgeAmount).send().wait(); - } - getL1FeeJuiceBalance(_address: EthAddress): Promise { - throw new Error('Cannot get Fee Juice balance on mocked L1.'); + return factory.createReal(); } } @@ -136,7 +105,7 @@ class MockGasBridgingTestHarness implements IGasBridgingTestHarness { * A Class for testing cross chain interactions, contains common interactions * shared between cross chain tests. */ -class GasBridgingTestHarness implements IGasBridgingTestHarness { +export class GasBridgingTestHarness implements IGasBridgingTestHarness { constructor( /** Aztec node */ public aztecNode: AztecNode, @@ -177,12 +146,13 @@ class GasBridgingTestHarness implements IGasBridgingTestHarness { return [secret, secretHash]; } - async mintTokensOnL1(amount: bigint) { + async mintTokensOnL1(amount: bigint, to: EthAddress = this.ethAccount) { this.logger.info('Minting tokens on L1'); + const balanceBefore = await this.underlyingERC20.read.balanceOf([to.toString()]); await this.publicClient.waitForTransactionReceipt({ - hash: await this.underlyingERC20.write.mint([this.ethAccount.toString(), amount]), + hash: await this.underlyingERC20.write.mint([to.toString(), amount]), }); - expect(await this.underlyingERC20.read.balanceOf([this.ethAccount.toString()])).toBe(amount); + expect(await this.underlyingERC20.read.balanceOf([to.toString()])).toBe(balanceBefore + amount); } async getL1FeeJuiceBalance(address: EthAddress) { diff --git a/yarn-project/ethereum/src/deploy_l1_contracts.ts b/yarn-project/ethereum/src/deploy_l1_contracts.ts index c493809c6323..9b63a51a5ae8 100644 --- a/yarn-project/ethereum/src/deploy_l1_contracts.ts +++ b/yarn-project/ethereum/src/deploy_l1_contracts.ts @@ -183,13 +183,60 @@ export const deployL1Contracts = async ( logger.info(`Deployed Fee Juice at ${feeJuiceAddress}`); - const rollupAddress = await deployer.deploy(contractsToDeploy.rollup, [ - getAddress(registryAddress.toString()), - getAddress(availabilityOracleAddress.toString()), - getAddress(feeJuiceAddress.toString()), - args.vkTreeRoot.toString(), - account.address.toString(), - ]); + const feeJuicePortalAddress = await deployL1Contract( + walletClient, + publicClient, + contractsToDeploy.feeJuicePortal.contractAbi, + contractsToDeploy.feeJuicePortal.contractBytecode, + ); + + logger.info(`Deployed Gas Portal at ${feeJuicePortalAddress}`); + + const feeJuicePortal = getContract({ + address: feeJuicePortalAddress.toString(), + abi: contractsToDeploy.feeJuicePortal.contractAbi, + client: walletClient, + }); + + // fund the portal contract with Fee Juice + const feeJuice = getContract({ + address: feeJuiceAddress.toString(), + abi: contractsToDeploy.feeJuice.contractAbi, + client: walletClient, + }); + + // @note This value MUST match what is in `constants.nr`. It is currently specified here instead of just importing + // because there is circular dependency hell. This is a temporary solution. #3342 + const FEE_JUICE_INITIAL_MINT = 20000000000; + const receipt = await feeJuice.write.mint([feeJuicePortalAddress.toString(), FEE_JUICE_INITIAL_MINT], {} as any); + await publicClient.waitForTransactionReceipt({ hash: receipt }); + logger.info(`Funded fee juice portal contract with Fee Juice`); + + await publicClient.waitForTransactionReceipt({ + hash: await feeJuicePortal.write.initialize([ + registryAddress.toString(), + feeJuiceAddress.toString(), + args.l2FeeJuiceAddress.toString(), + ]), + }); + + logger.info( + `Initialized Gas Portal at ${feeJuicePortalAddress} to bridge between L1 ${feeJuiceAddress} to L2 ${args.l2FeeJuiceAddress}`, + ); + + const rollupAddress = await deployL1Contract( + walletClient, + publicClient, + contractsToDeploy.rollup.contractAbi, + contractsToDeploy.rollup.contractBytecode, + [ + getAddress(registryAddress.toString()), + getAddress(availabilityOracleAddress.toString()), + getAddress(feeJuicePortalAddress.toString()), + args.vkTreeRoot.toString(), + account.address.toString(), + ], + ); logger.info(`Deployed Rollup at ${rollupAddress}`); // Set initial blocks as proven if requested @@ -239,39 +286,6 @@ export const deployL1Contracts = async ( logger.verbose(`Registry ${registryAddress} has already registered rollup ${rollupAddress}`); } - // this contract remains uninitialized because at this point we don't know the address of the Fee Juice on L2 - const feeJuicePortalAddress = await deployer.deploy(contractsToDeploy.feeJuicePortal); - - logger.info(`Deployed Gas Portal at ${feeJuicePortalAddress}`); - - const feeJuicePortal = getContract({ - address: feeJuicePortalAddress.toString(), - abi: contractsToDeploy.feeJuicePortal.contractAbi, - client: walletClient, - }); - - await publicClient.waitForTransactionReceipt({ - hash: await feeJuicePortal.write.initialize([ - registryAddress.toString(), - feeJuiceAddress.toString(), - args.l2FeeJuiceAddress.toString(), - ]), - }); - - logger.info( - `Initialized Gas Portal at ${feeJuicePortalAddress} to bridge between L1 ${feeJuiceAddress} to L2 ${args.l2FeeJuiceAddress}`, - ); - - // fund the rollup contract with Fee Juice - const feeJuice = getContract({ - address: feeJuiceAddress.toString(), - abi: contractsToDeploy.feeJuice.contractAbi, - client: walletClient, - }); - const receipt = await feeJuice.write.mint([rollupAddress.toString(), 100000000000000000000n], {} as any); - await publicClient.waitForTransactionReceipt({ hash: receipt }); - logger.info(`Funded rollup contract with Fee Juice`); - const l1Contracts: L1ContractAddresses = { availabilityOracleAddress, rollupAddress, diff --git a/yarn-project/foundation/src/config/env_var.ts b/yarn-project/foundation/src/config/env_var.ts index 438571ed225b..cf78a19e91be 100644 --- a/yarn-project/foundation/src/config/env_var.ts +++ b/yarn-project/foundation/src/config/env_var.ts @@ -89,6 +89,7 @@ export type EnvVar = | 'BOT_NO_START' | 'BOT_TX_MINED_WAIT_SECONDS' | 'BOT_NO_WAIT_FOR_TRANSFERS' + | 'BOT_MAX_PENDING_TXS' | 'PXE_BLOCK_POLLING_INTERVAL_MS' | 'PXE_L2_STARTING_BLOCK' | 'PXE_DATA_DIRECTORY' diff --git a/yarn-project/prover-node/src/factory.ts b/yarn-project/prover-node/src/factory.ts index ae6235af9d15..2dbb9260d31d 100644 --- a/yarn-project/prover-node/src/factory.ts +++ b/yarn-project/prover-node/src/factory.ts @@ -3,7 +3,7 @@ import { type AztecNode } from '@aztec/circuit-types'; import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log'; import { createStore } from '@aztec/kv-store/utils'; import { createProverClient } from '@aztec/prover-client'; -import { getL1Publisher } from '@aztec/sequencer-client'; +import { L1Publisher } from '@aztec/sequencer-client'; import { createSimulationProvider } from '@aztec/simulator'; import { type TelemetryClient } from '@aztec/telemetry-client'; import { NoopTelemetryClient } from '@aztec/telemetry-client/noop'; @@ -43,7 +43,7 @@ export async function createProverNode( const prover = await createProverClient(config, telemetry); // REFACTOR: Move publisher out of sequencer package and into an L1-related package - const publisher = getL1Publisher(config, telemetry); + const publisher = new L1Publisher(config, telemetry); const txProvider = deps.aztecNodeTxProvider ? new AztecNodeTxProvider(deps.aztecNodeTxProvider) diff --git a/yarn-project/sequencer-client/src/client/sequencer-client.ts b/yarn-project/sequencer-client/src/client/sequencer-client.ts index 4852518d47bf..02e173299815 100644 --- a/yarn-project/sequencer-client/src/client/sequencer-client.ts +++ b/yarn-project/sequencer-client/src/client/sequencer-client.ts @@ -8,8 +8,8 @@ import { type WorldStateSynchronizer } from '@aztec/world-state'; import { BlockBuilderFactory } from '../block_builder/index.js'; import { type SequencerClientConfig } from '../config.js'; -import { getGlobalVariableBuilder } from '../global_variable_builder/index.js'; -import { getL1Publisher } from '../publisher/index.js'; +import { GlobalVariableBuilder } from '../global_variable_builder/index.js'; +import { L1Publisher } from '../publisher/index.js'; import { Sequencer, type SequencerConfig } from '../sequencer/index.js'; import { TxValidatorFactory } from '../tx_validator/tx_validator_factory.js'; @@ -43,8 +43,8 @@ export class SequencerClient { simulationProvider: SimulationProvider, telemetryClient: TelemetryClient, ) { - const publisher = getL1Publisher(config, telemetryClient); - const globalsBuilder = getGlobalVariableBuilder(config); + const publisher = new L1Publisher(config, telemetryClient); + const globalsBuilder = new GlobalVariableBuilder(config); const merkleTreeDb = worldStateSynchronizer.getLatest(); const publicProcessorFactory = new PublicProcessorFactory( @@ -88,6 +88,11 @@ export class SequencerClient { await this.sequencer.stop(); } + /** Forces the sequencer to bypass all time and tx count checks for the next block and build anyway. */ + public flush() { + this.sequencer.flush(); + } + /** * Restarts the sequencer after being stopped. */ diff --git a/yarn-project/sequencer-client/src/global_variable_builder/global_builder.ts b/yarn-project/sequencer-client/src/global_variable_builder/global_builder.ts index 6ba6e3a1f799..f37db0af1cd8 100644 --- a/yarn-project/sequencer-client/src/global_variable_builder/global_builder.ts +++ b/yarn-project/sequencer-client/src/global_variable_builder/global_builder.ts @@ -5,71 +5,47 @@ import { GasFees, GlobalVariables, } from '@aztec/circuits.js'; +import { type L1ReaderConfig, createEthereumChain } from '@aztec/ethereum'; import { Fr } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; +import { RollupAbi } from '@aztec/l1-artifacts'; + +import { + type GetContractReturnType, + type HttpTransport, + type PublicClient, + createPublicClient, + getAddress, + getContract, + http, +} from 'viem'; +import type * as chains from 'viem/chains'; /** - * Reads values from L1 state that is used for the global values. + * Simple global variables builder. */ -export interface L1GlobalReader { - /** - * Fetches the version of the rollup contract. - * @returns The version of the rollup contract. - */ - getVersion(): Promise; - /** - * Gets the chain id. - * @returns The chain id. - */ - getChainId(): Promise; - - /** - * Gets the current L1 time. - * @returns The current L1 time. - */ - getL1CurrentTime(): Promise; +export class GlobalVariableBuilder { + private log = createDebugLogger('aztec:sequencer:global_variable_builder'); - /** - * Gets the current slot. - * @returns The current slot. - */ - getCurrentSlot(): Promise; + private rollupContract: GetContractReturnType>; + private publicClient: PublicClient; - /** - * Get the slot for a specific timestamp. - * @param timestamp - The timestamp to get the slot for. - */ - getSlotAt(timestamp: readonly [bigint]): Promise; + constructor(config: L1ReaderConfig) { + const { l1RpcUrl, l1ChainId: chainId, l1Contracts } = config; - /** - * Gets the timestamp for a slot - * @param slot - The slot to get the timestamp for. - * @returns The timestamp for the slot. - */ - getTimestampForSlot(slot: readonly [bigint]): Promise; -} + const chain = createEthereumChain(l1RpcUrl, chainId); -/** - * Builds global variables from L1 state. - */ -export interface GlobalVariableBuilder { - /** - * Builds global variables. - * @param blockNumber - The block number to build global variables for. - * @param coinbase - The address to receive block reward. - * @param feeRecipient - The address to receive fees. - * @returns The global variables for the given block number. - */ - buildGlobalVariables(blockNumber: Fr, coinbase: EthAddress, feeRecipient: AztecAddress): Promise; -} + this.publicClient = createPublicClient({ + chain: chain.chainInfo, + transport: http(chain.rpcUrl), + }); -/** - * Simple test implementation of a builder that uses the minimum time possible for the global variables. - * Also uses a "hack" to make use of the warp cheatcode that manipulates time on Aztec. - */ -export class SimpleTestGlobalVariableBuilder implements GlobalVariableBuilder { - private log = createDebugLogger('aztec:sequencer:simple_test_global_variable_builder'); - constructor(private readonly reader: L1GlobalReader) {} + this.rollupContract = getContract({ + address: getAddress(l1Contracts.rollupAddress.toString()), + abi: RollupAbi, + client: this.publicClient, + }); + } /** * Simple builder of global variables that use the minimum time possible. @@ -83,18 +59,18 @@ export class SimpleTestGlobalVariableBuilder implements GlobalVariableBuilder { coinbase: EthAddress, feeRecipient: AztecAddress, ): Promise { - // Not just the current slot, the slot of the next block. - const ts = (await this.reader.getL1CurrentTime()) + BigInt(ETHEREUM_SLOT_DURATION); + const version = new Fr(await this.rollupContract.read.VERSION()); + const chainId = new Fr(this.publicClient.chain.id); + + const ts = (await this.publicClient.getBlock()).timestamp; - const slot = await this.reader.getSlotAt([ts]); - const timestamp = await this.reader.getTimestampForSlot([slot]); + // Not just the current slot, the slot of the next block. + const slot = await this.rollupContract.read.getSlotAt([ts + BigInt(ETHEREUM_SLOT_DURATION)]); + const timestamp = await this.rollupContract.read.getTimestampForSlot([slot]); const slotFr = new Fr(slot); const timestampFr = new Fr(timestamp); - const version = new Fr(await this.reader.getVersion()); - const chainId = new Fr(await this.reader.getChainId()); - const gasFees = GasFees.default(); const globalVariables = new GlobalVariables( chainId, diff --git a/yarn-project/sequencer-client/src/global_variable_builder/index.ts b/yarn-project/sequencer-client/src/global_variable_builder/index.ts index 7125a7e7584a..5669a0412ae4 100644 --- a/yarn-project/sequencer-client/src/global_variable_builder/index.ts +++ b/yarn-project/sequencer-client/src/global_variable_builder/index.ts @@ -1,16 +1 @@ -import { type L1ReaderConfig } from '@aztec/ethereum'; - -import { type GlobalVariableBuilder, SimpleTestGlobalVariableBuilder } from './global_builder.js'; -import { ViemReader } from './viem-reader.js'; - -export { SimpleTestGlobalVariableBuilder as SimpleGlobalVariableBuilder } from './global_builder.js'; export { GlobalVariableBuilder } from './global_builder.js'; - -/** - * Returns a new instance of the global variable builder. - * @param config - Configuration to initialize the builder. - * @returns A new instance of the global variable builder. - */ -export function getGlobalVariableBuilder(config: L1ReaderConfig): GlobalVariableBuilder { - return new SimpleTestGlobalVariableBuilder(new ViemReader(config)); -} diff --git a/yarn-project/sequencer-client/src/global_variable_builder/viem-reader.ts b/yarn-project/sequencer-client/src/global_variable_builder/viem-reader.ts deleted file mode 100644 index dd6f59956ffd..000000000000 --- a/yarn-project/sequencer-client/src/global_variable_builder/viem-reader.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { type L1ReaderConfig, createEthereumChain } from '@aztec/ethereum'; -import { RollupAbi } from '@aztec/l1-artifacts'; - -import { - type GetContractReturnType, - type HttpTransport, - type PublicClient, - createPublicClient, - getAddress, - getContract, - http, -} from 'viem'; -import type * as chains from 'viem/chains'; - -import { type L1GlobalReader } from './global_builder.js'; - -/** - * Reads values from L1 state using viem. - */ -export class ViemReader implements L1GlobalReader { - private rollupContract: GetContractReturnType>; - private publicClient: PublicClient; - - constructor(config: L1ReaderConfig) { - const { l1RpcUrl, l1ChainId: chainId, l1Contracts } = config; - - const chain = createEthereumChain(l1RpcUrl, chainId); - - this.publicClient = createPublicClient({ - chain: chain.chainInfo, - transport: http(chain.rpcUrl), - }); - - this.rollupContract = getContract({ - address: getAddress(l1Contracts.rollupAddress.toString()), - abi: RollupAbi, - client: this.publicClient, - }); - } - - public async getVersion(): Promise { - return BigInt(await this.rollupContract.read.VERSION()); - } - - public async getChainId(): Promise { - return await Promise.resolve(BigInt(this.publicClient.chain.id)); - } - - public async getL1CurrentTime(): Promise { - return await Promise.resolve((await this.publicClient.getBlock()).timestamp); - } - - public async getCurrentSlot(): Promise { - return BigInt(await this.rollupContract.read.getCurrentSlot()); - } - - public async getSlotAt(timestamp: readonly [bigint]): Promise { - return BigInt(await this.rollupContract.read.getSlotAt(timestamp)); - } - - public async getTimestampForSlot(slot: readonly [bigint]): Promise { - return BigInt(await this.rollupContract.read.getTimestampForSlot(slot)); - } -} diff --git a/yarn-project/sequencer-client/src/publisher/index.ts b/yarn-project/sequencer-client/src/publisher/index.ts index 95f8d7c55fef..e51b4d3cdeae 100644 --- a/yarn-project/sequencer-client/src/publisher/index.ts +++ b/yarn-project/sequencer-client/src/publisher/index.ts @@ -1,16 +1,2 @@ -import { type TelemetryClient } from '@aztec/telemetry-client'; - -import { type PublisherConfig, type TxSenderConfig } from './config.js'; -import { L1Publisher } from './l1-publisher.js'; -import { ViemTxSender } from './viem-tx-sender.js'; - export { L1Publisher } from './l1-publisher.js'; export * from './config.js'; - -/** - * Returns a new instance of the L1Publisher. - * @param config - Configuration to initialize the new instance. - */ -export function getL1Publisher(config: PublisherConfig & TxSenderConfig, client: TelemetryClient): L1Publisher { - return new L1Publisher(new ViemTxSender(config), client, config); -} diff --git a/yarn-project/sequencer-client/src/publisher/l1-publisher.test.ts b/yarn-project/sequencer-client/src/publisher/l1-publisher.test.ts index c7fe318845f7..41b25de86a7f 100644 --- a/yarn-project/sequencer-client/src/publisher/l1-publisher.test.ts +++ b/yarn-project/sequencer-client/src/publisher/l1-publisher.test.ts @@ -1,26 +1,75 @@ import { L2Block } from '@aztec/circuit-types'; +import { EthAddress, Fr } from '@aztec/circuits.js'; import { sleep } from '@aztec/foundation/sleep'; import { NoopTelemetryClient } from '@aztec/telemetry-client/noop'; import { type MockProxy, mock } from 'jest-mock-extended'; +import { type GetTransactionReceiptReturnType, type PrivateKeyAccount } from 'viem'; -import { L1Publisher, type L1PublisherTxSender, type MinimalTransactionReceipt } from './l1-publisher.js'; +import { type PublisherConfig, type TxSenderConfig } from './config.js'; +import { L1Publisher } from './l1-publisher.js'; + +interface MockAvailabilityOracleWrite { + publish: (args: readonly [`0x${string}`], options: { account: PrivateKeyAccount }) => Promise<`0x${string}`>; +} + +interface MockAvailabilityOracleRead { + isAvailable: (args: readonly [`0x${string}`]) => Promise; +} + +class MockAvailabilityOracle { + constructor(public write: MockAvailabilityOracleWrite, public read: MockAvailabilityOracleRead) {} +} + +interface MockPublicClient { + getTransactionReceipt: ({ hash }: { hash: '0x${string}' }) => Promise; + getBlock(): Promise<{ timestamp: number }>; + getTransaction: ({ hash }: { hash: '0x${string}' }) => Promise<{ input: `0x${string}`; hash: `0x${string}` }>; +} + +interface MockRollupContractWrite { + publishAndProcess: ( + args: readonly [`0x${string}`, `0x${string}`, `0x${string}`], + options: { account: PrivateKeyAccount }, + ) => Promise<`0x${string}`>; + + process: ( + args: readonly [`0x${string}`, `0x${string}`], + options: { account: PrivateKeyAccount }, + ) => Promise<`0x${string}`>; +} + +interface MockRollupContractRead { + archive: () => Promise<`0x${string}`>; +} + +class MockRollupContract { + constructor(public write: MockRollupContractWrite, public read: MockRollupContractRead) {} +} describe('L1Publisher', () => { - let txSender: MockProxy; - let publishTxHash: string; - let processTxHash: string; - let publishAndProcessTxHash: string; - let processTxReceipt: MinimalTransactionReceipt; - let publishTxReceipt: MinimalTransactionReceipt; - let publishAndProcessTxReceipt: MinimalTransactionReceipt; + let rollupContractRead: MockProxy; + let rollupContractWrite: MockProxy; + let rollupContract: MockRollupContract; + + let availabilityOracleRead: MockProxy; + let availabilityOracleWrite: MockProxy; + let availabilityOracle: MockAvailabilityOracle; + + let publicClient: MockProxy; + + let processTxHash: `0x${string}`; + let publishAndProcessTxHash: `0x${string}`; + let processTxReceipt: GetTransactionReceiptReturnType; + let publishAndProcessTxReceipt: GetTransactionReceiptReturnType; let l2Block: L2Block; let header: Buffer; let archive: Buffer; - let txsEffectsHash: Buffer; let body: Buffer; + let account: PrivateKeyAccount; + let publisher: L1Publisher; beforeEach(() => { @@ -28,112 +77,142 @@ describe('L1Publisher', () => { header = l2Block.header.toBuffer(); archive = l2Block.archive.root.toBuffer(); - txsEffectsHash = l2Block.body.getTxsEffectsHash(); body = l2Block.body.toBuffer(); - txSender = mock(); - - publishTxHash = `0x${Buffer.from('txHashPublish').toString('hex')}`; // random tx hash processTxHash = `0x${Buffer.from('txHashProcess').toString('hex')}`; // random tx hash publishAndProcessTxHash = `0x${Buffer.from('txHashPublishAndProcess').toString('hex')}`; // random tx hash - publishTxReceipt = { - transactionHash: publishTxHash, - status: true, - logs: [{ data: txsEffectsHash.toString('hex') }], - } as MinimalTransactionReceipt; + processTxReceipt = { transactionHash: processTxHash, - status: true, - logs: [{ data: '' }], - } as MinimalTransactionReceipt; + status: 'success', + logs: [], + } as unknown as GetTransactionReceiptReturnType; publishAndProcessTxReceipt = { transactionHash: publishAndProcessTxHash, - status: true, - logs: [{ data: txsEffectsHash.toString('hex') }], - } as MinimalTransactionReceipt; - txSender.sendPublishTx.mockResolvedValueOnce(publishTxHash); - txSender.sendProcessTx.mockResolvedValueOnce(processTxHash); - txSender.sendPublishAndProcessTx.mockResolvedValueOnce(publishAndProcessTxHash); - txSender.getTransactionReceipt.mockResolvedValueOnce(publishTxReceipt).mockResolvedValueOnce(processTxReceipt); - txSender.getCurrentArchive.mockResolvedValue(l2Block.header.lastArchive.root.toBuffer()); - - publisher = new L1Publisher(txSender, new NoopTelemetryClient(), { l1PublishRetryIntervalMS: 1 }); + status: 'success', + logs: [], + } as unknown as GetTransactionReceiptReturnType; + + rollupContractWrite = mock(); + rollupContractRead = mock(); + rollupContract = new MockRollupContract(rollupContractWrite, rollupContractRead); + + availabilityOracleWrite = mock(); + availabilityOracleRead = mock(); + availabilityOracle = new MockAvailabilityOracle(availabilityOracleWrite, availabilityOracleRead); + + publicClient = mock(); + + const config = { + l1RpcUrl: `http://127.0.0.1:8545`, + l1ChainId: 1, + publisherPrivateKey: `0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80`, + l1Contracts: { + availabilityOracleAddress: EthAddress.ZERO.toString(), + rollupAddress: EthAddress.ZERO.toString(), + }, + l1PublishRetryIntervalMS: 1, + } as unknown as TxSenderConfig & PublisherConfig; + + publisher = new L1Publisher(config, new NoopTelemetryClient()); + + (publisher as any)['availabilityOracleContract'] = availabilityOracle; + (publisher as any)['rollupContract'] = rollupContract; + (publisher as any)['publicClient'] = publicClient; + + account = (publisher as any)['account']; }); - it('publishes l2 block to l1', async () => { + it('publishes and process l2 block to l1', async () => { + rollupContractRead.archive.mockResolvedValue(l2Block.header.lastArchive.root.toString() as `0x${string}`); + rollupContractWrite.publishAndProcess.mockResolvedValueOnce(publishAndProcessTxHash); + publicClient.getTransactionReceipt.mockResolvedValueOnce(publishAndProcessTxReceipt); + const result = await publisher.processL2Block(l2Block); expect(result).toEqual(true); - expect(txSender.sendPublishAndProcessTx).toHaveBeenCalledWith({ header, archive, body }); - expect(txSender.getTransactionReceipt).toHaveBeenCalledWith(publishAndProcessTxHash); + + const args = [`0x${header.toString('hex')}`, `0x${archive.toString('hex')}`, `0x${body.toString('hex')}`] as const; + expect(rollupContractWrite.publishAndProcess).toHaveBeenCalledWith(args, { account: account }); + expect(publicClient.getTransactionReceipt).toHaveBeenCalledWith({ hash: publishAndProcessTxHash }); }); it('publishes l2 block to l1 (already published body)', async () => { - txSender.checkIfTxsAreAvailable.mockResolvedValueOnce(true); + availabilityOracleRead.isAvailable.mockResolvedValueOnce(true); + rollupContractRead.archive.mockResolvedValue(l2Block.header.lastArchive.root.toString() as `0x${string}`); + rollupContractWrite.process.mockResolvedValueOnce(processTxHash); + publicClient.getTransactionReceipt.mockResolvedValueOnce(processTxReceipt); const result = await publisher.processL2Block(l2Block); expect(result).toEqual(true); - expect(txSender.sendProcessTx).toHaveBeenCalledWith({ header, archive, body }); - expect(txSender.getTransactionReceipt).toHaveBeenCalledWith(processTxHash); + const args = [`0x${header.toString('hex')}`, `0x${archive.toString('hex')}`] as const; + expect(rollupContractWrite.process).toHaveBeenCalledWith(args, { account }); + expect(publicClient.getTransactionReceipt).toHaveBeenCalledWith({ hash: processTxHash }); }); it('does not publish if last archive root is different to expected', async () => { - txSender.getCurrentArchive.mockResolvedValueOnce(L2Block.random(43).archive.root.toBuffer()); + rollupContractRead.archive.mockResolvedValue(Fr.random().toString()); + const result = await publisher.processL2Block(l2Block); expect(result).toBe(false); - expect(txSender.sendPublishTx).not.toHaveBeenCalled(); - expect(txSender.sendProcessTx).not.toHaveBeenCalled(); - expect(txSender.sendPublishAndProcessTx).not.toHaveBeenCalled(); + expect(availabilityOracleWrite.publish).not.toHaveBeenCalled(); + expect(rollupContractWrite.process).not.toHaveBeenCalled(); + expect(rollupContractWrite.publishAndProcess).not.toHaveBeenCalled(); }); it('does not retry if sending a process tx fails', async () => { - txSender.checkIfTxsAreAvailable.mockResolvedValueOnce(true); - txSender.sendProcessTx.mockReset().mockRejectedValueOnce(new Error()).mockResolvedValueOnce(processTxHash); + availabilityOracleRead.isAvailable.mockResolvedValueOnce(true); + rollupContractRead.archive.mockResolvedValue(l2Block.header.lastArchive.root.toString() as `0x${string}`); + rollupContractWrite.process + .mockRejectedValueOnce(new Error()) + .mockResolvedValueOnce(processTxHash as `0x${string}`); const result = await publisher.processL2Block(l2Block); expect(result).toEqual(false); - expect(txSender.sendProcessTx).toHaveBeenCalledTimes(1); + expect(rollupContractWrite.process).toHaveBeenCalledTimes(1); }); it('does not retry if sending a publish and process tx fails', async () => { - txSender.sendPublishAndProcessTx.mockReset().mockRejectedValueOnce(new Error()); - // .mockResolvedValueOnce(publishAndProcessTxHash); + rollupContractRead.archive.mockResolvedValue(l2Block.header.lastArchive.root.toString() as `0x${string}`); + rollupContractWrite.publishAndProcess.mockRejectedValueOnce(new Error()); const result = await publisher.processL2Block(l2Block); expect(result).toEqual(false); - expect(txSender.sendPublishAndProcessTx).toHaveBeenCalledTimes(1); + expect(rollupContractWrite.publishAndProcess).toHaveBeenCalledTimes(1); }); it('retries if fetching the receipt fails (process)', async () => { - txSender.checkIfTxsAreAvailable.mockResolvedValueOnce(true); - txSender.getTransactionReceipt - .mockReset() - .mockRejectedValueOnce(new Error()) - .mockResolvedValueOnce(processTxReceipt); + availabilityOracleRead.isAvailable.mockResolvedValueOnce(true); + rollupContractRead.archive.mockResolvedValue(l2Block.header.lastArchive.root.toString() as `0x${string}`); + rollupContractWrite.process.mockResolvedValueOnce(processTxHash); + publicClient.getTransactionReceipt.mockRejectedValueOnce(new Error()).mockResolvedValueOnce(processTxReceipt); const result = await publisher.processL2Block(l2Block); expect(result).toEqual(true); - expect(txSender.getTransactionReceipt).toHaveBeenCalledTimes(2); + expect(publicClient.getTransactionReceipt).toHaveBeenCalledTimes(2); }); it('retries if fetching the receipt fails (publish process)', async () => { - txSender.getTransactionReceipt - .mockReset() + rollupContractRead.archive.mockResolvedValue(l2Block.header.lastArchive.root.toString() as `0x${string}`); + rollupContractWrite.publishAndProcess.mockResolvedValueOnce(publishAndProcessTxHash as `0x${string}`); + publicClient.getTransactionReceipt .mockRejectedValueOnce(new Error()) .mockResolvedValueOnce(publishAndProcessTxReceipt); const result = await publisher.processL2Block(l2Block); expect(result).toEqual(true); - expect(txSender.getTransactionReceipt).toHaveBeenCalledTimes(2); + expect(publicClient.getTransactionReceipt).toHaveBeenCalledTimes(2); }); it('returns false if publish and process tx reverts', async () => { - txSender.getTransactionReceipt.mockReset().mockResolvedValueOnce({ ...publishAndProcessTxReceipt, status: false }); + rollupContractRead.archive.mockResolvedValue(l2Block.header.lastArchive.root.toString() as `0x${string}`); + rollupContractWrite.publishAndProcess.mockResolvedValueOnce(publishAndProcessTxHash); + publicClient.getTransactionReceipt.mockResolvedValueOnce({ ...publishAndProcessTxReceipt, status: 'reverted' }); const result = await publisher.processL2Block(l2Block); @@ -141,8 +220,10 @@ describe('L1Publisher', () => { }); it('returns false if process tx reverts', async () => { - txSender.checkIfTxsAreAvailable.mockResolvedValueOnce(true); - txSender.getTransactionReceipt.mockReset().mockResolvedValueOnce({ ...processTxReceipt, status: false }); + availabilityOracleRead.isAvailable.mockResolvedValueOnce(true); + rollupContractRead.archive.mockResolvedValue(l2Block.header.lastArchive.root.toString() as `0x${string}`); + + publicClient.getTransactionReceipt.mockResolvedValueOnce({ ...processTxReceipt, status: 'reverted' }); const result = await publisher.processL2Block(l2Block); @@ -150,25 +231,29 @@ describe('L1Publisher', () => { }); it('returns false if sending publish and progress tx is interrupted', async () => { - txSender.sendPublishAndProcessTx.mockReset().mockImplementationOnce(() => sleep(10, publishAndProcessTxHash)); + rollupContractRead.archive.mockResolvedValue(l2Block.header.lastArchive.root.toString() as `0x${string}`); + rollupContractWrite.publishAndProcess.mockImplementationOnce( + () => sleep(10, publishAndProcessTxHash) as Promise<`0x${string}`>, + ); const resultPromise = publisher.processL2Block(l2Block); publisher.interrupt(); const result = await resultPromise; expect(result).toEqual(false); - expect(txSender.getTransactionReceipt).not.toHaveBeenCalled(); + expect(publicClient.getTransactionReceipt).not.toHaveBeenCalled(); }); it('returns false if sending process tx is interrupted', async () => { - txSender.checkIfTxsAreAvailable.mockResolvedValueOnce(true); - txSender.sendProcessTx.mockReset().mockImplementationOnce(() => sleep(10, processTxHash)); + availabilityOracleRead.isAvailable.mockResolvedValueOnce(true); + rollupContractRead.archive.mockResolvedValue(l2Block.header.lastArchive.root.toString() as `0x${string}`); + rollupContractWrite.process.mockImplementationOnce(() => sleep(10, processTxHash) as Promise<`0x${string}`>); const resultPromise = publisher.processL2Block(l2Block); publisher.interrupt(); const result = await resultPromise; expect(result).toEqual(false); - expect(txSender.getTransactionReceipt).not.toHaveBeenCalled(); + expect(publicClient.getTransactionReceipt).not.toHaveBeenCalled(); }); }); diff --git a/yarn-project/sequencer-client/src/publisher/l1-publisher.ts b/yarn-project/sequencer-client/src/publisher/l1-publisher.ts index 58b71d9ea7c8..e1980dcb4a47 100644 --- a/yarn-project/sequencer-client/src/publisher/l1-publisher.ts +++ b/yarn-project/sequencer-client/src/publisher/l1-publisher.ts @@ -1,17 +1,34 @@ import { type L2Block, type Signature } from '@aztec/circuit-types'; import { type L1PublishBlockStats, type L1PublishProofStats } from '@aztec/circuit-types/stats'; -import { type EthAddress, type Header, type Proof } from '@aztec/circuits.js'; +import { ETHEREUM_SLOT_DURATION, EthAddress, type Header, type Proof } from '@aztec/circuits.js'; +import { createEthereumChain } from '@aztec/ethereum'; import { type Fr } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; import { serializeToBuffer } from '@aztec/foundation/serialize'; import { InterruptibleSleep } from '@aztec/foundation/sleep'; import { Timer } from '@aztec/foundation/timer'; +import { AvailabilityOracleAbi, RollupAbi } from '@aztec/l1-artifacts'; import { type TelemetryClient } from '@aztec/telemetry-client'; import pick from 'lodash.pick'; - -import { type L2BlockReceiver } from '../receiver.js'; -import { type PublisherConfig } from './config.js'; +import { + type GetContractReturnType, + type Hex, + type HttpTransport, + type PrivateKeyAccount, + type PublicClient, + type WalletClient, + createPublicClient, + createWalletClient, + getAddress, + getContract, + hexToBytes, + http, +} from 'viem'; +import { privateKeyToAccount } from 'viem/accounts'; +import type * as chains from 'viem/chains'; + +import { type PublisherConfig, type TxSenderConfig } from './config.js'; import { L1PublisherMetrics } from './l1-publisher-metrics.js'; /** @@ -27,7 +44,7 @@ export type TransactionStats = { }; /** - * Minimal information from a tx receipt returned by an L1PublisherTxSender. + * Minimal information from a tx receipt. */ export type MinimalTransactionReceipt = { /** True if the tx was successful, false if reverted. */ @@ -43,72 +60,11 @@ export type MinimalTransactionReceipt = { }; /** - * Pushes txs to the L1 chain and waits for their completion. + * @notice An attestation for the sequencing model. + * @todo This is not where it belongs. But I think we should do a bigger rewrite of some of + * this spaghetti. */ -export interface L1PublisherTxSender { - /** Returns the EOA used for sending txs to L1. */ - getSenderAddress(): Promise; - - /** Returns the address of the L2 proposer at the NEXT Ethereum block zero if anyone can submit. */ - getProposerAtNextEthBlock(): Promise; - - /** Returns the current epoch committee */ - getCurrentEpochCommittee(): Promise; - - /** - * Publishes tx effects to Availability Oracle. - * @param encodedBody - Encoded block body. - * @returns The hash of the mined tx. - */ - sendPublishTx(encodedBody: Buffer): Promise; - - /** - * Sends a tx to the L1 rollup contract with a new L2 block. Returns once the tx has been mined. - * @param encodedData - Serialized data for processing the new L2 block. - * @returns The hash of the mined tx. - */ - sendProcessTx(encodedData: L1ProcessArgs): Promise; - - /** - * Publishes tx effects to availability oracle and send L2 block to rollup contract - * @param encodedData - Data for processing the new L2 block. - * @returns The hash of the tx. - */ - sendPublishAndProcessTx(encodedData: L1ProcessArgs): Promise; - - /** - * Sends a tx to the L1 rollup contract with a proof. Returns once the tx has been mined. - * @param encodedData - Serialized data for processing the new L2 block. - * @returns The hash of the mined tx. - */ - sendSubmitProofTx(submitProofArgs: L1SubmitProofArgs): Promise; - - /** - * Returns a tx receipt if the tx has been mined. - * @param txHash - Hash of the tx to look for. - * @returns Undefined if the tx hasn't been mined yet, the receipt otherwise. - */ - getTransactionReceipt(txHash: string): Promise; - - /** - * Returns info on a tx by calling eth_getTransaction. - * @param txHash - Hash of the tx to look for. - */ - getTransactionStats(txHash: string): Promise; - - /** - * Returns the current archive root. - * @returns The current archive root of the rollup contract. - */ - getCurrentArchive(): Promise; - - /** - * Checks if the transaction effects of the given block are available. - * @param block - The block of which to check whether txs are available. - * @returns True if the txs are available, false otherwise. - */ - checkIfTxsAreAvailable(block: L2Block): Promise; -} +export type Attestation = { isEmpty: boolean; v: number; r: `0x${string}`; s: `0x${string}` }; /** Arguments to the process method of the rollup contract */ export type L1ProcessArgs = { @@ -144,30 +100,99 @@ export type L1SubmitProofArgs = { * * Adapted from https://github.com/AztecProtocol/aztec2-internal/blob/master/falafel/src/rollup_publisher.ts. */ -export class L1Publisher implements L2BlockReceiver { +export class L1Publisher { private interruptibleSleep = new InterruptibleSleep(); private sleepTimeMs: number; private interrupted = false; private metrics: L1PublisherMetrics; private log = createDebugLogger('aztec:sequencer:publisher'); - constructor(private txSender: L1PublisherTxSender, client: TelemetryClient, config?: PublisherConfig) { + private availabilityOracleContract: GetContractReturnType< + typeof AvailabilityOracleAbi, + WalletClient + >; + private rollupContract: GetContractReturnType< + typeof RollupAbi, + WalletClient + >; + private publicClient: PublicClient; + private account: PrivateKeyAccount; + + constructor(config: TxSenderConfig & PublisherConfig, client: TelemetryClient) { this.sleepTimeMs = config?.l1PublishRetryIntervalMS ?? 60_000; this.metrics = new L1PublisherMetrics(client, 'L1Publisher'); + + const { l1RpcUrl: rpcUrl, l1ChainId: chainId, publisherPrivateKey, l1Contracts } = config; + const chain = createEthereumChain(rpcUrl, chainId); + this.account = privateKeyToAccount(publisherPrivateKey); + const walletClient = createWalletClient({ + account: this.account, + chain: chain.chainInfo, + transport: http(chain.rpcUrl), + }); + + this.publicClient = createPublicClient({ + chain: chain.chainInfo, + transport: http(chain.rpcUrl), + }); + + this.availabilityOracleContract = getContract({ + address: getAddress(l1Contracts.availabilityOracleAddress.toString()), + abi: AvailabilityOracleAbi, + client: walletClient, + }); + this.rollupContract = getContract({ + address: getAddress(l1Contracts.rollupAddress.toString()), + abi: RollupAbi, + client: walletClient, + }); + } + + public getSenderAddress(): Promise { + return Promise.resolve(EthAddress.fromString(this.account.address)); } - public async senderAddress(): Promise { - return await this.txSender.getSenderAddress(); + // Computes who will be the L2 proposer at the next Ethereum block + // Using next Ethereum block so we do NOT need to wait for it being mined before seeing the effect + // @note Assumes that all ethereum slots have blocks + async getProposerAtNextEthBlock(): Promise { + try { + const ts = BigInt((await this.publicClient.getBlock()).timestamp + BigInt(ETHEREUM_SLOT_DURATION)); + const submitter = await this.rollupContract.read.getProposerAt([ts]); + return EthAddress.fromString(submitter); + } catch (err) { + this.log.warn(`Failed to get submitter: ${err}`); + return EthAddress.ZERO; + } } public async isItMyTurnToSubmit(): Promise { - const submitter = await this.txSender.getProposerAtNextEthBlock(); - const sender = await this.txSender.getSenderAddress(); + const submitter = await this.getProposerAtNextEthBlock(); + const sender = await this.getSenderAddress(); return submitter.isZero() || submitter.equals(sender); } - public getCurrentEpochCommittee(): Promise { - return this.txSender.getCurrentEpochCommittee(); + public async getCurrentEpochCommittee(): Promise { + const committee = await this.rollupContract.read.getCurrentEpochCommittee(); + return committee.map(EthAddress.fromString); + } + + checkIfTxsAreAvailable(block: L2Block): Promise { + const args = [`0x${block.body.getTxsEffectsHash().toString('hex').padStart(64, '0')}`] as const; + return this.availabilityOracleContract.read.isAvailable(args); + } + + async getTransactionStats(txHash: string): Promise { + const tx = await this.publicClient.getTransaction({ hash: txHash as Hex }); + if (!tx) { + return undefined; + } + const calldata = hexToBytes(tx.input); + return { + transactionHash: tx.hash, + calldataSize: calldata.length, + calldataGas: getCalldataGasUsage(calldata), + }; } /** @@ -197,7 +222,7 @@ export class L1Publisher implements L2BlockReceiver { let txHash; const timer = new Timer(); - if (await this.txSender.checkIfTxsAreAvailable(block)) { + if (await this.checkIfTxsAreAvailable(block)) { this.log.verbose(`Transaction effects of block ${block.number} already published.`, ctx); txHash = await this.sendProcessTx(processTxArgs); } else { @@ -217,7 +242,7 @@ export class L1Publisher implements L2BlockReceiver { // Tx was mined successfully if (receipt.status) { - const tx = await this.txSender.getTransactionStats(txHash); + const tx = await this.getTransactionStats(txHash); const stats: L1PublishBlockStats = { ...pick(receipt, 'gasPrice', 'gasUsed', 'transactionHash'), ...pick(tx!, 'calldataGas', 'calldataSize'), @@ -277,7 +302,7 @@ export class L1Publisher implements L2BlockReceiver { // Tx was mined successfully if (receipt.status) { - const tx = await this.txSender.getTransactionStats(txHash); + const tx = await this.getTransactionStats(txHash); const stats: L1PublishProofStats = { ...pick(receipt, 'gasPrice', 'gasUsed', 'transactionHash'), ...pick(tx!, 'calldataGas', 'calldataSize'), @@ -313,13 +338,18 @@ export class L1Publisher implements L2BlockReceiver { this.interrupted = false; } + async getCurrentArchive(): Promise { + const archive = await this.rollupContract.read.archive(); + return Buffer.from(archive.replace('0x', ''), 'hex'); + } + /** * Verifies that the given value of last archive in a block header equals current archive of the rollup contract * @param lastArchive - The last archive of the block we wish to publish. * @returns Boolean indicating if the hashes are equal. */ private async checkLastArchiveHash(lastArchive: Buffer): Promise { - const fromChain = await this.txSender.getCurrentArchive(); + const fromChain = await this.getCurrentArchive(); const areSame = lastArchive.equals(fromChain); if (!areSame) { this.log.debug(`Contract archive: ${fromChain.toString('hex')}`); @@ -332,7 +362,19 @@ export class L1Publisher implements L2BlockReceiver { try { const size = Object.values(submitProofArgs).reduce((acc, arg) => acc + arg.length, 0); this.log.info(`SubmitProof size=${size} bytes`); - return await this.txSender.sendSubmitProofTx(submitProofArgs); + + const { header, archive, proverId, aggregationObject, proof } = submitProofArgs; + const args = [ + `0x${header.toString('hex')}`, + `0x${archive.toString('hex')}`, + `0x${proverId.toString('hex')}`, + `0x${aggregationObject.toString('hex')}`, + `0x${proof.toString('hex')}`, + ] as const; + + return await this.rollupContract.write.submitProof(args, { + account: this.account, + }); } catch (err) { this.log.error(`Rollup submit proof failed`, err); return undefined; @@ -343,7 +385,11 @@ export class L1Publisher implements L2BlockReceiver { while (!this.interrupted) { try { this.log.info(`TxEffects size=${encodedBody.length} bytes`); - return await this.txSender.sendPublishTx(encodedBody); + const args = [`0x${encodedBody.toString('hex')}`] as const; + + return await this.availabilityOracleContract.write.publish(args, { + account: this.account, + }); } catch (err) { this.log.error(`TxEffects publish failed`, err); return undefined; @@ -354,7 +400,24 @@ export class L1Publisher implements L2BlockReceiver { private async sendProcessTx(encodedData: L1ProcessArgs): Promise { while (!this.interrupted) { try { - return await this.txSender.sendProcessTx(encodedData); + if (encodedData.attestations) { + const attestations = encodedData.attestations.map(attest => attest.toViemSignature()); + const args = [ + `0x${encodedData.header.toString('hex')}`, + `0x${encodedData.archive.toString('hex')}`, + attestations, + ] as const; + + return await this.rollupContract.write.process(args, { + account: this.account, + }); + } else { + const args = [`0x${encodedData.header.toString('hex')}`, `0x${encodedData.archive.toString('hex')}`] as const; + + return await this.rollupContract.write.process(args, { + account: this.account, + }); + } } catch (err) { this.log.error(`Rollup publish failed`, err); return undefined; @@ -365,7 +428,30 @@ export class L1Publisher implements L2BlockReceiver { private async sendPublishAndProcessTx(encodedData: L1ProcessArgs): Promise { while (!this.interrupted) { try { - return await this.txSender.sendPublishAndProcessTx(encodedData); + // @note This is quite a sin, but I'm committing war crimes in this code already. + if (encodedData.attestations) { + const attestations = encodedData.attestations.map(attest => attest.toViemSignature()); + const args = [ + `0x${encodedData.header.toString('hex')}`, + `0x${encodedData.archive.toString('hex')}`, + attestations, + `0x${encodedData.body.toString('hex')}`, + ] as const; + + return await this.rollupContract.write.publishAndProcess(args, { + account: this.account, + }); + } else { + const args = [ + `0x${encodedData.header.toString('hex')}`, + `0x${encodedData.archive.toString('hex')}`, + `0x${encodedData.body.toString('hex')}`, + ] as const; + + return await this.rollupContract.write.publishAndProcess(args, { + account: this.account, + }); + } } catch (err) { this.log.error(`Rollup publish failed`, err); return undefined; @@ -373,10 +459,34 @@ export class L1Publisher implements L2BlockReceiver { } } - private async getTransactionReceipt(txHash: string): Promise { + /** + * Returns a tx receipt if the tx has been mined. + * @param txHash - Hash of the tx to look for. + * @returns Undefined if the tx hasn't been mined yet, the receipt otherwise. + */ + async getTransactionReceipt(txHash: string): Promise { while (!this.interrupted) { try { - return await this.txSender.getTransactionReceipt(txHash); + const receipt = await this.publicClient.getTransactionReceipt({ + hash: txHash as Hex, + }); + + if (receipt) { + if (receipt.transactionHash !== txHash) { + throw new Error(`Tx hash mismatch: ${receipt.transactionHash} !== ${txHash}`); + } + + return { + status: receipt.status === 'success', + transactionHash: txHash, + gasUsed: receipt.gasUsed, + gasPrice: receipt.effectiveGasPrice, + logs: receipt.logs, + }; + } + + this.log.debug(`Receipt not found for tx hash ${txHash}`); + return undefined; } catch (err) { //this.log.error(`Error getting tx receipt`, err); await this.sleepOrInterrupted(); @@ -388,3 +498,12 @@ export class L1Publisher implements L2BlockReceiver { await this.interruptibleSleep.sleep(this.sleepTimeMs); } } + +/** + * Returns cost of calldata usage in Ethereum. + * @param data - Calldata. + * @returns 4 for each zero byte, 16 for each nonzero. + */ +function getCalldataGasUsage(data: Uint8Array) { + return data.filter(byte => byte === 0).length * 4 + data.filter(byte => byte !== 0).length * 16; +} diff --git a/yarn-project/sequencer-client/src/publisher/viem-tx-sender.ts b/yarn-project/sequencer-client/src/publisher/viem-tx-sender.ts deleted file mode 100644 index e33aafbe79f7..000000000000 --- a/yarn-project/sequencer-client/src/publisher/viem-tx-sender.ts +++ /dev/null @@ -1,289 +0,0 @@ -import { type L2Block } from '@aztec/circuit-types'; -import { ETHEREUM_SLOT_DURATION, EthAddress } from '@aztec/circuits.js'; -import { createEthereumChain } from '@aztec/ethereum'; -import { createDebugLogger } from '@aztec/foundation/log'; -import { AvailabilityOracleAbi, RollupAbi } from '@aztec/l1-artifacts'; - -import { - type GetContractReturnType, - type Hex, - type HttpTransport, - type PublicClient, - type WalletClient, - createPublicClient, - createWalletClient, - getAddress, - getContract, - hexToBytes, - http, -} from 'viem'; -import { type PrivateKeyAccount, privateKeyToAccount } from 'viem/accounts'; -import * as chains from 'viem/chains'; - -import { type TxSenderConfig } from './config.js'; -import { - type L1PublisherTxSender, - type L1SubmitProofArgs, - type MinimalTransactionReceipt, - type L1ProcessArgs as ProcessTxArgs, - type TransactionStats, -} from './l1-publisher.js'; - -/** - * Pushes transactions to the L1 rollup contract using viem. - */ -export class ViemTxSender implements L1PublisherTxSender { - private availabilityOracleContract: GetContractReturnType< - typeof AvailabilityOracleAbi, - WalletClient - >; - private rollupContract: GetContractReturnType< - typeof RollupAbi, - WalletClient - >; - - private log = createDebugLogger('aztec:sequencer:viem-tx-sender'); - private publicClient: PublicClient; - private account: PrivateKeyAccount; - - constructor(config: TxSenderConfig) { - const { l1RpcUrl: rpcUrl, l1ChainId: chainId, publisherPrivateKey, l1Contracts } = config; - const chain = createEthereumChain(rpcUrl, chainId); - this.account = privateKeyToAccount(publisherPrivateKey); - const walletClient = createWalletClient({ - account: this.account, - chain: chain.chainInfo, - transport: http(chain.rpcUrl), - }); - - this.publicClient = createPublicClient({ - chain: chain.chainInfo, - transport: http(chain.rpcUrl), - }); - - this.availabilityOracleContract = getContract({ - address: getAddress(l1Contracts.availabilityOracleAddress.toString()), - abi: AvailabilityOracleAbi, - client: walletClient, - }); - this.rollupContract = getContract({ - address: getAddress(l1Contracts.rollupAddress.toString()), - abi: RollupAbi, - client: walletClient, - }); - } - - getSenderAddress(): Promise { - return Promise.resolve(EthAddress.fromString(this.account.address)); - } - - // Computes who will be the L2 proposer at the next Ethereum block - // Using next Ethereum block so we do NOT need to wait for it being mined before seeing the effect - // @note Assumes that all ethereum slots have blocks - async getProposerAtNextEthBlock(): Promise { - try { - const ts = BigInt((await this.publicClient.getBlock()).timestamp + BigInt(ETHEREUM_SLOT_DURATION)); - const submitter = await this.rollupContract.read.getProposerAt([ts]); - return EthAddress.fromString(submitter); - } catch (err) { - this.log.warn(`Failed to get submitter: ${err}`); - return EthAddress.ZERO; - } - } - - async getCurrentEpochCommittee(): Promise { - const committee = await this.rollupContract.read.getCurrentEpochCommittee(); - return committee.map(address => EthAddress.fromString(address)); - } - - async getCurrentArchive(): Promise { - const archive = await this.rollupContract.read.archive(); - return Buffer.from(archive.replace('0x', ''), 'hex'); - } - - checkIfTxsAreAvailable(block: L2Block): Promise { - const args = [`0x${block.body.getTxsEffectsHash().toString('hex').padStart(64, '0')}`] as const; - return this.availabilityOracleContract.read.isAvailable(args); - } - - async getTransactionStats(txHash: string): Promise { - const tx = await this.publicClient.getTransaction({ hash: txHash as Hex }); - if (!tx) { - return undefined; - } - const calldata = hexToBytes(tx.input); - return { - transactionHash: tx.hash, - calldataSize: calldata.length, - calldataGas: getCalldataGasUsage(calldata), - }; - } - - /** - * Returns a tx receipt if the tx has been mined. - * @param txHash - Hash of the tx to look for. - * @returns Undefined if the tx hasn't been mined yet, the receipt otherwise. - */ - async getTransactionReceipt(txHash: string): Promise { - const receipt = await this.publicClient.getTransactionReceipt({ - hash: txHash as Hex, - }); - - if (receipt) { - return { - status: receipt.status === 'success', - transactionHash: txHash, - gasUsed: receipt.gasUsed, - gasPrice: receipt.effectiveGasPrice, - logs: receipt.logs, - }; - } - - this.log.debug(`Receipt not found for tx hash ${txHash}`); - return undefined; - } - - /** - * Publishes tx effects to Availability Oracle. - * @param encodedBody - Encoded block body. - * @returns The hash of the mined tx. - */ - async sendPublishTx(encodedBody: Buffer): Promise { - const args = [`0x${encodedBody.toString('hex')}`] as const; - - const gas = await this.availabilityOracleContract.estimateGas.publish(args, { - account: this.account, - }); - const hash = await this.availabilityOracleContract.write.publish(args, { - gas, - account: this.account, - }); - return hash; - } - - /** - * Sends a tx to the L1 rollup contract with a new L2 block. Returns once the tx has been mined. - * @param encodedData - Serialized data for processing the new L2 block. - * @returns The hash of the mined tx. - */ - async sendProcessTx(encodedData: ProcessTxArgs): Promise { - if (encodedData.attestations) { - // Get `0x${string}` encodings - const attestations = encodedData.attestations.map(attest => attest.toViemSignature()); - - const args = [ - `0x${encodedData.header.toString('hex')}`, - `0x${encodedData.archive.toString('hex')}`, - attestations, - ] as const; - - const gas = await this.rollupContract.estimateGas.process(args, { - account: this.account, - }); - return await this.rollupContract.write.process(args, { - gas, - account: this.account, - }); - } else { - const args = [`0x${encodedData.header.toString('hex')}`, `0x${encodedData.archive.toString('hex')}`] as const; - - const gas = await this.rollupContract.estimateGas.process(args, { - account: this.account, - }); - return await this.rollupContract.write.process(args, { - gas, - account: this.account, - }); - } - } - - /** - * @notice Publishes the body AND process the block in one transaction - * @param encodedData - Serialized data for processing the new L2 block. - * @returns The hash of the transaction - */ - async sendPublishAndProcessTx(encodedData: ProcessTxArgs): Promise { - // @note This is quite a sin, but I'm committing war crimes in this code already. - if (encodedData.attestations) { - const attestations = encodedData.attestations.map(attest => attest.toViemSignature()); - const args = [ - `0x${encodedData.header.toString('hex')}`, - `0x${encodedData.archive.toString('hex')}`, - attestations, - `0x${encodedData.body.toString('hex')}`, - ] as const; - - const gas = await this.rollupContract.estimateGas.publishAndProcess(args, { - account: this.account, - }); - return await this.rollupContract.write.publishAndProcess(args, { - gas, - account: this.account, - }); - } else { - const args = [ - `0x${encodedData.header.toString('hex')}`, - `0x${encodedData.archive.toString('hex')}`, - `0x${encodedData.body.toString('hex')}`, - ] as const; - - const gas = await this.rollupContract.estimateGas.publishAndProcess(args, { - account: this.account, - }); - return await this.rollupContract.write.publishAndProcess(args, { - gas, - account: this.account, - }); - } - } - - /** - * Sends a tx to the L1 rollup contract with a proof. Returns once the tx has been mined. - * @param encodedData - Serialized data for the proof. - * @returns The hash of the mined tx. - */ - async sendSubmitProofTx(submitProofArgs: L1SubmitProofArgs): Promise { - const { header, archive, proverId, aggregationObject, proof } = submitProofArgs; - const args = [ - `0x${header.toString('hex')}`, - `0x${archive.toString('hex')}`, - `0x${proverId.toString('hex')}`, - `0x${aggregationObject.toString('hex')}`, - `0x${proof.toString('hex')}`, - ] as const; - - const gas = await this.rollupContract.estimateGas.submitProof(args, { - account: this.account, - }); - const hash = await this.rollupContract.write.submitProof(args, { - gas, - account: this.account, - }); - - return hash; - } - - /** - * Gets the chain object for the given chain id. - * @param chainId - Chain id of the target EVM chain. - * @returns Viem's chain object. - */ - private getChain(chainId: number) { - for (const chain of Object.values(chains)) { - if ('id' in chain && chain.id === chainId) { - return chain; - } - } - - throw new Error(`Chain with id ${chainId} not found`); - } -} - -/** - * Returns cost of calldata usage in Ethereum. - * @param data - Calldata. - * @returns 4 for each zero byte, 16 for each nonzero. - */ -function getCalldataGasUsage(data: Uint8Array) { - return data.filter(byte => byte === 0).length * 4 + data.filter(byte => byte !== 0).length * 16; -} diff --git a/yarn-project/sequencer-client/src/receiver.ts b/yarn-project/sequencer-client/src/receiver.ts deleted file mode 100644 index 77ae6ee05a4d..000000000000 --- a/yarn-project/sequencer-client/src/receiver.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { type L2Block, type Signature } from '@aztec/circuit-types'; - -/** - * Given the necessary rollup data, verifies it, and updates the underlying state accordingly to advance the state of the system. - * See https://hackmd.io/ouVCnacHQRq2o1oRc5ksNA#RollupReceiver. - */ -export interface L2BlockReceiver { - processL2Block(block: L2Block, attestations?: Signature[]): Promise; -} diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts index 23df5037b10a..9f4f79046fa2 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts @@ -22,6 +22,7 @@ import { IS_DEV_NET, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, } from '@aztec/circuits.js'; +import { times } from '@aztec/foundation/collection'; import { randomBytes } from '@aztec/foundation/crypto'; import { type Writeable } from '@aztec/foundation/types'; import { type P2P, P2PClientState } from '@aztec/p2p'; @@ -376,6 +377,189 @@ describe('sequencer', () => { expect(blockSimulator.cancelBlock).toHaveBeenCalledTimes(0); }); + it('builds a block once it reaches the minimum number of transactions', async () => { + const txs = times(8, i => { + const tx = mockTxForRollup(i * 0x10000); + tx.data.constants.txContext.chainId = chainId; + return tx; + }); + const block = L2Block.random(lastBlockNumber + 1); + const result: ProvingSuccess = { + status: PROVING_STATUS.SUCCESS, + }; + const ticket: ProvingTicket = { + provingPromise: Promise.resolve(result), + }; + + blockSimulator.startNewBlock.mockResolvedValueOnce(ticket); + blockSimulator.finaliseBlock.mockResolvedValue({ block }); + publisher.processL2Block.mockResolvedValueOnce(true); + + const mockedGlobalVariables = new GlobalVariables( + chainId, + version, + new Fr(lastBlockNumber + 1), + block.header.globalVariables.slotNumber, + Fr.ZERO, + coinbase, + feeRecipient, + gasFees, + ); + + globalVariableBuilder.buildGlobalVariables.mockResolvedValueOnce(mockedGlobalVariables); + + await sequencer.initialSync(); + + sequencer.updateConfig({ minTxsPerBlock: 4 }); + + // block is not built with 0 txs + p2p.getTxs.mockReturnValueOnce([]); + //p2p.getTxs.mockReturnValueOnce(txs.slice(0, 4)); + await sequencer.work(); + expect(blockSimulator.startNewBlock).toHaveBeenCalledTimes(0); + + // block is not built with 3 txs + p2p.getTxs.mockReturnValueOnce(txs.slice(0, 3)); + await sequencer.work(); + expect(blockSimulator.startNewBlock).toHaveBeenCalledTimes(0); + + // block is built with 4 txs + p2p.getTxs.mockReturnValueOnce(txs.slice(0, 4)); + await sequencer.work(); + expect(blockSimulator.startNewBlock).toHaveBeenCalledWith( + 4, + mockedGlobalVariables, + Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(new Fr(0n)), + ); + expect(publisher.processL2Block).toHaveBeenCalledTimes(1); + expect(publisher.processL2Block).toHaveBeenCalledWith(block, getAttestations()); + expect(blockSimulator.cancelBlock).toHaveBeenCalledTimes(0); + }); + + it('builds a block that contains zero real transactions once flushed', async () => { + const txs = times(8, i => { + const tx = mockTxForRollup(i * 0x10000); + tx.data.constants.txContext.chainId = chainId; + return tx; + }); + const block = L2Block.random(lastBlockNumber + 1); + const result: ProvingSuccess = { + status: PROVING_STATUS.SUCCESS, + }; + const ticket: ProvingTicket = { + provingPromise: Promise.resolve(result), + }; + + blockSimulator.startNewBlock.mockResolvedValueOnce(ticket); + blockSimulator.finaliseBlock.mockResolvedValue({ block }); + publisher.processL2Block.mockResolvedValueOnce(true); + + const mockedGlobalVariables = new GlobalVariables( + chainId, + version, + new Fr(lastBlockNumber + 1), + block.header.globalVariables.slotNumber, + Fr.ZERO, + coinbase, + feeRecipient, + gasFees, + ); + + globalVariableBuilder.buildGlobalVariables.mockResolvedValueOnce(mockedGlobalVariables); + + await sequencer.initialSync(); + + sequencer.updateConfig({ minTxsPerBlock: 4 }); + + // block is not built with 0 txs + p2p.getTxs.mockReturnValueOnce([]); + await sequencer.work(); + expect(blockSimulator.startNewBlock).toHaveBeenCalledTimes(0); + + // block is not built with 3 txs + p2p.getTxs.mockReturnValueOnce(txs.slice(0, 3)); + await sequencer.work(); + expect(blockSimulator.startNewBlock).toHaveBeenCalledTimes(0); + + // flush the sequencer and it should build a block + sequencer.flush(); + + // block is built with 0 txs + p2p.getTxs.mockReturnValueOnce([]); + await sequencer.work(); + expect(blockSimulator.startNewBlock).toHaveBeenCalledTimes(1); + expect(blockSimulator.startNewBlock).toHaveBeenCalledWith( + 2, + mockedGlobalVariables, + Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(new Fr(0n)), + ); + expect(publisher.processL2Block).toHaveBeenCalledTimes(1); + expect(publisher.processL2Block).toHaveBeenCalledWith(block, getAttestations()); + expect(blockSimulator.cancelBlock).toHaveBeenCalledTimes(0); + }); + + it('builds a block that contains less than the minimum number of transactions once flushed', async () => { + const txs = times(8, i => { + const tx = mockTxForRollup(i * 0x10000); + tx.data.constants.txContext.chainId = chainId; + return tx; + }); + const block = L2Block.random(lastBlockNumber + 1); + const result: ProvingSuccess = { + status: PROVING_STATUS.SUCCESS, + }; + const ticket: ProvingTicket = { + provingPromise: Promise.resolve(result), + }; + + blockSimulator.startNewBlock.mockResolvedValueOnce(ticket); + blockSimulator.finaliseBlock.mockResolvedValue({ block }); + publisher.processL2Block.mockResolvedValueOnce(true); + + const mockedGlobalVariables = new GlobalVariables( + chainId, + version, + new Fr(lastBlockNumber + 1), + block.header.globalVariables.slotNumber, + Fr.ZERO, + coinbase, + feeRecipient, + gasFees, + ); + + globalVariableBuilder.buildGlobalVariables.mockResolvedValueOnce(mockedGlobalVariables); + + await sequencer.initialSync(); + + sequencer.updateConfig({ minTxsPerBlock: 4 }); + + // block is not built with 0 txs + p2p.getTxs.mockReturnValueOnce([]); + await sequencer.work(); + expect(blockSimulator.startNewBlock).toHaveBeenCalledTimes(0); + + // block is not built with 3 txs + p2p.getTxs.mockReturnValueOnce(txs.slice(0, 3)); + await sequencer.work(); + expect(blockSimulator.startNewBlock).toHaveBeenCalledTimes(0); + + // flush the sequencer and it should build a block + sequencer.flush(); + + // block is built with 3 txs + p2p.getTxs.mockReturnValueOnce(txs.slice(0, 3)); + await sequencer.work(); + expect(blockSimulator.startNewBlock).toHaveBeenCalledTimes(1); + expect(blockSimulator.startNewBlock).toHaveBeenCalledWith( + 3, + mockedGlobalVariables, + Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(new Fr(0n)), + ); + expect(publisher.processL2Block).toHaveBeenCalledTimes(1); + expect(publisher.processL2Block).toHaveBeenCalledWith(block, getAttestations()); + expect(blockSimulator.cancelBlock).toHaveBeenCalledTimes(0); + }); + it('aborts building a block if the chain moves underneath it', async () => { const tx = mockTxForRollup(); tx.data.constants.txContext.chainId = chainId; diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.ts index d493e03e0a66..1fe8fa5f52c1 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.ts @@ -53,6 +53,7 @@ export class Sequencer { private allowedInTeardown: AllowedElement[] = []; private maxBlockSizeInBytes: number = 1024 * 1024; private metrics: SequencerMetrics; + private isFlushing: boolean = false; constructor( private publisher: L1Publisher, @@ -194,6 +195,10 @@ export class Sequencer { return; } + if (this.isFlushing) { + this.log.verbose(`Flushing all pending txs in new block`); + } + // Compute time elapsed since the previous block const lastBlockTime = historicalHeader?.globalVariables.timestamp.toNumber() || 0; const currentTime = Math.floor(Date.now() / 1000); @@ -203,7 +208,11 @@ export class Sequencer { ); // Do not go forward with new block if not enough time has passed since last block - if (this.minSecondsBetweenBlocks > 0 && elapsedSinceLastBlock < this.minSecondsBetweenBlocks) { + if ( + !this.isFlushing && + this.minSecondsBetweenBlocks > 0 && + elapsedSinceLastBlock < this.minSecondsBetweenBlocks + ) { this.log.debug( `Not creating block because not enough time ${this.minSecondsBetweenBlocks} has passed since last block`, ); @@ -216,7 +225,7 @@ export class Sequencer { const pendingTxs = this.p2pClient.getTxs('pending'); // If we haven't hit the maxSecondsBetweenBlocks, we need to have at least minTxsPerBLock txs. - if (pendingTxs.length < this.minTxsPerBLock) { + if (!this.isFlushing && pendingTxs.length < this.minTxsPerBLock) { if (this.skipMinTxsPerBlockCheck(elapsedSinceLastBlock)) { this.log.debug( `Creating block with only ${pendingTxs.length} txs as more than ${this.maxSecondsBetweenBlocks}s have passed since last block`, @@ -252,7 +261,11 @@ export class Sequencer { const validTxs = this.takeTxsWithinMaxSize(allValidTxs); // Bail if we don't have enough valid txs - if (!this.skipMinTxsPerBlockCheck(elapsedSinceLastBlock) && validTxs.length < this.minTxsPerBLock) { + if ( + !this.isFlushing && + !this.skipMinTxsPerBlockCheck(elapsedSinceLastBlock) && + validTxs.length < this.minTxsPerBLock + ) { this.log.debug( `Not creating block because not enough valid txs loaded from the pool (got ${validTxs.length} min ${this.minTxsPerBLock})`, ); @@ -334,7 +347,12 @@ export class Sequencer { // less txs than the minimum. But that'd cause the entire block to be aborted and retried. Instead, we should // go back to the p2p pool and load more txs until we hit our minTxsPerBLock target. Only if there are no txs // we should bail. - if (processedTxs.length === 0 && !this.skipMinTxsPerBlockCheck(elapsedSinceLastBlock) && this.minTxsPerBLock > 0) { + if ( + !this.isFlushing && + processedTxs.length === 0 && + !this.skipMinTxsPerBlockCheck(elapsedSinceLastBlock) && + this.minTxsPerBLock > 0 + ) { this.log.verbose('No txs processed correctly to build block. Exiting'); blockBuilder.cancelBlock(); return; @@ -374,6 +392,11 @@ export class Sequencer { } satisfies L2BlockBuiltStats, ); + if (this.isFlushing) { + this.log.verbose(`Flushing completed`); + } + this.isFlushing = false; + try { const attestations = await this.collectAttestations(block); await this.publishL2Block(block, attestations); @@ -381,7 +404,7 @@ export class Sequencer { this.log.info( `Submitted rollup block ${block.number} with ${ processedTxs.length - } transactions duration=${workDuration}ms (Submitter: ${await this.publisher.senderAddress()})`, + } transactions duration=${workDuration}ms (Submitter: ${await this.publisher.getSenderAddress()})`, ); } catch (err) { this.metrics.recordFailedBlock(); @@ -389,6 +412,11 @@ export class Sequencer { } } + /** Forces the sequencer to bypass all time and tx count checks for the next block and build anyway. */ + public flush() { + this.isFlushing = true; + } + protected async collectAttestations(block: L2Block): Promise { // @todo This should collect attestations properly and fix the ordering of them to make sense // the current implementation is a PLACEHOLDER and should be nuked from orbit.