<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
      <title>LambdaClass Blog</title>
      <link>https://lambdaclass.github.io/lambdaclass_blog</link>
      <description>Deep technical insights on cryptography, distributed systems, zero-knowledge proofs, and cutting-edge software engineering from the LambdaClass team.</description>
      <generator>Zola</generator>
      <language>en</language>
      <atom:link href="https://lambdaclass.github.io/lambdaclass_blog/rss.xml" rel="self" type="application/rss+xml"/>
      <lastBuildDate>Fri, 16 Jan 2026 00:00:00 +0000</lastBuildDate>
      <item>
          <title>A Sharper Look at FRI</title>
          <pubDate>Fri, 16 Jan 2026 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/a-sharper-look-at-fri/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/a-sharper-look-at-fri/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/a-sharper-look-at-fri/">&lt;h1 id=&quot;a-sharper-look-at-fri&quot;&gt;A sharper look at FRI&lt;&#x2F;h1&gt;
&lt;p&gt;In this article, we will review recent developments in the analysis of the cryptographic security of one of the biggest pieces of the ZK engine: the FRI protocol, implementing interactive oracle proofs of proximity, IOPPs. A newly uploaded article by Eli Ben-Sasson, Dan Carmon, Swastik Kopparty, and Shubhangi Saraf, alongside Ulrich Habock (BCHKS25), revisits the foundational 2020 paper “Proximity Gaps for Reed Solomon Code” (BCIKS20), in which the soundness of the RS-IOPP was established using the Correlated Agreement Theorem. By a more detailed and sharper use of linear algebra in the process under the list-decoding regime, they obtained improved security performance bounds for the standard FRI. Here, we will conceptually revise the protocol and give an outline of how their breakthrough was achieved.&lt;&#x2F;p&gt;
&lt;p&gt;The acquainted reader may skip directly to section 4, while newcomers are encouraged to read the first sections to get familiar with notations and concepts involved.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1-basic-reed-solomon-landscape&quot;&gt;1. Basic Reed-Solomon landscape&lt;&#x2F;h2&gt;
&lt;p&gt;Let us begin with an overview of one of the basics of code-based cryptography: an interactive instance of information exchange between a Prover (P) and a Verifier (V) - where P wants to convince V that he has executed a certain task or possesses certain information. Usually, the information P claims to possess is, in fact, the result of a computation, in the form of a low-degree polynomial f, say $\deg(f) &amp;lt; k$ with coefficients in a suitable finite field $\mathbb{F}_q$ of $q$ elements.&lt;&#x2F;p&gt;
&lt;p&gt;A completely naive approach would be for the prover to send the list of coefficients of the polynomial he claims to possess, or, by the Fundamental Theorem of Algebra, a list of $\deg(f)+1 \leq k$ evaluations of his polynomial. It is clear that such an idea is inefficient, since we would have to communicate a lot of information through a channel.&lt;&#x2F;p&gt;
&lt;p&gt;One of the ideas to circumvent the exposure of $f$ is to actually evaluate $f$ at many more points $\mathcal{D}$ with $n = |\mathcal{D}| &amp;gt;&amp;gt; k$ in the base field $\mathbb{F}_q$, so that now what the Prover and Verifier exchange are much longer lists of evaluations:&lt;&#x2F;p&gt;
&lt;p&gt;The effect that this has is that any attacker will be faced with the challenge of distinguishing between lists of numbers corresponding to evaluations of low-degree polynomials and lists that do not come from evaluating such polynomials.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Reed-Solomon Code:&lt;&#x2F;strong&gt; This is the very basic idea of a Reed-Solomon code $RS[q,n,k]$: length $n$ vectors consisting exactly of the evaluation of polynomials of degree bounded by $k$ over a domain $\mathcal{D} \subset \mathbb{F}_q$.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;As a subset of the ambient vector space $\mathbb{F}_q^n$, the Reed-Solomon code is a vector subspace since the evaluation of polynomials is a linear operation, and as such it is a prime example of a &lt;em&gt;linear code&lt;&#x2F;em&gt;. This means that the coordinate-wise addition of codewords is again a codeword, and pointwise multiplication of codewords by elements of the field is again a codeword. Not all codes are linear.&lt;&#x2F;p&gt;
&lt;p&gt;For a general code $\mathcal{C}$ defined over a finite field $\mathbb{F}_q$ with block length $n$, for any two codewords $\mathbf{u}, \mathbf{v} \in \mathbb{F}_q^n$, “absolute” Hamming distance $d(\mathbf{u}, \mathbf{v})$ is defined as the number of positions where the corresponding symbols differ:&lt;&#x2F;p&gt;
&lt;p&gt;$$d(\mathbf{u}, \mathbf{v}) = \left| { i \in {1, \dots, n} : u_i \neq v_i } \right|$$&lt;&#x2F;p&gt;
&lt;p&gt;and typically one works with a fractional version of $d$ which takes into account the blocklength:&lt;&#x2F;p&gt;
&lt;p&gt;$$\Delta(\mathbf{u}, \mathbf{v}) = \frac{d(\mathbf{u}, \mathbf{v})}{n}$$&lt;&#x2F;p&gt;
&lt;p&gt;This allows the &lt;strong&gt;interpretation of the distance as the fraction of entries in which two codewords differ&lt;&#x2F;strong&gt;. Finally, we recall the notion of the rate of a code of dimension $k$ and blocklength $n$ as the ratio:&lt;&#x2F;p&gt;
&lt;p&gt;$$\rho = \frac{k}{n}$$&lt;&#x2F;p&gt;
&lt;p&gt;This number can be interpreted in a few ways, namely as a measure of &lt;strong&gt;information content:&lt;&#x2F;strong&gt; $\rho$% of the transmitted symbols carry the actual information of the message. The &lt;strong&gt;redundancy&lt;&#x2F;strong&gt; is the remaining $(1-\rho)$% of the message and is the resource consumed to provide error-correction capabilities (more on this soon). A lower rate implies higher redundancy and theoretically higher resilience to noise, at the cost of throughput.&lt;&#x2F;p&gt;
&lt;p&gt;An important concept in coding theory is the concept of a list around a word w: for $w \in \mathbb{F}_q^n$ and $\delta &amp;gt; 0$, it is the set&lt;&#x2F;p&gt;
&lt;p&gt;$$List[w, \mathcal{C}, \delta]$$&lt;&#x2F;p&gt;
&lt;p&gt;and this is comprised of the codewords belonging to the code $\mathcal{C}$ that have distance at most $\delta$ from the word $w$. An associated question is given $w$ to decide, in terms of $\delta$, how many elements a list has. For sufficiently small $\delta$, the list around $w$ has at most one element, and in this sense we will say that $w$ can be “corrected” to the corresponding $u \in \mathcal{C}$; that is, the usual information-theoretic view of goodness of the code. We will say that in those circumstances, we’re within the “unique decoding regime”. For Reed-Solomon codes, this bound for $\delta$ can be given in terms of the rate of the code, and this regime is characterized by&lt;&#x2F;p&gt;
&lt;p&gt;$$\delta &amp;lt; \frac{1-\rho}{2}$$&lt;&#x2F;p&gt;
&lt;p&gt;However, this can sometimes be too restrictive when implementing efficient, fast code-based algorithms, and we will be willing to admit a list of candidate codewords sufficiently close to the received word $w$, rather than a single codeword.** At these times, we will be working in the “list decoding regime” and &lt;strong&gt;it is crucial for lists $\mathcal{L}$ around $w$ not to have too many elements.&lt;&#x2F;strong&gt; For that matter, there is a bound on $\delta$, usually called the Johnson bound, that says that the number of elements in a list $\mathcal{L}$ is polynomially bounded. The Johnson bound is valid for any code, and is obtained by combinatorial and geometric arguments.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Johnson Bound for Reed-Solomon Codes:&lt;&#x2F;strong&gt; Specifically for Reed-Solomon codes, it can be given in terms of the rat,e and the list decoding regime is characterized as&lt;&#x2F;p&gt;
&lt;p&gt;$$\delta &amp;lt; 1 - \sqrt{\rho} = J$$&lt;&#x2F;p&gt;
&lt;p&gt;and a standard upper bound for the list size $\mathcal{L}$ is:&lt;&#x2F;p&gt;
&lt;p&gt;$$\mathcal{L} \le \frac{1 - \delta}{(1 - \delta)^2 - \rho}$$&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Sometimes, this list size is expressed as the distance between the operating proximity parameter $\delta$ and the actual Johnson bound; typically, this is called the “safety gap” $\eta$. Naturally $\eta = J - \delta = 1 - \sqrt{\rho} - \delta$ and then&lt;&#x2F;p&gt;
&lt;p&gt;$$\delta = (1 - \sqrt{\rho}) - \eta \quad \implies \quad 1 - \delta = \sqrt{\rho} + \eta$$&lt;&#x2F;p&gt;
&lt;p&gt;This translates as&lt;&#x2F;p&gt;
&lt;p&gt;$$\mathcal{L} \le \frac{\sqrt{\rho} + \eta}{2\eta\sqrt{\rho} + \eta^2} \approx \frac{\sqrt{\rho}}{2\eta\sqrt{\rho}} = \frac{1}{2\eta}$$&lt;&#x2F;p&gt;
&lt;p&gt;The dependency $\mathcal{L} = O(1&#x2F;\eta)$ often cited in FRI literature is simply the asymptotic behavior of the exact discriminant bound $\frac{1-\delta}{(1-\delta)^2 - \rho}$ as the proximity parameter approaches the Johnson bound.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2-what-is-an-iopp&quot;&gt;2. What is an IOPP&lt;&#x2F;h2&gt;
&lt;p&gt;Going back to the problem of the Prover (P) and Verifier (V) exchanging information, let’s see how to set up that stage. Actually, it would be nice to start by spelling out what IOPP actually stands for: Interactive Oracle Proofs of Proximity. We’ll contextualize each of these titles in this itemized section:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Obviously, &lt;strong&gt;Interactive&lt;&#x2F;strong&gt; stands for the notion of prover and verifier interacting with each other, exchanging information.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Now comes the sketchy part: in these contexts, the Verifier ($V$) lacks the computational resources to read the entire Prover’s ($P$) message; it is restricted to open or look up a limited number of times a small portion of the data produced by the prover. Technically, the Verifier has what is called &lt;strong&gt;Oracle&lt;&#x2F;strong&gt; access: $P$ commits to a function $f: D \to \mathbb{F}$ and $V$ accesses $f$ essentially as a black box oracle. $V$ selects an index $x \in D$, and the oracle responds with $f(x)$.&lt;&#x2F;p&gt;
&lt;p&gt;In practice, this is achieved via &lt;em&gt;Merkle Trees&lt;&#x2F;em&gt;. The commitment is the Merkle Root. An oracle query response consists of the value $f(x)$ and the Merkle authentication path.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;The use of &lt;strong&gt;Proofs of Proximity&lt;&#x2F;strong&gt; rather than strict membership is both a fundamental theoretical necessity in succinct proofs and a practical limitation because &lt;strong&gt;to verify strict membership (that a vector is &lt;em&gt;exactly&lt;&#x2F;em&gt; a codeword), the verifier must read the entire input, and this requires linear time $\Omega(n)$.&lt;&#x2F;strong&gt; In order to break free from this limitation, the idea is not to test for word-membership to the code, but rather that a word is &lt;strong&gt;$\delta$-close&lt;&#x2F;strong&gt; to the code. Within the FRI protocol, this property can be checked with high probability using only a logarithmic number of queries.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Let us emphasize these facts again:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key Insight:&lt;&#x2F;strong&gt; In order to make an IOPP protocol feasible in practice, we relax the condition of membership $f \in \mathcal{C}$ to a condition of proximity $\Delta(f, \mathcal{C}) &amp;lt; \delta$ by allowing a positive distance $\delta &amp;gt; 0$: this allows sublinear number of queries (sublinear in the blocklength $n$) since now the Verifier does not have to read the whole message - and at the same time, for security reasons, but we do not allow a $\delta$ way too big: if a malicious Prover (P) wants get away with a false statement $f$ we want to make those chances as slim as possible. For that reason, we demand $\delta$ to be bounded by a meaningful constant, say, the Johnson bound.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;3-how-fri-works&quot;&gt;3. How FRI works&lt;&#x2F;h2&gt;
&lt;p&gt;FRI stands for Fast Reed-Solomon Interactive Proof of Proximity, a shortened version of RS-IOPP. It is actually an IOPP protocol adjusted for Reed-Solomon codes. It basically consists of two distinct phases: the COMMIT phase and the Verify phase. Most of the optimization and prover’s work occurs during the COMMIT phase, while the Verifier’s bulk of work occurs during the Verify phase. We proceed to briefly discuss each of these phases.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;3-1-the-commit-phase&quot;&gt;3.1 The COMMIT phase&lt;&#x2F;h3&gt;
&lt;p&gt;In this phase, the Prover wants to prove that he possesses a codeword in $\mathcal{C}_0 = RS[q,n,k]$ where the evaluation domain $\mathcal{D}_0$ is agreed beforehand. Conceptually, after the $i$-th round of interaction with the Verifier, the Prover produces a codeword $f_i$ belonging to a smaller Reed-Solomon code $C_i$. This results in a sequence of codewords $f_1, f_2, \ldots f_r$ belonging to an adequate sequence of Reed-Solomon codes $C_i = RS[q, n_i, k_i]$ such that if $n = n_0$ and $k = k_0$ then for $0 \leq i \leq r$:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;the evaluation domains are nested: $\mathcal{D}_{i+1} \subset \mathcal{D}&lt;em&gt;i$ and their sizes are uniformly related: this means that we have a relation of the form $n_i = a \cdot n&lt;&#x2F;em&gt;{i+1}$ where the constant $a$ is known as the &lt;em&gt;folding constant&lt;&#x2F;em&gt;. Typically, $a = 2, 4$ or $8$. In this exposition, we’ll stick to the case $a = 2$ for simplicity.&lt;&#x2F;li&gt;
&lt;li&gt;the rate of the code remains unchanged at each step: $\frac{k_i}{n_i} = \rho$.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;&#x2F;strong&gt; The FRI protocol is usually instantiated for fields of characteristic $&amp;gt; 2$, and blocksize $n_0$ being a power of $2$ such that $\mathcal{D}_0$ is indeed the collection of $n_0$-th roots of unity. Also, the code dimension is chosen to be a power of two.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;A brief description of the COMMIT phase goes as follows:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Initialization:&lt;&#x2F;strong&gt; An honest Prover $P$ commits to the initial codeword $f_0$ (via a Merkle Root).&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Interaction Loop ($i = 0$ to $r-1$):&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The verifier $V$ sends a random challenge $\alpha_i \in \mathbb{F}$.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;The $P$ now proceeds to construct a new word in a “smaller” Reed-Solomon code $\mathcal{C}&lt;em&gt;{i+1}$ over the new domain $D&lt;&#x2F;em&gt;{i+1} = {x^2 : x \in D_i}$, which is a subset of the previous domain and contains half the points. The rationale behind this is that for a polynomial $f_i$ with $\deg(f_i) &amp;lt; k_i,$ one can write $f_i$ as the sum of a polynomial containing all the even powers and a polynomial containing all the odd powers. This amounts to the guaranteed existence of two polynomials $g_i$ and $h$ both having degree $&amp;lt; \frac{k}{2}$ such that&lt;&#x2F;p&gt;
&lt;p&gt;$$f_i(X) = g_i(X^2) + X h(X^2)$$&lt;&#x2F;p&gt;
&lt;p&gt;One of the good things about this decomposition is that both $g_i$ and $h$ evaluated at $x^2$ are linearly related to $f$ evaluated at $x$ and $-x$:&lt;&#x2F;p&gt;
&lt;p&gt;$$g_i(x^2) = \frac{f(x) + f(-x)}{2} \quad \text{and} \quad h(x^2) = \frac{f(x) - f(-x)}{2x}$$&lt;&#x2F;p&gt;
&lt;p&gt;and so the Prover is now able to define a new Reed-Solomon codeword for $z \in D_{i+1}$ by&lt;&#x2F;p&gt;
&lt;p&gt;$$f_{i+1}(z) = g_i(z) + \alpha_i h_i(z)$$&lt;&#x2F;p&gt;
&lt;p&gt;belonging to $C_{i+1} = RS[q, \frac{n_i}{2}, \frac{k_i}{2}]$. $P$ computes and commits to this new word and sends the new Merkle root to V.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Termination:&lt;&#x2F;strong&gt; The process stops when the degree is small (e.g., constant). $P$ sends the final value directly.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The reader acquainted with the classical Fast Fourier Transform algorithm will find these last few lines very familiar.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;3-2-the-verify-phase&quot;&gt;3.2 The VERIFY phase&lt;&#x2F;h3&gt;
&lt;p&gt;We’re now ready to describe the VERIFY phase of the protocol: $V$ verifies that the committed functions satisfy the recurrence relation defined by the challenges $\alpha_i$.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sampling:&lt;&#x2F;strong&gt; $V$ samples a random point $z$ from the initial domain $D_0$.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Consistency Check:&lt;&#x2F;strong&gt; For each layer $i$:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;$V$ queries the oracle for $f_i(z)$ and $f_i(-z)$ (symmetric points in domain $D_i$).&lt;&#x2F;li&gt;
&lt;li&gt;$V$ queries the oracle for $f_{i+1}(z^2)$ in the next domain $D_{i+1}$.&lt;&#x2F;li&gt;
&lt;li&gt;$V$ verifies the collinearity equation:
$$f_{i+1}(z^2) \stackrel{?}{=} g_i(z^2) + \alpha_i \cdot h_i(z^2)$$
where $g_i$ and $h_i$ are derived from the even and odd coefficients of $f_i$.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This description leads to the article’s central question: how safe is this gadget?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;4-an-improved-soundness-analysis-of-fri-as-an-iopp-instantiation&quot;&gt;4. An improved soundness analysis of FRI as an IOPP instantiation&lt;&#x2F;h2&gt;
&lt;p&gt;Here is where the novelty of the recent work, BCHKS25, improves the soundness analysis of the FRI protocol done in BCIKS20. In the foundational article “Proximity Gaps for Reed-Solomon codes,” the authors proved a fundamental result (the Correlated Agreement Theorem), from which the soundness of the FRI protocol follows. In their most recent paper, a detailed analysis of a linear-algebraic fact is used to obtain tighter bounds on the soundness of the protocols, enabling their implementation in a wider setting. Before diving into the mathematics involved, we need to define the concept of $\delta$-soundness, which establishes and fine-tunes the protocol’s security.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Soundness Definition:&lt;&#x2F;strong&gt; In order to define what it means for an IOPP to have a soundness with parameters $(\delta, \epsilon)$ we will simply take the simplest route first: the probability of the Verifier accepting a forged proof $f^&lt;em&gt;$ should be as small as possible. In terms of distance to a code, let us re-phrase the previous sentence as: the probability of the Verifier accepting a word $f^&lt;&#x2F;em&gt;$ which is $\delta$-far should be less than $\epsilon$.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Mathematically, let $\mathcal{C} \subseteq \mathbb{F}_q^n$ be a Reed-Solomon code. Let $P^&lt;em&gt;$ be any (potentially malicious) prover strategy that outputs an oracle function $f^&lt;&#x2F;em&gt;: D \to \mathbb{F}$.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Definition:&lt;&#x2F;strong&gt; The FRI protocol is said to have &lt;strong&gt;soundness error $\epsilon$ for proximity parameter $\delta$&lt;&#x2F;strong&gt; if the following implication holds:&lt;&#x2F;p&gt;
&lt;p&gt;$$\text{If } \min_{c \in \mathcal{C}} \Delta(f^&lt;em&gt;, c) &amp;gt; \delta \quad \implies \quad \Pr\left[ V^{f^&lt;&#x2F;em&gt;} \text{ accepts} \right] \le \epsilon$$&lt;&#x2F;p&gt;
&lt;p&gt;Where $\Delta(\cdot, \cdot)$ denotes the relative Hamming distance.&lt;&#x2F;p&gt;
&lt;p&gt;From the definition of $(\delta, \epsilon)$ soundness of the IOPP, one can define the security level $\lambda$ (in bits) of the Protocol. It relates to the soundness error $\epsilon$ of the protocol, defined as the probability that a Verifier accepts a proof for an invalid statement (i.e., a codeword that is $\delta$-far from the code).&lt;&#x2F;p&gt;
&lt;p&gt;$$\epsilon \le 2^{-\lambda} \iff \lambda = -\log_2(\epsilon)$$&lt;&#x2F;p&gt;
&lt;p&gt;Now the nature of the soundness error can also be characterized in a colloquial manner: the acceptance of a forged codeword could be the result of two combined effects&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;A dishonest Prover being lucky proposing a forged codeword $f^*$ which is $\delta$ far from the code and gets closer to the code at each folding step: this will be typically named “folding error” or “commit error” since it happens during the COMMIT phase, $\epsilon_{commit}$&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;A Verifier being unlucky and spot checking at places where a forged codeword $f^*$ actually coincides with a valid codeword: this error usually goes by the name of “query error”, $\epsilon_{query}$.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The total soundness error is composed of errors from the two main phases:&lt;&#x2F;p&gt;
&lt;p&gt;$$\epsilon_{\text{total}} \le \epsilon_{\text{commit}} + \epsilon_{\text{query}}$$&lt;&#x2F;p&gt;
&lt;p&gt;Particularly, the commit error is of relevance because it talks about a structural feature of the whole FRI gadget: we need to know that a dishonest Prover has very little chance of getting away with a forged proof - in terms of vicinity, the chances for a forged word becoming closer to the code at each folding step must be negligible. And here is where the celebrated Correlated Agreement comes in: it states that &lt;strong&gt;whenever a folding of two words is sufficiently close to a Reed-Solomon code, it must be because the words being folded have themselves a very high agreement with valid Reed-Solomon words, this is, they are close to Reed Solomon code themselves to begin with.&lt;&#x2F;strong&gt; This rules out the possibility of “fabricating valid words from invalid ones”.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;5-what-changed&quot;&gt;5. What changed?&lt;&#x2F;h2&gt;
&lt;p&gt;In the classic analysis presented in BCIKS20, the soundness error is derived using a union bound over the $r$ rounds of folding, and the expression obtained by the authors was roughly:&lt;&#x2F;p&gt;
&lt;p&gt;$$\epsilon_{\text{classic}} \approx \underbrace{\frac{n^2}{q}}&lt;em&gt;{\text{Commit Error}} + \underbrace{(1 - \delta)^l}&lt;&#x2F;em&gt;{\text{Query Error}}$$&lt;&#x2F;p&gt;
&lt;p&gt;where $l$ was the number of queries, $n$ the block size and $q$ the number of elements in the field. The immediate implications were that in order to achieve, say $\lambda = 100$ bits of security, one required $\frac{n^2}{q} &amp;lt; 2^{-100}$. This forced $q \approx n^2 \cdot 2^{100}$, prohibiting the use of small fields (like 64-bit fields) for large $n$. Also, the bits of security from the query phase scale linearly with $l$:&lt;&#x2F;p&gt;
&lt;p&gt;$$\lambda_{\text{query}} \approx l \cdot \log_2\left(\frac{1}{1-\delta}\right)$$&lt;&#x2F;p&gt;
&lt;p&gt;In their recent article, Ben-Sasson et al. revisited the original proof and refined the use of a linear-algebra argument in the application of the Guruswami-Sudan decoder, achieving tighter and better bounds for this error. The refined error bound is approximately:&lt;&#x2F;p&gt;
&lt;p&gt;$$\epsilon_{\text{modern}} \approx \underbrace{\frac{n}{q}}&lt;em&gt;{\text{Commit Error (Linear)}} + \underbrace{C \cdot (1 - \delta)^l}&lt;&#x2F;em&gt;{\text{Query Error}}$$&lt;&#x2F;p&gt;
&lt;p&gt;(Where $C$ is a small constant related to the list size, often close to 1 in practice). The key improvements can be directly seen from their estimate: the improvement from $|S| \approx n^2$ to $|S| \approx n$ fundamentally changes the requirements for the field size $q$ in the Commit Phase soundness error $\epsilon = |S|&#x2F;q$.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;In BCIKS20:&lt;&#x2F;strong&gt; To get $\epsilon &amp;lt; 2^{-40}$ with $n = 2^{20}$, one required $q \approx n^2 \cdot 2^{40} = 2^{80}$. This ruled out efficient 64-bit fields (like Goldilocks).&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;In BCHKS25:&lt;&#x2F;strong&gt; With $|S| \approx n$, to get $\epsilon &amp;lt; 2^{-40}$, one requires $q \approx n \cdot 2^{40} = 2^{60}$. This allows the use of small, hardware-friendly fields (e.g., 64-bit fields) while maintaining rigorous provable security.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;the-origin-of-the-n-2-q-error-term-in-classic-fri-analysis-and-how-it-got-shaved&quot;&gt;The origin of the $n^2&#x2F;q$ error term in classic FRI analysis and how it got shaved&lt;&#x2F;h3&gt;
&lt;p&gt;This section is aimed at the mathy reader familiar with the technical folklore of polynomials and their use in coding theory. The derivation of the bound for the commit phase error can be understood once we are clear in the role of some sets and consistent with the notation.&lt;&#x2F;p&gt;
&lt;p&gt;Conceptually speaking, the bound for the commit phase can be interpreted by looking at the event of the Prover going lucky by folding two codewords which are $\delta$-far from the code with an unfortunate bad choice of $\alpha \in \mathbb{F}_q$ by the Verifier (V), and obtaining a codeword which is closer to the code. Concretely, let $u_0, u_1: \mathcal{D} \to \mathbb{F}$ be the functions committed by the Prover. Let $\mathcal{C}$ be the target Reed-Solomon code. The set $S$ is defined as:&lt;&#x2F;p&gt;
&lt;p&gt;$$S = { z \in \mathbb{F}_q : \Delta(u_0 + z \cdot u_1, \mathcal{C}) \le \delta }$$&lt;&#x2F;p&gt;
&lt;p&gt;In words, $S$ contains every field element $z$ such that the linear combination $u_0 + z u_1$ falls within the proximity radius $\delta$ of the code, even if $u_0$ and $u_1$ themselves are far from $\mathcal{C}$. At the level of the FRI Protocol, the size of $S$ directly dictates the soundness error of the Commit Phase, since assuming uniformly random choices of challenges at the Verifier’s end,&lt;&#x2F;p&gt;
&lt;p&gt;$$\text{Probability of Commit Error} = \Pr_{\alpha \leftarrow \mathbb{F}_q}[\alpha \in S] = \frac{|S|}{q}$$&lt;&#x2F;p&gt;
&lt;p&gt;Of course, to ensure security, we must prove that $|S|$ is as small as possible when compared to the field size $q$. In the seminal paper BCIKS20, the authors obtain a very important and celebrated result, the Correlated Agreement Theorem (or CAT for short), which involves the size of this set $S$ of “bad folds” and is &lt;em&gt;almost&lt;&#x2F;em&gt; a proof of the soundness of FRI.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Theorem (Correlated Agreement on lines):&lt;&#x2F;strong&gt; Let $u_0, u_1: \mathcal{D} \to \mathbb{F}_q$, $m \geq 3$ and define $\delta_0(\rho, m) = J - \frac{\sqrt{\rho}}{2m}$. Set $\delta \leq \delta_0$. If&lt;&#x2F;p&gt;
&lt;p&gt;$$|S| &amp;gt; \frac{(1 + \frac{1}{2m})^7 m^7}{3\rho^{3&#x2F;2}} n^2$$&lt;&#x2F;p&gt;
&lt;p&gt;then there exist two Reed-Solomon codewords $v_0, v_1 \in \mathcal{C}$ such that they jointly coincide with $u_0, u_1$ in a set of size at least $(1-\delta)n$:&lt;&#x2F;p&gt;
&lt;p&gt;$$|{x \in \mathcal{D}: (u_0(x), u_1(x)) = (v_0(x), v_1(x))}| &amp;gt; (1-\delta)n$$&lt;&#x2F;p&gt;
&lt;p&gt;At this point, the reader is rightly puzzled, since, off the bat, we’re confronted with very funny expressions that oddly depend on some new constants. The thing is that the bound on $S$, its shape, and qualitative meaning are derived from the &lt;em&gt;method of proof&lt;&#x2F;em&gt; of the CA theorem, namely the use of a very important piece of machinery from coding theory called the Guruswami-Sudan decoder. Before commenting on this powerful algorithm, let’s brush up on the statement of the CAT in terms more sensible to the FRI protocol. By setting $\eta &amp;gt; 0$ the distance from $\delta$ to the Johnson bound $J = 1 - \sqrt{\rho}$ and $m = O(\frac{\sqrt{\rho}}{\eta})$, the previous theorem allows us to have the following &lt;em&gt;working version&lt;&#x2F;em&gt; of CAT:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Theorem (Working Version):&lt;&#x2F;strong&gt; Let $u_0, u_1: \mathcal{D} \to \mathbb{F}_q$, $\delta, \eta &amp;gt; 0$ and suppose $\eta \leq \frac{\sqrt{\rho}}{20}$. Define $\delta_0(\rho, \eta) = J - \eta$ and set $\delta &amp;lt; \delta_0$. If&lt;&#x2F;p&gt;
&lt;p&gt;$$|S| &amp;gt; \frac{\rho^2}{(2\eta)^7} \frac{n^2}{q}$$&lt;&#x2F;p&gt;
&lt;p&gt;then there exist two Reed-Solomon codewords $v_0, v_1 \in \mathcal{C}$ such that they jointly coincide with $u_0, u_1$ in a set of size at least $(1-\delta)n$:&lt;&#x2F;p&gt;
&lt;p&gt;$$|{x \in \mathcal{D}: (u_0(x), u_1(x)) = (v_0(x), v_1(x))}| &amp;gt; (1-\delta)n$$&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Now this is a little bit easier for the eyes. And now, how does this actually help us prove the soundness of FRI? What this theorem says is that whenever the set of bad folds is “big enough”, then the words being folded are close to the RS code itself. This implies that a malicious prover does not havea  high chance of cheating: his “bad folding set” will be of limited size, and so the expression&lt;&#x2F;p&gt;
&lt;p&gt;$$\frac{\rho^2}{(2\eta)^7} \frac{n^2}{q}$$&lt;&#x2F;p&gt;
&lt;p&gt;serves as an upper bound for $\epsilon_{commit}$.&lt;&#x2F;p&gt;
&lt;p&gt;So how do we make sense of why we see a quadratic term $n^2$ in this expression? Let’s dive into the mechanics of the proof of this result: the application of the Guruswami-Sudan Decoder.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Guruswami-Sudan Decoder:&lt;&#x2F;strong&gt; Briefly speaking, the Guruswami-Sudan decoder is an algorithm that takes as inputs: a word in the form of list of pairs $(x_i, y_i) \in \mathbb{F}^2$ for $1 \leq i \leq n$, a “multiplicity parameter” $m$, and an integer $D_X = D_X(m)$. Then proceeds in two phases:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Interpolation Phase:&lt;&#x2F;strong&gt; The algorithm finds a polynomial $Q(X,Y) \in \mathbb{F}[X,Y]$ such that has zeros of order at $m$ at each $(x_i, y_i)$, this is, a polynomial $Q$ that satisfies&lt;&#x2F;p&gt;
&lt;p&gt;$$Q(x_i, y_i) = 0 \quad \text{and} \quad \nabla_X^{m_X} \nabla_Y^{m_Y} Q(x_i, y_i) = 0$$&lt;&#x2F;p&gt;
&lt;p&gt;for all non negative integers $m_X, m_Y$ such that $m_X + m_Y &amp;lt; m$. Here, the symbol $\nabla_X^{m_X}$ stands for “take the derivative of $Q$ with respect to the variable $X$ exactly $m_X$ times”, and by that, we mean the Hasse derivative at $(x_i, y_i)$. The choice of $m$ is made to ensure that these equations form a compatible system of linear equations for the coefficients of $Q$ producing a non-trivial polynomial. This typically occurs when the number of unknowns exceeds the number of equations.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Factorization Phase:&lt;&#x2F;strong&gt; The algorithm finds factors of $Q(X,Y)$ of the form $R(X,Y) = Y - P(X)$&lt;&#x2F;p&gt;
&lt;p&gt;The vanishing of $Q$ implies then that each factor produces a word $P$ interpolating “sufficiently many” of the points inputs $(x_i, y_i)$. The number of such factors is bounded above by $D_Y = \deg_Y(Q)$, the total $Y$ degree of $Q$.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;In terms of list decoding Reed Solomon words, the GS decoder produces all the words that are close enough to the received points.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The idea in BCIKS is that since the GS decoder works for any field, the authors now instantiate the algorithm with $\mathbb{F}_q(Z)$ as basefield, and interpret a folded word $u_0(X) + Z u_1(X)$ as a Reed Solomon word in this extended setting. By appropriately choosing $m$ and $D_X$, the GS decoder produces an interpolating polynomial&lt;&#x2F;p&gt;
&lt;p&gt;$$Q(X,Y) \in \mathbb{F}_q(Z)[X,Y]$$&lt;&#x2F;p&gt;
&lt;p&gt;The coefficients of this polynomial are a priori, elements of the field $\mathbb{F}_q(Z)$, this means that the coefficients are quotients of polynomials: rational functions of $Z$. So, here comes the first feat of fine-tuning:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key Observation:&lt;&#x2F;strong&gt; By carefully looking at the rank of the interpolation matrix and an application of Cramer’s rule to non singular minor of the coefficient matrix, a non-trivial solution to the interpolation problem can be found such that its coefficients are actually polynomials in $Z$, and their degree can be tracked.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Now, we can suppose that the coefficients of $Q$ are simply polynomials in $Z$, and so we can consider&lt;&#x2F;p&gt;
&lt;p&gt;$$Q(X,Y,Z) \in \mathbb{F}_q[X,Y,Z]$$&lt;&#x2F;p&gt;
&lt;p&gt;It is in terms of the weighted degree of this polynomial that the bound for $S$ is expressed. Concretely, the authors prove that the following inequalities hold:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;$\deg_X(Q) &amp;lt; D_X = (m + \frac{1}{2})\sqrt{\rho} n$&lt;&#x2F;li&gt;
&lt;li&gt;$\deg_Y(Q) &amp;lt; \frac{D_X}{k} = \frac{(m + \frac{1}{2})}{\sqrt{\rho}}$&lt;&#x2F;li&gt;
&lt;li&gt;$\deg_{YZ}(Q) \leq \frac{(m + \frac{1}{2})^3}{6\sqrt{\rho}} n$&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;where $D_{YZ}$ is the $(0,1,1)$ weighted degree of $Q$. This measures the degree in $Z$ &lt;em&gt;after&lt;&#x2F;em&gt; substituting $Y$ for a polynomial of degree 1 in $Z$. This is a crucial quantity to look after, since it controls the vanishing of $Q$.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;In this language, the hypothesis on the lower bound of the set of “bad folds” becomes&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;$$|S| &amp;gt; 2 D_X D_Y^3 D_{YZ}$$&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;We will devote the rest of this article to making sense of this inequality, and crucially, how it is used.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;We will begin by exploiting the interpolation with multiplicity which is granted by the GS algorithm: whenever $z \in S$ we know that there’s a polynomial $P_z(X)$ with coefficients in $\mathbb{F}_q$ with $\deg_X(P_z) &amp;lt; k$ such that $Y - P_z(X)$ is a factor of $Q(X, Y, z)$. This means, that $Q(X, P_z(X), z) = 0$ and whenever $Q$ factors as $Q = A \cdot B$, then&lt;&#x2F;p&gt;
&lt;p&gt;$$A(X, P_z(X), z) = 0 \quad \text{or} \quad B(X, P_z(X), z) = 0$$&lt;&#x2F;p&gt;
&lt;p&gt;since $\mathbb{F}_q$ is a field. This allows us to concentrate on irreducible factors $\Psi \in \mathbb{F}_q[X,Y,Z]$ of $Q$; supposing&lt;&#x2F;p&gt;
&lt;p&gt;$$Q(X,Y,Z) = C(X,Z) \prod_i \Psi_i(X,Y,Z)$$&lt;&#x2F;p&gt;
&lt;p&gt;where each factor $\Psi$ is irreducible with $\deg_Y(\Psi_i) \geq 1$ and for simplicity we also assume they are &lt;em&gt;separable&lt;&#x2F;em&gt; in the $Y$ variable. Now, for each $z \in S$ we must have some factor $\Psi_i$ vanishing, and since $\deg_Y(Q) = D_Y$, there are at most $D_Y$ such factors. This implies that there must be one factor that “absorbs” at least $\frac{|S|}{D_Y}$ such points. Let $\Psi$ be such a factor.&lt;&#x2F;p&gt;
&lt;p&gt;Now the next step is finding “a good $x_0$” - this is, a good starting point in the domain $\mathcal{D}$ to characterize such a polynomial $P_z(X)$. In order to do so, it is proven that there exists an $x_0 \in \mathbb{F}_q$ such that $\Psi(x_0, Y, Z)$ is again separable in $Y$. For such a point now the dependency on $X$ disappears, and the “good factor” can now be expressed as&lt;&#x2F;p&gt;
&lt;p&gt;$$\Psi(x_0, Y, Z) = C \psi(Z) \prod_j H_{\psi,j}(Y,Z)$$&lt;&#x2F;p&gt;
&lt;p&gt;so the vanishing of $\Psi$ is translated as the vanishing of one of its factors $H$ when evaluated at $(P_z(x_0), z)$. So we will be interested in the set&lt;&#x2F;p&gt;
&lt;p&gt;$$S_{x_0, \Psi, H} = {z \in S: \Psi \text{ vanishes at } (X, P_z(X), z) \text{ and } H(P_z(x_0), z) = 0}$$&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Conceptually, this is exactly the set of $z$ such that the Implicit Function Theorem, in a finite field setting, applies. In the algebraic literature, this goes by the folk name of “Hensel lifting”. For these values of $z$, a solution $P_z(X)$ in the form of a power series with coefficients in $\mathbb{F}_q(Z)$ and powers of $(X - x_0)$ exists.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Notice that the separability of $\Psi(x_0, Y, Z)$ is typically the non-vanishing of the $Y$-derivative. Since we are interested in polynomial solutions, some of these points in $S_{x_0, \Psi, H}$ won’t work: the ones that are poles of the coefficients of the series. So, in order to guarantee this local existence of $P_z(x_0)$, we need to show that the set&lt;&#x2F;p&gt;
&lt;p&gt;$$S’ = S_{x_0, \Psi, H} - {z \in S: \text{ are poles of the coefficients present in the power series}}$$&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;is “big enough”&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The biggest source of complications comes from the set of poles - and this is so because there is no guarantee that the $H_{\psi,j}$ factor of $\Psi$ is monic: this is what produces the denominators in the coefficients of the formal power series solution around $x_0$. Dealing with this involves the theory of weight and descending to the theory of algebraic function fields (a fascinating subject a little bit far from the aims of this review).&lt;&#x2F;p&gt;
&lt;p&gt;Cutting to the chase, the hypothesis in the Correlated Agreement Theorem&lt;&#x2F;p&gt;
&lt;p&gt;$$|S| &amp;gt; 2 D_X D_Y^3 D_{YZ}$$&lt;&#x2F;p&gt;
&lt;p&gt;enables to firstly find an important lower bound for the $z$ leading to a formal power series solution:&lt;&#x2F;p&gt;
&lt;p&gt;$$|S_{x_0, \Psi, H}| \geq \frac{|S|}{D_Y} &amp;gt; 2 D_Y^2 D_X D_{YZ}$$&lt;&#x2F;p&gt;
&lt;p&gt;The authors also obtain an upper bound on the number of poles using an analogue of the Schwarz-Zippel lemma (Lemma A.1 in their appendix), which is used crucially three times in their proof.** First, to obtain an upper bound for the set of poles reading $D_Y^2 D_{YZ}$&lt;&#x2F;p&gt;
&lt;p&gt;and in turn this produces a lower bound for the number of elements in $S’$:&lt;&#x2F;p&gt;
&lt;p&gt;$$|S’| &amp;gt; |S_{x_0, \Psi, H}| - D_Y^2 D_{YZ} &amp;gt; 2 D_X D_Y^2 D_{YZ} - D_Y^2 D_{YZ} = D_Y^2 D_{YZ}(2D_X - 1)$$&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Secondly, this lower bound is exactly what the Schwarz-Zippel lemma demands to guarantee polynomial solutions of degree at most $k$ in $X$; then again it is used to guarantee (together with the Fundamental Theorem of Algebra) that the degree in $Z$ of the solution is at most 1&lt;&#x2F;strong&gt; and so&lt;&#x2F;p&gt;
&lt;p&gt;$$P(X,Z) = V_0(X) + Z V_1(X)$$&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;produces the promised Reed-Solomon words $v_0$ and $v_1$ and this concludes the path set in BCIKS.&lt;&#x2F;p&gt;
&lt;p&gt;In the recent BCHKS25, two improvements are made: first of all, a tighter linear algebra argument is carried on at the Cramer Rule level, producing an interpolating polynomial $Q$ with a smaller $D_{YZ}$:&lt;&#x2F;p&gt;
&lt;p&gt;$$D_{YZ} \leq \frac{1}{3}(m + \frac{1}{2})^2 \frac{n}{k}$$&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;now the choice of $m$ is bound to be $m \geq 3$ and still allows some optimization. Second, in carrying out the very same analysis of BCIKS20, a closer look at the set $S_{x_0, \Psi, H}$ yields a smaller lower bound for $S$ while keeping the use of the Schwarz-Zippel lemma for algebraic function fields. What happens is that in the original paper, &lt;strong&gt;lower bounds on this set are established in terms of the weighted degree bounds of $Q$, while the set is defined in terms of a factor of $Q$.&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Before continuing, let’s set:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;$D_Y^{\Psi_i} = \deg_Y(\Psi_i)$&lt;&#x2F;li&gt;
&lt;li&gt;$D_Y^{H_{i,j}} \equiv D_Y^{H_{\psi_i,j}} = \deg_Y(H_{\psi_i,j})$&lt;&#x2F;li&gt;
&lt;li&gt;$D_Z^{\Psi_i} = \deg_{YZ}(\Psi_i) - \deg_Z(C_i)$ - the weighted $(1,1)$ degree of the part of $\Psi_i$ that does not include the pure $Z$ factor.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;since we’re going to use these quantities to bound the size of the sets $S_{x_0, \Psi_i, H_{ij}}$. Now the authors prove that there exists a pair of factors $\Psi_i, H_{ij}$ such that&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;$|S_{x_0, \Psi_i, H_{ij}}| \geq 2 D_X D_Y^{\Psi_i} D_Y^{H_{ij}} D_Z^{\Psi_i}$&lt;&#x2F;li&gt;
&lt;li&gt;$|S_{x_0, \Psi_i, H_{ij}}| &amp;gt; D_Y^{\Psi_i} D_Y^{H_{ij}} D_Z^{\Psi_i} + \delta n + 1$&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;both hold simultaneously; if these inequalities fail to hold for all possible pairs, then the fact that the sets $S_{x_0, \Psi_i, H_{ij}}$ form a partition of $S$ implies that by summing over all possible factors, we achieve&lt;&#x2F;p&gt;
&lt;p&gt;$$|S| \leq 2 D_X D_Y^2 D_{YZ} + (\delta n + 1) D_Y$$&lt;&#x2F;p&gt;
&lt;p&gt;This last inequality is obtained by formally summing and using the additivity of degrees when factoring a polynomial (this is what makes the funny degree notation above disappear and lets the degrees of $Q$ finally pop up); details are present in section 3 of BCHKS25.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What this result is saying is that whenever $|S| &amp;gt; 2 D_X D_Y^2 D_{YZ} + (\delta n + 1) D_Y$, a polynomial of adequate degrees in $X$ and $Z$ can be found from Hensel Lifting, producing the promised Reed-Solomon words that appear in the conclusion of the Correlated Agreement.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The last part of this analysis amounts to taking a look at the bound for $S$ employing the improved weighted degree bounds for $Q$; by losing the linear part in $D_Y$, we obtain&lt;&#x2F;p&gt;
&lt;p&gt;$$|S| &amp;gt; 2 D_X D_Y^2 D_{YZ} &amp;gt; 2(m + \frac{1}{2})\sqrt{nk} \cdot \left((m + \frac{1}{2})\frac{n}{k}\right)^2 \cdot \frac{1}{3}(m + \frac{1}{2})\frac{n}{k}$$&lt;&#x2F;p&gt;
&lt;p&gt;and since the rate of the code is defined as $\rho = \frac{k}{n}$, we obtain&lt;&#x2F;p&gt;
&lt;p&gt;$$|S| &amp;gt; \frac{2}{3}(m + \frac{1}{2})^5 \sqrt{nk} \frac{n}{k} \frac{n}{k} = \frac{2}{3} \frac{(m + \frac{1}{2})^5}{\rho^{3&#x2F;2}} \cdot n$$&lt;&#x2F;p&gt;
&lt;p&gt;which is pretty much the promised improvement against the former known bound&lt;&#x2F;p&gt;
&lt;p&gt;$$|S| &amp;gt; \frac{(m + \frac{1}{2})^7}{3\rho^{3&#x2F;2}} \cdot n^2$$&lt;&#x2F;p&gt;
&lt;p&gt;To finally land on our feet, what this discussion has been about: if for sufficiently many $z$ the words $u_0(X) + z u_1(X)$ are $\delta$ close to the code, then an Implicit Function argument produces Reed-Solomon codewords $v_0(X), v_1(X)$ which are $\delta$-close to the original words (where all this runs on the choice of $\delta$ and the parameters of the Reed-Solomon code). So the chances for a malicious prover to cheat the verifier are indeed slim, namely linear in the size of the evaluation domain $\mathcal{D}$.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Ethereum is the new financial backend of the world</title>
          <pubDate>Thu, 11 Dec 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/ethereum-is-the-new-financial-backend-of-the-world/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/ethereum-is-the-new-financial-backend-of-the-world/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/ethereum-is-the-new-financial-backend-of-the-world/">&lt;h4 id=&quot;by-federico-carrone-and-roberto-catalan&quot;&gt;By Federico Carrone and Roberto Catalan&lt;&#x2F;h4&gt;
&lt;p&gt;Ethereum is emerging as a general purpose financial backend that reduces the cost and complexity of building financial services while improving their speed and security. For decades the internet accelerated communication but did not create a neutral system for defining ownership or enforcing obligations. Economic activity moved online without the accompanying machinery of rights, records, and jurisdiction. Ethereum fills this gap by embedding these functions in software and enforcing them through a distributed validator set.&lt;&#x2F;p&gt;
&lt;p&gt;Markets depend on property rights, and property rights depend on reliable systems for recording ownership, supporting transfer, and enforcing obligations. Prices then communicate scarcity and preference, enabling coordination at scale. Technological progress has repeatedly lowered the cost of transmitting information and synchronizing action. Ethereum extends this pattern by lowering the cost of establishing and verifying ownership across borders.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;from-internet-native-to-global-infrastructure&quot;&gt;From internet native to global infrastructure&lt;&#x2F;h2&gt;
&lt;p&gt;Ethereum’s early innovation was the introduction of programmable digital assets with defined economic properties. Issuers could establish monetary rules, engineer scarcity, and integrate assets into applications. Before Ethereum, such experimentation required constructing a network and persuading others to secure it, a process limited to technically sophisticated groups. Ethereum replaced infrastructure duplication with shared security and a general purpose environment, turning issuance from a capital intensive undertaking into a software driven activity.&lt;&#x2F;p&gt;
&lt;p&gt;The more consequential development has been the recognition that Ethereum can reconstruct traditional financial services in a form that is more transparent and less operationally burdensome. Financial institutions devote substantial resources to authorization, accounting, monitoring, dispute resolution, and reporting. Consumer interfaces sit atop complex internal systems designed to prevent error and misconduct. Ethereum substitutes a portion of this apparatus with a shared ledger, a programmable execution environment, and cryptographic enforcement. Administrative complexity is reduced because core functions are delegated to software rather than replicated within each institution.&lt;&#x2F;p&gt;
&lt;p&gt;Ethereum reduces that burden by providing a shared ledger with real time updates, a programmable space for defining rules, and cryptographic enforcement. It does not remove institutions but changes which parts of the financial stack they must build themselves. Issuance becomes simpler, custody more secure, and administration less dependent on proprietary infrastructure.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;software-trust-and-the-reduction-of-friction&quot;&gt;Software, trust and the reduction of friction&lt;&#x2F;h2&gt;
&lt;p&gt;Some economists describe transaction costs through three frictions: triangulation, transfer and trust. Triangulation concerns how economic actors identify each other and agree on terms. Transfer concerns how value moves between them. Trust concerns the enforcement of obligations. Traditional financial architecture manages these frictions through scale, proprietary systems, and coordination among intermediaries.&lt;&#x2F;p&gt;
&lt;p&gt;Ethereum remove middlemen and therefore lowers the three frictions enumerated before. Open marketplaces support discovery of assets and prices. Digital value can settle globally within minutes without the layers of correspondent banking. Obligations can be executed automatically and verified publicly. These capabilities do not eliminate institutional functions but shift part of the work from organizations to software, reducing cost and operational risk.&lt;&#x2F;p&gt;
&lt;p&gt;New entrants benefit immediately. They can rely on infrastructure maintained by thousands of engineers rather than building their own systems for settlement, custody, and enforcement. Business logic becomes code. Obligations can be automated. Settlement becomes immediate. Users retain custody. This expands the range of viable business models and allows firms to serve markets that incumbents consider too small or too complex.&lt;&#x2F;p&gt;
&lt;p&gt;Having a single global ledger also changes operational dynamics. Many institutions operate multiple databases that require frequent reconciliation and remain vulnerable to error. Ethereum maintains a continuously updated and replicated record that cannot be amended retroactively. Redundancy and recoverability become default properties rather than costly internal functions.&lt;&#x2F;p&gt;
&lt;p&gt;Security follows the same pattern. Instead of defending a central database, Ethereum distributes verification among many independent actors. Altering history requires coordination at scale and becomes prohibitively expensive. Confidence arises from system design rather than institutional promises.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;new-financial-services-and-global-reach&quot;&gt;New financial services and global reach&lt;&#x2F;h2&gt;
&lt;p&gt;These features enable services that resemble established financial activities but operate with different cost structures. International transfers can use digital dollars rather than correspondent networks. Loans can enforce collateral rules in code. Local payment systems can interoperate without proprietary standards. Individuals in unstable economies can store value in digital instruments independent of local monetary fragility.&lt;&#x2F;p&gt;
&lt;p&gt;Clearing, custody, reconciliation, monitoring, and enforcement shift from organizational processes into shared software. Companies can focus on product design and distribution rather than maintaining complex internal infrastructure. Scale is achieved by acquiring users, because infrastructure is shared. Value accrues to applications rather than to duplicated internal systems.&lt;&#x2F;p&gt;
&lt;p&gt;The impact is most visible in markets with fragile financial systems. In economies with unstable currencies or slow payment networks, Ethereum provides immediate functional gains. In developed markets the benefits appear incremental but accumulate as more instruments and processes become programmable.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;institutional-transformation-and-long-term-dynamics&quot;&gt;Institutional transformation and long term dynamics&lt;&#x2F;h2&gt;
&lt;p&gt;Many financial instruments are heterogeneous. Corporate debt is a clear example. Terms differ by maturity, coupon, covenants, collateral, and risk. Trading depends on bilateral negotiation and intermediaries who maintain records and enforce obligations. Ethereum can represent these instruments digitally, track ownership, and execute terms automatically. Contracts retain their specificity, while administration becomes standardized and interoperable.&lt;&#x2F;p&gt;
&lt;p&gt;This suggests a shift in institutional architecture. Regulation and legal systems remain central, but the boundary between what firms must build and what software can enforce changes. Institutions evolve from infrastructure providers to service designers. Cost structures diverge between firms that maintain legacy systems and those that rely on shared infrastructure.&lt;&#x2F;p&gt;
&lt;p&gt;Ethereum already functions as an alternative financial rail. Its reliability, the presence of multiple independently developed clients, substantial real world usage, active research community, and commitment to openness and verification distinguish it from other blockchain networks. These qualities align with the requirements of durable financial infrastructure.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;Ethereum converts core financial frictions into software functions. This changes the economics of building and operating financial services. Talent and capital shift from operations to innovation in product design. Institutions become lighter and more focused. Those who will adopt Ethereum will have lower costs of operation and will have a head start against competitors.&lt;&#x2F;p&gt;
&lt;p&gt;Technological transitions begin in niches where incumbents do not meet demand. As systems mature, costs fall and broader adoption becomes feasible. Ethereum followed this path. It began with internet native communities, expanded across emerging markets where users lacked reliable financial tools, and is now positioned to upgrade mainstream markets by making financial companies easier to create and operate.&lt;&#x2F;p&gt;
&lt;p&gt;The broader implication is that software is becoming the organizing principle of financial infrastructure. Ethereum makes this shift concrete. Whether it becomes foundational will depend on regulation and institutional adaptation, but the economic incentives are increasingly aligned with systems that are open, verifiable, and resilient.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>The missing institution of the Internet: Ethereum</title>
          <pubDate>Tue, 02 Dec 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/the-missing-institution-of-the-internet-ethereum/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/the-missing-institution-of-the-internet-ethereum/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/the-missing-institution-of-the-internet-ethereum/">&lt;p&gt;Modern economic systems rest on two foundations: tools that expand productive capacity and institutions that define who controls their output. The internet transformed how information moves, but it did not reconstruct the institutional machinery that governs ownership and exchange. Digital economic life therefore expanded without a durable system of rights, enforcement, or jurisdiction. Blockchain networks, and Ethereum in particular, address this gap by embedding institutional functions in software and enforcing them through economic incentives and cryptographic verification.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;technology-culture-and-institutional-design&quot;&gt;Technology, Culture and Institutional Design&lt;&#x2F;h2&gt;
&lt;p&gt;In most species, behavior is shaped by biology and fixed through genetic inheritance. Humans diverged by inventing technologies that alter their environment more rapidly than biological evolution can adapt to it. Fire, agriculture, medicine and computing enabled a physically vulnerable species to extend its productive frontiers.&lt;&#x2F;p&gt;
&lt;p&gt;Equally significant was the emergence of institutions that facilitated cooperation beyond small groups. Human societies are organized not through inherited instinct but through constructed systems of norms, laws and symbolic abstractions that can be revised in response to changing conditions. Cultural evolution permits continuous redesign and operates on a faster timescale than genetic change.&lt;&#x2F;p&gt;
&lt;p&gt;This dual process, technological augmentation and institutional invention, generated compounding effects. Tools expanded individual capacity and institutions aggregated that capacity into collective action. Property rights, contracts, markets and corporate entities emerged as mechanisms to coordinate behavior at scale by defining entitlements and aligning incentives.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;property-rights-and-markets-as-social-technologies&quot;&gt;Property Rights and Markets as Social Technologies&lt;&#x2F;h2&gt;
&lt;p&gt;Economic development depends not only on productive capability but on credible commitments. Individuals and firms invest when they can expect to benefit from their efforts and be protected from arbitrary interference. Property rights provide that assurance by specifying ownership, use and exclusion. Markets, layered on top of these rights, coordinate production and exchange by allocating resources through price signals.&lt;&#x2F;p&gt;
&lt;p&gt;These arrangements are often treated as natural features of economic life. They are engineered agreements constructed through law and political settlement. Their value lies in enabling investment, specialization and trade under uncertainty. Prices, money and contracts compress information about scarcity, preferences and risk, enabling production to be coordinated across large populations without centralized direction.&lt;&#x2F;p&gt;
&lt;p&gt;The global expansion of trade in the twentieth century reflected these institutional foundations. Specialization increased productivity and interdependence reduced conflict by raising the cost of disruption. Innovations such as neutral jurisdictions and corporate structures enabled strangers to transact under shared rules. Legal entities functioned as containers that allowed participants from different regulatory environments to collaborate.&lt;&#x2F;p&gt;
&lt;p&gt;This infrastructure, whether admired or criticized, underwrote the international economic order of the late twentieth century.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-missing-architecture-of-digital-ownership&quot;&gt;The Missing Architecture of Digital Ownership&lt;&#x2F;h2&gt;
&lt;p&gt;The internet lowered the cost of communication and commerce across borders, but it did not establish a neutral mechanism for defining and enforcing claims on digital assets. Offline, ownership is adjudicated by courts, enforced by states and geographically bounded. Online, in the absence of a global authority, ownership defaults to either national legal systems or to the platforms that mediate activity.&lt;&#x2F;p&gt;
&lt;p&gt;Corporations filled this vacuum by providing infrastructure for identity, communication and exchange. They set terms of access, mediate transactions and retain discretionary control over assets generated within their systems. Users and firms may create content, build businesses and accumulate value, but their rights are contingent on the policies of the platform operator.&lt;&#x2F;p&gt;
&lt;p&gt;The experience of Zynga illustrates this dynamic. The company developed a profitable games business on Facebook and briefly achieved a valuation exceeding that of Electronic Arts. Its fortunes deteriorated when Facebook revised its policies and altered its revenue share. Zynga owned its intellectual property and its infrastructure but not the environment on which its business model depended, a common position for firms built on platform economies. In digital markets, platforms function as de facto landlords.&lt;&#x2F;p&gt;
&lt;p&gt;This is not an isolated case but a structural feature of platform centered economies: extensive participation paired with limited control.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ethereum-as-an-institutional-experiment&quot;&gt;Ethereum as an Institutional Experiment&lt;&#x2F;h2&gt;
&lt;p&gt;Ethereum is a response to this institutional absence. It provides a mechanism for creating, transferring and enforcing digital assets without reliance on corporate or national intermediaries. The system operates as a verifiable computing environment in which rules are encoded in software and enforced collectively by a distributed network.&lt;&#x2F;p&gt;
&lt;p&gt;Traditional computing systems require users to trust the operator. Ethereum distributes computation across thousands of machines that execute identical code and verify each other in a continuous process. Outputs are accepted when consensus is reached and misbehavior is economically penalized. Under these conditions, property rights and contractual commitments can be represented as digital objects whose enforcement does not depend on courts or discretionary authority.&lt;&#x2F;p&gt;
&lt;p&gt;This architecture automates functions normally performed by institutions. Auditors repeat financial records to detect manipulation. Courts resolve disputes. Regulators impose compliance standards. These systems are essential but costly and slow. Ethereum replicates aspects of verification and enforcement at the system level using software, mathematics and economic incentives.&lt;&#x2F;p&gt;
&lt;p&gt;The network is open to participation without authorization and resistant to censorship because no single entity can unilaterally block or rewrite transactions. These properties arise from the structure of the system rather than ideological intent.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-emergence-of-a-digital-financial-system&quot;&gt;The Emergence of a Digital Financial System&lt;&#x2F;h2&gt;
&lt;p&gt;The first adopters of Ethereum were technologists experimenting with new mechanisms for ownership and coordination. Most of the culture and products were created for themselves. Over time, a broader range of actors began using the system for financial services.&lt;&#x2F;p&gt;
&lt;p&gt;The most consequential development has been the rise of stablecoins, digital representations of fiat currency backed by real world assets. Their combined market capitalization exceeds three hundred billion dollars, with a majority circulating on Ethereum. Transaction volumes on blockchain networks now approach those processed by major payment systems.&lt;&#x2F;p&gt;
&lt;p&gt;Stablecoins replicate core financial functions such as store of value and transfer of funds without geographic restrictions and with continuous settlement. Their programmability enabled the construction of lending protocols that allow users to lend and borrow assets with risk parameters enforced in software rather than through institutional mediation.&lt;&#x2F;p&gt;
&lt;p&gt;These systems differ from traditional financial infrastructure. Participation is global rather than jurisdictional. Switching costs are low because services are built on interoperable standards. Exit is immediate. Risk is transparent though often misunderstood.&lt;&#x2F;p&gt;
&lt;p&gt;Compare that to countries like Argentina, where interoperability between banks and fintech wallets, something as trivial as scanning a QR code, is still an ongoing regulatory battle. Incumbents try to use their market position to avoid being interoperable. On Ethereum, interoperability is structural. Individuals can receive payment, convert assets, provide liquidity and borrow collateralized funds within minutes from a mobile device. In legacy systems, similar transactions take days and incur high fees. Adoption reflects demand for neutral infrastructure in environments where intermediation is unreliable.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;implications&quot;&gt;Implications&lt;&#x2F;h2&gt;
&lt;p&gt;Several areas of financial activity are migrating to blockchain based systems, including remittances, trade finance and private credit. Others, such as corporate debt markets, remain fragmented and costly but exhibit characteristics that may make them suitable for digital reconstruction on top of Ethereum.&lt;&#x2F;p&gt;
&lt;p&gt;Significant obstacles remain. Regulatory uncertainty, operational risk and user experience challenges constrain adoption. Scaling transaction throughput without compromising decentralization is an engineering problem that has not been solved conclusively. Software vulnerabilities and governance failures present meaningful risk.&lt;&#x2F;p&gt;
&lt;p&gt;These challenges appear tractable. Early evidence suggests that elements of financial intermediation can be automated at lower cost and with greater transparency than existing systems. The trajectory of adoption will depend on institutional responses as much as technical progress.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;artificial-intelligence-and-coordination&quot;&gt;Artificial Intelligence and Coordination&lt;&#x2F;h2&gt;
&lt;p&gt;Artificial intelligence increases productive capacity by automating tasks but does not resolve questions of ownership, governance or compliance. Output may be generated more efficiently, but disputes over entitlement, liability and compensation persist.&lt;&#x2F;p&gt;
&lt;p&gt;Artificial intelligence and blockchains, but in particular Ethereum, are the two biggest innovations in the decades to come. The two technologies solve concrete core primitives of humans: productivity gains and coordination. Artificial intelligence will make people more productive, but it will not eliminate the bureaucratic machinery required to verify and enforce outcomes. Ethereum introduces a technology that complements AI: a system where humans and autonomous agents can coordinate, trade, and settle disputes directly through code, without relying on institutions to prove that everyone followed the rules.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;The internet lowered the cost of transmitting information but did not create institutions for defining and enforcing rights over digital assets. The result has been an economy coordinated by private platforms rather than neutral systems of governance. Ethereum reconstructs elements of property rights and contractual enforcement as public infrastructure encoded in software.&lt;&#x2F;p&gt;
&lt;p&gt;Whether such systems become core infrastructure or remain specialized instruments will depend on institutional adaptation, regulation and technological progress. They have already demonstrated an alternative cost structure for financial coordination and introduced mechanisms for digital property that do not rely on centralized administration.&lt;&#x2F;p&gt;
&lt;p&gt;The internet built an economy without institutions. Ethereum is an attempt to build them.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Speeding up sumcheck for Ethereum&#x27;s Lean zkVM: an in-depth walkthrough of our implementation</title>
          <pubDate>Fri, 28 Nov 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/speeding-up-sumcheck-an-in-depth-walkthrough-of-our-implementation/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/speeding-up-sumcheck-an-in-depth-walkthrough-of-our-implementation/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/speeding-up-sumcheck-an-in-depth-walkthrough-of-our-implementation/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;In this post, we’ll present an in-depth walkthrough of our implementation of the sumcheck optimizations proposed by Bagad, Dao, Domb, and Thaler (BDDT) in their &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2025&#x2F;1117&quot;&gt;paper&lt;&#x2F;a&gt;. In previous posts, we’ve explained the main theoretical ideas (see &lt;a href=&quot;&#x2F;optimizing-sumcheck&#x2F;&quot;&gt;part I&lt;&#x2F;a&gt; and &lt;a href=&quot;&#x2F;how-factoring-equality-polynomials-optimizes-sumcheck&#x2F;&quot;&gt;part II&lt;&#x2F;a&gt;). Here, we dive deep into the implementation details, showing exactly how we implemented &lt;em&gt;Algorithm 6&lt;&#x2F;em&gt; from that paper within the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tcoratger&#x2F;whir-p3&quot;&gt;whir-p3&lt;&#x2F;a&gt; repository.&lt;&#x2F;p&gt;
&lt;p&gt;This work was motivated by the Lean Ethereum team, which uses Whirlaway, a multilinear protocol that relies on Whir as its Polynomial Commitment Scheme (PCS). The team identified that the sumcheck protocol could benefit from existing optimizations (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tcoratger&#x2F;whir-p3&#x2F;issues&#x2F;280&quot;&gt;see issue #280&lt;&#x2F;a&gt;). To address this, we stepped in to implement the BDDT optimizations in their codebase.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;&#x2F;strong&gt; The code snippets presented in this post correspond to the implementation merged in this &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tcoratger&#x2F;whir-p3&#x2F;pull&#x2F;322&quot;&gt;PR&lt;&#x2F;a&gt;. While the whir-p3 repository is under active and constant development, we have chosen to analyze this specific snapshot because it offers the highest didactic clarity. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;whir-p3&#x2F;tree&#x2F;eec71d03a5ec81f30acc6d591f42f318941c6df5&quot;&gt;This version&lt;&#x2F;a&gt; — which you can find in our repository fork — maintains a faithful one-to-one mapping with the theoretical concepts of the BDDT paper, making it the ideal reference for understanding the core logic before further engineering optimizations are applied.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;i-the-core-idea-delaying-expensive-field-arithmetic&quot;&gt;I. The Core Idea: Delaying Expensive Field Arithmetic&lt;&#x2F;h2&gt;
&lt;p&gt;The naive sumcheck prover forces expensive extension field arithmetic too early. The goal of the BDDT optimizations is simple: &lt;strong&gt;delay the introduction of extension field operations as long as possible&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;extension-field-computation&quot;&gt;Extension Field Computation&lt;&#x2F;h3&gt;
&lt;p&gt;In systems like Jolt (which motivated the paper) or Whir, the underlying computation (e.g., an execution trace) operates over small base field values—32-bit or 64-bit integers. However, cryptographic security requires the sumcheck protocol to use extension field random challenges. In our implementation, we work with base fields like &lt;em&gt;Baby Bear&lt;&#x2F;em&gt; (31-bit), &lt;em&gt;Koala Bear&lt;&#x2F;em&gt; , or &lt;em&gt;Goldilocks&lt;&#x2F;em&gt; (64-bit), along with their extensions (e.g., &lt;code&gt;BinomialExtensionField&amp;lt;BabyBear, 4&amp;gt;&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;The performance gap between these operations is dramatic. The BDDT paper introduces a precise cost model:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **𝔰𝔰 (small-small)** : Multiplying two base field elements, e.g., `BabyBear * BabyBear`. This is the fastest—just a single base field multiplication.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **𝔰𝔩 (small-large)** : Multiplying a base field element by an extension field element, e.g., `BabyBear * BinomialExtensionField&amp;lt;BabyBear, 4&amp;gt;` requires 4 base field multiplications (one per extension coefficient).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **𝔩𝔩 (large-large)** : Multiplying two extension field elements, e.g., `BinomialExtensionField&amp;lt;BabyBear, 4&amp;gt; * BinomialExtensionField&amp;lt;BabyBear, 4&amp;gt;` is dramatically slower, requiring 16 base field multiplications plus additional operations—often an order of magnitude slower than 𝔰𝔰.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;the-cost-problem&quot;&gt;The Cost Problem&lt;&#x2F;h3&gt;
&lt;p&gt;The naive (or classical) sumcheck prover (&lt;em&gt;Algorithm 1&lt;&#x2F;em&gt; in the paper) suffers from premature extension field propagation:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Round 1** : The prover computes sums of products of base field values—all cheap 𝔰𝔰 operations.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Round 2 onward** : The verifier sends a random challenge $r_1 \in \mathbb{F_{\text{ext}}}$, an extension field element. This forces all subsequent computations to use extension field arithmetic. From this point on, the prover must perform expensive 𝔩𝔩 operations for all remaining rounds.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;The key insight:&lt;&#x2F;strong&gt; Delay this transition as long as possible. It is better to perform more operations, but in the base field. That’s the whole idea.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ii-the-two-optimizations-svo-and-eq-poly&quot;&gt;II. The Two Optimizations: SVO and Eq-Poly&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;em&gt;Algorithm 6&lt;&#x2F;em&gt; synthesizes two complementary optimizations. Understanding each in isolation clarifies how they work together.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;a-small-value-optimization-svo&quot;&gt;A. Small Value Optimization (SVO)&lt;&#x2F;h3&gt;
&lt;p&gt;The Small Value Optimization (&lt;em&gt;Algorithm 4&lt;&#x2F;em&gt;) is a computational strategy: &lt;strong&gt;to delay extension field operations&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;A naive approach (&lt;em&gt;Algorithm 3&lt;&#x2F;em&gt;) would expand the polynomial into $\mathcal{O}( 2^{ d \cdot \ell_0})$ terms to keep base field and extension field components separated. This is exponentially expensive and infeasible for practical values.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;The SVO insight:&lt;&#x2F;strong&gt; Use &lt;strong&gt;Lagrange Interpolation&lt;&#x2F;strong&gt; instead of expansion. This is the same principle behind Toom-Cook multiplication. By treating the round polynomial as something to be interpolated (from a small number of evaluation points) rather than expanded (into exponentially many monomials), we reduce precomputation cost from $\mathcal{O} (2^{ d \cdot \ell_0})$ to $\mathcal{O}(( d + 1)^{ \ell_0})$.&lt;&#x2F;p&gt;
&lt;p&gt;You can see &lt;a href=&quot;&#x2F;optimizing-sumcheck&#x2F;&quot;&gt;part I&lt;&#x2F;a&gt; of our series for the intuition behind this optimization.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;b-eq-poly-optimization-algorithm-5&quot;&gt;B. Eq-Poly Optimization (Algorithm 5)&lt;&#x2F;h3&gt;
&lt;p&gt;The second optimization (&lt;em&gt;Algorithm 5&lt;&#x2F;em&gt;) addresses the specific case&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
g(X) = \mathrm{eq}(w, X)p(X).&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;It is based on Gruen’s optimization, and the idea is to reduce 𝔩𝔩 multiplications associated with the $\mathrm{eq}$ polynomial.&lt;&#x2F;p&gt;
&lt;p&gt;Instead of summing over all remaining variables at once, the algorithm “splits the sum” into two halves.&lt;&#x2F;p&gt;
&lt;p&gt;See &lt;a href=&quot;&#x2F;how-factoring-equality-polynomials-optimizes-sumcheck&#x2F;&quot;&gt;part II&lt;&#x2F;a&gt; of our series for the full explanation.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;iii-the-protocol-architecture-two-phase-strategy&quot;&gt;III. The Protocol Architecture: Two-Phase Strategy&lt;&#x2F;h2&gt;
&lt;p&gt;Our implementation is essentially encapsulated within the function &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;whir-p3&#x2F;blob&#x2F;eec71d03a5ec81f30acc6d591f42f318941c6df5&#x2F;src&#x2F;sumcheck&#x2F;sumcheck_single_svo.rs#L22&quot;&gt;&lt;code&gt;from_base_evals_svo&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, which is called by the prover to execute the sumcheck protocol following &lt;em&gt;Algorithm 6&lt;&#x2F;em&gt;. It combines both SVO and Eq-Poly optimization. In our implementation, we chose:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $\ell_0 = 3$: We just do three SVO rounds since this optimization is efficient only for a few rounds, as we&amp;#39;ll explain in detail later on.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $d = 1$: We only accept one multilinear polynomial, instead of a product of polynomials as shown in the BDDT paper. This choice is due to the fact that in the use case that interests us (that is, in the context of Whir) we only have one polynomial.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Given the base field evaluations of the multilinear polynomial $p$ on the hypercube (&lt;code&gt;evals&lt;&#x2F;code&gt;) and an eq-poly constraint (&lt;code&gt;constraint&lt;&#x2F;code&gt;), it applies a certain number of sumcheck rounds (&lt;code&gt;folding_factor&lt;&#x2F;code&gt;), returning a new &lt;code&gt;SumcheckSingle&lt;&#x2F;code&gt; and the challenges used.&lt;&#x2F;p&gt;
&lt;p&gt;It is important to point out that this implementation is designed for a &lt;code&gt;folding_factor&lt;&#x2F;code&gt; greater than 5 and a &lt;code&gt;constraint&lt;&#x2F;code&gt; containing only &lt;strong&gt;one equality statement&lt;&#x2F;strong&gt; , since we want to use Whir as a PCS.&lt;&#x2F;p&gt;
&lt;p&gt;So, the goal of this function is to prove an equality constraint&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\sigma = p(w),&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;where we can rewrite the evaluation as a sum:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
p(w) = \sum_{x \in \{0, 1\}^\ell} \mathrm{eq}(w, x) p(x).&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;The core insight of this algorithm: &lt;strong&gt;use different strategies for different phases&lt;&#x2F;strong&gt;. Here’s the high-level structure:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; Run a Sumcheck prover following Algorithm 6.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn from_base_evals_svo&amp;lt;Challenger&amp;gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    evals: &amp;amp;EvaluationsList&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    prover_state: &amp;amp;mut ProverState&amp;lt;F, EF, Challenger&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    folding_factor: usize,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pow_bits: usize,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    constraint: &amp;amp;Constraint&amp;lt;F, EF&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; (Self, MultilinearPoint&amp;lt;EF&amp;gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut challenges = Vec::with_capacity(folding_factor);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Here we are assuming the equality statement has only one constraint.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut sum = constraint.eq_statement.evaluations[0];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let w = &amp;amp;constraint.eq_statement.points[0];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Create the unified equality polynomial evaluator&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut eq_poly = SumcheckEqState::&amp;lt;_, NUM_SVO_ROUNDS&amp;gt;::new(w);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; --- PHASE 1: SVO for first 3 rounds ---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let (r_1, r_2, r_3) = svo_three_rounds(prover_state, evals, w, &amp;amp;mut sum, pow_bits);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    challenges.extend([r_1, r_2, r_3]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; --- THE SWITCHOVER: Fold polynomial with the 3 challenges ---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; We fold to obtain p(r1, r2, r3, x).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut folded_evals = fold_evals_with_challenges(evals, &amp;amp;challenges);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; --- PHASE 2: Algorithm 5 for remaining rounds ---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    algorithm_5(prover_state, &amp;amp;mut folded_evals, w, &amp;amp;mut challenges, &amp;amp;mut sum, pow_bits);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let challenge_point = MultilinearPoint::new(challenges);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Final weight: eq(w, r)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let weights = EvaluationsList::new(vec![w.eq_poly(&amp;amp;challenge_point)]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let sumcheck = Self::new(folded_evals, weights, sum);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    (sumcheck, challenge_point)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let’s explain each phase in detail.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;iv-phase-1-the-first-three-rounds&quot;&gt;IV. Phase 1: The First Three Rounds&lt;&#x2F;h2&gt;
&lt;p&gt;The first three sumcheck rounds are implemented by &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;whir-p3&#x2F;blob&#x2F;eec71d03a5ec81f30acc6d591f42f318941c6df5&#x2F;src&#x2F;sumcheck&#x2F;sumcheck_small_value.rs#L220&quot;&gt;&lt;code&gt;svo_three_rounds&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;. In each round $i$, the prover needs to:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Compute the univariate polynomial evaluations $S_i (0)$ and $S_i (\infty)$ (i.e., the leading coefficient).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Add these evaluations to the prover state.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Sample a new challenge $r_i$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Fold the polynomial $p$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Update the claimed sum $\sigma$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The only heavy step is the first one. We want the prover to compute $S_i$ efficiently. That is where SVO comes into play.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;factoring-the-univariate-round-polynomial&quot;&gt;Factoring the Univariate Round Polynomial&lt;&#x2F;h3&gt;
&lt;p&gt;Recall that the claimed sum we want to prove is:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\sigma = p(w) = \sum_{x \in \{0, 1\}^\ell} \mathrm{eq}(w, x) p(x).&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;Then, for each round $i$, the prover needs to compute the univariate round polynomial $S_i (u)$ where:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
S_i(u) = \sum_{x \in \{0, 1\}^{ \ell - i}} \mathrm{eq} \bigl(w_{[1, i -1]} ; r_{[1, i - 1]}, u, x\bigr) \cdot p(r_{[1, i - 1]}, u, x).&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;Splitting the eq-poly, we can factorize $S_i$ in the following way, with $\ell$ the easy part and $t$ the hard part:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\begin{aligned}&lt;br &#x2F;&gt;
S_i(u) &amp;amp;= \ell_i(u) t_i(u), \newline&lt;br &#x2F;&gt;
\ell_i(u) &amp;amp;=&lt;br &#x2F;&gt;
\mathrm{eq}\bigl(w_{[1,i - 1]} ; r_{[1,i - 1]}\bigr)&lt;br &#x2F;&gt;
\mathrm{eq}(w_i; u), \newline&lt;br &#x2F;&gt;
t_i(u) &amp;amp;=&lt;br &#x2F;&gt;
\sum_{x \in \{0,1 \}^{\ell - i}}&lt;br &#x2F;&gt;
\mathrm{eq}\bigl(w_{[i+1,\ell]}; x\bigr)&lt;br &#x2F;&gt;
p(r_{[1,i - 1]}, u, x).&lt;br &#x2F;&gt;
\end{aligned}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;where:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $\ell_i(u)$ is the **linear part** : it comes from the eq-poly portion for variables $1$ to $i$. This is a linear polynomial in $u$ and is easy to compute.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $t_i(u)$ is the **heavy part** : it incorporates the sum over all remaining variables $x$ as well as the polynomial $p$. This is where all the complexity lives.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note that computing $\ell_i (0)$ and $\ell_i(1)$ is essentially “free”, but computing $t_i(0)$ and $t_i(1)$ naively would require summing over exponentially many terms. That’s where &lt;strong&gt;accumulators&lt;&#x2F;strong&gt; come in.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;accumulator-computation-procedure-9&quot;&gt;Accumulator Computation (Procedure 9)&lt;&#x2F;h3&gt;
&lt;p&gt;The “heavy part” $t_i (u)$ is where SVO (&lt;em&gt;Algorithm 4&lt;&#x2F;em&gt;) and Eq-Poly (&lt;em&gt;Algorithm 5&lt;&#x2F;em&gt;) combine. We apply the Toom-Cook insight by using Lagrange interpolation on the challenges $r_{[1, i - 1]}$ and the sum-splitting insight on the remaining variables $x$.&lt;&#x2F;p&gt;
&lt;p&gt;This gives us the reformulation of $t_i(u)$ in terms of the precomputed accumulators $A_i(v, u)$:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
t_i(u) =&lt;br &#x2F;&gt;
\sum_{v \in \{0, 1\}^{i - 1}}&lt;br &#x2F;&gt;
L_v(r_{[1, i - 1]}) \cdot&lt;br &#x2F;&gt;
\underbrace{&lt;br &#x2F;&gt;
\left(&lt;br &#x2F;&gt;
\sum_{x_L} \mathrm{eq}(w_{[i + 1, \ell&#x2F;2]}; x_L)&lt;br &#x2F;&gt;
\sum_{x_R} \mathrm{eq}(w_{[\ell&#x2F;2 + 1, \ell]}; x_R)&lt;br &#x2F;&gt;
\cdot p(v, u, x_L, x_R)&lt;br &#x2F;&gt;
\right)&lt;br &#x2F;&gt;
}_{A_i(v, u)}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;Here, $L_v$ is the Lagrange basis polynomial. This formula is the core of &lt;em&gt;Algorithm 6&lt;&#x2F;em&gt; ’s precomputation. The “how” of computing these $A_i(v,u)$ accumulators is &lt;em&gt;Procedure 9&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;We can rewrite the inner part of the previous equation in the following way:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\begin{aligned}&lt;br &#x2F;&gt;
A_i(v,u) =&lt;br &#x2F;&gt;
\sum_{y \in {0,1}^{\ell_0 - i}}&lt;br &#x2F;&gt;
\sum_{x_{\mathrm{out}} \in {0,1}^{\ell&#x2F;2 - \ell_0}}&lt;br &#x2F;&gt;
\mathrm{eq} \left(&lt;br &#x2F;&gt;
\left( w_{[(i + 1):\ell_0]}, w_{[(\ell&#x2F;2 + \ell_0+1):]} \right),&lt;br &#x2F;&gt;
(y, x_{\mathrm{out}})&lt;br &#x2F;&gt;
\right)&lt;br &#x2F;&gt;
\cdot \newline&lt;br &#x2F;&gt;
\sum_{x_{\mathrm{in}} \in \{0 , 1 \}^{ \ell&#x2F;2 }}&lt;br &#x2F;&gt;
\mathrm{eq} \left(&lt;br &#x2F;&gt;
w_{[(\ell_0+1):(\ell_0+\ell&#x2F;2)]}, x_{\mathrm{in}}&lt;br &#x2F;&gt;
\right)&lt;br &#x2F;&gt;
\cdot&lt;br &#x2F;&gt;
p \left( v,u,y,, x_{\mathrm{in}}, x_{\mathrm{out}} \right)&lt;br &#x2F;&gt;
\end{aligned}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;In the paper, we can see that &lt;em&gt;Procedure 9&lt;&#x2F;em&gt; cleverly inverts the loops: instead of iterating by accumulator $A_i(v,u)$, it iterates over the data $(x_{\mathrm{out}}, x_{\mathrm{in}}, \beta)$ and “distributes” each result to the correct $A_i(v,u)$ bin. This is done in two stages:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. **Temporal Accumulation** ($\mathrm{tA}[\beta]$): For a fixed $x_{\mathrm{out}}$, the algorithm computes the entire inner sum for every prefix $\beta \in \\{0,1 \\}^{ \ell_0 }$. This loop contains the dominant 𝔰𝔩 operation: `e_in_value * poly_evals[index]`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\mathrm{tA}[\beta] =&lt;br &#x2F;&gt;
\sum_{x_{\mathrm{in}} \in \{0,1\}^{ \ell&#x2F;2}}&lt;br &#x2F;&gt;
E_{\mathrm{in}}[x_{\mathrm{in}}] \cdot&lt;br &#x2F;&gt;
p(\beta, x_{\mathrm{in}}, x_{\mathrm{out}})&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
E_{\mathrm{in}}[x_{\mathrm{in}}]&lt;br &#x2F;&gt;
=\mathrm{eq} \left(w_{[(\ell_0 + 1):(\ell_0 + \ell&#x2F;2)]}, x_{\mathrm{in}}\right)&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. **Distribution** : Once the $\mathrm{tA}$ vector is computed, the algorithm &amp;quot;distributes&amp;quot; these values to the correct final accumulators $A_i (v,u)$, multiplying them by their respective $E_{\mathrm{out}}$ weights.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let’s dive into our implementation.&lt;&#x2F;p&gt;
&lt;p&gt;First, we have an &lt;code&gt;Accumulators&lt;&#x2F;code&gt; struct where we store the values, along with a couple of basic methods to create, modify, and read them:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#[derive(Debug, Clone, Eq, PartialEq)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub struct Accumulators&amp;lt;F: Field&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;&#x2F; One accumulator vector per SVO round.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;&#x2F; - `accumulators[0]` has 2^1 = 2 elements for A_0(u)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;&#x2F; - `accumulators[1]` has 2^2 = 4 elements for A_1(v, u)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;&#x2F; - `accumulators[2]` has 2^3 = 8 elements for A_2(v, u)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub accumulators: [Vec&amp;lt;F&amp;gt;; NUM_SVO_ROUNDS],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;impl&amp;lt;F&amp;gt; Accumulators&amp;lt;F&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;where&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    F: Field,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    #[must_use]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub fn new_empty() -&amp;gt; Self {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Self {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; In round 0, we have 2 accumulators: A_0(u) with u in {0, 1}.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; In round 1, we have 4 accumulators: A_1(v, u) with v in {0, 1} and u in {0, 1}.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; In round 2, we have 8 accumulators: A_2(v, u) with v in {0, 1}^2 and u in {0, 1}.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; We won&amp;#39;t need accumulators with any digit as infinity.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            accumulators: [F::zero_vec(2), F::zero_vec(4), F::zero_vec(8)],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;&#x2F; Adds a value to a specific accumulator.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub fn accumulate(&amp;amp;mut self, round: usize, index: usize, value: F) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        self.accumulators[round][index] += value;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;&#x2F; Gets the slice of accumulators for a given round.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    #[must_use]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub fn get_accumulators_for_round(&amp;amp;self, round: usize) -&amp;gt; &amp;amp;[F] {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;self.accumulators[round]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Notice that in the code we only compute the accumulators for $u \in \{0,1 \}$, even though initially, since $S(u)$ has degree 2, we should have three evaluations: at $0$, $1$, and at $\infty$. We’ll explain this later on.&lt;&#x2F;p&gt;
&lt;p&gt;So let’s see how we adapt &lt;em&gt;Procedure 9&lt;&#x2F;em&gt; to our specific use case.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; Procedure 9. Page 37.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; We compute only the accumulators that we&amp;#39;ll use, that is,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; A_i(v, u) for i in {0, 1, 2}, v in {0, 1}^{i}, and u in {0, 1}.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn compute_accumulators&amp;lt;F: Field, EF: ExtensionField&amp;lt;F&amp;gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    poly: &amp;amp;EvaluationsList&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    e_in: &amp;amp;[EF],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    e_out: &amp;amp;[Vec&amp;lt;EF&amp;gt;; NUM_SVO_ROUNDS],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; Accumulators&amp;lt;EF&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [...]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The function receives as input the evaluations of $p(x)$, $E_{\mathrm{in}}$, and $E_{\mathrm{out}}$.&lt;&#x2F;p&gt;
&lt;p&gt;We can see in the paper that these are computed as follows:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
E_{\text{in}} :=\left(\mathrm{eq} \left(&lt;br &#x2F;&gt;
w_{\left[\ell_0 + 1 : (\ell_0 + \ell&#x2F;2)\right]}, x_{\text{in}}&lt;br &#x2F;&gt;
\right) \right) \quad \text{with} \quad { x_{\text{in } } \in \{0,1 \}^{ \ell&#x2F;2 }}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
E_{\text{out},i} := \left( \mathrm{eq} \left(&lt;br &#x2F;&gt;
\left( w_{\left[(i+1):\ell_0\right]}, w_{\left[(\ell&#x2F;2+\ell_0+1):\right]} \right),&lt;br &#x2F;&gt;
(y, x_{\text{out}})&lt;br &#x2F;&gt;
\right)&lt;br &#x2F;&gt;
\right)\quad \text{with} \quad {(y, x_{ \text{out} }) \in \{0, 1\}^{ \ell_0 } \times \{0, 1 \}^{ \ell&#x2F;2 - \ell_0 }}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;These values depend only on our challenge $w$, so we can precompute them as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; Precomputation needed for Procedure 9 (compute_accumulators).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; Compute the evaluations eq(w_{l0 + 1}, ..., w_{l0 + l&#x2F;2} ; x) for all x in {0,1}^l&#x2F;2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn precompute_e_in&amp;lt;F: Field&amp;gt;(w: &amp;amp;MultilinearPoint&amp;lt;F&amp;gt;) -&amp;gt; Vec&amp;lt;F&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let half_l = w.num_variables() &#x2F; 2;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let w_in = &amp;amp;w.0[NUM_SVO_ROUNDS..NUM_SVO_ROUNDS + half_l];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    eval_eq_in_hypercube(w_in)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; Precomputation needed for Procedure 9 (compute_accumulators).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; Compute three E_out vectors, one per round i in {0, 1, 2}.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; For each i, E_out = eq(w_{i+1}, ..., l0, w_{l&#x2F;2 + l0 + 1}, ..., w_l ; x)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn precompute_e_out&amp;lt;F: Field&amp;gt;(w: &amp;amp;MultilinearPoint&amp;lt;F&amp;gt;) -&amp;gt; [Vec&amp;lt;F&amp;gt;; NUM_SVO_ROUNDS] {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let half_l = w.num_variables() &#x2F; 2;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let w_out_len = w.num_variables() - half_l - 1;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    std::array::from_fn(|round| {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let mut w_out = Vec::with_capacity(w_out_len);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        w_out.extend_from_slice(&amp;amp;w.0[round + 1..NUM_SVO_ROUNDS]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        w_out.extend_from_slice(&amp;amp;w.0[half_l + NUM_SVO_ROUNDS..]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        eval_eq_in_hypercube(&amp;amp;w_out)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Once we have computed these values, we can return to our &lt;code&gt;compute_accumulators&lt;&#x2F;code&gt; function.&lt;&#x2F;p&gt;
&lt;p&gt;The first thing we do is compute the number of variables in $x_{\mathrm{out}}$ as $\ell&#x2F;2 - \ell_0$, where $\ell$ is the number of variables of $p(X)$ and $\ell_0$ is the number of SVO rounds, taking into account the case where $\ell$ is odd.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[...]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let l = poly.num_variables();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let half_l = l &#x2F; 2;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let x_out_num_vars = half_l - NUM_SVO_ROUNDS + (l % 2);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let x_num_vars = l - NUM_SVO_ROUNDS;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    debug_assert_eq!(half_l + x_out_num_vars, x_num_vars);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let poly_evals = poly.as_slice();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [...]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we can run the outer loop, where for each value of $x_{\mathrm{out}}$ we will:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Initialize the temporary accumulators and compute the number of variables in $x_{\mathrm{in}}$:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(0..1 &amp;lt;&amp;lt; x_out_num_vars)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .into_par_iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .map(|x_out| {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; Each thread will compute its own set of local accumulators.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; This avoids mutable state sharing and the need for locks.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let mut local_accumulators = Accumulators::&amp;lt;EF&amp;gt;::new_empty();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let mut temp_accumulators = [EF::ZERO; 1 &amp;lt;&amp;lt; NUM_SVO_ROUNDS];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let num_x_in = 1 &amp;lt;&amp;lt; half_l;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. For each value of $x_{\mathrm{in}}$ we compute the $\mathrm{tA}$ values using:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\mathrm{tA}(x_{\mathrm{out}}) =&lt;br &#x2F;&gt;
\sum_{\beta \in \{0,1 \}^{3}}&lt;br &#x2F;&gt;
E_{\mathrm{in}}[x_{\mathrm{in}}] \cdot p(\beta, x_{\mathrm{in}}, x_{\mathrm{out}})&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;for (x_in, &amp;amp;e_in_value) in e_in.iter().enumerate().take(num_x_in) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                &#x2F;&#x2F; For each beta in {0,1}^3, we update tA(beta) += e_in[x_in] * p(beta, x_in, x_out)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                #[allow(clippy::needless_range_loop)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                for i in 0..(1 &amp;lt;&amp;lt; NUM_SVO_ROUNDS) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    let beta = i &amp;lt;&amp;lt; x_num_vars;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    let index = beta | (x_in &amp;lt;&amp;lt; x_out_num_vars) | x_out; &#x2F;&#x2F; beta | x_in | x_out&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    temp_accumulators[i] += e_in_value * poly_evals[index]; &#x2F;&#x2F; += e_in[x_in] * p(beta, x_in, x_out)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Once we have all the temporary accumulators, we unpack them and collect all the $E_{\mathrm{out}}$ values we will need.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Remember that $E_{\mathrm{out}}$ depends only on $y$. So in the first round, $y$ has 2 variables, giving us 4 possible $E_{\mathrm{out}}$ values. In the second round, $y$ has 1 variable, so there are 2 possible $E_{\mathrm{out}}$ values. In the third round, it does not depend on $y$, so we have a single $E_{\mathrm{out}}$ value.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Destructure things since we will access them many times later&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let [t0, t1, t2, t3, t4, t5, t6, t7] = temp_accumulators;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Get E_out(y, x_out) for this x_out&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Round 0 (i=0) -&amp;gt; y=(b1,b2) -&amp;gt; 2 bits&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let e0_0 = e_out[0][x_out]; &#x2F;&#x2F; y=00&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let e0_1 = e_out[0][(1 &amp;lt;&amp;lt; x_out_num_vars) | x_out]; &#x2F;&#x2F; y=01&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let e0_2 = e_out[0][(2 &amp;lt;&amp;lt; x_out_num_vars) | x_out]; &#x2F;&#x2F; y=10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let e0_3 = e_out[0][(3 &amp;lt;&amp;lt; x_out_num_vars) | x_out]; &#x2F;&#x2F; y=11&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Round 1 (i=1) -&amp;gt; y=(b2) -&amp;gt; 1 bit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let e1_0 = e_out[1][x_out]; &#x2F;&#x2F; y=0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let e1_1 = e_out[1][(1 &amp;lt;&amp;lt; x_out_num_vars) | x_out]; &#x2F;&#x2F; y=1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Round 2 (i=2) -&amp;gt; y=() -&amp;gt; 0 bits&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let e2 = e_out[2][x_out]; &#x2F;&#x2F; y=()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Once we have all these values, we can start adding them to the corresponding accumulators. In _Procedure 9_ , this is done by iterating over $(i, v, u, y) \in \mathrm{idx4}(\beta)$, but since we only need to compute 3 rounds and the values for $u = 0$ and $u = 1$, we can do it directly using the following sum:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\sum_{\beta \in U_d^{\ell_0}}&lt;br &#x2F;&gt;
\sum_{\substack{(i^\prime, v^\prime, u^\prime, y) \in \mathrm{idx4}(\beta) \ i^\prime = i, v^\prime = v, u^\prime = u}}&lt;br &#x2F;&gt;
E_{\mathrm{out}, i^\prime}[y, x_{\mathrm{out}}] \cdot \mathrm{tA}[\beta]&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Round 0 (i=0)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     &#x2F;&#x2F; A_0(u=0) = Σ_{y} E_out_0(y) * tA( (u=0, y), x_out )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     local_accumulators.accumulate(0, 0, e0_0 * t0 + e0_1 * t1 + e0_2 * t2 + e0_3 * t3);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     &#x2F;&#x2F; A_0(u=1) = Σ_{y} E_out_0(y) * tA( (u=1, y), x_out )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     local_accumulators.accumulate(0, 1, e0_0 * t4 + e0_1 * t5 + e0_2 * t6 + e0_3 * t7);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     &#x2F;&#x2F; Round 1 (i=1)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     &#x2F;&#x2F; A_1(v, u) = Σ_{y} E_out_1(y) * tA( (v, u, y), x_out )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     &#x2F;&#x2F; v=0, u=0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     local_accumulators.accumulate(1, 0, e1_0 * t0 + e1_1 * t1);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     &#x2F;&#x2F; v=0, u=1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     local_accumulators.accumulate(1, 1, e1_0 * t2 + e1_1 * t3);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     &#x2F;&#x2F; v=1, u=0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     local_accumulators.accumulate(1, 2, e1_0 * t4 + e1_1 * t5);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     &#x2F;&#x2F; v=1, u=1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     local_accumulators.accumulate(1, 3, e1_0 * t6 + e1_1 * t7);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     &#x2F;&#x2F; Round 2 (i=2)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     &#x2F;&#x2F; A_2(v, u) = E_out_2() * tA( (v, u), x_out )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     #[allow(clippy::needless_range_loop)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     for i in 0..8 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          local_accumulators.accumulate(2, i, e2 * temp_accumulators[i]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally, the only thing left is to perform the final sum over (x_{\mathrm{out}}).&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.par_fold_reduce(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            || Accumulators::&amp;lt;EF&amp;gt;::new_empty(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            |a, b| a + b,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            |a, b| a + b,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;v-phase-2-the-switchover-to-algorithm-5&quot;&gt;V. Phase 2: The Switchover to Algorithm 5&lt;&#x2F;h2&gt;
&lt;p&gt;The switchover strategy is critical. SVO is only cheaper for the first few rounds. That’s why after the first three rounds, we need to “apply” the challenges we’ve collected to the remaining polynomial evaluations. This process is formally known as &lt;strong&gt;folding&lt;&#x2F;strong&gt; or partial evaluation. We transform our original polynomial $p(x_1, \dots, x_\ell)$ into a smaller polynomial $p^{(3)}(x_4, \dots, x_\ell)$ by binding the first three variables:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
p^{(3)} (x_4, \dots, x_\ell) =&lt;br &#x2F;&gt;
\sum_{b \in \{0,1 \}^3} \mathrm{eq}\left((r_1, r_2, r_3), b\right) \cdot p(b, x_4, \dots, x_\ell)&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;The polynomial folding is done in the following line:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Fold to obtain p(r1, r2, r3, x)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let mut folded_evals = fold_evals_with_challenges(evals, &amp;amp;challenges); &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This operation contracts our evaluation domain from $2^\ell$ down to $2^{\ell - 3}$. In our implementation the function &lt;code&gt;fold_evals_with_challenges&lt;&#x2F;code&gt; handles this folding operation in parallel.&lt;&#x2F;p&gt;
&lt;p&gt;Since multilinear evaluations are stored in lexicographic order, fixing the first 3 variables conceptually slices the hypercube into $2^3 = 8$ large contiguous blocks. To compute the value for a point $i$ in the new, smaller domain, we need to gather the value at offset $i$ from each of these 8 blocks.&lt;&#x2F;p&gt;
&lt;p&gt;The index logic &lt;code&gt;(j * num_remaining_evals) + i&lt;&#x2F;code&gt; allows us to jump to the correct block $j$ and access the specific element $i$, accumulating the weighted sum into the result.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn fold_evals_with_challenges&amp;lt;F, EF&amp;gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    evals: &amp;amp;EvaluationsList&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    challenges: &amp;amp;[EF],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; EvaluationsList&amp;lt;EF&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let n = evals.num_vars();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let k = challenges.len(); &#x2F;&#x2F; k = 3 in our case&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; The size of the new, smaller hypercube (2^{l-3})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let num_remaining_evals = 1 &amp;lt;&amp;lt; (n - k); &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; 1. Precompute weights eq(r, b) for all 8 prefixes b in {0,1}^3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let eq_evals: Vec&amp;lt;EF&amp;gt; = eval_eq_in_hypercube(challenges);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; 2. Parallel Fold&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let folded_evals_flat: Vec&amp;lt;EF&amp;gt; = (0..num_remaining_evals)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .into_par_iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .map(|i| {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             &#x2F;&#x2F; For each point &amp;#39;i&amp;#39; in the destination domain, sum over the 8 source prefixes.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            eq_evals&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                .iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                .enumerate()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                .fold(EF::ZERO, |acc, (j, &amp;amp;eq_val)| {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    &#x2F;&#x2F; Reconstruct the index: prefix (j) + suffix (i)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    let original_eval_index = (j * num_remaining_evals) + i;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    let p_b_x = evals.as_slice()[original_eval_index];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    acc + eq_val * p_b_x&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .collect();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    EvaluationsList::new(folded_evals_flat)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;the-svo-to-standard-handover&quot;&gt;The SVO-to-Standard Handover&lt;&#x2F;h3&gt;
&lt;p&gt;Why do we stop SVO exactly here? The decision is dictated by the cost of field multiplications, as analyzed in the paper:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. **Before Folding ($\mathfrak{ss}$ Regime):** Our polynomial evaluations are in the base field (small). SVO exploits this by using efficient interpolation on small values, avoiding expensive extension field arithmetic.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. **The Folding Operation:** The folding operation itself is a linear combination involving the challenges $r_i$. Since $r_i \in \mathbb{F_{\text{ext}}}$, the output of the fold must be in the extension field.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. **After Folding ($\mathfrak{ll}$ Regime):** Once our evaluations are promoted to the extension field, the benefits of SVO evaporate. SVO introduces an overhead of $\mathcal{O} (d^2 )$ operations to save on multiplications.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After three rounds the folded multilinear polynomial is sufficiently small so that the standard linear-time prover (&lt;em&gt;Algorithm 5&lt;&#x2F;em&gt;) becomes more efficient than SVO. By switching immediately after the fold, we ensure we treat base field values with SVO and extension field values with the standard approach, maintaining optimal performance across the entire protocol execution.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;algorithm-5&quot;&gt;Algorithm 5&lt;&#x2F;h3&gt;
&lt;p&gt;Once we have folded the polynomial, we proceed to use &lt;em&gt;Algorithm 5&lt;&#x2F;em&gt; to execute the remaining $\ell - \ell_0$ rounds. You’ll find our implementation in the function called &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;whir-p3&#x2F;blob&#x2F;eec71d03a5ec81f30acc6d591f42f318941c6df5&#x2F;src&#x2F;sumcheck&#x2F;sumcheck_small_value.rs#L402&quot;&gt;&lt;code&gt;algorithm_5&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn algorithm_5&amp;lt;Challenger, F: Field, EF: ExtensionField&amp;lt;F&amp;gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    prover_state: &amp;amp;mut ProverState&amp;lt;F, EF, Challenger&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    poly: &amp;amp;mut EvaluationsList&amp;lt;EF&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    w: &amp;amp;MultilinearPoint&amp;lt;EF&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    challenges: &amp;amp;mut Vec&amp;lt;EF&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    sum: &amp;amp;mut EF,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pow_bits: usize,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) where&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Challenger: FieldChallenger&amp;lt;F&amp;gt; + GrindingChallenger&amp;lt;Witness = F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [...]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In each round $j$, the prover’s goal is the same as in the first three rounds. We need to:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Compute and send the univariate polynomial evaluations $S_j (u)$ for $u \in \\{0,\infty \\}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Update variables for the next round.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To do so, we’ll continue using the factorization of $S_j$ in:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
S_j(u) = \ell_j(u) \cdot t_j(u)&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;where, recall,&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\begin{align}&lt;br &#x2F;&gt;
\ell_j (u) &amp;amp;= \mathrm{eq}(w_{[1, j - 1]} ; r_{[1, j - 1]}) \cdot \mathrm{eq}(w_j; u) \newline&lt;br &#x2F;&gt;
t_j (u) &amp;amp;= \sum_{x \in \{0, 1\}^{\ell - j}} \mathrm{eq}(w_{[j + 1, \ell]}; x)\cdot p(r_{[1, j - 1]}, u, x)&lt;br &#x2F;&gt;
\end{align}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;However, to compute $t_j$ we won’t use SVO and accumulators, as we did before. Instead, we’ll simply split its eq-poly into two halves, taking advantage of the fact that one part can be precomputed, thus avoiding recomputation in each round.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s break down the function &lt;code&gt;algorithm_5&lt;&#x2F;code&gt; step by step. Before the round loop you’ll see this code snippet:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let num_vars = w.num_variables();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let half_l = num_vars &#x2F; 2;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Precompute eq_R = eq(w_{l&#x2F;2+1..l}, x_R)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let eq_r = eval_eq_in_hypercube(&amp;amp;w.0[half_l..]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let num_vars_x_r = eq_r.len().ilog2() as usize;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; The number of variables of x_R is: l&#x2F;2 if l is even and l&#x2F;2 + 1 if l is odd.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;debug_assert_eq!(num_vars_x_r, num_vars - half_l);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; start_round should be NUM_SVO_ROUNDS.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let start_round = challenges.len();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;challenges.reserve(num_vars - start_round);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here we define several parameters, such as the total number of variables $(\ell)$ and the round where we currently are $(\ell_0)$. But, most importantly, we precompute the right (or final) half of the eq-poly:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\mathrm{eq_R} = \mathrm{eq} (w_{\ell&#x2F;2 + 1}, \ldots, w_\ell; x_{ \ell&#x2F;2 + 1}, \ldots, x_\ell).&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;After that, we start the loop. In each round $j$ we need to compute $t_j(0)$ and $t_j(1)$. To do so, we consider two cases: on one hand, the first rounds until round $\ell&#x2F;2 - 1$, and on the other hand, the last rounds starting at round $\ell&#x2F;2$.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Disclaimer:&lt;&#x2F;em&gt; You’ll see that in the code the loop starts at $i = \ell_0$, but the first round that should be computed is $\ell_0 + 1$. That’s why we have the variable &lt;code&gt;round = i + 1&lt;&#x2F;code&gt; in the code. Here in the post, to simplify the notation we call $j =$ &lt;code&gt;round&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Compute the remaining rounds, from l_0 + 1 to the end.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;for i in start_round..num_vars {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; `i` is the 0-indexed variable number, so `round = i + 1`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let round = i + 1;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let num_vars_poly_current = poly.num_variables();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let poly_slice = poly.as_slice();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [...]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;first-half-rounds&quot;&gt;First Half Rounds&lt;&#x2F;h4&gt;
&lt;p&gt;For the cases where $j &amp;lt; \frac{\ell}{2}$, we use the function &lt;code&gt;compute_t_evals_first_half&lt;&#x2F;code&gt; to obtain $t_j(0)$ and $t_j(1)$ in parallel. These values are computed using the following sum-splitting:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\begin{align}&lt;br &#x2F;&gt;
t(0) &amp;amp;=&lt;br &#x2F;&gt;
\sum_{x_R} \mathrm{eq}(w_{[\ell&#x2F;2 + 1, \ell]}, x_R)&lt;br &#x2F;&gt;
\sum_{x_L} \mathrm{eq}(w_{[j + 1, \ell&#x2F;2]}, x_L) \cdot&lt;br &#x2F;&gt;
p(r_{[1,j - 1]}, 0, x_L, x_R) \newline&lt;br &#x2F;&gt;
t(1) &amp;amp;=&lt;br &#x2F;&gt;
\sum_{x_R} \mathrm{eq}(w_{[\ell&#x2F;2 + 1, \ell]}, x_R)&lt;br &#x2F;&gt;
\sum_{x_L} \mathrm{eq}(w_{[j+1, \ell&#x2F;2]}, x_L) \cdot&lt;br &#x2F;&gt;
p(r_{[1,j - 1]}, 1, x_L, x_R)&lt;br &#x2F;&gt;
\end{align}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Compute t(u) for u in {0, 1}.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let t_evals: [EF; 2] = if round &amp;lt;= half_l {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Case i+1 &amp;lt;= l&#x2F;2: Compute eq_L = eq(w_{i+2..l&#x2F;2}, x_L)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let eq_l = eval_eq_in_hypercube(&amp;amp;w.0[round..half_l]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let (t_0, t_1) = join(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        || compute_t_evals_first_half(&amp;amp;eq_l, &amp;amp;eq_r, poly_slice, num_vars_x_r, 0),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        || {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            compute_t_evals_first_half(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                &amp;amp;eq_l,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                &amp;amp;eq_r,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                poly_slice,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                num_vars_x_r,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                1 &amp;lt;&amp;lt; (num_vars_poly_current - 1), &#x2F;&#x2F; offset for u=1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    (t_0, t_1).into()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [...]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;second-half-rounds&quot;&gt;Second Half Rounds&lt;&#x2F;h4&gt;
&lt;p&gt;Similarly, in the case $j \geq \frac{\ell}{2}$, we compute $t_j(0)$ and $t_j(1)$ using &lt;code&gt;compute_t_evals_second_half&lt;&#x2F;code&gt;. Note that since $j \geq \frac{\ell}{2}$, we don’t have the sum involving the $\mathrm{eq_L}$ polynomial. So:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\begin{align}&lt;br &#x2F;&gt;
t(0) &amp;amp;= \sum_x \mathrm{eq}(w_{[j + 1, \ell]}, x) \cdot p(r_{[1,j - 1]}, 0, x) \newline&lt;br &#x2F;&gt;
t(1) &amp;amp;= \sum_x \mathrm{eq}(w_{[j + 1, \ell]}, x) \cdot p(r_{[1,j - 1]}, 1, x)&lt;br &#x2F;&gt;
\end{align}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;} else {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Case i+1 &amp;gt; l&#x2F;2: Compute eq_tail = eq(w_{i+2..l}, x_tail)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let eq_tail = eval_eq_in_hypercube(&amp;amp;w.0[round..]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let half_size = 1 &amp;lt;&amp;lt; (num_vars_poly_current - 1);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let (t_0, t_1) = join(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        || compute_t_evals_second_half(&amp;amp;eq_tail, &amp;amp;poly_slice[..half_size]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        || compute_t_evals_second_half(&amp;amp;eq_tail, &amp;amp;poly_slice[half_size..]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    (t_0, t_1).into()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;send-sample-and-update&quot;&gt;Send, Sample and Update&lt;&#x2F;h4&gt;
&lt;p&gt;Once we have $t_j(0)$ and $t_j(1)$, we compute $\ell_j(0)$ and $\ell_j(1)$ and get:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\begin{aligned}&lt;br &#x2F;&gt;
S_j(0) &amp;amp;= \ell_j(0) \cdot t_j(0) \newline&lt;br &#x2F;&gt;
S_j(\infty) &amp;amp;= \bigl(\ell_j(1) - \ell_j(0)\bigr) \cdot \left(t_j (1) - t_j(0)\right)&lt;br &#x2F;&gt;
\end{aligned}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;Then we add these evaluations to the prover state and sample an extension field element $r_j$. After that, we fold the polynomial and obtain:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
p(r_1, \ldots, r_j, x_{j+1}, \ldots, x_\ell).&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;Finally, we update the claimed sum:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\sigma_{j+1} = S_j (r_j).&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Compute S_i(u) = t_i(u) * l_i(u) for u in {0, inf}:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let linear_evals = compute_linear_function(&amp;amp;w.0[..round], challenges);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let [s_0, s_inf] = get_evals_from_l_and_t(&amp;amp;linear_evals, &amp;amp;t_evals);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Send S_i(u) to the verifier.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;prover_state.add_extension_scalars(&amp;amp;[s_0, s_inf]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;prover_state.pow_grinding(pow_bits);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Receive the challenge r_i from the verifier.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let r_i: EF = prover_state.sample();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;challenges.push(r_i);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Fold and update the poly.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;poly.compress_svo(r_i);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Update claimed sum&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let eval_1 = *sum - s_0;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;*sum = s_inf * r_i.square() + (eval_1 - s_0 - s_inf) * r_i + s_0;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;vi-communication-optimization&quot;&gt;VI. Communication Optimization&lt;&#x2F;h2&gt;
&lt;p&gt;Independent of the prover computation (SVO), we also optimize the communication. In a standard sumcheck, the prover sends three field elements per round (since the polynomial that needs to be sent has degree 2). However, we only send two, reducing the proof size.&lt;&#x2F;p&gt;
&lt;p&gt;The trick is that the verifier can derive the third value. For any round $i$, the prover sends:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $S_i (0)$ — the evaluation at zero.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $S_i (\infty)$ — the leading coefficient.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The verifier, who knows the claimed sum $\sigma_i = S_{i - 1} (r_{i - 1})$ from the previous round, derives the third evaluation:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
S_i(1) = \sigma_i - S_i(0)&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;This holds due to the sum constraint $S_i (0) + S_i (1) = \sigma_i$.&lt;&#x2F;p&gt;
&lt;p&gt;You can find this implemented for the prover in both &lt;code&gt;svo_three_rounds&lt;&#x2F;code&gt; and &lt;code&gt;algorithm_5&lt;&#x2F;code&gt; functions. For example, for the first round you’ll see:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Prover side&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; [...]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Round 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;prover_state.add_extension_scalars(&amp;amp;[s_0, s_inf]); &#x2F;&#x2F; Send 2 values.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let r_1: EF = prover_state.sample(); &#x2F;&#x2F; Sample a random challenge.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let s_1 = *sum - s_0; &#x2F;&#x2F; Derive 3rd value. &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;*sum = s_inf * r_1.square() + (s_1 - s_0 - s_inf) * r_1 + s_0; &#x2F;&#x2F; Update sum.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; [...]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The verifier’s job is simpler: it reads the proof, derives missing values, and verifies consistency. You can find the implementation in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;whir-p3&#x2F;blob&#x2F;eec71d03a5ec81f30acc6d591f42f318941c6df5&#x2F;src&#x2F;whir&#x2F;verifier&#x2F;sumcheck.rs#L144&quot;&gt;&lt;code&gt;verify_sumcheck_round_svo&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Verifier Side&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; [...]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;for _ in 0..rounds {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Extract the first and third evaluations of the sumcheck polynomial&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; and derive the second evaluation from the latest sum.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let c0 = verifier_state.next_extension_scalar()?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let c1 = *claimed_sum - c0;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let c2 = verifier_state.next_extension_scalar()?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; PoW interaction (grinding resistance)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    verifier_state.check_pow_grinding(pow_bits)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Sample the next verifier folding randomness rᵢ.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let rand: EF = verifier_state.sample();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Update sum.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    *claimed_sum = c2 * rand.square() + (c1 - c0 - c2) * rand + c0;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    randomness.push(rand);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; [...]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The verifier never computes accumulators or evaluates polynomials directly. It only reads two field elements from the proof and derives the third value. This is significantly more efficient than the classical sumcheck verifier, which needs to read three elements and verify the sum constraint explicitly.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;vii-conclusion&quot;&gt;VII. Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;In this post we present a complete implementation in Rust of &lt;em&gt;Algorithm 6&lt;&#x2F;em&gt; from the BDDT paper, bringing together both optimization techniques (SVO and Eq-Poly) into a working prover.&lt;&#x2F;p&gt;
&lt;p&gt;As a bonus, we also reduce the proof size by sending only two field elements per round, exploiting the sum constraint to let the verifier derive the missing value.&lt;&#x2F;p&gt;
&lt;p&gt;These optimizations are now part of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;whir-p3&quot;&gt;our whir-p3 fork&lt;&#x2F;a&gt; and have been &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tcoratger&#x2F;whir-p3&#x2F;pull&#x2F;322&quot;&gt;merged into the original repository&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Small Value Optimization Paper](https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2025&#x2F;1117)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Optimizing Sumcheck (Part I)](&#x2F;optimizing-sumcheck&#x2F;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [How factoring equality polynomials optimizes sumcheck (Part II)](&#x2F;how-factoring-equality-polynomials-optimizes-sumcheck&#x2F;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Whirlaway: Multilinear STARKs using WHIR](&#x2F;whirlaway-multilinear-starks-using-whir-as-polynomial-commitment-scheme&#x2F;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [whir-p3 Repository](https:&#x2F;&#x2F;github.com&#x2F;tcoratger&#x2F;whir-p3)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Our fork of whir-p3 Repository](https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;whir-p3)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</description>
      </item>
      <item>
          <title>Efficient attention explained: the math behind linear-time transformers</title>
          <pubDate>Mon, 13 Oct 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/efficient-attention-explained-the-math-behind-linear-time-transformers/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/efficient-attention-explained-the-math-behind-linear-time-transformers/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/efficient-attention-explained-the-math-behind-linear-time-transformers/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;One of the key components of the Transformer architecture is the Attention layer, which is in charge of making every word (or more generally, every &lt;em&gt;token&lt;&#x2F;em&gt;) learn the context given by every other in a sequence, and was introduced in the seminal paper &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;abs&#x2F;1706.03762&quot;&gt;Attention is all you need&lt;&#x2F;a&gt;. In this post, we will explore this equation and a specific approach that manages to improve its complexity to be linear with a few mathematical tricks, following the work of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;pdf&#x2F;1812.01243&quot;&gt;Shein et al. (2021)&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-the-original-implementation-of-attention-works&quot;&gt;How the original implementation of Attention works&lt;&#x2F;h2&gt;
&lt;p&gt;There’s a lot of information about the original Attention (also known as dot product Attention) implementation out there so we’ll do just a quick recap of it. It all comes down to a bunch of matrix multiplications with a normalization function. The exact mathematical formulation is&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
Attention(Q,K,V) = softmax(\frac{{QK^T}}{\sqrt{d_k}})V&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;where,&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $Q \in \mathbb{R}^{N\times d_q}$, are the projections of the input sequence over the query space&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $K \in \mathbb{R}^{N\times d_k}$ are the projections of the input sequence over the key space&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $V \in \mathbb{R}^{N\times d_v}$ are the projections of the input sequence over the value space&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $N$ is the sequence (or _context_) length, i.e., the maximum size of the input&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $d_{q}, d_{k}$ and $d_{v}$ are the dimensions of each of the projection spaces&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Both the $Q$ and $K$ matrices must have the same embedding dimension, so we can assume $d_k = d_q$ and without loss of generality we can consider $d_{q} = d_{k} = d_{v} = d$ for simplicity.&lt;&#x2F;p&gt;
&lt;p&gt;The softmax function works by mapping each element of an arbitrary, real numbers array into the range $(0, 1)$ - this is how it looks for a given input element:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;softmax.png?raw=true&quot; alt=&quot;Im 1&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The $\sqrt{d_k}$ scaling factor is present to prevent the softmax function from saturating – as $d_k$ becomes larger, the dot products in $QK^T$ grows larger in magnitude, pushing the softmax function into regions where it is essentially flat and thus has extremely small gradients. While using backpropagation for training, this may turn into stability issues, slow training or even leaving some parameters entirely frozen for the whole training process.&lt;&#x2F;p&gt;
&lt;p&gt;We use the softmax function to go from attention scores (the results of the matrix multiplication of $QK^T$) to attention weights that will be multiplied by the $V$ matrix. The attention weights can be interpreted as how much each token affects the other ones in the sequence. If the attention weight between a pair of tokens is high, then we say that one &lt;em&gt;attends&lt;&#x2F;em&gt; to the other.&lt;br &#x2F;&gt;
As an example, from basic english grammar, we know that in the sentence&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Do androids dream of electric sheep?&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;the word &lt;em&gt;&lt;strong&gt;sheep&lt;&#x2F;strong&gt;&lt;&#x2F;em&gt; attends more to &lt;em&gt;&lt;strong&gt;electric&lt;&#x2F;strong&gt;&lt;&#x2F;em&gt; than to the word &lt;em&gt;&lt;strong&gt;do&lt;&#x2F;strong&gt;.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;deep-dive-into-attention-complexity&quot;&gt;Deep dive into Attention complexity&lt;&#x2F;h2&gt;
&lt;p&gt;One of the major drawbacks of the Attention mechanism is the way in which computational resources scale with respect to the sequence length $N$. In the definition of the Attention function we can see the similarity calculation between the vectors in $Q$ and $K$, given by $QK^T$. From basic matrix multiplication we know that,&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
(\mathbb{R}^{N\times d} \times \mathbb{R}^{d\times N}) \rightarrow \mathbb{R}^{N\times N}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;which means that we end up having to store a $N \times N$ matrix and hence have $O(N^2)$ memory complexity. On the other hand, this matrix multiplication needs a total of $O(d_{k}N^2)$ operations, so we can clearly see that resource demands scale quite quickly as the sequence length gets larger.&lt;&#x2F;p&gt;
&lt;p&gt;In essence, the original attention architecture is really limited by the sequence length we can use, making it infeasible for situations where bigger contexts are needed. There has been a lot of effort on trying to optimize the original Attention mechanism and we will focus on one that really stands out due to the simplicity of its approach, taking into account some of their trade-offs.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;efficient-attention&quot;&gt;Efficient Attention&lt;&#x2F;h2&gt;
&lt;p&gt;Since the scaling issues come from having to compute and store the $N \times N$ matrix as an intermediate value in the computation, if we could somehow apply softmax piecemeal we could have simpler intermediate values. If we apply softmax to the rows of $Q$, and to the columns of $K$ separately and &lt;em&gt;then&lt;&#x2F;em&gt; do the product, we can avoid storing the entire matrix. Since we are no longer performing a dot product in this approximation, we also do not need the scaling factor $\sqrt{d_k}$.&lt;&#x2F;p&gt;
&lt;p&gt;Thus, efficient Attention, as proposed by &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;pdf&#x2F;1812.01243&quot;&gt;Shen et al. (2021)&lt;&#x2F;a&gt;, is given by:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
E(Q,K,V) = softmax_{row}(Q)softmax_{col}(K)^T V&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;where now we make the distinction between $softmax_{row}$ and $softmax_{col}$, where we apply the softmax function in the rows and the columns of the matrices, respectively. In general, when there is no specification, the $softmax_{row}$ version is assumed.&lt;&#x2F;p&gt;
&lt;p&gt;The trick boils down to getting rid of applying the softmax function over the result of $QK^T$ – kind of like distributing the softmax function into $Q$ and $K$, with the caveat that this is not really a mathematical property of the softmax function but an approximation. This way, we can arrange the order of the matrix multiplications in this expression to our advantage, making the resulting computation much more efficient.&lt;&#x2F;p&gt;
&lt;p&gt;If we first compute $softmax_{col}(K)^TV$, we have to store an $d \times d$ matrix, which means a $O(d^2)$ memory complexity, and requiring $O(Nd^2) \approx O(N)$ calculations with $d≪N$. This attention implementation is sometimes referred as &lt;em&gt;Linear Attention&lt;&#x2F;em&gt; due to the dependency with $N$&lt;em&gt;.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The efficiency gains make themselves obvious considering that $d &amp;lt; N$ in any practical case, and the difference grows as we make context lengths bigger and bigger.&lt;&#x2F;p&gt;
&lt;p&gt;To reiterate, the mathematical expression for this new Attention mechanism works as an &lt;em&gt;approximation&lt;&#x2F;em&gt; since the two softmax operations applied over $Q$ and $K$ are not equivalent to the single softmax over $QK^T$. The core property that both variants share, and what makes the approximation reasonable is the fact that the sum over the rows of $softmax_{row}(QK^T)$ and $softmax_{row}(Q)softmax_{col}(K)^T$ both equal 1.&lt;&#x2F;p&gt;
&lt;p&gt;The approximation is good enough for some applications where the context length $N$ can be large. An example of this is the Computer Vision field, where input tokens may represent pixels of an image. Other examples include audio and genomics, where input lengths can reach millions.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;interpretability-of-efficient-attention&quot;&gt;Interpretability of Efficient Attention&lt;&#x2F;h2&gt;
&lt;p&gt;When trying to make sense of what this change means in the LLM context, we can think of the standard attention mechanism as the process of all elements in our query matrix asking all elements in the key matrix what they should pay attention to. It’s an iterative process to get the correlation between one word (the query element) and the rest of the words in the same sentence (the key elements). We’re essentially doing:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
s_{ij} = Q_iK_j^T&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;for all &lt;em&gt;j&lt;&#x2F;em&gt; in the input sequence. Each of these $s_i$ (the full set of scores for position &lt;em&gt;i&lt;&#x2F;em&gt;) is called an &lt;em&gt;attention map&lt;&#x2F;em&gt; , so we create $N$ of such attention maps (one for each of our $N$ input positions).&lt;&#x2F;p&gt;
&lt;p&gt;The Efficient Attention mechanism creates attention maps that do not follow positional information about our queries and instead reference a more general aspect of the whole input. Instead of each query having its own attention map checking correlation with every other element, we create &lt;strong&gt;global attention maps&lt;&#x2F;strong&gt; with information that captures general semantic themes.&lt;&#x2F;p&gt;
&lt;p&gt;These maps are derived from the keys $K$, but they no longer depend on a specific positions. They are denoted $k_j^T$ and when multiplied by the elements in our value matrix we get $d_{k}$ vectors denoted as $g_i$. Each query then uses coefficients to mix these global themes rather than attending to individual positions.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s see a practical toy example with some random numbers to see the difference clearly:&lt;&#x2F;p&gt;
&lt;p&gt;Suppose we have the sentence &lt;strong&gt;“With great power comes great responsibility”&lt;&#x2F;strong&gt; with &lt;strong&gt;N = 6&lt;&#x2F;strong&gt; tokens and &lt;strong&gt;$d_{k} = 4$&lt;&#x2F;strong&gt; (so we’ll generate 4 global attention maps).&lt;&#x2F;p&gt;
&lt;p&gt;In &lt;strong&gt;Dot Product Attention&lt;&#x2F;strong&gt; , each of the 6 tokens creates its own attention map over all 6 positions:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Token 3 (“power”)&lt;&#x2F;strong&gt; creates an attention map $s_3$:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
s_3 = [0.08, 0.45, 0.15, 0.20, 0.05, 0.07]&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;This tells “power” to attend strongly to position 2 (“great”) and moderately to position 4 (“comes”). We got the output:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
output_3=0.08⋅V_1+0.45⋅V_2+0.15⋅V_3+0.20⋅V_4+0.05⋅V_5+0.07⋅V_6&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Token 4 (“comes”)&lt;&#x2F;strong&gt; creates its own separate attention map $s_4$:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
s_4 = [0.05, 0.12, 0.38, 0.10, 0.08, 0.27]&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;This tells “comes” to attend strongly to positions 3 (“power”) and 6 (“responsibility”). We get the output:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
output_4=0.05⋅V_1+0.12⋅V_2+0.38⋅V_3+0.10⋅V_4+0.08⋅V_5+0.27⋅V_6&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;Similarly, all 6 tokens each create their own attention map. &lt;strong&gt;Total: 6 attention maps, each of size 6.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In &lt;strong&gt;Efficient Attention&lt;&#x2F;strong&gt; , instead of position-specific attention maps, we can create, for example, &lt;strong&gt;4 global semantic attention maps&lt;&#x2F;strong&gt; that capture themes across the entire sentence. In a language context, an example of these global maps for this input sentence could be something like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Modifier theme: The model encodes the fact that _great_ qualifies both _power_ and _responsibility_. &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * _“great” → “power”_&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * _“great” → “responsibility”_&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Cause-consequence theme: This encodes the overall causal&#x2F;propositional structure &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * “power” → “responsibility”&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * “with … power” → “comes … responsibility”&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Predicate theme: Maps tokens to the main predicate. This reduces the need for the model to discover the verb as the organizing node — the map enforces it. &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * All words point toward the main verb _“comes”_&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Parallelism - Analogy theme: Highlights symmetry between paired concepts &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * _“power” ↔ “responsibility”_&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * Both are treated as abstract nouns of similar importance&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;$k_1^T$ (Modifier theme)&lt;&#x2F;strong&gt; : $[0.10, 0.85, 0.15, 0.10, 0.85, 0.20]$ → creates $g_1$&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;$k_2^T$ (Cause-consequence theme)&lt;&#x2F;strong&gt; : $[0.05, 0.10, 0.90, 0.05, 0.10, 0.88]$ → creates $g_2$&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;$k_3^T$ (Predicate theme)&lt;&#x2F;strong&gt; : $[0.20, 0.05, 0.10, 0.95, 0.05, 0.10]$ → creates $g_3$&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;$k_4^T$ (Parallelism-Analogy theme)&lt;&#x2F;strong&gt; : $[0.90, 0.15, 0.20, 0.15, 0.10, 0.10]$ → creates $g_4$&lt;&#x2F;p&gt;
&lt;p&gt;Each $g_i$ is a weighted sum of all value vectors $V_{j}$ using the corresponding global map weights.&lt;&#x2F;p&gt;
&lt;p&gt;Each token mixes these 4 global themes:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Token 3 (“power”)&lt;&#x2F;strong&gt; with $q_3=[0.30,0.20,0.10,0.40]$&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
output_3=0.30⋅g_1+0.20⋅g_2+0.10⋅g_3+0.40⋅g_4&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Token 4 (“comes”)&lt;&#x2F;strong&gt; with $q_4=[0.10,0.25,0.40,0.25]$&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
output_4=0.10⋅g_1+0.25⋅g_2+0.40⋅g_3+0.25⋅g_4&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;Here, there are only four global maps shared by all tokens, and each token selects which themes it should attend to, rather than attending to each of the other words in the sentence. The number and composition of themes and how they are picked are just part of this example.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;lost-in-the-big-picture&quot;&gt;Lost in the Big Picture&lt;&#x2F;h2&gt;
&lt;p&gt;While Efficient Attention offers significant computational advantages, it comes with an important trade-off: it loses the ability to sharply focus on specific positions and instead focuses on coarse global features. Let’s demonstrate this limitation with a practical example.&lt;&#x2F;p&gt;
&lt;p&gt;In this example, we’ll compare the attention scores produced by $softmax(\frac{{QK^T}}{\sqrt{d_k}})$ vs $softmax({{Q}}) ⋅ softmax({{K}})^T$. Although Efficient Attention actually computes $softmax({{K}})^T ⋅ V$ first to achieve its efficiency gains, the final attention distribution remains the same. Examining the scores directly helps us visualize and understand what’s happening to the attention pattern.&lt;&#x2F;p&gt;
&lt;p&gt;Recall from linear algebra that the dot product of two vectors relates to their similarity:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
a⋅b=∣a∣.∣b∣cos⁡(θ_{ab})&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;When vectors are closely aligned, their dot product is large.&lt;&#x2F;p&gt;
&lt;p&gt;In the example below, we have one query vector and four key vectors. Notice that the third key is identical to our query, so we should expect it to receive most of the attention:&lt;&#x2F;p&gt;
&lt;p&gt;$q = [2, 1, 3]$&lt;&#x2F;p&gt;
&lt;p&gt;$k_1 = [1, 0, 1]$, $k_2 = [0, 1, 0]$, $k_3 = [2, 1, 3]$, $k_{4} = [1, 1, 0]$&lt;&#x2F;p&gt;
&lt;p&gt;For the standard Dot-product Attention case,&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
AttnWeight_1= softmax(\frac{q.k_1}{\sqrt{3}}) = 0.005&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
AttnWeight_2 = softmax(\frac{q.k_2}{\sqrt{3}}) = 0.001&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
AttnWeight_3 = softmax(\frac{q.k_3}{\sqrt{3}}) = 0.992&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
AttnWeight_4 = softmax(\frac{q.k_4}{\sqrt{3}}) = 0.002&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;As we expected, position 3 got almost all the attention.&lt;&#x2F;p&gt;
&lt;p&gt;We now repeat the same calculations for the Efficient Attention case. For simplicity in the calculations here, we will use the matrix formulation where $K$ is the matrix created by setting the vectors $k_i$ as rows.&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
softmax(q).softmax_{col}(K)^T = [0.1309, 0.0713, 0.6962, 0.1017]&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;The trade-off is clear: by applying softmax before computing similarities, Efficient Attention smooths out the attention distribution. Instead of sharply focusing on the most relevant position (3), it distributes attention more uniformly across all positions. This flattening effect is why the mechanism is sometimes described as capturing broad semantic themes rather than precise positional relationships.&lt;br &#x2F;&gt;
This limitation explains why state-of-the-art language models still prefer standard attention despite its quadratic cost; the ability to attend precisely to specific tokens is crucial for many language understanding tasks. However, although Efficient Attention is not commonly used in LLMs, it remains highly valuable for AI models in other domains. In applications such as computer vision, where inputs represent pixels in images, the model can still perform well with this type of attention mechanism, making the substantial efficiency gains well worth the trade-off.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;code-implementation-and-benchmarks&quot;&gt;Code implementation and benchmarks&lt;&#x2F;h2&gt;
&lt;p&gt;To have a rough idea of the improvements over computational resources with efficient attention, we will run comparisons for some values of $N$and how each of the Attention implementations scales as it increases.&lt;&#x2F;p&gt;
&lt;p&gt;We’ll see how easy it is to implement these functions using PyTorch and also to use them as a layer in a LLM.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;import torch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;def dot_product_attention(Q, K, V):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    attn_scores = torch.matmul(Q, K.T)                 # N x N&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    attn_weights = torch.softmax(attn_scores, dim=-1)  # N x N&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return torch.matmul(attn_weights, V)               # N x d&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;def efficient_attention(Q, K, V):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Q_smr = torch.softmax(Q, dim=-1)                   # N x d&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    K_smc = torch.softmax(K, dim=-2)                   # N x d&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    KV = torch.matmul(K_smc.T, V)                      # d x d&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return torch.matmul(Q_smr, KV) &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Below you can see a comparison of the execution times for different values of the sequence length $N$, for both Attention implementations.&lt;&#x2F;p&gt;
&lt;p&gt;For reference, these benchmarks were run on a machine with the following specs:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **GPU:** NVIDIA RTX A4000 (16 GB)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **OS:** Ubuntu 22.04 LTS (Kernel 5.15.0-157)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **CPU:** 8 × Intel(R) Xeon(R) Gold 5315Y @ 3.20 GHz&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;execution_time.png?raw=true&quot; alt=&quot;Im 2&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Similarly, below is the comparison for the memory resources&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;memory_usage.png?raw=true&quot; alt=&quot;Im 3&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;As one can see, at the beginning, the memory and performance are similar for both (although better for the linear attention implementation), but for larger sequence lengths, both the time and memory requirements of the original implementation grow exponentially (plots are in log-log scale, so a greater slope means greater exponent), whilst the Efficient Attention implementation doesn’t.&lt;&#x2F;p&gt;
&lt;p&gt;You can see the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;linear_attention_blog&#x2F;blob&#x2F;main&#x2F;notebook&#x2F;benchmark.ipynb&quot;&gt;code used for the benchmarks&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The same repository also includes a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;linear_attention_blog&#x2F;blob&#x2F;main&#x2F;transformer.py&quot;&gt;full Transformer implementation&lt;&#x2F;a&gt; following the GPT architecture, with a configuration option to switch between &lt;strong&gt;Efficient Attention&lt;&#x2F;strong&gt; and the &lt;strong&gt;original Dot Product Attention&lt;&#x2F;strong&gt; , providing a broader view of how everything fits together.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;Efficient Attention has been shown to be much more memory and performance efficient than the usual Dot Product Attention, allowing for much larger contexts to be processed due to its linear dependency with it. So why aren’t they more widely adopted? State-of-the-art models will rather pay the high costs of training to have that small edge over the competition.&lt;&#x2F;p&gt;
&lt;p&gt;Nevertheless, efficient attention implementations remain important in domains such as video generation or genomics, where context sizes can inherently become very large.&lt;&#x2F;p&gt;
&lt;p&gt;In this blog post, we’ve presented the original and simplest implementation of linearized attention; however, this is an ever-evolving field, and new and improved implementations have emerged, such as CosFormer, LinFormer, and Mamba. Some modern architectures also take a hybrid approach, mixing standard and efficient attention heads to balance accuracy and stability.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Efficient Attention paper](https:&#x2F;&#x2F;arxiv.org&#x2F;pdf&#x2F;1812.01243)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * &amp;lt;https:&#x2F;&#x2F;github.com&#x2F;lucidrains&#x2F;linear-attention-transformer&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * &amp;lt;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=LgsiwDRnXls&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * &amp;lt;https:&#x2F;&#x2F;cmsflash.github.io&#x2F;ai&#x2F;2019&#x2F;12&#x2F;02&#x2F;efficient-attention.html&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</description>
      </item>
      <item>
          <title>How factoring equality polynomials optimizes sumcheck</title>
          <pubDate>Thu, 25 Sep 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/how-factoring-equality-polynomials-optimizes-sumcheck/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/how-factoring-equality-polynomials-optimizes-sumcheck/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/how-factoring-equality-polynomials-optimizes-sumcheck/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;In this article we will continue our study and analysis of the work by Bagad, Dao, Domb and Thaler,’‘Speeding up SUMCHECK’’ regarding optimizations for the SUMCHECK protocol applied to polynomials that are products of multilinear polynomials. It is now time to dive into specificity: since equality polynomials are widely used in cryptographic environments, a great deal of interest is order.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;once-upon-a-time&quot;&gt;Once upon a time…&lt;&#x2F;h2&gt;
&lt;p&gt;The reader of this article surely must have surely come across equality polynomials (also known as ’‘eq polynomials’’) - polynomials that evaluate to zero at all points of their domain but one, where they evaluate to one. In the usual real analysis jargon, they also known as indicator functions for points in the cartesian space. Recalling the role of multilinear polynomials in one and several variables, equality polynomials can be obtained by multiplying together “smaller ones”. Concretely, suppose $\mathbb{F}$ is a field and let $\omega \in \mathbb{F}^\ell$: this is&lt;&#x2F;p&gt;
&lt;p&gt;$$\omega = (\omega_1, \omega_2, \ldots, \omega_\ell)$$&lt;&#x2F;p&gt;
&lt;p&gt;for $\omega_i \in \mathbb{F}$. Suppose now that we partition $\omega$ in blocks; for instance, suppose we want to split it into three blocks, say&lt;&#x2F;p&gt;
&lt;p&gt;$$\omega = (\omega_L,\omega_C,\omega_R)$$&lt;&#x2F;p&gt;
&lt;p&gt;where $L,C,R$ are a partition of $[\ell] = \{1,2,\ldots \ell \}$ such that $$l &amp;lt; c &amp;lt; r \quad \forall\ l \in L, c\in C, r\in R$$. These subsets indicate the indices involved in each ’‘chunk’’ of $\omega$. If the reader needs some help visualizing this, just think&lt;&#x2F;p&gt;
&lt;p&gt;$$\omega = (2,3,4,2,5,5) = ((2,3), (4,2), (5,5))$$&lt;&#x2F;p&gt;
&lt;p&gt;for $L = \{1,2\}, C = \{3,4}, R = \{5,6\}$.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The good thing about block partitioning points is that it is compatible with factorization of equality polynomials: $$\omega = (\omega_L ,\omega_R )\implies eq_\omega (x) = eq_{\omega_L}(x_L ) eq_{\omega_R} (x_R )$$ for $x = (x_L,x_R)$, a block partition of the variable $x$.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;This is of course absolutely compatible with the tensor nature of the interpolation basis of multilinear polynomials, and comes as no surprise. One extra observation comes handy and will play a crucial role, especially when summing evaluations of polynomials defined over finite fields. Whenever a polynomial $f$ can be block-factored as shown above, then its integral (i.e. the sum of its evaluations) can be done sequentially, or in other words: there is a clever way of reordering the domain of evaluation we can take advantage of. Specifically, suppose $x\in\mathbb{F}^\ell$ and that&lt;&#x2F;p&gt;
&lt;p&gt;$$f(x) = f_L (x_L ) f_R (x_R )$$&lt;&#x2F;p&gt;
&lt;p&gt;then &lt;strong&gt;the sum over all $x$ can be indexed according to any of its blocks&lt;&#x2F;strong&gt; :&lt;&#x2F;p&gt;
&lt;p&gt;$$\sum\limits_{x\in\mathbb{F}^\ell } f(x) = \sum\limits_{ x\in\mathbb{F}^\ell } f_L (x_L ) f_R (x_R ) = \sum\limits_{ x_R\in\mathbb{F}^R }\sum\limits_{ x_L\in\mathbb{F}^L } f_L (x_L ) f_R (x_R )$$&lt;&#x2F;p&gt;
&lt;p&gt;where by fixing the index in the outer sum, the factors involving that very index can be taken out of the inner sum (i.e. distributive law in reverse), so&lt;&#x2F;p&gt;
&lt;p&gt;$$\sum\limits_{ x\in\mathbb{F}^\ell } f(x) = \sum\limits_{ x_R\in\mathbb{F}^R } f_R (x_R ) \sum\limits_{ x_L\in\mathbb{F}^L } f_L (x_L )$$&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;This sort of ideas will be the ones we’ll discuss and exploit: fixing $X_R$ will allow to pre-compute sums over $X_L$ where $X_R$ is considered as a parameter: in this sense, the latter sum is pre-computed and then re-used whenever the parameter $X_R$ is invoked.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If the reader is wondering what is the name of the game: the name of the game is accumulate, accumulate, accumulate (but cleverly).&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ideas-ideas&quot;&gt;Ideas(ideas)&lt;&#x2F;h2&gt;
&lt;p&gt;We’re now ready to dive into the optimizations proposed by BDDT. The starting point is a sum-check protocol over a polynomial of the form $$g(X) = \tilde{eq}(w, X) \cdot p(X)$$ where $p(X)$ is itself a product of $d$ multilinear polynomials. This makes $g(X)$ a polynomial of degree $d+1$. In each round $i$ of the sum-check protocol, the prover must send a univariate polynomial $s_i (X)$, which is the sum of $g(X)$ over the remaining variables. To define this polynomial, the prover needs to compute $d + 2$ of its evaluations.&lt;&#x2F;p&gt;
&lt;p&gt;The authors take up on the work by Angus Gruen and take it even further. Briefly, &lt;strong&gt;Gruen’s key idea&lt;&#x2F;strong&gt; is to leverage the special structure of the equality polynomial, $\tilde{eq}$. This polynomial can be decomposed into a product:&lt;br &#x2F;&gt;
$$\tilde{eq}(w, (r_1 , …, r_{i - 1}, X_i, x_{i + 1}, …, x_l )) = \underbrace{\tilde{eq}(w_{[&amp;lt;i]}, r_{[&amp;lt;i]}) \cdot \tilde{eq}(w_i, X_i) }_ \text{ Linear part l_i(X) } \cdot \underbrace{\tilde{eq}(w_{[&amp;gt;i]}, x’)}_ \text{Remaining part}$$&lt;&#x2F;p&gt;
&lt;p&gt;The effect of this decomposition is that the round polynomial, $s_i (X_i)$ originally defined as the sum over $x^\prime$ now looks like a product:&lt;&#x2F;p&gt;
&lt;p&gt;\begin{equation}&lt;br &#x2F;&gt;
\begin{split}&lt;br &#x2F;&gt;
s_i (X_i) &amp;amp;=\sum\limits_{x’}g(r,X_i,x’) = \sum\limits_{x’}eq(r,X_i,x’)p(r,X_i,x’) \newline&lt;br &#x2F;&gt;
&amp;amp;= \sum\limits_{x’}eq_{w&amp;lt;i}(r)eq_{w_i}(X_i)eq_{w&amp;gt;i}(x’)p(r,X_i,x’) \newline&lt;br &#x2F;&gt;
&amp;amp;= eq_{w&amp;lt;i}(r)eq_{w_i}(X_i)\left(\sum\limits_{x’}eq_{w&amp;gt;i}(x’)p(r,X_i,x’)\right)&lt;br &#x2F;&gt;
\end{split}&lt;br &#x2F;&gt;
\end{equation}&lt;&#x2F;p&gt;
&lt;p&gt;The round polynomial now is a product of &lt;strong&gt;a linear factor $l_i(X_i)$}&lt;&#x2F;strong&gt; , namely&lt;&#x2F;p&gt;
&lt;p&gt;$$l_i(X_i) = eq_{w&amp;lt;i} (r) eq_{w_i} (X_i)$$&lt;br &#x2F;&gt;
that depends on the challenges from previous rounds ($r_{[&amp;lt;i]}$) and the current variable ($X_i$) and &lt;strong&gt;a degree-$d$ factor, $t_i(X_i)$:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;$$t_i(X_i) = \sum\limits_{x’}eq_{w&amp;gt;i}(x’)p(r,X_i,x’)$$&lt;&#x2F;p&gt;
&lt;p&gt;which contains the actual summation, including the product of the $p_k$ polynomials and the remaining part of the $\tilde{eq}$ polynomial. The polynomial to be calculated by the prover at the $i-th$ round is then&lt;br &#x2F;&gt;
$$s_i(X_i) = l_i(X_i) \cdot t_i(X_i)$$&lt;&#x2F;p&gt;
&lt;p&gt;The reader might be asking what is the benefit of thinking of $s_i$ in this way.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Instead of computing $d + 2$ evaluations of the complex polynomial $s_i(X)$ (degree $d + 1$), the prover now only needs to compute $d + 1$ evaluations of the simpler polynomial $t_i(X)$ (degree $d$). One of these evaluations, $t_i(1)$, can be derived from the protocol’s consistency check ($s_i(0) + s_i(1) = C_{i - 1}$), so in practice, only $d$ sums are explicitly calculated.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;In summary, Gruen reduces the degree of the polynomial that the prover must perform the most work on, saving the cost of one full evaluation in each round of the protocol. &lt;strong&gt;BDDT’s key idea is to re-apply the separability property of the $\tilde{eq}$ polynomial, but this time on the remaining variables being summed over ($x’$)&lt;&#x2F;strong&gt; , combined with their previous proposal of deflecting the evaluation of $p$ at the random challenges to the evaluation of Lagrange interpolation polynomials. In broad strokes, the novel work goes like&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. **Variable Splitting:** They divide the set of remaining variables $x&amp;#39;$ into two parts of proper length, which we for now call $x_L$ (left) and $x_R$ (right).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. **Nested Summation:** Thanks to this split, the sum to compute $t_i(u)$ can be rewritten as a nested sum: $$t_i(u) = \sum_{x_R} \tilde{eq}(w_R, x_R) \cdot \left( \sum_{x_L} \tilde{eq}(w_L, x_L) \cdot \prod_{k=1}^{d} p_k(r,u,x_L,x_R) \right)$$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;This rewriting is the core of the optimization. The prover can now first compute the inner sum (over $x_L$) and then use those results for the outer sum (over $x_R$).&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;This “sum-splitting” technique yields very significant benefits in terms of time and, above all, memory.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Drastic Memory Reduction:** The standard method would require precomputing and storing a table with the evaluations of $\tilde{eq}(w, x)$ for all $x$—a table of size $2^l$. BDDT&amp;#39;s optimization **eliminates the need for this giant table**. Instead, the prover only needs to precompute tables for the evaluations of $\tilde{eq}$ over the halves of the variables ($x_L$ and $x_R$), which are of size $\approx 2^{l&#x2F;2}$. Moving from a memory requirement of $O(2^l)$ to $O(2^{ l&#x2F;2 })$ is an exponential improvement and makes much larger problems feasible.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Reduced Computational Cost (Time):** By avoiding multiplications with the large $\tilde{eq}$ table, the prover saves a considerable number of operations. The paper estimates this optimization reduces the cost by roughly $N$ multiplications between large field elements, where $N = 2^l$ is the size of the summation domain. The sums are processed over smaller domains iteratively, which improves memory locality and computational efficiency.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This optimization is applied during the first $l&#x2F;2$ rounds of the protocol. For the remaining rounds, the benefit diminishes, and the algorithm switches back to a standard method.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;organization-beats-time&quot;&gt;Organization beats time&lt;&#x2F;h2&gt;
&lt;p&gt;The fact that the authors propose a combination of Gruen’s strategy and their own ideas from &lt;em&gt;SmallValues&lt;&#x2F;em&gt; optimization implies that there is special care to be taken at the time of evaluating the polynomials $l_i$ and $t_i$. At round $i$ the data sent to the verifier&lt;&#x2F;p&gt;
&lt;p&gt;$$s_i (u) = l_i (u) t_i (u)$$&lt;&#x2F;p&gt;
&lt;p&gt;has a part which is more computationally demanding: the computation of $t_i(u)$ for $u$ in an appropiately large set. So far, the only definition available for this polynomial is given by&lt;&#x2F;p&gt;
&lt;p&gt;$$t_i(u) = \sum_{x_R} \tilde{eq}(w_R, x_R) \cdot \left( \sum_{ x_L } \tilde{eq}(w_L, x_L) \cdot \prod_{k = 1}^{d} p_k(r,u,x_L,x_R) \right)$$&lt;&#x2F;p&gt;
&lt;p&gt;and still needs some clarification. How are the parts of $x’$ defined? How is this sum performed? How does it relate to the SmallValues optimization the authors worked out previously?&lt;&#x2F;p&gt;
&lt;p&gt;It needs to be stressed that this description is conceptually sound and contains the key ideas involved in this optimization. In addition, it must me mentioned that at this level, the block partition of the remaining vectors $x’$ and the factoring of the equality polynomials is a &lt;strong&gt;dynamic&lt;&#x2F;strong&gt; factor: the length of $x’$ is $\ell-i$ at round $i$ and so in absolute terms, the lengths of $x_L$ and $x_R$ will vary from round to round.&lt;&#x2F;p&gt;
&lt;p&gt;While this is enough for a coffee table conversation, it leaves something to be desired from the algorithmic perspective, especially if some gains are to be expected.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-need-for-an-optimality-parameter&quot;&gt;The need for an optimality parameter&lt;&#x2F;h3&gt;
&lt;p&gt;In order to maneuver between conceptual clarity and efficient computation, authors define an optimality parameter called $l_0$ - carefully chosen to minimize the prover’s total time. Its selection is based on a cost trade-off:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Cost of optimized rounds ($i \le l_0$)** : This cost (primarily `sl` multiplications) grows exponentially with $l_0$, as the size of the accumulators is on the order of $O((d + 1)^{l_0})$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Cost of standard rounds ($i &amp;gt; l_0$)**: This cost (primarily `ll` multiplications) decreases as $l_0$ increases, because there are fewer &amp;#39;&amp;#39;expensive&amp;#39;&amp;#39; rounds to execute.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The optimal value for $l_0$ is the one where these two costs are balanced. The paper provides a formula to estimate this optimal point for Algorithm 4, which depends on the polynomial’s structure (the number of factors, $d$) and the relative costs of hardware operations (the ratio $\kappa$ between the cost of an &lt;code&gt;ll&lt;&#x2F;code&gt; and an &lt;code&gt;ss&lt;&#x2F;code&gt; multiplication). The optimal switchover point $l_0$ can be estimated by the following formula:&lt;&#x2F;p&gt;
&lt;p&gt;$$l_0 = \frac{\log\left(\frac{\kappa \cdot d^2}{2(d - 1)}\right)}{\log(d + 1)}$$&lt;br &#x2F;&gt;
where:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $d$ is the number of multilinear factors.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $\kappa$ is the factor difference in cost between a large-large (`ll`) and a small-small (`ss`) multiplication. The authors use $\kappa = 30$ for their estimations and provide a deeper background for that choice (the reader is encouraged to seek for details in the original article!)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This parameter controls in a strict sense the regime in which the SUMCHECK protocol works at any given stage:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **If $i \le l_0$** : You are in the &amp;#39;&amp;#39;optimized phase&amp;#39;&amp;#39;. The protocol uses the pre-computed accumulators to compute the prover&amp;#39;s message very quickly.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **If $i &amp;gt; l_0$**: You have crossed the threshold. The protocol switches to a more standard algorithm (like Algorithm 5) for the remaining rounds, as the benefit of the pre-computation has ended.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we are able to take a further look at the block partition of $x’$. The implementation of the author’s optimization is based in a static partition of these points in terms of the optimization parameter $\ell_0$ and the number of variables $\ell$. This partition is named&lt;&#x2F;p&gt;
&lt;p&gt;$$x’ = (x_{in}, x_{out})$$&lt;&#x2F;p&gt;
&lt;p&gt;works in the same way as the dynamic one but allows for an efficient computation since lengths are now constant. They represent a fixed split of the variables that are not in the $l_0$-round prefix.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $x_{in}$ is the set of variables over which the &amp;#39;&amp;#39;inner sum&amp;#39;&amp;#39; is calculated.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $x_{out}$ is the set of variables over which the &amp;#39;&amp;#39;outer sum&amp;#39;&amp;#39; iterates.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;The $l$ total variables of the polynomial are divided into three disjoint groups whose union forms the complete set of variables:&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. **Pre-computation Prefix $\beta$** : The first $l_0$ variables.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. **Set $x_{in}$** : The next $\lfloor l&#x2F;2 \rfloor$ variables&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. **Set $x_{out}$** : The final $\lfloor l&#x2F;2 \rfloor - l_0$ variables&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Therefore, $x_{in}$ and $x_{out}$ &lt;strong&gt;together form a partition&lt;&#x2F;strong&gt; of the set of variables that do not belong to the pre-computation prefix (i.e., the pre-computation suffix). The sum of their sizes is $(\lfloor l&#x2F;2 \rfloor) + (\lfloor l&#x2F;2 \rfloor - l_0)$, which is approximately $l - l_0$, the total size of the pre-computation suffix.&lt;&#x2F;p&gt;
&lt;p&gt;Now that we have settled the notation and parameters involved, lets see how their algorithm actually computes the desires values in the round $i$.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-effect-of-block-description-in-the-pre-computation-phase&quot;&gt;The effect of block description in the pre-computation phase&lt;&#x2F;h3&gt;
&lt;p&gt;In order to compute $t_i (u)$ - the authors make use of the SmallValue optimization - it allows to compute the evaluation at random challenges sent by the verifier of a product of multilinear polynomials. As we mentioned in an earlier post, this is done by deflecting the burden of evaluation to multivariate Lagrange polynomials defined over a grid of points with coefficients in the base field - and evaluate those polynomials. The desired evaluation is now a sum weighted by pre-computed coefficients called accumulators, which depend on the grid and the product.&lt;&#x2F;p&gt;
&lt;p&gt;For concreteness, recall the definition of $t_i$&lt;&#x2F;p&gt;
&lt;p&gt;$$t_i(u) = \sum\limits_{x’} \tilde{eq}(w_{&amp;gt;i}, x’) \cdot \prod_{k = 1}^{d} p_k(r,u,x’)$$&lt;&#x2F;p&gt;
&lt;p&gt;The SmallValues optimization allows a re-writing of this as&lt;&#x2F;p&gt;
&lt;p&gt;$$t_i(u) = \sum\limits_{v\in G_i} \left(\sum_{x’} \tilde{eq}(w_{&amp;gt;i}, x’) \cdot \prod_{k=1}^{d} p_k(v,u,x’)\right)\cdot L_v(r) $$&lt;&#x2F;p&gt;
&lt;p&gt;where&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. $G_i$ is an adequate interpolation grid of points in the base field. Specifically, if $g$ is a product of $d$ multilinear polynomials not counting the eq factor, setting $U_d = {\infty, 0, 1, \dots, d - 1}$ then $$G_i = U_d^{ i - 1 }\quad i\geq 2\quad\text{and}\quad G_1 = \emptyset$$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. The polynomials $L_v$ are the $i - 1$ variate Lagrange interpolation polynomials associated with the grid $G_i$ - it is those polynomials that end up being evaluated at the challenges $r_1,\ldots r_{ i - 1}$. For $i = 1$ we set $L_1 = 1$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Authors fancy to collect the $\lvert G_i\rvert$ values of the polynomials $L_v(r)$ in a single $\lvert G_i\rvert$-long vector indexed by the points in the grid, in a single challenge vector $R_i$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. The sum between parenthesis in the last line is the definition of the **accumulators $A_i(v,u)$** \- simply the coefficients needed to express, in terms of the Lagrange interpolation polynomials, the value of $t_i(u)$. Authors express this as an &amp;#39;&amp;#39;inner product&amp;#39;&amp;#39; between the challenge vector and an accumulator vector, also indexed by $v$: $$t_i(u) = \sum\limits_{ v\in G_i} R_i (v)A_i (v,u)$$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now is time to let the power of block partitioning shine and do its magic: the sum over $x’$ now can be take in two steps:&lt;&#x2F;p&gt;
&lt;p&gt;$$A_i(v, u) = \sum_{x_{out}} \tilde{eq}(w_{out}, x_{out}) \sum_{x_{in}} \tilde{eq}(w_{in}, x_{in}) \prod_{k = 1}^{d} p_k(v, u, x_{in}, x_{out})$$&lt;&#x2F;p&gt;
&lt;p&gt;Don’t panic, we’re there already. Consider now the prefix $\beta = (v,u)$ and call $E_{in} [x_{in}] =eq(w_{in},x_{in})$. The last inner sum is then parametrized by $\beta$ and $x_{out}$ and shall be called temporary accumulator $tA[\beta]$.&lt;&#x2F;p&gt;
&lt;p&gt;$$tA[\beta] = \sum_{x_{in} \in \{0,1\}^{ l&#x2F;2 }} E_{in}[x_{in}] \cdot \prod_{k = 1}^{d} p_k(\beta, x_{in}, x_{out})$$&lt;&#x2F;p&gt;
&lt;p&gt;Now that we have baptized the proper objects, we can describe how the algorithm works.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;logic-and-algorithmic-steps&quot;&gt;Logic and Algorithmic Steps:&lt;&#x2F;h4&gt;
&lt;p&gt;The core idea is a form of &lt;strong&gt;memoization&lt;&#x2F;strong&gt;. Instead of calculating the entire sum for each accumulator, it calculates the innermost sum once and reuses the result: really, the effecto of the block partitioning.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. **Outer Iteration over $x_{out}$** : The algorithm has a main loop that iterates over all possible assignments of the variables in the $x_{out}$ segment.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. **Inner Sum Calculation** : Inside that loop, for a fixed value of $x_{out}$, the algorithm computes the innermost sum. This sum is over all assignments of $x_{in}$ and depends on the prefix $\beta$ (which generalizes $(v,u,y)$) and the current $x_{out}$.  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;a. For each prefix $\beta$, it computes $\sum_{x_{in}} E_{in}[x_{in}] \cdot \prod p_k(\beta, x_{in}, x_{out})$.&lt;br &#x2F;&gt;
b. The result of this inner sum for each $\beta$ is stored in a &lt;strong&gt;temporary accumulator&lt;&#x2F;strong&gt; called $tA[\beta]$.
3. &lt;strong&gt;Distribution to Final Accumulators&lt;&#x2F;strong&gt; : Once all the $tA$ values have been computed for the current $x_{out}$, the algorithm distributes them to the final accumulators $A_i(v,u)$. This is done in the following way:&lt;br &#x2F;&gt;
a. It iterates over each prefix $\beta$ and its corresponding value in $tA[\beta]$.&lt;br &#x2F;&gt;
b. Using the mapping function &lt;code&gt;idx4&lt;&#x2F;code&gt; (defined in A.5), it determines which final accumulators $(i, v, u)$ this prefix $\beta$ contributes to.&lt;br &#x2F;&gt;
c. It adds the value of $tA[\beta]$ to the appropriate final accumulator, weighted by the outer &lt;code&gt;eq-poly&lt;&#x2F;code&gt; factor, $E_{out,i}$.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;classification-and-distribution-mechanism&quot;&gt;Classification and distribution mechanism&lt;&#x2F;h3&gt;
&lt;p&gt;We discussed this method when we studied BDDT’s SmallValue optimization, but it is nice to refresh the reader how this is performed. The role of the &lt;em&gt;idx4&lt;&#x2F;em&gt; classification algorithm is to act as an intelligent &lt;strong&gt;’‘dispatcher’’ or ’‘router’’&lt;&#x2F;strong&gt; during the pre-computation phase. Its function is to determine which final accumulators $A_i(v,u)$, possibly from different rounds, should be updated with an intermediate result that has just been computed.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Procedure 9&lt;&#x2F;em&gt; (the pre-computation engine for Algorithm 6) is designed for high efficiency. Instead of calculating each accumulator $A_i(v,u)$ separately, it iterates over all possible prefixes $\beta$ of length $l_0$ and computes a single value for each: the temporary accumulator $tA[\beta]$.&lt;&#x2F;p&gt;
&lt;p&gt;The problem is that a single value $tA[\beta]$ (calculated, for example, for the prefix $\beta=(0,1,0)$) can be part of the calculation for:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The accumulator for **Round 1** : $A_1(u=0)$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The accumulator for **Round 2** : $A_2(v=(0), u=1)$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The accumulator for **Round 3** : $A_3(v=(0,1), u=0)$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The question that &lt;em&gt;idx4&lt;&#x2F;em&gt; answers is: given a $\beta$, what are all the ’‘addresses’’ $(i, v, u)$ of the final accumulators to which this $tA[\beta]$ must be sent?&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Its logic consists of “decomposing” the prefix $\beta$ for each round $i$ (from 1 to $l_0$) and checking if it meets the required structure. For a prefix $\beta$ to be valid for an accumulator of round $i$, the part of the prefix corresponding to the future variables (the vector $y$) &lt;strong&gt;{must be binary (containing only 0s and 1s)&lt;&#x2F;strong&gt;. The fact that the polynomial $g$ has an $eq$ factor ends up greatly simplyfing this distribution step, since a very little number of precomputed products&#x2F;sums are involved in the construction of the accumulators.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;intuitive-example&quot;&gt;Intuitive Example&lt;&#x2F;h3&gt;
&lt;p&gt;Imagine $l_0 = 3$ and the computed prefix is $\beta = (0, 1, 0)$. &lt;em&gt;idx4&lt;&#x2F;em&gt; would do the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. **Does it contribute to Round 1 ($i = 1$)?**  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;a. $u=\beta_1=0$.&lt;br &#x2F;&gt;
b. The remainder is $y = (\beta_2, \beta_3) = (1,0)$.&lt;br &#x2F;&gt;
c. Since $y$ is binary, &lt;strong&gt;Yes&lt;&#x2F;strong&gt;. &lt;em&gt;idx4&lt;&#x2F;em&gt; generates the tuple &lt;em&gt;$(i=1, v=(), u = 0, y = (1,0))$&lt;&#x2F;em&gt;.
2. &lt;strong&gt;Does it contribute to Round 2 ($i = 2$)?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
a. $v = (\beta_1) = (0)$.&lt;br &#x2F;&gt;
b. $u = \beta_2 = 1$.&lt;br &#x2F;&gt;
c. The remainder is $y=(\beta_3)=(0)$.&lt;br &#x2F;&gt;
d. Since $y$ is binary, &lt;strong&gt;Yes&lt;&#x2F;strong&gt;. &lt;em&gt;idx4&lt;&#x2F;em&gt; generates the tuple $(i=2, v=(0), u=1, y=(0))$.
3. &lt;strong&gt;Does it contribute to Round 3 ($i = 3$)?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
a. $v = (\beta_1, \beta_2) = (0,1)$.&lt;br &#x2F;&gt;
b. $u=\beta_3=0$.&lt;br &#x2F;&gt;
c. The remainder, $y$, is empty.&lt;br &#x2F;&gt;
d. &lt;strong&gt;Yes&lt;&#x2F;strong&gt;. &lt;em&gt;idx4&lt;&#x2F;em&gt; generates the tuple $(i = 3, v = (0,1), u = 0, y = ())$.&lt;&#x2F;p&gt;
&lt;p&gt;In contrast, if $\beta = (2, 1, 0)$, it would only contribute to Round 1. For Rounds 2 and 3, the $v$ part of the prefix would contain a &lt;code&gt;2&lt;&#x2F;code&gt;, which is not a binary value and thus is not part of the sum over the Boolean hypercube that defines the accumulators for those rounds.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-small-example-before-you-fall-off-the-chair&quot;&gt;A small example before you fall off the chair&lt;&#x2F;h2&gt;
&lt;p&gt;To fix ideas, we will now walk through an example with small, concrete numbers. If you will, grab a piece of paper and some coffee and double check the computations as we move along the initial rounds.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;setup&quot;&gt;Setup&lt;&#x2F;h3&gt;
&lt;p&gt;We will use a polynomial of &lt;strong&gt;6 variables&lt;&#x2F;strong&gt; while keeping the optimization rounds at &lt;strong&gt;$l_0 = 2$&lt;&#x2F;strong&gt;. This change allows us to have a non-empty $x_{out}$ in Round 2, thus showing the complete interaction between temporary and final accumulators.&lt;&#x2F;p&gt;
&lt;p&gt;Consider the polynomial&lt;&#x2F;p&gt;
&lt;p&gt;$$g(X) = \tilde{eq}(w, X) \cdot (X_1 + X_3 + X_5 + 1) \cdot (X_2 + X_4 + X_6 + 2)$$&lt;&#x2F;p&gt;
&lt;p&gt;and $eq$ is the equality polynomial for the vector $w = (1, 0, 1, 1, 0, 1)$. Considering $l_0 = 2$ then only rounds 1 and 2 are optimized. As the author’s choice of interpolation set, we will stick to $U_2 = \{\infty, 0, 1 \}$. The prover needs to compute $t_2(u)$ for $u \in \hat{U_2} = \{\infty, 0\}$.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;getting-the-partitioning-straight&quot;&gt;Getting the partitioning straight&lt;&#x2F;h3&gt;
&lt;p&gt;Since $\ell_0=2$, the 6 variables are partitioned as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **The pre-computation prefix** $\beta = (X_1, X_2)$ and its &amp;#39;&amp;#39;eq&amp;#39;&amp;#39; companion $w_L=(w_1, w_2)=(1,0)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **The pre-computation suffix** $(X_3, X_4, X_5, X_6)$ is then split as  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;a. &lt;strong&gt;$x_{in}$ (size $l&#x2F;2 = 3$)&lt;&#x2F;strong&gt; : $(X_3, X_4, X_5)$. Its &lt;code&gt;eq&lt;&#x2F;code&gt; vector is $w_{in} = (w_3, w_4, w_5) = (1,1,0)$.&lt;br &#x2F;&gt;
b. &lt;strong&gt;$x_{out}$ (size $l&#x2F;2 - l_0 = 1$)&lt;&#x2F;strong&gt; : $(X_6)$. Its &lt;code&gt;eq&lt;&#x2F;code&gt; vector is $w_{out} = (w_6) = (1)$.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-first-round&quot;&gt;The first round&lt;&#x2F;h3&gt;
&lt;p&gt;The prover needs to compute the values of&lt;&#x2F;p&gt;
&lt;p&gt;$$s_1 (X_1) = l_1 (X_1) t_1 (X_1)$$&lt;&#x2F;p&gt;
&lt;p&gt;at $\infty$ and $0$. Remember that the linear factor $l_i (X_i)$ is defined as:&lt;br &#x2F;&gt;
$$l_i(X_i) = \underbrace{\tilde{eq}(w_{[&amp;lt;i]}, r_{[&amp;lt;i]})}_ {\text{past challenges}} \cdot \underbrace{\tilde{eq}(w_i, X_i)}_ {\text{current variable}}$$&lt;&#x2F;p&gt;
&lt;p&gt;So in round 1 $i = 1$ the set of past challenges $r_{[&amp;lt;1]}$ is empty. By convention, a product over an empty set is 1. Therefore, the first factor of the formula is simply 1. This means that&lt;&#x2F;p&gt;
&lt;p&gt;$$l_1 (X_1) = 1 \cdot \tilde{eq}(w_1, X_1) = \tilde{eq}(1, X_1) = X_1$$&lt;&#x2F;p&gt;
&lt;p&gt;This implies that $l_1 (\infty) = 1$ and $l_1 (0) = 0$ so the good news is that we don’t need to compute $t_1 (0)$. Let’s get to work and see how the leading coefficient of $t_1$ is computed.&lt;&#x2F;p&gt;
&lt;p&gt;According to Algorithm 6,&lt;br &#x2F;&gt;
$$t_1(u) = \langle R_1, A_1(u) \rangle = A_1(u) \quad (\text{since } R_1=[1])$$&lt;&#x2F;p&gt;
&lt;p&gt;Therefore, the task reduces to calculating the final accumulator $A_1(\infty)$ and this is where the temporary accumulators come into play. Since the optimization parameter is $\ell_0 = 2$ then&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * for this first round the prefixes $\beta$ we will be interested in taking in account are $$\beta = (\infty,0)\quad\text{and}\quad \beta = (\infty,1)$$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * then the **suffix** is split into $x_{in}=(X_3,X_4,X_5)$ and $x_{out}=(X_6)$ and since the **`eq` vectors** are $w_{in} = (1,1,0)$ and $w_{out} = (1)$, we have $$E_{out,1}(1,0) = 0\quad\text{and}\quad E_{out,1}(1,1) = 1$$ so we won&amp;#39;t be computing the temporary acumulator for $x_6 = 0$ (it gets multiplied by zero).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For completeness, we include here a small table with the precomputation in this case:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Temporary Accumulators for $x_6 = 1$&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;$u$&lt;&#x2F;th&gt;&lt;th&gt;$y_2$&lt;&#x2F;th&gt;&lt;th&gt;$p_1 = u + 2$&lt;&#x2F;th&gt;&lt;th&gt;$p_2 = y_2 + 4$&lt;&#x2F;th&gt;&lt;th&gt;&lt;strong&gt;$tA [u,y_2]$&lt;&#x2F;strong&gt;&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;$\infty$&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;$1 \cdot 4 = 4$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$\infty$&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;5&lt;&#x2F;td&gt;&lt;td&gt;$1 \cdot 5 = 5$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;$2 \cdot 4 = 8$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;5&lt;&#x2F;td&gt;&lt;td&gt;$2 \cdot 5 = 10$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;So let’s compute the outer loop for $x_6 = 1$. Now the inner weight of the product is given by $$E_{in} (w_{in},x_{in})$$ so the only term in the inner sum is the one corresponding to $x_{in} = (1,1,0)$ and so&lt;&#x2F;p&gt;
&lt;p&gt;$$tA[\infty,0] = p_1 (\infty,0,1,1,0,1) \cdot p_2 (\infty,0,1,1,0,1) = 1\cdot 4 = 4$$&lt;&#x2F;p&gt;
&lt;p&gt;and&lt;&#x2F;p&gt;
&lt;p&gt;$$tA[\infty,1] = p_1(\infty,1,1,1,0,1)\cdot p_2(\infty,1,1,1,0,1) = 1\cdot 5 = 5$$&lt;&#x2F;p&gt;
&lt;p&gt;which implies that&lt;&#x2F;p&gt;
&lt;p&gt;$$A_1(\infty) = 1\cdot tA[\infty,0] + 1\cdot tA[\infty,1] = 4 + 5 = 9$$&lt;br &#x2F;&gt;
and so, the prover sends&lt;&#x2F;p&gt;
&lt;p&gt;$$s_1 (\infty) = 1\cdot 9 = 9\quad\text{and }\quad s_1(0) = 0$$&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-second-round&quot;&gt;The second round&lt;&#x2F;h3&gt;
&lt;p&gt;Firstly, we tackle the linear factor $l_2 (X_2)$. This factor comes from the &lt;code&gt;eq&lt;&#x2F;code&gt; over the prefix variables $(X_1, X_2)$ evaluated at $(r_1, X_2)$:&lt;br &#x2F;&gt;
$$l_2(X_2) = \tilde{eq}((w_1, w_2), (r_1, X_2)) = \tilde{eq}(1, r_1) \cdot \tilde{eq}(0, X_2) = r_1 \cdot (1-X_2)$$&lt;&#x2F;p&gt;
&lt;p&gt;and obviously&lt;&#x2F;p&gt;
&lt;p&gt;$$l_2(\infty) = - r_1\quad\text{and}\quad l_2(0) = r_1$$&lt;&#x2F;p&gt;
&lt;p&gt;Now comes the tough part of computing $t_2(X_2)$. Since this is computed via the SmallValue optimization, it involves combining the evaluations at the random challenge $r_1$ of the Lagrange interpolation polynomials using the pre-computed accumulators: this ends up being a sum of products and the authors usually show this as an inner product $$t_2(u) = \langle R_2, A_2(u) \rangle$$ where the challenge vector $R_2$ depends on $r_1$ and $U_2 = \{\infty, 0, 1\}$, and is calculated as:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $R_2[\infty] = (r_1 - 0)(r_1 - 1) = r_1(r_1 - 1)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $R_2[0] = \frac{r_1 - 1}{0 - 1} = 1 - r_1$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $R_2[1] = \frac{r_1 - 0}{1 - 0} = r_1$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;The challenge vector is then &lt;strong&gt;$R_2 = (r_1 (r_1 - 1), 1 - r_1, r_1)$&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;We will now compute the values $A_2(v,u)$ for $v,u \in U_2$ by following the logic of Procedure 9, which iterates over $x_{out} = (X_6)$; again, since&lt;&#x2F;p&gt;
&lt;p&gt;$$E_{out,2} (1,X_6) = X_6$$&lt;&#x2F;p&gt;
&lt;p&gt;we only need to take in account the case $x_6 = 1$. Also the computation of temporary accumulators $tA$ in this case benefits from what we already learned in the first round: the sum still collapses for $x_{in} = (1,1,0)$ For completeness we include&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Temporary Accumulators for $x_6 = 1$&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;$v$&lt;&#x2F;th&gt;&lt;th&gt;$u$&lt;&#x2F;th&gt;&lt;th&gt;$p_1 = v+2$&lt;&#x2F;th&gt;&lt;th&gt;$p_2 = u+4$&lt;&#x2F;th&gt;&lt;th&gt;&lt;strong&gt;$tA[v,u]$&lt;&#x2F;strong&gt;&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;$\infty$&lt;&#x2F;td&gt;&lt;td&gt;$\infty$&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;$1 \cdot 1 = 1$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$\infty$&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;$1 \cdot 4 = 4$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;$\infty$&lt;&#x2F;td&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;$2 \cdot 1 = 2$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;$2 \cdot 4 = 8$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;$\infty$&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;$3 \cdot 1 = 3$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;$3 \cdot 4 = 12$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;We are now in position of constructing a table with the final accumulators involved in this round. Since the prover needs to send evaluations at $\infty$ and $0$, we only compute the accumulators&lt;&#x2F;p&gt;
&lt;p&gt;$$A_2(\infty,\infty),, A_2(0,\infty),, A_2(1,\infty),, A_2(\infty,0),, A_2(0,0),\text{and}, A_2(1,0)$$&lt;&#x2F;p&gt;
&lt;p&gt;Remember: the $E_{out,2}$ and $E_{in}$ weights eliminate most of the sums in the definition&lt;&#x2F;p&gt;
&lt;p&gt;$$A_2 (v,u) = \sum\limits_{x_{out}} E_{out,2} \sum\limits_{x_{in}} E_{in}[x_{in}] p_1 (v,u,x_{in},x_{out}) p_2 (v,u,x_{in},x_{out})$$&lt;&#x2F;p&gt;
&lt;p&gt;which reduces to&lt;&#x2F;p&gt;
&lt;p&gt;$$A_2(v,u) = p_1(v,u,1,1,0,1) p_2(v,u,1,1,0,1)$$&lt;&#x2F;p&gt;
&lt;p&gt;This drastic reduction in cases is a clear example of how this approach to computing the round polynomials works: block partitioning the eq factor collected by $t_i$ causes much of the sum to vanish and yields very few nontrivial summands contributing to the accumulators.&lt;&#x2F;p&gt;
&lt;p&gt;For completeness, here’s a table showing the final accumulators&lt;&#x2F;p&gt;
&lt;h3 id=&quot;final-accumulator-values-for-round-2&quot;&gt;Final Accumulator Values for Round 2&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;strong&gt;$A_2(v,u)$&lt;&#x2F;strong&gt;&lt;&#x2F;th&gt;&lt;th&gt;&lt;strong&gt;$u=\infty$&lt;&#x2F;strong&gt;&lt;&#x2F;th&gt;&lt;th&gt;&lt;strong&gt;$u=0$&lt;&#x2F;strong&gt;&lt;&#x2F;th&gt;&lt;th&gt;&lt;strong&gt;$u=1$&lt;&#x2F;strong&gt;&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;$v=\infty$&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;(not needed)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;$v=0$&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;td&gt;(not needed)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;$v=1$&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;td&gt;(not needed)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;In this round, we combine the challenge vector using the accumulators as weights to produce the evaluations of $t_2(u)$:&lt;&#x2F;p&gt;
&lt;p&gt;\begin{itemize}&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Computation of $t_2(0)$:**  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;\begin{align*}&lt;br &#x2F;&gt;
t_2(0) &amp;amp;= \sum_{v \in U_2} R_2[v] \cdot A_2(v, 0) \newline&lt;br &#x2F;&gt;
&amp;amp;= r_1(r_1 - 1) \cdot A_2(\infty, 0)) + (1 - r_1)\cdot A_2(0, 0) + r_1 \cdot A_2(1, 0) \newline&lt;br &#x2F;&gt;
&amp;amp;= r_1(r_1 - 1) \cdot 4 + (1 - r_1) \cdot 8 + r_1 \cdot 12&lt;br &#x2F;&gt;
\end{align*}
* &lt;strong&gt;Computation of $t_2(\infty)$&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
\begin{align*}&lt;br &#x2F;&gt;
t_2(\infty) &amp;amp;= \sum_{v \in U_2} R_2[v] \cdot A_2(v, \infty) \newline&lt;br &#x2F;&gt;
&amp;amp;= (r_1(r_1 - 1) \cdot A_2(\infty, \infty)) + ((1 - r_1)\cdot A_2(0, \infty)) + (r_1 \cdot A_2(1, \infty)) \newline&lt;br &#x2F;&gt;
&amp;amp;= (r_1(r_1-1) \cdot 1) + ((1 - r_1) \cdot 2) + (r_1 \cdot 3)&lt;br &#x2F;&gt;
\end{align*}&lt;&#x2F;p&gt;
&lt;p&gt;Finally, the prover send the following values to the verifier&lt;&#x2F;p&gt;
&lt;p&gt;$$s_2(\infty) = l_2(\infty)\cdot t_2(\infty)\quad\text{and}\quad s_2(\infty) = l_2(\infty)\cdot t_2(\infty)$$&lt;&#x2F;p&gt;
&lt;p&gt;(an actual prover replaces the challenge $r_1$ and produces a numerical output to hand in to the verifier and this is it for the first two rounds)&lt;&#x2F;p&gt;
&lt;h2 id=&quot;rounds-after-l-0&quot;&gt;Rounds After $l_0$&lt;&#x2F;h2&gt;
&lt;p&gt;Once the optimized rounds using pre-computation are finished, the algorithm switches its strategy for the remainder of the protocol.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Transition Phase (Round $l_0 + 1$)**  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The objective of this single round is to switch from the ’‘fast mode’’ of pre-computation to the ’‘standard’’ linear mode. The prover computes the evaluations of the polynomials $p_k$ with the first $l_0$ variables already fixed to the challenges $(r_1, \dots, r_{l_0})$. The result of this phase is the creation of the data arrays (called $P_k$) that will be used in the final rounds.
* &lt;strong&gt;Final Phase (Rounds $l_0+2$ to $l$)&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
From this point on, the protocol follows the standard linear sum-check algorithm (similar to Algorithm 1 or 5). In each of these rounds:&lt;br &#x2F;&gt;
i. The prover uses the current arrays $P_k$ to compute and send its message.&lt;br &#x2F;&gt;
ii. It receives a new challenge $r_i$.&lt;br &#x2F;&gt;
iii. It uses the challenge to combine pairs of entries in the arrays, &lt;strong&gt;halving their size&lt;&#x2F;strong&gt; and preparing everything for the next round.&lt;&#x2F;p&gt;
&lt;p&gt;This halving process continues until the last round, where the arrays are so small that the problem is reduced to a single final check.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Whirlaway: Multilinear STARKs using WHIR as polynomial commitment scheme</title>
          <pubDate>Fri, 29 Aug 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/whirlaway-multilinear-starks-using-whir-as-polynomial-commitment-scheme/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/whirlaway-multilinear-starks-using-whir-as-polynomial-commitment-scheme/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/whirlaway-multilinear-starks-using-whir-as-polynomial-commitment-scheme/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;Ethereum has been quickly evolving to become the financial backend of the World. Research and development in zero-knowledge proofs have allowed Ethereum to scale with rollups, by batching transactions off-chain and then posting an update of the accounts together with a cryptographic proof attesting to the validity of the transactions. While progress has been impressive, there remain still some challenges related to the rise of quantum computers (which would break elliptic curve cryptography, now a core primitive in Ethereum), increasing decentralization, and simplifying the protocol to reduce attack surface and possible bugs.&lt;&#x2F;p&gt;
&lt;p&gt;Ethereum presented in Devcon 2024 the roadmap for &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;leanroadmap.org&#x2F;&quot;&gt;Lean Ethereum&lt;&#x2F;a&gt; to research, define specifications, develop, test and deploy the future of Ethereum, which would allow the protocol to go on maintenance mode and avoid performing major changes. One of the key problems is related to post-quantum secure aggregatable signatures to replace the (elliptic curve-based) BLS signatures powering Ethereum’s consensus. While there are several candidates for post-quantum secure signatures, we should pay attention to those that can provide an efficient aggregation algorithm or whose verification can be proven efficiently using post-quantum secure proof systems. Hash-based signatures using SNARK (succinct, non-interactive argument of knowledge)-friendly hashes (such as Poseidon 2 or Rescue Prime Optimized) appear as promising candidates, since current state of the art provers are able to prove nearly 1,000,000 hashes per second on GPU. An important constraint is related to proof sizes, which should be as small as possible, to reduce the communication footprint between the nodes. Current security analysis shows that proof sizes targeting 128 bits of security using FRI are larger, which is why a different candidate is needed. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2024&#x2F;1586.pdf&quot;&gt;WHIR&lt;&#x2F;a&gt; provides a good candidate, even though it may be slower in concrete terms compared to FRI. It is not surprising, then, that the roadmap contains at least 4 elements in its roadmap targeting the primitives for post-quantum secure aggregatable signatures using succinct arguments of knowledge:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Poseidon cryptanalysis initiative.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Hash-based multisignatures&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Minimal zero-knowledge virtual machines (to handle proof aggregation)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Formal verification of virtual machines and specification of proof systems.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this post, we will cover the basics of WHIR used to prove the execution of a virtual machine as described by means of an algebraic intermediate representation (AIR). The way to derive the non-interactive argument of knowledge will be in a standard way, first by a polynomial interactive oracle proof, instantiating the oracle proof using a polynomial commitment scheme and using the Fiat-Shamir transformation. Later posts will focus on signature schemes and virtual machines. You can see the presentation of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;ethresear.ch&#x2F;t&#x2F;whir-for-ethereum&#x2F;22938&quot;&gt;WHIR at ethresearch&lt;&#x2F;a&gt; for further references, as well as the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2024&#x2F;1586.pdf&quot;&gt;WHIR paper&lt;&#x2F;a&gt;. For the specification of Whirlaway, see the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;TomWambsgans&#x2F;Whirlaway&#x2F;tree&#x2F;master&quot;&gt;repo&lt;&#x2F;a&gt;, as well as &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tcoratger&#x2F;whir-p3&#x2F;tree&#x2F;main&#x2F;src&#x2F;whir&#x2F;pcs&quot;&gt;whir-p3&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;multilinear-polynomials&quot;&gt;Multilinear polynomials&lt;&#x2F;h2&gt;
&lt;p&gt;A polynomial in $m$-variables is called multilinear if, in every monomial, the highest power of each indeterminate, $x_i$ is at most 1.&lt;&#x2F;p&gt;
&lt;p&gt;Given a set of evaluations of a function $f$ over $H^m$, there is a unique multilinear polynomial $\hat{f}$ over $H^m$ such that $\hat{f} (x) = f(x)$ for every $x \in H^m$. We can represent the same multilinear polynomial using different basis, the two most common being the monomial basis ($1, x_0, x_1, x_0 x_1, x_2, x_0 x_2, …$) and the Lagrange basis over $H^m$. For simplicity, we will henceforth take $H = {0 , 1}$. These are defined as follows,&lt;br &#x2F;&gt;
$\chi_k (x) = \mathrm{eq} ( k_b , x) = \prod_i ( k_{b,i} x_i + (\left\k_{b,i} - 1)(x_i - 1))$&lt;br &#x2F;&gt;
where $k_b$ is the binary decomposition of $k$, that is $k = \sum_i k_{b,i} 2^i$. The multilinear extension, give the evaluations of $f$ over $\{0, 1\}^m$,&lt;br &#x2F;&gt;
$\hat{f} (x) = \sum_{b \in \{0,1\}^m } f(b) \mathrm{eq} (b , x) = \sum_k f_k \chi_k (x)$&lt;&#x2F;p&gt;
&lt;p&gt;We can easily check that we can evaluate $\hat{f} (x)$ at any point by evaluating the Lagrange polynomials $\chi_k (x)$ and performing a scalar product between the vector of evaluations of $f$ and the vector of Lagrange basis polynomials,&lt;br &#x2F;&gt;
$\hat{f} (z) = \sum_k f_k \chi_k (z) = f^t \cdot \chi$&lt;&#x2F;p&gt;
&lt;p&gt;We can find a way of seeing a multilinear polynomial as a univariate polynomial by a suitable transformation. Given a polynomial in the multilinear basis,&lt;br &#x2F;&gt;
$$f(x_0 , x_1 , x_2 , \dots x_{ m - 1 } ) = a_0 + a_1 x_0 + a_2 x_1 + a_3 x_0 x_1 + a_4 x_2 + a_5 x_0 x_2 + a_6 x_1 x_2 + \dots a_{ 2^m - 1 } x_0 x_1 \dots x_{m - 1}$$&lt;br &#x2F;&gt;
If we let $x_0 = x$, $x_1 = x^2$, $x_2 = x^4$, $\dots$, $x_{m - 1} = x^{ 2^{ m - 1} }$, then&lt;br &#x2F;&gt;
$$f(x) = a_0 + a_1 x + a_2 x^2 + a_3 x x^2 + a_4 x^4 + a_5 x x^4 + a_6 x^2 x^4 + \dots a_{ 2^m - 1 } x x^2 x^4 … x^{ 2^{ m - 1 } }$$&lt;&#x2F;p&gt;
&lt;p&gt;Doing all the products, $f( x ) = \sum_j a_j x^j$&lt;&#x2F;p&gt;
&lt;p&gt;WHIR will make use of this transformation from the multilinear monomial basis to the univariate monomial basis. For example, the paper defines $\mathrm{pow} (z, m) = (z , z^2 , … z^{ 2^{ m - 1 } })$ which is used to evaluate the multilinear polynomial to $f(z)$.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sumcheck-protocol&quot;&gt;Sumcheck protocol&lt;&#x2F;h2&gt;
&lt;p&gt;The sumcheck protocol is an important building block for designing efficient interactive proofs. The sumcheck protocol is applied to proving statements of the form&lt;br &#x2F;&gt;
$\sum_{x \in H^\ell} f(x) = S$&lt;br &#x2F;&gt;
where $f(x)$ is a multivariate polynomial in $\ell$ variables and $H$ is a set (typically, ${0, 1}$). In other words, we want to show that the sum of the evaluations of $f$ over all the values in $H^\ell$ is equal to $S$. While this seems a bit restrictive or convoluted, computations can be reduced to some instance of this protocol via a suitable transformation. For example, the evaluation of the multilinear extension of a function at $z$ can be written precisely in this form, when using the Lagrange basis polynomials,&lt;br &#x2F;&gt;
$\hat{f} (z) = \sum_{b \in \{0,1\}^m } f(b) \mathrm{eq} (b , z)$&lt;br &#x2F;&gt;
The protocol allows the prover to convince the verifier that the sum is $S$ by sending to the verifier $\mathcal{O} (\ell)$ elements, and having the latter perform $\mathcal{O} (\ell)$ operations, plus a single evaluation to $f$ at a random point $(r_0, r_1, … r_{ \ell - 1})$. We can then compile this to a non-interactive succinct argument of knowledge using the Fiat-Shamir transformation and using a polynomial commitment scheme (PCS) to grant oracle access to $f(r_0, r_1, … r_{ \ell - 1})$ to the verifier.&lt;&#x2F;p&gt;
&lt;p&gt;The sumcheck protocol can be used several times to reduce complex claims into simpler ones, such as in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2019&#x2F;550&quot;&gt;Spartan&lt;&#x2F;a&gt;. We can also combine several sumchecks into a single one by batching them using random linear combinations. For example, say we want to prove that:&lt;br &#x2F;&gt;
$\sum_{x \in H^\ell} f_1 (x) = S_1$&lt;br &#x2F;&gt;
$\sum_{x \in H^\ell} f_2 (x) = S_2$&lt;br &#x2F;&gt;
We can have the verifier sample random scalars $\alpha_1, \alpha_2$ and we can run the sumcheck over&lt;br &#x2F;&gt;
$\sum_{x \in H^\ell} \left( \alpha_1 f_1 (x) + \alpha_2 f_2 (x) \right) = \alpha_1 S_1 + \alpha_2 S_2$&lt;br &#x2F;&gt;
This reduces the amount of elements that the prover needs to send to the verifier and the amount of work involved compared to running the two instances separately.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;overview-of-the-protocol&quot;&gt;Overview of the protocol&lt;&#x2F;h2&gt;
&lt;p&gt;In AIR, we have a set of polynomial constraints, such as:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $f_0 (x_7) = x_7 - a_k$ and which is valid for the first row. This is a boundary constraint.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $f_1 (x_0, x_1, x_2, y_0, y_1, y_2) = x_0 x_1 x_2 - y_1 y_2 y_3$ which should be valid for all consecutive rows, except the last one. This is an example of a transition constraint.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $f_2 (x_3) = x_3 (x_3 - 1)$ and valid over all rows, asserts that $x_3$ is a boolean variable. This constraint enforces a consistency condition.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Constraints are given by a multivariate polynomial with a set over which the constraint applies. The degree of the constraint (equal to the highest degree of the monomials) is important since it provides information on the number of points where we need to evaluate in order to fully determine the composition polynomial.&lt;&#x2F;p&gt;
&lt;p&gt;In ordinary STARKs, we can check the validity of the constraints by&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Interpolating the trace columns to obtain (univariate) trace polynomials.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Composing the trace polynomials with the constraint polynomials.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Dividing each constraint by the corresponding zerofier.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Use FRI to show that the result is close to a low-degree polynomial.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If we want to use multivariate polynomials, we need to perform some changes on how the protocol works. We will go step-by-step to show how everything works.&lt;&#x2F;p&gt;
&lt;p&gt;We will start with the trace table, $T$. We suppose that the trace has $2^n$ rows and $2^m$ columns. We can always pad tables not fulfilling this condition, or leverage the ideas of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2025&#x2F;917&quot;&gt;jagged PCS&lt;&#x2F;a&gt; to avoid padding. The table has $2^{n + m}$ elements, which we can view as evaluations of a polynomial $f_{trace}$ over $\{0, 1\}^{n + m}$. In Whirlaway, the elements are stored in row-major order.&lt;&#x2F;p&gt;
&lt;p&gt;The trace is committed as a single multilinear polynomial using WHIR as a polynomial commitment scheme. We will reduce all the polynomial checks to a single evaluation of this polynomial, which we can prove thanks to the polynomial commitment scheme.&lt;&#x2F;p&gt;
&lt;p&gt;We can always get the columns from the trace polynomial by multiplying with a suitable polynomial, in a similar way as we could recover the column from the flattened vector using a suitable matrix-vector product. The computation is correct if we can show that each of the constraint polynomials vanishes on the corresponding set. Suppose we need to show that $f_{16} (X_3 ) = X_3 (X_3 - 1) = 0$ for all rows, where $X_3$ indicates that we need to evaluate this polynomial using column 3. We call this polynomial $c_3 (x)$, where $c_3 ( j_b ) = c_{3j}$, where $j_b$ is the binary representation of $j$, with $j = 0, 1, … 2^n - 1$. The validity of the constraint is equal to showing that $c_3 (x) (c_3 (x) - 1) = 0$ for all the valid values of $x = j_b$.&lt;&#x2F;p&gt;
&lt;p&gt;We apply a variant of the sumcheck protocol, called the zerocheck to show that all the evaluations are zero over the set:&lt;br &#x2F;&gt;
$$\sum_{ x \in \{0,1\}^{n}} \mathrm{eq} (\tau,x) c_3(x) (c_3 (x) - 1) = 0$$&lt;br &#x2F;&gt;
where $\tau$ is sampled at random by the verifier. Eventually, after applying the sumcheck protocol, the verifier is left with the check $\mathrm{eq} (\tau,r) c_3(r) (c_3 (r) - 1) = v_r$. The verifier can compute $\mathrm{eq} (\tau,r)$ efficiently, since it is a linear product of $n$ terms. For $c_3 (r)$, the verifier can query the oracle and he can finally carry out the multiplications. Showing that the evaluation is valid can be done using the PCS, but the problem is how does he know that $c_3 (r)$ is correct, given that the prover committed to $f_{trace} (x)$ and not to the individual columns?&lt;&#x2F;p&gt;
&lt;p&gt;The core idea is that we can run another instance of the sumcheck protocol, linking the trace polynomial with the columns and reducing the checks to a single point.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;small-detour-spartan&quot;&gt;Small detour - Spartan&lt;&#x2F;h3&gt;
&lt;p&gt;Whirlaway is a proof system based on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;solvable.group&#x2F;posts&#x2F;super-air&#x2F;#fnref:1&quot;&gt;SuperSpartan for AIR&lt;&#x2F;a&gt;, but we can gain an intuition on how it works by looking at other multivariate proof systems, such as Spartan. While there are some differences, the core principles remain similar. We will start with R1CS, which is a common way of representing circuits, where we have matrices $A, B, C$ (from $\mathbb{F}^{n \times m}$) and a vector $z = (w, 1, u)$, where $w$ is the witness vector, and $u$ is the instance vector such that&lt;br &#x2F;&gt;
$Az \circ Bz - Cz = 0$&lt;br &#x2F;&gt;
where $\circ$ denotes the Hadamard (component-wise) product of vectors. We can transform this into an instance of the sumcheck protocol, by noting the following:&lt;br &#x2F;&gt;
$$F (x) = \left( \sum_y A(x,y) z(y)\right) \left( \sum_y B(x,y) z(y)\right) - \left( \sum_y C(x,y) z(y)\right)$$&lt;br &#x2F;&gt;
$$\sum_x \mathrm{eq} (\tau , x) F(x) = 0$$&lt;br &#x2F;&gt;
We can have the prover do the work and provide $a(x) = \sum_y A(x,y) z(y)$, $b(x) = \sum_y B(x,y) z(y)$ and $c(x) = \sum_y C(x,y) z(y)$. The zerocheck can be reduced to&lt;br &#x2F;&gt;
$$\mathrm{eq} (\tau, r_x) F(r_x) = v_x = \mathrm{eq} (\tau, r_x) (a (r_x ) b (r_x) - c( r_x ))$$&lt;br &#x2F;&gt;
The prover can then show that $a (r_x ), b (r_x ), c( r_x )$ are correct by running the following sumchecks:&lt;br &#x2F;&gt;
$$\sum_y A(r_x , y) z(y) = a (r_x )$$&lt;br &#x2F;&gt;
$$\sum_y B(r_x , y) z(y) = b (r_x )$$&lt;br &#x2F;&gt;
$$\sum_y C(r_x , y) z(y) = c (r_x )$$&lt;&#x2F;p&gt;
&lt;p&gt;All these can be combined into a single check by taking random linear combinations,&lt;br &#x2F;&gt;
$$\sum_y \left(\alpha A(r_x , y) + \beta B(r_x , y) + \gamma C( r_x , y ) \right) z(y) = \alpha a (r_x ) + \beta b (r_x ) + \gamma c (r_x )$$&lt;&#x2F;p&gt;
&lt;p&gt;This avoids working with one large sumcheck and breaks it into one working with a linear combination of the columns and another with a linear combination of the rows. This idea is exploited in Whirlaway to first perform a zerocheck with the columns and then reducing the evaluation of the columns to the evaluation of the trace polynomial.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;Steps in the protocol:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Commit to the trace&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Compute the trace columns that are necessary to evaluate the transition constraints, $c_k^{up}$ and $c_k^{down}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Perform a zerocheck with those columns and the polynomial constraints, which reduces the verifier&amp;#39;s task to evaluating $c_k^{up}$ and $c_k^{down}$ at the random point $\delta$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Batch the evaluation claims for all the columns and perform the inner sumcheck.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. Find the multilinear extension of the columns&amp;#39; evaluations, evaluates at $z$ and checks that this matches the opening of the commitment to the trace at the point $(z, \delta)$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;whir&quot;&gt;WHIR&lt;&#x2F;h2&gt;
&lt;p&gt;WHIR is an interactive oracle proof of proximity to constrained Reed-Solomon codes. FRI is also an interactive oracle proof of proximity, but to Reed-Solomon codes. We can transform WHIR into a polynomial commitment scheme in the same way we transformed FRI into a PCS, via committing to the codewords using Merkle trees.&lt;&#x2F;p&gt;
&lt;p&gt;Before jumping into the actual protocol, we will begin with the definitions of error correcting codes.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Definition (error-correcting code)&lt;&#x2F;strong&gt; : An error-correcting code of length $n$ over an alphabet $A$ is a subset of $A^n$. In particular, a linear code over a finite field $\mathbb{F}$ is a subspace of $\mathbb{F}^n$.&lt;&#x2F;p&gt;
&lt;p&gt;Linear codes are important because they allow for efficient encoding, and linear combination of codewords results in a codeword.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Definition (interleaved code)&lt;&#x2F;strong&gt; : Given a code $C \subseteq A^n$, the $m$ -interleaved code is the code $C^m \subseteq { (A^m ) }^n$. Each element of a codeword is now an element of $A^m$.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1-smooth-reed-solomon-codes&quot;&gt;1. Smooth Reed-Solomon Codes&lt;&#x2F;h3&gt;
&lt;p&gt;Given a finite field $\mathbb{F}$, a degree $d = 2^m$ and an evaluation domain $\mathcal{L} \subseteq \mathbb{F}^\star$, that must be a multiplicative &lt;em&gt;coset&lt;&#x2F;em&gt; whose order $n$ is a power of two, we define&lt;br &#x2F;&gt;
$$RS \left[\mathbb{F}, \mathcal{L}, m \right] = \{ f: \mathcal{L} \to \mathbb{F} : &#x2F; : \exists g \in \mathbb{F}^{ \leq d - 1} \left[X\right] : s.t. : f(x) = g(x) : \forall x \in \mathcal{L} \}.$$&lt;br &#x2F;&gt;
In other words, it represent all the evaluations that come from a polynomial of small degree. In proof systems, the prover claims that a funtion $f$ (or a its evaluations) is in $RS\left[\mathbb{F}, \mathcal{L}, m\right]$ to convince the verifier that $f$ is polynomial, showing that the function is close to a polynomial of degree $d - 1$.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Let’s recall what is a &lt;em&gt;coset&lt;&#x2F;em&gt; : For example, in Stark101 we have a trace of one column of length 1023, so we define as an evaluation domain a subgroup $G \subseteq \mathbb{F}^\star$ with order $|G| = 1024$. Then we interpolate and want to extend the domain eigth times larger (blowup factor 8), creating a Reed-Solomon error correction code. We take a subgroup $H \subseteq \mathbb{F}^\star$ with $|H| = 8192$, and define as the LDE the &lt;em&gt;coset&lt;&#x2F;em&gt; of $H$ $$wH = \{ w \cdot h_1, \ldots, w \cdot h_{8192} \}$$ with $w$ the generator of $\mathbb{F}^\star$.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;2-multilinear-reed-solomon-codes&quot;&gt;2. Multilinear Reed-Solomon Codes:&lt;&#x2F;h3&gt;
&lt;p&gt;Equivalently, such Reed–Solomon codes can be viewed as evaluations of multilinear polynomials in m variables:&lt;&#x2F;p&gt;
&lt;p&gt;$$\begin{align*}&lt;br &#x2F;&gt;
RS\left[\mathbb{F}, \mathcal{L}, m\right] &amp;amp;= \{ f: \mathcal{L} \to \mathbb{F} : &#x2F; : \exists g \in \mathbb{F}^{ &amp;lt; d} [X] : s.t. : f(x) = g(x) : \forall x \in \mathcal{L} \} \newline&lt;br &#x2F;&gt;
&amp;amp;= \{ f: \mathcal{L} \to \mathbb{F} : &#x2F; : \exists \hat f \in \mathbb{F}^{\leq 1} [X_0, \ldots, X_{m-1}] : s.t. : f(x) = \hat f(x^{ 2^{0} }, x^{ 2^{1} }, \ldots, x^{ 2^{ m - 1 } }) : \forall x \in \mathcal{L}\}&lt;br &#x2F;&gt;
\end{align*}$$&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;&#x2F;strong&gt; If $m =3$, $2^m - 1 = 7$ and $2^{m - 1} = 4$. We can represent a univariate polynomial $g$ of degree $7$ as a 3-variable polynomial $\hat f$. Indeed we just need three variables $X_0, X_1, X_2$, since $x_0 \cdot x_1 \cdot x_2 = x^1 \cdot x^2 \cdot x^4 = x^7.$ And in the other way, if we have a 3-variable polynomial $\hat f$, we can represent it as a univariate polynomial $g$ of degree $7$: The maximum degree obtained is in $x_0 \cdot x_1 \cdot x_2 = x^7.$ For example, the polynomial $$g(x) = a_0 + a_3x^3 + a_6x^6$$&lt;br &#x2F;&gt;
is equivalent to the polynomial&lt;br &#x2F;&gt;
$$\hat f(x_0, x_1, x_2) = a_0 x_0 + a_1 x_0 x_2 + a_2 x_1 x_2$$&lt;&#x2F;p&gt;
&lt;h3 id=&quot;3-constrained-reed-solomon-code&quot;&gt;3. Constrained Reed–Solomon Code:&lt;&#x2F;h3&gt;
&lt;p&gt;It is a Smooth Reed-Solomon Code with an additional constraint. Given a weight polynomial $\hat w \in \mathbb{F} \left[Z, X_1, \ldots, X_m \right]$ and a target $\sigma \in \mathbb{F}$, we additionaly ask&lt;br &#x2F;&gt;
$$ \sum_{b \in \{0, 1 \}^m} \hat w(\hat f(b), b) = \sigma.$$&lt;&#x2F;p&gt;
&lt;p&gt;This can help enforce a particular evaluation of the polynomial (which reduces the number of codewords that could simultaneously be close to $f$ and fulfill the condition) or show that the polynomial has zeros over some set.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;why-do-we-use-this&quot;&gt;Why do we use this?&lt;&#x2F;h4&gt;
&lt;p&gt;Given an evaluation point $r = (r_1, \ldots, r_m) \in \mathbb{F}^m$, we want to additionally constrain that $$\hat f (r) = \sigma.$$&lt;br &#x2F;&gt;
So if we choose&lt;br &#x2F;&gt;
$$\hat w(Z, X_1, \ldots X_m) = Z \cdot eq( (X_1, \ldots, X_m), (r_1, \ldots, r_m)),$$&lt;br &#x2F;&gt;
then we have&lt;br &#x2F;&gt;
$$ \sigma = \sum_{b \in \{0, 1 \}^m} \hat w(\hat f(b), b) = \sum_{b \in \{0, 1 \}^m} \hat f(b) \cdot eq( b, r) = \hat f(r).$$&lt;&#x2F;p&gt;
&lt;h2 id=&quot;whir-protocol&quot;&gt;WHIR Protocol&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;preliminary-notations&quot;&gt;Preliminary notations&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $\rho := \frac{ 2^m }{n}$ is the _rate of the code_ , where $n = |\mathcal{L}|$ and $m$ is the number of variables.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $\mathcal{L}^{ (i) } = \\{x^i : x \in \mathcal{L} \\}$. Since $\mathcal{L}$ is smooth, if $i$ is a power of two, then $|\mathcal{L}^{(i)}| = |\mathcal{L}| &#x2F; i.$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $k &amp;gt; 1$ is the _folding parameter_.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;the-basic-idea&quot;&gt;The basic idea&lt;&#x2F;h3&gt;
&lt;p&gt;Each WHIR iteration will reduce the task of testing&lt;br &#x2F;&gt;
$$f \in C = CRS\left[\mathbb{F}, \mathcal{L}, m, \hat w, \sigma \right]$$&lt;br &#x2F;&gt;
to the task of testing&lt;br &#x2F;&gt;
$$f \in C^\prime = CRS\left[\mathbb{F}, \mathcal{L}^{(2)}, m - k, \hat w^\prime , \sigma^\prime \right],$$&lt;br &#x2F;&gt;
where the size of the domain decreases from $n$ to $n&#x2F;2$, and the number of variables decreases from $m$ to $m - k$.&lt;&#x2F;p&gt;
&lt;p&gt;The WHIR protocol has $M = m&#x2F;k$ of these WHIR iterations, reducing the proximity test for&lt;br &#x2F;&gt;
$$C^{(0)} = C$$&lt;br &#x2F;&gt;
to a proximity test for&lt;br &#x2F;&gt;
$$C^{ (M) } = CRS\left[\mathbb{F}, \mathcal{L}^{ (2^M) }, O(1), \hat w^{ (M) }, \sigma^{ (M) } \right].$$&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Obs.&lt;&#x2F;em&gt; $O(1)$: It doesn’t depend on $m$ or $k$.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;protocol-steps&quot;&gt;Protocol Steps&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;1-sumcheck-rounds&quot;&gt;1. Sumcheck rounds&lt;&#x2F;h4&gt;
&lt;p&gt;The Prover and Verifier apply $k$ rounds of the sumcheck protocol for the claim&lt;br &#x2F;&gt;
$$\sum_{b \in \{0, 1 \}^m} \hat w(\hat f(b), b) = \sigma.$$&lt;&#x2F;p&gt;
&lt;p&gt;The protocol starts with&lt;br &#x2F;&gt;
$$ \hat w (Z, X) = Z \cdot eq(X, r)$$&lt;br &#x2F;&gt;
where $\hat f(r) = \sigma$.&lt;&#x2F;p&gt;
&lt;p&gt;The Prover sends the univariate round polynomials $h_1, \ldots k_k$, by fixing in each round the first variable and summing over the rest.&lt;&#x2F;p&gt;
&lt;p&gt;The Verifier samples $\alpha_1, \ldots, \alpha_k \in \mathbb{F}$, and checks $h_1 (0) + h_1 (1) = \sigma$ and $h_j(0) + h_j(1) = h_{j - 1}(\alpha_{j - 1})$.&lt;&#x2F;p&gt;
&lt;p&gt;This reduces the intitial claim to the claim&lt;br &#x2F;&gt;
$$\sum_{b \in \{0, 1 \}^{ m - k}} \hat w^\prime (\hat f(\alpha_1, \ldots, \alpha_k, b_{k +1 }, \ldots b_m), (\alpha_1, \ldots, \alpha_k, b_{k + 1}, \ldots b_m)) = h_k(\alpha_k),$$&lt;&#x2F;p&gt;
&lt;p&gt;In simpler notation:&lt;br &#x2F;&gt;
$$\sum_{b \in \{0, 1 \}^{ m - k}} \hat w^\prime(\hat f(\alpha, b), \alpha, b) = h_k (\alpha_k),$$&lt;&#x2F;p&gt;
&lt;h4 id=&quot;2-send-folded-function&quot;&gt;2. Send folded function&lt;&#x2F;h4&gt;
&lt;p&gt;The Prover sends a function $g: \mathcal{L}^{(2)} \to \mathbb{F}$. In the honest case, $$\hat g(X) = \hat f(\alpha, X),$$ then $\hat g \in \mathbb{F}^{\leq 1} \left[X_1, \ldots, X_{ m - k}\right]$, and $g$ represents the evaluations of $\hat g$ on the domain&lt;br &#x2F;&gt;
$$ g(x) = \hat f(\alpha_1^{ 2^0 }, \ldots, \alpha_k^{ 2^k }, x^{ 2^{ k + 1}}, \ldots, x^{ 2^m } ) : \forall x \in \mathcal{L}^{(2)}.$$&lt;&#x2F;p&gt;
&lt;h4 id=&quot;3-out-of-domain-sample-and-evaluation&quot;&gt;3. Out-of-domain sample and evaluation&lt;&#x2F;h4&gt;
&lt;p&gt;The Verifier samples and sends $z_0 \in \mathbb{F}$. The prover evaluates and sends $y_0 = \hat g(z_0)$.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Abuse of notation:&lt;&#x2F;em&gt; We denote $\hat g(z_0) = \hat g(z_0^{ 2^0 }, z_0^{ 2^1 }, \ldots, z_0^{ 2^{ m - k - 1}})$.&lt;&#x2F;p&gt;
&lt;p&gt;The out-of-domain sampling essentially forces the prover to choose one of the possible polynomials within a list of polynomials associated with the oracle.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;4-shift-queries-and-combination-randomness&quot;&gt;4. Shift queries and combination randomness&lt;&#x2F;h4&gt;
&lt;p&gt;The Verifier samples and sends $z_1, \ldots, z_t \in \mathcal{L}^{ (2^k) }$, where $t$ is the number required in this WHIR iteration, determined by the security parameter $\lambda$. Then for each $i \in \{1, \ldots t\}$, the Verifier queries f and obtains&lt;br &#x2F;&gt;
$$y_i = \text{Fold}(f, \alpha) (z_i)$$&lt;br &#x2F;&gt;
Then, the Verifier samples and sends $\gamma \in \mathbb{F}$.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is the Fold function?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Folding of Reed–Solomon codes is a method for lowering the complexity of a code at a relatively small cost and lies at the core of IOPPs for Reed–Solomon codes.&lt;&#x2F;p&gt;
&lt;p&gt;Given $f: \mathcal{L} \to \mathbb{F}$ and $a \in \mathbb{F}$ we define $\text{Fold}(f, a): \mathcal{L}^{(2)} \to \mathbb{F}$ as follows: For each $z \in \mathcal{L}^{(2)}$&lt;&#x2F;p&gt;
&lt;p&gt;$$\text{Fold}(f, a) (z) = \frac{f(x) + f(- x)}{2} + a \cdot \frac{f(x) - f(- x)}{2x},$$&lt;&#x2F;p&gt;
&lt;p&gt;where $x$ is the point in $\mathcal{L}$ such that $z = x^2 = (- x)^2$.&lt;&#x2F;p&gt;
&lt;p&gt;Now, given a vector $\alpha = (\alpha_1, \ldots, \alpha_k) \in \mathbb{F}^k,$ we denote&lt;br &#x2F;&gt;
$$\text{Fold}(f, \alpha): \mathcal{L}^{ (2^{k}) } \to \mathbb{F}$$&lt;br &#x2F;&gt;
to the recursive folding on each of the entries in $\alpha$. That is:&lt;&#x2F;p&gt;
&lt;p&gt;$$\text{Fold}(f, (\alpha_j, \ldots, \alpha_k)) = \text{Fold}(\text{Fold}(f, \alpha_j), (\alpha_{j+1}, \ldots, \alpha_k))$$&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Example:&lt;&#x2F;em&gt; If $k = 3$, then&lt;br &#x2F;&gt;
$$\text{Fold}(f, (\alpha_1, \alpha_2, \alpha_3)) = \text{Fold}(\text{Fold}(f, \alpha_1), (\alpha_2, \alpha_3))$$&lt;&#x2F;p&gt;
&lt;p&gt;Let’s say $\text{Fold}(f, \alpha_1) = f_1$. Then,&lt;&#x2F;p&gt;
&lt;p&gt;$$\text{Fold}(\text{Fold}(f, \alpha_1), (\alpha_2, \alpha_3)) = \text{Fold}(f_1, (\alpha_2, \alpha_3)) = \text{Fold}(\text{Fold}(f_1, \alpha_2), \alpha_3)$$&lt;&#x2F;p&gt;
&lt;p&gt;Let’s say $\text{Fold}(f_1, \alpha_2) = f_2$. Then,&lt;&#x2F;p&gt;
&lt;p&gt;$$\text{Fold}(\text{Fold}(f_1, \alpha_2), \alpha_3) = \text{Fold}(f_2, \alpha_3)$$&lt;&#x2F;p&gt;
&lt;p&gt;So in conclusion,&lt;br &#x2F;&gt;
$$\begin{align}&lt;br &#x2F;&gt;
\text{Fold}(f, (\alpha_1, \alpha_2, \alpha_3)) &amp;amp;= \text{Fold}(f_2, \alpha_3) \&lt;br &#x2F;&gt;
&amp;amp;= \text{Fold}(\text{Fold}(\text{Fold}(f, \alpha_1), \alpha_2), \alpha_3)&lt;br &#x2F;&gt;
\end{align}$$&lt;&#x2F;p&gt;
&lt;h4 id=&quot;6-recursive-claim&quot;&gt;6. Recursive claim&lt;&#x2F;h4&gt;
&lt;p&gt;Both Prover and Verifier define the new weight polynomial and target&lt;br &#x2F;&gt;
$$\hat w^\prime (Z, X) = \hat w(Z, \alpha, X) + Z \cdot \sum_{i = 0}^t \gamma^{i + 1} \cdot \text{eq}(z_i, X)$$&lt;br &#x2F;&gt;
$$\sigma’ = \hat h(\alpha_k) + \sum_{i = 0}^t \gamma^{i+1} \cdot y_i$$&lt;&#x2F;p&gt;
&lt;p&gt;and recurse on the claim that&lt;br &#x2F;&gt;
$$g \in CRS\left[\mathbb{F}, \mathcal{L}^{(2)}, m - k, \hat w^\prime, \sigma^\prime \right].$$&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why this weight and this target?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We want to see how this iteration replace the claim&lt;br &#x2F;&gt;
$$f \in C = CRS\left[\mathbb{F}, \mathcal{L}, m, \hat w, \sigma\right]$$ to the claim $$g \in C^\prime = CRS\left[\mathbb{F}, \mathcal{L}^{(2)}, m-k, \hat w^\prime, \sigma^\prime\right].$$&lt;br &#x2F;&gt;
First, note that $\hat w \in \mathbb{F} \left[Z, X_1, \ldots, X_m\right]$ and $\hat w^\prime \in \mathbb{F}\left[Z, X_1, \ldots, X_{ m - k }\right]$.&lt;&#x2F;p&gt;
&lt;p&gt;If the Prover is honest and $f \in C$, why does $g \in C^\prime$?&lt;&#x2F;p&gt;
&lt;p&gt;On one hand, $g \in RS\left[\mathbb{F}, \mathcal{L}^{(2)}, m - k\right]$ because $\hat g \in \mathbb{F}^{\leq 1} \left[X_1, \ldots, X_{ m - k }\right]$ is such that $g(x) = \hat f(\alpha_1^{ 2^0 }, \ldots, \alpha_k^{ 2^k }, x^{ 2^{ k + 1 }}, \ldots, x^{ 2^m } )$.&lt;&#x2F;p&gt;
&lt;p&gt;On the other hand, we need to check the sum constraint: We want to prove that&lt;br &#x2F;&gt;
$$\sum_{b \in \{0, 1 \}^{ m - k}} \hat w^\prime (\hat g(b), b) = \sigma^\prime .$$&lt;br &#x2F;&gt;
Let’s see:&lt;br &#x2F;&gt;
$$\sum_{b \in \{0, 1 \}^{ m - k}} \hat w^\prime (\hat g(b), b) = \sum_{b \in \{0, 1 \}^{ m - k}} \hat w(\hat f(\alpha, b), (\alpha, b)) + \hat f(\alpha, b) \sum_{i = 0}^t \gamma^{i + 1} \cdot eq(z_i, b)$$&lt;br &#x2F;&gt;
$$\sigma^\prime = \hat h(\alpha_k) + \sum_{i = 0}^t \gamma^{ i + 1} \cdot y_i$$&lt;&#x2F;p&gt;
&lt;p&gt;Since&lt;br &#x2F;&gt;
$$\hat h(\alpha_k) = \sum_{b \in \{0, 1 \}^{ m - k}} \hat w(\hat f(\alpha, b), (\alpha, b)),$$&lt;br &#x2F;&gt;
we just need to check that&lt;br &#x2F;&gt;
$$\sum_{i = 0}^t \gamma^{i+1} \cdot y_i = \sum_{b \in \{0, 1 \}^{ m - k}} \hat f(\alpha, b) \cdot \sum_{i = 0}^t \gamma^{i + 1} \cdot eq(z_i, b),$$&lt;br &#x2F;&gt;
where&lt;br &#x2F;&gt;
$$\sum_{i = 0}^t \gamma^{i + 1} \cdot y_i = \gamma \cdot \hat f(\alpha, z_0) + \sum_{i = 1}^t \gamma^{i + 1} \cdot \text{Fold}(f, \alpha)(z_i).$$&lt;&#x2F;p&gt;
&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;&#x2F;h2&gt;
&lt;p&gt;In upcoming posts, we will be covering several aspects related to the security of WHIR, its use as a proving backend for efficient post-quantum secure signature aggregation and possible improvements to reduce proof size and proving time.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Optimizing Sumcheck</title>
          <pubDate>Thu, 28 Aug 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/optimizing-sumcheck/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/optimizing-sumcheck/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/optimizing-sumcheck/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;In this article we review some of the optimizations for the SUMCHECK protocol as discussed in the recent article by Bagad, Dao, Domb and Thaler. The authors tackle the problem of &lt;em&gt;disproportionate cost of field multiplications&lt;&#x2F;em&gt;. In many SNARK applications, the sum-check protocol operates over &lt;em&gt;extension fields&lt;&#x2F;em&gt; , which are much larger than their &lt;em&gt;base fields&lt;&#x2F;em&gt;. While the actual values being summed or computed are often “small” (e.g., 32-bit integers or elements of the smaller base field), multiplications involving elements from the larger extension field (large-large (ll) multiplications) are significantly more expensive than those within the smaller base field (small-small (ss) multiplications). This cost disparity can be substantial, sometimes orders of magnitude.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;quick-review-of-the-sumcheck-protocol&quot;&gt;Quick review of the SUMCHECK Protocol&lt;&#x2F;h2&gt;
&lt;p&gt;As the reader might already know, the SUMCHECK protocol is a fundamental interactive proof system in verifiable computing and cryptography first introduced by Lund, Fortnow, Karloff, and Nisan around 1990-1991. We will begin by broadly describing its purpose and typical usage and then we’ll start looking into details of implementation where some clever observations can lead to an enhanced performance. The reader familiar with the protocol can safely skip the first section; those who want a quick refresher are invited to read.&lt;&#x2F;p&gt;
&lt;p&gt;The primary purpose of the SUMCHECK Protocol is for a &lt;em&gt;prover (P)&lt;&#x2F;em&gt; to convince a &lt;em&gt;verifier (V)&lt;&#x2F;em&gt; that a &lt;em&gt;large sum of polynomial evaluations&lt;&#x2F;em&gt; equals a specified value, without the verifier having to compute the entire sum herself. This sum is typically over all inputs in the &lt;em&gt;Boolean hypercube&lt;&#x2F;em&gt; , $\{0,1 \}^l$, for an $l$-variate polynomial $g$.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The core benefit for the verifier is a drastic reduction in computational work: the verifier could compute the sum by evaluating the polynomial at all $2^n$ possible inputs. However, using the SUMCHECK Protocol, the &lt;em&gt;verifier ultimately only needs to evaluate the polynomial at a single, randomly chosen point&lt;&#x2F;em&gt; in a larger finite field. This random point is selected from a “much bigger space” than just $\{0,1\ }^l$.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The protocol proceeds through an interactive series of rounds between the prover and the verifier:&lt;br &#x2F;&gt;
1. &lt;strong&gt;Initial Claim:&lt;&#x2F;strong&gt; At the start, the prover sends a value, $C_1$, which is claimed to be equal to the desired sum $H$.&lt;br &#x2F;&gt;
2. &lt;strong&gt;Iterative Reduction:&lt;&#x2F;strong&gt; The protocol involves $n$ rounds (where $n$ is the number of variables in the polynomial). In each round $j$ (from 1 to $l$):&lt;br &#x2F;&gt;
- The &lt;em&gt;prover sends a univariate polynomial&lt;&#x2F;em&gt; , $g_j(X_j)$, which is claimed to represent a partial sum of the original polynomial where the first $j-1$ variables have been “bound” to random values chosen by the verifier in previous rounds, and the $j$-th variable is left free. This process “gets rid of one variable in the sum check” in each round.&lt;br &#x2F;&gt;
- The &lt;em&gt;verifier performs consistency checks&lt;&#x2F;em&gt; on the received polynomial, notably checking if the current polynomial is consistent with the value established in the previous round (e.g., $C_1 = g_1(0) + g_1(1)$ in Round 1, and $g_{j - 1}(r_{j - 1}) = g_j(0) + g_j(1)$ in subsequent rounds). The verifier also checks that the degree of $g_j (X_j)$ is not too high.&lt;br &#x2F;&gt;
- If checks pass, the &lt;em&gt;verifier chooses a new random field element, $r_j$&lt;&#x2F;em&gt; , and sends it to the prover. This random choice serves to probabilistically verify the polynomial sent by the prover.&lt;br &#x2F;&gt;
3. &lt;strong&gt;Final Check:&lt;&#x2F;strong&gt; In the last round ($l$), the prover sends a univariate polynomial $g_l (X_l)$ which should be the original polynomial $g$, evaluated at all the random $r$ values chosen so far for the first $l - 1$ variables. The verifier then picks a final random $r_l$ and directly evaluates the original polynomial $g$ at the complete random point $(r_1, \dots, r_l)$, comparing this result to $g_l(r_l)$. If all checks pass, the verifier accepts the initial sum.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;A significant feature of the protocol is that the &lt;em&gt;verifier’s messages are simply random field elements&lt;&#x2F;em&gt; , independent of the input polynomial $g$ (except for needing an upper bound on its degree in each variable and the ability to evaluate it at a random point).&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Before jumping under the hood, let’s talk notation. For brevity and to make our life easier, we will simplify notations when the number of variables and involved dimensions are clear from the context. In this article we concentrate in polynomials in $\ell$ variables $X_1, X_2,\ldots X_{\ell}$, but for simplicity we adopt&lt;&#x2F;p&gt;
&lt;p&gt;$$f(X_1, X_2 , \ldots X_{\ell}) = f(X)$$&lt;&#x2F;p&gt;
&lt;p&gt;as standard notation. When these $\ell$ variables get partitioned, we also use a single letter to denote its limbs, say we split $X$ in three parts&lt;&#x2F;p&gt;
&lt;p&gt;$$(X_1, X_2 ,\ldots X_{\ell}) = (Y_1 , Y_2, \ldots Y_{i - 1},X_i, x^\prime_{i + 1},\ldots x^\prime_{\ell})$$&lt;&#x2F;p&gt;
&lt;p&gt;we simply use $(Y, X_i , x^\prime)$ to reduce cumbersome indexing.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-setting&quot;&gt;The setting&lt;&#x2F;h3&gt;
&lt;p&gt;The authors focus on a specific setting for the SUMCHECK, useful in various contexts: they narrow their attention to the case where the polynomial $g$ object of the SUMCHECK claim can be written as a product of $d$ multilinear polynomials&lt;&#x2F;p&gt;
&lt;p&gt;$$g(X) = \prod\limits_{k = 1}^d p_k(X)$$&lt;&#x2F;p&gt;
&lt;p&gt;where by multilinear polynomial we mean a $\ell$ variate polynomial such that each of its monomials has the following feature: each variable is raised to a power which is either 0 or 1. These polynomials are of great use and appear throughout field theory literature in different guises and recently re emerged as useful objects in Ben Diamond and Jim Posen’s effort BINIUS. For the unfamiliar reader, we recommend giving a quick read to our self-contained primer on these objects, &lt;a href=&quot;&#x2F;multilinear-polynomials-survival-kit&#x2F;&quot;&gt;Multilinear polynomials: a basic survival guide&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-closer-look&quot;&gt;A closer look&lt;&#x2F;h2&gt;
&lt;p&gt;The key observation in the optimizations considered dwells on the realization that the polynomial sent in the $i - th$ round by the prover:&lt;&#x2F;p&gt;
&lt;p&gt;$$s_i (X_i) = \sum\limits_{x^\prime \in \{0,1\}^{\ell - i}} \prod\limits_{ k = 1 }^d p(r, X_i ,x^\prime)$$&lt;&#x2F;p&gt;
&lt;p&gt;is indeed a sum of univariate polynomials on the variable $X_i$. The way polynomials are handed over between prover and verifier is usually by means of passing their evaluations on an adequate set. From the evaluations of $s_i$ on a a sufficiently large set, the verifier is able to reconstruct the polynomial. from the data received.&lt;&#x2F;p&gt;
&lt;p&gt;How big should the evaluation set be? Well, this question was answered many many years ago by the Fundamental Theorem of Algebra: for a polynomial $f$ of degree $deg(f)$ it suffices to have $deg(f) + 1$ evaluations to fully reconstruct its coefficients. So the prover needs to send $deg(s_i)_{i + 1}$ evaluations to the verifier, and now the problem becomes sending the elements&lt;&#x2F;p&gt;
&lt;p&gt;$$s_i (u) = \sum\limits_{x^\prime \in \{0,1\}^{\ell -i }}\prod\limits_{ k = 1}^d p(r,u,x^\prime)$$&lt;&#x2F;p&gt;
&lt;p&gt;for all $u$ in a set of size at least $deg(s_i)_i+1$.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-key-insight&quot;&gt;The key insight&lt;&#x2F;h3&gt;
&lt;p&gt;The key insight is that the elements being summed for each $s_i (u)$, namely&lt;&#x2F;p&gt;
&lt;p&gt;$$\prod\limits_{ k = 1 }^d p_k(r,u,x^\prime)$$&lt;&#x2F;p&gt;
&lt;p&gt;are not only products of evaluations of multilinear factors, but also: there are &lt;em&gt;different types of evaluations going on&lt;&#x2F;em&gt; in each summand:&lt;&#x2F;p&gt;
&lt;p&gt;i. On the one hand, factors $p_k$ are evaluated at $r = (r_1 ,r_2 ,\ldots r_{i - 1})$ in its first $i - 1$ variables - these evaluations involve interaction with the verifier since they employ random elements from a much bigger space than the boolean cube (typically a field extension of the base field) chosen by the verifier. Representation and algebraic manipulation of these challenges take up more memory and time than the demanded by the base field. In the context of BDDT, they involve $\frak{ll}$ and $\frak{ls}$ (large-large and large-small) multiplications.&lt;br &#x2F;&gt;
ii. On the other hand we have $u$ which is simply a base field element and also the evaluation of the factors $p_k$ at points in the boolean hypercube $\{0,1\}^{ \ell - i}$ corresponding to the last $\ell - i$ variables: these evaluations need no interaction with the verifier and crucially, do not involve elements in an extension of the base field. These are considered $\frak{ss}$ multiplications since they are taken to be base field elements.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;This observation gives the following idea: if it were possible to de-couple such evaluations then there might be some margins for improving performance: evaluations not depending on the interaction with the verifier could be done offline as part of a pre-processing phase, and then the ones involving the random challenges could be tackled online…&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The good news is that Bagad, Dao Domb and Thaler succesfully pursue this stream of ideas by cleverly employing (once again) the notion of interpolation: a polynomial can be expressed as a sum of &lt;strong&gt;basis interpolation polynomials&lt;&#x2F;strong&gt; that can be &lt;strong&gt;precomputed&lt;&#x2F;strong&gt; and more importantly, defined on an arbitrary large enough subset of the &lt;strong&gt;base field&lt;&#x2F;strong&gt; ; then evaluations on any desired challenge can be computed evaluating these auxiliary polynomials instead of the original polynomial instead.&lt;&#x2F;p&gt;
&lt;p&gt;To see how this decoupling can be done, let’s go for a very very simple example. Suppose that we are asked by a verifier to evaluate a polynomial $f$ at a random challenge $r$. For concreteness, let&lt;&#x2F;p&gt;
&lt;p&gt;$$f(x) = 2x^2 - 3x + 1$$&lt;&#x2F;p&gt;
&lt;p&gt;Here’s how we use interpolation to perform the task: since $f$ has degree 2, we need at least 3 points to evaluate $f$. Let’s pick the set&lt;br &#x2F;&gt;
$${\{0, 1, 2\}}$$&lt;&#x2F;p&gt;
&lt;p&gt;First, we need to find the value of our polynomial $f(x)$ at each of these points.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $f(0) = 2(0)^2 - 3(0) + 1 = \mathbf{1}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $f(1) = 2(1)^2 - 3(1) + 1 = 0$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $f(2) = 2(2)^2 - 3(2) + 1 = 8 - 6 + 1 = \mathbf{3}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Secondly, we build the Lagrange basis for the set $\{0, 1, 2\}$: it has three degree 2 polynomials&lt;&#x2F;p&gt;
&lt;p&gt;$$\{L_0 ,L_1 ,L_2 \}$$&lt;br &#x2F;&gt;
that work just as the canonical basis: each basis polynomial $L_j(x)$ has the special property that&lt;&#x2F;p&gt;
&lt;p&gt;$$L_i (j) = 1\quad\text{ if } j = i,\quad L_i (j) = 0\quad\text{ if } j\neq i,$$&lt;&#x2F;p&gt;
&lt;p&gt;Lagrange’s formula for producing such polynomials is well known and produces&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **$L_0(x)$:** (associated with $x_0 = 0$):$$L_0(x) =0.5x^2 - 1.5x + 1$$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **$L_1(x)$:** (associated with $x_1 = 1$):$$L_1(x) = -x^2 + 2x$$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **$L_2(x)$:** (associated with $x_2 = 2$):$$L_2(x) = 0.5x^2 - 0.5x$$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;These three polynomials form the &lt;strong&gt;Lagrange basis&lt;&#x2F;strong&gt; for the set $\{0, 1, 2\}$.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, the Lagrange polynomial is constructed as a weighted sum of these basis polynomials, where each weight is the value of the function at the corresponding point. We have&lt;&#x2F;p&gt;
&lt;p&gt;$$f(x) = f(0) \cdot L_0 (x) + f(1) \cdot L_1 (x) + f(2) \cdot L_2(x)$$&lt;br &#x2F;&gt;
This is&lt;&#x2F;p&gt;
&lt;p&gt;$$f(x) = \mathbf{1} \cdot (0.5x^2 - 1.5x + 1) + \mathbf{0} \cdot (-x^2 + 2x) + \mathbf{3} \cdot (0.5x^2 - 0.5x)$$&lt;&#x2F;p&gt;
&lt;p&gt;Now we’re ready to observe that $f$ can be expressed as a combination of polynomials (that are &lt;strong&gt;independent of the choice of $r$&lt;&#x2F;strong&gt; and that are auxiliary respect to $f$) with weights being evaluations of $f$ at base field point chosen by the prover. In this sense, the computation of these scalars is also independent of the interaction with the verifier and can be done in a pre-processing phase.&lt;&#x2F;p&gt;
&lt;p&gt;It is only at this stage that the verifier hands the random challenge $r$ and &lt;strong&gt;the prover computes $f(r)$ not by evaluating $f$ itself but evaluating the basis polynomials $L_i$&lt;&#x2F;strong&gt; at $r$:&lt;&#x2F;p&gt;
&lt;p&gt;$$f(r) = f(0) L_0 (r) + f(1) L_1(r) + f(2) L_2(2)$$&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The take away is:&lt;&#x2F;strong&gt; evaluation of $f$ on the random challenges will be deflected to evaluation of auxiliary polynomials that can be precomputed and will concentrate the heavier computational burden.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Of course, this idea can be extrapolated to multivariate polynomials by the use of tensor products of univariate Lagrange bases. For instance, suppose we need to evaluate the polynomial&lt;&#x2F;p&gt;
&lt;p&gt;$$f(Y_1, Y_2) = Y_1 (2 + Y_2 )^2$$&lt;&#x2F;p&gt;
&lt;p&gt;It has degree 1 as polynomial in $Y_1$ and degree 2 as polynomial in $Y_2$. We will consider now interpolating $f$ over the grid $\{0,1,2\}^2$; the next step is to find bivariate polynomials that play the same role as the univariate Lagrange polynomials. It is no wonder that if we consider the univariate basis&lt;&#x2F;p&gt;
&lt;p&gt;$$\{L_0 ,L_1 ,L_2\}$$&lt;&#x2F;p&gt;
&lt;p&gt;and define $L_{i,j} (Y_1 ,Y_2) = L_i (Y_1) L_j (Y_2)$ then the collection&lt;&#x2F;p&gt;
&lt;p&gt;$$\mathcal{L} = \{L_{i,j}: (i,j)\in\{0,1,2\}^2\}$$&lt;&#x2F;p&gt;
&lt;p&gt;will verify&lt;&#x2F;p&gt;
&lt;p&gt;$$L_{i,j} (a,b) = 1\quad\text{ if }, (a,b) = (i,j),\quad L_{i,j}(a,b) = 0\quad\text{ if }, (a,b)\neq (i,j)$$&lt;&#x2F;p&gt;
&lt;p&gt;and so&lt;&#x2F;p&gt;
&lt;p&gt;$$f(Y_1,Y_2) = \sum\limits_{(i,j)\in \{0,1,2\}^2} f(i,j) L_{i,j}(Y_1, Y_2)$$&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pushing-forward&quot;&gt;Pushing forward&lt;&#x2F;h2&gt;
&lt;p&gt;So the previous discussion will come to fruition within the SUMCHECK protocol at the time of interpreting&lt;&#x2F;p&gt;
&lt;p&gt;$$\prod\limits_{ k = 1}^d p_k(r,X_i ,x^\prime)$$&lt;&#x2F;p&gt;
&lt;p&gt;for fixed $x^\prime$ in the boolean hypercube $\{0,1\}^{ \ell - i}$ and $u$ in a convenient subset of the base field as the evaluation of the polynomial&lt;&#x2F;p&gt;
&lt;p&gt;$$F_{u,x^\prime} (Y_1 ,Y_2 ,\ldots,Y_{i - 1}) = \prod\limits_{k = 1}^d p_k(Y,u,x^\prime)$$&lt;&#x2F;p&gt;
&lt;p&gt;at the random challenge $r = (r_1 ,r_2 ,\ldots r_{ i - 1})$. Again, for simplicity we will adopt the more reasonable notation&lt;&#x2F;p&gt;
&lt;p&gt;$$F(Y) = \prod\limits_{ k = 1}^d p_k(Y,u,x^\prime)$$&lt;&#x2F;p&gt;
&lt;p&gt;Also at this point, we will generically suppose that each of the factors $p_k$ factors indeed include $X_i$ as a variable; in that case, the polynomial $s_i (X_i)$ that the prover needs to evaluate has degree $d$ and therefore we need a subset of at least $d + 1$ elements to evaluate such a polynomial.&lt;&#x2F;p&gt;
&lt;p&gt;For concreteness, suppose we pick a subset $U_d$ in the base field with $d + 1$ points. We will then consider the grid&lt;&#x2F;p&gt;
&lt;p&gt;$$G_g = U_d\times\cdots\times U_d = U_d^i$$&lt;&#x2F;p&gt;
&lt;p&gt;to build our Lagrange multivariate polynomials $L_v(Y)$ with $v\in G_d$. For simplicity, we are ommiting $i$ from the notation in the grid.\medskip&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Now interpolating $F$ with the multivariate Lagrange basis will transform this $F$ into a sum indexed by a grid of points $v\in G_d$ with small coordinates, weighted with coefficients being the evaluations of $F$ at base field elements&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;$$F(Y) = \sum\limits_{v\in G_d} F(v) L_v (Y)$$&lt;&#x2F;p&gt;
&lt;p&gt;Now at the time of looking at $s_i (u)$, remember that we need to sum over the hypercube of the last $\ell - 1$ coordinates and that $u$ is now the evaluation of the $X_i$ variable. The point here is that we realize that &lt;strong&gt;the sum over the hypercube interacts nicely with the sum coming from the interpolation: we will now make explicit the dependence of F with $u$ and $x^\prime$&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;$$s_i (u) = \sum\limits_{x^\prime \in \{0,1\}^{ \ell - i}} F_{u,x^\prime }(r) = \sum\limits_{x^\prime \in \{0,1\}^{ \ell - i}} \sum\limits_{v\in G_d} F_{ u,x^\prime } (v) L_v(r) = \sum\limits_{v\in G_d} \left(\sum\limits_{ x^\prime\in \{0,1\}^{ \ell - i}} F_{u,x^\prime}(v)\right) L_v(r)$$&lt;&#x2F;p&gt;
&lt;p&gt;From this expression we are able to see why this strategy works: the desired values $s_i(u)$ to be sent to the verifier are simply linear combinations of precomputed interpolation polynomials involving large multiplications (since they depend on the random challenges) weighted by sums indexed by the hypercube, of pre-computed evaluations over base field grid vectors, this is, &lt;em&gt;small&lt;&#x2F;em&gt; coefficients.&lt;&#x2F;p&gt;
&lt;p&gt;The coefficients in this linear combination are termed &lt;strong&gt;accumulators&lt;&#x2F;strong&gt; , mainly because they are a sum. For each fixed $v\in G_d$ and $u$, then&lt;&#x2F;p&gt;
&lt;p&gt;$$\sum\limits_{x^\prime \in \{0,1\}^{ \ell - i}} F(v) = \sum\limits_{x^\prime \in \{0,1\}^{ \ell - 1}} \prod\limits_{ k = 1}^d p_k(v,u,x^\prime) = A_i(v,u)$$&lt;&#x2F;p&gt;
&lt;p&gt;None of these depend on interactions with the verifier and can be conveniently hanldled offline. The number of accumulators to be computed depends on the degree of the polynomial $s_i (X_i)$ to be sent, and that problem can be addressed generically by assuming it’s a degree $d$ polynomial or by refining at each round deciding how many factors indeed contain the interesting variable.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;optimizing-the-pre-computation-phase&quot;&gt;Optimizing the pre-computation phase&lt;&#x2F;h3&gt;
&lt;p&gt;Now much work can be done still in the pre-computation phase, due to the nature of the indexing of the elements in the grid and the structure of the coefficients. Authors propose an algorithm coined $idx4$ - simply a selection rule. Its function is to determine which accumulators $A_i (v,u)$ a product term contributes to, allowing that term to be calculated only once and then reused efficiently.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The Goal: Reusing Calculations.&lt;&#x2F;strong&gt; Instead of re-calculating all products for each accumulator, the optimization involves computing each $P$ just once and then distributing it to all corresponding accumulators. The $idx4$ function is the mechanism that decides “where each product $P$ goes”.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;You can think of $idx4$ as a pattern matching or deconstruction function. Its job is to take an evaluation prefix $\beta$ and see how many valid accumulator patterns it fits into.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Input:** A prefix $\beta = (\beta_1, \dots, \beta_{l})$, where each $\beta_j$ belongs to the set of evaluation points $U_d$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Process** : For each round $i$ (from $1$ to $l$), $idx4$ tries to decompose $\beta$ into three parts that match the structure of an accumulator $A_i (v,u)$: &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      1. $v = (\beta_1, \dots, \beta_{i-1})$: The prefix corresponding to the challenges from previous rounds.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      2. $u = \beta_i$: The evaluation point for the current round $i$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      3. $y = (\beta_{i+1}, \dots, \beta_{l})$: The suffix of the prefix.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **The Key Selection Condition:** The selection rule is simple: the deconstruction for a given round $i$ is only valid if the suffix $y$ is composed **exclusively of binary values (0s and 1s)**. If any element in $y$ is non-binary then the prefix $\beta$ does not contribute to any accumulator for round $i$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Output:** The function returns a set of all valid tuples $(i, v, u, y)$ that could be formed from the input $\beta$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This selection process is carried out within the pre-computation phase, the typical flow being as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. The algorithm iterates over every possible evaluation prefix $\beta \in (U_d)^{l}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. For a given $\beta$, it computes the product term $P = \prod_{ k = 1 }^{d} p_k(\beta, x&amp;#39;&amp;#39;)$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. It calls the function $idx4(\beta)$ to get the set of destination indices $\mathcal{I}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Finally, it iterates over each tuple $(i, v, u, y)$ in $\mathcal{I}$ and adds the value of $P$ to the corresponding accumulator $A_i (v,u)$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;choices-for-interpolation&quot;&gt;Choices for interpolation&lt;&#x2F;h2&gt;
&lt;p&gt;Our article expanded on the general principles of decoupling the different types of evaluations via Lagrange interpolation. However, BDDT dive deeper into the details and slightly modify the interpolation basis involved to exploit the fact that the factors of $g$ are indeed, &lt;em&gt;multilinear&lt;&#x2F;em&gt; polynomials.&lt;&#x2F;p&gt;
&lt;p&gt;The variant of Lagrange interpolation presented by the authors reconstructs a polynomial of degree $d$ using its evaluations at $d$ distinct points plus its leading (highest-degree) coefficient, instead of the typical $d + 1$ evaluations. This leading coefficient is termed the &lt;em&gt;evaluation at infinity&lt;&#x2F;em&gt; and is denoted as $s(\infty)$.&lt;&#x2F;p&gt;
&lt;p&gt;The formula used for interpolation then becomes:&lt;br &#x2F;&gt;
$$s(X) = a \cdot \prod_{ k = 1}^{d} (X - x_k ) + \sum_{k = 1}^{d} s(x_k ) \cdot \mathcal{L_{ \{x_i\},k}} (X)$$&lt;&#x2F;p&gt;
&lt;p&gt;Where:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $a$ is the leading coefficient of $s(X)$, also denoted $s(\infty)$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $x_1, \dots, x_d$ are the $d$ distinct evaluation points.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $s(x_k)$ is the evaluation of $s(X)$ at the point $x_k$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $\mathcal{L_{ \\{x_i\\},k}}(X)$ is the k-th Lagrange basis polynomial for the set of points $\\{x_1, \dots, x_d\\}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let’s cook up an example and show that this actually holds.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;toy-example-degree-2-polynomial&quot;&gt;Toy example: Degree 2 Polynomial&lt;&#x2F;h3&gt;
&lt;p&gt;Let’s take the polynomial $s(X) = 3X^2 - 5X + 2$. In the BDDT approach, to fully encode this polynomial we just need &lt;em&gt;only 2 evaluations and the leading coefficient&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. **We begin by gathering the necessary information:**&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * **Evaluation at infinity** : The leading coefficient is $a = 3$. Therefore, $s(\infty) = 3$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * **Evaluation points** : We choose two distinct points, for example, $x_1 = 0$ and $x_2 = 1$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * **Evaluations:**  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;a. $s(0) = 3(0)^2 - 5(0) + 2 = 2$&lt;br &#x2F;&gt;
b. $s(1) = 3(1)^2 - 5(1) + 2 = 0$
2. &lt;strong&gt;Now we construct the interpolation basis:&lt;&#x2F;strong&gt;
* The Lagrange basis polynomials for the points ${0, 1}$ are:&lt;br &#x2F;&gt;
a. $\mathcal{L_1} (X) = \frac{X - 1}{0 - 1} = 1-X$&lt;br &#x2F;&gt;
b. $\mathcal{L_2} (X) = \frac{X - 0}{1 - 0} = X$
* The interpolation formula for $d = 2$ is: $$s(X) = s(\infty) \cdot (X - x_1) (X - x_2) + s(x_1)\mathcal{L_1} (X) + s(x_2)\mathcal{L_2} (X)$$
* Substituting the values:&lt;br &#x2F;&gt;
$$s(X) = 3 \cdot (X - 0)(X - 1) + 2 \cdot (1 - X) + 0 \cdot (X)$$
* Simplifying:&lt;br &#x2F;&gt;
$$s(X) = 3(X^2 - X) + 2 - 2X$$&lt;br &#x2F;&gt;
$$s(X) = 3X^2 - 3X + 2 - 2X$$&lt;br &#x2F;&gt;
$$s(X) = 3X^2 - 5X + 2$$&lt;br &#x2F;&gt;
The result matches the original polynomial.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;For practical purposes, BDDT concentrates on an evaluation set of the form $$U_d = \{\infty,0,1,2,\ldots d - 1\}$$ to interpolate a degree $d$ polynomial.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;calculation-of-s-infty-for-a-product-of-polynomials&quot;&gt;Calculation of $s(\infty)$ for a Product of Polynomials&lt;&#x2F;h3&gt;
&lt;p&gt;The reason why this modification takes place is that leading coefficients of products of polynomials are always easy to compute: the distributive law ensures that&lt;&#x2F;p&gt;
&lt;p&gt;$$s(X) = p(X) q(X) \implies s(\infty) = p(\infty) q(\infty)$$&lt;br &#x2F;&gt;
this is - the leading coefficient of a product is the product of the leading coefficients. Moreover, for a linear polynomial $p_i(X)$, its leading coefficient can be calculated as the difference of its evaluations at 1 and 0: $p_i(1) - p_i(0)$.&lt;&#x2F;p&gt;
&lt;p&gt;Therefore, the formula is:&lt;br &#x2F;&gt;
$$s(\infty) = \prod_{i = 1}^{d} p_i(\infty) = \prod_{i = 1}^{d} (p_i (1) - p_i (0))$$&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Let $s(X) = p_1(X) \cdot p_2(X)$, where:&lt;br &#x2F;&gt;
- $p_1(X) = 2X + 3$&lt;br &#x2F;&gt;
- $p_2(X) = 5X - 4$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. **Calculate $p_i (\infty)$ for each factor:**&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * $p_1 (\infty) = p_1 (1) - p_1 (0) = (2(1) + 3) - (2(0) + 3) = 5 - 3 = 2$. (The leading coefficient of $p_1$ is 2).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * $p_2 (\infty) = p_2 (1) - p_2 (0) = (5(1) - 4) - (5(0) - 4) = 1 - (- 4) = 5$. (The leading coefficient of $p_2$ is 5).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. **Calculate $s(\infty)$:** $$s(\infty) = p_1(\infty) \cdot p_2(\infty) = 2 \cdot 5 = 10$$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. **Verification** :  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let’s multiply the polynomials to find $s(X)$ explicitly: $$s(X) = (2X + 3)(5X - 4) = 10X^2 - 8X + 15X - 12 = 10X^2 + 7X - 12$$&lt;&#x2F;p&gt;
&lt;p&gt;The leading coefficient of $s(X)$ is &lt;strong&gt;10&lt;&#x2F;strong&gt; , which confirms that the rule works perfectly.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Multilinear polynomials: survival kit</title>
          <pubDate>Tue, 26 Aug 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/multilinear-polynomials-survival-kit/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/multilinear-polynomials-survival-kit/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/multilinear-polynomials-survival-kit/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;In this article we briefly introduce a list of basic properties of multilinear polynomials that are convenient to have in mind when tackling a very interesting piece of work by Bagad, Dao, Domb and Thaler: “Speeding up SUM-CHECK proving”. The authors focus on a specific setting for the SUMCHECK protocol, useful in various contexts: they narrow their attention to the case where the polynomial $g$ object of the SUMCHECK claim can be written as a product of $d$ multilinear polynomials&lt;&#x2F;p&gt;
&lt;p&gt;$$g(X) = \prod\limits_{ k = 1 }^d p_k (X)$$&lt;&#x2F;p&gt;
&lt;p&gt;and proceed to craft a series of algorithms tayloring their time and memory usage. Before diving into their findings, it is maybe timely that we refresh some facts about these type of polynomials for future use.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;multilinear-polynomials-definition-and-basic-properties&quot;&gt;Multilinear polynomials: definition and basic properties&lt;&#x2F;h2&gt;
&lt;p&gt;For the rest of the article, fix a field $k$. By multilinear polynomial we mean a $\ell\geq 0$ variate polynomial $f\in k\left[X_1,\ldots X_\ell\right]$ such that each of its monomials has the following feature: each variable is raised to a power which is either 0 or 1. These polynomials are of great use and appear throughout field theory literature in different guises and recently re emerged as useful objects in Ben Diamond and Jim Posen’s effort BINIUS.&lt;&#x2F;p&gt;
&lt;p&gt;We will use $\mathcal{M_k} \left[X_1,\ldots X_\ell\right]$ to denote the collection of all multilinear polynomials of $\ell$ variables with coefficients in $k$. Examples of multilinear polynomials abound:&lt;&#x2F;p&gt;
&lt;p&gt;$$p(X_1 , X_2) = 2 + X_1 + X_1 X_2,\quad q(X_1,X_2,X_3) = 2x_3 + X_1 X_2 X_3 + X_1 X_2, , \text{etc}$$&lt;&#x2F;p&gt;
&lt;p&gt;It should be noticed that multilinear polynomials of $\ell$ indeterminates have degree bounded by $\ell$; naturally, $\mathcal{M_k} \left[X_1,\ldots X_\ell\right]$ is a vector subspace of $k\left[X_1, \ldots X_\ell \right]$: it is closed respect to addition and scalar multiplication.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;interpolation&quot;&gt;Interpolation&lt;&#x2F;h3&gt;
&lt;p&gt;One of the great features of multilinear polynomials is that they allow a neat way of replacing arbitrary functions over a very special domain. Cutting to the chase, &lt;em&gt;any&lt;&#x2F;em&gt; function $\varphi$ defined over the hypercube $\{ 0,1 \}^\ell$ can be interpolated with multilinear polynomials. This happens because the hypercube being discrete, it allows the identification of the function $\varphi$ with the list of its images ${\varphi(x): x \in \{0,1 \}^\ell}$ and crucially, for each $x$ in the hypercube we have a multilinear polynomial that takes the value 1 over $x$ and evaluates to zero elsewhere.&lt;&#x2F;p&gt;
&lt;p&gt;For example, take $b = (1,0,1,1) \in \{0,1 \}^4$. Then&lt;&#x2F;p&gt;
&lt;p&gt;$$\chi_b (X_1 , X_2 , X_3 , X_4 ) = X_1 (1 - X_2 ) X_3 X_4$$&lt;&#x2F;p&gt;
&lt;p&gt;is a multilinear polynomial evaluating to 1 over $b$ and to 0 elsewhere. Generally, for $b \in \{0,1 \}^\ell$, the multilinear polynomial having this property can be expressed as&lt;&#x2F;p&gt;
&lt;p&gt;$$\chi_b (X) = \prod_{ j = 1 }^{\ell} ( b_j X_j + (1 - b_j) (1 - X_j))$$&lt;&#x2F;p&gt;
&lt;p&gt;The reader may recall Lagrange interpolation in one variable and polynomials satisfying this sort of condition). In cyprographic lingo, these are sometimes called “equality polynomials” and commonly nomenclated as $eq(x,y)$. So how does this interpolation property work? Let’s cook up an example.&lt;&#x2F;p&gt;
&lt;p&gt;Suppose we are given the function&lt;&#x2F;p&gt;
&lt;p&gt;$$\varphi (X_1 ,X_2 ) = (1 + X_1) (X_1 + X_2)$$&lt;&#x2F;p&gt;
&lt;p&gt;As it is, this polynomial has degree 2 in $X_1$ so it is not a multilinear polynomial. However it can be interpolated over the cube $\{0,1 \}^2$, by the use of the equality or Lagrange polynomials: $\chi_b$ with $b$ in the boolean square $\{0,1 \}^2$.&lt;&#x2F;p&gt;
&lt;p&gt;\begin{align*}&lt;br &#x2F;&gt;
\varphi(X_1, X_2) =&amp;amp; \sum\limits_{ b \in \{0,1\}^2 } g(b) \chi_b (x) =\newline&lt;br &#x2F;&gt;
=&amp;amp; \varphi(0,0)(1 - X_1)(1 - X_2) + \varphi(1,0) X_1 (1 - X_2)\newline&lt;br &#x2F;&gt;
+&amp;amp; \varphi(0,1) (1 - X_1) X_2 + \varphi(1,1) X_1 X_2&lt;br &#x2F;&gt;
\end{align*}&lt;&#x2F;p&gt;
&lt;p&gt;where this equality is functionally understood: it is the equality of two functions over the boolean hypercube, one of which is a multilinear polynomial. Before getting carried away, lets state a fact&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Fact number 1:&lt;&#x2F;strong&gt; $\mathcal{M_\ell}$ is a vector space of dimension $2^\ell$ with basis the Lagrange polynomials&lt;&#x2F;p&gt;
&lt;p&gt;$$\mathcal{L_\ell} = \{ \chi_b : b\in \{0,1\}^\ell \}$$&lt;&#x2F;p&gt;
&lt;p&gt;As it is customarily done, there is an ordering of the dimension $\ell$ hypercube obtained by the binary expansion of the first $2^\ell$ non negative integers: if $0\leq m\leq 2^{\ell} - 1$ then&lt;&#x2F;p&gt;
&lt;p&gt;$$m = m_0 2^0 + m_1 2^1 + \cdots m_{ \ell - 1 } 2^{ \ell - 1}\quad m_i\in \{0,1 \}$$&lt;&#x2F;p&gt;
&lt;p&gt;we set the $m$-th basis polynomial to be the equality polynomial for the string $$(m_{ \ell - 1} ,\ldots m_1, m_0)$$ This will be the ordering we adopt for the Lagrange basis and the order we will use to obtain crucial information: the standard binary order. For those unfamiliar:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. The **first variable** , $X_1$, is associated with the **most significant bit (MSB)**.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. The **last variable** , $X_l$, is associated with the **least significant bit (LSB)**.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For example, for a 3-variable polynomial, $g(X_1, X_2, X_3)$, the hypercube coordinates are ordered as follows:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;strong&gt;Hypercube Point&lt;&#x2F;strong&gt; (Binary Representation)&lt;&#x2F;th&gt;&lt;th&gt;&lt;strong&gt;Polynomial Coordinates&lt;&#x2F;strong&gt; $(X_1, X_2, X_3)$&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;$000_2 = 0$&lt;&#x2F;td&gt;&lt;td&gt;$(0, 0, 0)$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$001_2 = 1$&lt;&#x2F;td&gt;&lt;td&gt;$(0, 0, 1)$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$010_2 = 2$&lt;&#x2F;td&gt;&lt;td&gt;$(0, 1, 0)$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$\dots$&lt;&#x2F;td&gt;&lt;td&gt;$\dots$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$111_2 = 7$&lt;&#x2F;td&gt;&lt;td&gt;$(1, 1, 1)$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Don’t fret, this is simply a choice to walk the cube and how we will consider the interpolation basis. For sake of clarity:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. One can easily verify that the basis&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$\mathcal{L_2} = \{ (1 - X_1) (1 - X_2), (1 - X_1) X_2, X_1 (1 - X_2), X_1 X_2 \}$$&lt;&#x2F;p&gt;
&lt;p&gt;interpolates the boolean hypercube in the sense that the $k$-th basis vector takes the value 1 over the binary representation of $k$ and takes the value 0 elsewhere.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. The basis for $\mathcal{M} \left[X_1 ,X_2 ,X_3 \right]$ is obtained by simply orderly taking from left to right each vector in $\mathcal{L_2}$ and multiplying it by ($1 - X_3$) first, and then secondly, by $X_3$. Then $\mathcal{L_3}$ consists of the collection&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $(1 - X_1) ( 1 - X_2 )( 1 - X_3)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $(1 - X_1) (1 - X_2) X_3$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $(1 - X_1) X_2 (1 - X_3)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $(1 - X_1) X_2 X_3$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $X_1 (1 - X_2) (1 - X_3)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $X_1 (1 - X_2) X_3$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $X_1 X_2 (1 - X_3)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $X_1 X_2 X_3$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;in this specific order.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;coordinates-and-evaluations-the-golden-link&quot;&gt;Coordinates and evaluations: the golden link&lt;&#x2F;h3&gt;
&lt;p&gt;What we just discussed in the previous section already sets multlinear polynomials and their basis in a different ground respect to other sets. In linear algebra for instance, the expression of a vector as a linear combination of a basis set involves building (and solving!) a system of linear equations. As much as we love systems of linear equations, finding the coordinates of the vector REQUIRES SOLVING the system and this obviously costs time and memory. It is for this reason that some basis are preferred over others: finding coordinates of vectors should be as easy as possible.&lt;&#x2F;p&gt;
&lt;p&gt;Concretely, if we wanted to represent $v = (2,3)$ as a combination of $(1,2)$ and $(5, - 7)$ we would be required to first build a system of equations and secondly, solving it dealing with all the numerical complexities involved (this is a small example but think of vectors with $2^{128}$ elements…).&lt;&#x2F;p&gt;
&lt;p&gt;It results in a different story altogether if now the vectors we want to use are $(1,0)$ and $(0,1)$: the canonical basis. Now the problem is almost trivially solved by eyeballing or directly, evaluating what the contents of $v$ are:&lt;&#x2F;p&gt;
&lt;p&gt;$$v = 2\cdot (1,0) + 3\cdot (0,1)$$&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is the precise situation we have with the equality polynomials: now coordinates in this basis are simply the evaluations of the function we want to interpolate. And this is great news because computers love to evaluate.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;This conversation yields&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Fact number 2:&lt;&#x2F;strong&gt; Coordinates of a function $f$ defined over the boolean hypercube $\{0,1 \}^\ell$ respect to the Lagrange basis $\mathcal{L_\ell}$ are simply its evaluations:&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;$$coords(f)= \left[f(b) \right]_{ b\in \{0,1 \}^\ell}$$&lt;&#x2F;p&gt;
&lt;p&gt;For instance, for the multilinear polynomial&lt;&#x2F;p&gt;
&lt;p&gt;$$g(X_1 , X_2) = 1 + X_1 + X_1 X_2$$&lt;&#x2F;p&gt;
&lt;p&gt;Then its coordinates in the interpolation basis are simply&lt;&#x2F;p&gt;
&lt;p&gt;$$g\longleftrightarrow coords(g) = \left[1,1,2,3 \right] = \left[g(0), g(1), g(2), g(3) \right]$$&lt;&#x2F;p&gt;
&lt;p&gt;where we exploited the ordering of teh cube and took the liberty of “evaluating $g$ at the integers $0\leq n\leq 2^2 - 1$”.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;tensorization-in-this-context&quot;&gt;Tensorization in this context&lt;&#x2F;h3&gt;
&lt;p&gt;One of the operations between polynomials that we learn in highschool is polynomial multiplication: for example, when given polynomials&lt;&#x2F;p&gt;
&lt;p&gt;$$X + 1\quad\text{and }\quad 2 + Y$$&lt;&#x2F;p&gt;
&lt;p&gt;we compute their product using the distributive law, juxtaposing indeterminates and using powers to abbreviate equal symbols juxtaposed:&lt;&#x2F;p&gt;
&lt;p&gt;$$(X + 1)( 2 + Y) = 2 X + XY + 2 + Y$$&lt;&#x2F;p&gt;
&lt;p&gt;and assuming the order of the symbols in monomial is irrelevant. When thinking of polynomials as vectors, we need a formalism to portray this exact operation. That formalism is called the tensor product and allows vector multiplication just as we know it; the field that studies tensor products is called multilinear algebra and is obviously an older brother of linear algebra. The symbol commonly found for the tensor product of vectors $v\in\mathbb{V}$ and $w\in\mathbb{W}$ is&lt;&#x2F;p&gt;
&lt;p&gt;$$v\otimes w\in \mathbb{V}\otimes\mathbb{W}$$&lt;&#x2F;p&gt;
&lt;p&gt;and we notice that $\mathbb{V}\otimes\mathbb{W}$ is a new vector space, constructed with $\mathbb{V}$ and $\mathbb{W}$ obviously called their tensor product. This product has all the properties we want to abstract, the distributive law being crucial for our needs:&lt;&#x2F;p&gt;
&lt;p&gt;$$v\otimes w + 2v.u \otimes w = (3v + u)\otimes w$$&lt;&#x2F;p&gt;
&lt;p&gt;All this in our setting is quite natural: if we set $\mathbb{V}$ the vector space of polynomials of degree at most 1 in the indeterminate $X_1$ and $\mathbb{W}$ the vector space of polynomials of degree at most 1 in the indeterminate $X_2$, then&lt;&#x2F;p&gt;
&lt;p&gt;$$\mathbb{V}\otimes \mathbb{W} = \mathcal{M} \left[X_1 \right]\otimes \mathcal{M} \left[X_2 \right] = \mathcal{M_2} \left[X_1,X_2 \right]$$&lt;&#x2F;p&gt;
&lt;p&gt;and more importantly, the tensor product of the basis yields a basis for the tensor product. The general theory guarantees that whenever $\mathcal{B}$ and $\mathcal{C}$ are basis for $\mathbb{V}$ and $\mathbb{W}$ respectively, then&lt;&#x2F;p&gt;
&lt;p&gt;$$\mathcal{B}\otimes\mathcal{C}={v_i\otimes w_j: 1\leq i\leq dim(\mathbb{V}), 1\leq j\leq dim(\mathbb{W})}$$&lt;&#x2F;p&gt;
&lt;p&gt;is a basis for the new vector space. However a choice of order for those vectors must be made. To our interest, it is convenient to order the tensor products of the basis vectors in a fashion compatible with the binary expansion; in the case of $dim(\mathbb{V})=dim(\mathbb{W})=2$ the basis we’re going to be looking at is simply&lt;&#x2F;p&gt;
&lt;p&gt;$$\mathcal{B}\otimes\mathcal{C}={v_1\otimes w_1, v_1\otimes w_2, v_2\otimes w_1,v_2\otimes w_2}$$&lt;&#x2F;p&gt;
&lt;p&gt;which is commonly referred to as the lexicographic order. In this sense, this basis works just fine: say you pick $z \in V \otimes W$ for instance&lt;&#x2F;p&gt;
&lt;p&gt;$$z = 2(v_1 \otimes w_1) + 5(v_1 \otimes w_2) + 3(v_2 \otimes w_1) - 1(v_2 \otimes w_2)$$&lt;&#x2F;p&gt;
&lt;p&gt;Its coordinate vector turns out to be $[2, 5, 3, -1]$. Moreover, since tensors are compatible with the distributive law, we are allowed to regroup the terms:&lt;&#x2F;p&gt;
&lt;p&gt;$$z = (2w_1 + 5w_2) \otimes v_1 + (3w_1 - 1w_2) \otimes v_2$$&lt;&#x2F;p&gt;
&lt;p&gt;The coefficients of this combination are the following elements of $V$:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Coefficient of $v_1$** : $c_1 = 2w_1 + 5w_2$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Coefficient of $v_2$** : $c_2 = 3w_1 - 1w_2$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;These coefficients, expressed in coordinates of the basis chosen for $\mathbb{W}$ are simply $[2, 5]$ and $[3, -1]$. The way the order for the tensor basis is chosen to recreate the fact:&lt;&#x2F;p&gt;
&lt;p&gt;$$\text{concat}(\text{coords}(c_1), \text{coords}(c_2)) = \text{concat}([2, 5], [3, -1]) = [2, 5, 3, -1]$$&lt;&#x2F;p&gt;
&lt;p&gt;In the context of multilinear polynomials, this discussion makes clear that these polynomials can be obtained by recursively tensoring vector spaces of polynomials of degree at most 1 in distinct variables: we have an algebraic characterization of the vector space of multilinear polynomials&lt;&#x2F;p&gt;
&lt;p&gt;$$\mathcal{M_\ell} \left[X_1,\ldots X_\ell \right] = \mathcal{M_\ell} \left[X_1,\ldots X_{ \ell - 1} \right]\bigotimes \mathcal{M}\left[X_\ell \right]$$&lt;&#x2F;p&gt;
&lt;p&gt;and moreover, exploiting the associativity of the tensor product we arrive at a very natural fact:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Fact number 3:&lt;&#x2F;strong&gt; Let $\{1,2,\ldots, \ell \} = J \bigcup I$ with $J,I$ disjoint. Then multilinear polynomials with indeterminates $X_1,\ldots X_\ell$ can be regarded as multlinear polynomials with indeterminates $X_j\in J$ and coefficients being multilinear polynomials in the indeterminates $X_i\in I$.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;To fix the idea, take a look at the polynomial&lt;&#x2F;p&gt;
&lt;p&gt;$$h = X_1+X_1 X_3 + 2X_2 X_3 X_4 + 2X_4$$&lt;&#x2F;p&gt;
&lt;p&gt;This naturally is a multilinear polynomial in $X_3$ and $X_4$, since they are raised to power at most 1. Using the Lagrange basis for multilinear polynomials in the variables $X_3$ and $X_4$&lt;&#x2F;p&gt;
&lt;p&gt;$$\{(1 - X_3) (1 - X_4), (1 - X_3 ) X_4, X_3 (1 - X_4), X_3 X_4 \}$$&lt;&#x2F;p&gt;
&lt;p&gt;we find the corresponding coefficients by making use of we what we already discussed: the coefficients will be polynomials in the remaining variables, $X_1$ and $X_2$ obtained by evaluating the original polynomial $h$ at the four points of the hypercube for $X_3$ and $X_4$.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Coefficient of $(1 - X_3) (1 - X_4)$:** We evaluate $h$ at $(X_3 = 0, X_4 = 0)$.  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$h(X_1, X_2, 0, 0) = X_1 + X_1(0) + 2 X_2 (0)(0) + 2(0) = X_1$$&lt;br &#x2F;&gt;
This is the coefficient for the first basis polynomial.
* &lt;strong&gt;Coefficient of $(1 - X_3) X_4$:&lt;&#x2F;strong&gt; We evaluate $h$ at $(X_3 = 0, X_4 = 1)$.&lt;br &#x2F;&gt;
$$h(X_1, X_2, 0, 1) = X_1 + X_1(0) + 2X_2 (0)(1) + 2(1) = X_1 + 2$$&lt;br &#x2F;&gt;
This is the coefficient for the second basis polynomial.
* &lt;strong&gt;Coefficient of $X_3 (1 - X_4)$:&lt;&#x2F;strong&gt; We evaluate $h$ at $(X_3 = 1, X_4 = 0)$.&lt;br &#x2F;&gt;
$$h(X_1, X_2, 1, 0) = X_1 + X_1(1) + 2X_2 (1)(0) + 2(0) = X_1 + X_1 = 2X_1$$&lt;br &#x2F;&gt;
This is the coefficient for the third basis polynomial.
* &lt;strong&gt;Coefficient of $X_3 X_4$:&lt;&#x2F;strong&gt; We evaluate $h$ at $(X_3 = 1, X_4 = 1)$.&lt;br &#x2F;&gt;
$$h(X_1, X_2, 1, 1) = X_1 + X_1(1) + 2X_2(1)(1) + 2(1) = X_1 + X_1 + 2X_2 + 2 = 2X_1 + 2X_2 + 2$$&lt;br &#x2F;&gt;
This is the coefficient for the fourth basis polynomial.&lt;&#x2F;p&gt;
&lt;p&gt;Putting it all together, the coordinates for $h$ viewed as a multilinear polynomial in the variables $X_3$ and $X_r$ is simply&lt;&#x2F;p&gt;
&lt;p&gt;$$\left[X_1, 2+X_1, 2X_1, 2 + 2X_1 + 2X_2 \right]$$&lt;&#x2F;p&gt;
&lt;p&gt;As the reader may already be thinking “but we can also compute the coordinates of the coordinates” and yes, there is where we are headed: a recursive algorithm to produce coordinates of multilinear polynomial or in a different light: a protocol to use strings of evaluations.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Fact number 4:&lt;&#x2F;strong&gt; In the same vein, evaluating a multilinear polynomial in a subset of its variables yields a multilinear polynomial in the remaining ones.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;the-adventure-of-multilinear-interpolation&quot;&gt;The adventure of multilinear interpolation&lt;&#x2F;h2&gt;
&lt;p&gt;What we just discussed can be seen as a case of &lt;em&gt;multilinear interpolation&lt;&#x2F;em&gt;. By the nature of the interpolation basis for multilinear polynomials in $\ell$ variables, this process can be iterated and coordinates computed efficiently, if tackled in an organized manner.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;algorithm-multilinearcoordinates-interpolationbasis-g-l&quot;&gt;Algorithm: MultilinearCoordinates&#x2F; InterpolationBasis(g, l)&lt;&#x2F;h3&gt;
&lt;p&gt;This algorithm takes a multilinear polynomial $g$ in $l$ variables and returns a vector of $2^l$ coordinates that represent $g$ in the multilinear interpolation basis.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. **Base Case:**&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * **If** $l = 0$:  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;i. The polynomial $g$ is a constant.&lt;br &#x2F;&gt;
ii. &lt;strong&gt;Return&lt;&#x2F;strong&gt; the vector with the single coordinate $[g]$.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * **If** $l = 1$:  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;i. The polynomial $g$ is multilinear in one variable $X_1$.&lt;br &#x2F;&gt;
ii. The coordinates are the evaluations of $g(0)$ and $g(1)$.&lt;br &#x2F;&gt;
iii. &lt;strong&gt;Return&lt;&#x2F;strong&gt; the vector $[g(0), g(1)]$.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. **Recursive Step:**&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * **If** $l &amp;gt; 1$:  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;i. Express $g$ as a polynomial in the variable $X_l$ with coefficients that are multilinear polynomials in the first $l - 1$ variables:&lt;br &#x2F;&gt;
$$g(\mathbf{X}) = C_0 (X_1, \dots, X_{l - 1})(1 - X_l) + C_1 (X_1, \dots, X_{l - 1}) X_l$$&lt;br &#x2F;&gt;
ii. Compute the coefficients $C_0$ and $C_1$ by evaluating $g$ at the extreme points of $X_l$:&lt;br &#x2F;&gt;
$$C_0(\mathbf{X_{&amp;lt;l}}) = g(\mathbf{X_{&amp;lt;l}}, 0)$$&lt;br &#x2F;&gt;
$$C_1(\mathbf{X_{&amp;lt;l}}) = g(\mathbf{X_{&amp;lt;l}}, 1)$$&lt;br &#x2F;&gt;
iii. &lt;strong&gt;Recursively call&lt;&#x2F;strong&gt; the algorithm to find the coordinates of these two new polynomials in $l - 1$ variables:&lt;br &#x2F;&gt;
a. $coords_0 \gets$ &lt;code&gt;MultilinearCoordinatesInterpolationBasis(C_0, l - 1)&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
b. $coords_1 \gets$ &lt;code&gt;MultilinearCoordinatesInterpolationBasis(C_1, l - 1)&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
iv. The coordinates of the original polynomial $g$ are the concatenation of the vectors $coords_0$ and $coords_1$.&lt;br &#x2F;&gt;
v. &lt;strong&gt;Return&lt;&#x2F;strong&gt; $$concat(coords_0, coords_1)$$&lt;&#x2F;p&gt;
&lt;p&gt;This algorithm exploits the fact that over the corresponding interpolation basis, the coordinates are none but the evaluation of the polynomial in the designated point in the hypercube, just as in the previous section.&lt;&#x2F;p&gt;
&lt;p&gt;To illustrate let’s pick up our previous example. For our toy polynomial&lt;&#x2F;p&gt;
&lt;p&gt;$$h = X_1 + X_1 X_3 + 2X_2 X_3 X_4 + 2X_4$$&lt;&#x2F;p&gt;
&lt;p&gt;we computed its coordinates in the interpolation basis in the variables $X_3, X_4$, obtaining:&lt;&#x2F;p&gt;
&lt;p&gt;$$\left[ X_1, 2+X_1, 2X_1, 2 + 2X_1 + 2X_2 \right]$$&lt;&#x2F;p&gt;
&lt;p&gt;Now we go on by obtaining the coordinates of each of these polynomials in the multilinear interpolation basis for the variables $X_1$ and $X_2$:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Coordinates for $X_1$:** We evaluate $X_1$ at each of the points of the boolean square, obtaining  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$X_1\longleftrightarrow \left[0, 1, 0, 1 \right]$$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Coordinates for $2 + X_1$:** We evaluate $2 + X_1$ at each of the points of the boolean square, obtaining  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$2 + X_1\longleftrightarrow \left[2, 3, 2, 3 \right]$$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Coordinates for $2X_1$:** repeating the idea we get  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$2X_1\longleftrightarrow \left[0, 2, 0, 2 \right]$$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Coordinates for $2 + 2X_1 + 2X_2$:** finally, evaluating at the point of the boolean square in binary order  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$2 + 2X_1 + 2X_2 \longleftrightarrow \left[2, 4, 4, 6 \right]$$&lt;&#x2F;p&gt;
&lt;p&gt;The concatenation of these final coordinates gives us the 16 evaluations of the polynomial $h$ on the hypercube ${0,1}^4$:&lt;&#x2F;p&gt;
&lt;p&gt;$$\text{coords}(h) = \text{concat}([0,1,0,1], [2,3,2,3], [0,2,0,2], [2,4,4,6] )$$&lt;&#x2F;p&gt;
&lt;p&gt;this is,&lt;&#x2F;p&gt;
&lt;p&gt;$$\text{coords}(h) = [0,1,0,1,2,3,2,3,0,2,0,2,2,4,4,6]$$&lt;&#x2F;p&gt;
&lt;p&gt;As we can easily verify the evaluations of $h$ directly. We’ve shown this procedure forwards, but this makes available for us a quick way of looking at coordinates in a quick way by simply eyeballing sub-vectors in the original string of coordinates. More on this later.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;products-of-multilinear-polynomials&quot;&gt;Products of multilinear polynomials&lt;&#x2F;h2&gt;
&lt;p&gt;As we’ve seen already, the set of multilinear polynomials in $\ell$ variables is indeed a vector space over the base field. However, product of multilinear polynomials fails to be a multilinear polynomial, in general.&lt;br &#x2F;&gt;
Suppose now that&lt;&#x2F;p&gt;
&lt;p&gt;$$g = \prod\limits_{ k = 1 }^d p_k$$&lt;&#x2F;p&gt;
&lt;p&gt;where the factors $p_k$ are all multilinear polynomials in $X_1,\ldots X_\ell$. By picking a variable $X_i$ we can view the product as a general polynomial in $X_i$ and coefficients in the ring of polynomials in the remaining variables.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Fact number 4:&lt;&#x2F;strong&gt; The degree of $g$ as a polynomial in $X_i$ is the sum of the degrees, as polynomials in $X_i$ for each of the factors $p_k$; this can be determined by deciding whether the polynomial $p_k$ has $X_i$ as a variable.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;So if we want to decide what is the degree of $g$ in the $X_i$ variable, we need to check whether each multilinear factor includes this variable or not. We can decide this fact with a rudimentary algorithm that uses a simple evaluation-based test: a multilinear polynomial $p(X_1, \dots, X_\ell)$ does &lt;strong&gt;not&lt;&#x2F;strong&gt; include the variable $X_k$ if and only if its value remains constant when you change the value of $X_k$ from 0 to 1, while keeping all other variables fixed. This is, if&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Fact number 5:&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
$$p(x_1, \dots, x_{k - 1}, 0, x_{k + 1}, \dots, x_\ell) = p(x_1, \dots, x_{k - 1}, 1, x_{k + 1}, \dots, x_\ell)$$&lt;br &#x2F;&gt;
for all $x_j \in \{0,1 \}$ where $j \neq k$ $\iff$ $p$ does not depend on $X_k$.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;To illustrate this fact, suppose we have&lt;&#x2F;p&gt;
&lt;p&gt;$$p(X_1, X_2, X_3) = X_1 (X_2 + X_3)$$&lt;&#x2F;p&gt;
&lt;p&gt;and we want to test if this polynomial includes the variable &lt;strong&gt;$X_3$&lt;&#x2F;strong&gt;. The test requires us to check if $$p(X_1, X_2, 0) = p(X_1, X_2, 1)$$ for all possible combinations of $(X_1, X_2) \in \{0,1 \}^2$.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. **First we check for $(x_1, x_2) = (0, 0)$:**&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $p(0, 0, 0) = 0(0 + 0) = 0$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $p(0, 0, 1) = 0(0 + 1) = 0$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The equality holds and observe that if the algorithm stopped here, it would wrongly conclude that the polynomial does not depend on $X_3$. Checking equality at all points of the hypercube is necessary.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. **Now check for $(x_1, x_2) = (1, 0)$:**&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $p(1, 0, 0) = 1(0 + 0) = 0$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $p(1, 0, 1) = 1(0 + 1) = 1$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The equality **fails**.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Because the equality fails for at least one case, an algorithm comparing evaluations correctly concludes that the variable $X_3$ &lt;strong&gt;is&lt;&#x2F;strong&gt; included in the polynomial.&lt;&#x2F;p&gt;
&lt;p&gt;Since we’ve spent some time discussing the connection between evaluations on the hypercube and coordinates over the multilinear interpolation basis - how can we make use of what we already know?&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Concretely, can we come up with an algorithm to decide whether a certain multilinear polynomial includes a specific variable or not, in a way that the algorithm exploits the recursive nature of the coordinates in the multilinear interpolation basis and the ordering of the hypercube?&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Since evaluations are no other than coordinates in the multilinear interpolation basis, performing the test we mentioned before amounts to inspecting different entries in the coordinate vector.&lt;&#x2F;p&gt;
&lt;p&gt;And how is this possible? Well, the first step is realizing that there is a relation between the position on the coordinate vector and the value of a variable $X_i$. For instance, take the polynomial $$g(X_1, X_2, X_3) = X_1 + X_3$$ which clearly does not depend on $X_2$. Its coordinate vector is:&lt;&#x2F;p&gt;
&lt;p&gt;$$\text{coords}(g) = [0, 1, 0, 1, 1, 2, 1, 2]$$&lt;&#x2F;p&gt;
&lt;p&gt;The first half of the vector corresponds to evaluations over points in the hypercube with $X_1=0$ and the second half corresponds to evaluations over points with $X_1=1$. In this way we split the coordinates in two chunks of half the size and proceed to compare those strings:&lt;&#x2F;p&gt;
&lt;p&gt;$$\text{coords} g_{ X_1 = 0} = [0, 1, 0, 1],\quad \text{coords} g_{ X_1 = 1 } = [1, 2, 1, 2]$$&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;As a brief comment: it is worth mentioning that these new strings of evaluations correspond to the coordinates of the multilinear polynomials that act as coefficients of $g$ as discussed in the earlier sections: they are the coordinates of $C_0^1 (X_2 , X_3)$ and $C_1^1 (X_2 , X_3)$ in the equality&lt;&#x2F;em&gt; $$g(X_1, X_2 , X_3 ) = C_0^1 (X_2 , X_3) ( 1 - X_1 ) + C_1^1 (X_2 , X_3) X_1$$&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;But let’s stick to the coordinates. We now scan these pieces: since they differ in the fist position we correctly conclude that $g$ depends on $X_1$.&lt;&#x2F;p&gt;
&lt;p&gt;Next we have the task to decide whether $X_2$ is present in $g$: w can now identify these two sub-vectors as coefficients in the multilinear interpolation basis for the variables $X_2$ and $X_3$ and call this test again on both pieces. We split both in two halves, corresponging to the evaluations $X_2 = 0$ and $X_2 = 1$:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * the coordinates of $C^1_0 (X_2,X_3)$ are $\text{coords}(c^1_0 ) = [0, 1, 0, 1]$ and split into $[0, 1]$ and $[0, 1]$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * the coordinates of $C^1_1 (X_2 , X_3)$ are $\text{coords}(c^1_1 ) = [1, 2, 1, 2]$ and split into $[1, 2]$ and $[1, 2]$  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;in both cases, the sub-vectors coincide and this means that in effect, $X_2$ is not present in $g$.&lt;&#x2F;p&gt;
&lt;p&gt;Finally to decide for $X_3$ we perform the same test on each of the 4 pieces obtained in the last step. It is easy to see that splitting $[0, 1]$ yields the scalar vectors&lt;&#x2F;p&gt;
&lt;p&gt;$$[0]\quad\text{and}\quad [1] $$&lt;&#x2F;p&gt;
&lt;p&gt;which are obviously different and so $g$ effectively contains the variable $X_3$.&lt;&#x2F;p&gt;
&lt;p&gt;In this example, we organized the routine in a “divide and conquer” fashion which is already appealing by inspecting equality starting in the most significant bit (MSB), working by halving string size towards the less significant bit (LSB) $X_3$. However, this is not the only way the inspection can be done, and as a matter of fact, for memory access reasons it is more convenient to assess variables &lt;em&gt;in reverse order of significance&lt;&#x2F;em&gt;. On the one hand this kills the divide and conquer approach but yields better performance results: modern computers access memory in contiguous blocks (cache) and the “divide and conquer” approach we discussed compares positions that are far apart in the original vector: $g(0)$ is compared to $g(5)$, $g(1)$ is compared to $g(6)$, and so on, and this is costly in terms of performance. How do cook up a way of using contiguity?&lt;&#x2F;p&gt;
&lt;p&gt;A good way of making use of contiguity is by the use of &lt;em&gt;strides&lt;&#x2F;em&gt;. The coordinate vector is ordered lexicographically, which means the indices of the elements correspond to the binary representation of integers, from 0 to $2^l - 1$. In this convention, each polynomial variable, $X_k$, is associated with a specific bit in the binary representation of the coordinates.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;em&gt;stride&lt;&#x2F;em&gt; for variable $X_k$ is simply the &lt;strong&gt;positional weight&lt;&#x2F;strong&gt; of its bit in the binary representation: in other words, how much does the $k-th$ bit contribute to the position in the hypercube. For a polynomial&lt;br &#x2F;&gt;
$$g(X_1, X_2, X_3)$$&lt;br &#x2F;&gt;
with an 8-element coordinate vector, the &lt;em&gt;stride&lt;&#x2F;em&gt; aligns with the inspection of each variable:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **For $X_3$ (LSB):** To change the value of $X_3$ from 0 to 1, we only need to change the least significant bit. The weight of this bit is $2^0 = 1$. Therefore, the _stride_ for $X_3$ is **1**. The test compares pairs of adjacent coordinates, such as $v_0$ with $v_1$ (corresponding to $000$ and $001$).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **For $X_2$:** To change the value of $X_2$ from 0 to 1, we need to change the middle bit. The weight of this bit is $2^1 = 2$. Therefore, the _stride_ for $X_2$ is **2**. The test compares pairs of coordinates that are 2 positions apart, such as $v_0$ with $v_2$ (corresponding to $000$ and $010$).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **For $X_1$ (MSB):** To change the value of $X_1$ from 0 to 1, we need to change the most significant bit. The weight of this bit is $2^2 = 4$. Therefore, the _stride_ for $X_1$ is **4**. The test compares pairs of coordinates that are 4 positions apart, such as $v_0$ with $v_4$ (corresponding to $000$ and $100$).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;em&gt;stride&lt;&#x2F;em&gt; works as an algorithmic shortcut to find the pairs of coordinates that only differ in the variable you are testing, by leveraging the structure of the binary encoding.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;By the use of the stride for each variable, now we have a way of scanning the coordinate vector in an efficient way. The pseudocode of such an algorithm is not complicated:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Inputs:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * _coords_ : A vector of $2^l$ coordinates (evaluations) of the polynomial $g$ on the hypercube ${0,1}^l$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * _l_ : The total number of variables in the polynomial ($X_1$ to $X_l$).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Intermediate Parameters:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * _stride_ : The step or distance between the coordinates being compared. Its value is $2^{l-k}$ for variable $X_k$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * _block length_ : The size of each iteration block. Its value is $2^{k - 1}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;The algorithm &lt;em&gt;DecideDependence_LSBFirst(coords, l)&lt;&#x2F;em&gt; is executed as follows:&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. For each variable $X_k$ (iterating from $k = l$ down to $1$):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Calculate _stride_ $= 2^{l - k}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Set a flag _depends_ to _FALSE_.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Iterate from $j = 0$ to $j = 2^{l} - 1$, with a step of $2 \cdot \text{stride}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. In each iteration, compare the coordinates _coords[j]_ and _coords[j + stride]_.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    6. If it is found that _coords[j]_ $\neq$ _coords[j + stride]_ , set _depends_ to _TRUE_ and exit the inner loop.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    7. Report the result of _depends_ for variable $X_k$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As an example with absolutely no surprises, here’s the application to the polynomial $$g(X - 1, X_2, X_3) = X_1 + X_3$$&lt;&#x2F;p&gt;
&lt;p&gt;We will use the same 8-element coordinate vector for $g$:&lt;br &#x2F;&gt;
$$\text{coords}(g) = [0, 1, 0, 1, 1, 2, 1, 2]$$&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1-decision-for-x-3-k-3&quot;&gt;1. Decision for $X_3$ ($k = 3$)&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. _stride_ = $2^{ 3 - 3} = 1$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. The algorithm compares the pairs _(coords[j], coords[j+1])_ for $j = 0, \dots, 6$ with a step of 2.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. For $j = 0$: _coords[0] (0)_ vs. _coords[1] (1)_. Since $0 \neq 1$, the test fails.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. **Conclusion:** $g$ **depends** on $X_3$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;2-decision-for-x-2-k-2&quot;&gt;2. Decision for $X_2$ ($k = 2$)&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. _stride_ = $2^{ 3 - 2} = 2$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. The algorithm compares the pairs _(coords[j], coords[j+2])_ for $j = 0, \dots, 6$ with a step of 4.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. For $j = 0$: _coords[0]} (0)_ vs. _coords[2] (0)_. They are equal.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. For $j = 1$: _coords[1]} (1)_ vs. _coords[3] (1)_. They are equal.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. For $j = 4$: _coords[4]} (1)_ vs. _coords[6] (1)_. They are equal.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    6. For $j = 5$: _coords[5]} (2)_ vs. _coords[7] (2)_. They are equal.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    7. **Conclusion:** $g$ **does not depend** on $X_2$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;3-decision-for-x-1-k-1&quot;&gt;3. Decision for $X_1$ ($k = 1$)&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. _stride_ = $2^{ 3 - 1} = 4$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. The algorithm compares the pairs _(coords[j], coords[j+4])_ for $j = 0, \dots, 3$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. For $j = 0$: _coords[0] (0)_ vs. _coords[4] (1)_.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Since $0 \neq 1$, the test fails.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. **Conclusion:** $g$ **depends** on $X_1$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is obviously the same result as above, but the way in which the comparisons are executed makes this algorithm preferrable.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-comes-next&quot;&gt;What comes next&lt;&#x2F;h2&gt;
&lt;p&gt;Next will employ these ideas to understand the algorithmic proposed by Bagad, Dao, Domb and Thaler in their recent article “Speeding-up SUMCHECK proving” where they explore different implementations of the SUMCHECK protocol for polynomials of the shape just described: products of multilinear polynomials. They investigate and exploiting the different multiplication and addition costs involved in the interaction between base field elements and random field elements at each step of the protocol and this obviously involves clever manipulation and understading of multilinear polynomials and their properties.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>GKR protocol implementation: deep dive into the code</title>
          <pubDate>Tue, 22 Jul 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/gkr-protocol-implementation-deep-dive-into-the-code/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/gkr-protocol-implementation-deep-dive-into-the-code/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/gkr-protocol-implementation-deep-dive-into-the-code/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;The &lt;strong&gt;GKR&lt;&#x2F;strong&gt; (Goldwasser–Kalai–Rothblum) protocol provides an efficient way to verify computations over arithmetic circuits, avoiding re-execution and reducing the verifier’s work. In our previous post, &lt;a href=&quot;&#x2F;gkr-protocol-a-step-by-step-example&#x2F;&quot;&gt;GKR protocol: a step-by-step example&lt;&#x2F;a&gt;, we explored how the protocol works in detail, focusing on its mathematical structure and walking through a concrete hand-worked example. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2023&#x2F;1284&quot;&gt;GKR&lt;&#x2F;a&gt; is currently used to improve the performance of lookup arguments, which are crucial for proving the execution of zero-knowledge virtual machines.&lt;&#x2F;p&gt;
&lt;p&gt;The goal of this post is to explain &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;1011&quot;&gt;our implementation&lt;&#x2F;a&gt; of the protocol in Lambdaworks, showing how arithmetic circuits are described and validated, and how the prover and verifier operate in practice. We’ll also see how the &lt;strong&gt;Fiat-Shamir transform&lt;&#x2F;strong&gt; is applied to make the protocol &lt;strong&gt;non-interactive&lt;&#x2F;strong&gt; , and how the &lt;strong&gt;Sumcheck protocol&lt;&#x2F;strong&gt; is adapted and integrated as the core component for verifying each circuit layer.&lt;&#x2F;p&gt;
&lt;p&gt;If you’re not familiar with the protocol or need a refresher, we recommend starting with our previous post linked above.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Warning:&lt;&#x2F;strong&gt; The GKR implementation presented here is for educational purposes only and should not be used in production. Note that for more general circuits, the protocol is vulnerable to practical attacks, as it relies on the Fiat-Shamir transform (see &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2025&#x2F;118.pdf&quot;&gt;“How to Prove False Statements”&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;circuit-structure&quot;&gt;Circuit Structure&lt;&#x2F;h2&gt;
&lt;p&gt;A GKR circuit is composed of layers. Each layer contains gates, and each gate operates on outputs from the previous layer. Gates can be either addition or multiplication. For protocol compatibility, each layer must have a power-of-two number of gates.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;BkLEjCjIlx.png&quot; alt=&quot;image&quot; &#x2F;&gt;&lt;br &#x2F;&gt;
&lt;em&gt;The arithmetic circuit used in the previous post as an example&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In some cases, we can work with more efficient versions if all the gates are, for example, multiplications.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;circuit-api&quot;&gt;Circuit API&lt;&#x2F;h3&gt;
&lt;p&gt;The main structures for circuit construction are:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `Circuit` — Consists of a vector of layers (ordered from top to bottom, starting at the output layer and not including the input layer); the number of inputs; and the number of variables needed to index the input layer.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          pub struct Circuit {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;              &#x2F;&#x2F;&#x2F; First layer is the output layer. It doesn&amp;#39;t include the input layer.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;              layers: Vec&amp;lt;CircuitLayer&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;              &#x2F;&#x2F;&#x2F; Number of inputs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;              num_inputs: usize,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;              input_num_vars: usize, &#x2F;&#x2F; log2 of number of inputs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `CircuitLayer` — contains a vector of gates and the number of variables needed to index those gates.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          pub struct CircuitLayer {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;              pub gates: Vec&amp;lt;Gate&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;              pub num_of_vars: usize, &#x2F;&#x2F; log2 of number of gates in this layer&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `Gate` — a single gate, with its type and input indices.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `GateType` — either `Add` or `Mul`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;circuit-gates&quot;&gt;Circuit Gates&lt;&#x2F;h3&gt;
&lt;p&gt;Each gate in the circuit is either an addition (&lt;code&gt;Add&lt;&#x2F;code&gt;) or multiplication (&lt;code&gt;Mul&lt;&#x2F;code&gt;) gate. The gate type determines how the outputs from the previous layer are combined:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `Add`: The gate outputs the sum of its two input wires.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `Mul`: The gate outputs the product of its two input wires.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For example:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let gate_1 = Gate::new(GateType::Mul, [0, 1]); &#x2F;&#x2F;Multiplies outputs at indices 0 and 1 from the previous layer.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let gate_2 = Gate::new(GateType::Add, [2, 3]); &#x2F;&#x2F; Adds outputs at indices 2 and 3 from the previous layer.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;SkRvRAjIlx.png&quot; alt=&quot;image&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;example-the-blog-post-circuit&quot;&gt;Example: The Blog Post Circuit&lt;&#x2F;h3&gt;
&lt;p&gt;To illustrate this, let’s walk through the construction of the exact circuit used in our &lt;a href=&quot;&#x2F;gkr-protocol-a-step-by-step-example&#x2F;&quot;&gt;step-by-step GKR blog post&lt;&#x2F;a&gt;. This is available as &lt;code&gt;lambda_post_circuit()&lt;&#x2F;code&gt; in the codebase, and you can use it directly or as a template for your circuits.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn lambda_post_circuit() -&amp;gt; Result&amp;lt;Circuit, CircuitError&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    use crate::circuit::{Circuit, CircuitLayer, Gate, GateType};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Circuit::new(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        vec![&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; Layer 0 (output layer): Two gates&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            CircuitLayer::new(vec![&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                Gate::new(GateType::Mul, [0, 1]), &#x2F;&#x2F; Multiplies outputs 0 and 1 from previous layer&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                Gate::new(GateType::Add, [2, 3]), &#x2F;&#x2F; Adds outputs 2 and 3 from previous layer&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; Layer 1: Four gates&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            CircuitLayer::new(vec![&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                Gate::new(GateType::Mul, [0, 1]), &#x2F;&#x2F; Multiplies the two inputs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                Gate::new(GateType::Add, [0, 0]), &#x2F;&#x2F; Adds the first input to itself&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                Gate::new(GateType::Add, [0, 1]), &#x2F;&#x2F; Adds both inputs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                Gate::new(GateType::Mul, [0, 1]), &#x2F;&#x2F; Multiplies the two inputs again&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        2, &#x2F;&#x2F; Two inputs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;how-to-build-your-circuit&quot;&gt;How to Build Your Circuit&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. **Decide the number of inputs.** Each input will be referenced by its index (starting from 0).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. **Build the first layer:** Each gate in the first layer operates on the inputs. Use `Gate::new(GateType::Add, [i, j])` or `Gate::new(GateType::Mul, [i, j])` to add or multiply input indices `i` and `j`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. **Build subsequent layers:** Each gate operates on outputs from the previous layer. Indices always refer to the order of outputs of the prior layer. Each new layer should be inserted at the beginning of the `layers` vector, since layers are ordered from the top (output layers) to the bottom of the circuit.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. **Repeat until you reach the output layer.**&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. **Wrap your layers in a`Circuit::new(layers, num_inputs)` call.**&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Important:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Each layer must have a power-of-two number of gates.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Indices must be valid (i.e., not out of bounds for the previous layer).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;circuit-automatic-validation&quot;&gt;Circuit Automatic Validation&lt;&#x2F;h3&gt;
&lt;p&gt;When you construct a &lt;code&gt;Circuit&lt;&#x2F;code&gt;, several checks are performed automatically to ensure the circuit is well-formed:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Power-of-two gates** : Each layer must have a number of gates that is a power of two. This is required for the protocol to work efficiently.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Valid input indices** : Each gate&amp;#39;s input indices must refer to valid outputs from the previous layer. If an index is out of bounds, the construction fails.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Power-of-two inputs** : The number of circuit inputs must also be a power of two.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If any of these conditions are not met, the constructor returns a descriptive error (as a &lt;code&gt;Result::Err&lt;&#x2F;code&gt;). This prevents invalid circuits from being created and helps catch mistakes early in development.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-gkr-protocol&quot;&gt;The GKR Protocol&lt;&#x2F;h2&gt;
&lt;p&gt;Let’s see how each step of the protocol is implemented in our code. We aim to demonstrate how it leverages the sumcheck protocol to recursively reduce a claim about the correctness of a computation at one layer of a circuit to a claim about the next layer, progressing from the output layer down to the input layer.&lt;&#x2F;p&gt;
&lt;p&gt;Recall that in our implementation, we utilize the Fiat-Shamir transform to render the protocol non-interactive, which results in a slightly different appearance from the version described in the previous post.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;prover&quot;&gt;Prover&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;the-proof-structure&quot;&gt;The proof structure&lt;&#x2F;h4&gt;
&lt;p&gt;The prover is responsible for evaluating the circuit and constructing a proof that convinces the verifier of the correctness of this evaluation. The core logic for the prover resides in &lt;code&gt;prover.rs&lt;&#x2F;code&gt;, where you can find the struct &lt;code&gt;GKRProof&lt;&#x2F;code&gt; that consists of:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The input and the output values of the circuit.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * A sumcheck proof for each circuit layer having: &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      * The round univariate polynomials $g_j$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      * The composition of the univariate polynomial $q$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let’s recall what the polynomials $g_j$ and $q$ are. In each circuit layer and for each round $j$ of its sumcheck, the prover has to compute the univariate polynomial $g_j$ by fixing the first variable and summing over all the others. For example, in our previous post, in the layer $0$, the sumcheck had four rounds leading to these polynomials:&lt;&#x2F;p&gt;
&lt;p&gt;$$\begin{align}&lt;br &#x2F;&gt;
g_1 (z) &amp;amp;= \sum_{(b_2, c_1, c_2) : \in {0, 1}^3} \tilde f_{ r_0 }^{ (0) } (z, b_2, c_1, c_2), \ \newline&lt;br &#x2F;&gt;
g_2 (z) &amp;amp;= \sum_{(c_1, c_2) : \in {0, 1}^2} \tilde f_{ r_0 }^{ (0) } (s_1, z, c_1, c_2), \ \newline&lt;br &#x2F;&gt;
g_3 (z) &amp;amp;= \sum_{c_2 : \in {0, 1}} \tilde f_{ r_0 }^{ (0) } (s_1, s_2, z, c_2),\ \newline&lt;br &#x2F;&gt;
g_4 (z) &amp;amp;= \tilde f_{ r_0 }^{ (0) } (s_1, s_2, s_3, z),&lt;br &#x2F;&gt;
\end{align}$$&lt;&#x2F;p&gt;
&lt;p&gt;where $s_j$ are random challenges.&lt;&#x2F;p&gt;
&lt;p&gt;On the other hand, for each layer $i$, the polynomial $q$ is the composition $q = \tilde W_{i + 1} \circ \ell$, where $\tilde W_{i + 1}$ is the multilinear polynomial extension of the function that maps a node’s position to its actual value, and $\ell$ is the line that goes from $b^\star$ to $c^\star$. In the previous example, $\ell (0) = (s_1, s_2)$ and $\ell (1) = (s_3, s_4)$.&lt;&#x2F;p&gt;
&lt;p&gt;In the codebase, you’ll see it as:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub struct GKRProof&amp;lt;F: IsField&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub input_values: Vec&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub output_values: Vec&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub layer_proofs: Vec&amp;lt;LayerProof&amp;lt;F&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The proof for each circuit layer is:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub struct LayerProof&amp;lt;F: IsField&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub sumcheck_proof: GKRSumcheckProof&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub poly_q: Polynomial&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally, the &lt;code&gt;sumcheck_proof&lt;&#x2F;code&gt; contains the round polynomials $g_j$ and the challenges used in those rounds, so that both prover and verifier can calculate the line $\ell$.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub struct GKRSumcheckProof&amp;lt;F: IsField&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub round_polynomials: Vec&amp;lt;Polynomial&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub challenges: Vec&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;building-the-proof&quot;&gt;Building the proof&lt;&#x2F;h4&gt;
&lt;p&gt;The prover constructs the proof using the &lt;code&gt;Prover::generate_proof()&lt;&#x2F;code&gt; method. This function takes the circuit and its inputs, evaluates the circuit on them, and generates the proof. Let’s break down this function into the following steps:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. **Circuit Evaluation:** The Prover evaluates the whole circuit in the given inputs.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           let evaluation = circuit.evaluate(input);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. **Transcript Initialization** :&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Since we implemented the non-interactive version of the protocol, the prover must &lt;strong&gt;commit to the circuit, its inputs, and its outputs&lt;&#x2F;strong&gt;. This is done by defining a &lt;code&gt;DefaultTranscript&lt;&#x2F;code&gt;, from which we can commit to and sample new values. Both prover and verifier append this data to the transcript. To append the circuit, they need to convert it into bytes, and they do so using the function &lt;code&gt;circuit_to_bytes()&lt;&#x2F;code&gt; that you can find in the file &lt;code&gt;lib.rs&lt;&#x2F;code&gt;. We’ll see more about the transcript later on in the Fiat-Shamir subsection.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. **Sample $r_0$** :  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The prover samples the first $r_0$ to fix the variable $a$ and begin the sumcheck. Recall that the variable $a$ could have more than one bit, so $r_0$ has the same size as $a$ called $k_0$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           let k_0 = circuit.num_vars_at(0).ok_or(ProverError::CircuitError)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           let mut r_i: Vec&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt; = (0..k_0)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;               .map(|_| transcript.sample_field_element())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;               .collect();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. **Sumcheck layer iteration:** For each layer, the prover applies the sumcheck protocol following these steps:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * **Building the function** :  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The prover builds the function to which he wants to apply the sumcheck,&lt;br &#x2F;&gt;
$$\tilde f_{ r_i } (b, c) = \widetilde{\text{add_i}} (r_i, b, c) \cdot (\widetilde W_{i + 1}(b) + \widetilde W_{i + 1}(c)) + \widetilde{\text{mul_i}} (r_i, b, c) \cdot (\widetilde{W_{i + 1}} (b) \cdot \widetilde{W_{i + 1}} (c)),$$&lt;br &#x2F;&gt;
using the method &lt;code&gt;Prover::build_gkr_polynomial()&lt;&#x2F;code&gt;. Note that this method returns two terms instead of just one. More specifically, it returns a 2-item vector whose elements are themselves vectors of two multilinear polynomials:&lt;br &#x2F;&gt;
First term or vector:&lt;br &#x2F;&gt;
$$[\widetilde{\text{add_i}} (r_i, b, c), \widetilde{W_{i + 1}} (b) + \widetilde{W_{i + 1}} (c)]$$&lt;br &#x2F;&gt;
Second term or vector:&lt;br &#x2F;&gt;
$$[\widetilde{\text{mul_i}} (r_i, b, c), \widetilde{W_{i + 1}} (b) \cdot \widetilde{W_{i + 1}} (c)]$$&lt;&#x2F;p&gt;
&lt;p&gt;This is necessary because the sumcheck implementation at lambdaworks only accepts a product of multilinear polynomials. That is why we separate our polynomial $\tilde f_{r_i}$ into two terms of products of multilinear polynomials.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             let gkr_poly_terms =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                     Prover::build_gkr_polynomial(circuit, &amp;amp;r_i, w_next_evals, layer_idx)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * **Apply the GKR Sumcheck Prover:**  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We use a sumcheck implementation specifically designed for the GKR protocol. We’ll go into more detail about this new sumcheck later, but there are three &lt;strong&gt;key changes&lt;&#x2F;strong&gt; to keep in mind:&lt;br &#x2F;&gt;
&lt;strong&gt;I)&lt;&#x2F;strong&gt; We need a sumcheck prover that &lt;strong&gt;takes a transcript as input&lt;&#x2F;strong&gt; , so we can maintain the same transcript for both the prover and the verifier, which is created at the start.&lt;br &#x2F;&gt;
&lt;strong&gt;II)&lt;&#x2F;strong&gt; This new sumcheck also &lt;strong&gt;returns the random values sampled during execution&lt;&#x2F;strong&gt;. This allows both the prover and verifier to compute the function $\ell$ later, which depends on those values.&lt;br &#x2F;&gt;
&lt;strong&gt;III)&lt;&#x2F;strong&gt; The GKR sumcheck allows us to &lt;strong&gt;work with both terms&lt;&#x2F;strong&gt; of $\tilde f_{ r_i } (b,c)$ at the same time.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             let sumcheck_proof = gkr_sumcheck_prove(gkr_poly_terms, &amp;amp;mut transcript)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * **Sumcheck final claim:**  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The prover samples a new field element $r^\star$ (called &lt;code&gt;r_new&lt;&#x2F;code&gt;in the code), evaluates the line $\ell$ at it, and calculates the composition polynomial $q$. The evaluation of $\ell$ is computed using the function &lt;code&gt;line()&lt;&#x2F;code&gt; that you can find in &lt;code&gt;lib.rs&lt;&#x2F;code&gt; (since it is used by both prover and verifier). On the other hand, the polynomial $q$ is calculated using the method &lt;code&gt;Prover::build_polynomial_q()&lt;&#x2F;code&gt;. To calculate this polynomial, the prover needs to interpolate three points, since $q$ has degree 2 (as $\ell$ is linear and $\tilde W_{i + 1}$ multilinear in each variable).&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             &#x2F;&#x2F; r* in our blog post &amp;lt;https:&#x2F;&#x2F;blog.lambdaclass.com&#x2F;gkr-protocol-a-step-by-step-example&#x2F;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             let r_new = transcript.sample_field_element();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             &#x2F;&#x2F; Construct the next round&amp;#39;s random point using line function&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             &#x2F;&#x2F;  l(x) = b + x * (c - b)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             let (b, c) = sumcheck_challenges.split_at(num_vars_next);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             &#x2F;&#x2F; r_i = l(r_new)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             r_i = crate::line(b, c, &amp;amp;r_new);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             let poly_q = Prover::build_polynomial_q(b, c, w_next_evals.clone())?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. **Make the proof:** Finally, the prover has all the ingredients to make the proof.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           let proof = GKRProof {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;               input_values: input.to_vec(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;               output_values,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;               layer_proofs,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;verifier&quot;&gt;Verifier&lt;&#x2F;h3&gt;
&lt;p&gt;Once we understand what the prover does, it’s easy to see what the verifier needs to do. It simply follows the same steps as the prover, using the elements of the proof and performing the necessary checks at each step. She verifies the proof using the method &lt;code&gt;Verifier::verify()&lt;&#x2F;code&gt; following these steps:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. **Transcript Initialization:**  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Just as the prover, start by creating a transcript and appending the &lt;strong&gt;circuit&lt;&#x2F;strong&gt; (which is known to both parties), the &lt;strong&gt;inputs&lt;&#x2F;strong&gt; , and the &lt;strong&gt;outputs&lt;&#x2F;strong&gt; sent in the proof by the prover.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. **Initial Sum Calculation:**  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Sample field elements for $r_0$ to fix the variable $a$ and set the initial sum as $m_0 = \tilde D (r_0)$, where $\tilde D$ is the multilinear polynomial extension of the function that maps the output gates to the evaluation values. The prover sent these values as part of the proof.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           let output_poly_ext = DenseMultilinearPolynomial::new(proof.output_values.clone());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           let mut claimed_sum = output_poly_ext&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;               .evaluate(r_i.clone())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;               .map_err(|_e| VerifierError::MultilinearPolynomialEvaluationError)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. **Layer-by-Layer Verification:** For each layer $i$, the verifier performs the following:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * **Verify the sumcheck proof:**  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The verifier checks the sumcheck proof for the current layer using the function &lt;code&gt;gkr_sumcheck_verify&lt;&#x2F;code&gt;. This function ensures that the sequence of univariate polynomials $g_j$ provided by the prover has degree 2 and is consistent with the claimed sum in each sumcheck round $j$; that is,&lt;br &#x2F;&gt;
$$ deg(g_j) \leq 2,$$$$g_j (0) + g_j (1) == g_{j - 1} (s_{ j - 1 }).$$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             let (sumcheck_verified, sumcheck_challenges) = gkr_sumcheck_verify(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                 claimed_sum.clone(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                 &amp;amp;layer_proof.sumcheck_proof,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                 &amp;amp;mut transcript,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             )?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             if !sumcheck_verified {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                 return Ok(false);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * **Check the final round $n$ using the composition polynomial $q$:**  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To verify the final claim of the sumcheck in the last round, the verifier needs the values $\tilde W_{ i + 1}(b^\star)$ and $\tilde W_{i + 1}(c^\star)$. However, the polynomial $\tilde W_{ i + 1}$ is unknown to her: the verifier doesn’t have the circuit evaluations. That is why she performs this final check using the composition polynomial $q$ provided by the prover. Recall that if the prover didn’t cheat, $q(0) = \tilde W_{ i + 1}(b^\star)$ and $q(1) = \tilde W_{ i + 1}(c^\star)$. Therefore, the verifier must check that&lt;br &#x2F;&gt;
$$g_n (s_n) = \widetilde{\text{add_i}} (r_i, b^\star, c^\star) \cdot (q(0) + q(1)) + \widetilde{\text{mul_i}} (r_i, b^\star, c^\star) \cdot (q(0) \cdot q(1))$$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             let last_poly = layer_proof.sumcheck_proof.round_polynomials.last().unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             let last_challenge = sumcheck_challenges.last().unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             let expected_final_eval = last_poly.evaluate::&amp;lt;F&amp;gt;(last_challenge);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             let q_at_0 = layer_proof.poly_q.evaluate(&amp;amp;FieldElement::zero());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             let q_at_1 = layer_proof.poly_q.evaluate(&amp;amp;FieldElement::one());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             let add_eval = circuit.add_i_ext(&amp;amp;r_i, layer_idx).evaluate(sumcheck_challenges.clone())?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             let mul_eval = circuit.mul_i_ext(&amp;amp;r_i, layer_idx).evaluate(sumcheck_challenges.clone())?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             let final_eval = add_eval * (&amp;amp;q_at_0 + &amp;amp;q_at_1) + mul_eval * q_at_0 * q_at_1;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             if final_eval != expected_final_eval {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                 return Ok(false);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * **Sample a new challenge and update the evaluation point:**  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The verifier samples a new field element $r^\star$ from the transcript, then uses the line function to compute the next evaluation point $r_{ i + 1} = \ell (r^\star)$ for the following layer. The claimed sum is updated by evaluating the composition polynomial $q$ at the new challenge: $q(r^\star)$.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             let r_new = transcript.sample_field_element();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             let num_vars_next = circuit.num_vars_at(layer_idx + 1).ok_or(VerifierError::CircuitError)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             let (b, c) = sumcheck_challenges.split_at(num_vars_next);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             r_i = crate::line(b, c, &amp;amp;r_new);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             claimed_sum = layer_proof.poly_q.evaluate(&amp;amp;r_new);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. **Final Input Check:**  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After all layers have been processed, the verifier checks that the final claimed sum matches the evaluation of the multilinear extension of the input values at the final evaluation point $r_i$. In the previous post example, that would be $$q(r^\star) == \tilde W_2 (r_2).$$ This ensures that the entire computation, from outputs down to the inputs, is consistent.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           let input_poly_ext = DenseMultilinearPolynomial::new(proof.input_values.clone());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           if claimed_sum&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;               != input_poly_ext&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                   .evaluate(r_i)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                   .map_err(|_| VerifierError::MultilinearPolynomialEvaluationError)?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;               return Ok(false);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If all checks pass, the verifier accepts the proof as valid. Otherwise, the proof is rejected at the first failed check. This process allows the verifier to efficiently confirm the correctness of the computation without re-executing the entire circuit.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-sumcheck-protocol&quot;&gt;The Sumcheck Protocol&lt;&#x2F;h2&gt;
&lt;p&gt;The Sumcheck protocol is a central component of the GKR protocol. Its role is to allow the prover to convince the verifier that a sum over a product of multilinear polynomials is correct, without requiring the verifier to compute the sum directly. This is achieved by reducing the original sum to a sequence of univariate polynomial checks, one for each variable.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;quick-recap-what-is-the-sum-being-checked&quot;&gt;Quick Recap: What is the sum being checked?&lt;&#x2F;h3&gt;
&lt;p&gt;At each layer $i$ of the GKR protocol, the prover and verifier need to check a sum of the form:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
S = \sum_{x_1, \ldots, x_n \in {0,1}} \tilde f_{ r_i }(x_1, \ldots, x_n)&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;where $\tilde f_{ r_i } (x_1, \ldots, x_n)$ is a multilinear polynomial that encodes the wiring and values of the circuit at that layer, and $n$ is the number of variables for that layer (which depends on the number of bits needed to index the gates of the next layer).&lt;&#x2F;p&gt;
&lt;p&gt;The sumcheck protocol allows the prover to convince the verifier that the claimed value $S$ is correct, by sending a sequence of univariate polynomials $g_1, g_2, \ldots, g_n$ such that, in round $j$:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
g_j(z) = \sum_{x_{j + 1}, \ldots, x_n} f_{r} (s_1, \ldots, s_{j - 1}, z, x_{j + 1}, \ldots, x_n)&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;where $s_1, \ldots, s_{j - 1}$ are the challenges sampled in previous rounds, $z$ is the variable for the current round, and the remaining variables are summed over. The number of rounds (and thus the number of $g_j$ polynomials) is always equal to the number of variables of $\tilde f_{ r_i }$ for the layer being checked.&lt;&#x2F;p&gt;
&lt;p&gt;At each round, the verifier checks the key sumcheck property:&lt;&#x2F;p&gt;
&lt;p&gt;$$deg(g_j) \leq 2$$&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
g_j(0) + g_j(1) = \text{previous sum}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;and then samples a new challenge $s_j$ for the next round. After all rounds, the verifier is left with a claim about $f_{r} (s_1, \ldots, s_n)$, which is checked against the next layer.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;splitting-the-gkr-polynomial-for-sumcheck&quot;&gt;Splitting the GKR Polynomial for Sumcheck&lt;&#x2F;h3&gt;
&lt;p&gt;The GKR polynomial $\tilde f_{ r_i } (b, c)$, which encodes the relationship between two adjacent layers, is given by:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\tilde f_{r_i}(b, c) = \widetilde{\text{add_i}} (r_i, b, c) \cdot \left( W_{ i + 1} (b) + W_{ i + 1} (c) \right) + \widetilde{\text{mul_i}} (r_i, b, c) \cdot \left( W_{ i + 1 }(b) \cdot W_{ i + 1}(c) \right)&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;To apply the sumcheck protocol, this polynomial is split into two terms, each being a product of two multilinear polynomials:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The first term:  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\widetilde{\text{add_i}} (r_i, b, c) \cdot \left( W_{ i + 1}(b) + W_{ i + 1}(c) \right)&lt;br &#x2F;&gt;
$$
* The second term:&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
\widetilde{\text{mul_i}} (r_i, b, c) \cdot \left( W_{ i + 1 }(b) \cdot W_{ i + 1}(c) \right)&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;This splitting is necessary because the sumcheck implementation expects a product of multilinear polynomials. In the code, this is handled by the function &lt;code&gt;Prover::build_gkr_polynomial&lt;&#x2F;code&gt; (see the Prover section), which returns a vector with two entries, each being a vector of two multilinear polynomials (the factors of each term). These are then passed to the sumcheck prover, which processes both terms together in each round.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;implementation-in-the-codebase&quot;&gt;Implementation in the Codebase&lt;&#x2F;h3&gt;
&lt;p&gt;The logic for the sumcheck protocol is implemented in &lt;a href=&quot;https:&#x2F;&#x2F;lambdaclass.github.io&#x2F;lambdaclass_blog&#x2F;posts&#x2F;gkr-protocol-implementation-deep-dive-into-the-code&#x2F;.&#x2F;src&#x2F;sumcheck.rs&quot;&gt;&lt;code&gt;sumcheck.rs&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;. This file contains the functions used by both the prover and the verifier to perform the sumcheck rounds for each circuit layer.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;prover-step-by-step-sumcheck-proof-generation&quot;&gt;Prover: Step-by-step sumcheck proof generation:&lt;&#x2F;h4&gt;
&lt;p&gt;At each layer, the prover constructs the sumcheck proof as follows:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;1. Build the GKR polynomial terms&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;For the current layer, construct the GKR polynomial and split it into two terms as required by the protocol:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let factors_term_1 = terms[0].clone();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let factors_term_2 = terms[1].clone();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let mut prover_term_1 = Prover::new(factors_term_1)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let mut prover_term_2 = Prover::new(factors_term_2)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;2. Compute the initial claimed sum&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The prover computes the initial sum for both terms and adds them:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let claimed_sum_term_1 = prover_term_1.compute_initial_sum()?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let claimed_sum_term_2 = prover_term_2.compute_initial_sum()?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let claimed_sum = claimed_sum_term_1 + claimed_sum_term_2;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;3. Apply the sumcheck protocol round by round&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;For each round, the prover computes the univariate polynomial for each term, sums them, and appends the result to the transcript. Each resulting polynomial $g_j$ is collected in a vector:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let mut proof_polys = Vec::with_capacity(num_vars);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;for j in 0..num_vars {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let g_j_term_1 = prover_term_1.round(current_challenge.as_ref())?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let g_j_term_2 = prover_term_2.round(current_challenge.as_ref())?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let g_j = g_j_term_1 + g_j_term_2;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; ...append g_j to transcript...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    proof_polys.push(g_j);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; ...sample challenge, update current_challenge...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;4. Collect the proof data&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;After all rounds, the vector of polynomials and the challenges are used to construct the sumcheck proof object:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let sumcheck_proof = GKRSumcheckProof {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    round_polynomials: proof_polys,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    challenges,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;5. Send to verifier&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Include the sumcheck proof as part of the overall GKR proof, which the verifier will check in the next phase.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;verifier-step-by-step-sumcheck-verification&quot;&gt;Verifier: Step-by-step sumcheck verification:&lt;&#x2F;h4&gt;
&lt;p&gt;At each layer, the verifier processes the sumcheck proof as follows:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;1. For each round, check the degree and sum property&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;For each univariate polynomial $g_j$ received, check that the degree is at most two and that the sum of its evaluations at 0 and 1 matches the expected value (either the initial claim or the previous polynomial evaluated at the previous challenge):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Check that the degree of g_j does not exceed the theoretical bound&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;if g_j.degree() &amp;gt; 2 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return Err(crate::verifier::VerifierError::InvalidDegree);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let g_j_0 = g_j.evaluate::&amp;lt;F&amp;gt;(&amp;amp;FieldElement::zero());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let g_j_1 = g_j.evaluate::&amp;lt;F&amp;gt;(&amp;amp;FieldElement::one());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let sum_evals = &amp;amp;g_j_0 + &amp;amp;g_j_1;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let expected_sum = if j == 0 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    claimed_sum.clone()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;} else {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let prev_poly = &amp;amp;proof_polys[j - 1];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let prev_challenge = &amp;amp;challenges[j - 1];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    prev_poly.evaluate::&amp;lt;F&amp;gt;(prev_challenge)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;if sum_evals != expected_sum {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return Ok((false, challenges));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;2. Update the transcript and sample the next challenge&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;After each round, the verifier appends the polynomial to the transcript and samples the next challenge:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let r_j = transcript.sample_field_element();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;challenges.push(r_j.clone());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;3. Accept or reject&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If all rounds pass the checks, accept the sum as correct, without needing to evaluate the full sum directly. If any check fails, reject the proof immediately.&lt;&#x2F;p&gt;
&lt;p&gt;Each round of the sumcheck protocol reduces the number of variables by one, transforming a multivariate sum into a sequence of univariate checks. The prover performs the main computations, while the verifier only needs to check a small number of polynomial evaluations and field operations. The use of the Fiat-Shamir transform ensures that the protocol is non-interactive, with all challenges derived from the transcript.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;fiat-shamir-transform-making-it-non-interactive&quot;&gt;Fiat-Shamir Transform: Making it Non-Interactive&lt;&#x2F;h2&gt;
&lt;p&gt;The original GKR protocol is interactive, meaning it requires a series of back-and-forth communications between the prover and the verifier. While interactive proofs are theoretically sound, they can be impractical for many real-world applications due to latency and communication overhead. The Fiat-Shamir transform is a cryptographic technique used to convert interactive proof systems into non-interactive ones.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;how-fiat-shamir-is-applied&quot;&gt;How Fiat-Shamir is Applied&lt;&#x2F;h3&gt;
&lt;p&gt;In our implementation, the Fiat-Shamir transform replaces the verifier’s random challenges with outputs from a cryptographic hash function, specifically a &lt;code&gt;DefaultTranscript&lt;&#x2F;code&gt; from the &lt;code&gt;lambdaworks_crypto&lt;&#x2F;code&gt; crate. This allows the prover to generate all necessary challenges deterministically, without any interaction with the verifier.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. **Transcript Initialization** : A transcript is created and seeded with public information relevant to the proof. This includes:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * The circuit structure (serialized via `circuit_to_bytes(circuit)`).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * The public input values.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * The claimed output values.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;By including this information, any party can reconstruct the same transcript and verify the challenges generated.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. **Challenge Generation** : At each step where the interactive protocol would require a random challenge from the verifier, the implementation instead:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * Appends the current state of the proof (e.g., the coefficients of a polynomial sent by the prover) to the transcript.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * Samples a random field element from the transcript using `transcript.sample_field_element()`. This element is cryptographically derived from all previous information in the transcript, making it unpredictable to the prover before the relevant information is committed.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;key-challenge-points&quot;&gt;Key Challenge Points&lt;&#x2F;h3&gt;
&lt;p&gt;The Fiat-Shamir transform is applied at several critical junctures in the GKR protocol:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Initial Random Values** ($r_0$): For the output layer, initial random challenges are sampled to begin the layer-by-layer reduction.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Sumcheck Challenges** ($s_j$): In each round of the Sumcheck protocol, challenges are generated from the transcript. These challenges are essential for the verifier to check the consistency of the prover&amp;#39;s univariate polynomials.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Line Function Parameter** ($r^\star$ or `r_new`): After each layer&amp;#39;s sumcheck, a new challenge `r_new` is sampled. This challenge is used in the `line` function to derive the evaluation point for the next layer&amp;#39;s claimed sum, effectively linking the layers in the proof.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;By leveraging the Fiat-Shamir transform, our GKR implementation achieves non-interactivity, making it more practical for real-world applications where continuous communication between prover and verifier might be infeasible or introduce undesirable latency. This transformation is a cornerstone of many modern zero-knowledge proof systems, enabling efficient and verifiable computation in a wide range of scenarios.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;In this post, we showed how we implemented the GKR protocol. Starting from a circuit description, the prover evaluates each layer, constructs the corresponding polynomial, and runs a tailored Sumcheck protocol whose challenges are generated through a Fiat–Shamir transcript. The verifier, working with the same transcript, replays the Sumcheck rounds, checks the final claim with the composition polynomial $q$, and ultimately confirms that the computation is correct all the way down to the public inputs. In this way, a potentially expensive re-execution of the circuit is reduced to a series of lightweight algebraic checks.&lt;br &#x2F;&gt;
Although this implementation is intended for educational use, it captures every essential step of the protocol.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>BitVM: enabling efficient verifiable computation in Bitcoin</title>
          <pubDate>Thu, 26 Jun 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/bitvm-enabling-efficient-verifiable-computation-in-bitcoin/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/bitvm-enabling-efficient-verifiable-computation-in-bitcoin/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/bitvm-enabling-efficient-verifiable-computation-in-bitcoin/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;Bitcoin was the first blockchain in history, enabling a peer-to-peer electronic cash system for the first time. Introduced in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;bitcoin.org&#x2F;bitcoin.pdf&quot;&gt;2008 by Satoshi Nakamoto&lt;&#x2F;a&gt;, it provided an elegant yet simple construction to enable people from across the world to store and exchange value over a permissionless and censorship-resistant network.&lt;&#x2F;p&gt;
&lt;p&gt;An important drawback from all blockchains is that they suffer from scalability issues, which stems from the blockchain trilemma between security, decentralization and scalability. The fact that all nodes have to do the same amount of work to secure the network limits the throughput, since the less powerful ones act as bottlenecks. Zero-knowledge proofs allow a party, the prover, to convince another, the verifier, that a given statement is true, without revealing anything else other than the validity of the statement. These proofs are much faster to verify than naïve re-execution.&lt;&#x2F;p&gt;
&lt;p&gt;The smart contract capabilities in Bitcoin are limited to basic types, such as signature, timelocks and hashlocks. Besides, Bitcoin’s block size and stack (limited to 1000 elements) are important constraints when it comes to running programs. Bitcoin was not designed to carry out stateful computation, that is, computation that can persist through multiple transactions and user interactions. There a couple of ways of achieving stateful computation with varying security assumptions:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Multisigs: a predetermined set of $n$ parties oversee the computation. It assumes there are at least $t$-of-$n$ honest parties for both safety and liveness. While this is the most straightforward construction, it has undesirable security assumptions for a censorship resistant and permissionless network.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Covenants: they allow the locking script to constrain the spending transaction. This allows for data and logical persistence in Bitcoin without additional assumptions. However, covenants are not available in Bitcoin and would require an upgrade.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. ColliderScript: uses a prohibitive amount of computation to emulate covenants. On the upside, it does not require trusted parties and has essentially the same security guarantees as covenants.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The BitVMs are a paradigm that allows for the execution of arbitrary programs in Bitcoin, achieving greater expressivity while keeping the security of Bitcoin’s consensus. There are other proposals, such as &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2025&#x2F;591.pdf&quot;&gt;ColliderVM&lt;&#x2F;a&gt;. In this post, we will discuss some designs for the BitVM and their tradeoffs. Having more general compute capabilities would allow us to build bridges, L2 and general smart contracts on top of Bitcoin.&lt;&#x2F;p&gt;
&lt;p&gt;There have been several advances and criticism on these approaches. For example, see&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [advances and breakthroughs on BitVM](https:&#x2F;&#x2F;x.com&#x2F;david_seroy&#x2F;status&#x2F;1930342753961161172),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [BitVM on X](https:&#x2F;&#x2F;x.com&#x2F;ercwl&#x2F;status&#x2F;1936774866432110678),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Transfer of Ownership by Fairgate Labs](https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2025&#x2F;964.pdf),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [On proving pairings by Alpen Labs](https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2024&#x2F;640.pdf),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Why BitVM bridges are unsafe](https:&#x2F;&#x2F;medium.com&#x2F;@twhittle&#x2F;bitvm-bridges-considered-unsafe-9e1ce75c8176),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [How adding a simple opcode could make zk a reality in Bitcoin](https:&#x2F;&#x2F;x.com&#x2F;ercwl&#x2F;status&#x2F;1918938164929962268),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Engineering challenges regarding circuit sizes](https:&#x2F;&#x2F;x.com&#x2F;dntse&#x2F;status&#x2F;1937843989031555124).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;challenges&quot;&gt;Challenges&lt;&#x2F;h2&gt;
&lt;p&gt;Bitcoin script has limited expressivity, making the execution of arbitrary programs extremely expensive. For example, executing the verification of a Groth16 proof, which in a consumer-end laptop can be carried out in few milliseconds, requires up to 3GB in storage space-almost three orders of magnitude more than the 4MB blockspace available right now! Doing operations on-chain is expensive, both in terms of space and wasted resources, so being able to move as much as possible of the computation off-chain can result in greater efficiency. In Ethereum, using ZK proofs is more straightforward, since verification contracts are deployed once and we can call them whenever needed. Even if verification is quite expensive, we can always use recursive proof verification (such as Aligned’s proof aggregation mode) to combine several proofs into one and amortize the cost among the constituent proofs.&lt;&#x2F;p&gt;
&lt;p&gt;In Bitcoin, we will have to leverage optimistic computation, assuming the party submitting the proof is behaving honestly, and different parties will be able to challenge him, forcing the disclosure of intermediate steps and allowing them to provide fraud proofs showing where the submitter cheated. That way, the prover does not have to present most of the steps unless he is challenged. This is actually an example of a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2023&#x2F;1472.pdf&quot;&gt;naysayer’s proof&lt;&#x2F;a&gt;, which can help reduce the on-chain burden significantly.&lt;&#x2F;p&gt;
&lt;p&gt;A positive point of the construction is that we do not need to implement changes at the consensus level in Bitcoin.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bitvm-1&quot;&gt;BitVM-1&lt;&#x2F;h2&gt;
&lt;p&gt;This was the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;bitvm.org&#x2F;bitvm.pdf&quot;&gt;first design&lt;&#x2F;a&gt; to enable verifiable computation on top of Bitcoin. The basic point is that the prover can claim that a given function over certain inputs, evaluates to a result. If the claim is false, the verifier can trigger a dispute, provide a short fraud proof and punish the prover.&lt;&#x2F;p&gt;
&lt;p&gt;In this case, the design involved only two parties, a prover and a verifier. The off-chain computational burden and communication needed for the protocol is significant, limiting the kind of programs that can be executed. Future designs improved on these aspects, allowing for more parties to interact and further reducing the size of disputes and off-chain communicational and computational burden.&lt;&#x2F;p&gt;
&lt;p&gt;Prover and verifier compile the program into a binary circuit. Any arbitrary computer program can be represented as a circuit of 1s and 0s flowing through logic gates like AND, OR, and NAND. BitVM chooses NAND (NOT-AND) gates as they are universal – any computation can be built using enough NAND gates. The prover then commits to the binary circuit in a Taproot address having one leaf script for each binary gate in the circuit. A taproot tree or taptree makes an UTXO spendable by satisfying certain conditions; the spending conditions are tap-leaves of a Merkle tree. They then presign a sequence of transactions, to enable the challenge-response dynamics. After this, they can make on-chain deposits to the address, which activates the contract and they can start exchaning off-chain data to produce changes in the circuit. Should the prover make false claims, the verifier can take his deposit.&lt;&#x2F;p&gt;
&lt;p&gt;How does the prover commit to a circuit? Basically, for each &lt;code&gt;bit&lt;&#x2F;code&gt; he wants to commit to, he has two hashes, &lt;code&gt;hash0&lt;&#x2F;code&gt; and &lt;code&gt;hash1&lt;&#x2F;code&gt;. If he wants to set the &lt;code&gt;bit&lt;&#x2F;code&gt; to 0, he reveals the preimage of &lt;code&gt;hash0&lt;&#x2F;code&gt; and if he wants to set &lt;code&gt;bit&lt;&#x2F;code&gt; to 1, he reveals the preimage of &lt;code&gt;hash1&lt;&#x2F;code&gt;. If at some point the prover ends up revealing both preimages, then the verifier can use them to punish the prover. The value of the bit is set in the stack by hashing the preimage and checking that is matches with one of the hashes. Any gate can be committed to by supplying two commitments to the input and one commitment to the output. Needless to say, this results in a huge blowup in memory footprint, since every bit will require two hashes, and the program has to be represented by a Boolean circuit, which may not be the most efficient form to represent it. Using other operations, such as those involving &lt;code&gt;u32&lt;&#x2F;code&gt; can result in a more compact representation.&lt;&#x2F;p&gt;
&lt;p&gt;Once everything is set, the prover and verifier can engage in a game of challenges and responses. If at some point any of them stops cooperating (there is a time limit), the other can claim the deposit. The leaves in the prover’s tree (representing the gates) can only be spent if he knows the preimage held by the verifier. If the prover tries to change at least one of the values used in the gate, he would be revealing the preimage of the undisclosed hash (either &lt;code&gt;hash0&lt;&#x2F;code&gt; or &lt;code&gt;hash1&lt;&#x2F;code&gt;) and the verifier would be in possession of both preimages and can punish the prover for misbehavior. Using binary search, the verifier can find the error efficiently in a few rounds of interaction. In order to reduce the on-chain footprint, prover and verifier can exchange the preimages off-chain. In case the prover doesn’t want to cooperate, the verifier can force him to disclose on-chain. A huge drawback is that disproving a computation involves nearly 70 transactions.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bitvm-2&quot;&gt;BitVM-2&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;bitvm.org&#x2F;bitvm_bridge.pdf&quot;&gt;BitVM-2&lt;&#x2F;a&gt; achieves several advantages in security and efficiency. For example, we can solve the problem of bridging from a t-of-n honest majority to existential honesty during setup, 1-of-n. The new design enabled multiple verifiers (allowing permissionless challenging) and the development of a bridge on top of it, which is a core component for L2 layers.&lt;&#x2F;p&gt;
&lt;p&gt;To be able to execute arbitrary programs, we will leverage SNARKs to generate a proof for the correct execution of the program and verify the proof on Bitcoin. Since verifying the proof is still expensive, we can have the prover commit to the results and, should watchers assume that he is cheating, can challenge him. The dispute can be solved in just 3 on-chain transactions, which is significantly less than in BitVM-1. To be able to run the verification, we proceed as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. The verification program (at least 1.2 GB for Groth16 after optimizations) is broken up into subprograms, each at most 4 MB. Each chunk can be run in a single Bitcoin block. The programs run sequentially, and each depends on the output of the previous program.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. The prover&#x2F;operator commits to executing the program, presigning especially crafted messages and taproot trees to ensure that he can withdraw funds and still be challenged for misbehavior.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. When he wants to withdraw funds, he must provide the output of the SNARK verifier on-chain and stake capital.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Anyone can check the result with their (local) execution of the SNARK verifier and the public input (which should be available). In other words, other parties can run the full verification on chain and compare their results with the one published by the prover.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. If there is a difference, anyone can challenge the prover, who is forced to reveal the whole computation on-chain.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    6. Anyone can then find the wrong chunks, execute them on-chain, proving that the results for the subprogram don&amp;#39;t match and slash the prover.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To avoid malicious verifiers from challenging correct executions just to increase the cost for the prover, the verifiers have to pay a fee, which should be at least equal to the cost of posting an intermediate step.&lt;&#x2F;p&gt;
&lt;p&gt;The BitVM-2 could be implemented in a simpler fashion if covenants where available in Bitcoin. These are a proposed class of spending constraints allowing a locking script to restrict how the coins in UTXOs can be spent in the future. To circunvent this, during the setup phase of every instance of the BitVM, a committee of $n$ signers creates a new key pair, presigns messages with the key that should be used to spend the UTXO, establishing that an $n$-of-$n$ quorum must be reached. The members then delete their keys, ensuring that things can only be spent in the intended way. As long as a single one of them complies with this, we ensure that the constraints are enforced.&lt;&#x2F;p&gt;
&lt;p&gt;There are a couple of objections to this design, particularly, the bridge. For example, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;@twhittle&#x2F;bitvm-bridges-considered-unsafe-9e1ce75c8176&quot;&gt;here&lt;&#x2F;a&gt; it is shown that the bridge is secure so long as the operator is collaterallized at least 1:1. Different options are considered in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;stacker.news&#x2F;items&#x2F;495391&quot;&gt;following discussion&lt;&#x2F;a&gt;. The fact that security requires very large liquidity poses a great threat and has practical implications. Another drawback of this design is the still high cost of asserting and disproving a transaction, with a high on-chain footprint.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bitvm-3&quot;&gt;BitVM-3&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;bitvm.org&#x2F;bitvm3.pdf&quot;&gt;BitVM-3&lt;&#x2F;a&gt; uses garbled circuits to reduce the on-chain footprint of its predecessor. The circuit is designed to conditionally reveal a secret only if the garbler provides an invalid SNARK proof, acting as a fraud proof. Garbled circuits are a technique from secure two-party computation (Yao’s protocol) where one party (garbler) creates an encrypted version of a boolean circuit and provides “keys” for the input values such that the other party (evaluator) can evaluate the circuit without learning intermediate values – except for the final output, which in certain cases can be a secret reveal. In the context of BitVM3, the idea is that the Prover garbles the SNARK verifier circuit in such a way that if the SNARK proof provided is invalid, the garbled circuit’s output reveals a secret (which serves as a fraud proof).&lt;&#x2F;p&gt;
&lt;p&gt;The largest cost involves sharing the circuit, which takes 5 TB of memory. While this can take several days, it is a one-time setup cost. Asserting a transaction takes around 56 kB, while disproving a transaction involves roughly 200 bytes (compared to between 2 and 4 MB in BitVM-2). This cost reduction puts proof verification in Bitcoin in the realm of feasibility, though we still need to overcome the large communication costs of the circuit, which luckily will go down with further optimizations.&lt;&#x2F;p&gt;
&lt;p&gt;The garbling of the circuit relies on RSA. Each wire in the circuit has two possible keys corresponding to 0 or 1. The garbler (Prover) generates these such that only the correct combination yields a meaningful output key. According to the BitVM3 text, the garbler selects an RSA modulus $N = (2p + 1)(2q + 1)$ (product of two safe primes) and some public exponents $e, e_1 , e_2 , e_3 , e_4$. There are also secret exponents, $d, d_1 , d_2 , d_3 , d_4$ and $h = e_1 e_4 d_2 - e_3$. The $e_i$ and $d_i$ are inverses modulo $\phi (N)&#x2F;4 = pq$, that is $e_i d_i \equiv 1 \pmod{pq}$. Using the secret factors of $N$ (the trapdoor), the garbler computes wire label values such that the relationships between them hold if and only if the gate’s logical truth table is satisfied. For the output labels $c_0, c_1$ from the circuit, he computes the secret input wires $a_0, a_1, b_0, b_1$ from the following equations:&lt;br &#x2F;&gt;
$$
\begin{align*}
b_0 &amp;amp;= (c_1 c_0^{-1} )^{ h^{-1} } \pmod{N} \\
b_1 &amp;amp;= b_0^{ e_1 d_2} \pmod{N} \\
a_0 &amp;amp;= c_0^d b_0^{ - e_1 d} \pmod{N} \\
a_1 &amp;amp;= c_0^d b_0^{ - e_3 d} \pmod{N}
\end{align*}
$$&lt;&#x2F;p&gt;
&lt;p&gt;These exponentiations can be computed efficiently, since the exponents $e_i$ are chosen as small numbers. Besides, $b_0^d$ and $c_0^d$ can be computed just once and reused in the calculations.&lt;&#x2F;p&gt;
&lt;p&gt;The garbler starts from the output of the circuit and works backwards, producing the labels $a_0 , a_1 , b_0 , b_1$ for each gate. For a preceding gate with output feeding into the first input of the next gate, use $c_0 = a_0$ and $c_1 = a_1$ and if it is for the other input, use $b_0$ and $b_1$.&lt;&#x2F;p&gt;
&lt;p&gt;To be able to handle more general gates (with fan-out &amp;gt; 1, that is, more than one output), the garbler precomputes and publishes a static factor $T_{ik}$. For an output wire $W_{y}$ using labels $l_{y0} , l_{y1}$, feeds and input wire $W_x$, the static factor is given by&lt;br &#x2F;&gt;
$$l_{xi,k} = l_{yi,k} T_{ik}$$&lt;br &#x2F;&gt;
so that $T_{ik} = l_{xi,k} l_{yi,k}^{ - 1 }$. The adaptors become part of the public parameters of the circuit.&lt;&#x2F;p&gt;
&lt;p&gt;We can also reblind the labels several times (which amounts to reusing the circuit several times). This is useful to define smaller subcircuits which are used several times, such as field arithmetic or elliptic curve operations. For each round of reblinding, the garbler needs to publish a new $u_k$ which is pairwise coprime with the exponents of previous rounds (the only common divisor of $u_k$ and $u_i$ must be 1).&lt;&#x2F;p&gt;
&lt;p&gt;In case we are using different subcircuits for field operations, we need to add connectors linking the output of one subcircuit to the input of another one. To avoid telescoping attacks, there are two copies of every subcircuit (for example, MulA and MulB) and forbid the use of the same type twice in a row.&lt;&#x2F;p&gt;
&lt;p&gt;The verifier can check the correctness of the garbled circuit’s structure by checking each gate in plaintext. Thus, the garbler only needs to prove in zero-knowledge that the circuit’s inputs were correctly reblinded, and this involves only few exponentiations. If the prover misbehaves by providing a wrong calculation, the circuit will reveal the hash of the output label for 0 (a short string), which is used as fraud proof.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;BitVM and its variants are a significant milestone in Bitcoin’s evolution, showing that it is possible to have general computation on top of Bitcoin (like Ethereum), without changes to how Bitcoin’s consensus works. The core idea is based on naysayer’s proofs, which reduces the on-chain footprint, representing the highest cost in the protocol. Since verifying the proof on-chain is expensive, we can have the prover post a claim on-chain and watchers&#x2F;verifiers can do the check off-chain and dispute the prover’s claim using a short proof on-chain. BitVM had a large challenge and response game, involving several transactions and with a large finality. BitVM-2 reduced the response and challenge game to only 3 transactions, but the costs remained high. BitVM-3 uses garbled circuits to further reduce the costs of proving and challenging to 56 kB and 200 bytes, at the expense of a very large setup. It is clear that research and engineering have been improving over the last year and that it won’t be long before we have trust-minimized bridges, L2s and general smart contracts on Bitcoin. In upcoming posts, we will cover more in depth different aspects of Bitcoin, its L2 solutions and other virtual machines.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Diving deep into Binius M3 arithmetization using Merkle tree inclusion as an example</title>
          <pubDate>Mon, 23 Jun 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/diving-deep-into-binius-m3-arithmetization-using-merkle-tree/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/diving-deep-into-binius-m3-arithmetization-using-merkle-tree/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/diving-deep-into-binius-m3-arithmetization-using-merkle-tree/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;At the heart of any Zero-Knowledge Proof (ZKP) system lies the concept of arithmetization, the process of transforming a computational problem into a mathematical problem that can be expressed and verified within a specific algebraic structure, such as polynomials or arithmetic circuits. Within the Binius framework, this arithmetization is managed through the &lt;strong&gt;Multi-Multiset Matching (M3)&lt;&#x2F;strong&gt; system, which introduces significant changes and improvements compared to more commonly used arithmetizations.&lt;&#x2F;p&gt;
&lt;p&gt;While previous posts focused on the mathematical foundations used by Binius—such as &lt;a href=&quot;&#x2F;the-fields-powering-binius&#x2F;&quot;&gt;binary fields&lt;&#x2F;a&gt; and &lt;a href=&quot;&#x2F;additive-fft-background&#x2F;&quot;&gt;additive FFT&lt;&#x2F;a&gt;—this post aims to explore how Binius M3 system is implemented. To do so, we take a deep dive into a specific gadget: the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;IrreducibleOSS&#x2F;binius&#x2F;tree&#x2F;main&#x2F;crates&#x2F;m3&#x2F;src&#x2F;gadgets&#x2F;merkle_tree&quot;&gt;Merkle tree&lt;&#x2F;a&gt;. By walking through this example in detail, we aim to understand how constraint systems, tables, and channels are represented and handled in code.&lt;&#x2F;p&gt;
&lt;p&gt;To gain a more general intuition about why the tables and arithmetization techniques we explain in detail here actually work, we strongly recommend reading &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.binius.xyz&#x2F;basics&#x2F;arithmetization&#x2F;m3&quot;&gt;Binius M3 documentation&lt;&#x2F;a&gt;. It’s very clear and presents toy examples that help illustrate the core ideas.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;m3-general-idea&quot;&gt;M3 General Idea&lt;&#x2F;h2&gt;
&lt;p&gt;Unlike traditional arithmetizations that often rely on a sequential main execution trace, M3 distinguishes itself by not requiring a main trace or for its tables to be sequential. In M3, tables are merely declarative instances, specifically designed for the purpose of the proof. The prover fills these tables with data relevant to the computation, and these tables serve as a source for interacting with a key component: channels.&lt;&#x2F;p&gt;
&lt;p&gt;Within M3, tables and channels are the fundamental pillars for building and verifying complex computations. &lt;strong&gt;Tables&lt;&#x2F;strong&gt; are the primary means of representing and structuring computation data, functioning as collections of columns where each row represents a step or an instance of an operation. For example, in the context of a Merkle Tree, some tables will have parent and children nodes data.&lt;&#x2F;p&gt;
&lt;p&gt;Complementing tables, &lt;strong&gt;channels&lt;&#x2F;strong&gt; act as communication conduits within the M3 constraint system. They facilitate the flow of data between different tables or between tables and the external world (such as public inputs and outputs). Tables &lt;strong&gt;push&lt;&#x2F;strong&gt; into or &lt;strong&gt;pull&lt;&#x2F;strong&gt; from channels data. This mechanism is crucial for connecting various parts of a complex computation, ensuring that data dependencies are correctly maintained and verifiable. To verify the validity of a proof, the verifier simply needs to check that all channels are &lt;strong&gt;balanced&lt;&#x2F;strong&gt; —meaning that the data pushed into a channel matches the data pulled from it.&lt;&#x2F;p&gt;
&lt;p&gt;While M3 also relies on polynomially-constrained tables, as previous schemes do, it departs from traditional approaches by using these tables solely to support channel balancing, rather than as a vehicle for constructing a global execution trace.&lt;&#x2F;p&gt;
&lt;p&gt;In this post, we’ll explore specific examples of tables and channels within the Binius Merkle Tree constraint system, illustrating how they are used to build a verifiable proof of Merkle Tree inclusion. To see all of that theory in action, the Merkle Tree example wraps the setup in a single helper: &lt;code&gt;MerkleTreeCS&lt;&#x2F;code&gt;. A call to &lt;code&gt;MerkleTreeCS::new&lt;&#x2F;code&gt; sets up five tables, opens three channels, and returns a constraint system that’s ready to be filled with path data. With the plumbing taken care of, we can now look at what each table and channel does.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;merkletreecs&quot;&gt;MerkleTreeCS&lt;&#x2F;h2&gt;
&lt;p&gt;The &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;IrreducibleOSS&#x2F;binius&#x2F;blob&#x2F;main&#x2F;crates&#x2F;m3&#x2F;src&#x2F;gadgets&#x2F;merkle_tree&#x2F;mod.rs#L45&quot;&gt;MerkleTreeCS&lt;&#x2F;a&gt; (Merkle Tree Constraint System) consists of 5 tables and 3 channels that work together to ensure the correctness of Merkle paths verification.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;tables&quot;&gt;Tables&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `merkle_path_table_left`: A table of type `NodesTable` that handles Merkle paths where only the left child must be pulled from a channel. We&amp;#39;ll see in detail what this means later on.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `merkle_path_table_right`: A table of type NodesTable that handles cases where only the right child is pulled.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `merkle_path_table_both`: A table of type `NodesTable` that handles cases where both left and right children are pulled.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `root_table`: A table of type `RootTable` that reconciles the final values of Merkle paths with the expected roots.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `incr_table`: A table of type `IncrLookup`. A lookup table for increment operations to verify the depth relationships between parent and children nodes.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;channels&quot;&gt;Channels:&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `nodes_channel` \- Manages intermediate nodes in Merkle paths (format: `[Root ID, Digest, Depth, Index]`)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `roots_channel` \- Handles root verification (format: `[Root ID, Digest]`)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `lookup_channel` \- Coordinates increment operations to verify that child depth is the parent depth plus one.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;initialization&quot;&gt;Initialization&lt;&#x2F;h3&gt;
&lt;p&gt;The &lt;code&gt;MerkleTreeCS::new()&lt;&#x2F;code&gt; method constructs the entire constraint system. The main goal of this method is to add the tables and channels to &lt;code&gt;cs&lt;&#x2F;code&gt; (the constraint system) and create the &lt;code&gt;MerkleTreeCS&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn new(cs: &amp;amp;mut ConstraintSystem) -&amp;gt; Self {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let nodes_channel = cs.add_channel(&amp;quot;merkle_tree_nodes&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let roots_channel = cs.add_channel(&amp;quot;merkle_tree_roots&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let lookup_channel = cs.add_channel(&amp;quot;incr_lookup&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let permutation_channel = cs.add_channel(&amp;quot;permutation&amp;quot;);  &#x2F;&#x2F; ← NEW CHANNEL!&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Create the three Merkle path tables&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let merkle_path_table_left =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        NodesTable::new(cs, MerklePathPullChild::Left, nodes_channel, lookup_channel);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let merkle_path_table_right =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        NodesTable::new(cs, MerklePathPullChild::Right, nodes_channel, lookup_channel);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let merkle_path_table_both =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        NodesTable::new(cs, MerklePathPullChild::Both, nodes_channel, lookup_channel);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let root_table = RootTable::new(cs, nodes_channel, roots_channel);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Create the increment lookup table with the new permutation channel&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut table = cs.add_table(&amp;quot;incr_lookup_table&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let incr_table = IncrLookup::new(&amp;amp;mut table, lookup_channel, permutation_channel, 20);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Self { &#x2F;* ... *&#x2F; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As can be seen, there is an extra channel not mentioned before:&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;permutation_channel&lt;&#x2F;code&gt; is a new channel introduced specifically for the &lt;code&gt;IncrLookup&lt;&#x2F;code&gt; table. This channel serves a crucial purpose in the lookup table verification process. It ensures that the two columns in IncrLookup are permutations of each other. These columns are called &lt;code&gt;entries_ordered&lt;&#x2F;code&gt; and &lt;code&gt;entries_sorted&lt;&#x2F;code&gt;, and we will examine them in detail later.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;an-example-step-by-step&quot;&gt;An Example Step by Step&lt;&#x2F;h2&gt;
&lt;p&gt;We believe that the best way to understand how the constraint system is built and how the tables are created is by looking at an example. For this, we’ll use the example provided by Binius in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;IrreducibleOSS&#x2F;binius&#x2F;blob&#x2F;main&#x2F;examples&#x2F;merkle_tree.rs&quot;&gt;merkle_tree.rs&lt;&#x2F;a&gt;, where we’ll be able to construct a tree, some paths, the constraint system, and the proof that validates those paths.&lt;&#x2F;p&gt;
&lt;p&gt;The file begins with some arguments that we’re going to adjust. For simplicity, we want to create a tree with 8 leaves and prove that two of them are part of the tree. In other words, we’ll take &lt;code&gt;default_value_t = 3&lt;&#x2F;code&gt; for the &lt;code&gt;log_leaves&lt;&#x2F;code&gt; (since we want an 8-leaves tree), &lt;code&gt;default_value_t = 1&lt;&#x2F;code&gt; for &lt;code&gt;log_paths&lt;&#x2F;code&gt; (since we want two prove two paths), and &lt;code&gt;default_value_t = 1&lt;&#x2F;code&gt; for &lt;code&gt;log_inv_rate&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;struct Args {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;&#x2F; The number of leaves in the merkle tree.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;&#x2F; By default 8 leaves.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    #[arg(long, default_value_t = 3, value_parser = value_parser!(u32).range(1..))]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    log_leaves: u32,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;&#x2F; The number of Merkle paths to verify.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;&#x2F; By default 2 paths.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    #[arg(short,long, default_value_t = 1, value_parser = value_parser!(u32).range(1..))]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    log_paths: u32,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;&#x2F; The negative binary logarithm of the Reed–Solomon code rate.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    #[arg(long, default_value_t = 1, value_parser = value_parser!(u32).range(1..))]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    log_inv_rate: u32,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;building-the-tree-and-paths&quot;&gt;Building the Tree and paths&lt;&#x2F;h3&gt;
&lt;p&gt;Now that we have the arguments, if you follow the function &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;IrreducibleOSS&#x2F;binius&#x2F;blob&#x2F;main&#x2F;examples&#x2F;merkle_tree.rs#L39&quot;&gt;main()&lt;&#x2F;a&gt; you’ll see that the tree and the Merkle paths are built there. Let’s add some prints in this part of the code to see their values.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;* ... *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let mut rng = StdRng::seed_from_u64(0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Create a Merkle Tree with 8 leaves&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let leaves = (0..1 &amp;lt;&amp;lt; args.log_leaves)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .map(|_| rng.r#gen::&amp;lt;[u8; 32]&amp;gt;())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .collect::&amp;lt;Vec&amp;lt;_&amp;gt;&amp;gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let tree = MerkleTree::new(&amp;amp;leaves);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let roots: [u8; 32] = tree.root();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;println!(&amp;quot;--------- Merkle tree data -------&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;println!(&amp;quot;Leaves: {:?}&amp;quot;, leaves);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;println!(&amp;quot;Root: {:?}&amp;quot;, roots);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let paths = (0..1 &amp;lt;&amp;lt; args.log_paths)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .map(|_| {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let index = rng.gen_range(0..1 &amp;lt;&amp;lt; args.log_leaves);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        println!(&amp;quot;------- Path data -------&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        println!(&amp;quot;Proving leaf index: {:?}&amp;quot;, index);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        println!(&amp;quot;Proving leaf: {:?}&amp;quot;, leaves[index]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        println!(&amp;quot;Merkle tree path: {:?}&amp;quot;, tree.merkle_path(index));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        MerklePath {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            root_id: 0,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            index,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            leaf: leaves[index],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            nodes: tree.merkle_path(index),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .collect::&amp;lt;Vec&amp;lt;_&amp;gt;&amp;gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;* ... *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This should print first the eight leaves and the root (each of them is a 32-byte array):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--------- Merkle tree data -------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Leaves: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [127, 178, 123, 148, 22, 2, 208, 29, 17, 84, 34, 17, 19, 79, 199, 26, 172, 174, 84, 227, 126, 125, 0, 123, 187, 123, 85, 239, 240, 98, 162, 132], &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [154, 99, 40, 60, 186, 240, 253, 188, 235, 31, 100, 121, 177, 151, 243, 168, 141, 208, 216, 9, 47, 231, 42, 124, 86, 40, 21, 56, 115, 139, 7, 226], &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [114, 238, 165, 17, 148, 16, 151, 58, 227, 40, 173, 146, 145, 98, 104, 18, 142, 219, 71, 16, 110, 26, 214, 168, 195, 213, 69, 132, 155, 138, 184, 27], &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [16, 24, 93, 38, 2, 59, 54, 16, 206, 183, 217, 245, 125, 73, 210, 179, 135, 99, 161, 43, 43, 189, 250, 147, 39, 90, 255, 24, 42, 251, 149, 220],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [118, 35, 234, 226, 120, 82, 64, 185, 61, 18, 177, 106, 102, 216, 22, 16, 124, 220, 140, 137, 199, 16, 143, 255, 32, 149, 225, 141, 223, 239, 137, 134], &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [177, 24, 234, 85, 97, 98, 77, 166, 204, 83, 123, 174, 213, 110, 96, 47, 147, 140, 128, 78, 39, 248, 49, 150, 97, 12, 136, 40, 199, 35, 247, 152], &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [80, 79, 178, 164, 68, 97, 204, 11, 235, 179, 37, 40, 14, 217, 19, 10, 89, 187, 219, 49, 28, 1, 253, 115, 73, 9, 161, 31, 158, 72, 102, 40], &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [180, 59, 54, 61, 129, 174, 139, 104, 153, 70, 236, 229, 198, 130, 205, 89, 138, 101, 234, 191, 246, 58, 53, 114, 223, 228, 95, 181, 173, 229, 139, 220]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Root: [193, 178, 67, 64, 61, 105, 200, 119, 129, 200, 250, 91, 108, 49, 178, 161, 234, 142, 150, 145, 206, 128, 43, 153, 216, 191, 196, 183, 198, 179, 118, 122]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then the first Merkle path:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;------- Path data -------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Proving leaf index: 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Proving leaf: [16, 24, 93, 38, 2, 59, 54, 16, 206, 183, 217, 245, 125, 73, 210, 179, 135, 99, 161, 43, 43, 189, 250, 147, 39, 90, 255, 24, 42, 251, 149, 220]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Merkle tree path: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [114, 238, 165, 17, 148, 16, 151, 58, 227, 40, 173, 146, 145, 98, 104, 18, 142, 219, 71, 16, 110, 26, 214, 168, 195, 213, 69, 132, 155, 138, 184, 27], &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [246, 247, 101, 36, 57, 192, 24, 48, 162, 208, 160, 30, 187, 154, 180, 176, 208, 104, 135, 216, 175, 8, 0, 249, 96, 50, 194, 72, 102, 219, 184, 27], &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [70, 219, 30, 17, 251, 21, 8, 37, 23, 248, 120, 106, 49, 210, 42, 247, 15, 227, 231, 151, 101, 7, 187, 203, 29, 109, 186, 223, 43, 126, 183, 173]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And finally, the second Merkle path:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;------- Path data -------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Proving leaf index: 4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Proving leaf: [118, 35, 234, 226, 120, 82, 64, 185, 61, 18, 177, 106, 102, 216, 22, 16, 124, 220, 140, 137, 199, 16, 143, 255, 32, 149, 225, 141, 223, 239, 137, 134]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Merkle tree path: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [177, 24, 234, 85, 97, 98, 77, 166, 204, 83, 123, 174, 213, 110, 96, 47, 147, 140, 128, 78, 39, 248, 49, 150, 97, 12, 136, 40, 199, 35, 247, 152],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [44, 37, 79, 124, 156, 84, 213, 102, 239, 101, 1, 89, 211, 73, 117, 58, 143, 41, 102, 47, 67, 32, 248, 100, 29, 138, 44, 204, 232, 177, 216, 54], &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [124, 166, 97, 100, 173, 242, 98, 95, 141, 158, 147, 144, 202, 239, 150, 192, 0, 99, 9, 138, 61, 19, 65, 163, 160, 4, 227, 66, 233, 115, 199, 3]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So, our Merkle tree should look like the one below. To make the graph more readable, we only wrote the first byte of each node, even though we should have written all 32 bytes. The first path is shown in green, and the second one in blue. You may be wondering how we know the content of the middle nodes “181” and “67”, since they are neither the leaves, the root, nor part of the Merkle paths. We got that information from prints we’ll make later.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;BJe-hoFQlx.png&quot; alt=&quot;image&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In the remainder of this post, we’ll explain the three types of tables used in a &lt;code&gt;MerkleTreeCS&lt;&#x2F;code&gt;: &lt;strong&gt;NodesTable&lt;&#x2F;strong&gt; , &lt;strong&gt;RootTable&lt;&#x2F;strong&gt; and &lt;strong&gt;IncrLookup&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;What are they for? How are they populated? How do they interact with the different channels? We’ll answer these questions using the tree we just built as an illustration.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;nodestable&quot;&gt;NodesTable&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;purpose&quot;&gt;Purpose&lt;&#x2F;h3&gt;
&lt;p&gt;This table type is designed to handle the relationships between parent and child nodes. Each row in the table corresponds to a &lt;code&gt;MerklePathEvent&lt;&#x2F;code&gt;, which captures the interaction between three related nodes: two children (left and right) and their parent.&lt;&#x2F;p&gt;
&lt;p&gt;When proving Merkle tree paths, the table is populated by traversing each path and creating one row for every parent-children trio encountered. This systematic approach ensures that all necessary node relationships are properly encoded and can be verified through the constraint system.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;content-and-columns&quot;&gt;Content and Columns&lt;&#x2F;h3&gt;
&lt;p&gt;The &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;IrreducibleOSS&#x2F;binius&#x2F;blob&#x2F;main&#x2F;crates&#x2F;m3&#x2F;src&#x2F;gadgets&#x2F;merkle_tree&#x2F;mod.rs#L218&quot;&gt;NodesTable&lt;&#x2F;a&gt; contains a set of columns that can be categorized into three main groups:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. **MerklePathEvent Data**  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;These columns store the fundamental information about each node relationship:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * `root_id`: Identifies which Merkle tree the three nodes belong to.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * `left_columns`, `right_columns`: Store the digest values of the left and right child nodes.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * `parent_depth`, `child_depth`: indicate the tree levels where the parent and children nodes are. The levels (or depths) start at 0 in the top (the root) and continues until $\log_2 (\text{leaves}.\text{len()})$, ending at the leaves.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * `parent_index`, `left_index`, `right_index_packed`: Store the positional indices of nodes.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * `_pull_child`: Specifies which child node needs to be pulled from the channel.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. **Groestl-256 Hash Computation**  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;These columns handle the cryptographic hash operations:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * `state_out_shifted`: Contains the concatenated bytes of left and right children organized for the Groestl-256 permutation.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * `permutation_output_columns`: Store the bytes after the Groestl-256 output transformation.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * `permutation`: The Groestl-256 permutation gadget.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: This serves as a clear example of the power of gadgets. In a sense, the gadget responsible for verifying a Merkle path delegates the task of checking the validity of the hash function to another gadget (not detailed in this post, but it operates in an analogous way). This modular approach allows us to build proofs for more complex programs in a clean and scalable manner.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. **Depth Constraint**&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;increment&lt;&#x2F;code&gt;: A gadget used to ensure the child node depth is exactly one more than the parent node depth.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;initialization-1&quot;&gt;Initialization&lt;&#x2F;h3&gt;
&lt;p&gt;The &lt;code&gt;NodesTable&lt;&#x2F;code&gt; is created through its &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;IrreducibleOSS&#x2F;binius&#x2F;blob&#x2F;main&#x2F;crates&#x2F;m3&#x2F;src&#x2F;gadgets&#x2F;merkle_tree&#x2F;mod.rs#L249&quot;&gt;new()&lt;&#x2F;a&gt; method. This initialization process involves:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Adding the table to the **constraint system** using `cs.add_table()`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Adding **committed columns** to the table using `table.add_committed()` or `table.add_committed_multiple()`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Adding **virtual columns** to the table using `table.add_packed()`, `table.add_shifted()` and `table.add_computed()`. In the [Binius documentation](https:&#x2F;&#x2F;www.binius.xyz&#x2F;building&#x2F;pattern&#x2F;declaring) you can see an explanation of the difference between committed and virtual columns.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: This is particularly relevant in M3, as it represents one of the key differences compared to other proving systems. Virtual columns play a fundamental role by allowing the prover to commit only to a reduced number of tables (committed columns), while avoiding the need to commit to the virtual ones. The reason this is possible is that all the information required to reconstruct the virtual columns from the committed ones is fully encoded in the constraint system.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Establishing a **zero constraint** to ensure that the concatenation of left and right children nodes equals the input of the parent hash. This is implemented using `table.assert_zero()`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;for i in 0..8 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    table.assert_zero(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        format!(&amp;quot;state_in_assert[{i}]&amp;quot;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        state_in_packed[i]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            - upcast_col(left_packed[i])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            - upcast_col(right_packed[i]) * B64::from(1 &amp;lt;&amp;lt; 32),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Setting up **flushing rules** that define how the table interacts with the [NodesChannel](https:&#x2F;&#x2F;github.com&#x2F;IrreducibleOSS&#x2F;binius&#x2F;blob&#x2F;main&#x2F;crates&#x2F;m3&#x2F;src&#x2F;gadgets&#x2F;merkle_tree&#x2F;mod.rs#L409) using `nodes_channel.push()` and `nodes_channel.pull()`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;channel-interaction&quot;&gt;Channel interaction&lt;&#x2F;h3&gt;
&lt;p&gt;Let’s explain a bit more the last point mentioned in the table initialization. The &lt;code&gt;NodesTable&lt;&#x2F;code&gt; interacts with the &lt;code&gt;NodesChannel&lt;&#x2F;code&gt; through the following push-pull rule: &lt;em&gt;Push Parent, Pull Child&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Push:** Parent node information (root ID, content, depth, and index) should be pushed to the channel.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Pull:** Depending on the `pull_child` input, pull either the left child, right child, or both children from the channel. For each path, only one child should be pulled, left or right depending the path route. But if there is a parent-children trio Merkle event that is used in different paths once pulling left and once pulling right, then both children are pulled.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;table-population&quot;&gt;Table population&lt;&#x2F;h3&gt;
&lt;p&gt;The struct &lt;code&gt;NodesTable&lt;&#x2F;code&gt; implements the &lt;code&gt;TableFiller&lt;&#x2F;code&gt; trait, with the core population logic in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;IrreducibleOSS&#x2F;binius&#x2F;blob&#x2F;main&#x2F;crates&#x2F;m3&#x2F;src&#x2F;gadgets&#x2F;merkle_tree&#x2F;mod.rs#L508&quot;&gt;fill()&lt;&#x2F;a&gt; function. For each &lt;code&gt;MerklePathEvent&lt;&#x2F;code&gt;, the function:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Extracts the node relationship data (parent, left child, right child)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Computes derived values like child indices and depth increments.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Fills the permutation state with the concatenated child node data.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Populates all table columns with the appropriate values.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This filling process transforms the trace data into the constraint system representation needed for proof generation and verification.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;our-example&quot;&gt;Our Example&lt;&#x2F;h3&gt;
&lt;p&gt;To understand what a &lt;code&gt;MerklePathEvent&lt;&#x2F;code&gt; is and how these tables are populated let’s look at our example.&lt;&#x2F;p&gt;
&lt;p&gt;In the &lt;code&gt;main()&lt;&#x2F;code&gt; function of &lt;code&gt;merkle_tree.rs&lt;&#x2F;code&gt; example, once we have the tree and the paths, the trace is generated and after that the tables are filled using the function &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;IrreducibleOSS&#x2F;binius&#x2F;blob&#x2F;main&#x2F;crates&#x2F;m3&#x2F;src&#x2F;gadgets&#x2F;merkle_tree&#x2F;mod.rs#L100&quot;&gt;fill_tables()&lt;&#x2F;a&gt;. Here we can add more prints to see what all this data looks like.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn fill_tables(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;amp;self,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    trace: &amp;amp;MerkleTreeTrace,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    cs: &amp;amp;ConstraintSystem,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    witness: &amp;amp;mut WitnessIndex,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; anyhow::Result&amp;lt;()&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Filter the MerklePathEvents into three iterators based on the pull child type.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let left_events = trace&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .nodes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .copied()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .filter(|event| event.flush_left &amp;amp;&amp;amp; !event.flush_right)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .collect::&amp;lt;Vec&amp;lt;_&amp;gt;&amp;gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let right_events = trace&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .nodes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .copied()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .filter(|event| !event.flush_left &amp;amp;&amp;amp; event.flush_right)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .collect::&amp;lt;Vec&amp;lt;_&amp;gt;&amp;gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let both_events = trace&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .nodes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .copied()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .filter(|event| event.flush_left &amp;amp;&amp;amp; event.flush_right)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .collect::&amp;lt;Vec&amp;lt;_&amp;gt;&amp;gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    println!(&amp;quot;------- Merkle Path Events -------&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    println!(&amp;quot;Left events: {:?}&amp;quot;, &amp;amp;left_events);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    println!(&amp;quot;Right events: {:?}&amp;quot;, &amp;amp;right_events);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    println!(&amp;quot;Both events: {:?}&amp;quot;, &amp;amp;both_events);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Fill the nodes tables based on the filtered events.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    witness.fill_table_parallel(&amp;amp;self.merkle_path_table_left, &amp;amp;left_events)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    witness.fill_table_parallel(&amp;amp;self.merkle_path_table_right, &amp;amp;right_events)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    witness.fill_table_parallel(&amp;amp;self.merkle_path_table_both, &amp;amp;both_events)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;*...*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This should print, first the left events:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Left events: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MerklePathEvent { &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        root_id: 0, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        left: [67, 45, 38, 237, 191, 26, 225, 172, 10, 94, 207, 176, 214, 146, 204, 230, 180, 241, 18, 217, 51, 18, 215, 92, 201, 50, 136, 22, 3, 172, 197, 55], &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        right: [44, 37, 79, 124, 156, 84, 213, 102, 239, 101, 1, 89, 211, 73, 117, 58, 143, 41, 102, 47, 67, 32, 248, 100, 29, 138, 44, 204, 232, 177, 216, 54], &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        parent: [70, 219, 30, 17, 251, 21, 8, 37, 23, 248, 120, 106, 49, 210, 42, 247, 15, 227, 231, 151, 101, 7, 187, 203, 29, 109, 186, 223, 43, 126, 183, 173], &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        parent_depth: 1, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        parent_index: 1, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        flush_left: true, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        flush_right: false &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MerklePathEvent { &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        root_id: 0, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        left: [118, 35, 234, 226, 120, 82, 64, 185, 61, 18, 177, 106, 102, 216, 22, 16, 124, 220, 140, 137, 199, 16, 143, 255, 32, 149, 225, 141, 223, 239, 137, 134], &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        right: [177, 24, 234, 85, 97, 98, 77, 166, 204, 83, 123, 174, 213, 110, 96, 47, 147, 140, 128, 78, 39, 248, 49, 150, 97, 12, 136, 40, 199, 35, 247, 152], &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        parent: [67, 45, 38, 237, 191, 26, 225, 172, 10, 94, 207, 176, 214, 146, 204, 230, 180, 241, 18, 217, 51, 18, 215, 92, 201, 50, 136, 22, 3, 172, 197, 55], &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        parent_depth: 2, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        parent_index: 2, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        flush_left: true, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        flush_right: false &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This event is a left one because the node that has to be pulled out from the channel is the left child “67”:&lt;br &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;r19SajY7ee.png&quot; alt=&quot;image&quot; &#x2F;&gt;&lt;br &#x2F;&gt;
The same with the second event. Here, the node that has to be pulled is the left child “118”:&lt;br &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;HJF1CjYXee.png&quot; alt=&quot;image&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;On the other hand, you should also see the prints of the right events:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Right events: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MerklePathEvent { &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        root_id: 0, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        left: [114, 238, 165, 17, 148, 16, 151, 58, 227, 40, 173, 146, 145, 98, 104, 18, 142, 219, 71, 16, 110, 26, 214, 168, 195, 213, 69, 132, 155, 138, 184, 27], &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        right: [16, 24, 93, 38, 2, 59, 54, 16, 206, 183, 217, 245, 125, 73, 210, 179, 135, 99, 161, 43, 43, 189, 250, 147, 39, 90, 255, 24, 42, 251, 149, 220], &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        parent: [181, 157, 35, 221, 161, 240, 65, 205, 125, 210, 142, 58, 147, 55, 148, 56, 221, 206, 216, 118, 104, 90, 130, 87, 219, 62, 104, 251, 27, 201, 113, 211], &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        parent_depth: 2, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        parent_index: 1, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        flush_left: false, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        flush_right: true &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MerklePathEvent { &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        root_id: 0, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        left: [246, 247, 101, 36, 57, 192, 24, 48, 162, 208, 160, 30, 187, 154, 180, 176, 208, 104, 135, 216, 175, 8, 0, 249, 96, 50, 194, 72, 102, 219, 184, 27], &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        right: [181, 157, 35, 221, 161, 240, 65, 205, 125, 210, 142, 58, 147, 55, 148, 56, 221, 206, 216, 118, 104, 90, 130, 87, 219, 62, 104, 251, 27, 201, 113, 211], &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        parent: [124, 166, 97, 100, 173, 242, 98, 95, 141, 158, 147, 144, 202, 239, 150, 192, 0, 99, 9, 138, 61, 19, 65, 163, 160, 4, 227, 66, 233, 115, 199, 3], &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        parent_depth: 1, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        parent_index: 0, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        flush_left: false, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        flush_right: true &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In these cases the nodes that have to be pulled are the right children:&lt;br &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;S19_AiY7ge.png&quot; alt=&quot;image&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;ByT3DLk4gg.png&quot; alt=&quot;image&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Finally, you’ll find a print of a both left and right event:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Both events: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MerklePathEvent { &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        root_id: 0, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        left: [124, 166, 97, 100, 173, 242, 98, 95, 141, 158, 147, 144, 202, 239, 150, 192, 0, 99, 9, 138, 61, 19, 65, 163, 160, 4, 227, 66, 233, 115, 199, 3], &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        right: [70, 219, 30, 17, 251, 21, 8, 37, 23, 248, 120, 106, 49, 210, 42, 247, 15, 227, 231, 151, 101, 7, 187, 203, 29, 109, 186, 223, 43, 126, 183, 173], &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        parent: [193, 178, 67, 64, 61, 105, 200, 119, 129, 200, 250, 91, 108, 49, 178, 161, 234, 142, 150, 145, 206, 128, 43, 153, 216, 191, 196, 183, 198, 179, 118, 122], &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        parent_depth: 0, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        parent_index: 0, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        flush_left: true, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        flush_right: true &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this case, if you are looking at the blue path, the right child node “70” has to be pulled, but if you are looking at the green path, the left child “124” has to be pulled. That’s why this event is both left and right:&lt;br &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;SJV1r2tmxx.png&quot; alt=&quot;image&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;roottable&quot;&gt;RootTable&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;purpose-1&quot;&gt;Purpose&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;RootTable&lt;&#x2F;code&gt; is a table within the Binius Merkle Tree constraint system that is responsible for reconciling the final values of Merkle paths with the declared Merkle roots. While &lt;code&gt;NodesTable&lt;&#x2F;code&gt; verifies the steps along a path, &lt;code&gt;RootTable&lt;&#x2F;code&gt; provides the ultimate cryptographic guarantee that these paths lead to the correct, pre-committed Merkle roots.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;content&quot;&gt;Content&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub struct RootTable {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub id: TableId,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub root_id: Col&amp;lt;B8&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub digest: [Col&amp;lt;B32&amp;gt;; 8]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This table contains the data -the Id and the digest (or content)- of the root nodes of all the trees we are analyzing, since we can prove different paths for different trees.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;initialization-2&quot;&gt;Initialization&lt;&#x2F;h3&gt;
&lt;p&gt;RootTable initialization is done by its method &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;IrreducibleOSS&#x2F;binius&#x2F;blob&#x2F;main&#x2F;crates&#x2F;m3&#x2F;src&#x2F;gadgets&#x2F;merkle_tree&#x2F;mod.rs#L469&quot;&gt;new()&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;impl RootTable {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub fn new(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        cs: &amp;amp;mut ConstraintSystem,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        nodes_channel: ChannelId,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        roots_channel: ChannelId,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ) -&amp;gt; Self {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;*...*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This function:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Adds a table to the `cs`:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let mut table = cs.add_table(&amp;quot;merkle_tree_roots&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Defines columns within that table (committed and&#x2F;or virtual):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let root_id = table.add_committed(&amp;quot;root_id&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let digest = table.add_committed_multiple(&amp;quot;digest&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let zero = table.add_constant(&amp;quot;zero&amp;quot;, [B32::ZERO]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Adds the flushing rules associated with that table and its channels (`nodes_channel` and `roots_channel`).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;table.pull(roots_channel_id, to_root_flush(root_id_upcasted, digest));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let mut nodes_channel = NodesChannel::new(&amp;amp;mut table, nodes_channel_id);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;nodes_channel.pull(root_id_upcasted, digest, zero, zero);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;flushing-rules&quot;&gt;Flushing Rules&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;RootTable&lt;&#x2F;code&gt; primarily interacts with the &lt;code&gt;nodes_channel&lt;&#x2F;code&gt; and &lt;code&gt;roots_channel&lt;&#x2F;code&gt; to perform its reconciliation. It will &lt;code&gt;pull&lt;&#x2F;code&gt; data from both channels to verify consistency.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **`nodes_channel`** : This channel carries information about all intermediate and final nodes of the Merkle paths. `RootTable` will `pull` the digest of the final node of a path from this channel.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **`roots_channel`** : This channel contains the actual Merkle roots that are being proven against. `RootTable` will `pull` these values to ensure that the path&amp;#39;s end-point matches one of the valid roots.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The flushing rules would ensure that the necessary data (final path node digests and declared root digests) are available to the &lt;code&gt;RootTable&lt;&#x2F;code&gt; for its internal consistency checks. This comparison forms the core of the zero-knowledge constraint for root verification, ensuring that the Merkle path indeed leads to the claimed root.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;incrlookup&quot;&gt;IncrLookup&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;purpose-2&quot;&gt;Purpose&lt;&#x2F;h3&gt;
&lt;p&gt;Beyond &lt;code&gt;NodesTable&lt;&#x2F;code&gt; and &lt;code&gt;RootTable&lt;&#x2F;code&gt;, the Binius Merkle Tree constraint system also utilizes &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;IrreducibleOSS&#x2F;binius&#x2F;blob&#x2F;main&#x2F;crates&#x2F;m3&#x2F;src&#x2F;gadgets&#x2F;indexed_lookup&#x2F;incr.rs#L161&quot;&gt;IncrLookup&lt;&#x2F;a&gt;. This is a specialized gadget designed to efficiently verify 8-bit increment operations with a carry bit. Instead of writing complex arithmetic constraints for each instance of an increment operation, &lt;code&gt;IncrLookup&lt;&#x2F;code&gt; allows the prover to simply demonstrate that each operation performed is present in a pre-defined table of all valid increment results. This significantly reduces the computational cost and proof size.&lt;&#x2F;p&gt;
&lt;p&gt;In the specific context of Merkle tree inclusion proofs, &lt;code&gt;IncrLookup&lt;&#x2F;code&gt; is used to ensure that in each &lt;code&gt;MerklePathEvent&lt;&#x2F;code&gt;, the child’s depth is exactly one greater than the parent’s depth.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;content-1&quot;&gt;Content&lt;&#x2F;h3&gt;
&lt;p&gt;The &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;IrreducibleOSS&#x2F;binius&#x2F;blob&#x2F;main&#x2F;crates&#x2F;m3&#x2F;src&#x2F;gadgets&#x2F;indexed_lookup&#x2F;incr.rs#L161&quot;&gt;IncrLookup&lt;&#x2F;a&gt; only has two columns &lt;code&gt;entries_ordered&lt;&#x2F;code&gt; and &lt;code&gt;entries_sorted&lt;&#x2F;code&gt;. Both columns have exactly the same values but sorted in different ways. We’ll see how these columns are filled later on.&lt;&#x2F;p&gt;
&lt;p&gt;The struct &lt;code&gt;IncrLookup&lt;&#x2F;code&gt; has one more field &lt;code&gt;lookup_producer&lt;&#x2F;code&gt;. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;IrreducibleOSS&#x2F;binius&#x2F;blob&#x2F;main&#x2F;crates&#x2F;m3&#x2F;src&#x2F;gadgets&#x2F;lookup.rs#L16&quot;&gt;LookupProducer&lt;&#x2F;a&gt; is the gadget in charge of creating the lookup table.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;initialization-3&quot;&gt;Initialization&lt;&#x2F;h3&gt;
&lt;p&gt;When the &lt;code&gt;MerkleTreeCS&lt;&#x2F;code&gt; is set up, an &lt;code&gt;IncrLookup&lt;&#x2F;code&gt; instance is created (see &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;IrreducibleOSS&#x2F;binius&#x2F;blob&#x2F;main&#x2F;crates&#x2F;m3&#x2F;src&#x2F;gadgets&#x2F;merkle_tree&#x2F;mod.rs#L87&quot;&gt;here&lt;&#x2F;a&gt;) through its method &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;IrreducibleOSS&#x2F;binius&#x2F;blob&#x2F;main&#x2F;crates&#x2F;m3&#x2F;src&#x2F;gadgets&#x2F;indexed_lookup&#x2F;incr.rs#L176&quot;&gt;new()&lt;&#x2F;a&gt;, which does the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Fixes the size for the columns:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;table.require_fixed_size(IncrIndexedLookup.log_size());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note that &lt;code&gt;IncrIndexedLookup.log_size()&lt;&#x2F;code&gt; is $2^9 = 512$ as you can see &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;IrreducibleOSS&#x2F;binius&#x2F;blob&#x2F;main&#x2F;crates&#x2F;m3&#x2F;src&#x2F;gadgets&#x2F;indexed_lookup&#x2F;incr.rs#L245&quot;&gt;here&lt;&#x2F;a&gt;. This is because each index $i \in {0, \ldots, 511}$ of the column will represent an incrementation of some certain input. The 8 less significant bits of $i$ tell us the input and the most significant bit tell us the carry.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Adds the `entries_ordered` and `entries_sorted` columns to the table.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Adds **flushing rules** for the `permutation_channel` of our constraint system to ensure that one column is the permutation of the other one:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Use flush to check that entries_sorted is a permutation of entries_ordered.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;table.push(permutation_chan, [entries_ordered]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;table.pull(permutation_chan, [entries_sorted]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Configures a `LookupProducer` to manage how entries are queried and to handle their multiplicities (how many times each specific increment operation occurs during the proof).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;table-population-1&quot;&gt;Table population&lt;&#x2F;h3&gt;
&lt;p&gt;As well as the other tables, the &lt;code&gt;incr_table&lt;&#x2F;code&gt; of the &lt;code&gt;MerkleTreeCS&lt;&#x2F;code&gt; is filled inside the function &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;IrreducibleOSS&#x2F;binius&#x2F;blob&#x2F;main&#x2F;crates&#x2F;m3&#x2F;src&#x2F;gadgets&#x2F;merkle_tree&#x2F;mod.rs#L100&quot;&gt;fill_tables()&lt;&#x2F;a&gt;, specifically in this part:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let lookup_counts = tally(cs, witness, &amp;amp;[], self.lookup_channel, &amp;amp;IncrIndexedLookup)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Fill the lookup table with the sorted counts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let sorted_counts = lookup_counts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .into_iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .enumerate()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .sorted_by_key(|(_, count)| Reverse(*count))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .collect::&amp;lt;Vec&amp;lt;_&amp;gt;&amp;gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;witness.fill_table_parallel(&amp;amp;self.incr_table, &amp;amp;sorted_counts)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let’s break down this code snippet in detail. For that, we have to understand what is the variable &lt;code&gt;lookup_counts&lt;&#x2F;code&gt; and what does the function &lt;code&gt;tally()&lt;&#x2F;code&gt; do.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;lookup-counts&quot;&gt;Lookup Counts&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;code&gt;lookup_counts&lt;&#x2F;code&gt; is a vector of 512 integer elements. This vector is the result of the function &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;IrreducibleOSS&#x2F;binius&#x2F;blob&#x2F;main&#x2F;crates&#x2F;m3&#x2F;src&#x2F;builder&#x2F;indexed_lookup.rs#L51&quot;&gt;tally()&lt;&#x2F;a&gt;. As its documentation explains, this function “determines the read counts of each entry in an indexed lookup table”. It iterates over every table of our constraint system looking for a specific flushing rule: a pull operation on the input channel. In our case, the input channel is called &lt;code&gt;lookup_channel&lt;&#x2F;code&gt;. Whenever it finds this flushing rule it adds 1 to the result vector at a specific index (that depends on the value being pulled).&lt;&#x2F;p&gt;
&lt;p&gt;To understand how this index is chosen let’s add some prints and see what happens in our example.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn tally&amp;lt;P&amp;gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	cs: &amp;amp;ConstraintSystem&amp;lt;B128&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	&#x2F;&#x2F; TODO: This doesn&amp;#39;t actually need mutable access. But must of the WitnessIndex methods only&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	&#x2F;&#x2F; allow mutable access.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	witness: &amp;amp;mut WitnessIndex&amp;lt;P&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	boundaries: &amp;amp;[Boundary&amp;lt;B128&amp;gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	chan: ChannelId,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	indexed_lookup: &amp;amp;impl IndexedLookup&amp;lt;B128&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; Result&amp;lt;Vec&amp;lt;u32&amp;gt;, Error&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;where&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	P: PackedField&amp;lt;Scalar = B128&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		+ PackedExtension&amp;lt;B1&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		+ PackedExtension&amp;lt;B8&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		+ PackedExtension&amp;lt;B16&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		+ PackedExtension&amp;lt;B32&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		+ PackedExtension&amp;lt;B64&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		+ PackedExtension&amp;lt;B128&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	println!(&amp;quot;------- Look up counts for channel: {chan} -------&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	let mut counts = vec![0; 1 &amp;lt;&amp;lt; indexed_lookup.log_size()]; &#x2F;&#x2F; 2^{8+1} &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	&#x2F;&#x2F; Tally counts from the tables&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	for table in &amp;amp;cs.tables {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		&#x2F;&#x2F; In merkle tree example, NodesTable and RootTable&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		if let Some(table_index) = witness.get_table(table.id()) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;			println!(&amp;quot;--- Processing table: {} (ID: {}) ---&amp;quot;, table.name, table.id());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;			for partition in table.partitions.values() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;				for flush in &amp;amp;partition.flushes {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;					if flush.channel_id == chan &amp;amp;&amp;amp; flush.direction == FlushDirection::Pull {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;						&#x2F;&#x2F; In the merkle tree example, this occurs in every NodesTable pull from the&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;						&#x2F;&#x2F; lookup_channel.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;						println!(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;							&amp;quot;Found matching flush: The table has a Pull operation on channel {}&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;							chan&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;						);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;						let table_size = table_index.size();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;						&#x2F;&#x2F; TODO: This should be parallelized, which is pretty tricky.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;						let segment = table_index.full_segment();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;						let cols = flush&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;							.columns&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;							.iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;							.map(|&amp;amp;col_index| segment.get_dyn(col_index))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;							.collect::&amp;lt;Result&amp;lt;Vec&amp;lt;_&amp;gt;, _&amp;gt;&amp;gt;()?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;						if !flush.selectors.is_empty() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;							&#x2F;&#x2F; TODO: check flush selectors&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;							todo!(&amp;quot;tally does not support selected table reads yet&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;						}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;						let mut elems = vec![B128::ZERO; cols.len()];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;						&#x2F;&#x2F; It&amp;#39;s important that this is only the unpacked table size(rows * values&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;						&#x2F;&#x2F; per row in the partition), not the full segment size. The entries&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;						&#x2F;&#x2F; after the table size are not flushed.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;						for i in 0..table_size * partition.values_per_row {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;							for (elem, col) in iter::zip(&amp;amp;mut elems, &amp;amp;cols) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;								*elem = col.get(i);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;							}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;							let index = indexed_lookup.entry_to_index(&amp;amp;elems);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;							println!(&amp;quot;Index {index} corresponds to element: {:?}&amp;quot;, elems);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;							counts[index] += 1;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;						}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;					}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;				}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;			}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This should print at first the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;------- Look up counts for channel: 2 -------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--- Processing table: merkle_tree_nodes_left (ID: 0) ---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Found matching flush: The table has a Pull operation on channel 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Index 258 corresponds to element: [BinaryField128b(0x00000000000000000000000000010302)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Index 257 corresponds to element: [BinaryField128b(0x00000000000000000000000000010201)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This tells us this information: We are looking for pull outs on the channel 2 (the &lt;code&gt;lookup_channel&lt;&#x2F;code&gt;), and we analize first the &lt;code&gt;NodesTable&lt;&#x2F;code&gt; that has the &lt;em&gt;left events&lt;&#x2F;em&gt;. In that table it encountered two pull outs from the channel:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. The first pull out is  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;BinaryField128b(0x00000000000000000000000000010302)&lt;&#x2F;code&gt;. To understand what this binary field element represent follow this steps:
* convert its hex value to a binary expansion:&lt;br &#x2F;&gt;
$$0\text{x}10302 = 00010000001100000010$$
* Take the 8 less significant bits. The resulting number is called &lt;em&gt;input&lt;&#x2F;em&gt; : $00000010$.
* Take the bit at position 16 (from LSB to MSB and starting in 0). The resulting number is called &lt;em&gt;carry in&lt;&#x2F;em&gt; : $1$
* Concatenate them in the following way: &lt;em&gt;carry in&lt;&#x2F;em&gt; || &lt;em&gt;input&lt;&#x2F;em&gt;. This results in&lt;br &#x2F;&gt;
$$100000010.$$
* The result is the binary expansion of our index:&lt;br &#x2F;&gt;
$$100000010 = 258.$$&lt;&#x2F;p&gt;
&lt;p&gt;Now, what is has to do all of this with our Merkle tree? Well, this index $258$ is representing the parent’s and children’s depths in the following event:&lt;br &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;ryf9s5lEgl.png&quot; alt=&quot;image&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Since the parent’s depth is 2, the input will be $00000010$. And since the children depth is the parent’s plus one, the carry is $1$. You can see this better at the initialization of every &lt;code&gt;NodesTable&lt;&#x2F;code&gt; (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;IrreducibleOSS&#x2F;binius&#x2F;blob&#x2F;main&#x2F;crates&#x2F;m3&#x2F;src&#x2F;gadgets&#x2F;merkle_tree&#x2F;mod.rs#L249&quot;&gt;here&lt;&#x2F;a&gt;), in this specific part:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let parent_depth = table.add_committed(&amp;quot;parent_depth&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let one = table.add_constant(&amp;quot;one&amp;quot;, [B1::ONE]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let increment = Incr::new(&amp;amp;mut table, lookup_chan, parent_depth, one);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let child_depth = increment.output;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here the &lt;code&gt;input&lt;&#x2F;code&gt; is &lt;code&gt;parent_depth&lt;&#x2F;code&gt;and the &lt;code&gt;carry_in&lt;&#x2F;code&gt; is &lt;code&gt;one&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. The second pull out is `BinaryField128b(0x00000000000000000000000000010201)`. Let&amp;#39;s do the same thing we did above: &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * Convert to binary: $$0\text{x}10201 = 00010000001000000001$$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * Then, `input = 00000001`. This means that it represent an event with parent&amp;#39;s depth 1.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * `carry_in = 1` because children&amp;#39;s depth is parent&amp;#39;s depth plus 1.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * Concatenate to get the index: $100000001 = 257$.  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This index corresponds to the following event:&lt;br &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;Skm17oe4ll.png&quot; alt=&quot;image&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Now, let’s see what else the function &lt;code&gt;tally()&lt;&#x2F;code&gt; printed. You should also see this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--- Processing table: merkle_tree_nodes_right (ID: 1) ---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Found matching flush: The table has a Pull operation on channel 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Index 257 corresponds to element: [BinaryField128b(0x00000000000000000000000000010201)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Index 258 corresponds to element: [BinaryField128b(0x00000000000000000000000000010302)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note that we have here the same indeces as before. That’s because the right events have the same parent depths as the left ones:&lt;br &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;SkTU7oxNeg.png&quot; alt=&quot;image&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;After that you should see in your terminal the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--- Processing table: merkle_tree_nodes_both (ID: 2) ---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Found matching flush: The table has a Pull operation on channel 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Index 256 corresponds to element: [BinaryField128b(0x00000000000000000000000000010100)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here, note that $$0\text{x}10100 = 00010000000100000000.$$ Then, &lt;code&gt;input = 00000000&lt;&#x2F;code&gt; and that means parent’s depth is 0. The index $256 = 100000000$ is representing this both left and right event:&lt;br &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;rkTmBjxElx.png&quot; alt=&quot;image&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Finally, you should see printed the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--- Processing table: merkle_tree_roots (ID: 3) ---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This means that it processed the roots table but, as expected, it didn’t find any pull out from the lookup channel.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;sorted-counts&quot;&gt;Sorted counts&lt;&#x2F;h4&gt;
&lt;p&gt;Recall that we were trying to understand how the &lt;code&gt;incr_table&lt;&#x2F;code&gt; is populated. After calculating all the &lt;code&gt;lookup_counts&lt;&#x2F;code&gt;, we sort them in a specific way, store it in &lt;code&gt;sorted_counts&lt;&#x2F;code&gt; and use it to fill the table.&lt;&#x2F;p&gt;
&lt;p&gt;The variable &lt;code&gt;sorted_counts&lt;&#x2F;code&gt; is a vector of 512 tuples. The first element of each tuple is an index and the second element has the count that the variable &lt;code&gt;lookup_counts&lt;&#x2F;code&gt;has at that index. These tuples are sorted according to counts from highest to lowest. One more time let’s add this print at the function &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;IrreducibleOSS&#x2F;binius&#x2F;blob&#x2F;main&#x2F;crates&#x2F;m3&#x2F;src&#x2F;gadgets&#x2F;merkle_tree&#x2F;mod.rs#L100&quot;&gt;fill_tables()&lt;&#x2F;a&gt; to understand it better:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let lookup_counts = tally(cs, witness, &amp;amp;[], self.lookup_channel, &amp;amp;IncrIndexedLookup)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Fill the lookup table with the sorted counts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let sorted_counts = lookup_counts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .into_iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .enumerate()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .sorted_by_key(|(_, count)| Reverse(*count))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .collect::&amp;lt;Vec&amp;lt;_&amp;gt;&amp;gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;println!(&amp;quot;------- Increment Table -------&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;println!(&amp;quot;Sorted counts: {sorted_counts:?}&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;witness.fill_table_parallel(&amp;amp;self.incr_table, &amp;amp;sorted_counts)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This should print:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;------- Increment Table -------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Sorted counts: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    (257, 2), (258, 2), (256, 1), (0, 0), (1, 0), (2, 0), ..., (510, 0), (511, 0)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;IncrLookup&lt;&#x2F;code&gt; instance uses these counts to fill its internal &lt;code&gt;entries_ordered&lt;&#x2F;code&gt; and &lt;code&gt;entries_sorted&lt;&#x2F;code&gt; columns, and its &lt;code&gt;LookupProducer&lt;&#x2F;code&gt; records the exact multiplicity for each valid increment operation that occurred in the Merkle tree paths computation.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;This post offers an in-depth exploration of Binius’s M3 arithmetization framework, using a Merkle tree inclusion proof as a concrete example. We examined how tables and channels serve as the foundational abstractions in M3, replacing the traditional concept of a sequential execution trace with a declarative, data-driven model. In this paradigm, computation is decomposed into modular tables, while global consistency is maintained through channel balancing.&lt;&#x2F;p&gt;
&lt;p&gt;At the core of the example lies the &lt;code&gt;MerkleTreeCS&lt;&#x2F;code&gt; gadget, which coordinates five specialized tables and multiple channels to verify Merkle path correctness. The &lt;code&gt;NodesTable&lt;&#x2F;code&gt; handles the hashing of parent-child node relationships, the &lt;code&gt;RootTable&lt;&#x2F;code&gt; ties computed paths to expected root values, and the &lt;code&gt;IncrLookup&lt;&#x2F;code&gt; table validates depth transitions using a permutation-checked lookup structure. These components communicate via channels like &lt;code&gt;nodes_channel&lt;&#x2F;code&gt; and &lt;code&gt;lookup_channel&lt;&#x2F;code&gt;, ensuring that every consumed value was properly produced and accounted for.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Additive FFT: background</title>
          <pubDate>Tue, 17 Jun 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/additive-fft-background/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/additive-fft-background/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/additive-fft-background/">&lt;p&gt;&lt;strong&gt;Warning&lt;&#x2F;strong&gt; : This post is more math heavy than other articles.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;In this article we continue our study of &lt;a href=&quot;&#x2F;the-fields-powering-binius&#x2F;&quot;&gt;towers of binary fields&lt;&#x2F;a&gt;, motivated by the proposal of Diamond and Posen for a complete protocol working over fields of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Characteristic_(algebra)&quot;&gt;characteristic 2&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.binius.xyz&#x2F;&quot;&gt;BINIUS&lt;&#x2F;a&gt;. Previously we covered basic arithmetic of field elements in a tower of binary fields, namely Wiedemann’s iterative quadratic extension of $\mathbb{F_2}$. We address the problem of evaluating and interpolating polynomials with coefficients in such fields, with cryptographic applications in mind. Devising a smart and efficient algorithm for doing polynomial evaluations will open the door for efficient implementation of Reed-Solomon encoding in characteristic 2, which is a crucial building block for polynomial commitments.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;on-the-general-problem-of-polynomial-multiplication&quot;&gt;On the general problem of polynomial multiplication&lt;&#x2F;h2&gt;
&lt;p&gt;Once we covered the structure of the Wiedemann’s binary tower, it is natural to wonder how functions over this tower can be evaluated or multiplied together. To our goals, this is important since polynomial evaluation over a cleverly selected subset of the base field (for example, the $n$-th roots of unity) is the ground for encoding messages using Reed-Solomon techniques; in this light, the problem of polynomial evaluation is &lt;em&gt;very close&lt;&#x2F;em&gt; the problem of Reed-Solomon encoding.&lt;&#x2F;p&gt;
&lt;p&gt;A recollection of an efficient method for multiplication of polynomials comes to mind: the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;tree&#x2F;main&#x2F;crates&#x2F;math&#x2F;src&#x2F;fft&quot;&gt;Fast Fourier Transform&lt;&#x2F;a&gt; algorithm. It employs the celebrated scheme&lt;&#x2F;p&gt;
&lt;p&gt;$$\text{ evaluate }\implies\text{ multiply }\implies \text{ interpolate}$$&lt;&#x2F;p&gt;
&lt;p&gt;In more technical terms for the acquainted reader, “polynomial evaluation” stands for “take the FFT of the polynomial”, multiply means “&lt;strong&gt;pointwise&lt;&#x2F;strong&gt; multiply their FFT’s” and interpolate says “take the inverse FFT of the result”. This general scheme allows us to bypass the computational cost of multiplying two polynomials and applying the distributive law, as in highschool. These “evaluation” and “interpolation” steps usually involve matrix multiplication; whenever we evaluate a polynomial $f$ in the powers if a primitive $n$-th root of unity and $n$ is a power of 2, a recursive algorithm is available and all this can be done quickly, say $\mathcal{O}(n\log(n))$. Obviously this has to be one of the most recorded facts of the history of mathematics; literature abounds.&lt;&#x2F;p&gt;
&lt;p&gt;So what about applying the FFT here? Well, there’s a catch. In the context of finite fields “roots of unity” may not readily exist, or finding a sufficient number of them might require working in much larger and more complex extension fields.&lt;strong&gt;This fundamental limitation renders the standard FFT either impractical or very slow for these specific field types.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-general-framework-for-towers-of-extensions-in-positive-characteristic&quot;&gt;A general framework for towers of extensions in positive characteristic&lt;&#x2F;h2&gt;
&lt;p&gt;To overcome this, we look into the work of David Cantor, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.sciencedirect.com&#x2F;science&#x2F;article&#x2F;pii&#x2F;0097316589900204&quot;&gt;“On Arithmetical Algorithms over Finite Fields”&lt;&#x2F;a&gt; from 1989. There he develops an analogue of the FFT that operates on &lt;strong&gt;additive subgroups&lt;&#x2F;strong&gt; of the base field instead of multiplicative ones; since now we are dealing with additions instead of multiplication of group elements, this scheme is usually coined “Additive FFT”. Cantor finds an analogue of the roots of unity and proceeds to break down the problem into a smaller one that can be solved recursively, just like in the classical FFT case. The good piece good news is that these additive subgroups are no other than than $\mathbb{F_p}$-vector subspaces, closely related to the familiar subfields that appear in Wiedemann’s work and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2023&#x2F;1784&quot;&gt;Diamond and Posen’s proposal&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The crucial object for the construction of the Additive FFT is the notion of &lt;strong&gt;linearized polynomial&lt;&#x2F;strong&gt; ; they are a special class of polynomials that exhibit very interesting properties due to their “linear” nature with respect to addition and scalar multiplication in the base finite field. &lt;strong&gt;A linearized polynomial is such that all its monomials have a degree that is a power of $q$, that is $q^r$&lt;&#x2F;strong&gt; ; this is a polynomial of the form (check the appendix at the end for more)&lt;&#x2F;p&gt;
&lt;p&gt;$$L(x) = \sum_{ i = 0 }^d a_i x^{ q^i }$$&lt;&#x2F;p&gt;
&lt;p&gt;where $a_i \in F_q$ (in this discussion, assume $p$ is a prime number and $q = p^n$ for some natural number $n$) The main property of this polynomials is that since we’re working modulo $p$, &lt;strong&gt;behave just like linear transformations, in the standard linear algebra sense&lt;&#x2F;strong&gt;. This is, they satisfy for any $u, v \in F_{ q^n }$ and $c \in F_q$:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $L(u + v) = L(u) + L(v)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $L(cu) = cL(u)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Whenever we have a linearized polynomial $L$, the set of its roots (zeros) &lt;em&gt;forms a vector space over $\mathbb{F_q}$&lt;&#x2F;em&gt; (called Kernel):&lt;&#x2F;p&gt;
&lt;p&gt;$$Ker(L) = \{v \in \mathbb{F_{ q^n }} : L(v) = 0 \}\subset \mathbb{F_{ q^n }}$$&lt;&#x2F;p&gt;
&lt;p&gt;fact that stems from the general theory of linear algebra; this means that linear combinations of roots are still roots of $L$. Lastly, the very form (along with the linearity just discussed) of linearized polynomials offers a very neat property: composition of linearized polynomials is again linearized. &lt;em&gt;This is the backbone of Cantor’s description of towers of fields in positive characteristic&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;towers-of-extensions-in-prime-characteristic&quot;&gt;Towers of extensions in prime characteristic&lt;&#x2F;h2&gt;
&lt;p&gt;To be concise, we will concentrate on a very simple yet important example that will drive our understanding of Cantor’s Additive FFT effort; for this fix a prime $p$ and if $\tilde{F}$ is the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Algebraic_closure&quot;&gt;algebraic closure&lt;&#x2F;a&gt; (for example, the complex numbers $\mathbb{C}$ are the algebraic closure of the real numbers $\mathbb{R}$) of $\mathbb{F_p}$, take the linearized polynomial&lt;&#x2F;p&gt;
&lt;p&gt;$$S(t) = t^p - t$$&lt;&#x2F;p&gt;
&lt;p&gt;From the basic definitions discussed above, we get tons of objects:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Consider then succesive compositions of $S$ with itself, obtaining the collection of linearized polynomials&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$S_{m} (t) = S\circ S\cdots\circ S (t) = S(S_{ m - 1}(t))$$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * For notational convenience, set $W_1 = Ker(S) = \mathbb{F_p}$ and $W_m = Ker(S_m)$: the collection of roots of $S_m$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * This is where all the clockwork comes to life, since for all $m$ the following are true:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. $W_{ m - 1}\subset W_m$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. $S: W_m \rightarrow W_{ m - 1}$ is a surjective function&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. $W_{ m - 1}$ has [codimension](https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Codimension) 1 in $W_m$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This last subitem plays a very important role in the structure of Cantor’s idea: it means that &lt;strong&gt;if we picture $W_m$ like a chocolate bar, then it can be also thought as the union of exactly $p$ disjoint copies of $W_{ m - 1}$&lt;&#x2F;strong&gt; : draw a rectangle and call it $W_m$ and then split it into $p$ pieces of equal shape and size. Each one of those is a copy of $W_{ m - 1}$!&lt;&#x2F;p&gt;
&lt;p&gt;Once equipped with this (very) brief summary, here’s where the good stuff comes. A key observation is that whenever $m=p^k$, since we work modulo $p$ we have a very neat shape for the linearized polynomials involved:&lt;&#x2F;p&gt;
&lt;p&gt;$$S_{ p^k } (t) = t^{ p^{ p^k } } - t$$&lt;&#x2F;p&gt;
&lt;p&gt;They are said to be &lt;strong&gt;sparse&lt;&#x2F;strong&gt; in the sense that they only have few coefficients; this comes useful when computing the complexity of polynomial division later on. The set of its roots form a field of exactly $p^{ p^k }$ elements, and so recalling the itemized list of properties, what we obtain is then a tower of extensions of $\mathbb{F_p}$:&lt;&#x2F;p&gt;
&lt;p&gt;$$W_0 \subset W_p \subset W_{ p^2 }\subset\ldots W_{ p^k }\subset\ldots $$&lt;&#x2F;p&gt;
&lt;p&gt;in which every step we have degree $p$ field extensions $[W_{ p^k } : W_{ p^{ k - 1} }] = p$. Surjectivity of the map $S:W_{ p^k }\rightarrow W_{ p^{ k-1 }}$ implies that for each $k\geq 1$ and each $u_{ k - 1}\in W_{ p^{k - 1 }}$there always exists an element $u_k\in W_{ p^k } - W_{ p^{ k - 1 }}$ such that&lt;&#x2F;p&gt;
&lt;p&gt;$$S(u_k) = u_{ k - 1}$$&lt;&#x2F;p&gt;
&lt;p&gt;and this will bring a very familiar result.&lt;&#x2F;p&gt;
&lt;p&gt;Setting $p=2$ we recover Wiedemann’s tower of binary fields:&lt;&#x2F;p&gt;
&lt;p&gt;$$W_0 \subset W_2\subset W_{ 2^2 }\subset\ldots W_{ 2^{ 2^k }}\subset\ldots $$&lt;&#x2F;p&gt;
&lt;p&gt;which we recognize by acknowledging the equivalence of notation $$W_{ 2^{ 2^k }} = \mathcal{T_k}$$&lt;&#x2F;p&gt;
&lt;p&gt;Furthermore, the surjectivity of the map $S$ allows to find generators and basis for each of the levels of the tower. Explicitly,&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The first generator of the tower is set to be 1.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The second generator is an element $u_0$ satisfying $$S(u_0) = 1$$ Notice that this is equivalent to $u_0$ being a root of $X^2 + X + 1$. It is easy to check that since this polynomial has no roots in $\mathbb{F_2}$, then $u_0 \notin\mathbb{F_2}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The third generator is then defined as $$S( u_1 ) = u_0$$ This implies $u_1^2 + u_1 = u_0$ or equivalently $u_1^2 + u_1 + u_0 = 0$. Again, this implies that $u_1$ is a root of $X^2 + X + u_0 \in \mathcal{T_1} [X]$. It is easy to check that this polynomial has no roots in $\mathcal{T_1}$ and so $u_1\notin\mathcal{T_1}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * For $k &amp;gt; 1$, the rest of the elements are defined by the recursive relation $$S( u_k ) = u_{ k - 1}$$ and also, a field-theoretic relation $u_k^2 + u_k + u_{ k - 1} = 0$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Building upon these generators, Cantor then defines basis elements $y_m$ according to the base-$2$ (binary) expansion of $m$, mimicking what was naturally exploited in element field multiplication in Wiedemann’s binary tower. Explicitly, if we write down $m$’s binary expansion&lt;&#x2F;p&gt;
&lt;p&gt;$$m = m_k 2^k + m_{ k - 1} 2^{ k - 1} + \cdots + m_0 2^0$$&lt;&#x2F;p&gt;
&lt;p&gt;where $m_i \in \{0 , 1 \}$ are the bits of $m$, then:&lt;&#x2F;p&gt;
&lt;p&gt;$$y_m = u_0^{ m_0 } u_1^{ m_1 } \cdots u_k^{ m_k }.$$&lt;&#x2F;p&gt;
&lt;p&gt;To get out feet wet, as examples we have&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Example Basis Elements:**  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;1. $y_0 = 1$ (for $m = 0$, all $m_i = 0$)&lt;br &#x2F;&gt;
2. $y_1 = u_0$ (for $m = 1$, binary is $1_2$, so $m_0 = 1$)&lt;br &#x2F;&gt;
3. $y_2 = u_1$ (for $m = 2$, binary is $10_2$, so $m_1 = 1$)&lt;br &#x2F;&gt;
4. $y_3 = u_0 u_1$ (for $m = 3$, binary is $11_2$, so $m_0 = 1, m_1 = 1$)&lt;br &#x2F;&gt;
5. $y_4 = u_2$ (for $m = 4$, binary is $100_2$, so $m_2 = 1$)&lt;br &#x2F;&gt;
6. Generally, $y_{ 2^r } = u_r$ for $r = 0, 1, 2, \ldots$&lt;&#x2F;p&gt;
&lt;p&gt;This explicit basis for $\mathcal{T_k}$ directly corresponds to what Diamond and Posen refer to as the “multilinear basis” for the Wiedemann tower $\mathcal{T_\iota}$. They state that for $\mathcal{T_\iota}$, the set of monomials $${1, X_0, X_1, X_0 \cdot X_1, \ldots, X_0 \cdot \ldots X_{\iota - 1}}$$ forms a basis, with their $X_i$ effectively serving as Cantor’s $u_i$. It is important to note that the Wiedemann tower generators in Diamond’s paper use a slightly different relation: $$X_{ j + 1}^2 + X_{ j + 1 }X_j + 1 = 0$$&lt;&#x2F;p&gt;
&lt;p&gt;Despite these differences in specific generator relations, the underlying algebraic structure of these iterated quadratic extensions aligns with Cantor’s general framework for efficient basis representations and arithmetic.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-the-additive-fft-works-a-recursive-divide-and-conquer-strategy-for-polynomial-evaluation&quot;&gt;How the Additive FFT Works: A Recursive “Divide and Conquer” Strategy for Polynomial Evaluation&lt;&#x2F;h2&gt;
&lt;p&gt;The core mechanism of Cantor’s Additive FFT is a recursive “divide and conquer” process, mirroring the efficiency principles of a conventional FFT algorithm. Here we will first give a high-level overview for the problem of evaluating a degree $n = p^m$ polynomial $a$ with coefficients in $F_p$. In the following, we’ll keep the notations used in the preceding sections.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Setting up the evaluation set: the subspaces ($W_m$):**  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;1. The primary objective is to evaluate the polynomial $a(t)$ of degree at most $n = p^m$ at all the $p^m$ elements of $W_m$; in this sense, the subspace $W_m$ plays the role of the $n$-th roots of unity form the classical FFT algorithm.&lt;br &#x2F;&gt;
2. Crucially, $W_m$ can be partitioned into $p$ smaller, disjoint “cosets” of $W_{ m - 1}$ This allows for a hierarchical decomposition of the problem just like the case in the classical setting when $n$ is a power of 2. Being more specific, we know that $S$ is a $\mathbb{F_p}$-linear map that surjects $W_m$ onto $W_{ m - 1}$, and that this image has codimension 1. This ensures that there exists an element $u\in W_m$ such that&lt;br &#x2F;&gt;
$$W_m = \langle u\rangle \oplus W_{ m - 1}$$&lt;&#x2F;p&gt;
&lt;p&gt;since $\mathbb{F_p}$ has exactly $p$ elements then&lt;br &#x2F;&gt;
$$W_m = \bigcup\limits_{ \alpha\in\mathbb{F_p } } \left(\alpha\cdot u + W_{ m - 1}\right)$$&lt;&#x2F;p&gt;
&lt;p&gt;where this union is disjoint and each subset is simply a translate of $W_{m - 1}$. For simplicity, we’ll adopt the following notation:&lt;br &#x2F;&gt;
$$\alpha\cdot u + W_{ m - 1} = W_{ m - 1}^\alpha$$&lt;br &#x2F;&gt;
and observe that this set has exactly $p^{ m - 1}$ elements, since $W_{ m - 1}$ is the set of roots of $S_{ m - 1} (t)$, which has degree $p^{ m - 1}$.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **The Recursive Step: Breaking Down the Problem:**&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      1. Now in order to evaluate $a(t)$ on $W_m$ it would suffice to know the values of $a(t)$ at each of the cosets $W_{ m - 1 }^\alpha$. Since these cosets have $p^{ m - 1}$ elements, it would be awesome if we could reduce this problem to the problem of evaluating a polynomial $b_\alpha$ of _strictly smaller degree_ than $deg(a)$ on $W_{ m - 1}^\alpha$; ideally $deg(b_\alpha ) &amp;lt; p^{ m - 1}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      2. In order to get hold of one such $b_\alpha$ the following observations come in handy:  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;a. $W_{ m - 1}$ is the set of roots of the $p^{ m - 1}$ degree polynomial $S_{ m - 1} (t)$&lt;br &#x2F;&gt;
b. a translate of this polynomial will vanish on $W_{ m - 1}^\alpha$:&lt;br &#x2F;&gt;
$$S_{ m - 1 }^\alpha (t) = S_{ m - 1}( t - \alpha\cdot u)$$&lt;br &#x2F;&gt;
don’t trust us, check it yourself.&lt;br &#x2F;&gt;
c. the Fundamental Theorem of Algebra states then that the remainder of the quotient of $a$ by $S_{ m - 1}^\alpha$ is a polynomial of degree strictly less than $p^m$ and that&lt;br &#x2F;&gt;
$$a(t) = Q(t) s_{ m - 1}^\alpha (t) +b_\alpha (t)$$&lt;br &#x2F;&gt;
holds. In particular, whenever $w\in W_{ m - 1 }^\alpha$,&lt;&#x2F;p&gt;
&lt;p&gt;$$a(w) = Q(w)\cdot 0 + b_\alpha (w)$$&lt;&#x2F;p&gt;
&lt;p&gt;and this means $a\equiv b_\alpha$ on $W_{m-1}^\alpha$.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      3. The algorithm then **recursively calls itself** to evaluate each $b_\alpha (t)$ on its corresponding smaller subspace $W_{ m - 1 }^\alpha$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **The Base Case:**  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;1. This recursive decomposition continues until the polynomials $b_i (t)$ reach a degree of 0, meaning they become constants.&lt;br &#x2F;&gt;
2. These resulting constants are the desired functional values of the original polynomial $a(t)$ at the points in $W_m$&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-reverse-process-interpolation&quot;&gt;The Reverse Process: Interpolation&lt;&#x2F;h3&gt;
&lt;p&gt;Cantor also outlines the inverse operation, known as &lt;strong&gt;interpolation&lt;&#x2F;strong&gt;. If the values of a polynomial are known for all points within $W_m$, one can reverse the steps of the Additive FFT algorithm to reconstruct the coefficients of the original polynomial. This inverse process involves similar division and summation techniques, executed in reverse order.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;computational-cost-and-efficiency&quot;&gt;Computational Cost and Efficiency&lt;&#x2F;h3&gt;
&lt;p&gt;Cantor rigorously analyzes the computational complexity of his algorithm, categorizing operations into two types:&lt;br &#x2F;&gt;
- &lt;strong&gt;A-operations (Addition-like):&lt;&#x2F;strong&gt; These operations have a computational cost comparable to additions within the underlying field $F$.&lt;br &#x2F;&gt;
- &lt;strong&gt;M-operations (Multiplication-like):&lt;&#x2F;strong&gt; These operations have a computational cost comparable to multiplications within the underlying field $F$.&lt;&#x2F;p&gt;
&lt;p&gt;For evaluating a polynomial of degree $&amp;lt;n = p^m$ at all points of $W_m$:&lt;br &#x2F;&gt;
1. The total number of A-operations is approximately $O(n (\log n)^{ 1 + \log_p ((p + 1) &#x2F;2) })$. For $p = 2$, this simplifies to roughly $O(n (\log n)^{ 1.585 })$.&lt;br &#x2F;&gt;
2. The total number of M-operations is approximately $O(n \log n)$.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;In summary, vector subspaces are the “domains” over which the Additive FFT operates. The algorithm recursively divides them and uses the linear properties of linearized polynomials (and the Frobenius automorphism) to relate evaluations across different subspaces, allowing for efficient multipoint evaluation and interpolation.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;appendix-proofs-and-ideas&quot;&gt;Appendix - Proofs and ideas&lt;&#x2F;h2&gt;
&lt;p&gt;Here we sum up most of the proofs, definitions and technicalities around linearized polynomials that are mentioned throughout the text. We begin by the first definitions and deduce some of the properties employed.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Definition (Linearized polynomial)&lt;&#x2F;strong&gt; A linearized polynomial over a finite field $F_q$ has the general form:&lt;br &#x2F;&gt;
$$L(x) = \sum_{ i = 0 }^d a_i x^{ q^i }$$&lt;br &#x2F;&gt;
where $a_i \in F_q$&lt;&#x2F;p&gt;
&lt;p&gt;Here we collect some of their the main properties as an itemized list; most of these are easily provable facts and could serve as encouraging exercises (and also a reminder of how important basic linear algebra really is):&lt;br &#x2F;&gt;
- &lt;strong&gt;They are Linear Transformations:&lt;&#x2F;strong&gt; If $L(x)$ is a linearized polynomial with coefficients in $F_q$, the mapping $x \mapsto L(x)$ is a &lt;strong&gt;linear transformation&lt;&#x2F;strong&gt; from $F_{ q^n }$ to itself, considering this extension as $n-$ dimensional vector space over $F_q$. This means that for any $u, v \in F_{ q^n }$ and $c \in F_q$:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $L(u + v) = L(u) + L(v)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $L(cu) = cL(u)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;(This property stems from characterization of the field of $q$ elements as the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Splitting_field&quot;&gt;splitting field&lt;&#x2F;a&gt; of the polynomial $X^{q} - X$.) Since $L$ is a linear map, then the set of its roots &lt;strong&gt;forms a vector space over $\mathbb{F_q}$&lt;&#x2F;strong&gt; :&lt;&#x2F;p&gt;
&lt;p&gt;$$Ker(L) = \{v\in\mathbb{F_{ q^n }} : L(v) = 0 \} \subset \mathbb{F_{ q^n }}$$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **The uncanny effects of composition:** Usually, composition of polynomials produces a new polynomial and not much else can be said in the general setting. But since linearized polynomials can be seen as linear maps, there are some astonishing consequences:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      1. Right from their definition, linearized polynomials can be viewed as ordinary polynomials pre-composed with $x^q$. This is, there&amp;#39;s a correspondence between linearized polynomials over $F_q$ and &amp;quot;ordinary&amp;quot; polynomials in $F_q [x]$. To a linearized polynomial $L(x) = \sum_{ i = 0 }^d a_i x^{ q^i }$, we associate a &amp;quot;$q$-conventional&amp;quot; polynomial $l(y) = \sum_{ i = 0}^d a_i y^i$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      2. Also from their definition and the linearity property, we see that the composition of two linearized polynomials is also a linearized polynomial. This binary operation is non-commutative but is distributive respect to polynomial addition.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      3. If we interpret composition as a non-commutative multiplication, then an analogue of a division concept can be devised: we will say that $L$ symbolically divides $M$ if there exists a linearized polynomial $R$ such that  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$M(X) = L\circ N(X)$$
4. Not only this, but there’s also a very remarkable link between linearized polynomials, symbolic divisibility and their $q$-Conventionals: $L(x)$ symbolically divides $M(x)$ if and only if $\ell(y)$ divides $m(y)$ in the ordinary sense.
5. A linearized polynomial $L(x)$ is compositionally irreducible if and only if its associated $q$-conventional polynomial $l(y)$ is irreducible over $F_q$. It’s important to note that a compositinally irreducible linearized polynomial is &lt;em&gt;always&lt;&#x2F;em&gt; reducible in the ordinary sense (it has the factor $x$).
* &lt;strong&gt;Regarding the construction of towers of extensions,&lt;&#x2F;strong&gt; succesive compositions of the linearized polynomial $S(t) = t^p - t$ with itself&lt;&#x2F;p&gt;
&lt;p&gt;$$S_{m} (t) = S\circ S\cdots\circ S (t) = S(S_{ m - 1} (t))$$&lt;&#x2F;p&gt;
&lt;p&gt;yield subsets in which the algorithm is defined on. From the general theory of linear maps we know that if whenever the composition $F\circ G$ of linear maps $F,G$ is possible, then&lt;&#x2F;p&gt;
&lt;p&gt;$$Ker(G)\subset Ker(F\circ G);$$&lt;&#x2F;p&gt;
&lt;p&gt;in our context this gives an incidence relation between the corresponding kernels: $$Ker(S_{ m - 1 })\subset Ker(S\circ S_{ m - 1 }) = Ker(S_m)$$&lt;&#x2F;p&gt;
&lt;p&gt;This is, $W_{ m - 1} \subset W_m$. From this relation we also see that $S(W_m )\subset W_{ m - 1 }$ since&lt;&#x2F;p&gt;
&lt;p&gt;$$S_{ m - 1 }(S(W_m ))=S_m (W_m ) = 0$$&lt;&#x2F;p&gt;
&lt;p&gt;So we can consider the restriction of $S$ to $W_m$ and look at it as an &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Endomorphism&quot;&gt;endomorphism&lt;&#x2F;a&gt; $S : W_m\rightarrow W_m$. The incidence relation and the dimension theorem for linear maps yields&lt;&#x2F;p&gt;
&lt;p&gt;$$\dim(W_{ m - 1 }) \leq \dim(W_m ) = \dim(Ker(S)) + \dim(S( W_m )) \leq 1 + \dim(W_{ m - 1})$$&lt;&#x2F;p&gt;
&lt;p&gt;Since $S_{ m - 1}$ and $S_m$ have different degrees, they can’t have the same roots in $\tilde{F}$, so their kernels as linear maps are different. This implies&lt;&#x2F;p&gt;
&lt;p&gt;$$W_{ m - 1}\neq W_m \implies \dim(W_m) = 1 + \dim(W_{ m - 1})$$&lt;&#x2F;p&gt;
&lt;p&gt;and since $\dim(W_1) = 1$ we have as conclusions that $\dim(W_m ) = m$ and that $S$ surjects $W_m$ onto $W_{ m - 1}$.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;cantor-s-basis-theorem&quot;&gt;Cantor’s basis theorem&lt;&#x2F;h3&gt;
&lt;p&gt;One of the pillars of Cantor’s contributions is what in his paper is coined as “Theorem 1.1”, in which he proves that a certain set is a basis over $\mathbb{F}_p$ of its algebraic closure. In order to state the theorem, we need to make the following observations. Fix your favourite prime $p$ and consider the collection of $u_j \in\tilde{F}$ defined by $S$ in the following fashion:&lt;&#x2F;p&gt;
&lt;p&gt;$$S(u_j ) = u_{ j - 1 },\quad u_j \in W_{ j +1 } - W_j$$&lt;br &#x2F;&gt;
Then&lt;br &#x2F;&gt;
a. each positive integer $m$ has an expansion in base $p$: this is, there exist a non-negative integer $k$ and integers $0\leq m_i \leq p - 1$ with $0\leq i\leq k$ such that&lt;br &#x2F;&gt;
$$m = \sum\limits_{ i = 0}^k m_i p^i \quad\text{with }\quad m_k\neq 0$$&lt;&#x2F;p&gt;
&lt;p&gt;To symbolize this, we write $E(m) = [m_0 m_1 \cdots m_k ]$ and we may think of this vector of exponents as the image of $m$ through an “expansion map”&lt;br &#x2F;&gt;
b. Let $\gamma_m$ be the first non zero entry in $[m]^p$.&lt;br &#x2F;&gt;
c. Set $y_0 = 1$ and for positive $m$, define&lt;br &#x2F;&gt;
$$y_m = \textbf{u}^{ E(m) } = u_0^{ m_0 }\cdot u_1^{ m_1 }\cdot u_k^{ m_k }$$&lt;br &#x2F;&gt;
and observe that in particular&lt;br &#x2F;&gt;
$$y_{ p^r } = u_r$$&lt;&#x2F;p&gt;
&lt;p&gt;It turns out that the collection $\{y_0, y_1, \ldots \}$ has &lt;em&gt;very nice&lt;&#x2F;em&gt; properties, that come summarized in the following theorem&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Theorem(Cantor’s 1.11 Theorem):&lt;&#x2F;strong&gt; In the same context as the conversation above&lt;br &#x2F;&gt;
1. $\{y_0 , y_1 ,\ldots y_m \}$ is a basis for $W_{ m + 1}$ and $y_m \in W_{ m + 1} - W_m$.&lt;br &#x2F;&gt;
2. When $m\geq 1$, then&lt;br &#x2F;&gt;
$$S(y_m ) - \gamma_m y_{ m - 1} \in W_{ m - 1}$$&lt;br &#x2F;&gt;
3. the full collection $\{y_0 , y_1 , \ldots \}$ is a basis for $\tilde{F}$.&lt;&#x2F;p&gt;
&lt;p&gt;This specific basis is important for theoretical purposes, but it also may be convenient to consider basis for $W_m$ with nice properties respect to $S$; we have already encountered one such, the one defined by the $u$’s. Set&lt;&#x2F;p&gt;
&lt;p&gt;$$\mathcal{U_m} = \{u_0 ,u_1 ,\ldots, u_{ m - 1} \}$$&lt;&#x2F;p&gt;
&lt;p&gt;as a basis for $W_m$. Now for each $x\in W_m$ there exist unique $\alpha_i \in\mathbb{F_p}$ such that&lt;&#x2F;p&gt;
&lt;p&gt;$$x = \sum\limits_{ i = 0 }^{ m - 1 } \alpha_i u_i$$&lt;&#x2F;p&gt;
&lt;p&gt;By considering $0\leq \alpha_i \leq p - 1$ then we obtain a “replacement map” that is able to interpret $x$ as an integer, by&lt;&#x2F;p&gt;
&lt;p&gt;$$x\in W_m \longmapsto R(x) = \sum\limits_{ i = 0}^{ m - 1} \alpha_i p^i\in [0, p^m - 1]$$&lt;&#x2F;p&gt;
&lt;p&gt;An enduring reader will notice that this map is the inverse of the “expansion map” that appeared earlier. One good property of this particular choice of basis is that&lt;&#x2F;p&gt;
&lt;p&gt;$$\alpha = R(x)\implies \lfloor \alpha &#x2F;p \rfloor = R(S(x))$$&lt;&#x2F;p&gt;
&lt;p&gt;This fact will become handy when the time to describe the FFT algorithm comes.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>The fields powering Binius</title>
          <pubDate>Thu, 12 Jun 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/the-fields-powering-binius/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/the-fields-powering-binius/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/the-fields-powering-binius/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;The development of general-purpose zkVMs has made writing verifiable applications easier, by allowing developers to write high-level code and then compiling it to RISC-V or another instruction set architecture (ISA) and running it on top of the virtual machine. The virtual machine then generates a succinct proof of execution using a proof system, such as STARKs or Groth16. Recent advances in proof systems have allowed to reduce proving times, and we are heading towards real-time proving of Ethereum blocks. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.binius.xyz&#x2F;&quot;&gt;Binius&lt;&#x2F;a&gt; is a proof system that was developed focusing on how to create a technology that is hardware-friendly. Knowing how hardware works, a tailored proof system with really fast mathematics on it can yield significant improvements. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;PetraProver&#x2F;PetraVM&quot;&gt;Petra&lt;&#x2F;a&gt; is the first virtual machine to leverage Binius. What makes Binius special and how does it work?&lt;&#x2F;p&gt;
&lt;p&gt;In this article we will review the basic mathematics behind the Binius protocol, which exploits the boolean hypercube $\mathcal{B_\ell} = \{0 , 1 \}^\ell$. We’ll concentrate in an elementary description of binary towers and the representation of field elements, as well as addition and multiplication of field elements exploiting their natural relation with circuit level operations. Throughout this article, we will cover some of the ground material from which binary towers emerge and came to life as a technologically interesting object, namely:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Diamond and Posen&amp;#39;s work from 2023, [&amp;quot;Succint Arguments over Towers of Binary Fields&amp;quot;](https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2023&#x2F;1784)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * David Cantor&amp;#39;s seminal 1989 paper [&amp;quot;On Arithmetical Algorithms over Finite Fields&amp;quot;](https:&#x2F;&#x2F;www.sciencedirect.com&#x2F;science&#x2F;article&#x2F;pii&#x2F;0097316589900204)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Wiedemann&amp;#39;s 1987 article [&amp;quot;An Iterated Quadratic Extension of GF(2)&amp;quot;](https:&#x2F;&#x2F;www.fq.math.ca&#x2F;Scanned&#x2F;26-4&#x2F;wiedemann.pdf)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For more background material, see our &lt;a href=&quot;&#x2F;snarks-on-binary-fields-binius&#x2F;&quot;&gt;previous post on Binius part 1&lt;&#x2F;a&gt; and &lt;a href=&quot;&#x2F;binius-part-2&#x2F;&quot;&gt;Binius part 2&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;field-extensions-and-representation-of-field-elements&quot;&gt;Field extensions and representation of field elements&lt;&#x2F;h2&gt;
&lt;p&gt;In the following discussion, we will fix $\mathbb{F_2} = {0,1}$ as the field with two elements. Finite field extensions of degree $d$ of this field can be characterized as the quotient ring&lt;&#x2F;p&gt;
&lt;p&gt;$$\mathbb{F}_{q} \equiv \mathbb{F}[X]&#x2F;\langle f(X)\rangle$$&lt;&#x2F;p&gt;
&lt;p&gt;where $f$ is any irreducible polynomial $f \in \mathbb{F_2} [X]$ of degree $d$: this field has exactly $q = 2^d$ elements and consists of all the remainders of polynomial division by $f$. In other words, it consists of polynomials of degree at most $d - 1$ with coefficients in $\mathbb{F_2}$. Also, this extension can be viewed as a vector space of dimension $d$ over the base field $\mathbb{F_2}$ which is a very nice feature. The collection&lt;&#x2F;p&gt;
&lt;p&gt;$$B_q = \{1 , X , X^2 ,\ldots, X^{d - 1} \}$$&lt;&#x2F;p&gt;
&lt;p&gt;commonly called “the monomial basis” and upon fixing this basis, an isomorphism identifying such a polynomial with its $\mathbb{F_2}$ coordinates is established. Addition and multiplication of field elements when viewed as polynomials, are performed modulo $f$.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;example&quot;&gt;Example&lt;&#x2F;h3&gt;
&lt;p&gt;Consider the polynomial $$f(X) = X^2 + X + 1$$ as an element in $\mathbb{F_2} [X]$. The $f$ is irreducible; if it had a non-trivial factor $g$ then $\deg(g) = 1$ and since $g \in \mathbb{F_2} [X]$ that would force that a root of $g$ be a root of $f$. Since $f$ has no roots in the base field, then we conclude that $f$ is irreducible and&lt;&#x2F;p&gt;
&lt;p&gt;$$\mathbb{F}[X]&#x2F;\langle X^2+X+1\rangle $$&lt;&#x2F;p&gt;
&lt;p&gt;is indeed a degree 2 extension of $\mathbb{F_2}$; this means that it can be considered as a dimension 2 vector space over the base field. The canonical basis for this vector space is then&lt;&#x2F;p&gt;
&lt;p&gt;$$B_2 = \{1 , X \}$$&lt;&#x2F;p&gt;
&lt;p&gt;and all its elements can be listed as linear combinations of elements of $B_2$:&lt;&#x2F;p&gt;
&lt;p&gt;$$\mathbb{F_4} = \{0 , 1 , X , 1 + X \}$$&lt;&#x2F;p&gt;
&lt;p&gt;The coordinate Representation of $\mathbb{F_4}$ over $\mathbb{F_2}$ can be viewed in the following table&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Polynomial Representation&lt;&#x2F;th&gt;&lt;th&gt;Coordinate Representation&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;$0$&lt;&#x2F;td&gt;&lt;td&gt;$(0, 0)$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$1$&lt;&#x2F;td&gt;&lt;td&gt;$(1, 0)$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$X$&lt;&#x2F;td&gt;&lt;td&gt;$(0, 1)$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$1 + X$&lt;&#x2F;td&gt;&lt;td&gt;$(1, 1)$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;The field operations in the extensions are ring operations in $\mathbb{F_2} [X]$ taken to the quotient field by considering the non-trivial relation $X^2 + X + 1 = 0 \iff X^2 = 1 + X$. &lt;strong&gt;This is sometimes interpreted in a straightforward manner: now $X$ becomes a root of $f$ in the field extension $\mathbb{F_4}$&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;We observe that the irreducibility of $f$ in the last example was simple since the degree of $f$ was low enough: if $\deg(f)\leq 3$ then $f$ is irreducible over $\mathbb{F}[X] \iff \quad f$ has no roots in $\mathbb{F}$ (this is a theorem in the theory of fields).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Definition (Quadratic extensions):&lt;&#x2F;strong&gt; Field extensions defined by quotienting by irreducible polynomials of degree 2 are called &lt;em&gt;quadratic&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Definition (Towers of fields):&lt;&#x2F;strong&gt; Whenever there are fields $K,E,F$ such that&lt;&#x2F;p&gt;
&lt;p&gt;$$K,\subset, E\quad\text{ and }\quad E,\subset, F$$&lt;&#x2F;p&gt;
&lt;p&gt;we say that &lt;em&gt;$E$ is an extension of $K$&lt;&#x2F;em&gt; (usually noted $E,\rvert K$) and that &lt;em&gt;$F$ is an extension of $E$&lt;&#x2F;em&gt;. Putting these extensions together result in a &lt;em&gt;tower of extensions&lt;&#x2F;em&gt; , and we denote it by $F\rvert\quad E\quad \rvert\quad K$.&lt;&#x2F;p&gt;
&lt;p&gt;It turns out that concatenating field extensions at first sight might seem alien and overly complicated but ultimately, will yield great results.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;extended-example-two-constructions-of-mathbb-f-16&quot;&gt;Extended example: two constructions of $\mathbb{F_{16}}$&lt;&#x2F;h3&gt;
&lt;p&gt;Let’s work two different realizations of the field of 16 elements and see how fields are constructed.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;First construction:&lt;&#x2F;strong&gt; $\mathbb{F_{16}}$ as quotient by a degree 4 polynomial:&lt;&#x2F;p&gt;
&lt;p&gt;To construct the field $\mathbb{F_{16}}$ we need to find an irreducible polynomial of degree 4 over the field of two elements, $\mathbb{F_2} = \{0, 1 \}$. One such irreducible polynomial is:&lt;br &#x2F;&gt;
$$p(X) = X^4 + X + 1$$&lt;&#x2F;p&gt;
&lt;p&gt;To verify that this polynomial is irreducible over $\mathbb{F_2}$, we need to check that it has no roots in $\mathbb{F_2}$ &lt;strong&gt;and&lt;&#x2F;strong&gt; that it cannot be factored into the product of two irreducible polynomials of degree 2 over $\mathbb{F_2}$.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. **No roots in $\mathbb{F_2}$:**  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;- $p(0) = 0^4 + 0 + 1 = 1 \neq 0$&lt;br &#x2F;&gt;
- $p(1) = 1^4 + 1 + 1 = 1 + 1 + 1 = 1 \pmod{2} \neq 0$&lt;br &#x2F;&gt;
Since $p(X)$ has no roots in $\mathbb{F_2}$, it has no linear factors $(X - a)$ where $a \in \mathbb{F_2}$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. **No factorization into two irreducible polynomials of degree 2:**  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The only irreducible polynomial of degree 2 over $\mathbb{F_2}$ is $X^2 + X + 1$. If $X^4 + X + 1$ were reducible into two degree 2 polynomials, it would have to be $(X^2 + X + 1)(X^2 + aX + b)$, where $a, b \in \mathbb{F_2}$.&lt;br &#x2F;&gt;
Expanding this product:&lt;br &#x2F;&gt;
$$(X^2 + X + 1) (X^2 + aX + b) = X^4 + (a + 1)X^3 + (b + a + 1)X^2 + (b + a) X + b$$&lt;br &#x2F;&gt;
Comparing the coefficients with $X^4 + 0X^3 + 0X^2 + 1X + 1$:&lt;br &#x2F;&gt;
- Coefficient of $X^3$: $a + 1 = 0 \implies a = 1$&lt;br &#x2F;&gt;
- Coefficient of $X^2$: $b + a + 1 = 0 \implies b + 1 + 1 = b = 0$&lt;br &#x2F;&gt;
- Coefficient of $X$: $b + a = 1 \implies 0 + 1 = 1$ (This is consistent)&lt;br &#x2F;&gt;
- Constant term: $b = 1$&lt;br &#x2F;&gt;
We have a contradiction since we found $b = 0$ and $b = 1$. Therefore, $X^4 + X + 1$ cannot be factored into two irreducible polynomials of degree 2 over $\mathbb{F_2}$.&lt;&#x2F;p&gt;
&lt;p&gt;Since $p(X) = X^4 + X + 1$ is irreducible of degree 4 over $\mathbb{F_2}$, the quotient ring&lt;br &#x2F;&gt;
$$\mathbb{F_2} [X] &#x2F; \langle X^4 + X + 1 \rangle$$&lt;br &#x2F;&gt;
is a field with $2^4 = 16$ elements.&lt;&#x2F;p&gt;
&lt;p&gt;Elements of this field can be represented as polynomials in $X$ of degree at most 3 with coefficients in $\mathbb{F_2}$; moreover, addition of these elements is done by adding the polynomials coefficient-wise modulo 2 while multiplication is done by multiplying the polynomials &lt;strong&gt;and then&lt;&#x2F;strong&gt; reducing the result modulo $X^4 + X + 1$. This reduction is achieved by repeatedly using the relation $X^4 \equiv -X - 1 \equiv X + 1 \pmod{X^4 + X + 1}$.&lt;&#x2F;p&gt;
&lt;p&gt;For instance, to multiply $\alpha = 1 + X + X^3$ and $\beta = X^2 + X^3$,&lt;&#x2F;p&gt;
&lt;p&gt;$$\alpha\cdot\beta = ( 1 + X + X^3 )\cdot (X^2 + X^3) = X^2 + X^3 + X^3 + X^4 + X^5 + X^6$$&lt;&#x2F;p&gt;
&lt;p&gt;By making use of addition modulo 2 we may eliminate the third powers of $X$ and by the defining relation we may replace all powers of $X$ above 4:&lt;&#x2F;p&gt;
&lt;p&gt;$$\alpha\cdot\beta = X^2 + ( 1 + X ) + X (1 + X) + X^2 ( 1 + X ) = X^2 + 1 + X + X + X^2 + X^2 + X^3$$&lt;&#x2F;p&gt;
&lt;p&gt;and again by addition modulo 2, we obtain $\alpha \cdot \beta = 1 + X^2 + X^3$.&lt;&#x2F;p&gt;
&lt;p&gt;We will see that even if it is straightforward to understand the mechanics of this pattern for multiplication, it is highly non-efficient. We would like to have a different way of representing elements in a field extension such that multiplication could be done fast and efficiently.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Second construction&lt;&#x2F;strong&gt; : $\mathbb{F_{16}}$ as a sequence of quadratic extensions&lt;&#x2F;p&gt;
&lt;p&gt;In this approach, we will construct the field of 16 elements by realizing a tower of fields which has $\mathbb{F_{16}}$ at the top; we will exploit quadratic extensions and the fact that when polynomials are of low degree (at most 3) their irreducibility can be deduced by looking for roots.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: $\mathbb{F_4}$ as an extension of $\mathbb{F_2}$:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;As before, we use the irreducible polynomial $p(t) = t^2 + t + 1$ over $\mathbb{F_2}$. Since extending $\mathbb{F_2}$ is adjoining a root $X_0$ of $f$, we will simply say that&lt;&#x2F;p&gt;
&lt;p&gt;$$\mathbb{F_4} = \mathbb{F_2} (X_0 )$$&lt;&#x2F;p&gt;
&lt;p&gt;and the four elements of this field are simply ${ 0, 1, X_0, 1 + X_0 }$, with $X_0^2 = X_0 + 1$.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Step 2: $\mathbb{F_{ 16 }}$ as an extension of $\mathbb{F_4}$:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Since $\mathbb{F_4}$ has 4 elements, we need an irreducible polynomial of degree $2$ over $\mathbb{F_4}$ to construct $\mathbb{F_{16}}$ and grant $[\mathbb{F_{16}} : \mathbb{F_4} ] = 2$ (see here for &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Degree_of_a_field_extension&quot;&gt;degree of an extension&lt;&#x2F;a&gt;); consider the polynomial $$q(t) = t^2 + t + X_0$$ over $\mathbb{F_4}$. To check for irreducibility, we need to see if it has roots in $\mathbb{F_4} = {0, 1, X_0, 1 + X_0}$. So, let’s begin checking one by one:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $q(0) = 0^2 + 0 + X_0 = X_0 \neq 0$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $q(1) = 1^2 + 1 + X_0 = 1 + 1 + X_0 = 0 + X_0 = X_0 \neq 0$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $q(X_0) = X_0^2 + X_0 + X_0 = (X_0 + 1) + X_0 + X_0 = X_0 + 1 + 0 = X_0 + 1 \neq 0$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $$\begin{align*} q(1 + X_0) &amp;amp;= (1 + X_0)^2 + (1 + X_0) + X_0 = (1 + X_0^2) + 1 + X_0 + X_0 \\\\ &amp;amp;= 1 + (X_0 + 1) + 1 + 0 = X_0 + 1 + 1 = X_0 \neq 0 \end{align*}$$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Since $q(t)$ has degree 2 and no roots in $\mathbb{F_4}$, it is irreducible over $\mathbb{F_4}$ and the extension obtained by adjoining a root $X_1$ of $q$ yields&lt;&#x2F;p&gt;
&lt;p&gt;$$\mathbb{F_{16}} = \mathbb{F_4} (Y) = \mathbb{F_2} (X_0 ) (X_1 ) = \mathbb{F_2} (X_0 , X_1 )$$&lt;&#x2F;p&gt;
&lt;p&gt;subject to the relations:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $X_0^2 = X_0 + 1$ (this comes from the first extension)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $X_1^2 = X_1 + X_0$ (this comes from the second extension)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Each step is indeed defined by quotienting by an irreducible polynomial of degree 2, i.e. each step is a &lt;em&gt;quadratic extension&lt;&#x2F;em&gt;. More importantly, each element in $\mathbb{F_{16}}$ is a linear combination with coefficients in $\mathbb{F_2}$ of the basis elements&lt;&#x2F;p&gt;
&lt;p&gt;$$\{ 1 , X_0 ,X_1 ,X_0 \cdot X_1 \}$$&lt;&#x2F;p&gt;
&lt;h3 id=&quot;a-word-about-coordinates&quot;&gt;A word about coordinates:&lt;&#x2F;h3&gt;
&lt;p&gt;Let’s work out the coordinate representation of $\mathbb{F_{ 16 }}$ over $\mathbb{F_4}$ and over the base field $\mathbb{F_2}$. The elements of $\mathbb{F_{ 16 }}$ can be written in the form $$a + bX_1$$ where $a, b \in \mathbb{F_4}$. Since each of $a$ and $b$ has 4 choices, there are $4 \times 4 = 16$ elements in $\mathbb{F_{16}}$; also recall that a basis for $\mathbb{F_4}$ over $\mathbb{F_2}$ is $\{1, X_0 \}$ and that $\mathbb{F_{16}}$ over $\mathbb{F_4}$ is $\{1, X_1\}$.&lt;&#x2F;p&gt;
&lt;p&gt;It is a well known theorem of the theory of fields a basis for the upper field in a tower consists of the multiplication of the basis elements in the lower extensions. But there’s a caveat: we will consider ordered basis. This means that in order to show a basis one must not only exhibit a linearly independent subset that spans the vector space, but also we need to make explicit &lt;em&gt;the order&lt;&#x2F;em&gt; in which those elements lie in the basis. This order is needed in order to make available the use of coordinates. Considering the ordered basis above, let’s take a look at the elements in $\mathbb{F_{16}}$:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Element in $\mathbb{F_{16}}$&lt;&#x2F;th&gt;&lt;th&gt;Coordinates over $\mathbb{F_4}$&lt;&#x2F;th&gt;&lt;th&gt;Coordinates over $\mathbb{F_2}$&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;$0$&lt;&#x2F;td&gt;&lt;td&gt;$(0, 0)$&lt;&#x2F;td&gt;&lt;td&gt;$(0, 0, 0, 0)$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$1$&lt;&#x2F;td&gt;&lt;td&gt;$(1, 0)$&lt;&#x2F;td&gt;&lt;td&gt;$(1, 0, 0, 0)$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$X_0$&lt;&#x2F;td&gt;&lt;td&gt;$(X_0, 0)$&lt;&#x2F;td&gt;&lt;td&gt;$(0, 1, 0, 0)$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$1 + X_0$&lt;&#x2F;td&gt;&lt;td&gt;$(1 + X_0, 0)$&lt;&#x2F;td&gt;&lt;td&gt;$(1, 1, 0, 0)$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$X_1$&lt;&#x2F;td&gt;&lt;td&gt;$(0, 1)$&lt;&#x2F;td&gt;&lt;td&gt;$(0, 0, 1, 0)$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$1 + X_1$&lt;&#x2F;td&gt;&lt;td&gt;$(1, 1)$&lt;&#x2F;td&gt;&lt;td&gt;$(1, 0, 1, 0)$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$X_0 + X_1$&lt;&#x2F;td&gt;&lt;td&gt;$(X_0, 1)$&lt;&#x2F;td&gt;&lt;td&gt;$(0, 1, 1, 0)$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$(1 + X_0) + X_1$&lt;&#x2F;td&gt;&lt;td&gt;$(1 + X_0, 1)$&lt;&#x2F;td&gt;&lt;td&gt;$(1, 1, 1, 0)$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$X_0X_1$&lt;&#x2F;td&gt;&lt;td&gt;$(0, X_0)$&lt;&#x2F;td&gt;&lt;td&gt;$(0, 0, 0, 1)$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$1 + X_0X_1$&lt;&#x2F;td&gt;&lt;td&gt;$(1, X_0)$&lt;&#x2F;td&gt;&lt;td&gt;$(1, 0, 0, 1)$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$X_0 + X_0X_1$&lt;&#x2F;td&gt;&lt;td&gt;$(X_0, X_0)$&lt;&#x2F;td&gt;&lt;td&gt;$(0, 1, 0, 1)$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$(1 + X_0) + X_0 X_1$&lt;&#x2F;td&gt;&lt;td&gt;$(1 + X_0, X_0)$&lt;&#x2F;td&gt;&lt;td&gt;$(1, 1, 0, 1)$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$(1 + X_0 ) X_1$&lt;&#x2F;td&gt;&lt;td&gt;$(0, 1 + X_0)$&lt;&#x2F;td&gt;&lt;td&gt;$(0, 0, 1, 1)$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$1 + (1 + X_0 ) X_1$&lt;&#x2F;td&gt;&lt;td&gt;$(1, 1 + X_0)$&lt;&#x2F;td&gt;&lt;td&gt;$(1, 0, 1, 1)$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$X_0 + (1 + X_0 ) X_1$&lt;&#x2F;td&gt;&lt;td&gt;$(X_0, 1 + X_0)$&lt;&#x2F;td&gt;&lt;td&gt;$(0, 1, 1, 1)$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$(1 + X_0) + (1 + X_0 ) X_1$&lt;&#x2F;td&gt;&lt;td&gt;$(1 + X_0, 1 + X_0)$&lt;&#x2F;td&gt;&lt;td&gt;$(1, 1, 1, 1)$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;The way monomial basis are chosen also show how coordinates in succesive basis relate to one another: for instance, suppose we take an element $$\omega=a + bX_1 \in \mathbb{F_{16}} \quad \text{ with } a, b \in \mathbb{F_4}$$ and we represent $\omega$ by its coordinates $(a, b)$. If we now express $a$ and $b$ in terms of the basis $\{1, X_0 \}$ over $\mathbb{F_2}$ then we’ll be able to find the coordinates of $\omega$ over $\mathbb{F_2}$ by simply concatenating coordinates of $a$ and $b$!&lt;&#x2F;p&gt;
&lt;p&gt;To illustrate what the table is saying, take the element $\omega = X_0 + X_1$. Over $\mathbb{F_4}$, it is $X_0 \cdot 1 + 1 \cdot X_1$, so the coordinates are $$[\omega]^{ \mathbb{F_4} } = ( X_0 , 1)$$.&lt;br &#x2F;&gt;
Now, $[ X_0 ]^{ \mathbb{F_2} } = (0 , 1)$ and $[1]^{\mathbb{F_2}} = (1,0)$, so&lt;&#x2F;p&gt;
&lt;p&gt;$$[X_0 + X_1]^{ \mathbb{F_2} } = (0, 1, 1, 0)$$&lt;&#x2F;p&gt;
&lt;p&gt;We repeat what we mentioned earlier: whenever a choice of basis is made, there’s also a choice of order of the basis elements; mathematically speaking, basis consisting of the same elements but in a different order are different basis. In this exposition, the order is selected folklorically, reading the basis from left to right, aggregating elements as we read matching the succesive extensions. This is not the only way this could be done; as a matter of fact, the reverse ordering is popular among computer scientists.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;wiedemann-towers-and-the-work-of-diamond-and-posen&quot;&gt;Wiedemann towers and the work of Diamond and Posen&lt;&#x2F;h2&gt;
&lt;p&gt;What we have just seen in the example of $\mathbb{F_{16}}$ is an instance of a &lt;em&gt;Wiedemann tower&lt;&#x2F;em&gt; : a sequence of field extensions such that each extension is a quadratic extension of the previous one, represented in such a way that a basis of the extension can be obtained by adjoining roots of a certain sequence of irreducible polynomials at the time. In the case just seen, the basis was simply&lt;&#x2F;p&gt;
&lt;p&gt;$$\mathcal{B} = \{1, X_0 ,X_1 ,X_0 X_1 \}$$&lt;&#x2F;p&gt;
&lt;p&gt;and the field elements are simply $\mathbb{F_2}$ linear combinations of these symbols: we will commonly view them as polynomials in 2 variables over $\mathbb{F_2}$ in which all the variables appear raised to the first power, at most. These polynomials are usually called “multilinear” in the cryptography context. These type of field extensions and polynomials are central to the work of Ben Diamond and Jim Posen in their proposition for a setting in which zero knowledge protocols can be implemented in characteristic 2 for more efficient performance relying on circuitry-level arithmetical operations: &lt;strong&gt;BINIUS&lt;&#x2F;strong&gt;. The binary tower defined in their work is defined just like an iterative quadratic sequence of extensions, inspired in the work of Wiedemann. To match their notation set $\mathcal{T_0} = \mathbb{F_2}$ and then recursively define&lt;&#x2F;p&gt;
&lt;p&gt;$$\mathcal{T_{ k + 1}} = \mathcal{T_{k}} [X_{ k + 1}]&#x2F; \langle f_{ k + 1} \rangle$$&lt;&#x2F;p&gt;
&lt;p&gt;where $f_{ k + 1 } ( X_{ k + 1 }) = X_{ k + 1 }^2 + X_{k} X_{ k + 1 } + 1$; Wiedemann proved that this polynomial is indeed irreducible over $\mathcal{T_k}$ and so it defines $\mathcal{T_{ k + 1}}$ as a quadratic extension of $\mathcal{T_{k}}$. Briefly write down a few extensions&lt;&#x2F;p&gt;
&lt;p&gt;$$\mathbb{F_2} = \mathcal{T_0},\quad \mathbb{F_4} = \mathcal{T_1} , \quad \mathbb{F_{16}} = \mathcal{T_2},\ldots $$&lt;&#x2F;p&gt;
&lt;p&gt;We will usually refer to $\mathcal{T_k}$ as the $k-$th level or extension of $\mathcal{T_0}$; and such a field has exactly $2^{ 2^k }$ elements. In such level, elements are described as polynomials in the set of $k$ variables $\{X_0 , X_1 , \ldots, X_{ k - 1} \}$ such that every $X$ is raised to a power at most 1, this is, they are linear combinations over $\mathbb{F_2}$ of multilinear monomials. For simplicity, there is also an extremely convenient way to point to specific monomials and it relates to the binary expansion of the non-negative integers.&lt;&#x2F;p&gt;
&lt;p&gt;To make this clear, suppose we need to find the $n-$th basis element, and we’ll call it $y_n$. To do that, we simply expand $n$ in base 2:&lt;&#x2F;p&gt;
&lt;p&gt;$$n = \sum \limits_{ i = 0 } n_i 2^i , \quad \text{ where } n_i \in {0,1}$$&lt;&#x2F;p&gt;
&lt;p&gt;and then set&lt;&#x2F;p&gt;
&lt;p&gt;$$y_n = \prod_{i: n_i = 1} X_i$$&lt;&#x2F;p&gt;
&lt;p&gt;For instance, to obtain the tenth basic element in the Wiedemann tower, first expand in base 2:&lt;&#x2F;p&gt;
&lt;p&gt;$$10 = 0\cdot 2^0 + 1 \cdot 2^1 + 0 \cdot 2^2 + 1\cdot 2^3 , \quad\text{ or more briefly } [10]^2 = [1010]$$&lt;&#x2F;p&gt;
&lt;p&gt;(and you need to remember that it is customary in computer science to start the expansion with the most significant digit and that counts of elements usually start at zero), and then build&lt;&#x2F;p&gt;
&lt;p&gt;$$y_{10} = X_1 X_3$$&lt;&#x2F;p&gt;
&lt;p&gt;This specific ordering of the basis, which we admitted naturally from the conversation is indeed a &lt;em&gt;lexicographic order&lt;&#x2F;em&gt; , and such fact which will allow various things:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * First of all, it will allow us to eyeball if an elements belongs to a specific subfield of $\mathcal{T_k}$; whenever the coordinate vector associated to a level $k$ element has its last half of coordinates equal to zero, then we know it belongs to $\mathcal{T_{ k - 1}}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * This previous fact shows that the tower construction nicely embeds $\mathcal{T_{ k - 1}}$ into $\mathcal{T_k}$ by zero padding in the last half of the coordinate vector. Computationally it has &amp;quot;zero cost&amp;quot; to view elements from a subfield as an element of an extension of that field.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This properties make the Wiedemann towers so suitable for coding and chip-level implementations: there is no mathematical guarantee on arbitrary extensions that we can identify to which subfield an element belongs to. However, in this case and due to the highly structured nature of these fields, that problem can be sometimes quickly solved. Or phrased better: we can easily characterize subfields of the extension.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;field-operations-and-the-issue-of-multiplication&quot;&gt;Field operations and the issue of multiplication&lt;&#x2F;h2&gt;
&lt;p&gt;An interesting aspect of these type of towers is the way coordinates behave under the usual field operations.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;addition&quot;&gt;Addition&lt;&#x2F;h3&gt;
&lt;p&gt;The relationship between addition in $\mathbb{F_2}$ (which is the operation performed on the coordinates) and the XOR operation is direct and fundamental. Addition of two elements in a finite extension $\mathcal{T_k}$ is performed by adding their corresponding coordinates modulo 2. Since addition modulo 2 is equivalent to the XOR operation, addition is a very fast and efficient bitwise operation in most processor architectures.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;multiplication&quot;&gt;Multiplication&lt;&#x2F;h3&gt;
&lt;p&gt;Now here is where things get slippery. Multiplication of field elements can be carried out in different ways according to how those elements are represented. Let’s begin with&lt;&#x2F;p&gt;
&lt;h4 id=&quot;multiplication-the-naive-way-polynomials-with-reduction&quot;&gt;Multiplication the naive way: polynomials with reduction&lt;&#x2F;h4&gt;
&lt;p&gt;One of the more straightforward way of multiplying elements in a field extension is by first representing elements as polynomials, then multiplying those polynomials and finally reducing the product modulo the irreducible that defines the extension of $\mathbb{F_2}$.&lt;&#x2F;p&gt;
&lt;p&gt;To illustrate, consider $u,v \in \mathcal{T_2}$. Let’s go slowly.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Multiplication as Polynomials in $X_1$ with Coefficients in $\mathcal{T_1}$:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;$$
\begin{align*}
u \cdot v &amp;amp;= ((1 + X_0) + X_1)(X_0 + X_0X_1) \\
&amp;amp;= (1 + X_0)X_0 + (1 + X_0)X_0X_1 + X_1X_0 + X_1(X_0X_1) \\
&amp;amp;= (X_0 + X_0^2) + (X_0 + X_0^2 ) X_1 + X_0 X_1 + X_0 X_1^2
\end{align*}
$$&lt;&#x2F;p&gt;
&lt;p&gt;Now, we substitute $X_0^2 = X_0 + 1$ and $X_1^2 = X_1 X_0 + 1$:&lt;&#x2F;p&gt;
&lt;p&gt;$$
\begin{align*}
&amp;amp;= (X_0 + X_0 + 1) + (X_0 + X_0 + 1)X_1 + X_0 X_1 + X_0(X_1 X_0 + 1) \\
&amp;amp;= (2X_0 + 1) + (2X_0 + 1)X_1 + X_0 X_1 + X_1 X_0^2 + X_0)
\end{align*}
$$&lt;&#x2F;p&gt;
&lt;p&gt;Since we are in a field with characteristic 2, $2X_0 = 0$. So,&lt;&#x2F;p&gt;
&lt;p&gt;$$
\begin{align*}
&amp;amp;= 1 + X_1 + X_0X_1 + X_1(X_0 + 1) + X_0 \\
&amp;amp;= 1 + X_1 + X_0X_1 + X_0X_1 + X_1 + X_0 \\
&amp;amp;= 1 + X_0
\end{align*}
$$&lt;br &#x2F;&gt;
So, $((1 + X_0 ) + X_1 )(X_0 + X_0 X_1 ) = 1 + X_0$ in $\mathcal{T_2}$.&lt;&#x2F;p&gt;
&lt;p&gt;As the reader may have guessed - this is a lot of work. We’d like to have a more efficient algorithm for multiplication of field elements that draws from the highly structured tower of extensions.&lt;&#x2F;p&gt;
&lt;p&gt;One way of having a systematic approach to field element multiplication is by using a Karatsuba-like technique.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;karatsuba-like-multiplication-in-the-wiedemann-tower&quot;&gt;Karatsuba-like Multiplication in the Wiedemann Tower&lt;&#x2F;h4&gt;
&lt;p&gt;The primary aim of the Karatsuba algorithm, when applied to multiplication of elements in a finite field extension (like the levels of the Wiedemann tower), is to &lt;strong&gt;reduce the number of field multiplications&lt;&#x2F;strong&gt; in the larger field by increasing the number of &lt;em&gt;field additions&lt;&#x2F;em&gt; and &lt;em&gt;sub-field multiplications&lt;&#x2F;em&gt; by exploiting the fact that additions (done through XOR) is computationally cheap.&lt;&#x2F;p&gt;
&lt;p&gt;Specifically, for multiplying two degree-1 polynomials over a subfield, a naive approach would require four multiplications in the subfield. Karatsuba’s method achieves this with only &lt;strong&gt;three multiplications&lt;&#x2F;strong&gt; and a few additions in the subfield. This seemingly small reduction becomes significant when applied recursively across many levels of a tower extension, leading to a sub-quadratic asymptotic complexity.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s start describing the Karatsuba formula for multiplication of two elements in $\mathcal{T_k}$ (which are polynomials of degree at most 1 in $X_{ k - 1}$ with coefficients in $\mathcal{T_{ k - 1}}$) by stating what the multiplication looks like and then by sharpening our eye:&lt;&#x2F;p&gt;
&lt;p&gt;Suppose that we need to multiply together $$u = \alpha_0 + \alpha_1 X_{ k - 1 }\quad \text{and } \quad v = \beta_0 + \beta_1 X_{ k - 1}$$ with $\alpha_i, \beta_i \in \mathcal{T_{ k - 1}}$ for $i = 0,1$. Then multiplication obeys the distributive law and so the product we’re looking for is then&lt;&#x2F;p&gt;
&lt;p&gt;$$u\cdot v = \alpha_1 \beta_1 X_{ k - 1}^2 + (\alpha_0 \beta_1 + \alpha_1 \beta_0) X_{ k - 1} + \alpha_0 \beta_0 $$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Step 1: Compute the three intermediate products in the subfield $\mathcal{T_{ k - 1 }}$.**&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is where the Karatsuba trick reduces multiplications. Instead of computing the four products involving $\alpha_i\beta_j$, we resort to compute three multiplications instead:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $P_A = \alpha_0 \beta_0$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $P_B = \alpha_1 \beta_1$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $P_C = (\alpha_0 + \alpha_1)(\beta_0 + \beta_1)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;and note that in characteristic two these three products suffice to produce the coefficents in $u\cdot v$ since&lt;&#x2F;p&gt;
&lt;p&gt;$$P_A + P_B + P_C = \alpha_0 \beta_1 + \alpha_1 \beta_0 = M$$&lt;&#x2F;p&gt;
&lt;p&gt;We commonly call $M$ the “middle term”. These three multiplications and two additions are performed in $\mathcal{T_{ k - 1}}$.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Step 2: Reduce the product using the defining irreducible polynomial.**&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Up to this point, the product is given by:&lt;&#x2F;p&gt;
&lt;p&gt;$$P_B X_{ k - 1 }^2 + MX_{ k - 1} + P_A$$&lt;&#x2F;p&gt;
&lt;p&gt;Now the relation $X_{ k - 1 }^2 = X_{ k - 2} X_{ k - 1} + 1$ will yield the final expression for the desired product:&lt;&#x2F;p&gt;
&lt;p&gt;$$u\cdot v= (P_A + P_B) + (M + P_B X_{ k - 2}) X_{ k - 1}$$&lt;&#x2F;p&gt;
&lt;p&gt;This is the final reduction to the canonical polynomial representation of the element. There is something relevant to point out exactly here. How is this computation performed?&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * As mentioned before, the coefficients $P_A + P_B$ and $M + P_B X_{k - 2}$ computed in the subfield $\mathcal{T_{ k - 1}}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * To compute the greater linear combination, we must compute the product&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$(M + P_B X_{ k - 2}) X_{ k - 1}$$&lt;&#x2F;p&gt;
&lt;p&gt;first. The catch is that when considering $\mathcal{T_k}$ as a vector space over $\mathcal{T_0}$, multiplication by $X_{ k - 1}$ is then an automorphism, so the product mentioned above can be obtained by matrix multiplication once we look at the elements in the convenient level of the Wiedemann tower (and here is where the way the subfields are linked together pays dividends). Explicitly, &lt;strong&gt;we first interpret $M + P_B X_{ k - 2}$ as an element of the upper field $\mathcal{T_k}$. In coordinates this fact is expressed by padding the coordinates $[\cdot]^{ k - 1}$ with zeros to obtain its coordinates $[\cdot]^k$:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;$$[M + P_B X_{ k - 2}]^k = [ [M + P_B X_{ k - 2}]^{ k - 1}:, 0,0,\cdots 0]$$&lt;&#x2F;p&gt;
&lt;p&gt;If we consider $M + P_B X_{ k - 2} \in \mathcal{T_k}$ then the product against $X_{ k - 1}$ con be performed in coordinates by matrix multiplication:&lt;&#x2F;p&gt;
&lt;p&gt;$$[(M + P_B X_{ k - 2}) X_{ k - 1 }]^{k} = [M + P_B X_{ k - 2}]^{k} A_{ k - 1}$$&lt;&#x2F;p&gt;
&lt;p&gt;where $A_k$ is the matrix that has &lt;strong&gt;as rows&lt;&#x2F;strong&gt; the coordinates over $\mathcal{T_k}$ of the products of the basis elements of $\mathcal{T_k}$ by $X_{ k - 1}$.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The final addition is performed in the top field $\mathcal{T_k}$; in coordinates this is simply done by XOR.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;a-quick-summary-so-far&quot;&gt;A quick summary, so far:&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Concatenation for Hierarchy:** The key insight of the multilinear basis (as implicitly adopted by Diamond and Posen) is that an element&amp;#39;s representation in $\mathcal{T_k}$ is simply the concatenation of its coefficients from $\mathcal{T_{ k - 1}}$. This means you can &amp;quot;unpack&amp;quot; an element into its sub-elements simply by splitting its bit string. This is a &amp;quot;free&amp;quot; operation, involving no computation beyond index manipulation.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Recursive Application:** The Karatsuba algorithm maps perfectly to this recursive structure. This is exactly how the algorithm is designed to work efficiently.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Bitwise XOR for Additions:** All additions are simply bitwise XORs ($\oplus$) on the coordinate vectors. This is exceptionally fast on modern processors, which can perform XOR on entire machine words in a single cycle.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Defined Reductions:** The irreducible polynomials ($X_0^2 = X_0 + 1$, $X_1^2 = X_0 X_1 + 1$, $X_2^2 = X_1 X_2 + 1$) are simple trinomials or binomials in $\mathbb{F_2}$. The reduction step (e.g., $X_1^2 \to X_0 X_1 + 1$) translates into a linear transformation on the coefficient vector that can be done with a few XORs and re-indexing.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Small Coefficients:** Because the field is $\mathbb{F_2}$, all coefficients ($a_0, a_1, \ldots$) are single bits (0 or 1). This simplifies the base multiplications within the $M_1$ function, making it extremely efficient.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;an-extended-example-by-hand&quot;&gt;An extended example, by hand&lt;&#x2F;h2&gt;
&lt;p&gt;Let’s work out the product of two elements in $\mathcal{T_3}$, namely&lt;&#x2F;p&gt;
&lt;p&gt;$$u = X_0 + X_1 X_2 \quad\text{and }\quad v = 1 + X_1 + X_0 X_2$$&lt;&#x2F;p&gt;
&lt;p&gt;using the aforementioned algorithm. Before going any further, and just because we want to avoid the pain of going way too deep in the recursion, we can be practical and cook up the matrix for the “multiplication by $X_0$” map. This matrix is then&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\boxed{&lt;br &#x2F;&gt;
\begin{matrix}&lt;br &#x2F;&gt;
0 &amp;amp; 1 \newline&lt;br &#x2F;&gt;
1 &amp;amp; 1&lt;br &#x2F;&gt;
\end{matrix}&lt;br &#x2F;&gt;
}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;and helps building a complete multiplication table; to multiply $\gamma$ by $X_0$ we compute&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
[\gamma]^{1} \cdot \boxed{&lt;br &#x2F;&gt;
\begin{matrix}&lt;br &#x2F;&gt;
0 &amp;amp; 1 \newline&lt;br &#x2F;&gt;
1 &amp;amp; 1&lt;br &#x2F;&gt;
\end{matrix}&lt;br &#x2F;&gt;
} = [\gamma\cdot X_0 ]^1&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;For a full multiplication table covering all possible field element multiplications in $\mathcal{T_1}$, we resort to linearity and the gadget above.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s get started. Remember that $\mathcal{T_3}$ is a field with $2^{ 2^3 } = 2^8 = 256$ elements, and as a vector space over $\mathbb{F_2} = \mathcal{T_0}$ is has dimension 8; its multilinear basis is then&lt;&#x2F;p&gt;
&lt;p&gt;$$\{1, X_0 ,X_1 ,X_0 X_1 ,X_2 ,X_0 X_2 ,X_1 X_2 ,X_0 X_1 X_2 \}$$&lt;&#x2F;p&gt;
&lt;p&gt;We will carry out the product of $u$ and $v$ in coordinates. First of all,&lt;&#x2F;p&gt;
&lt;p&gt;$$[u]^3 = (0,1,0,0,0,0,1,0) \quad\text{and }\quad [v]^3 =(1,0,1,0,0,1,0,0)$$&lt;&#x2F;p&gt;
&lt;p&gt;are the coordinates of $u$ and $v$ in the multilinear basis for $\mathcal{T_3}$. Before carrying out Karatsuba’s algorithm, we will display both set of coordinates in matrix form and hint a partition corresponding to the canonical description of both elements as elements of the last extension in the tower. This is&lt;&#x2F;p&gt;
&lt;p&gt;$$\begin{pmatrix}u\newline \hline v\end{pmatrix}^3 = \begin{pmatrix}&lt;br &#x2F;&gt;
0 &amp;amp; 1 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1 &amp;amp; 0 \newline&lt;br &#x2F;&gt;
\hline&lt;br &#x2F;&gt;
1 &amp;amp; 0 &amp;amp; 1 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1 &amp;amp; 0 &amp;amp; 0&lt;br &#x2F;&gt;
\end{pmatrix}=&lt;br &#x2F;&gt;
\left(&lt;br &#x2F;&gt;
\begin{array}{cccc:cccc} % ‘c’ for centered column, ‘:’ for a dotted vertical line&lt;br &#x2F;&gt;
0 &amp;amp; 1 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1 &amp;amp; 0 \newline&lt;br &#x2F;&gt;
\hline % Solid horizontal line&lt;br &#x2F;&gt;
1 &amp;amp; 0 &amp;amp; 1 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1 &amp;amp; 0 &amp;amp; 0&lt;br &#x2F;&gt;
\end{array}&lt;br &#x2F;&gt;
\right)&lt;br &#x2F;&gt;
= \left(&lt;br &#x2F;&gt;
\begin{array}{c:c} % ‘c’ for centered column, ‘:’ for a dotted vertical line&lt;br &#x2F;&gt;
\alpha_0 &amp;amp; \alpha_1 \newline&lt;br &#x2F;&gt;
\hline % Solid horizontal line&lt;br &#x2F;&gt;
\beta_0 &amp;amp; \beta_1&lt;br &#x2F;&gt;
\end{array}&lt;br &#x2F;&gt;
\right)$$&lt;&#x2F;p&gt;
&lt;p&gt;where we’re exploiting the fact that we can write $u$ and $v$ over the previous extension $\mathcal{T_2}$:&lt;&#x2F;p&gt;
&lt;p&gt;$$u = \alpha_0 + \alpha_1 X_2 \quad\text{and }\quad v = \beta_0 + \beta_1 X_2$$&lt;&#x2F;p&gt;
&lt;p&gt;for certain $\alpha_i , \beta_j \in \mathcal{T_2}$. Recall that this field has dimension 4 and that the previous matrix partition already gives us the coordinates over $\mathcal{T_0}$ of the coordinates over $\mathcal{T_2}$! This is the utterly COOL feature of multilinear basis for binary towers! We’re now ready to proceed with Karatsuba’s algorithm.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **First step:** We proceed to compute the products&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. $P_A = \alpha_0 \beta_0$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. $P_B = \alpha_1 \beta_1$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. $P_C = (\alpha_0 + \alpha_1) (\beta_0 + \beta_1)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. $P_B X_1$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;where &lt;strong&gt;all of these elements belong to and action is done in the subfield $\mathcal{T_2}$.&lt;&#x2F;strong&gt; In order to do this, we need to go one layer deep for each of the products needed. Let’s proceed with caution.&lt;&#x2F;p&gt;
&lt;p&gt;i. To calculate $P_A$ we interpret the &lt;strong&gt;coordinates over $\mathcal{T_2}$ in coordinates over $\mathcal{T_0}$&lt;&#x2F;strong&gt; and just as in the previous layer and write&lt;&#x2F;p&gt;
&lt;p&gt;$$\begin{pmatrix}\alpha_0\newline \hline \beta_0\end{pmatrix}^2=\begin{pmatrix}&lt;br &#x2F;&gt;
0 &amp;amp; 1 &amp;amp; 0 &amp;amp; 0\newline&lt;br &#x2F;&gt;
\hline % This command draws a solid horizontal line&lt;br &#x2F;&gt;
1 &amp;amp; 0 &amp;amp; 1 &amp;amp; 0&lt;br &#x2F;&gt;
\end{pmatrix}=&lt;br &#x2F;&gt;
\left(&lt;br &#x2F;&gt;
\begin{array}{cc:cc} % ‘c’ for centered column, ‘:’ for a dotted vertical line&lt;br &#x2F;&gt;
0 &amp;amp; 1 &amp;amp; 0 &amp;amp; 0 \newline&lt;br &#x2F;&gt;
\hline % Solid horizontal line&lt;br &#x2F;&gt;
1 &amp;amp; 0 &amp;amp; 1 &amp;amp; 0&lt;br &#x2F;&gt;
\end{array}&lt;br &#x2F;&gt;
\right)&lt;br &#x2F;&gt;
= \left(&lt;br &#x2F;&gt;
\begin{array}{c:c} % ‘c’ for centered column, ‘:’ for a dotted vertical line&lt;br &#x2F;&gt;
\alpha_{00} &amp;amp; \alpha_{01} \newline&lt;br &#x2F;&gt;
\hline % Solid horizontal line&lt;br &#x2F;&gt;
\beta_{00} &amp;amp; \beta_{01}&lt;br &#x2F;&gt;
\end{array}&lt;br &#x2F;&gt;
\right)$$&lt;&#x2F;p&gt;
&lt;p&gt;Applying Karatsuba’s algorithm in this scenario requires reaching for the multiplication table we mentioned earlier,&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $P^\prime_A = \alpha_{00}\cdot\beta_{00}$, which in $\mathcal{T_1}$ coordinates is the product $$\boxed{0, 1}\times \boxed{1, 0}=\boxed{0,1}$$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $P^\prime_B = \alpha_{01}\cdot\beta_{01}$, which in $\mathcal{T_1}$ coordinates is the product $$\boxed{0, 0}\times \boxed{1, 0}=\boxed{0,0}$$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $P^\prime_C = (\alpha_{00}+\alpha_{01})\cdot(\beta_{00}+\beta_{01})$, which in $\mathcal{T_1}$ coordinates is the product $$\boxed{0, 1}\times \boxed{0, 0}=\boxed{0,0}$$ (once done the necessary addition in each factor)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * And finally the product of the uncanny $P^\prime_B X_{0}$ term:  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$\boxed{0,0}\times\boxed{&lt;br &#x2F;&gt;
\begin{matrix}&lt;br &#x2F;&gt;
0 &amp;amp; 1 \newline&lt;br &#x2F;&gt;
1 &amp;amp; 1&lt;br &#x2F;&gt;
\end{matrix}&lt;br &#x2F;&gt;
}=\boxed{0,0}$$&lt;&#x2F;p&gt;
&lt;p&gt;It is now time to construct the product $\alpha_0 \beta_0$ as an element in $\mathcal{T_2}$; and now is where the special choice of basis comes into play (again): &lt;strong&gt;The way elements of $\mathcal{T_1}$ sit into $\mathcal{T_2}$ is fundamental and computationally crucial: to view them in the extension above we simply pad with zeros at the end of their $\mathcal{T_1}$ coordinates to get a 4 bit string.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;According to the algorithm presented, the coordinate expression for&lt;&#x2F;p&gt;
&lt;p&gt;$$\alpha_0 \beta_0 = (P^\prime_A + P^\prime_B) + (M + P^\prime_B X_0) X_1$$&lt;&#x2F;p&gt;
&lt;p&gt;can be reconstructed step by step. &lt;strong&gt;First add&lt;&#x2F;strong&gt; in $\mathcal{T_1}$, &lt;strong&gt;then pad&lt;&#x2F;strong&gt; :&lt;&#x2F;p&gt;
&lt;p&gt;$$[P^\prime_A + P^\prime_B ]^1 = \boxed{0,1} + \boxed{0,0} = \boxed{0,1} \implies [P\prime_A+P\prime_B]^2 = \boxed{0,1,0,0}$$&lt;&#x2F;p&gt;
&lt;p&gt;Then, the slippery part: viewed as elements in $\mathcal{T_1}$,&lt;&#x2F;p&gt;
&lt;p&gt;$$[P^\prime_B X_0 ]^1 = \boxed{0,0} \implies [M + P^\prime_B X_0 ]^1 = \boxed{0,1} + \boxed{0,0} =\boxed{0,1}$$&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Before multiplying it with $X_1$, we embed this element in $\mathcal{T_2}$ by padding with zeros at the end.&lt;&#x2F;strong&gt; Multiplication by $X_1$ is done by matrix multiplication&lt;&#x2F;p&gt;
&lt;p&gt;$$[(M + P^\prime_B X_0 )\cdot X_1 ]^2 = \boxed{0,1,0,0}\times \boxed{&lt;br &#x2F;&gt;
\begin{matrix}&lt;br &#x2F;&gt;
0 &amp;amp; 0 &amp;amp; 1 &amp;amp;0\newline&lt;br &#x2F;&gt;
0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1\newline&lt;br &#x2F;&gt;
1 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1\newline&lt;br &#x2F;&gt;
0 &amp;amp; 1 &amp;amp; 1 &amp;amp; 1&lt;br &#x2F;&gt;
\end{matrix}&lt;br &#x2F;&gt;
} =\boxed{0,0,0,1}$$&lt;&#x2F;p&gt;
&lt;p&gt;Finally, performing the sum we obtain&lt;&#x2F;p&gt;
&lt;p&gt;$$\boxed{0,1,0,0} + \boxed{0,0,0,1} = \boxed{0,1,,0,1}$$&lt;&#x2F;p&gt;
&lt;p&gt;which means that $P_A = \alpha_0 \beta_0 = X_0 + X_0 X_1 \in \mathcal{T_2}$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Once that we explained in detail the first case, we proceed to calculate $P_B:$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$\begin{pmatrix}\alpha_1\newline \hline \beta_1\end{pmatrix}^2=\begin{pmatrix}&lt;br &#x2F;&gt;
0 &amp;amp; 0 &amp;amp; 1 &amp;amp; 0\newline&lt;br &#x2F;&gt;
\hline % This command draws a solid horizontal line&lt;br &#x2F;&gt;
0 &amp;amp; 1 &amp;amp; 0 &amp;amp; 0&lt;br &#x2F;&gt;
\end{pmatrix}=&lt;br &#x2F;&gt;
\left(&lt;br &#x2F;&gt;
\begin{array}{cc:cc} % ‘c’ for centered column, ‘:’ for a dotted vertical line&lt;br &#x2F;&gt;
0 &amp;amp; 0 &amp;amp; 1 &amp;amp; 0 \newline&lt;br &#x2F;&gt;
\hline % Solid horizontal line&lt;br &#x2F;&gt;
0 &amp;amp; 1 &amp;amp; 0 &amp;amp; 0&lt;br &#x2F;&gt;
\end{array}&lt;br &#x2F;&gt;
\right)&lt;br &#x2F;&gt;
= \left(&lt;br &#x2F;&gt;
\begin{array}{c:c} % ‘c’ for centered column, ‘:’ for a dotted vertical line&lt;br &#x2F;&gt;
\alpha_{10} &amp;amp; \alpha_{11} \newline&lt;br &#x2F;&gt;
\hline % Solid horizontal line&lt;br &#x2F;&gt;
\beta_{10} &amp;amp; \beta_{11}&lt;br &#x2F;&gt;
\end{array}&lt;br &#x2F;&gt;
\right)$$&lt;&#x2F;p&gt;
&lt;p&gt;We’ll compute $\alpha_1 \beta_1$ going one level down in the recursion, viewing its coordinates in $\mathcal{T_2}$ in its coordinates in $\mathcal{T_0}$, just as before:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. $P^\prime_A = \alpha_{10}\cdot\beta_{10}$, which in $\mathcal{T_1}$ coordinates is the product $$\boxed{0, 0}\times \boxed{1, 0} = \boxed{0,0}$$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. $P^\prime_B = \alpha_{11}\cdot\beta_{11}$, which in $\mathcal{T_1}$ coordinates is the product $$\boxed{1, 0}\times \boxed{0, 0} = \boxed{0,0}$$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. $P^\prime_C = (\alpha_{10} + \alpha_{11})\cdot(\beta_{10} + \beta_{11})$, which in $\mathcal{T_1}$ coordinates is the product $$\boxed{1, 0}\times \boxed{0, 1} = \boxed{0,1}$$ (once done the necessary addition in each factor)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. And finally we have the $P^\prime_B X_{0}$ term (we omit writing down the matrix product since this is fairly trivial and intuitive from reading the coordinates):  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$\boxed{0,0}\times\boxed{0,1} = \boxed{0,0}$$&lt;&#x2F;p&gt;
&lt;p&gt;With all these, we’re ready to reconstruct $\alpha_1 \beta_1$ as an element in $\mathcal{T_2}$. The coordinate expression for&lt;&#x2F;p&gt;
&lt;p&gt;$$\alpha_1 \beta_1 = (P^\prime_A + P^\prime_B ) + (M + P^\prime_B X_0) X_1$$&lt;&#x2F;p&gt;
&lt;p&gt;can be reconstructed from the 2-bit strings as follows: &lt;strong&gt;first, add then pad.&lt;&#x2F;strong&gt; We get&lt;&#x2F;p&gt;
&lt;p&gt;$$[P^\prime_A + P^\prime_B ]^1 = \boxed{0,0} + \boxed{0,0} = \boxed{0,0}\implies [P^\prime_A + P^\prime_B ]^2 = \boxed{0,0,0,0}$$&lt;&#x2F;p&gt;
&lt;p&gt;remembering the padding to view them in $\mathcal{T_2}$ coordinates. Then, the slippery part: viewed as elements in $\mathcal{T_1}$,&lt;&#x2F;p&gt;
&lt;p&gt;$$[P^\prime_B X_0 ]^1=\boxed{0,0}\implies [M + P^\prime_B X_0]^1 = \boxed{0,1} + \boxed{0,0} = \boxed{0,1}$$&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Before multiplying it with $X_1$, we embed this element in $\mathcal{T_2}$ by padding with zeros at the end.&lt;&#x2F;strong&gt; Then, matrix multiplication:&lt;&#x2F;p&gt;
&lt;p&gt;$$[(M + P^\prime_B X_0 ) X_1]^2 = \boxed{0,1,0,0}\times \boxed{&lt;br &#x2F;&gt;
\begin{matrix}&lt;br &#x2F;&gt;
0 &amp;amp; 0 &amp;amp; 1 &amp;amp;0\newline&lt;br &#x2F;&gt;
0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1\newline&lt;br &#x2F;&gt;
1 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1\newline&lt;br &#x2F;&gt;
0 &amp;amp; 1 &amp;amp; 1 &amp;amp; 1&lt;br &#x2F;&gt;
\end{matrix}&lt;br &#x2F;&gt;
}=\boxed{0,0,0,1}$$&lt;&#x2F;p&gt;
&lt;p&gt;We then perform the sum to obtain&lt;&#x2F;p&gt;
&lt;p&gt;$$\boxed{0,0,0,0} + \boxed{0,0,0,1} = \boxed{0,0,,0,1}$$&lt;&#x2F;p&gt;
&lt;p&gt;which means that $P_B = \alpha_1 \beta_1 = X_0 X_1 \in \mathcal{T_2}$&lt;&#x2F;p&gt;
&lt;p&gt;Now we want to compute $P_C = (\alpha_) + \alpha_1)(\beta_0 + \beta_1)$. By taking a look at the expression in coordinates of $u$ and $v$, the sum of its first and second halves is done quickly and now we have&lt;&#x2F;p&gt;
&lt;p&gt;$$\begin{pmatrix}\alpha_0 + \alpha_1\newline \hline \beta_0 + \beta_1\end{pmatrix}^2=\begin{pmatrix}&lt;br &#x2F;&gt;
0 &amp;amp; 1 &amp;amp; 1 &amp;amp; 0\newline&lt;br &#x2F;&gt;
\hline % This command draws a solid horizontal line&lt;br &#x2F;&gt;
1 &amp;amp; 1 &amp;amp; 1 &amp;amp; 0&lt;br &#x2F;&gt;
\end{pmatrix}=&lt;br &#x2F;&gt;
\left(&lt;br &#x2F;&gt;
\begin{array}{cc:cc} % ‘c’ for centered column, ‘:’ for a dotted vertical line&lt;br &#x2F;&gt;
0 &amp;amp; 1 &amp;amp; 1 &amp;amp; 0 \newline&lt;br &#x2F;&gt;
\hline % Solid horizontal line&lt;br &#x2F;&gt;
1 &amp;amp; 1 &amp;amp; 1 &amp;amp; 0&lt;br &#x2F;&gt;
\end{array}&lt;br &#x2F;&gt;
\right)&lt;br &#x2F;&gt;
= \left(&lt;br &#x2F;&gt;
\begin{array}{c:c} % ‘c’ for centered column, ‘:’ for a dotted vertical line&lt;br &#x2F;&gt;
a &amp;amp; b \newline&lt;br &#x2F;&gt;
\hline % Solid horizontal line&lt;br &#x2F;&gt;
c &amp;amp; d&lt;br &#x2F;&gt;
\end{array}&lt;br &#x2F;&gt;
\right)$$&lt;&#x2F;p&gt;
&lt;p&gt;We’ll compute $P_C$ going one level down in the recursion, viewing its coordinates in $\mathcal{T_2}$ in its coordinates in $\mathcal{T_0}$, just as before:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. $P^\prime_A = a\cdot c$, which in $\mathcal{T_1}$ coordinates is the product $$\boxed{0, 1}\times \boxed{1, 1} = \boxed{1,0}$$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. $P^\prime_B = b\cdot d$, which in $\mathcal{T_1}$ coordinates is the product $$\boxed{1, 0}\times \boxed{1, 0} = \boxed{1,0}$$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. $P^\prime_C = (a + b)\cdot(c + d)$, which in $\mathcal{T_1}$ coordinates is the product $$\boxed{1, 1}\times \boxed{0, 1}=\boxed{1,0}$$ (once done the necessary addition in each factor)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. And finally we have the $P^\prime_B X_{0}$ term:  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$\boxed{1,0}\times\boxed{0,1} = \boxed{0,1}$$&lt;&#x2F;p&gt;
&lt;p&gt;With all these, we’re ready to reconstruct $P_C$ as an element in $\mathcal{T_2}$. The coordinate expression for&lt;&#x2F;p&gt;
&lt;p&gt;$$P_C = (P^\prime_A + P^\prime_B) + (M + P^\prime_B X_0 )X_1$$&lt;&#x2F;p&gt;
&lt;p&gt;can be reconstructed from the 2-bit strings as follows: &lt;strong&gt;first add, then pad&lt;&#x2F;strong&gt;. Since we already did this a couple of times, we allow some speeding:&lt;&#x2F;p&gt;
&lt;p&gt;$$[P^\prime_A + P^\prime_B ]^2 = \boxed{1,0,0,0} + \boxed{1,0,0,0} = \boxed{0,0,0,0}$$&lt;&#x2F;p&gt;
&lt;p&gt;Then, the slippery part: viewed as elements in $\mathcal{T_1}$,&lt;&#x2F;p&gt;
&lt;p&gt;$$P^\prime_B X_0 = \boxed{0,1}\implies M + P^\prime_B X_0 = \boxed{1,0} + \boxed{0,1} = \boxed{1,1}$$&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Before multiplying it with $X_1$, we embed this element in $\mathcal{T_2}$ by padding with zeros at the end.&lt;&#x2F;strong&gt; We now perform the product in the upper extension by simply shifting its coefficients in two positions to the left while padding with zeros the first two slots:&lt;&#x2F;p&gt;
&lt;p&gt;$$[M + P^\prime_B X_0 ]^2=\boxed{1,1,0,0},\quad\text{then }\quad [(M + P^\prime_B X_0 )X_1 ]^2 = \boxed{0,0,1,1}$$&lt;&#x2F;p&gt;
&lt;p&gt;We obtain $[P_C ]^2=\boxed{0,0,1,1}$, this is, $P_C = X_1 + X_0 X_1 \in\mathcal{T_2}$&lt;&#x2F;p&gt;
&lt;p&gt;The last branch of this first layer amounts to computing $P_BX_1$; this product happens in the $\mathcal{T_2}$ subfield. In coordinates we have&lt;&#x2F;p&gt;
&lt;p&gt;$$[P_B X_1 ]^2 = \boxed{0,1,1,1}$$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Second step:** Reconstruct by performing additions&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We’re now ready to build $u\cdot v$ with Karatsuba’s recipe:&lt;&#x2F;p&gt;
&lt;p&gt;$$u\cdot v = (P_A + P_B ) +(M + P_B X_1 ) X_2$$&lt;&#x2F;p&gt;
&lt;p&gt;Let’s proceed in coordinates. Before anything else, lest begin by displaying all the elements we need to combine so we don’t mess up.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. $P_A = X_0 + X_0 X_1 \in\mathcal{T_2} \iff [P_A ]^2 = \boxed{0,1,0,1}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. $P_B = X_0 X_1 \in\mathcal{T_2} \iff [P_B ]^2 = \boxed{0,0,0,1}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. $P_C = X_1 + X_0 X_1 \in\mathcal{T_2} \iff [P_C ]^2 = \boxed{0,0,1,1}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. $M = P_A + P_B + P_C = X_0 + X_1 + X_0 X_1 \in\mathcal{T_2} \iff [M]^2 = \boxed{0,1,1,1}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. $P_B X_1 = X_0 + X_1 + X_0 X_1 \in\mathcal{T_2} \iff [P_B X_1 ]^2 = \boxed{0,1,1,1}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To do this, we add these elements in $\mathcal{T_2}$ and then embed them in $\mathcal{T_3}$ by simply padding with zeros their last 4 positions to obtain 8 bit strings. This gives&lt;&#x2F;p&gt;
&lt;p&gt;$$[P_A + P_B]^3 = \boxed{0,1,0,0,0,0,0,0}$$&lt;&#x2F;p&gt;
&lt;p&gt;is the first thing we need. Now compute $M + P_B X_1$ in $\mathcal{T}^3$;&lt;&#x2F;p&gt;
&lt;p&gt;$$[M + P_B X_1 ]^2 = \boxed{0,0,0,0}\implies [M + P_B X_1 ]^3 = \boxed{0,0,0,0,0,0,0,0}$$&lt;&#x2F;p&gt;
&lt;p&gt;so trivially&lt;&#x2F;p&gt;
&lt;p&gt;$$[(M + P_B X_1 )X_2 ]^3 = \boxed{0,0,0,0,0,0,0,0}$$&lt;&#x2F;p&gt;
&lt;p&gt;The desired product is then&lt;&#x2F;p&gt;
&lt;p&gt;$$[u\cdot v]^3 = \boxed{0,1,0,0,0,0,0,0} + \boxed{0,0,0,0,0,0,0,0} = \boxed{0,1,0,0,0,,0,0}$$&lt;&#x2F;p&gt;
&lt;p&gt;this is $u\cdot v = X_0$ which can be verified directly by hand.&lt;&#x2F;p&gt;
&lt;p&gt;Obviously, this last example performed in full can quickly turn dull, but it only hightens the convenient recursive nature of multiplication in binary towers and that circuitry-level operations appear as a key element for fast and efficient implementations.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;In this post, we covered the basics of the tower construction powering Binius and some of its interesting properties. In an upcoming article, we raise the bar and aim for a more involved problem: polynomial evaluation in binary towers.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>An introduction to Merkle Patricia Trie</title>
          <pubDate>Mon, 09 Jun 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/an-introduction-to-merkle-patricia-trie/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/an-introduction-to-merkle-patricia-trie/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/an-introduction-to-merkle-patricia-trie/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;Ethereum relies on cryptographic data structures to efficiently store and verify its state. One of these structures is the Merkle Patricia Trie (MPT), which powers Ethereum’s state management. After exploring this tool in more depth, it becomes clear that the MPT is a complex structure—far more intricate than a simple Merkle tree. That’s why we felt it was important to create this post: to make MPTs more accessible and easier to understand. Here we’ll explain what an MPT is, how Ethereum uses it and how its proofs work. In an upcoming post, we will explain how to arithmetize the MPT to be able to generate proofs for showing that we verified that elements are in the tree or that the tree has been updated successfully.&lt;&#x2F;p&gt;
&lt;p&gt;In what follows we only assume that you have a basic knowledge of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;decentralizedthoughts.github.io&#x2F;2020-12-22-what-is-a-merkle-tree&#x2F;&quot;&gt;Merkle Trees&lt;&#x2F;a&gt; and cryptographic hash functions.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;quick-merkle-tree-recap&quot;&gt;Quick Merkle Tree Recap&lt;&#x2F;h2&gt;
&lt;p&gt;A Merkle Tree is a binary tree where:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * _Leaves_ contain hashes of data.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * _Non-leaf nodes_ contain hashes of the concatenation of their child nodes.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The _root hash_ acts as a cryptographic fingerprint of all the leaves data. In other words, it&amp;#39;s a short, fixed-size summary (a hash) that uniquely identifies a large set of data — like a unique signature.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Merkle trees are used for &lt;strong&gt;data integrity proofs&lt;&#x2F;strong&gt; : you can prove efficiently that a piece of data belongs to the tree’s leaves by providing a Merkle path (a sequence of hashes from the leaf to the root).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-a-trie&quot;&gt;What is a trie?&lt;&#x2F;h2&gt;
&lt;p&gt;A Trie (short for retrieval tree, also known as a prefix tree) is a tree-like data structure used to efficiently store and retrieve key-value pairs, especially when the keys are strings or sequences.&lt;&#x2F;p&gt;
&lt;p&gt;Each level of the trie represents a character in the key, and the path from the root to a leaf corresponds to an entire key. Shared prefixes between keys are stored only once, making tries very space-efficient for datasets with common prefixes.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s see a toy example to make it easier to understand. Let’s say we want to store these key-value pairs:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Key&lt;&#x2F;th&gt;&lt;th&gt;Value&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;cat&lt;&#x2F;td&gt;&lt;td&gt;curious&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;cake&lt;&#x2F;td&gt;&lt;td&gt;sweet&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;cup&lt;&#x2F;td&gt;&lt;td&gt;fragile&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;cups&lt;&#x2F;td&gt;&lt;td&gt;plural&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;book&lt;&#x2F;td&gt;&lt;td&gt;heavy&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Our toy trie would look something like this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;HyXnHtvzgl.png&quot; alt=&quot;image&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;To look up the value of the key “cake”:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Start at the root.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Follow the nodes corresponding to the key&amp;#39;s characters: `c -&amp;gt; a -&amp;gt; k -&amp;gt; e`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Retrieve value &amp;quot;sweet&amp;quot; at the last node `e`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;what-is-a-merkle-patricia-trie&quot;&gt;What is a Merkle Patricia Trie?&lt;&#x2F;h2&gt;
&lt;p&gt;Ethereum uses a specialized form of trie called the Modified Merkle Patricia Trie (MPT). The name combines three core ideas:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Trie:** For organizing keys by shared prefixes.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Merkle:** Every node is hashed, forming a Merkle structure that enables cryptographic verification of the entire dataset.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Patricia:** Short for Practical Algorithm to Retrieve Information Coded in Alphanumeric — a variant of a trie that compresses paths where nodes have a single child (also called radix or compact trie).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;how-are-mpts-used-in-ethereum&quot;&gt;How are MPTs used in Ethereum?&lt;&#x2F;h2&gt;
&lt;p&gt;Ethereum uses several MPTs, but we’ll focus on just one of them, the &lt;strong&gt;State Trie&lt;&#x2F;strong&gt; , and use it as an example to explain how they work.&lt;&#x2F;p&gt;
&lt;p&gt;In the State Trie, the state of every account is stored as a key-value pair where:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The **key** is the Keccak-256 hash of the account address.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The **value** is the account, which is the [RLP](https:&#x2F;&#x2F;ethereum.org&#x2F;en&#x2F;developers&#x2F;docs&#x2F;data-structures-and-encoding&#x2F;rlp&#x2F;) encoding of a four item array: `[nonce, balance, storageRoot, codeHash]`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To reach consensus, when a new block appears with a transaction set, every Ethereum node would need to execute all those transactions and verify that the resulting state is the same for all the nodes. However, comparing every account would be computationally very expensive, so instead they use an MPT. The states of all the accounts of Ethereum are stored in a single Merkle trie called &lt;strong&gt;State Trie&lt;&#x2F;strong&gt; that is constantly updated after each transaction execution. To reach consensus, the nodes just compare the &lt;strong&gt;StateRoot&lt;&#x2F;strong&gt; (the root of the State Trie). If two nodes have the same StateRoot, their states match.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;immutability-the-big-mpt-s-advantage&quot;&gt;Immutability: The big MPT’s advantage&lt;&#x2F;h2&gt;
&lt;p&gt;Ethereum needs to be able to revert easily to previous states: when nodes disagree on the next block, a blockchain fork is necessary. This is possible because tries keep the old state around, instead of deleting or modifying it directly. The trie is persistent and versionable, rather than a mutable in-place structure.&lt;&#x2F;p&gt;
&lt;p&gt;When the state changes (e.g., an account balance updates), the trie creates new nodes for the changed paths, while the rest of the trie (the unchanged parts) are reused. Therefore, previous versions of the trie are still accessible via their root. Every block stores a state root in its header and this root uniquely identifies the entire Ethereum state at that point in time. So, if Ethereum needs to rollback, it just uses the state root of a previous block. Since the old nodes were never deleted, the trie can rebuild the old state efficiently. This means Ethereum can restore the old state just by switching back to an earlier root hash.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;mpt-structure&quot;&gt;MPT Structure&lt;&#x2F;h2&gt;
&lt;p&gt;Let’s explain how the State Trie is built. As we said above the keys of this trie consist of the hashes of the addresses, represented as a hexadecimal string. As we showed in the toy example, each node of the trie will store a character of the hex string, that is, a single &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Nibble&quot;&gt;nibble&lt;&#x2F;a&gt; (four bits of data).&lt;&#x2F;p&gt;
&lt;p&gt;There are three types of nodes in an MPT:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. **Branch Node**&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * It stores a 17-item array.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * The first 16 items represent one of each hexadecimal digit the key prefix can be. If the key prefix is the digit $i$, then at index $i$ you&amp;#39;ll find the pointer to the next node that continues the key&amp;#39;s path.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * The last item can allocate a value in the case a key ends there.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * Example:  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;[0x, 0x, child_hash, 0x, 0x, other_child_hash, 0x, 0x, 0x, 0x, 0x, 0x, 0x, 0x, 0x, 0x, value]&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
Here, &lt;code&gt;&quot;0x&quot;&lt;&#x2F;code&gt; represents the unused slots, i.e. digits that don’t have children.
2. &lt;strong&gt;Extension Node&lt;&#x2F;strong&gt;
* It’s the result of an optimization to compresses shared key prefixes.
* It stores a two item array that contains the shared key prefix and a pointer to the next node.
* Example: &lt;code&gt;[shared_prefix, child_hash]&lt;&#x2F;code&gt;
3. &lt;strong&gt;Leaf Node&lt;&#x2F;strong&gt;
* It stores a two item array with the remaining key fragment and its associated value, ending the path.
* Example: &lt;code&gt;[key_remaining, value]&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The three types of nodes store a single array encoded in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;ethereum.org&#x2F;en&#x2F;developers&#x2F;docs&#x2F;data-structures-and-encoding&#x2F;rlp&#x2F;&quot;&gt;RLP&lt;&#x2F;a&gt;. The pointer to a certain node is always the hash of this RLP string data that stores. The root can be of any type, but usually, since we have a lot of data, the root is a branch node.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;node-and-parity-flags&quot;&gt;Node and parity flags&lt;&#x2F;h3&gt;
&lt;p&gt;When traversing a key path nibble by nibble (or character by character), we may end up with a leaf or extension node that has an odd number of nibbles to store. But since all data is stored in bytes, this creates a problem. For instance, if we wanted to store the nibble &lt;code&gt;1&lt;&#x2F;code&gt;, we would have to save it as &lt;code&gt;01&lt;&#x2F;code&gt;, but we wouldn’t be able to tell whether it came from the two nibbles &lt;code&gt;01&lt;&#x2F;code&gt;, or from a single nibble &lt;code&gt;1&lt;&#x2F;code&gt;. To indicate whether we are storing an even or odd number of nibbles — and what type of node we are dealing with (leaf or extension) — the partial path is prefixed with the following flags.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;flag&lt;&#x2F;th&gt;&lt;th&gt;node type&lt;&#x2F;th&gt;&lt;th&gt;path length parity&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;00&lt;&#x2F;td&gt;&lt;td&gt;Extension&lt;&#x2F;td&gt;&lt;td&gt;Even&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;Extension&lt;&#x2F;td&gt;&lt;td&gt;Odd&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;20&lt;&#x2F;td&gt;&lt;td&gt;Leaf&lt;&#x2F;td&gt;&lt;td&gt;Even&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;Leaf&lt;&#x2F;td&gt;&lt;td&gt;Odd&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;example-building-an-mpt-step-by-step&quot;&gt;Example: Building an MPT step by step&lt;&#x2F;h2&gt;
&lt;p&gt;The best way to understand what is an MPT is to see a full example. Let’s simulate a real State Trie. Let’s say we have data for five accounts that translate into the following key-value pairs:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;| Keys | Values&lt;br &#x2F;&gt;
—|—|—&lt;br &#x2F;&gt;
1 | 0x616b6c64 | 0x01&lt;br &#x2F;&gt;
2 | 0x616b6c65 | 0x02&lt;br &#x2F;&gt;
3 | 0x616b6c78 | 0x03&lt;br &#x2F;&gt;
4 | 0x616b6d31 | 0x04&lt;br &#x2F;&gt;
5 | 0x31323334 | 0x05&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;As we mentioned earlier, the keys should be the hashes of the account addresses. Since Ethereum uses Keccak-256, the keys should be 32 bytes long (or 64 hexadecimal characters). However, for this example, we’ll use much shorter keys so that the resulting trie isn’t too large and is easier to understand. Ethereum also uses optimizations, such as inlining small nodes, which we’ll skip in this example for clarity.&lt;&#x2F;p&gt;
&lt;p&gt;Now we are ready to build the MPT:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Start with an empty MPT and add the first key-value pair: `(0x616b6c64, 0x01)`. Since it is just one key, it results in a trie of only one leaf node. To create that node proceed in the following way:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * **Write a two-item array:** The first element should be the whole key and second one the value. Add the prefix flag `20` to the first element indicating that the node is a leaf and that the key has an even amount of nibbles. Then, the array should look like this: `[&amp;quot;0x20616b6c64&amp;quot;,&amp;quot;0x01&amp;quot;]`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * **Encode in RLP the array:** You can use an [RLP converter](https:&#x2F;&#x2F;toolkit.abdk.consulting&#x2F;ethereum#rlp) or this python script:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;import rlp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;key = bytes.fromhex(&amp;quot;20616b6c64&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;value = bytes.fromhex(&amp;quot;01&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;encoded = rlp.encode([key, value])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;print(encoded.hex())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This should output this hex: &lt;code&gt;c78520616b6c6401&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * **Hash the RLP encoding** using Keccak-256 to get the pointer of this node. You can use an [online hasher](https:&#x2F;&#x2F;emn178.github.io&#x2F;online-tools&#x2F;keccak_256.html) or this script:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;from eth_utils import keccak&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;rlp_bytes = bytes.fromhex(&amp;quot;c78520616b6c6401&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;hash_pointer = keccak(rlp_bytes)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;print(hash_pointer.hex())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This should output:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4e2d0fbe6726eac15c5ecf49a4e1f947aa50e0531f4f3e98b8e1577ba52e1783&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The resulting MPT should look like this:&lt;br &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;BJ7XSE1mex.png&quot; alt=&quot;image&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Add the second key-value pair: `(0x616b6c65, 0x02)`. Since this key shares the first 7 digits with the previous one, we proceed in the following way:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * **Build one leaf for each key:** In each leaf, the array&amp;#39;s first element should be the remaining path, but since the two keys share every digit except the last one, the remaining path is empty. So, we should just write there the flag `20` indicating that we are in a leaf node and that the path has an even amount of digits (zero digits). After that, encode the arrays in RLP and hash the RLP encodings, as we did in the step 1.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * **Build a branch node:** Create a 17-item array. Write the hash of the first key&amp;#39;s leaf node at index $4$ and the hash of the second key&amp;#39;s leaf node at index $5$. Encode the array in RLP and hash the encoding.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * **Build the extension and root node:** Create a two item array that contains the shared prefix as first element and the hash of the previous built branch node as second element. Since the shared prefix has an odd number of digits, add the flag `1` to it. Encode the array in RLP and hash the encoding.  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;BJaRZEJQll.png&quot; alt=&quot;image&quot; &#x2F;&gt;
3. Add the key-value pair &lt;code&gt;(0x616b6c78, 0x03)&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * **Add a leaf node:** Notice that in this case, since the new key shares with the previous ones all the digits except the last two, the array&amp;#39;s first item will have just one digit as remaining path and the flag `3` indicating that it is a leaf node with an odd amount of path digits.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * **Add a branch node:** Its array should contain at index $6$ the hash pointer of the branch node built in step 2, and at index $7$ the hash pointer of the new leaf node we recently added.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * **Add an extension node:** The root will be another extension node. Its array should contain the shared prefix as first element and the hash of the recently added branch node as second element. Since the share prefix has an even number of digits, add the flag `00` to it.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The current trie should look lik this:&lt;br &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;HJrfJHJXee.png&quot; alt=&quot;image&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Add the last two key-value pairs continuing in this way, following the same steps as we did for the previous keys. When you&amp;#39;re done, you should have the following MPT:  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;Skc3rByXee.png&quot; alt=&quot;image&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;trie-proof&quot;&gt;Trie Proof&lt;&#x2F;h2&gt;
&lt;p&gt;Let’s now understand what a proof looks like in an MPT. Continuing with the previous example, let’s say we want to prove that the key-value pair &lt;code&gt;(0x616b6d31, 0x04)&lt;&#x2F;code&gt; belongs to our State Trie. How do we build the proof?&lt;&#x2F;p&gt;
&lt;p&gt;The proof will consist of the &lt;strong&gt;StateRoot&lt;&#x2F;strong&gt; &lt;code&gt;0x13ea...bed7&lt;&#x2F;code&gt; (the hash of the root node) along with a path that starts at the root and traverses the trie downward, following every digit of the target key until it reaches its leaf. Let’s go step by step to see how we build this path:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. The first element of the path is the RLP of the root node: `0xf851...8080`.  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If we decode this RLP, we find that the root is a branch node. The array it represents has all empty slots except at indices 3 and 6 (because all the keys start with the digit &lt;code&gt;3&lt;&#x2F;code&gt; or &lt;code&gt;6&lt;&#x2F;code&gt;). This means that the root node branches into two child nodes. Since the first digit of the key we’re looking for is &lt;code&gt;6&lt;&#x2F;code&gt;, we need to look at the hash stored in the array at index 6 and move to that node.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. We move to the next node and store its RLP content as the second element of the path: `0xe583...67e9`.  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This node is an extension node because all keys starting with 6 share the same next four digits: &lt;code&gt;16b6&lt;&#x2F;code&gt;. To determine where to go next, we decode the RLP and get a two-item array. The second item gives us the hash of the next node we need to access.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Again, we move to the next node and store its RLP content as the third element of the path: `0xf851...8080`.  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This node is a branch node. Since our key continues with the digit &lt;code&gt;d&lt;&#x2F;code&gt;, we need to look at the hash stored in this node’s array at index $d$ and move to the node that this hash points to.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Finally, we reach the leaf node: `0xc482203104`. We store the RLP content of this final node, and with that, the proof is complete.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then the proof for the key-value &lt;code&gt;(0x616b6d31, 0x04)&lt;&#x2F;code&gt; should look like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;state_root = 0x13ea549e268b5aa80e9752c6be0770cffba34d2b1aa1f858cb90f3f13ac3bed7&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;proof_path = &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    0xf851808080a0a26b2ac124718443aeed68fa0309225d0c8dd9dbee45685909e92fb594e1a4638080a02ccd118c9470c051689543b233ab109ad74d2fb4f57eb429c4d43294d6ae686780808080808080808080,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    0xe5831616b6a0917fa5cab26d915e2a89a263a578fa5f9ecf02cc0b1d3eeb433e7f32499267e9,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    0xf851808080808080808080808080a0cc97f12ea3217345e666974cd81b117ca02404f19c15d31158ac1d1e55398706a0822a55ca308aa885ad385d5e61aabaca54c2e4361eb03b6f851668c0f095ab77808080,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    0xc482203104&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;verify&quot;&gt;Verify&lt;&#x2F;h2&gt;
&lt;p&gt;If a verifier receives the StateRoot and the proof path for a certain key, how does he verify that the proof is valid?&lt;&#x2F;p&gt;
&lt;p&gt;A key distinction from standard Merkle Trees is the verification direction. While a typical Merkle proof is verified from the bottom up (from the leaf to the root), a Merkle Patricia Tries proof is verified from the top down. The process starts at the &lt;code&gt;StateRoot&lt;&#x2F;code&gt; and traverses the trie downwards, node by node, using the provided path to eventually reach the target leaf.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s say the verifier receives the proof of above for the key-value &lt;code&gt;(0x616b6d31, 0x04)&lt;&#x2F;code&gt;. Then, he has to follow these steps:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. [Hash](https:&#x2F;&#x2F;emn178.github.io&#x2F;online-tools&#x2F;keccak_256.html) the first element of the path and check that it matches the given **StateRoot**. Indeed:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;keccak(bytes.fromhex(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;quot;f851808080a0a26b2ac124718443aeed68fa0309225d0c8dd9dbee45685909e92fb594e1a4638080a02ccd118c9470c051689543b233ab109ad74d2fb4f57eb429c4d43294d6ae686780808080808080808080&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)).hex() ==&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;quot;13ea549e268b5aa80e9752c6be0770cffba34d2b1aa1f858cb90f3f13ac3bed7&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. [Decode](https:&#x2F;&#x2F;toolkit.abdk.consulting&#x2F;ethereum#rlp) the **first RLP element** of the path and verify that in the index $6$ has the hash of the second path element. Indeed:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;rlp.decode(bytes.fromhex(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;quot;f851808080a0a26b2ac124718443aeed68fa0309225d0c8dd9dbee45685909e92fb594e1a4638080a02ccd118c9470c051689543b233ab109ad74d2fb4f57eb429c4d43294d6ae686780808080808080808080&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;))[6].hex() ==&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;quot;2ccd118c9470c051689543b233ab109ad74d2fb4f57eb429c4d43294d6ae6867&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Decode the **path&amp;#39;s second RLP element**. You&amp;#39;ll find a two-item array whose first element is `0x1616b6`. Since its first digit is `1` we know that we are on an extension node. Check that the rest of the digits correspond to the key we are looking for. Verify the array&amp;#39;s second element is the hash of the path&amp;#39;s next element.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Decode the **third path element**. You&amp;#39;ll find a branch node. Verify that at index $d$ it stores the hash of the path&amp;#39;s element.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. Decode the **path&amp;#39;s last element**. You&amp;#39;ll find a two item array whose first element is `0x2031`. Since its firs two digits are `20`, we know that we reach a leaf node. Verify that the first item contains the remaining key&amp;#39;s digits `31` and the second item contains the key&amp;#39;s value `0x04`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;The Merkle Patricia Trie is the backbone of Ethereum’s state management. It combines the key-navigation efficiency of tries, and the cryptographic guarantees of Merkle trees. This structure allows Ethereum to store, verify, and revert state efficiently and securely. With the MPT, Ethereum nodes can independently execute transactions and verify consensus simply by comparing state roots, enabling a scalable and trustless blockchain system. In an upcoming post we will develop how to arithmetize the MPT update and show that we verified inclusion proofs.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Our Succinct explanation of jagged polynomial commitments</title>
          <pubDate>Fri, 06 Jun 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/our-succinct-explanation-of-jagged-polynomial-commitments/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/our-succinct-explanation-of-jagged-polynomial-commitments/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/our-succinct-explanation-of-jagged-polynomial-commitments/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;Few weeks ago, Succinct release their paper &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;succinctlabs&#x2F;hypercube-verifier&#x2F;blob&#x2F;main&#x2F;jagged-polynomial-commitments.pdf&quot;&gt;Jagged Polynomial Commitments&lt;&#x2F;a&gt; and their verifier using the techniques described there, allowing them to prove Ethereum blocks in around 12 seconds, showing that real-time proving of the chain is possible. While this represents &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;x.com&#x2F;VitalikButerin&#x2F;status&#x2F;1925050155922862526&quot;&gt;the average case and energy consumption is still high&lt;&#x2F;a&gt;, it is a major step towards scaling Ethereum using ZK. The paper makes heavy use of multilinear polynomials and the sumcheck protocol, so we recommend you read our post on &lt;a href=&quot;&#x2F;have-you-checked-your-sums&#x2F;&quot;&gt;sumcheck&lt;&#x2F;a&gt;, &lt;a href=&quot;&#x2F;gkr-protocol-a-step-by-step-example&#x2F;&quot;&gt;GKR&lt;&#x2F;a&gt; and &lt;a href=&quot;&#x2F;gkr-protocol-a-step-by-step-example&#x2F;&quot;&gt;Basefold&lt;&#x2F;a&gt; if you are unfamiliar with them. For more background on sparse commitments and its uses, see &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2025&#x2F;105.pdf&quot;&gt;twist and shout&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2023&#x2F;1216.pdf&quot;&gt;Lasso&lt;&#x2F;a&gt;. For more background on read-once branching programs and their use in evaluating multilinear extensions, see &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2018&#x2F;861.pdf&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;jagged-functions&quot;&gt;Jagged functions&lt;&#x2F;h2&gt;
&lt;p&gt;Typical arithmetization schemes consist of several tables (for example, one for the CPU, one for the ALU, another for memory, etc) and a set of algebraic constraints that have to be enforced over the table. Each column of the tables is encoded using univariate or multivariate polynomials and the prover then commits to these encodings (using a polynomial commitment scheme, PCS). In both cases, we require that the length of the columns is a power of 2, since this enables efficient encoding, either via the fast Fourier transform (FFT) or the multilinear Lagrange basis polynomials. This imposes several constraints:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. All columns in a table must have the same length&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. We need to pad the columns to ensure their length is equal to a power of 2.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This results in a lot of overhead, since we need to pad all columns to the same length and store a large number of dummy entries in the tables (for example, zero values). We would like to use some sparse representation of the data, that is, just storing all the non-dummy values. Moreover, we would like to compress everything into a single column to commit to just one encoding. This is precisely one of the main points of the paper, which finds a way to obtain a dense representation of the tables, without all the padding (note that we will need the column to have a length equal to a power of 2, and some padding might be necessary).&lt;&#x2F;p&gt;
&lt;p&gt;We will explain the idea behind the dense representation using one table, but the idea can be extended to several tables, adding one additional variable keeping track of the number of table and the number of columns each table has. Suppose we have a table which has 32 columns ($32 = 2^5$). For each column, we keep the length $l_k$ of each column, consisting of the non-dummy entries. For example, $l_0 = 2^{20}$, $l_1 = 2^{18} + 15$, $l_2 = 2^{16} + 1475$, and so on and so forth. The prover can construct a vector whose entries are the added lengths of the columns, $t$. So, $t_0 = l_0$, $t_1 = l_0 + l_1$, $t_2 = l_0 + l_1 + l_2$. In summary,&lt;br &#x2F;&gt;
$t_0 = l_0$&lt;br &#x2F;&gt;
$t_{k + 1} = t_k + l_{k + 1}$&lt;br &#x2F;&gt;
Note that, since the $l_k$ are all positive, the vector $t$ has non-decreasing entries. We can merge all the columns into a single one, by stacking them one below the other. Given an index $j$ for the vector of stacked columns, we can find where the original element was. First, we look for the smallest $k$, such that $j &amp;lt; t_k$. This $k$ gives the column where the element belongs. Then, we can compute the row by doing $i = j - t_{k - 1}$ (if $k = 0$, then $i = j$). This yields a one-to-one correspondence between the original table and the stacked columns (we will call this, the dense representation form now on). The dense representation has a length equal to $2^m$, where $m = \lceil \log_2 \max{t} \rceil$. Given the procedure to find the row and column, we can define two functions,&lt;br &#x2F;&gt;
$\mathrm{col}(j) = \min_k \{t_k &amp;gt; j \}$&lt;br &#x2F;&gt;
$\mathrm{row}(j) = j - t_{k - 1}$&lt;br &#x2F;&gt;
Using the letter $q$ to denote the multilinear encoding of the dense representation, we see that each entry corresponds to the non-dummy part of the multilinear extension of the whole table, $p$.&lt;br &#x2F;&gt;
$p(\mathrm{row}(j), \mathrm{col}(j)) = q(j)$.&lt;&#x2F;p&gt;
&lt;p&gt;This saves a lot of space to represent the whole table, at the expense of having the prover send the vector $t$. We can then show that if we want to evaluate $p(z_r , z_c)$ this is equivalent to,&lt;br &#x2F;&gt;
$p(z_r , z_c) = \sum p(x , y) \mathrm{eq} (x , z_r) \mathrm{eq} (y , z_c) = \sum q(i) \mathrm{eq}(\mathrm{row}(i) , z_r) \mathrm{eq}(\mathrm{col}(i) , z_c)$&lt;br &#x2F;&gt;
since any zero entry of $p(x,y)$ does not contribute to the sum.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-does-this-work-with-multilinear-polynomials&quot;&gt;Why does this work with multilinear polynomials?&lt;&#x2F;h2&gt;
&lt;p&gt;Multivariate polynomials use the sumcheck protocol to reduce statements to the evaluation of the polynomial at a random point. For example, we can use the sumcheck protocol to show that the multivariate polynomial $g$ evaluates to zero over the hypercube using the zero-check,&lt;br &#x2F;&gt;
$$\sum \mathrm{eq}(r,x) g(x) = 0$$&lt;br &#x2F;&gt;
and, by interacting with the prover, the verifier is left to perform one evaluation at $z$ for $\mathrm{eq} (r,z) g(z)$, plus some simple checks involving univariate polynomials. Using a PCS, the prover can give the verifier access to $g$ and query for the evaluation at $z$ using the evaluation protocol of the PCS.&lt;&#x2F;p&gt;
&lt;p&gt;In the case of univariate polynomials, we show that $g(x)$ has zeros over a domain $D$ by quotienting with the zerofier&#x2F;vanishing polynomial over $D$, $Z_D (x)$. In general, if $D$ has a nice structure (for example, $D$ consists of the n-th roots of unity), the vanishing polynomial can be evaluated very efficiently (in our example, $Z_D (x) = x^n - 1$. In the case of sparse polynomials, the representation of $Z_D (x)$ may be complicated and thus not efficiently computable.&lt;&#x2F;p&gt;
&lt;p&gt;Thus, multilinear polynomials do not require computing quotients and you can work a priori on more general fields (FFTs, on the other hand, need smooth domains where $|F| - 1 = 2^n c$, where $n$ is typically at least $24$).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-to-handle-a-large-number-of-columns&quot;&gt;How to handle a large number of columns&lt;&#x2F;h2&gt;
&lt;p&gt;The paper offers two optimizations to deal with a large number of columns:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Fancy jagged: if all the columns in a table have the same height, we reduce the amount of information we need to pass to compute $t$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Commit to the column heights. The prover can include the column heights (prepending them to the table) in the table and commit to them.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;jagged-pcs&quot;&gt;Jagged PCS&lt;&#x2F;h2&gt;
&lt;p&gt;Another core part of the paper consists in developing a PCS for sparse&#x2F;jagged polynomials. Remember that, from the discussion above,&lt;br &#x2F;&gt;
$p(z_r , z_c) = \sum p(x , y) \mathrm{eq} (x , z_r) \mathrm{eq} (y , z_c) = \sum q(i) \mathrm{eq}(\mathrm{row}(i) , z_r) \mathrm{eq}(\mathrm{col}(i) , z_c)$&lt;br &#x2F;&gt;
We can find the multilinear extension of a function $f_t$ given by&lt;br &#x2F;&gt;
$f_t (x) = \mathrm{eq}(\mathrm{row}(x) , z_r) \mathrm{eq}(\mathrm{col}(x) , z_c)$&lt;br &#x2F;&gt;
Using the sumcheck protocol for products of multilinears, it suffices for the verifier to show that $v = q(\alpha) f_t (\alpha)$, which in turn amounts to $q(\alpha) = \beta_1$ and $f_t (\alpha) = \beta_2$. The key point lies in that $f_t$ can be efficiently evaluated by the verifier. This is proven in claim 3.2.1.&lt;&#x2F;p&gt;
&lt;p&gt;To show that the function can be computed efficiently, the paper introduces a function $g(w,x,y,z)$ which satisfies that $g(w,x,y,z) = 1$ if and only if $x &amp;lt; z$ and $x = w + y$. This function can be directly related to $f_t$ and $g$ can be computed efficiently using a width 4 branching program:&lt;br &#x2F;&gt;
$f_t (z_r , z_c , i) = \sum_y \mathrm{eq} (z_r , y) g(z_c , y , t_{y - 1} , t_y )$&lt;&#x2F;p&gt;
&lt;p&gt;The proof relies on the uniqueness of the multilinear extension, so it suffices to check the equality for $z_r , z_c , i$ as binary strings. If $g(z_r , i , t_{ y - 1} , t_y ) = 1$, then $i &amp;lt; t_y$ and $i = z_r + t_{ y - 1}$. Since $z_r \geq 0$, it follows that $t_{y - 1} \leq i &amp;lt; t_y$ and $z_r = i - t_{y - 1}$. Since we have that $\mathrm{col}_t (i) = z_c$ and $\mathrm{row}_t (i) = z_r$, it follows that $f_t (z_r , z_c , i) = 1$. Similarly, if $f_t (z_r , z_c , i) = 1$, then the variables $w, x, y , z$ automatically satisfy the conditions for $g(w,x,y,z) = 1$.&lt;&#x2F;p&gt;
&lt;p&gt;From the above, we see that we can compute $f_t$ by calculating $2^k$ evaluations of $g$. By claim 3.2.2, a width-4 read-once branching program can compute efficiently $g$, by inspecting each bit of $w, x, y, z$ in a streaming fashion. The conditions $i &amp;lt; t_y$ and $z_r = i - t_{ y - 1}$ for non-vanishing $g$ can be inspected by looking at 4 bits at a time and keeping track of two additional variables.&lt;&#x2F;p&gt;
&lt;p&gt;The paper then discusses how to produce symbolic evaluations using a read-once matrix branching program, which we will need for batch-proving multiple evaluations. The program is defined by a sequence of matrices $M = {M_j^\sigma }$ where $\sigma \in { 0,1 }^b$ and $j = 1, 2, … , n$ and a sink vector $u$. Given an input $x \in {0 , 1 }^n$, the output of the program is the first component of the vector given by $(\prod M_j^{ x_j }) u$, that is $e_1^t (\prod M_j^{ x_j }) u$, where $e_{1j} = \delta_{1j}$ (one if and only if $j = 1$, zero otherwise).&lt;&#x2F;p&gt;
&lt;p&gt;If the matrices are boolean matrices (having as entries either $0$ or $1$), matrix multiplication involves only additions (the paper calls matrices multiplication friendly if computing their product involves a linear number of additions and no multiplications).&lt;&#x2F;p&gt;
&lt;p&gt;When the sink vector $u$ is not given, the evaluation can be done in symbolic form, and, when the vector is finally given, get the final value of the matrix branching program. The idea is that we can get a vector $\mathrm{res}$ such that $\mathrm{res} . u = f_{M,u} (z)$, where $f$ is the multilinear extension of the matrix branching program given by $M$ and $u$. The vector $\mathrm{res}$ is given by&lt;br &#x2F;&gt;
$$\mathrm{res} = e_1^t \prod_j \left( \sum_\sigma \mathrm{eq} (z_j , \sigma) M_j^\sigma \right)$$&lt;&#x2F;p&gt;
&lt;h2 id=&quot;batch-proving-of-multiple-evaluations&quot;&gt;Batch-proving of multiple evaluations&lt;&#x2F;h2&gt;
&lt;p&gt;The problem we face is that the verifier should compute $k$ evaluations, which can be prohibitely costly. However, by interacting with the prover, we can boil everything down to just one evaluation. This follows a standard technique, where the verifier selects random weights $\alpha_0, \alpha_1, … \alpha_{ k - 1}$ and the prover performs a random linear combination. More precisely, suppose that we want to prove that&lt;br &#x2F;&gt;
$h (z_0 ) = v_0$&lt;br &#x2F;&gt;
$h (z_1 ) = v_1$&lt;br &#x2F;&gt;
$\vdots$&lt;br &#x2F;&gt;
$h (z_{ k - 1} ) = v_{ k - 1}$&lt;br &#x2F;&gt;
The prover then does the following linear combination with $\alpha_j$,&lt;br &#x2F;&gt;
$\sum_j \alpha_j h( z_j ) = \sum_j \alpha_j v_j$&lt;br &#x2F;&gt;
The prover wants to convince the verifier that $h( z_j ) = v_j$ holds for every $j$, so $v_j$ is sent to the verifier. The verifier can compute the sum on the right-hand side on his own, $\sum \alpha_j v_j$.&lt;&#x2F;p&gt;
&lt;p&gt;The left-hand side can be calculated efficiently by the prover. First, note that&lt;br &#x2F;&gt;
$h( z_j ) = \sum h (b) \mathrm{eq} (b , z_j) = \sum h_k \mathrm{eq} (b , z_j)$&lt;br &#x2F;&gt;
where $k = \sum_j b_j 2^j$ with $b = b_0 b_1 b_2 … b_{ k - 1}$. In other words, the evaluation $h (z_j)$ can be computed as the inner product between the vector h, such that $h_k = h(b)$, and the vector of Lagrange basis polynomials $\mathrm{eq}(b , z_j)$. Since the inner product is (bi)linear, we can write the linear combination as&lt;br &#x2F;&gt;
$\sum \alpha_j h( z_j ) = \sum h(b) \left(\sum \alpha_j \mathrm{eq} (b , z_j) \right)$&lt;br &#x2F;&gt;
The prover and verifier can run the sumcheck protocol on $\left(h(b) \sum \alpha_j \mathrm{eq} (b , z_j) \right)$ and at the end the verifier has to compute $h(\rho ) \sum \alpha_j \mathrm{eq} (\rho , z_j)$ at the random point $\rho$, which in practice would be an oracle query for $h$ plus computing the linear combination $\sum \alpha_j \mathrm{eq} (\rho , z_j)$. Some optimizations used in the sumcheck protocol are presented in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2024&#x2F;108.pdf&quot;&gt;improvements on zerocheck&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;where-does-all-this-fit-in-and-future-work&quot;&gt;Where does all this fit in and future work&lt;&#x2F;h2&gt;
&lt;p&gt;The jagged approach allows us to commit to the non-zero part of tables and save a lot of work, both in terms of memory requirements as well as commitment times. If we combine this idea with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.binius.xyz&#x2F;basics&#x2F;arithmetization&#x2F;m3&quot;&gt;M3 arithmetization&lt;&#x2F;a&gt;, where we do not need to commit to polynomials that can be computed via certain operations from trace polynomials (virtual polynomials), we see a massive reduction in the amount of work we have to do. This, in turn, could drive proving time, proving cost and memory footprint down, allowing us to prove bigger Ethereum and L2 blocks, effectively scaling it to bring more users and power more usecases.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Supporting Science: LambdaClass Donates to the Argentine Astronomical Association</title>
          <pubDate>Thu, 29 May 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/supporting-science-lambdaclass-donates-to-the-argentine-astronomical-association/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/supporting-science-lambdaclass-donates-to-the-argentine-astronomical-association/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/supporting-science-lambdaclass-donates-to-the-argentine-astronomical-association/">&lt;p&gt;At LambdaClass we believe that advancing science requires collaboration across disciplines and sectors. As part of our commitment to supporting scientific research and education, we recently made a donation to the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.astronomiaargentina.org.ar&#x2F;&quot;&gt;&lt;em&gt;Asociación Argentina de Astronomía&lt;&#x2F;em&gt;&lt;&#x2F;a&gt; (Argentine Astronomical Association), a non-profit organization dedicated to promoting astronomical research and knowledge in Argentina since 1958.&lt;&#x2F;p&gt;
&lt;p&gt;We were honored to receive the following letter of appreciation from the Association:&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;Dear Federico Carrone,&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We would like to express our deepest gratitude, and ask that you extend it to LambdaClass, for the generous annual donation of USD 10,000 to the Argentine Astronomical Association (AAA). This contribution will cover the two most significant annual expenses of our organization, which in some years account for up to 80% of our total budget:&lt;&#x2F;p&gt;
&lt;p&gt;a) The payment of the national membership fee to the International Astronomical Union (IAU) for Argentine astronomers and physicists;&lt;&#x2F;p&gt;
&lt;p&gt;b) The annual contribution as a sponsoring country of the journal &lt;em&gt;Astronomy &amp;amp; Astrophysics&lt;&#x2F;em&gt; (A&amp;amp;A).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;why-does-iau-membership-justify-this-investment&quot;&gt;&lt;strong&gt;Why does IAU membership justify this investment?&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Access to travel grants for General Assemblies, Regional Meetings, and Symposia.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Active participation in the scientific structure of the IAU, with opportunities to hold leadership positions on the Executive Committee and to join Divisions, Commissions, and Working Groups, as well as to propose symposia.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Eligibility for IAU awards, which recognize scientific excellence and community engagement.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Access to development and outreach grants that support socially impactful projects and specialized training events.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. Participation in global scientific resolutions and decision-making processes.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    6. Regular newsletters from Divisions and Commissions, becoming an active member of the largest international community of professional astronomers.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    7. Promotion of astronomy in STEM education at all levels through the IAU Office of Astronomy for Education (IAU-OAE).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;argentina-as-a-sponsoring-country-of-astronomy-astrophysics-a-a&quot;&gt;&lt;strong&gt;Argentina as a sponsoring country of &lt;em&gt;Astronomy &amp;amp; Astrophysics&lt;&#x2F;em&gt; (A&amp;amp;A):&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;em&gt;A &amp;amp;A&lt;&#x2F;em&gt; is consistently ranked among the most prestigious journals in the field of astronomy and astrophysics worldwide. Publishing in it is considered a significant scientific achievement.&lt;&#x2F;p&gt;
&lt;p&gt;Its open-access model ensures that all articles are freely and immediately available globally, increasing both their visibility and citation potential.&lt;&#x2F;p&gt;
&lt;p&gt;Thanks to Argentina’s sponsorship, our astronomy community can publish in &lt;em&gt;A &amp;amp;A&lt;&#x2F;em&gt; without additional costs or delays. Without this benefit, individual researchers would face fees of up to USD 2,000 per article.&lt;&#x2F;p&gt;
&lt;p&gt;Through its annual contribution LambdaClass will enable (primarily but not exclusively) the astronomers and physicists of the Argentine astronomical community to publish their articles at no additional cost in one of the most prestigious international journals of Astronomy and Astrophysics, while maintaining our contribution to the international scientific community.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;We believe in long-term investment in knowledge and curiosity-driven research. Like computer science, astronomy is built on rigorous thinking, open collaboration, and the pursuit of deeper understanding.&lt;&#x2F;p&gt;
&lt;p&gt;This donation is more than a gesture; it’s a recognition of the vital role that institutions such as the Asociación Argentina de Astronomía play in advancing science and education in our country, and a tribute to the people who make that work possible.&lt;&#x2F;p&gt;
&lt;p&gt;Civil and public institutions are only as strong as the societies that support and value them. By strengthening these institutions, we strengthen our collective future.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Celebrating a year of ethrex</title>
          <pubDate>Fri, 16 May 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/celebrating-a-year-of-ethrex/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/celebrating-a-year-of-ethrex/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/celebrating-a-year-of-ethrex/">&lt;p&gt;We have been working at LambdaClass on an Ethereum L1 Execution and L2 client called ethrex since June 2024. Now that it’s maturing and&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ethereum&#x2F;hive&#x2F;pull&#x2F;1286&quot;&gt; &lt;em&gt;recently added to Hive&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;, we think it’s time to talk about it a bit and highlight what sets it apart from others.&lt;&#x2F;p&gt;
&lt;p&gt;Ethrex began as an exploratory project with just three team members and has since grown into a 40-person initiative—now one of LambdaClass’ top priorities. It is the first stack to natively incorporate based rollups since day one. We’re preparing to enter the security audit phase and will move directly into production with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;x.com&#x2F;fede_intern&#x2F;status&#x2F;1846035499799978475&quot;&gt;&lt;em&gt;Rogue&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;, alongside several institutions and clients eager to deploy their own L2 stacks.&lt;&#x2F;p&gt;
&lt;p&gt;Most of the ideas that motivate ethrex share a core tenet: simplicity. We recommend reading Vitalik’s &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;vitalik.eth.limo&#x2F;general&#x2F;2025&#x2F;05&#x2F;03&#x2F;simplel1.html&quot;&gt;&lt;em&gt;recent post&lt;&#x2F;em&gt;&lt;&#x2F;a&gt; about simplifying the L1; it shares many of the same ideas we will talk about in this post and greatly resonates with us as a guiding principle.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-build-yet-another-ethereum-execution-client&quot;&gt;&lt;strong&gt;Why build yet another Ethereum execution client?&lt;&#x2F;strong&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;At this point, the Ethereum ecosystem has good client diversity: Geth, Besu, Erigon, Nethermind and Reth are all production-grade choices, though with varying degrees of popularity. So why write a new client, and why do it in Rust when Reth exists?&lt;&#x2F;p&gt;
&lt;p&gt;The more we got involved in the crypto space and used its tools and codebases, the more we realized that most of them had more complexity than we were comfortable with; sometimes even actively seeking it as part of their development process. Libraries with dozens of modules to modularize even the slightest things, APIs with tons of traits and generics looking to abstract every contingency, macros used to (debatably) save lines of code at the cost of readability, these are all inconveniences we and others have to constantly deal with when integrating with crypto repositories.&lt;&#x2F;p&gt;
&lt;p&gt;Ethrex is our attempt at solving this. It aims to be the infrastructure, libraries and tooling we wish we had when we started. In line with the&lt;a href=&quot;&#x2F;lambdas-engineering-philosophy&#x2F;&quot;&gt; &lt;em&gt;LambdaClass work ethos&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;, our goal is to always keep things simple and minimal. This is reflected in a few different ways.&lt;&#x2F;p&gt;
&lt;p&gt;We track lines of code for the project, ensuring we never go over a limit. The entire repo currently sits at 62k lines. This includes code for our EVM implementation, our L2 stack (along with ZK provers and TEE code), and our ethereum sdk. Most other clients average around 200k on their main repos, not even counting their dependencies, that are usually split into other repos (EVM, sdk, provers). Including those can easily tip it over 300k or more. Our approach heavily leans into vertical integration and minimalism, ensuring we have control over the whole stack while keeping it as simple as possible.&lt;&#x2F;p&gt;
&lt;p&gt;We have daily automated slack messages to be vigilant about lines of code on our project, and regularly look for dead or unnecessary code and refactor opportunities to trim them down.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;lh7-rt.googleusercontent.com&#x2F;docsz&#x2F;AD_4nXdcALtGQVAcNJIEOOLkG6-jxrPB_TceM-wGY_XHqMNqk7mA0-e5ybIXqr0avzaihCNCcjfkKC-Kyved58JHcVGJ0fBgBMs1JBAOpfhUwm-v9V3DTQ0JwQZHRpbayXHK3aF-YodyWQ?key=QZhQagxqvNX4hb2HYsJWkA&quot; alt=&quot;&quot; &#x2F;&gt;Lines of code report&lt;&#x2F;p&gt;
&lt;p&gt;As the image above shows, the ethrex repo consists only of six self-explanatory main crates:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * blockchain&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * common&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * l2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * networking (divided into p2p and rpc)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * storage&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * vm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is very much on purpose; other clients tend to modularize code too much into different packages, hurting readability and simplicity.&lt;&#x2F;p&gt;
&lt;p&gt;Use of traits is kept to a minimum, only when it absolutely makes sense to introduce them. Our codebase contains as few as 12 traits, which we already consider to be too many and are actively looking to reduce them. They are used for the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * RLP encoding and decoding.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Signing of data.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Trie Storage, Regular Storage, and L2 Storage.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * RLPx encoding and RPC handlers.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * EVM hooks.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Use of macros is frowned upon throughout the codebase. There are only four of them in ethrex, three used only for tests and one for Prometheus metrics collection.&lt;&#x2F;p&gt;
&lt;p&gt;Dependencies are also kept in check as much as possible. Rust codebases are notorious for piling up crates, and while we still consider we depend on too many of them, we make periodic efforts to reduce them.&lt;&#x2F;p&gt;
&lt;p&gt;Minimalism is also reflected in our decision not to implement historical features; ethrex only supports post merge forks. We believe Ethereum should have a forward-looking accelerationist attitude to win over its competitors in the blockchain landscape, which means moving fast, embracing change, and remaining lean by not being afraid of quickly dropping support for old features. This also improves ROI on the project because it allows us to both develop and maintain it with a smaller team.&lt;&#x2F;p&gt;
&lt;p&gt;We are very opinionated about how to write Rust code. While we love the language for its mix of high performance, memory safety guarantees and high level language constructs, we believe it is easy to get carried away with its features and overcomplicate codebases; having a rich and expressive type system does not mean one should take every opportunity to reify every problem into it through a trait. This obfuscates code for newcomers and makes it more complex at very little benefit.&lt;&#x2F;p&gt;
&lt;p&gt;For developers, all this has an impact not only on readability and ease of use, but also on compilation times. Complex code architectures with many traits and macros add to compile times, which hurts developer experience. It is not uncommon to see Rust projects take multiple minutes to compile on modern machines, and code complexity plays a big part in that.&lt;&#x2F;p&gt;
&lt;p&gt;However, simplicity and minimalism is not just about making developer experience easier. The fewer the lines of code, the easier it is to maintain the code, to find bugs or vulnerabilities, and to spot possible performance bottlenecks and improvements. It also reduces the attack surface for security vulnerabilities to be there in the first place.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ethrex-l2&quot;&gt;&lt;strong&gt;Ethrex L2&lt;&#x2F;strong&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;From the beginning, ethrex was conceived not just as an Ethereum L1 client, but also as an L2 (ZK Rollup) client. This means anyone can use ethrex to deploy an EVM equivalent, multi-prover (supporting SP1, RISC Zero and TEEs) based rollup with just one command. Financial institutions can also use it to deploy their own L2, with the choice of deploying it as a Validium, a based Rollup or a regular ZK Rollup. In fact, our upcoming permissionless based L2&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;x.com&#x2F;fede_intern&#x2F;status&#x2F;1846035499799978475&quot;&gt; &lt;em&gt;Rogue&lt;&#x2F;em&gt;&lt;&#x2F;a&gt; uses ethrex and anyone will be able to join it by just cloning the repo and running a command.&lt;&#x2F;p&gt;
&lt;p&gt;Key to the development of ethrex L2 is the availability of general purpose ZK virtual machines using hash-based proving systems, such as SP1 and RISC Zero, that allow proving arbitrary code written in Rust.&lt;&#x2F;p&gt;
&lt;p&gt;Being in the crypto space for some years now, we have experienced firsthand the pains of writing arithmetic circuits using libraries like Circom, Bellman, Arkworks or Gnark. Doing so requires in-depth knowledge about the internals of zk-SNARKS, which most engineers do not and should not care about. Additionally, requiring a different API or DSL to write circuits means you end up with two implementations of the same thing: one out of circuit and one in-circuit. This is a huge source of problems, because on every code change there’s the possibility of a divergence between the code being executed and the code being proven, and solving those types of bugs can be challenging and time consuming.&lt;&#x2F;p&gt;
&lt;p&gt;With a RISC-V zkVM, those problems go away; engineers can easily write the code to be proven without having to understand any of the internals, and the chances of a divergence are minimal, because almost all code can be shared between the “out of circuit” and the “in circuit” versions.&lt;&#x2F;p&gt;
&lt;p&gt;ZK-rollups like Scroll and ZKsync tightly coupled their proving system with their VM. While this worked, it meant having a non-EVM architecture and going through a lot of hoops to support EVM equivalence. It also meant having an in-house team of expert cryptographers to design and develop all the complex circuits required to prove their execution. At LambdaClass, we believe that the low level cryptography should be left to projects like Starkware’s Stwo, Lita’s Valida, Polygon’s PetraVM, Succinct’s SP1, or a16z’s Jolt. Our job is to then plug their work into ours, decoupling the cryptography from the rest of the codebase, greatly simplifying the development. This is what allowed us to be the only client designed from the beginning to be an L1, an L2 and a based rollup.&lt;&#x2F;p&gt;
&lt;p&gt;All these benefits can be seen very clearly: the entire l2&#x2F;prover directory where all the related code lives has only 1.3k lines of code, and even that can be reduced further since we haven’t moved some behavior to common functions yet. In other projects we have used and worked with, the ZK-related code was massive, sometimes matching or surpassing the regular non-ZK one.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-s-left&quot;&gt;&lt;strong&gt;What’s left&lt;&#x2F;strong&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;We have made a lot of progress in the past year, from an empty repository to a full-fledged L1 and L2 client, but there is still work to be done to make ethrex production-ready. The main focus right now is on performance. We are currently sitting at around 0.3 gigagas&#x2F;s, and we aim to hit at least 1 gigagas&#x2F;s in the coming weeks, most of it coming from improvements to trie&#x2F;database accesses. Afterwards come security audits and based rollup support. We also have extra features planned on top, including alternative DA support for validiums and custom native token mode, both for ethrex L2.&lt;&#x2F;p&gt;
&lt;p&gt;This year’s Devconnect will take place in our hometown, Buenos Aires. By then, we aim to have a feature-complete version of ethrex running in production, ready to showcase some of its most exciting use cases. As mentioned, a growing number of companies and institutions have expressed interest in ethrex and its potential. Our mission is to help advance Ethereum’s development by building infrastructure and applications that address real-world challenges.&lt;&#x2F;p&gt;
&lt;p&gt;We invite you to follow along our progress as we build in the open and try it out yourself:&lt;&#x2F;p&gt;
&lt;p&gt;Telegram: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;t.me&#x2F;ethrex_client&quot;&gt;&lt;em&gt;https:&#x2F;&#x2F;t.me&#x2F;ethrex_client&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;&lt;br &#x2F;&gt;
Github: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;ethrex&quot;&gt;&lt;em&gt;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;ethrex&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Lambda&#x27;s new strategic partnership with Nous Research: decentralized artificial intelligence</title>
          <pubDate>Tue, 06 May 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/lambdas-new-strategic-partnership-with-nous-research-decentralized-artificial-intelligence/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/lambdas-new-strategic-partnership-with-nous-research-decentralized-artificial-intelligence/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/lambdas-new-strategic-partnership-with-nous-research-decentralized-artificial-intelligence/">&lt;p&gt;We’re pleased to announce our partnership with &lt;strong&gt;Nous Research&lt;&#x2F;strong&gt; to help develop &lt;strong&gt;Psyche&lt;&#x2F;strong&gt; , a decentralized AI training network. The system is designed to allow anyone to contribute to model training using idle compute, making AI development more open, efficient, and verifiable.&lt;&#x2F;p&gt;
&lt;p&gt;This initiative addresses a long-standing problem in AI: the high barrier to entry caused by the cost of training. Psyche is built to enable experimentation, lower infrastructure requirements, and distribute control away from a small number of centralized actors.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-psyche&quot;&gt;What is Psyche?&lt;&#x2F;h2&gt;
&lt;p&gt;Psyche is a Rust-based decentralized training system that uses peer-to-peer networking to coordinate multiple training runs across devices. Instead of relying on centralized data centers, it allows individual users with idle machines—such as gaming PCs—to contribute compute to model training.&lt;&#x2F;p&gt;
&lt;p&gt;All coordination between nodes happens on the &lt;strong&gt;Solana blockchain&lt;&#x2F;strong&gt; , providing a fault-tolerant and censorship-resistant system.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-core-technology-distro&quot;&gt;The Core Technology: DisTrO&lt;&#x2F;h2&gt;
&lt;p&gt;Psyche is made possible by &lt;strong&gt;DisTrO&lt;&#x2F;strong&gt; , a set of training optimizers developed by Nous Research. DisTrO reduces the amount of data exchanged between nodes during training by several orders of magnitude, enabling training over standard broadband connections.&lt;&#x2F;p&gt;
&lt;p&gt;The idea is conceptually similar to image compression (like JPEG): much of the essential information in a model’s gradient can be retained by transmitting only a few low-frequency components. DisTrO goes further by transmitting just the &lt;strong&gt;sign&lt;&#x2F;strong&gt; of each frequency amplitude, quantizing it down to one bit. This results in roughly a 3x further reduction in data transmission.&lt;&#x2F;p&gt;
&lt;p&gt;Additionally, nodes can start training without immediately applying the updates from the previous training step. This means that network latency does not become a bottleneck, improving resource utilization and allowing decentralized training to approach the efficiency of centralized systems.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-p2p-layer&quot;&gt;The P2P Layer&lt;&#x2F;h2&gt;
&lt;p&gt;Networking for Psyche is handled by &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;n0-computer&#x2F;iroh&quot;&gt;&lt;strong&gt;Iroh&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;, a protocol designed for decentralized applications:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Each peer is identified by a 32-byte Ed25519 public key, not an IP address.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Communication is end-to-end encrypted and authenticated.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Nodes behind NAT or firewalls connect using UDP hole-punching in approximately 90% of cases, with relays used as fallback.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Nodes participating in training runs share training metadata using &lt;strong&gt;iroh-gossip&lt;&#x2F;strong&gt; , which builds on the HyParView and PlumTree protocols. Training results are shared using the &lt;strong&gt;iroh-blobs&lt;&#x2F;strong&gt; protocol, which bundles gradient information into binary blobs and references them via content-addressed tickets.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;training-lifecycle&quot;&gt;Training Lifecycle&lt;&#x2F;h2&gt;
&lt;p&gt;Training in Psyche occurs in &lt;strong&gt;epochs&lt;&#x2F;strong&gt; (groups of training steps). Nodes can join or leave the network at the start or end of an epoch, reducing the opportunity cost for contributors.&lt;&#x2F;p&gt;
&lt;p&gt;At the beginning of each epoch, nodes download the current model (either from a HuggingFace repo or from other peers directly) and begin training. Some nodes act as &lt;strong&gt;witnesses&lt;&#x2F;strong&gt; , verifying received results using Bloom filters. If too few nodes remain active or witness quorum is lost, training is paused and checkpointed until new nodes join and resume the process.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;verification&quot;&gt;Verification&lt;&#x2F;h2&gt;
&lt;p&gt;To verify that nodes are training correctly, selected nodes should recompute the training performed by another node and check that the resulting gradient is accurate&lt;&#x2F;p&gt;
&lt;p&gt;Due to the non-deterministic nature of training (from rounding errors, hardware differences, etc.), the system must find a balance between accepting minor differences in output and detecting actual faults or adversarial behavior. Various similarity metrics—such as Jaccard index, Manhattan distance, and Hamming distance—are being explored.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-this-matters&quot;&gt;Why This Matters&lt;&#x2F;h2&gt;
&lt;p&gt;The current landscape of AI is dominated by a small number of entities with access to significant compute resources. This centralization limits who can participate in developing and steering the future of AI.&lt;&#x2F;p&gt;
&lt;p&gt;Our work with Nous Research on Psyche represents a meaningful step toward more open and equitable participation. It allows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Efficient use of idle compute&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Lower-cost training of custom models&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Greater experimentation and model diversity&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * More transparency and less reliance on opaque corporate infrastructures&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We believe AI should be owned by everyone. This partnership is a move in that direction. Lambda will work as hard as possible to build the new networks that make decentralized, open, and verifiable AI development practical, scalable, and accessible to all.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Lambda&#x27;s new strategic partnership with Miden: the Edge blockchain</title>
          <pubDate>Mon, 05 May 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/lambdas-new-strategic-partnership-with-miden-the-edge-blockchain/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/lambdas-new-strategic-partnership-with-miden-the-edge-blockchain/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/lambdas-new-strategic-partnership-with-miden-the-edge-blockchain/">&lt;p&gt;We are very proud to celebrate over 18 months of collaboration between Miden and LambdaClass. The partnership began by helping Miden develop the client, facilitating the execution and proving of transactions for the Miden network. Over time, our collaboration deepened, and we expanded our efforts to support the development of the protocol and node, focusing on various aspects. More recently, we’ve started assisting with the compiler effort, further expanding our involvement in the Miden ecosystem.&lt;&#x2F;p&gt;
&lt;p&gt;Miden is the edge blockchain: a rollup for high-throughput, private applications, powered by the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;0xPolygonMiden&#x2F;miden-vm&quot;&gt;Miden-VM&lt;&#x2F;a&gt;, a STARK-based virtual machine. It has been designed using ZK technology, aiming to achieve two goals simultaneously: private state management and high scalability. These are crucial properties for real-world applications, allowing users to choose the data they want to share and process a large number of transactions. The actor-based model allows for concurrent transactions and ensures that transaction data is not revealed in the blockchain, enabling digital cash and giving users the choice of which information to keep publicly in the ledger. Thus, Miden enables applications to scale efficiently with both public and private transactions, meeting their diverse requirements.&lt;&#x2F;p&gt;
&lt;p&gt;In Miden, accounts hold assets and can define rules for transferring them. The data can be public or private and is kept in a Miden node. Notes are a way to transfer assets and interact with other accounts, and they contain a script that indicates how the note can be consumed. The transfer of notes can be done asynchronously and privately. If the note is private, only its hash is stored on the chain. Asset transfer is done in two steps: first, the sender generates a note and updates its internal state. Secondly, the receiver account executes a new transaction to consume the note and update its internal state. Miden keeps track of the accounts’ state, the created notes, and the nullifiers for consumed notes.&lt;&#x2F;p&gt;
&lt;p&gt;The Miden-VM is a STARK-based virtual machine with its customized instruction set architecture (ISA), using ZK-friendly primitives to make proving efficient. The VM works with the MiniGoldilocks field and its extensions, which have fast arithmetic. With its specialized ISA, programs need to be written in Miden assembly language. The development and use of compilers for general-purpose languages, such as Rust, will enable us to write high-level code and then compile it to Miden assembly to prove it, simplifying the development of provable applications.&lt;&#x2F;p&gt;
&lt;p&gt;Achieving all these features requires a lot of engineering effort and thought, and Miden has made the right choices, focusing on what they want to offer users and clients, all while working fully open-source and sharing their work and insights with others.&lt;&#x2F;p&gt;
&lt;p&gt;Our enthusiasm over Miden stems from the fact that it provides an innovative approach for blockchains: It leverages fast client-side proving for compliant privacy. Its design and architecture, inspired by the actor model, is simple yet elegant and very powerful, facilitating parallel transaction execution and batching for an incredible increase in throughput and scalability with minimal state bloat. With a mature codebase that empowers developers to solve complex problems, it sits right at the core of Lambda’s values.&lt;&#x2F;p&gt;
&lt;p&gt;Looking ahead, we remain committed to advancing Miden’s mission and enabling all the possibilities it unlocks for users and developers alike.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>The Wisdom of Iroh</title>
          <pubDate>Wed, 09 Apr 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/the-wisdom-of-iroh/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/the-wisdom-of-iroh/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/the-wisdom-of-iroh/">&lt;p&gt;As we’ve written before, most of us at Lambda are internet natives. The formative experiences that made us who we are include meeting people on the other side of the world through IRC, sharing knowledge, media, and code via BitTorrent, wikipedia, and software version control systems, the birth of the first search engines, and the feeling that &lt;em&gt;everything&lt;&#x2F;em&gt;  was accessible. We then grew up and found frustration that this experience did not yet extend to the financial tasks needed to be an adult, and that terms like &lt;em&gt;walled garden&lt;&#x2F;em&gt;  better described the new state of our internet home.&lt;&#x2F;p&gt;
&lt;p&gt;This is why we get a double high when learning about projects like Iroh: an emotional tug from a project that enables building distributed systems in a way that gives users more agency, and a nerdy thrill from the technical challenges they’ve solved to achieve it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-it&quot;&gt;What is it?&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.iroh.computer&#x2F;&quot;&gt;Iroh&lt;&#x2F;a&gt; is a distributed systems toolkit, focused on easily setting up reliable p2p connections. It includes facilities for establishing direct connections, moving data, syncing state, and pluggable application-level protocols. It’s working in production and has managed 200k concurrent connections and millions of devices on the same network with low service costs.&lt;&#x2F;p&gt;
&lt;p&gt;In their own words:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Iroh is a library for establishing the most direct QUIC connection possible between two devices. Every &lt;em&gt;endpoint&lt;&#x2F;em&gt;  uses the public half of a cryptographic keypair to identify itself. Assuming at least one configured &lt;em&gt;relay server&lt;&#x2F;em&gt;  is reachable, an endpoint keeps exactly one TCP connection to a “home relay” that other nodes use for connection establishment, and as a fallback transport. Iroh uses a suite of &lt;em&gt;discovery services&lt;&#x2F;em&gt;  to resolve home relays &amp;amp; endpoint IDs. Connections between endpoints use QUIC ALPNs to distinguish between &lt;em&gt;protocols&lt;&#x2F;em&gt; , while &lt;em&gt;routers&lt;&#x2F;em&gt;  automate the endpoint accept loop for protocol multiplexing.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;One of the things we like about Iroh is that it is clear on what it is about. It runs on QUIC, started out as a new implementation of IPFS, went through several iterations, and reduced its scope to better solve the problems they were facing. They wrote about this process in their &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.iroh.computer&#x2F;blog&#x2F;smaller-is-better&quot;&gt;Smaller is Better&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.iroh.computer&#x2F;blog&#x2F;road-to-1-0&quot;&gt;Roadmap&lt;&#x2F;a&gt; posts, and we fully agree that this is good engineering practice.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-can-iroh-be-used-for&quot;&gt;What can Iroh be used for?&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;n0.computer&#x2F;&quot;&gt;&lt;code&gt;n0&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, the company behind Iroh, keeps a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;n0-computer&#x2F;awesome-iroh&quot;&gt;list&lt;&#x2F;a&gt; of projects building on them but to get a quick idea, it can be of use in anything that needs file sync, p2p game streaming, distributed object storage, peer discoverability and swarm membership, local-first design, or compute job orchestration.&lt;&#x2F;p&gt;
&lt;p&gt;One of our partners, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nousresearch&quot;&gt;Nous Research&lt;&#x2F;a&gt; is using it in a decentralized program which relies on iroh to manage communications between nodes training LLMs, sending messages between the clients to advance the state of the network and share the gradients calculated by each node.&lt;&#x2F;p&gt;
&lt;p&gt;Today, we interviewed the team to get some insight.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1-many-of-the-n0-team-members-are-ex-ipfs-or-libp2p-developers-one-of-the-first-questions-asked-is-how-iroh-compares-to-libp2p-and-as-we-understand-it-the-answer-is-related-to-having-a-tighter-focus-keeping-the-core-about-making-p2p-connections-that-just-work-and-moving-the-rest-to-application-level-protocols-such-as-iroh-gossip-blobs-and-docs-that-can-be-mixed-and-matched-as-desired-can-you-elaborate-on-this-process-and-how-reducing-scope-helped&quot;&gt;&lt;em&gt;1. Many of the n0 team members are ex-IPFS or libp2p developers. One of the first questions asked is how Iroh compares to libp2p and as we understand it, the answer is related to having a tighter focus, keeping the core about making p2p connections that just work, and moving the rest to application-level protocols such as iroh-gossip, -blobs and -docs that can be mixed and matched as desired. Can you elaborate on this process and how reducing scope helped?&lt;&#x2F;em&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;b5: The process was one of slowly divesting ourselves of a lot of “p2p project baggage”. Most p2p projects end up defaulting into a boil-the-ocean stance where they try to ship one of everything: a DHT, transports, pubsub, RPC, and over time we’ve come to believe this is a big contributing factor to p2p projects feeling like half-baked prototypes. It clicked for us when our CTO dig pointed out “no one wants the nginx team to ship postgres”. A DHT is a huge undertaking, reliable sync is a huge undertaking, reliable transports are a huge undertaking. Sometime last year we realized it just wouldn’t be possible to ship all this stuff with the team we had, so we picked the transport layer, and are focused on integrating with other projects &amp;amp; the community forming near iroh for the things we can’t ship. Our bet is things will work better if a project like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;loro.dev&quot;&gt;loro&lt;&#x2F;a&gt; ships &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;loro-dev&#x2F;iroh-loro&quot;&gt;optional iroh support&lt;&#x2F;a&gt;, the loro team makes a truly robust CRDT, and we make a truly robust transport. There’s pressure on both teams to make the public APIs small &amp;amp; composable, to make integration easier.&lt;br &#x2F;&gt;
A lot of this is testament to just how incredible a technical feat &lt;code&gt;libp2p&lt;&#x2F;code&gt; is, especially when you see the sheer number of language implementations, it’s truly impressive. But that amount of work comes with a big API surface area, makes it very challenging to port all of that functionality into a robust package that works well on a phone. It also creates the expectation that &lt;code&gt;libp2p&lt;&#x2F;code&gt; maintainers commit to delivering both a robust DHT &lt;em&gt;and&lt;&#x2F;em&gt; a reliable transport. When we more focus we explicitly mean fewer features that both work more consistently &amp;amp; are integrated across organizations.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2-how-did-the-decision-to-use-quic-come-about-a-few-months-ago-some-research-indicated-quic-might-have-some-downsides-and-there-seems-to-be-anecdotal-evidence-of-hostility-to-the-new-protocol-from-network-engineers-does-your-team-have-opinions-wrt-to-any-aspect-of-this-are-there-any-indications-for-iroh-adopters-that-might-stem-from-quic-usage&quot;&gt;2. How did the decision to use QUIC come about? A few months ago some &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;10.1145&#x2F;3589334.3645323&quot;&gt;research&lt;&#x2F;a&gt; indicated QUIC might have some downsides and there seems to be anecdotal evidence of hostility to the new protocol from network engineers. Does your team have opinions wrt to any aspect of this? Are there any indications for Iroh adopters that might stem from QUIC usage?&lt;&#x2F;h3&gt;
&lt;p&gt;b5: the goals of QUIC closely resemble what we’re trying to do with iroh: ship new capabilities on the internet &lt;em&gt;with software&lt;&#x2F;em&gt;  because changing the hardware is impractical. QUIC is trying to tackle protocol ossification that set in because routers can inspect TCP headers, and doing that by dropping down to the UDP layer &amp;amp; working from there. Along with being aligned at “spiritual” level, things like QUIC multipath support seem almost designed for our exact use case. It’s a young technology that we’re all-in on.&lt;&#x2F;p&gt;
&lt;p&gt;I haven’t heard much in the way of hostility from network engineers, but I’m not entirely surprised. QUIC is intentionally trying to reduce the visible surface area to routers &amp;amp; internet middleboxes, which I’m sure would be frustrating. I happen to be of the mind that internet middle boxes shouldn’t be messing with those packets in the first place, but hey, that’s just me 😄&lt;&#x2F;p&gt;
&lt;h3 id=&quot;3-you-ve-mentioned-that-iroh-has-seen-a-million-devices-on-the-same-network-is-this-in-relation-to-the-public-iroh-relays-or-in-another-context-what-are-the-scalability-limits-you-ve-seen-and-in-which-scenarios&quot;&gt;3. You’ve mentioned that Iroh has seen a million devices on the same network. Is this in relation to the public Iroh relays or in another context? What are the scalability limits you’ve seen and in which scenarios?&lt;&#x2F;h3&gt;
&lt;p&gt;The biggest numbers we’ve seen have come from app developers deploying iroh as part of an update to an existing app. Each of those has stressed iroh in different ways. We’ve shipped against those stress tests for the last 6 months. It’s by no means done, but it is giving us in-production feedback that’s critical as we work toward our 1.0 release later this year.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;4-iroh-gossip-is-particularly-interesting-as-a-modern-implementation-of-hyparview-and-plumtree-what-made-you-choose-these-protocols-have-you-done-load-tests-on-this-protocol-in-particular-what-is-your-approach-to-testing-and-load-testing-in-general&quot;&gt;4. Iroh-gossip is particularly interesting as a modern implementation of HyParView and Plumtree. What made you choose these protocols? Have you done load tests on this protocol in particular? What is your approach to testing and load testing in general?&lt;&#x2F;h3&gt;
&lt;p&gt;b5: phones. If we’re going to make p2p work on a mobile devices, “star” topologies that compensate for high network churn with lots of connections simply aren’t viable, which makes the active&#x2F;passive divide in PlumTree particularly appealing. As I’m writing this someone in our discord is running a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;discord.com&#x2F;channels&#x2F;1161119546170687619&#x2F;1161119546644627528&#x2F;1357726363657834788&quot;&gt;2000 node iroh gossip stress test&lt;&#x2F;a&gt; using an erlang supervisor, so yes, it’s being tested! We also have a battery of smoke &amp;amp; simulation tests that run against the iroh gossip protocol as part of CI.&lt;br &#x2F;&gt;
Gossip has been getting more attention lately, which is driving us to put more time into it. Frando from our team has been actively working on stability as we speak.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;5-you-encourage-users-to-set-up-their-own-relays-for-their-networks-but-are-also-very-generous-with-the-three-public-ones-you-offer-aside-from-avoiding-the-rate-limits-why-use-private-relays-are-there-any-security-or-other-feature-considerations&quot;&gt;5. You encourage users to set up their own relays for their networks but are also very generous with the three public ones you offer. Aside from avoiding the rate limits, why use private relays? Are there any security or other feature considerations?&lt;&#x2F;h3&gt;
&lt;p&gt;b5: It’s totally fine to use the public relays! Honestly, we’d love to see more use so we can stress them more :). As a gentle reminder for everyone: relay traffic is e2ee, so the relays can’t see traffic, but relays &lt;em&gt;do&lt;&#x2F;em&gt; have a list of nodeIDs, and list of connections they’re facilitating, which is privileged information. Many of our more serious users are using private relays to avoid exposing that information to the public, or even to number 0, which is things working as intended in our view. We have some plans in the works for a complimentary service that will make spinning up relays very easy. Stay tuned for that!&lt;&#x2F;p&gt;
&lt;h3 id=&quot;6-when-developing-distributed-systems-observability-becomes-a-prime-concern-iroh-doctor-seems-like-a-cool-tool-to-have-does-iroh-offer-other-facilities-for-observing-and-debugging-its-internals-or-the-application-what-role-does-iroh-metrics-play-in-this&quot;&gt;6. When developing distributed systems, observability becomes a prime concern. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.iroh.computer&#x2F;blog&#x2F;iroh-0-16-a-better-client#iroh-doctor-plot&quot;&gt;Iroh-doctor&lt;&#x2F;a&gt; seems like a cool tool to have. Does Iroh offer other facilities for observing and debugging its internals or the application? What role does Iroh-metrics play in this?&lt;&#x2F;h3&gt;
&lt;p&gt;b5: We’re actively working on this. Gathering actionable network metrics in a p2p system is critical as we make p2p a mature, reliable thing. We’ll have way more to say on this one in the coming months.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;7-p2p-systems-usually-disclose-the-ip-addresses-of-the-participating-nodes-and-iroh-explicitly-chooss-to-give-applications-flexibility-in-what-if-anything-to-do-in-this-regard-what-choices-do-you-see-are-usually-taken-and-what-mechanisms-aside-from-vpns-can-applications-implement&quot;&gt;7. P2P systems usually disclose the IP addresses of the participating nodes and Iroh explicitly chooss to give applications flexibility in what (if anything) to do in this regard. What choices do you see are usually taken, and what mechanisms (aside from VPNs) can applications implement?&lt;&#x2F;h3&gt;
&lt;p&gt;b5: I should clarify that any connection within iroh will &lt;em&gt;always&lt;&#x2F;em&gt; end up exposing your IP address to the peer that you’re dialing, and the relay server your node uses as it’s home. This is also true of &lt;em&gt;so&lt;&#x2F;em&gt; many services you use every day, so iroh isn’t new in this regard. With that said, yeah a VPN is rarely a bad idea, and we expicitly run one-off tests between n0 staff where we start a big file transfer &amp;amp; switch VPN on &amp;amp; off during transfer to confirm it works (spoiler: it does).&lt;br &#x2F;&gt;
The implications of connecting users will be different for each application, but we generally ask folks to use their heads: if your app is 5-100 person invite-only chat rooms, then it makes sense to couple iroh connections with room memberships. If your app is, say, twitter, then you might need to introduce a new opt-in mechanism that makes it clear to the user that you’re disclosing something that might be abused.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;8-the-local-first-software-movement-prioritizing-user-data-being-stored-and-processed-on-their-own-devices-rather-than-relying-on-cloud-servers-is-new-and-slowly-gaining-traction-do-you-see-iroh-being-used-in-this-context-or-are-most-of-the-main-users-focused-on-other-use-cases&quot;&gt;8. The local-first software movement (prioritizing user data being stored and processed on their own devices rather than relying on cloud servers) is new and slowly gaining traction. Do you see Iroh being used in this context or are most of the main users focused on other use cases?&lt;&#x2F;h3&gt;
&lt;p&gt;b5: YES. we &amp;lt;3 local first in a big way, and think p2p is the only way to get to software that is both local first and networked. The thing user agency, p2p, and local first all have in common is shipping more capabilities to the end-user’s device than we traditionally get with today’s “view layer on an API” apps.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;9-coupling-iroh-with-a-crdt-such-as-automerge-seems-to-be-a-common-pattern-iroh-docs-seems-geared-to-be-a-distributed-kv-store-but-is-based-on-range-based-set-reconciliation-do-you-see-these-higher-level-usage-patterns-being-codified-as-other-protocols-are-there-other-protocols-in-development-or-do-you-see-any-particular-pattern-as-a-likely-future-protocol&quot;&gt;9. Coupling Iroh with a CRDT such as &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;automerge.org&#x2F;&quot;&gt;automerge&lt;&#x2F;a&gt; seems to be a common pattern. Iroh-docs seems geared to be a distributed KV store but is based on range-based set reconciliation. Do you see these higher-level usage patterns being codified as other protocols? Are there other protocols in development, or do you see any particular pattern as a likely future protocol?&lt;&#x2F;h3&gt;
&lt;p&gt;b5: yes, iroh + automerge is definitely “using iroh as intended”, and you get at a good point: there are common patterns like message bootstrapping, incremental updates, and pairwise reconciliation that are commmon across a bunch of these protocols. To be able to actually have those protocols share abstractions for these patterns we’d need a more robust story for protcol composition than we currently have, because we’d need a way for a protocol to express dependencies &amp;amp; do protocol version matching across the set of registered protocols at compilation time. Even then, it would require the buy-in from projects like automerge, which really isn’t a goal of ours right now.&lt;br &#x2F;&gt;
I think it’s going to take years, but I do think we’ll get to a place where we declare a dependency graph of protocols, the compiler will be able to tell you if you have a version mismatch, and we’ll be able to further decompose these patterns as a community. I’m doing some experiments in this direction on the side, but don’t expect to see anything in this department before we cut iroh 1.0.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;10-you-ve-written-about-the-challenges-of-using-async-rust-and-we-can-certainly-relate-in-our-experience-greenspun-s-tenth-rule-applies-transmuted-to-distributed-systems-sometimes-called-virding-s-rule-any-sufficiently-complicated-concurrent-program-in-another-language-contains-an-ad-hoc-informally-specified-bug-ridden-slow-implementation-of-half-of-erlang-what-is-your-experience-with-the-actor-and-message-passing-approach-both-in-rust-when-implementing-iroh-and-more-generally-when-using-iroh-to-build-systems-that-communicate&quot;&gt;10. You’ve &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.iroh.computer&#x2F;blog&#x2F;async-rust-challenges-in-iroh&quot;&gt;written&lt;&#x2F;a&gt; about the challenges of using async rust and we can certainly relate! In our experience Greenspun’s tenth rule applies transmuted to distributed systems (sometimes called Virding’s rule) “Any sufficiently complicated concurrent program in another language contains an ad hoc informally-specified bug-ridden slow implementation of half of Erlang.” What is your experience with the actor and message passing approach, both in Rust when implementing Iroh and more generally when using Iroh to build systems that communicate?&lt;&#x2F;h3&gt;
&lt;p&gt;b5: lol yes very much to the half-Erlang. We’re very much in that uncanny valley right now with iroh. Most of the internal guts are implemented with actors, but we haven’t formalized that into an actor abstraction, and it’s unclear that we ever will. Where that pain is felt more accutely is at the protocol level. At the level of protocol developement, it would be very nice to have easy-to-implement patterns that abstract around distibuted fault tolerance &amp;amp; give you that “fail whenever you want” characteristic the supervisor trees bring. The protocol dev is also at the right height in the stack, dealing with logical messages instead of raw packets.&lt;br &#x2F;&gt;
We’re still working on the groundwork of getting tutorials in place for writing a protocol in the first place, but I’d love to see us spend more time cooking up recipes for protcol development atop an actor model abstraction.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;&quot;&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;11. Your &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.iroh.computer&#x2F;roadmap&quot;&gt;roadmap&lt;&#x2F;a&gt; is quite clear, webassembly support being oft-requested and recently merged, and better support on the way for clients wanting to use Iroh in browsers without having to send all data over relays. Some notable items in the more distant roadmap are a spec and FFI integrations. Can you elaborate on their importance and&#x2F;or motivation? Do you have an estimate on when 1.0 is due and any comments on what motivates the upcoming features? What are you most excited about?&lt;&#x2F;p&gt;
&lt;p&gt;b5: The spec part is fun because iroh can be pretty easily expressed as a composition of existing specs, which is our plan. In our view 1.0 means you know clearly what the thing is, and how it &lt;em&gt;should&lt;&#x2F;em&gt; behave, so why not write that down in a spec? That said, we’re far more concerned with working software than a spec, and see taking the time to write out a spec as a means of confirming we’ve considered everything we need to as part of a 1.0 push, and can communicate that consideration clearly. As for FFI bindings, we &lt;em&gt;really&lt;&#x2F;em&gt; , &lt;em&gt;really&lt;&#x2F;em&gt; want to get to languages outside of rust, but have a lot of work to do here. More on FFI in the July-August time range. Current plan for 1.0 is sometime in September.&lt;br &#x2F;&gt;
As for excitement, Divma &amp;amp; Floris on our team have been hard at work on support for QUIC multipath for &lt;em&gt;months&lt;&#x2F;em&gt;. It’s a huge undertaking, and we’re all very excited to see it come together.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;12-are-there-any-bindings-or-plans-for-bindings-to-other-languages-iroh-ffi-seems-to-provide-support-for-python-what-is-it-s-status-and-do-you-plan-to-offer-official-support-for-any-other-languages&quot;&gt;12. Are there any bindings or plans for bindings to other languages? Iroh-ffi seems to provide support for Python, what is it’s status and do you plan to offer official support for any other languages?&lt;&#x2F;h3&gt;
&lt;p&gt;b5: Yes, we have plans, but need to figure out some hard stuff around what basically amounts to duck-typing in UniFFI bindings first :)&lt;&#x2F;p&gt;
&lt;p&gt;Many thanks to the Iroh team for taking the time to answer our questions!&lt;&#x2F;p&gt;
&lt;p&gt;References&lt;br &#x2F;&gt;
• &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.iroh.computer&#x2F;proto&#x2F;iroh-gossip&quot;&gt;https:&#x2F;&#x2F;www.iroh.computer&#x2F;proto&#x2F;iroh-gossip&lt;&#x2F;a&gt;&lt;br &#x2F;&gt;
• &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.bartoszsypytkowski.com&#x2F;hyparview&quot;&gt;https:&#x2F;&#x2F;www.bartoszsypytkowski.com&#x2F;hyparview&lt;&#x2F;a&gt;&lt;br &#x2F;&gt;
• &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;asc.di.fct.unl.pt&#x2F;~jleitao&#x2F;pdf&#x2F;dsn07-leitao.pdf&quot;&gt;https:&#x2F;&#x2F;asc.di.fct.unl.pt&#x2F;~jleitao&#x2F;pdf&#x2F;dsn07-leitao.pdf&lt;&#x2F;a&gt;&lt;br &#x2F;&gt;
• &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.bartoszsypytkowski.com&#x2F;plumtree&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.bartoszsypytkowski.com&#x2F;plumtree&#x2F;&lt;&#x2F;a&gt;&lt;br &#x2F;&gt;
• &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;asc.di.fct.unl.pt&#x2F;~jleitao&#x2F;pdf&#x2F;srds07-leitao.pdf&quot;&gt;https:&#x2F;&#x2F;asc.di.fct.unl.pt&#x2F;~jleitao&#x2F;pdf&#x2F;srds07-leitao.pdf&lt;&#x2F;a&gt;&lt;br &#x2F;&gt;
• &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.iroh.computer&#x2F;proto&#x2F;iroh-docs&quot;&gt;https:&#x2F;&#x2F;www.iroh.computer&#x2F;proto&#x2F;iroh-docs&lt;&#x2F;a&gt;&lt;br &#x2F;&gt;
• &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.iroh.computer&#x2F;proto&#x2F;iroh-blobs&quot;&gt;https:&#x2F;&#x2F;www.iroh.computer&#x2F;proto&#x2F;iroh-blobs&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ssl.gstatic.com&#x2F;ui&#x2F;v1&#x2F;icons&#x2F;mail&#x2F;images&#x2F;cleardot.gif&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>GKR protocol: a step-by-step example</title>
          <pubDate>Wed, 05 Mar 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/gkr-protocol-a-step-by-step-example/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/gkr-protocol-a-step-by-step-example/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/gkr-protocol-a-step-by-step-example/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;An interactive proof is a protocol between two parties, a prover $\mathcal{P}$ and a verifier $\mathcal{V}$, where the prover attempts to convince the verifier of the validity of a statement. By leveraging randomness and interaction, the verifier can check the statement more efficiently than by doing everything himself. There is always a trivial way in which we can verify a computation: re-execution. This is how blockchains achieve verifiability: each node re-executes transactions and then reaches consensus. However, this is inefficient since every node must repeat the same computations, leading to bottlenecks. Succinct proofs allow us to check computations much faster, avoiding re-execution and solving blockchain scalability issues. For an introduction to interactive proof systems, see &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;people.cs.georgetown.edu&#x2F;jthaler&#x2F;ProofsArgsAndZK.pdf&quot;&gt;Thaler&lt;&#x2F;a&gt;. One such protocol is the sum-check protocol, proposed by Lund, Fortnow, Karloff, and Nisan in 1992, which is one of the building blocks used by several proof systems.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.microsoft.com&#x2F;en-us&#x2F;research&#x2F;wp-content&#x2F;uploads&#x2F;2016&#x2F;12&#x2F;2008-DelegatingComputation.pdf&quot;&gt;GKR protocol&lt;&#x2F;a&gt; (Goldwasser–Kalai–Rothblum) extends the idea of the &lt;a href=&quot;&#x2F;have-you-checked-your-sums&#x2F;&quot;&gt;sum-check protocol&lt;&#x2F;a&gt; for efficient verification of arithmetic circuits. The protocol allows a verifier to check that a computation—expressed as a logarithmic‐depth circuit with low-degree gates—has been executed correctly. This is achieved with only $O(\log⁡(n))$ rounds of interaction and a total of $O(\text{poly} \log(n))$ operations.&lt;&#x2F;p&gt;
&lt;p&gt;The key idea of the GKR protocol is that instead of evaluating the entire circuit, it uses the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;people.cs.georgetown.edu&#x2F;jthaler&#x2F;sumcheck.pdf&quot;&gt;sum-check&lt;&#x2F;a&gt; protocol recursively to verify the partial sums that represent the computed value efficiently. This method enables a resource-limited verifier to check computations far larger than what they could perform on their own by leveraging the underlying algebraic structure of the problem. The advantage of the GKR protocol is that one avoids having to commit to intermediate results in the circuit, which is usually the expensive part of many proof systems.&lt;&#x2F;p&gt;
&lt;p&gt;This post will explain how the protocol works with an example. For additional explanations on the protocol, we recommend watching doubly efficient interactive proofs &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=db1xAyO4YgM&amp;amp;list=PLUl4u3cNGP61EZllk7zwgvPbI4kbnKhWz&amp;amp;index=3&quot;&gt;part 1&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=Ob1fFHAXlJQ&amp;amp;list=PLUl4u3cNGP61EZllk7zwgvPbI4kbnKhWz&amp;amp;index=4&quot;&gt;part 2&lt;&#x2F;a&gt; or reading &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;people.cs.georgetown.edu&#x2F;jthaler&#x2F;ProofsArgsAndZK.pdf&quot;&gt;Thaler’s book&lt;&#x2F;a&gt; or this &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;65610.csail.mit.edu&#x2F;2024&#x2F;lec&#x2F;l12-gkr.pdf&quot;&gt;short note&lt;&#x2F;a&gt;. The GKR protocol is used to improve the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2023&#x2F;1284&quot;&gt;LogUp lookup argument&lt;&#x2F;a&gt;. You can take a look at the implementation in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stwo&#x2F;tree&#x2F;dev&#x2F;crates&#x2F;prover&#x2F;src&#x2F;core&#x2F;lookups&quot;&gt;Stwo&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;protocol&quot;&gt;Protocol&lt;&#x2F;h2&gt;
&lt;p&gt;The goal of this post is to explain the protocol in detail. To do so, we will use a simple example and follow, step by step, everything that both the prover($\mathcal{P}$) and the verifier ($\mathcal{V}$) do.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Note: We will consider the interactive version of the protocol. &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;You can turn it into a non-interactive protocol with the Fiat-Shamir&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;transformation. &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let’s begin by describing the computation we wish to prove. We must express the computation as a log-space uniform arithmetic circuit $\mathcal{C}$ of fan-in 2 over a finite field $\mathbb{F}_p$. This means that:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The circuit has only two types of gates: addition and multiplication.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * It is layered so that each gate is connected to only two gates in the previous layer (possibly the same gate).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * In each layer $i$, the number of gates is $S_i = 2^{k_i}$ where $k_i \in \mathbb{N}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * All values are elements of $\mathbb{F_{p}}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Let’s build a circuit that meets these conditions:&lt;br &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;ByBJecQFkl.png&quot; alt=&quot;circuit_gkr&quot; &#x2F;&gt;&lt;br &#x2F;&gt;
Figure 1: Diagram of the arithmetic circuit used in the GKR protocol example.&lt;&#x2F;p&gt;
&lt;p&gt;This circuit models a program that has 2 inputs and two outputs, and we work over the field $\mathbb{F_{23}}$.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h4 id=&quot;the-final-goal-of-the-protocol-is-for-the-prover-to-provide-the-outputs-of-the-program-to-the-verifier-and-convince-the-verifier-that-these-outputs-were-computed-correctly-from-the-public-inputs&quot;&gt;&lt;strong&gt;The final goal of the protocol is for the prover to provide the outputs of the program to the verifier and convince the verifier that these outputs were computed correctly from the public inputs.&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Recall that both the circuit and the inputs are public.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;part-one-sharing-the-results&quot;&gt;Part One: Sharing the Results&lt;&#x2F;h2&gt;
&lt;p&gt;We can divide this into several steps:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Output Claim:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The prover $\mathcal{P}$ sends the verifier $\mathcal{V}$ the values claimed to be the circuit outputs. &lt;em&gt;These values are sent in the form of a function&lt;&#x2F;em&gt; $D: {0,1}^{ k_0 } \to \mathbb{F_{p}}$.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;For our example: $k_0 = 1$, so $\mathcal{P}$ sends the linear polynomial $D$ satisfying:&lt;&#x2F;p&gt;
&lt;p&gt;$$D(0) = 18$$ $$D(1) = 7$$&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Random Challenge:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;A key resource we’ll use frequently in the protocol is having the verifier select a random point and send it to the prover. The prover must then incorporate this point into their calculations. This prevents the prover from precomputing results and trying to deceive the verifier.&lt;&#x2F;p&gt;
&lt;p&gt;$\mathcal{V}$ picks a random $r_0 \in \mathbb{F}^{ k_0 }$ and send it to $\mathcal{P}$.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Let’s pick $r_0 = 2$&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Computing the Multilinear Extension:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Both $\mathcal{V}$ and $\mathcal{P}$ compute $\tilde D(r_0)$, where $\tilde D({x})$ is the multilinear extension of $D$. This is the unique multilinear polynomial over $\mathbb{F_{p}}$ satisfying:&lt;br &#x2F;&gt;
$$\tilde D(x) = f(x) \ \forall x \in {0, 1}^v$$&lt;&#x2F;p&gt;
&lt;p&gt;This is a $v-$variate polynomial over $\mathbb{F_{p}}$ where $\tilde D({x})$ agrees with $D({x})$ at all boolean-valued (or bitstrings of a given length) inputs. It acts as a distance-amplifying encoding of $D({x})$ because, if another function $D’({x})$ disagrees at even a single input, the extension $\tilde D({x})$ will differ with $\tilde D’({x})$ at almost every point outside the original domain. This is a consequence of the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Schwartz%E2%80%93Zippel_lemma&quot;&gt;Schwartz-Zippel lemma&lt;&#x2F;a&gt;, which states that the probability of choosing a zero of a polynomial at random is $v &#x2F; \lvert \mathbb{F_p} \rvert$ (which is negligible for a sufficiently large field).&lt;&#x2F;p&gt;
&lt;p&gt;Using Lagrange interpolation, we have:&lt;br &#x2F;&gt;
$$\tilde f (x_1, \ldots, x_v) = \sum_{w \in {0, 1}^v} f(w) \cdot \chi_w(x_1, \ldots, x_v)$$&lt;&#x2F;p&gt;
&lt;p&gt;where $\chi_w$ are the (multilinear) Lagrange basis polynomials: $$\chi_w(x_1, \ldots, x_v) = \prod_{i = 1}^{v} (x_i \cdot w_i + (1-x_i)(1-w_i))$$&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;In our case (with $k_0=1$):&lt;&#x2F;p&gt;
&lt;p&gt;$$\begin{align} \tilde D(x) &amp;amp;= D(0) : (x \cdot 0 + (1-x)(1-0)) + D(1) : (x \cdot 1 (1 - x)(1 - 1)) \newline&lt;br &#x2F;&gt;
&amp;amp;= D(0)\cdot(1-x) + D(1) \cdot x= 18(1-x)+7x\end{align}$$&lt;&#x2F;p&gt;
&lt;p&gt;Thus:&lt;&#x2F;p&gt;
&lt;p&gt;$$\tilde D(r_0) = \tilde D(2) = -4 \equiv 19 \text{ mod } (23)$$&lt;&#x2F;p&gt;
&lt;p&gt;We denote this value by:&lt;&#x2F;p&gt;
&lt;p&gt;$$\tilde D(r_0) = 19 = m_0.$$&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Now, we can see that verifying the program’s outputs comes down to checking that:&lt;br &#x2F;&gt;
$$m_0 = \tilde W_0(r_0)$$&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Before continuing, let’s introduce an additional notation. For each layer $i$ of the circuit, we will denote&lt;&#x2F;p&gt;
&lt;p&gt;$$W_i: \{0,1\}^{ k_i } \to \mathbb{F_{p}}$$&lt;&#x2F;p&gt;
&lt;p&gt;to be the function that maps a node’s position to its actual value, let $\tilde W_i(x)$ be its multilinear extension.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;B1M6_kEtkx.png&quot; alt=&quot;Screenshot 2025-02-07 at 5.09.49 PM&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;With this notation, the verifier’s task can be seen as checking that&lt;&#x2F;p&gt;
&lt;p&gt;$$D(x) = W_0(x)$$&lt;&#x2F;p&gt;
&lt;p&gt;since $D(x)$ represents the claimed outputs and $W_0(x)$ represents the correct values. Because multilinear extensions are unique, this is equivalent to verifying that:&lt;&#x2F;p&gt;
&lt;p&gt;$$\tilde D(x) = \tilde W_0(x)$$&lt;&#x2F;p&gt;
&lt;p&gt;Finally, by the Schwartz-Zippel lemma, it suffices to check that&lt;&#x2F;p&gt;
&lt;p&gt;$$\tilde D(r_0) = \tilde W_0(r_0)$$&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;But wait! The verifier cannot directly access $W(x)$. That is precisely the point of the protocol!&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;part-two-modeling-the-circuit&quot;&gt;Part Two: Modeling the circuit&lt;&#x2F;h2&gt;
&lt;p&gt;In this phase, the goal is to verify that the sum of many terms (corresponding to a node’s computed value) equals $m_0$.&lt;&#x2F;p&gt;
&lt;p&gt;To do this efficiently, we use the sum-check protocol.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;introducing-the-wiring-functions&quot;&gt;Introducing the Wiring Functions&lt;&#x2F;h4&gt;
&lt;p&gt;We define two functions that capture the circuit’s wiring:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Addition Function**.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This function marks all the addition nodes in layer $i$. It takes as input:&lt;&#x2F;p&gt;
&lt;p&gt;$$x \in \{0,1\}^{k_i + 2k_{i + 1}}$$&lt;&#x2F;p&gt;
&lt;p&gt;which encodes the position $a$ of an addition node in the current layer, along with the positions $b$ and $c$ of the two nodes in the next layer to which it is connected.&lt;&#x2F;p&gt;
&lt;p&gt;The function $\text{Add}_i$ is defined to be 1 when $x = (a,b,c)$ corresponds to a valid addition node with the proper inputs and zero otherwise.&lt;&#x2F;p&gt;
&lt;p&gt;Just like with $\tilde D(x)$, we will need to create the multilinear extension: $\widetilde{\text{Add}}_i(x)$.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;In our circuit:&lt;br &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;SyIm5y4F1x.png&quot; alt=&quot;Screenshot 2025-02-07 at 5.15.38 PM&quot; &#x2F;&gt;&lt;br &#x2F;&gt;
The output addition node is at position: $$a = (1)$$&lt;br &#x2F;&gt;
And is connected to nodes: $$b: (1,0) \ \ c: (1,1)$$&lt;br &#x2F;&gt;
Since this is the only addition node, we define the function:&lt;br &#x2F;&gt;
$$\text{Add_1}(x) \begin{cases}&lt;br &#x2F;&gt;
1 &amp;amp; \text{if } x = (1,1,0,1,1)\newline&lt;br &#x2F;&gt;
0 &amp;amp; \text{if not}.&lt;br &#x2F;&gt;
\end{cases}$$&lt;br &#x2F;&gt;
We then extend this function to a multilinear polynomial, denoted $\widetilde{\text{Add}}_i(x)$:&lt;&#x2F;p&gt;
&lt;p&gt;$$\widetilde{\text{Add}}_1 (x_1, x_2, x_3, x_4, x_5) = x_1 \cdot x_2 \cdot (1 - x_3) \cdot x_4 \cdot x_5 $$&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Multiplication Function**.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Similarly, we define the function $\text{Mult}_0(x)$ for the multiplication nodes and its multilinear extension.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;For the Multiplication node in our first layer:&lt;br &#x2F;&gt;
$$\text{Mult_1}(x) \begin{cases}&lt;br &#x2F;&gt;
1 &amp;amp; \text{if } x = (0,0,0,0,1)\newline&lt;br &#x2F;&gt;
0 &amp;amp; \text{if not}.&lt;br &#x2F;&gt;
\end{cases}$$&lt;br &#x2F;&gt;
Its multilinear extension is given by&lt;br &#x2F;&gt;
$$\widetilde{\text{Mult_1}}(x_1, x_2, x_3, x_4, x_5) = (1 - x_1) \cdot (1-x_2) \cdot (1 - x_3) \cdot (1 - x_4) \cdot x_5 $$&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Finally, we need to connect these two new functions. For that, we can define a function that “computes” the value of a node in layer $i$ given the values in the next layer:&lt;&#x2F;p&gt;
&lt;p&gt;$$\tilde f^{(i)}(a,b,c) := \widetilde{\text{Add_i}}(a,b,c)\cdot(\tilde W_{i + 1}(b) + \tilde W_{i + 1}(c)) + \widetilde{\text{Mult_i}} \cdot \tilde W_{i + 1}(b) \cdot \tilde W_{i + 1}(c)$$&lt;&#x2F;p&gt;
&lt;p&gt;When this function is evaluated on the values $(a,b,c)$ corresponding to a node in layer $i$, it yields the value of that node.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;In our first layer:&lt;br &#x2F;&gt;
$$\tilde f^{(0)}(0,0,0,0,1) = 18$$ $$\tilde f^{(0)}(1,1,0,1,1) = 7$$&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;This function is handy, but we can go one step forward and fix $a = r$ and sum over all possible binary assignments for $b$ and $c$, we obtain:&lt;&#x2F;p&gt;
&lt;p&gt;$$\sum_{(b,c) \in \{0,1\}^{ 2k_i }} \tilde f^{(i)}(r,b,c) = \tilde W(r)$$&lt;&#x2F;p&gt;
&lt;p&gt;This new function is now a univariate polynomial!&lt;&#x2F;p&gt;
&lt;p&gt;Let us denote the function with $a$ fixed at $r$ as $\tilde f_r(b,c)^{(i)}$.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Let’s go back a bit and not lose sight of the objective we had. We had reached the point where what we wanted to check was:&lt;br &#x2F;&gt;
$$\tilde D(r_0) = \tilde W(r_0)$$&lt;&#x2F;p&gt;
&lt;p&gt;or equivalently,&lt;&#x2F;p&gt;
&lt;p&gt;$$\tilde W(r_0) = m_0$$&lt;&#x2F;p&gt;
&lt;p&gt;So, with the new function $\tilde f$ we can think this as:&lt;&#x2F;p&gt;
&lt;p&gt;$$\sum_{(b,c) \in {0,1}^{2k_i}} \tilde f_{r_0}^{(0)}(b,c) = m_0$$&lt;&#x2F;p&gt;
&lt;p&gt;To verify this equality, which implies a lot of additions(operations), we will employ the Sum-Check protocol.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;part-three-sum-check&quot;&gt;Part Three: Sum-check&lt;&#x2F;h2&gt;
&lt;p&gt;Let’s describe, step by step, all the operations performed by the prover and the verifier during this phase to better understand the protocol.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. The prover $\mathcal{P}$ builds a new function $g_1(z)$:  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$g_1(z): \mathbb{F_{p}} \to \mathbb{F_{p}}$$&lt;br &#x2F;&gt;
$$g_1(z) := \sum_{ (x_2, x_3, … , x_{ 2k_1 }) \in \{0,1\}^{2k_1 - 1} } \tilde f_{r_0}^{(0)} (z, x_2, …, x_{2k_1 - 1})$$&lt;&#x2F;p&gt;
&lt;p&gt;In other words, we leave the first coordinate of $x$ in $\tilde f_{r_0}^{(0)} (x)$ as the free variable $z$ and sum over all possible assignments of the remaining coordinates.&lt;&#x2F;p&gt;
&lt;p&gt;Observe that this function satisfies:&lt;&#x2F;p&gt;
&lt;p&gt;$$g_1(0) + g_1(1) = m_0$$&lt;&#x2F;p&gt;
&lt;p&gt;Because $g_1(0)$ sums over all combinations with the first coordinate set to 0, and $g_1(0)$ does so for the first coordinate equal to 1.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;In our case, since $k_1 = 2$ (i.e. there are $2^2$ nodes in layer 2), we have:&lt;br &#x2F;&gt;
$$g_1 (z) = \sum_{ (x_2, x_3, x_4) \in \{0, 1\}^3 } \tilde f_{r_0}^{(0)} (z, x_2, x_3, x_4).$$&lt;br &#x2F;&gt;
$$\begin{align}&lt;br &#x2F;&gt;
f_{ r_0 }^{(0)} (b, c) = &amp;amp; \ 2b_1 (1 - b_2) c_1 c_2 \Big[&lt;br &#x2F;&gt;
(3(1 - b_1)(1 - b_2) + 6(1 - b_1)b_2 + 4b_1(1 - b_2) + 3b_1b_2) \notag \newline&lt;br &#x2F;&gt;
&amp;amp; \quad + (3(1 - c_1)(1 - c_2) + 6(1 - c_1)c_2 + 4c_1 (1 - c_2) + 3c_1 c_2 ) \Big] \notag \newline&lt;br &#x2F;&gt;
&amp;amp; - (1 - b_1)(1 - b_2)(1 - c_1)c_2 \notag \newline&lt;br &#x2F;&gt;
&amp;amp; \Big[ (3(1 - b_1)(1 - b_2) + 6(1 - b_1)b_2 + 4b_1(1 - b_2) + 3b_1b_2 ) \notag \newline&lt;br &#x2F;&gt;
&amp;amp; \quad \times (3(1 - c_1)(1 - c_2) + 6(1 - c_1)c_2 + 4c_1(1 - c_2) + 3c_1c_2) \Big]&lt;br &#x2F;&gt;
\end{align}&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
Now we have to keep $b_1$ fixed and $b_1,c_1, c_2$ change&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;$b_2$&lt;&#x2F;th&gt;&lt;th&gt;$c_1$&lt;&#x2F;th&gt;&lt;th&gt;$c_2$&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;blockquote&gt;
&lt;p&gt;Due to the multiplicative factors (for example, terms like&lt;br &#x2F;&gt;
$$2b_1(1 - b_2)c_1c_2$$&lt;br &#x2F;&gt;
vanish unless $(c_1 = c_2 = 1)$ in the first term, and similarly in the second term), most combinations will contribute zero. In our case, let’s assume that after substitution, the only nonzero contributions come from:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Case 1:** When $(b_2, c_1, c_2) = (0, 1, 1)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Case 2:** When $(b_2, c_1, c_2) = (0, 0, 1)$  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We now analyze these cases separately.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Case 1: $(b_2, c_1, c_2) = (0, 1, 1)$&lt;br &#x2F;&gt;
$$2b_1 [3(1-b_1)+4b_1+3] \to 2x(x - 6)\to 2x^2 +12x$$&lt;br &#x2F;&gt;
Case 2: $(b_2, c_1, c_2) = (0, 0, 1)$&lt;br &#x2F;&gt;
$$-(1-b_1) [3(1 - b_1)+ 4b_1 ]6 \to -6(1 - x)(3 - 3x + 4x) \to (- 6 + 6x)(x + 3)$$&lt;br &#x2F;&gt;
The sum leads to:&lt;br &#x2F;&gt;
$$g_1(z) = 8z^2 + 24z - 18 \equiv 8z^2 + z - 18$$&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The prover sends this polynomial (its low degree allows sending its coefficients directly) to the verifier.&lt;&#x2F;p&gt;
&lt;p&gt;The verifier checks two things:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * That $g_1$ is indeed a low-degree polynomial.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * That:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$g_1(0) + g_1(1) = m_0.$$&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;In our example: $$g_1(0) = -18$$ $$g_1(1) = 14$$ $$g_1(0) + g_1(1) = -4 \equiv 19 = m_0.$$&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. The verifier $\mathcal{V}$ chooses a random value $s_1 \in \mathbb{F_{p}}$ and sends it to the prover $\mathcal{P}$ . The verifier also computes:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$g_1(s_1) = C_1$$&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;We can sample $s_1$ = 3: $$g_1(s_1) = g_1(3) = 8 \cdot 3^2 + 24 \cdot 3 - 18 = 126 \equiv 11.$$&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Upon receiving $s_1$, $\mathbb{F_{p}}$ computes $C_1$ and then repeats a similar procedure. The prover defines a new function:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$g_2(z): \mathbb{F_{p}} \to \mathbb{F_{p}}$$&lt;br &#x2F;&gt;
$$g_2(z) := \sum_{(x_3, … , x_{2k_1}) \in \{0,1\}^{2k_1 - 2}} \tilde f_{r_0}^{(0)} (s_1, z, x_3 …, x_{ 2k_1 - 2})$$&lt;&#x2F;p&gt;
&lt;p&gt;Here, the prover fixes the first variable to $s_1$ and leaves the second variable free (denoted by $z$), summing over the remaining binary assignments.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;We have:&lt;br &#x2F;&gt;
$$g_2(z) = \sum_{(x_3, x_4) \in {0,1}^{2}} \tilde f_{ r_0 }^{(0)} (s_1, z, x_3, x_4)$$&lt;br &#x2F;&gt;
$$g_2(z) = 162x^2 - 288x + 126 \equiv x^2 - 12x + 11.$$&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. The prover $\mathcal{P}$ sends the coefficients of $g_2(z)$ to the $\mathcal{V}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. The verifier checks that:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$g_2(0) + g_2(1) = C_1$$&lt;&#x2F;p&gt;
&lt;p&gt;$$g_2(0) = 0$$&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;We must check: $$g_2(1) = 11$$ $$g_2(0) + g_2(1) = 11$$&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    6. This procedure is repeated until the verifier receives  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$C_{2k+1}$:&lt;&#x2F;p&gt;
&lt;p&gt;$$C_{ 2k + 1} := \tilde f_{ r_0 }^{(0)} (s_1, s_2, x_3 …, s_{ 2k_{ i + 1}})$$&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;This is the final step of the Sum-Check protocol.&lt;&#x2F;strong&gt; At this point, the verifier would normally query an oracle to compute this value directly; however, in our protocol, the verifier can’t evaluate the function directly.&lt;&#x2F;p&gt;
&lt;p&gt;The verifier can build $\widetilde{\text{Add}}$ and $\widetilde{\text{Mult_i}}$ but not to $\tilde W_{i+1}$, which represent the values of the nodes in the immediately preceding layer.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-have-we-achieved&quot;&gt;What Have We Achieved?&lt;&#x2F;h2&gt;
&lt;p&gt;In effect, we have reduced the problem of verifying the circuit’s outputs to verifying the values in one layer lower. This reduction is repeated layer by layer until the final layer is reached, which corresponds to the inputs the verifier already knows. This whole idea behind the protocol.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Let’s do the math for our example:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $\mathcal{V}$ samples $s_2 = 2$ and sends it to $\mathcal{P}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $\mathcal{V}$ and $\mathcal{P}$ calculate $C_2 = g_2(s_2)$:$$g_2(s_2) = g_2(2) = 2^2 - 12 \cdot 2 + 11 = -9 \equiv 14.$$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $\mathcal{P}$ calulates:$$g_3(z) = \sum_{x_4 \in {0,1}} \tilde {f_{ r_0 }^{(0)} (s_1, s_2, z, x_4)}$$ $$g_3(z) = 90x^2 - 180x + 144 \equiv 21x^2 - 19x + 6$$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $\mathcal{V}$ receives $g_3(z)$ and checks:$$g_3(0) = 8 $$ $$ g_3(1) = 6 $$ $$g_3(0) + g_3(1) = 14$$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $\mathcal{V}$ samples $s_3 = 4$ and sends it to $\mathcal{P}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $\mathcal{V}$ and $\mathcal{P}$ calculate $C_3 = g_3(s_3)$:  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$g_3(s_3) = 21 \cdot 4^2 - 19 \cdot 4 + 6 = 266 \equiv 13$$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $\mathcal{P}$ calculates:  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$g_4(z) = \tilde f_{r_0}^{(0)} (s_1, s_2, s_3, z)$$ $$g_4(z) = -288z^2 + 1152x \equiv 11z^2 + 2z$$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $\mathcal{V}$ receives $g_4(z)$ and checks:  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$g_4(0) = 0$$ $$g_4(1) = 13 $$ $$g_4(0) + g_3(1) = 13$$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $\mathcal{V}$ samples $s_4 = 7$ and sends it to $\mathcal{P}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $\mathcal{V}$ and $\mathcal{P}$ calculate $C_4 = g_4(s_4)$:  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$g_4(s_4) = 553 \equiv 1$$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $\mathcal{P}$ calulates  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$\tilde f^{(0)}_{r_0}(s_1,s_2,s_3,s_4) = c_4$$&lt;br &#x2F;&gt;
$$\begin{equation}&lt;br &#x2F;&gt;
\begin{aligned}&lt;br &#x2F;&gt;
\tilde{f}^{(0)}(r_1,s_1,s_2,s_3,s_4) := &amp;amp; \newline \widetilde{\text{Add}}_1(r_1,s_1,s_2,s_3,s_4) \cdot (\tilde{W}_2(s_1,s_2) + \tilde{W}_2(s_3,s_4)) \newline&lt;br &#x2F;&gt;
&amp;amp; + \widetilde{\text{Mult}}_1(r_1,s_1,s_2,s_3,s_4) \cdot \tilde{W}_2(s_1,s_2) \cdot \tilde{W}_2(s_3,s_4)&lt;br &#x2F;&gt;
\end{aligned}&lt;br &#x2F;&gt;
\end{equation}$$&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;part-four-recursion&quot;&gt;Part four: Recursion&lt;&#x2F;h2&gt;
&lt;p&gt;We reached a stage where the verifier’s goal is to check that&lt;&#x2F;p&gt;
&lt;p&gt;$$\tilde f_{ r_0 }^{(0)} (s_1, s_2, x_3, …, s_{2k_{i + 1}}) = C_1$$&lt;&#x2F;p&gt;
&lt;p&gt;However, to do so, the verifier would need to know:&lt;&#x2F;p&gt;
&lt;p&gt;$$\tilde W_2(s_1, s_2, … , s_{k + 1})$$ $$\tilde W_2(s_{ k + 1}, … , s_{ 2k + 1})$$&lt;&#x2F;p&gt;
&lt;p&gt;If the verifier were to perform two separate sum-checks for these values, the final workload would be excessive. Instead, the prover makes a single claim at one point. How?&lt;&#x2F;p&gt;
&lt;p&gt;Both parties compute the unique function&lt;&#x2F;p&gt;
&lt;p&gt;$$\ell: \mathbb{F} \to \mathbb{F}^{2k}$$&lt;&#x2F;p&gt;
&lt;p&gt;such that:&lt;&#x2F;p&gt;
&lt;p&gt;$$\ell(0) = (s_1, s_2, … , s_{k+1})$$ $$\ell(1) = (s_{k + 1}, … , s_{2k + 1})$$&lt;&#x2F;p&gt;
&lt;p&gt;Then $\mathcal{P}$ sends the function:&lt;br &#x2F;&gt;
$$q = \tilde W_2 \circ \ell : \mathbb{F} \to \mathbb{F}.$$&lt;&#x2F;p&gt;
&lt;p&gt;to the verifier. Notice that:&lt;&#x2F;p&gt;
&lt;p&gt;$$q(0) = \tilde W_2(s_1, s_2, … , s_{k+1})$$ $$q(1) = \tilde W_2(s_{k+1}, … , s_{2k+1})$$&lt;&#x2F;p&gt;
&lt;p&gt;Thus, by knowing $q(x)$, the verifier can recover the necessary values $q(0)$ and $q(1)$ to complete the final evaluation in the Sum-Check protocol.&lt;&#x2F;p&gt;
&lt;p&gt;So, with $q(x)$, $\mathcal{V}$ can use $q(0)$ and $q(1)$ to do the last evaluation in the sumcheck protocol.&lt;&#x2F;p&gt;
&lt;p&gt;But how does the verifier know that $q(x)$ is correct? Again, $\mathcal{V}$ samples a random element $r∗ \in \mathbb{F}$ and computes&lt;&#x2F;p&gt;
&lt;p&gt;$$r_1 = \ell (r^*)$$&lt;&#x2F;p&gt;
&lt;p&gt;Then, $\mathcal{P}$ and $\mathcal{V}$ compute:&lt;&#x2F;p&gt;
&lt;p&gt;$$m_1 = q(r_1)$$&lt;&#x2F;p&gt;
&lt;p&gt;Now, the prover’s task is to convince the verifier that:&lt;&#x2F;p&gt;
&lt;p&gt;$$\tilde W_2(r_1) = m_1$$&lt;&#x2F;p&gt;
&lt;p&gt;This claim is analogous to our initial verification step:&lt;&#x2F;p&gt;
&lt;p&gt;$$\tilde D(r_0) = m_0$$&lt;&#x2F;p&gt;
&lt;p&gt;where $\tilde D(x)$D encoded the output values and now $\tilde W_2(x)$ encodes the values of the nodes in the immediately preceding layer.&lt;&#x2F;p&gt;
&lt;p&gt;Thus, the remaining task is to apply the same Sum-Check protocol to this new layer.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;For our circuit:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $\mathcal{P}$ and $\mathcal{V}$ calculate:  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$\ell(0) = (s_1, s_2) = (3, 2)$$ $$ \ell(1) = (s_3, s_4) = (4, 7)$$ $$\ell(x) = (s_1(1-x) + s_3x, s_2(1-x) + s_4x) = (3(1-x) + 4x, 2(1-x) + 7x).$$
* $\mathcal{P}$ sends $q= \tilde W_1 \circ \ell : \mathbb{F} \to \mathbb{F}.$&lt;br &#x2F;&gt;
$$q(x) = -20x^2 -52x - 12 \equiv 3x^2 + 17x + 11$$
* $\mathcal{V}$ checks $\tilde f_{r_0}^{(0)} (s_1, s_2, s_3, s_4) = c_4$ using $q(x)$
* $\mathcal{V}$ sends $\mathcal{P}$ a random $r^* \in \mathbb{F}$&lt;br &#x2F;&gt;
$$r^* = 6$$
* $\mathcal{V}$ and $\mathcal{P}$ calculate:&lt;br &#x2F;&gt;
$$r_1 = \ell (6) = (9, 32) \equiv (9,9)$$ $$m_1 = q(6) = 14.$$
* Now $\mathcal{P}$ needs to convice $\mathcal{V}$ that:&lt;br &#x2F;&gt;
$$\sum_{(b, c) : \in {0, 1}^{2 \cdot 1}} f_{r_1}^{(1)} (b, c) = m_1$$
* $\mathcal{P}$ calculates $g_1(z)$ and sends it to $\mathcal{V}$ :&lt;br &#x2F;&gt;
$$g_1(z) = \sum_{x_2 \in {0, 1}} f_{r_1}^{(1)} (z, x_2)$$ $$g_1(z) = 2z^2 + 7z + 14$$
* $\mathcal{V}$ checks $g_1(0) + g_1(1) = m_1$:&lt;br &#x2F;&gt;
$$ g_1(0) = 14 $$ $$ g_1(1) = 0 $$ $$ g_1(0) + g_1(1) = 14$$
* $\mathcal{V}$ samplse $s_1 = 12$ and sends it to $\mathcal{P}$.
* $\mathcal{V}$ and $\mathcal{P}$ calculates $C_1 = g_1(s_1)$:&lt;br &#x2F;&gt;
$$g_1(12) = 2 \cdot 12^2 + 7 \cdot 12 + 14 = 386 \equiv 18$$
* $\mathcal{P}$ calculates $g_2(z)$ and send it to $\mathcal{V}$:&lt;br &#x2F;&gt;
$$g_2(z) = \tilde f_{r_1}^{(1)} (s_1, z)$$ $$g_2(z) = 9z^2 + z +4$$
* $\mathcal{V}$ checks $g_2(0) + g_2(1) = C_1$:&lt;br &#x2F;&gt;
$$g_2(0) = 4$$ $$g_2 (1) = 14$$ $$ g_2(0) + g_2(1) = 18$$
* $\mathcal{V}$ samples $s_2 = 5$ and sends it to $\mathcal{P}$.
* $\mathcal{V}$ and $\mathcal{P}$ calculate $C_2 = g_2(s_2)$:&lt;br &#x2F;&gt;
$$C_2 = g_2(5) = 4$$
* $\mathcal{P}$ and $\mathcal{V}$ calculate:&lt;br &#x2F;&gt;
$$ \ell(0) = s_1 = 12$$ $$ \ell(1) = s_2 = 5$$ $$\ell(x) = -7x + 12$$
* $\mathcal{P}$ sends $q= \tilde W_1 \circ \ell : \mathbb{F} \to \mathbb{F}.$&lt;br &#x2F;&gt;
$$q(x) = 3(1 - (-7x + 12) ) + (-7x +12)$$
* $\mathcal{V}$ checks $f_{r_1}^{(1)}(s_1,s_2) = c_2$ using $q(x)$
* $\mathcal{V}$ sends $\mathcal{P}$ a random $r^* \in \mathbb{F}$&lt;br &#x2F;&gt;
$$r^* = 17$$
* $\mathcal{V}$ and $\mathcal{P}$ calculate:&lt;br &#x2F;&gt;
$$r_2 = \ell (17) = 8$$ $$m_2 = q(17) = 10$$
* Finally, $\mathcal{V}$ calculates $\tilde W_2(x)$ and checks $\tilde W_2(r_2) = m_2$&lt;br &#x2F;&gt;
$$W_2(0) = 3$$ $$W_2(1) = 1$$ $$\tilde W_2(x) = 3(1 - x) + x$$ $$\tilde W_2(8) = 10$$&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;last-part-repeat&quot;&gt;Last part: repeat&lt;&#x2F;h2&gt;
&lt;p&gt;Well, everything is almost ready! We just need to repeat this procedure once per layer. Finally, $W_d(x)$ is the function that maps the program’s inputs, which we will use to verify the sum-check of layer $d-1$. If this check is correct, it means that all the previous ones are also correct, so we can confidently say that the computation was executed correctly.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion:&lt;&#x2F;h2&gt;
&lt;p&gt;In summary, the GKR protocol elegantly reduces the problem of verifying the output of a complex arithmetic circuit into a series of simpler verifications that recursively move from the output layer to the input layer. Each step relies on algebraic properties—most notably, the uniqueness of multilinear extensions and the Schwartz–Zippel lemma—to ensure that a resource-limited verifier can efficiently confirm the correctness of the computation. This protocol illustrates the power of interactive proofs and lays the foundation for more advanced cryptographic applications such as zero-knowledge proofs.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Why we believe that Pod, an optimal-latency, censorship-free, and accountable generalized consensus layer, is a groundbreaking technology for blockchains and distributed systems</title>
          <pubDate>Thu, 13 Feb 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/why-we-believe-that-pod-an-optimal-latency-censorship-free-and-accountable-generalized-consensus-layer-is-a-groundbreaking-technology-for-blockchains-and-distributed-systems/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/why-we-believe-that-pod-an-optimal-latency-censorship-free-and-accountable-generalized-consensus-layer-is-a-groundbreaking-technology-for-blockchains-and-distributed-systems/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/why-we-believe-that-pod-an-optimal-latency-censorship-free-and-accountable-generalized-consensus-layer-is-a-groundbreaking-technology-for-blockchains-and-distributed-systems/">&lt;p&gt;&lt;strong&gt;TL;DR:&lt;&#x2F;strong&gt; This post discusses &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;pdf&#x2F;2501.14931&quot;&gt;Pod&lt;&#x2F;a&gt;, a new notion of consensus that achieves optimal latency of one round-trip (about 200 ms), by removing inter-replica communication. We believe this paper and the work by pod network is groundbreaking and we want others to share our excitement and passion for their work, that’s why we wrote our understanding of what they have found and created.&lt;&#x2F;p&gt;
&lt;p&gt;The construction is simple and can be implemented in a few hundred lines of code in Rust. While the construction has weaker properties than total order broadcast, it still remains censorship resistant against Byzantine replicas, has accountability for safety violations and achieves low latency. In simpler terms, Pod removes the consensus from the blockchain equation, and allows transactions to happen as fast as ordinary searches on the web. This enables several applications, such as payments, auctions and decentralized data stores.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;introduction-the-problem-of-consensus-in-blockchain&quot;&gt;Introduction: The Problem of Consensus in Blockchain&lt;&#x2F;h2&gt;
&lt;p&gt;Blockchain technology has revolutionized the way we think about decentralized trust and distributed ledgers. At its heart lies the problem of consensus—the mechanism by which a network of untrusted parties agrees on the state of a shared ledger. Consensus protocols are responsible for ensuring that every transaction is confirmed, ordered, and irrevocably recorded while preserving key properties such as safety (no two honest nodes disagree on the ledger’s content) and liveness (transactions submitted by honest parties eventually become part of the ledger). One of the reasons why consensus is introduced is to prevent double spending: a party could sign two transactions using the same funds and try to have them approved by the ledger, effectively creating money out of thin air. The fact that one transaction must come before another prevents this, but we will see that consensus is not necessary to achieve this.&lt;&#x2F;p&gt;
&lt;p&gt;In classical distributed systems, consensus has been studied for decades, giving rise to robust algorithms that guarantee agreement among a small set of trusted parties. However, blockchains must operate in an open, permissionless setting where nodes may be geographically dispersed, and some may behave maliciously. The result is that consensus in blockchains must address several additional challenges:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Scalability and Throughput:** Many early blockchains—most notably Bitcoin—suffer from severe throughput limitations (e.g., around 7 transactions per second) and high latency (e.g., waiting up to 10 minutes for finality). These numbers pale in comparison to conventional payment systems like Visa, which processes tens of thousands of transactions per second.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Security and Byzantine Fault Tolerance:** The consensus algorithm must tolerate Byzantine faults (arbitrary and potentially malicious behavior) while ensuring that honest nodes do not disagree on the ledger’s contents.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Latency and Finality:** In many applications, the time between a client’s submission of a transaction and the transaction’s irreversible finalization is critical. High latency not only degrades user experience but can also open the door to adversarial exploits such as front-running.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Economic Incentives and Censorship Resistance:** The design of consensus protocols must account for economic incentives. For example, leader-based systems (where one node is given the right to propose the next block) can be vulnerable to censorship or manipulation if the leader is bribed or coerced.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;These challenges have motivated researchers and practitioners to seek new designs that minimize latency and improve throughput without compromising security.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;classical-consensus-and-its-limitations&quot;&gt;Classical Consensus and Its Limitations&lt;&#x2F;h2&gt;
&lt;p&gt;Traditional consensus protocols—such as Paxos, Raft, and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Byzantine_fault&quot;&gt;Byzantine Fault Tolerant&lt;&#x2F;a&gt; (BFT) algorithms—were originally designed for closed systems with a fixed number of nodes. These algorithms guarantee that if a message is accepted by one correct node, then it will eventually be accepted by all correct nodes (safety), and that new messages are eventually delivered (liveness). In the classical sense, consensus is achieved via multiple rounds of communication among nodes. This typically involves a leader or coordinator who proposes a value, and then the other nodes exchange messages to reach agreement.&lt;&#x2F;p&gt;
&lt;p&gt;However, these algorithms suffer from several limitations when applied to blockchain:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Communication Overhead:** Multiple rounds of message exchanges among all nodes lead to significant communication overhead. In a globally distributed network, this overhead translates into higher latency.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Leader-Based Bottlenecks:** Leader-based approaches centralize the ordering of transactions. While this can simplify the process of reaching consensus, it also creates vulnerabilities. A malicious or compromised leader can censor transactions, reorder them for personal gain (e.g., in the case of MEV), or cause delays.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Scalability:** Traditional consensus protocols are designed for small, known groups of nodes. Scaling these protocols to thousands of nodes (or more) in an open, permissionless network poses significant challenges in terms of both security and performance.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Latency:** Even in the best-case scenario, achieving consensus requires multiple network round trips. The lower bound for many protocols is expressed in terms of δ (the network delay). For instance, protocols based on Byzantine agreement have been shown to require at least t + 1 rounds (where t is the number of tolerated faults) in the synchronous setting, or at least 2n&#x2F;(n – t) rounds in the asynchronous case.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Because of these inherent limitations, blockchain systems that rely on traditional consensus (or their direct adaptations) often suffer from high transaction confirmation times, limiting their utility for applications that demand near-instant finality.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;consensus-in-blockchains&quot;&gt;Consensus in Blockchains&lt;&#x2F;h2&gt;
&lt;p&gt;Bitcoin introduced a revolutionary approach to consensus by using Proof-of-Work (PoW) to elect a leader probabilistically. In Bitcoin’s protocol, nodes (miners) compete to solve a cryptographic puzzle, and the first to solve it earns the right to propose the next block. While this approach has the advantage of being robust in an open, trustless environment, it also introduces significant inefficiencies:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **High Latency:** The block interval in Bitcoin is deliberately long (approximately 10 minutes) to reduce the probability of forks, resulting in slow confirmation times.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Energy Consumption:** PoW requires vast amounts of computational power and energy.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Finality Uncertainty:** Because Bitcoin’s chain can fork, finality is probabilistic. A transaction is typically considered “final” only after several blocks have been added to the chain (e.g., six confirmations).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Subsequent blockchain designs, such as Ethereum’s Proof-of-Stake (PoS) and various Byzantine Fault Tolerant (BFT) protocols, have attempted to reduce latency and improve throughput. Yet, many of these systems still rely on multi-round communication or leader-based architectures that inherently limit performance.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-quest-for-low-latency-consensus&quot;&gt;The Quest for Low-Latency Consensus&lt;&#x2F;h2&gt;
&lt;p&gt;The fundamental challenge for any blockchain consensus mechanism is the trade-off between the number of communication rounds (which directly impacts latency) and the security guarantees provided. The ideal scenario would be to achieve the “physically optimal” latency: a one-round-trip delay for writing a transaction and a one-round-trip delay for reading it—totaling 2δ, where δ is the actual network delay. This is the physical limit, as the information must travel from the writer to the replicas and then from the replicas to the reader.&lt;&#x2F;p&gt;
&lt;p&gt;Achieving such low latency, however, is not trivial. Eliminating inter-replica communication (which normally is required to guarantee total ordering and agreement) means that the system must forgo some of the stronger guarantees provided by classical consensus protocols. Instead, Pod aims for a “generalized consensus” that focuses on obtaining useful, application-specific information with minimal delay.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;beyond-total-order-broadcast-a-new-paradigm&quot;&gt;Beyond Total-Order Broadcast: A New Paradigm&lt;&#x2F;h2&gt;
&lt;p&gt;Most traditional blockchain consensus protocols focus on the total-order broadcast model. This means that every transaction is ordered sequentially, and all nodes agree on this order. While this is essential for certain applications, it is often overkill for other applications.&lt;&#x2F;p&gt;
&lt;p&gt;For instance, consider payment systems, decentralized auctions, or even certain types of decentralized data stores. In these cases, the requirement is not necessarily that every transaction be totally ordered, but rather that each transaction is confirmed quickly and that some weaker ordering properties hold. This is the insight behind Pod, which we discuss in the next section.&lt;&#x2F;p&gt;
&lt;p&gt;We can see that double-spending can be solved without total ordering, as &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pod.network&#x2F;blog&#x2F;wait-why-do-we-need-consensus-again&quot;&gt;explained here&lt;&#x2F;a&gt;: imagine I want to send two transactions to two different parties, Alice and Bob. Suppose that the number of validators is 3f + 1, where f is the number of Byzantine validators. I could bribe these f Byzantine validators to accept both transactions, and then I could send the one to Alice to f other validators, and Bob’s to different f validators. If 2f + 1 have to agree, there is no way I can gather acceptance for both from 2f + 1, and either my transactions don’t go through, or just one gets accepted, and the other would not receive support from honest parties.&lt;&#x2F;p&gt;
&lt;p&gt;The following picture, taken from &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pod.network&#x2F;how-it-works&quot;&gt;this post&lt;&#x2F;a&gt; shows the difference between total ordering and Pod:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;BJ9kfMYYyx.png&quot; alt=&quot;pod&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We can see that in some logs, transaction 4 could happen before transaction 3, but all lie within a prescribed range.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;overview-of-pod-s-design&quot;&gt;Overview of Pod’s Design&lt;&#x2F;h2&gt;
&lt;p&gt;At its core, Pod is designed to achieve transaction confirmation within 2δ latency—the physical lower bound dictated by network delays. To do this, the protocol makes a fundamental design decision: it eliminates inter-replica communication during the transaction write phase. Instead, the following process is used:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. **Client-to-Replica Communication:** When a client submits a transaction, it sends the transaction directly to all replicas in the network. Each replica processes the transaction independently and appends it to its local log.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. **Timestamping and Sequencing:** To allow clients (readers) to derive meaningful information from the separate logs maintained by each replica, the replicas attach timestamps and sequence numbers to each transaction. The timestamps have millisecond precision are non-decreasing. These values help clients determine when a transaction can be considered “confirmed.”&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. **Client-Side Log Aggregation:** When a client wishes to read the ledger, it collects the logs from enough replicas (typically 2&#x2F;3), validates the votes (which include digital signatures), and computes values such as **rmin** , **rmax** , and **rconf** (the minimum round, maximum round, and confirmed round, respectively). From these, the client can determine a past-perfect round—denoted **rperf** , such that the reader has received all transactions that are or will be confirmed prior to this round.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This design, while sacrificing the strong guarantees of total-order broadcast, enables the protocol to deliver transactions with a minimal delay of 2δ. The trade-off is that the ordering of transactions is “generalized” rather than strict; that is, the protocol guarantees that transactions will be confirmed within a specific time frame, and that their associated timestamps will lie within certain bounds.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;key-properties-and-guarantees&quot;&gt;Key Properties and Guarantees&lt;&#x2F;h2&gt;
&lt;p&gt;Pod is engineered to deliver several critical guarantees, making it particularly well-suited for applications where low latency is essential. These properties include:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Transaction Confirmation within 2δ:** Every transaction written by an honest client is guaranteed to be confirmed—i.e., appear in the output of any reader—with a delay of at most 2δ.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Censorship Resistance:** Even in the presence of Byzantine replicas (nodes that deviate arbitrarily), the protocol ensures that confirmed transactions are visible to every honest reader. This is crucial in applications such as payments and auctions, where censorship or selective inclusion could have severe consequences.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Past-Perfection Property:** Pod defines a “past-perfect round” (**rperf**), which guarantees that a client is seeing all possible transactions receiving rconf ≤ rperf. More precisely, suppose client A computes rperf and, at any point in the future, client B sees a transaction confirmed with rconf ≤ rperf, then client A was already aware of that transaction at the moment it computed rperf (though he may not have seen it as confirmed at that time). In the case of auctions, past-perfection ensures that no additional bids be included after the auctioneer sees the deadline as past-perfect.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Accountability for Safety Violations:** The protocol includes mechanisms that allow for the identification of misbehaving replicas. If a safety violation occurs, the protocol can pinpoint which nodes deviated from the prescribed behavior. This accountability is enforced by the digital signatures attached to each transaction vote. Having accountability means that malicious actors can be slashed.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Flexible Transaction Timestamps:** Although different replicas may assign slightly different timestamp values to the same transaction, the protocol guarantees that the rconf for any honest client will be bounded between rmin and rmax (this is the confirmation bounds property).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The past-perfection and confirmation bounds ensure that parties cannot be blindsided by transactions suddenly ap-&lt;br &#x2F;&gt;
pearing as confirmed too far in the past, and that the diﬀerent transaction timestamps stay in a certain range.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-pod-differs-from-traditional-consensus&quot;&gt;How Pod Differs from Traditional Consensus&lt;&#x2F;h2&gt;
&lt;p&gt;Traditional consensus protocols, such as those used in longest-chain blockchains or BFT systems, rely on extensive communication among nodes to establish a total order of transactions. In contrast, Pod’s approach is to sidestep inter-replica communication altogether during the transaction write phase. This decision is pivotal for achieving optimal latency, but it also means that the protocol must accept a weaker form of ordering.&lt;&#x2F;p&gt;
&lt;p&gt;To illustrate this, consider the following contrasts:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Leader Election vs. Leaderless Operation:** In many blockchain systems, a leader (or sequencer) is elected to propose the next block. This leader is responsible for ordering transactions and ensuring that all nodes see the same sequence. In Pod, there is no such leader. Instead, every replica processes transactions independently and the ordering is derived by the client at read time.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Total-Order vs. Generalized Order:** Total-order broadcast protocols ensure that every node sees every transaction in the same order. Pod, on the other hand, guarantees that transactions are confirmed within a certain latency and that the order is “good enough” for applications like payments and auctions, where strict ordering is less critical.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Inter-Replica Communication Overhead:** By eliminating the need for replicas to communicate with each other, Pod dramatically reduces the communication overhead that typically limits the performance of consensus protocols. This design choice is the key to achieving 2δ latency, the best possible time-to-finality dictated by physical network delays.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;pod-core-the-technical-construction&quot;&gt;Pod-Core: The Technical Construction&lt;&#x2F;h2&gt;
&lt;p&gt;The technical core of the Pod protocol (referred to as pod-core in the paper) is built around the following mechanisms:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Client State and Voting:** Clients maintain state that includes the most recent transaction round (mrt), sequence numbers, and a mapping of transactions to votes received from replicas. When a client submits a transaction, it waits to receive “votes” from each replica. These votes include a timestamp (ts) and a sequence number (sn) along with a digital signature.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Vote Validation and Ordering:** On receiving a vote, the client first verifies the signature to ensure authenticity. It then checks that the sequence number is as expected. If the vote passes these checks, it is incorporated into the client’s local state. Clients use the collection of votes to compute the rmin (the minimum timestamp), rmax (the maximum timestamp), and, via a median or other aggregation method, the confirmed round (rconf). This is a timestamp that is attached to a transaction that is taken as confirmed by a client and which may vary accordingly. The confirmation bounds property ensures, however, that all honest clients rconf will be bounded between rmin and rmax.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Replica Logs and Read Operations:** Replicas maintain their own logs of transactions. When a client performs a read operation, it collects these logs, validates them, and then computes a global view of the ledger that satisfies the past-perfection property. This view is then presented as the output of the read() operation.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;By adhering to these procedures, pod-core guarantees that any transaction written by an honest client will be confirmed with minimal latency and that any attempt by Byzantine nodes to censor or reorder transactions will be detectable and, thus, accountable.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-elimination-of-inter-replica-communication&quot;&gt;The Elimination of Inter-Replica Communication&lt;&#x2F;h2&gt;
&lt;p&gt;A central innovation in Pod is the removal of inter-replica communication during the write phase. Traditional consensus protocols require replicas to engage in multiple rounds of message exchanges to agree on the order of transactions. Pod circumvents this by allowing clients to broadcast their transactions directly to every replica. This design choice has several profound implications:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Optimal Latency:** Without waiting for replicas to coordinate with each other, the transaction’s propagation time is limited only by the physical delay of messages traveling through the network. Hence, the confirmation time is approximately 2δ.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Reduced Complexity:** By offloading the ordering responsibility to the client’s read operation, the protocol simplifies the interaction among replicas. Each replica independently timestamps and sequences transactions without needing to reconcile its state with others.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Localized Fault Isolation:** If a subset of replicas behaves maliciously, their misbehavior can be isolated and identified through the accountability mechanisms. The impact of Byzantine nodes is contained, and honest clients can still obtain a consistent view of the ledger by aggregating data from a sufficient number of honest replicas.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The protocol employs a streaming construction. Clients establish persistent connections with all replicas, enabling them to continuously receive “vote” messages as soon as a replica processes a transaction. This streaming nature means that rather than making isolated, one-off requests for each transaction, the client maintains an ongoing session where transaction updates—including timestamps, sequence numbers, and digital signatures—are streamed in real time. By persistently receiving this data, the client is able to immediately update its state and aggregate the votes necessary for computing parameters such as rmin, rmax, rconf, and rperf. This approach not only minimizes the overhead associated with repeatedly setting up new connections but also ensures that the client’s view of the ledger remains as current as possible, thereby contributing to the protocol’s objective of near-optimal latency. This moves from the pattern of blocks, where you have to wait until it appears to receive a confirmation, adding delay.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;timestamping-and-the-computation-of-rmin-rmax-and-rconf&quot;&gt;Timestamping and the Computation of rmin, rmax, and rconf&lt;&#x2F;h2&gt;
&lt;p&gt;Pod introduces a sophisticated scheme for assigning and aggregating timestamps to ensure that, even in the absence of inter-replica communication, clients can derive a coherent view of transaction ordering. The key components are:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **rmin (Minimum Round):** The lower bound for rconf for the transaction&amp;#39;s rconf for an honest client. Calculation given in [lines 1-13 of algorithm 3](https:&#x2F;&#x2F;arxiv.org&#x2F;pdf&#x2F;2501.14931).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **rmax (Maximum Round):** The upper bound for rconf for the transaction&amp;#39;s rconf for an honest client. Calculation given in [lines 14-26 of algorithm 3](https:&#x2F;&#x2F;arxiv.org&#x2F;pdf&#x2F;2501.14931).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **rconf (Confirmed Round):** A computed value—derived as the median of the timestamps received from a quorum of replicas—that signifies when a transaction becomes confirmed. Calculation given in [lines 12-18 of algorithm 2](https:&#x2F;&#x2F;arxiv.org&#x2F;pdf&#x2F;2501.14931).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The protocol guarantees that, for any transaction, the confirmed round rconf will satisfy the bounds determined by rmin and rmax.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;pdf&#x2F;2501.14931&quot;&gt;Lemma 1&lt;&#x2F;a&gt; shows that the values of rmin, rmax will correspond to the sorted values (in increasing order) at positions $\lfloor \alpha &#x2F; 2 \rfloor - \beta$ and $n - \alpha + \lfloor \alpha &#x2F; 2 \rfloor + \beta$, respectively. Here $\alpha$ is the confirmation threshold and $\beta$ the resilience threshold, satisfying $n - \alpha = \beta$. If $\alpha \geq 4\beta + 1$, lemma 2 indicates that there is at least one honest replica such that its most recent timestamp is, at most, rperf. Lemmas 3 and 4 guarantee, under the same assumptions, that we have confirmation within $2\delta$ and past-perfection within $\delta$. Lemmas 5, 6 and 7 guarantee that the construction has past-perfection safety, confirmation bounds and $\beta$-accountable safety, respectively. All these results are combined to prove the security of Pod-core as stated in theorem 1.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;digital-signatures-and-accountability&quot;&gt;Digital Signatures and Accountability&lt;&#x2F;h2&gt;
&lt;p&gt;Every transaction vote in Pod is accompanied by a digital signature. This has multiple advantages:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Authentication:** Clients can verify that the vote indeed comes from the claimed replica, preventing impersonation attacks.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Non-Repudiation:** Since signatures are cryptographically secure, a malicious replica cannot later deny that it sent a particular vote.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Misbehavior Detection:** If a replica sends inconsistent or out-of-order votes, these discrepancies can be detected by comparing signatures across different replicas’ logs. The identify() function in the protocol uses these digital proofs to pinpoint the source of any violation of safety properties.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This accountability mechanism is essential not only for security but also for enforcing economic incentives. If a replica is caught misbehaving, it can be penalized (for example, through slashing of its stake), which in turn discourages behavior that could undermine the protocol’s guarantees.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;algorithms&quot;&gt;Algorithms&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;client-algorithms-1-2-and-3&quot;&gt;Client (Algorithms 1, 2 and 3)&lt;&#x2F;h3&gt;
&lt;p&gt;The client maintains a state consisting of all the replicas, their public keys, and lists for the most recent timestamp, and next sequence number expected by each replica, the timestamps received for each transaction by each replica and the pod observed by the client so far.&lt;&#x2F;p&gt;
&lt;p&gt;After initialization (steps 7-14 of algorithm 1), the client could try to send a transaction to be included. To that end, the client sends it to all the replicas (steps 1-5 of algorithm 2). Upon reception, honest replicas will answer back with their vote. Every time the client receives a vote, the client (steps 15 - 24, algorithm 1):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. will verify the signature (step 16, returning if invalid).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. checks whether the serial number corresponds to the expectec (step 17, returning if the vote cannot be processed).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. updates the corresponding next sequence number (step 18).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. ensures that the timestamp is not less than the mrt (step 19, returning in case it&amp;#39;s a previous timestamp).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. updates the mrt (step 20) and checks whether the transaction is a heartbeat (step 21, doing nothing else for a heartbeat).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    6. checks for duplicate timestamps (step 22, returning if there is a duplicate).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    7. adds the timestamp for the transaction in the log corresponding to the replica (step 23).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The client can afterwards perform a read operation, following the steps 6 to 28 in algorithm 2:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Initializes transaction and additional information (step 7)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Loops over all transactions in the pod (steps 8 - 21),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Computes rmin and rmax (steps 9 and 10) and sets rconf to bottom, as well as setting the timestamps and additional information to empty (step 11).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * If there is a quorum (checking that there are at least $\alpha$ valid signatures), the client gets the timestamps (step 14), appends them to the timestamps (step 15), appens the vote to the additional information (step 16), and computes the rconf for the transaction as the median (step 18) and appends the transaction to the transation log (step 20).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Computes the rperf (step 22).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Appends the message votes for mrt for each replica (step 24).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. Assembles the pod from the information (transactions, rperf and additional information) and returns the pod (steps 26-27).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Algorithm 3 is concerned with the computation of median (33-35) and minimum (1-13), maximum (14-26) and minimum estimated next timestamps (27-32).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;replica-algorithm-4&quot;&gt;Replica (Algorithm 4)&lt;&#x2F;h3&gt;
&lt;p&gt;The replica contains a list of all connected clients, the next sequence number, its log and has a function to return the clock time of the replica (lines 1-4). The replica initializes with clean log and no connections (5-7). At the end of each round, the replica sends a hearbeat to each connection (26-28).&lt;&#x2F;p&gt;
&lt;p&gt;Whenever a client connects to the replica, it adds the client to the connected client list (9) and sends all votes to the client (10-12). If a client wants to perform a write, first the replica checks whether it is not a duplicate (15, returning if it is a duplicate) and sends back a vote.&lt;&#x2F;p&gt;
&lt;p&gt;The vote is performed in the following way:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. The replica gets the timestamp, next serial number and signs a messages with the transaction, the timestamp and serial number (step 19).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. The replica appends the transaction to its log, if valid (20).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. The replica sends the vote to all the clients (21-23)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. The replica updates the next serial number, increasing it by 1 (24).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;extensions&quot;&gt;Extensions&lt;&#x2F;h2&gt;
&lt;p&gt;Pod-core is very simple core, where clients can read and write, and replicas keep logs of transactions and vote. There are extensions from traditional databases that we can use to enhance performance or allow additional features. The extensions are added in a trust-minimized way, so that the security of the network relies on the security of pod-core.&lt;&#x2F;p&gt;
&lt;p&gt;We can use secondaries, separating the computers handling the read and write instructions. The secondaries are untrusted, read-only nodes that serve the requests from clients. They receive signed updates from write nodes (validators), keep them cached, and forward them to suscribed nodes. They do not sign any messages and the only thing they could do is stop responding. In that case, the user just switches to another secondary for the same validator.&lt;&#x2F;p&gt;
&lt;p&gt;Even though the reads are no longer handled by the validators, clients need to send their writes to all the validators, which is neither practical nor economical. We can solve this by incorporating untrusted gateways, which maintain an open connection to all validators. When clients want to submit a transaction, they reach the gateway and it then forwards to all validators, receives the signatures back, assembles a certificate consisting of at least $\alpha$ signatures and sends everything back to the client. Gateways do not sign transactions and, if they refuse to send transactions, the client may switch to another.&lt;&#x2F;p&gt;
&lt;p&gt;We can also reduce the amount of data storage by active validators using Merkle Mountain Ranges, reducing the requirements to run a validator, which, in turn, helps in increasing the decentralization of the network.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;implications-for-blockchain-design&quot;&gt;Implications for Blockchain Design&lt;&#x2F;h2&gt;
&lt;p&gt;For blockchain designers, the key takeaway is that any system optimized solely for high TPS may still fall short if its consensus mechanism introduces significant delays. Pod’s design philosophy—achieving optimal latency (2δ) through a consensusless, client-driven approach—addresses this by focusing on the true metric of performance: time-to-finality.&lt;&#x2F;p&gt;
&lt;p&gt;In practical terms, this means that blockchain systems need to:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Optimize for Low Latency:** Rather than simply increasing the number of transactions that can be processed per second, developers should strive to reduce the number of communication rounds required for consensus.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Minimize Overhead:** Eliminating unnecessary inter-node communication (as Pod does) can lead to dramatic improvements in confirmation times.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Reevaluate Throughput Metrics:** Marketing a blockchain based solely on TPS can be misleading; metrics such as average confirmation time and the worst-case time-to-finality are more indicative of real-world performance.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;real-time-auctions-and-the-limitations-of-leader-based-consensus&quot;&gt;Real-Time Auctions and the Limitations of Leader-Based Consensus&lt;&#x2F;h2&gt;
&lt;p&gt;Another critical application domain where consensus latency plays a central role is that of real-time auctions. Traditional blockchains are ill-suited for auctions because of inherent delays and vulnerabilities associated with leader-based ordering. In this section, we explore the challenges that auctions face in blockchain environments and how alternative consensus approaches can provide a better foundation for auction applications.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;auctions-in-the-blockchain-ecosystem&quot;&gt;Auctions in the Blockchain Ecosystem&lt;&#x2F;h2&gt;
&lt;p&gt;Auctions have long been a cornerstone of economic activity—from art sales to spectrum auctions—and have found numerous applications in the blockchain space:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **MEV (Maximal Extractable Value):** On Ethereum, there are auctions where block builders compete for the right to capture extra value through transaction ordering.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Decentralized Finance (DeFi):** Protocols like CowSwap, UniswapX, and dYdX employ auction mechanisms to determine optimal order flows and to settle trades.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Liquidation Auctions:** Lending protocols such as MakerDAO and Aave rely on auctions to liquidate collateral when borrowers fall below required thresholds.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Sequencing Rights:** Emerging systems like Espresso auctions share sequencing rights among multiple Layer 2 (L2) solutions, attempting to maximize throughput and fairness.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Despite these varied applications, the common thread is that the auction outcome depends critically on the ordering of bids and the rapid inclusion of all valid bids before a deadline.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;vulnerabilities-of-leader-based-consensus-in-auctions&quot;&gt;Vulnerabilities of Leader-Based Consensus in Auctions&lt;&#x2F;h2&gt;
&lt;p&gt;Most blockchains today rely on a leader-based architecture where one node (or a small group of nodes) is entrusted with proposing the next block. This design, while effective for ensuring global consensus, introduces several vulnerabilities in auction scenarios:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Censorship:** A leader has the power to censor transactions. In an auction, a leader might suppress competing bids to ensure that a colluding party wins the auction.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Last-Look Attacks:** In a leader-based system, a malicious leader can wait until the deadline to observe the current set of bids, then insert its own bid that is just slightly higher. This “last-look” strategy can subvert the fairness of the auction.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Delayed Finality:** The multiple rounds required for consensus in traditional systems can lead to delays that are unacceptable for real-time auctions. If bids are finalized too slowly, the auction outcome may not reflect the true state of the market at the moment of settlement.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;a-consensusless-approach-for-auctions&quot;&gt;A Consensusless Approach for Auctions&lt;&#x2F;h2&gt;
&lt;p&gt;Given the shortcomings of leader-based consensus for auctions, the pod protocol presents a promising alternative. By eliminating the need for inter-replica communication during the transaction write phase, Pod can:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Reduce Finality Delays:** With a target of 2δ latency, auctions can be concluded almost in real time, making them suitable for high-frequency and high-stakes bidding.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Mitigate Censorship and Reordering:** Since there is no single leader with unilateral control over the ordering of transactions, the risk of censorship or last-look manipulation is greatly reduced.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Enable Local Computation of Auction Outcomes:** In Pod, clients (or auctioneers) can collect the logs from various replicas and compute the set of bids. Since the ordering is not strictly enforced globally, the auction outcome is derived from the aggregated bid set—a process that is inherently more robust against adversarial manipulation.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The “past-perfection” property of Pod ensures that once bids are confirmed, they remain in the ledger permanently. This is particularly important for auctions, where the integrity of the bid set is paramount.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;benefits-for-decentralized-auctions&quot;&gt;Benefits for Decentralized Auctions&lt;&#x2F;h2&gt;
&lt;p&gt;Transitioning to a consensusless model for auctions offers several compelling benefits:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Faster Settlement:** Auctions can be resolved in near real time, enhancing user experience and enabling new business models such as flash auctions or real-time bidding for digital advertising.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Fairer Outcomes:** By removing the centralized role of the block proposer, the auction system becomes less prone to manipulation, ensuring that all valid bids are considered equally.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Enhanced Accountability:** Any attempt to censor or manipulate bids can be traced to specific replicas, ensuring that misbehavior is detectable and punishable.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;These features not only improve the functioning of existing auction mechanisms but also open up possibilities for innovative auction-based applications that require extremely low latency and high fairness.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;The landscape of blockchain technology is undergoing a profound transformation. Traditional consensus protocols, which have served as the backbone of early blockchain systems, are being reimagined to meet the demands of modern applications that require both high throughput and ultra-low latency. In this post, we have explored several ideas:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Pod’s Novel Approach:** By eliminating inter-replica communication during transaction submission and leveraging client-side aggregation of replica logs, Pod achieves transaction confirmation within the physical lower bound of 2δ. This design not only minimizes latency but also enhances censorship resistance and accountability.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Reevaluating Blockchain Performance:** The oft-cited metric of TPS (transactions per second) does not capture the true performance of a blockchain. Instead, time-to-finality—the time it takes for a transaction to be irrevocably confirmed—is an additional measure.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Challenges in Real-Time Auctions:** Leader-based consensus protocols have inherent vulnerabilities that make them unsuitable for applications such as real-time auctions. By adopting a consensusless model, as demonstrated by Pod, these applications can achieve rapid confirmation and mitigate risks such as censorship and last-look attacks.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</description>
      </item>
      <item>
          <title>Responsible disclosure: A potential sequencer-prover inconsistency in the Cairo VM</title>
          <pubDate>Fri, 07 Feb 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/responsible-disclosure-a-potential-sequencer-prover-inconsistency-in-the-cairo-vm/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/responsible-disclosure-a-potential-sequencer-prover-inconsistency-in-the-cairo-vm/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/responsible-disclosure-a-potential-sequencer-prover-inconsistency-in-the-cairo-vm/">&lt;h2 id=&quot;overview&quot;&gt;Overview&lt;&#x2F;h2&gt;
&lt;p&gt;On Sunday, January 26th, Starkware informed us that they had found a critical issue in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;cairo-vm&quot;&gt;Cairo VM&lt;&#x2F;a&gt; related to a program that would successfully execute on the VM but would violate the AIR constraints. The bug was found while investigating a separate issue reported by a third party and a fix was already implemented in a PR. The PR was merged, and a release was cut, which is already updated. You can read Starkware’s disclosure post &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;community.starknet.io&#x2F;t&#x2F;remediating-a-potential-sequencer-prover-inconsistency-in-the-cairo-vm&#x2F;115313&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;technical-implementation&quot;&gt;Technical Implementation&lt;&#x2F;h3&gt;
&lt;p&gt;The fix in pull request &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;cairo-vm&#x2F;pull&#x2F;1925&quot;&gt;#1925&lt;&#x2F;a&gt; adds two changes:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Additional verification while decoding instructions&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Additional verification on `verify_secure_runner`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;instruction-decoding-call-instruction&quot;&gt;Instruction Decoding**: Call Instruction**&lt;&#x2F;h4&gt;
&lt;p&gt;The call instruction does roughly the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Saves the current frame pointer to `[ap]`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Saves the call return address to `[ap + 1]`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Updates both `fp` and `ap` to `ap + 2`, skipping over the saved data.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Updates the `pc` to the start of the target function&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As some of the flags of the call instruction are fixed, we can verify that:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The `dst` register holds `ap+0`, where the current frame pointer will be stored.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dst_register == AP&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dst_offset   == 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The `op0` register holds `ap+1`, where the call return address will be stored.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;op0_register == AP&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;op0_offset   == 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Both `fp` and `ap` are updated to `ap+2`:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ap_update == Add2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fp_update == APPlus2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If these conditions are not met, the decoding fails.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;instruction-decoding-return-instruction&quot;&gt;Instruction Decoding**: Return Instruction**&lt;&#x2F;h4&gt;
&lt;p&gt;The return instruction does roughly the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Restores the previous frame pointer (at `[fp - 2]`)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Jumps to the call return address (at `[fp - 1]`)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As some of the flags of the return instruction are fixed, we can verify that:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The program counter is updated with an absolute jump&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pc_update == Jump&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The jump location is taken from `res`, which equals `fp-1`:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;res_logic   == Op1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;op1_offset  == -1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;op1_address == FP&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The next frame pointer is taken from `dst`, which equals `fp-2`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fp_update    == Dst&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dst_register == FP&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dst_offset   == -2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If these conditions are not met, the decoding also fails.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;conditional-jump&quot;&gt;Conditional Jump&lt;&#x2F;h4&gt;
&lt;p&gt;This PR also enforces that when &lt;code&gt;pc_update&lt;&#x2F;code&gt; is equal to &lt;code&gt;4&lt;&#x2F;code&gt; (conditional jump), then &lt;code&gt;res_logic&lt;&#x2F;code&gt; must equal &lt;code&gt;0&lt;&#x2F;code&gt; (which implies ignoring that field).&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;This behavior is documented in the Cairo Whitepaper, page 33:&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;if pc_update == 4:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if res_logic == 0 &amp;amp;&amp;amp; opcode == 0 &amp;amp;&amp;amp; ap_update != 1:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        res = Unused&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    else:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Undefined Behavior&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;secure-runner-verification&quot;&gt;&lt;strong&gt;Secure runner verification&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;The &lt;code&gt;verify_secure_runner&lt;&#x2F;code&gt; function verifies that the completed run in a runner is safe to be relocated and used by other Cairo programs.&lt;&#x2F;p&gt;
&lt;p&gt;The PR verifies that the final frame pointer coincides with the caller’s frame pointer, stored at &lt;code&gt;[initial_frame_pointer - 2]&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * When using `ExecutionMode::ProofModeCanonical`, the whole address must match.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * When using `ExecutionMode::RunnerMode`, only the offset must match.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;impact-analysis&quot;&gt;Impact Analysis&lt;&#x2F;h3&gt;
&lt;p&gt;As noted in Starkware’s &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;community.starknet.io&#x2F;t&#x2F;remediating-a-potential-sequencer-prover-inconsistency-in-the-cairo-vm&#x2F;115313&quot;&gt;release&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;”Since the missing check was in the sequencer and not the prover this has no implication whatsoever on the correctness or security of Starknet. In theory, it could have created a situation that a transaction that appears to have passed will later be reverted (reorg)”&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;the main risk was having transactions from &lt;code&gt;Cairo0&lt;&#x2F;code&gt; contracts execute on the sequencer and revert instead of being proved. Since the transaction would not pass the prover there is no risk of incorrect transaction being proved but the revert would impact user experience.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;As we’ve stated before, issues such as this one are always possible and likely in complex software and highlight the importance of having multiple teams paying attention to security, close collaboration between them, having simple codebases, and scrutinizing the interactions between components.&lt;&#x2F;p&gt;
&lt;p&gt;Many thanks to Starkware for the notice and quick fix!&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Summary on rStar-Math: showing how smaller LLMs can outperform bigger ones with deep thinking</title>
          <pubDate>Tue, 28 Jan 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/summary-on-rstar-math-showing-how-smaller-llms-can-outperform-bigger-ones-with-deep-thinking/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/summary-on-rstar-math-showing-how-smaller-llms-can-outperform-bigger-ones-with-deep-thinking/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/summary-on-rstar-math-showing-how-smaller-llms-can-outperform-bigger-ones-with-deep-thinking/">&lt;p&gt;&lt;strong&gt;TL;DR&lt;&#x2F;strong&gt; : this post addresses the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;pdf&#x2F;2501.04519&quot;&gt;paper introducing rStar-Math&lt;&#x2F;a&gt; and the techniques for smaller language models to outperform more complex large language models on math-related tasks. You can check the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;zhentingqi&#x2F;rStar&quot;&gt;code here&lt;&#x2F;a&gt;. rStar-Math significantly improved the math reasoning abilities of SLMs. For instance, on the MATH benchmark, it enhanced Qwen2.5-Math-7B’s performance from 58.8% to 90.0% and Phi3-mini-3.8B’s from 41.4% to 86.4%, surpassing OpenAI’s o1-preview model. Additionally, on the USA Math Olympiad (AIME), rStar-Math solved an average of 53.3% of problems, ranking among the top 20% of high school math students.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;Large Language Models (LLMs) are advanced artificial intelligence systems designed to understand, generate, and manipulate human language. They are trained on extensive datasets comprising billions of words, enabling them to perform a wide range of language-related tasks.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Key Characteristics of LLMs:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Scale:** LLMs contain many parameters ranging from millions to billions, allowing them to capture intricate patterns and nuances in language.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Training Data:** These models are trained on diverse and extensive text corpora, including books, articles, websites, and other textual sources, providing them with a broad understanding of language usage across different contexts.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Capabilities:** LLMs can perform various tasks such as text generation, translation, summarization, question-answering, and more, often with human-like proficiency.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Underlying Architecture:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Most LLMs are built upon the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;pdf&#x2F;1706.03762&quot;&gt;Transformer architecture&lt;&#x2F;a&gt;, introduced in 2017. This architecture uses self-attention to process and generate language efficiently, enabling models to consider the context of words in a sentence and capture long-range dependencies. One great advantage of transformers is that learning transfer can be very effective. Thus, we can train a model using large amounts of data and then train it in some other tasks using fine-tuning. An LLM that can be adapted to solve multiple different tasks is known as a foundational model. To process data, it must be first transformed into a sequence of tokens.&lt;&#x2F;p&gt;
&lt;p&gt;Most state-of-the-art LLM use the decoder part of the transformer, stacked several times (for example, 24, 48, 72, 100, etc). Each decoder contains the following elements:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Masked self-attention** : A multi-head attention sub-layer with a causal mask to ensure tokens cannot attend to future positions (we will explain these terms soon).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Feed-forward network** : A position-wise two-layer MLP with a nonlinearity.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Residual Connections** and **Layer Normalization** around each sub-layer.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;A minimal schematic for decoder layer $m$ is:&lt;br &#x2F;&gt;
$\mathbf{H_{ att }}^m = \mathrm{MHA}( \mathbf{H}^{m - 1 })$&lt;&#x2F;p&gt;
&lt;p&gt;$\mathbf{H_{addnorm}}^m = \mathrm{Layer Normalization}(\mathbf{H}^{m - 1} + \mathbf{H_{att}}^m)$&lt;&#x2F;p&gt;
&lt;p&gt;$\mathbf{H_{ffn}}^m = \mathrm{FFN} (\mathbf{H_{addnorm}}^m)$&lt;&#x2F;p&gt;
&lt;p&gt;$\mathbf{H}^m = \mathrm{Layer Normalization}( \mathbf{H_{addnorm }}^m + \mathbf{H_{ffn}}^m)$&lt;br &#x2F;&gt;
MHA denotes the multi-head attention function, LayerNormalization is the normalization function, and FFN is the feed-forward neural network.&lt;&#x2F;p&gt;
&lt;p&gt;The attention works by relating three elements: keys, queries, and values, which come from suitable transformations of the layer inputs. These transformations are linear, and the elements of the matrices should be learned by the model:&lt;br &#x2F;&gt;
$\mathbf{Q} = \mathbf{H}^{m - 1} W_Q$&lt;br &#x2F;&gt;
$\mathbf{K} = \mathbf{H}^{m - 1} W_K$&lt;br &#x2F;&gt;
$\mathbf{V} = \mathbf{H}^{m - 1} W_V$&lt;&#x2F;p&gt;
&lt;p&gt;The attention mechanism compares the keys and queries to find the best value match. One way to find a correlation between two vectors is via the cosine of the angle formed by queries and keys,&lt;br &#x2F;&gt;
$$\cos (\theta) = \frac{\mathbf{Q^t} \mathbf{K}}{\lVert\mathbf{Q} \rVert \lVert \mathbf{K} \rVert}$$&lt;br &#x2F;&gt;
The scalar product between two vectors shows how correlated they are. In LLMs, we use the softmax function, which ensures that the activations will be positive and, at most 1:&lt;br &#x2F;&gt;
$$a_{nm} = \frac{\exp(x_n^t x_m )}{\sum \exp(x_n^t x_l )}$$&lt;&#x2F;p&gt;
&lt;p&gt;There are two necessary adjustments to attention: scaling and causality. The first one is needed to rescale the arguments of the softmax function and avoid getting vanishingly small gradients. Causality ensures that a token cannot attend to future tokens so that the model can only use current or previous tokens, enabling autoregressive generation. Thus,&lt;br &#x2F;&gt;
$\mathbf{H}_{att,s} = \mathrm{attention}(\mathbf{Q}, \mathbf{K}, \mathbf{V}) = \mathrm{softmax}\left( \frac{\mathbf{Q} \mathbf{K}^t}{\sqrt{d_k}} + \mathbf{M} \right) \mathbf{V}$&lt;br &#x2F;&gt;
where $\mathbf{M}$ is the mask, which makes all the positions where a token should not attend future tokens equal to $- \infty$ (so that when we apply the softmax function, those elements are equal to zero). $d_k$ is the length of the key vector.&lt;&#x2F;p&gt;
&lt;p&gt;The multi-head attention function has $h$ different heads (each with its key, query, and value matrices). It concatenates the results of each head (basically gluing them one after the other) and applies a matrix $\mathbf{W}^o$,&lt;br &#x2F;&gt;
$head_i = \mathrm{attention}(\mathbf{H}^{m - 1} \mathbf{Q}^i , \mathbf{H}^{m - 1} \mathbf{K}^i , \mathbf{H}^{m - 1} \mathbf{V}^i )$&lt;br &#x2F;&gt;
$H_{att} = \mathrm{concatenate} \left( head_1 , head_2 , \dots head_h \right) \mathbf{W}^o$&lt;&#x2F;p&gt;
&lt;p&gt;After attention and normalization, each token’s representation goes through a &lt;strong&gt;position-wise&lt;&#x2F;strong&gt; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Multilayer_perceptron&quot;&gt;MLP&lt;&#x2F;a&gt; (applied identically to each sequence position, hence “position-wise”):&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\mathbf{z} = \mathbf{h} , W_1 + \mathbf{b}_1,&lt;br &#x2F;&gt;
\quad&lt;br &#x2F;&gt;
\mathbf{z}’ = \sigma(\mathbf{z}),&lt;br &#x2F;&gt;
\quad&lt;br &#x2F;&gt;
\mathbf{h}’ = \mathbf{z}’ , W_2 + \mathbf{b}_2,&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
where:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $\mathbf{h} \in \mathbb{R}^{d}$ is a single token’s representation from the attention sub-layer.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $W_1 \in \mathbb{R}^{d \times d_{\text{ff}}}$, $W_2 \in \mathbb{R}^{d_{\text{ff}} \times d}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $\sigma$ is typically a **GELU** (Gaussian error linear unit) or **ReLU** ([rectified linear unit](https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Rectifier_\(neural_networks\))) nonlinearity (activation function).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * This is done for each position independently, so in matrix form:  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$\text{FFN}(\mathbf{H}) ;=; \max\bigl(0,,\mathbf{H},W_1 + \mathbf{b}_1\bigr),W_2 + \mathbf{b}_2.$$&lt;&#x2F;p&gt;
&lt;p&gt;Before reading text or images, they have to be transformed into tokens. Let the input be a sequence of tokens:&lt;br &#x2F;&gt;
$(x_1, x_2, \dots, x_T),$&lt;br &#x2F;&gt;
where each $x_i$ is an integer index into a vocabulary. We map each $x_i$ to a &lt;strong&gt;d&lt;&#x2F;strong&gt; -dimensional embedding vector:&lt;br &#x2F;&gt;
$\mathbf{E}(x_i) \in \mathbb{R}^d.$&lt;br &#x2F;&gt;
Thus, the input sequence is transformed into an embedding matrix:&lt;br &#x2F;&gt;
$\mathbf{X} ;=;&lt;br &#x2F;&gt;
\bigl[&lt;br &#x2F;&gt;
\mathbf{E}(x_1);, \mathbf{E}(x_2);, \ldots; ,\mathbf{E}(x_T)&lt;br &#x2F;&gt;
\bigr]&lt;br &#x2F;&gt;
;\in; \mathbb{R}^{T \times d}.$&lt;&#x2F;p&gt;
&lt;p&gt;A decoder-only Transformer must still encode the notion of sequence position. Common methods include:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Learned positional embeddings** : A trainable $\mathbf{P}(i) \in \mathbb{R}^d$ for each position $i$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Sinusoidal (original Transformer)** :  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\begin{aligned}&lt;br &#x2F;&gt;
\text{PE}(i,,2k) &amp;amp;= \sin\Bigl(\tfrac{i}{10000^{2k&#x2F;d}}\Bigr),\quad&lt;br &#x2F;&gt;
\text{PE}(i,,2k+1) = \cos\Bigl(\tfrac{i}{10000^{2k&#x2F;d}}\Bigr).&lt;br &#x2F;&gt;
\end{aligned}&lt;br &#x2F;&gt;
$$
* &lt;strong&gt;Rotary Positional Embeddings (RoPE)&lt;&#x2F;strong&gt; : A rotation in the query&#x2F;key space (commonly used in GPT-NeoX, LLaMa, etc.).&lt;&#x2F;p&gt;
&lt;p&gt;Either way, the next step is typically:&lt;br &#x2F;&gt;
$\mathbf{H}^{(0)} = \mathbf{X} ;+; \mathbf{P},$&lt;br &#x2F;&gt;
where $\mathbf{P}$ indicates the positional information (shape $\mathbb{R}^{T \times d}$, same as $\mathbf{X}$).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Applications:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Natural Language Processing (NLP):** LLMs enhance various NLP tasks, including sentiment analysis, entity recognition, and language translation.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Content Creation:** They assist in generating articles, reports, and even creative writing, aiding authors and content creators.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Customer Service:** LLMs power chatbots and virtual assistants, providing human-like interactions in customer support scenarios.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Challenges and Considerations:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Despite their impressive capabilities, LLMs face challenges such as:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Resource Intensity:** Training and deploying LLMs require substantial computational resources, making them accessible primarily to large organizations.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Ethical Concerns:** Issues like the generation of biased or inappropriate content and the potential for misuse necessitate careful consideration and responsible deployment.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Interpretability:** Understanding the decision-making process of LLMs can be complex, raising concerns about transparency and trustworthiness.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In general, one would expect that the quality of the responses and LLM capabilities should be higher, given a greater set of parameters. The problem with this approach is that models become prohibitively expensive to train and fine-tune and cannot be run locally by users. The paper shows how a smaller LLM can outperform more powerful LLMs by using deep thinking and using the following concepts and ideas:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Code-Augmented Chain-of-Thought (CoT) Data Synthesis** : This method generates step-by-step verified reasoning trajectories by performing extensive Monte Carlo Tree Search (MCTS) rollouts. These trajectories are used to train the policy smaller language model (SLM), ensuring it learns accurate and logical reasoning steps.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Process Reward Model Training** : Instead of naïve step-level score annotation, the authors develop a more effective process preference model (PPM). This model evaluates the quality of reasoning steps, guiding the policy SLM to produce better solutions.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Self-Evolution Framework** : The policy SLM and PPM are built from scratch and iteratively evolved through multiple rounds. In each round, millions of synthesized solutions for a large set of math problems are generated, progressively enhancing the reasoning capabilities of the models.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It is important to note that while an LLM can provide a correct answer for a given problem, the reasoning may be flawed or contain invalid steps. Thus, it is essential that the model can learn how to avoid invalid steps along the way. rStar decouples reasoning into a generation-discrimination process. The following section will discuss the techniques used to train and improve the LLM.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;techniques&quot;&gt;Techniques&lt;&#x2F;h2&gt;
&lt;p&gt;rStar’s process involves generating alternative steps and reasoning about them. The main techniques are:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Monte Carlo Tree Search** (MCTS): [MCTS](https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Monte_Carlo_tree_search) is used during test-time to explore multiple reasoning paths. The policy SLM generates potential steps, and the PPM evaluates them, guiding the search towards the most promising solutions. MTCS is used because it breaks down problems into single-step generation tasks, yielding step-level training data for the LLM. Besides, this approach is simpler than Best-of-N or self-consistency, which requires generating full solutions at once.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Code-Augmented Data Synthesis** : By incorporating code execution into the data synthesis process, the system ensures the generated reasoning steps are verifiable and correct, providing high-quality training data for the policy SLM.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Process Preference Modeling (PPM)** : The PPM assesses the quality of intermediate reasoning steps, allowing the system to prefer more logical and accurate paths during the MCTS exploration.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Self-Evolution Strategy** : Through iterative training rounds, both the policy SLM and PPM are refined. Each round uses the outputs from the previous iteration to improve performance, enabling the models to develop advanced reasoning capabilities over time.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;MCTS is a decision-making algorithm used in complex domains such as board games (Go, Chess, Shogi), combinatorial optimization, and various planning problems. The key idea of MCTS is to incrementally build a search tree by running many simulated “playouts” (or rollouts) from a given state and using the simulation results to guide which parts of the tree should be explored more deeply. The four steps for MCTS are:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Selection** : Starting at the root node (the current game state), select child nodes down the tree according to a selection policy that balances exploration (trying less-visited moves) and exploitation (focusing on moves that appear promising). The Upper Confidence Bound for Trees (UCT) is a standard selection policy.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Expansion** : When you reach a node that is not a terminal state and has unvisited child states (moves), expand one (or more) of those child nodes in the tree.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Simulation (Rollout)** : From the expanded node, simulate a random (or semi-random) sequence of moves until reaching a terminal state (i.e., game over or a pre-defined depth for non-terminal states). The outcome of this simulation (win&#x2F;lose&#x2F;draw or another reward measure) is recorded.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Backpropagation** : Propagate the simulation’s result back up through the visited nodes in the tree, updating statistics (e.g., total reward, visit counts). This information is used to inform the next selection step.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this case, the LLM first generates the MCTS with a set of human reasoning actions to build higher quality reasoning trajectories such as:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Propose a one-step thought**.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Complete reasoning thought**.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Propose subquestions and answer**.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Re-answer the subquestion**.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Rephrase the question**.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;These are typical actions that we as humans do to solve complex tasks. We rephrase or find related questions that can help us shed new light on the problem.&lt;&#x2F;p&gt;
&lt;p&gt;A second LLM verifies each trajectory proposed by the first one and assesses their validity. If there is an agreement between both, the trajectories can be considered mutually consistent and valid with high likelihood. This resembles working with peers and checking each other’s answers. Since each step contains Python code, only those nodes with successful code execution are kept. These high-quality trajectories will be used as part of the training set.&lt;&#x2F;p&gt;
&lt;p&gt;The authors introduce a method to provide step-by-step verified trajectories with per-step Q-value annotations. They use four rounds of self-evolution: the first two are terminal-guided MCTS (since the PPM still has not been trained), while the next two rely on the trained PPM. Starting from the tree’s root (the original query), the LLM generates different alternative steps and annotates each with a Q-value. The process proceeds until the LLM reaches a solution corresponding to a tree leaf, $s_d$. Each $s_d$ contains a sequence of steps linking it to the root, corresponding to a single trajectory. Initially, all Q-values are set to $0$. We generate each new level of the tree until we get to the first leaf (terminal node) and reward it according to whether it got to the correct answer. Then, this score is backpropagated to all the steps in the trajectory, according to $Q(s_k ) = Q(s_k ) + Q(s_d )$. As we get more valid trajectories going through a node, the higher its $Q$ value. Finally, the LLM takes $n$ high-quality of these trajectories to use as training data.&lt;&#x2F;p&gt;
&lt;p&gt;Upper Confidence Bound for Trees (UCT) balances exploration and exploitation. For a node $k$, its UCT value is computed as&lt;br &#x2F;&gt;
$$UCT(k) = \frac{W_k }{N_k} + c \sqrt{\frac{\ln (N_p )}{\ln (N_k )}}$$&lt;&#x2F;p&gt;
&lt;p&gt;where $W_k$ is the total reward of node $k$, $N_k$ is the number of times node $k$ has been visited, $N_p$ is the number of times the parent node of $k$ has been visited and $c$ is a constant. A higher value of $c$ favors exploration. The first term focuses on the reward of the node (exploitation), while the second one encourages exploration by penalizing nodes with high visit counts relative to its parent. The reward will first be given from the terminal and later by the PPM. The authors introduce a novel training method based on positive-negative preference pairs.&lt;&#x2F;p&gt;
&lt;p&gt;Since SLM have weaker capabilities, the authors used four rounds of MCTS deep thinking to generate progressively higher quality data and extend the training set with more challenging problems:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Round 1** : Bootstrapping an initial strong policy model, SML-r1. This uses terminal annotated Q-values and performs 8 MCTS rollouts for efficiency. The data obtained is used to train PPM-r1.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Round 2** : Training a reliable PPM PPM-r2. Using PPM-r1, the authors conduct lots of MCTS with 16 rollouts per problem.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Round 3** : PPM-augmented MCTS for improved data quality. Using PPM-r2, the model tackles more complex problems and generates additional data to train PPM-r3.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Round 4** : Solving more challenging problems. For unsolved problems, the authors increase the number of rollouts to 64 or 128 and produce different MCTS with various initial seeds. This step boosts the success rate of the math model.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;results&quot;&gt;Results&lt;&#x2F;h2&gt;
&lt;p&gt;After four rounds of self-evolution, rStar-Math significantly improved the math reasoning abilities of SLMs. For instance, on the MATH benchmark, it enhanced Qwen2.5-Math-7B’s performance from 58.8% to 90.0% and Phi3-mini-3.8B’s from 41.4% to 86.4%, surpassing OpenAI’s o1-preview model. Additionally, on the USA Math Olympiad (AIME), rStar-Math solved an average of 53.3% of problems, ranking among the top 20% of high school math students. The following graphs compare the performance of rStar-math in different benchmarks with other LLMs based on the number of rollouts.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;SyLxqMdP1x.png&quot; alt=&quot;image&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;LLMs have shown great capabilities in understanding human language, image generation, and developing agents to perform various tasks. While their performance and accuracy have increased, this has been at the cost of a larger number of parameters, increasing training and inference costs and making it impossible for users to run them locally or fine-tune them to perform a particular task. Another important point is that LLMs can hallucinate, providing invalid answers or giving the right answer with flawed reasoning. This work explores how to use deep thinking with smaller LLM to improve performance, which could enable users to run the model locally or even fine-tune it. Using Monte Carlo Tree Search, scoring strategies based on Go engines, and code-augmented data, rStar-math achieves performance similar to that of much larger LLMs. In summary, rStar-Math demonstrates that with innovative training and reasoning strategies, small language models can achieve state-of-the-art performance in mathematical reasoning tasks, rivaling or surpassing larger models.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Responsible  disclosure of an exploit in Succinct&#x27;s SP1 zkVM, found in partnership with 3MI Labs and Aligned, which arises from the interaction of two distinct security vulnerabilities.</title>
          <pubDate>Sun, 26 Jan 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/responsible-disclosure-of-an-exploit-in-succincts-sp1-zkvm-found-in-partnership-with-3mi-labs-and-aligned-which-arises-from-the-interaction-of-two-distinct-security-vulnerabilities/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/responsible-disclosure-of-an-exploit-in-succincts-sp1-zkvm-found-in-partnership-with-3mi-labs-and-aligned-which-arises-from-the-interaction-of-two-distinct-security-vulnerabilities/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/responsible-disclosure-of-an-exploit-in-succincts-sp1-zkvm-found-in-partnership-with-3mi-labs-and-aligned-which-arises-from-the-interaction-of-two-distinct-security-vulnerabilities/">&lt;p&gt;&lt;strong&gt;TL;DR&lt;&#x2F;strong&gt; : We found two security bugs that can be combined to perform an exploit in Succinct’s SP1 zkVM, which allows you to generate false proofs. In severe cases, this could lead to loss of funds. This was found thanks to a collaboration between the top notch research &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.3milabs.tech&#x2F;&quot;&gt;3MI Labs&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;alignedlayer.com&#x2F;&quot;&gt;Aligned&lt;&#x2F;a&gt;, and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;lambdaclass.com&#x2F;&quot;&gt;LambdaClass&lt;&#x2F;a&gt;. This is a different security bug from the one we informed &lt;a href=&quot;&#x2F;the-future-of-zk-is-in-risc-v-zkvms-but-the-industry-must-be-careful-how-succincts-sp1s-departure-from-standards-causes-bugs&#x2F;&quot;&gt;previously in our blog&lt;&#x2F;a&gt; and it highlights the importance of having multiple teams paying attention to security and working towards having simpler codebases. For a PoC of the exploit, see the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;PoC-exploit-SP1&quot;&gt;following repo&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;LambdaClass and Fuzzing Labs will invest in further investigating critical security bugs in zkVMs. We believe that codebases have become too complex and over-engineered and this gives rise to lots of bugs. We think that the industry is at risk if we do not invest, add more eyes and simplify codebases. The industry has become complacent when it comes to security and is being pushed by business decisions to rush into production use, leaving aside these security issues, which could lead to very serious consequences. In this post, we analyze the case of SP1, but we think that all zkVM’s codebases need to be simplified and follow the standards, lowering the attack surface. As mentioned, we will conduct a more thourough research on different zkVMs.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;We have seen in several engineering projects the development of long and complex codebases, with too many fearures and poor documentation and testing. Some people believe that having such codebases shows that you are smart, have excellent coding skills and given a lot of thought on everything. We think it otherwise: the proof of mastery lies in simplicity. Bugs will always happen in any project, but the chance of having critical bugs increases with codebase complexity and length in a nonlinear way: the longer and more complex, the more bugs and hard to predict behaviors you can have. During our analysis of zk virtual machines and proof systems, we found two security bugs that can be combined to produce an exploit allowing a malicious party to prove false statements. Basically, you could generate false proofs for programs and modify some public inputs, which, in a world were computation is to be verified on chain using this technology, could lead to several exploits and loss of funds.&lt;&#x2F;p&gt;
&lt;p&gt;From our point of view, these exploits arise from the complexity of the codebase, having many files with different constraints and the addition of several features and optimizations that bloat the codebase. We also believe that business decisions are trying to rush these systems into production, when we should still focus on improving their security and auditability. We think that more care needs to be taken when designing, developing and testing zk virtual machines that could be used in real world applications, especially when funds are at risk.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;description-of-the-exploits&quot;&gt;Description of the exploits&lt;&#x2F;h2&gt;
&lt;p&gt;Two bugs were identified in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;sp1-sdk&quot;&gt;&lt;code&gt;sp1-sdk&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; crate at version 3.4.0, the most recently published version at the time we started our analysis. We were able to exploit them to generate valid SP1 proofs of incorrect execution of an arbitrary program, which results in universal forgeries of proofs for arbitrary statements, even incorrect ones.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bug-descriptions&quot;&gt;Bug Descriptions&lt;&#x2F;h2&gt;
&lt;p&gt;This report describes two bugs:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * SP1-2.1: Unconstrained `committed_value_digest` without `COMMIT` syscalls&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * SP1-2.2: Unchecked `next_pc` Condition in First Layer of Recursion Tree&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;sp1-2-1-unconstrained-committed-value-digest-without-commit-syscalls&quot;&gt;SP1-2.1: Unconstrained &lt;code&gt;committed_value_digest&lt;&#x2F;code&gt; without &lt;code&gt;COMMIT&lt;&#x2F;code&gt; syscalls&lt;&#x2F;h3&gt;
&lt;p&gt;When an SP1 executor executes a guest program, the &lt;code&gt;COMMIT&lt;&#x2F;code&gt; syscalls(&lt;code&gt;0x00_00_00_10&lt;&#x2F;code&gt;) resulting from calls to &lt;code&gt;sp1_zkvm::io::commit()&lt;&#x2F;code&gt; are delayed to the end of the execution and emitted only when the &lt;code&gt;main&lt;&#x2F;code&gt; function &lt;em&gt;returns&lt;&#x2F;em&gt;.&lt;br &#x2F;&gt;
Since these syscalls are the only events that generate constraints on the &lt;code&gt;committed_value_digest&lt;&#x2F;code&gt; of the &lt;code&gt;ExecutionRecord&lt;&#x2F;code&gt;, this implies that if the execution of the program is halted before the return point of &lt;code&gt;main()&lt;&#x2F;code&gt;, then the &lt;code&gt;COMMIT&lt;&#x2F;code&gt; syscalls are never issued. As a result, the &lt;code&gt;committed_value_digest&lt;&#x2F;code&gt; remains initialised to the all-zero value and is not constrained during proof generation.&lt;&#x2F;p&gt;
&lt;p&gt;This absence of constraints on the digest of committed values during the execution of the program raises further questions on the compatibility of the verifier code of &lt;code&gt;sp1-sdk&lt;&#x2F;code&gt; with proofs of “arbitrary” program, but exploring this falls outside of the scope of this report.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;sp1-2-2-unchecked-next-pc-condition-in-first-layer-of-recursion-tree&quot;&gt;SP1-2.2: Unchecked &lt;code&gt;next_pc&lt;&#x2F;code&gt; Condition in First Layer of Recursion Tree&lt;&#x2F;h3&gt;
&lt;p&gt;In the verifying code for the first layer of the recursion tree, the condition &lt;code&gt;next_pc == 0&lt;&#x2F;code&gt; is not checked if a shard is indicated as containing a “complete” execution. However, this check is present in other recursion constraints (e.g., two-to-one proof compression, field-switch wrapping, proof-system switching).&lt;&#x2F;p&gt;
&lt;p&gt;Other checks exist that are performed on other code paths when &lt;code&gt;is_complete&lt;&#x2F;code&gt; is asserted but are missing from the first layer of the recursion tree; these may be critical to proof soundness, but were not used in our exploit. These can be found in &lt;code&gt;sp1_recursion_circuit::machine::complete::assert_complete&lt;&#x2F;code&gt; (for the recursive constraints) and &lt;code&gt;sp1_prover::verify::verify&lt;&#x2F;code&gt; (for the plain, uncompressed verification). These checks include whether:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * at least one execution shard is present&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * (execution) shard numbering is consecutive, and starts at one,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * the leaf challenger and the final reconstruct challenger match&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * the deferred proof digests are consistent, and&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * the cumulative sum is consistent.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;exploit-description&quot;&gt;Exploit Description&lt;&#x2F;h2&gt;
&lt;p&gt;Initially, an attempt to exploit SP1-2.1 was made by making an explicit &lt;code&gt;HALT&lt;&#x2F;code&gt; (&lt;code&gt;0x00_00_00_00&lt;&#x2F;code&gt;) syscall within &lt;code&gt;main()&lt;&#x2F;code&gt;.&lt;br &#x2F;&gt;
While this is not the methodology that was ultimately used, we note that making such explicit &lt;code&gt;HALT&lt;&#x2F;code&gt; syscalls within main might reasonably be passed off as an optimization within the guest program, e.g., by arguing that an early halt within main is a way to shorten a program’s execution trace and therefore reduce its proof computation time. This would seem innocent enough, but SP1-2.1 would then imply that the digest of public values produced before the syscall would remain unconstrained.&lt;&#x2F;p&gt;
&lt;p&gt;However, it suffices to instead create a malicious SP1 executor which stops executing the guest program at an arbitrary &lt;code&gt;pc&lt;&#x2F;code&gt; value. As long as the chosen &lt;code&gt;pc&lt;&#x2F;code&gt; value happens before the return point of &lt;code&gt;main()&lt;&#x2F;code&gt;, no &lt;code&gt;COMMIT&lt;&#x2F;code&gt; syscall will have been produced by the virtual machine. In the exploit presented here, the proof forgery was produced by stopping execution as soon as the program reached the start of the &lt;code&gt;main&lt;&#x2F;code&gt; function.&lt;&#x2F;p&gt;
&lt;p&gt;Before returning the resulting &lt;code&gt;ExecutionRecord&lt;&#x2F;code&gt;, the malicious executor is then free to replace the &lt;code&gt;committed_value_digest&lt;&#x2F;code&gt; of the &lt;code&gt;public_values: PublicValues&lt;&#x2F;code&gt; field with the digest of an arbitrary value. This makes it seem as if the guest program had committed to it during its execution.&lt;&#x2F;p&gt;
&lt;p&gt;Then, an honest &lt;code&gt;CoreProver&lt;&#x2F;code&gt; (&lt;code&gt;sp1_prover::components::SP1ProverComponents::CoreProver&lt;&#x2F;code&gt;) is run to generate an &lt;code&gt;SP1CoreProof&lt;&#x2F;code&gt; (&lt;code&gt;sp1_prover::types::SP1CoreProof&lt;&#x2F;code&gt;) with the maliciously crafted &lt;code&gt;ExecutionRecord&lt;&#x2F;code&gt;. Since there are no &lt;code&gt;COMMIT&lt;&#x2F;code&gt; syscalls contained within the record, the altered &lt;code&gt;committed_value_digest&lt;&#x2F;code&gt;, which does not match the digest of the values committed to by the program, does not cause the proof generation to fail. The &lt;code&gt;CoreProver&lt;&#x2F;code&gt; therefore successfully creates an &lt;code&gt;SP1CoreProof&lt;&#x2F;code&gt; containing two shards &lt;code&gt;s1&lt;&#x2F;code&gt; and &lt;code&gt;s2&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, a malicious &lt;code&gt;SP1Prover&lt;&#x2F;code&gt; (&lt;code&gt;sp1_prover::SP1Prover&lt;&#x2F;code&gt;) is created with the following two modifications:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. The second shard `s2` of the `SP1CoreProof` is discarded.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. The `is_complete` flag is set to `true` in the `SP1RecursionWitnessValues` created from the remaining first shard `s1`. This recursion witness is then used when generating the recursion program for compressing the `SP1CoreProof` with a `CompressProver`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Because the malicious executor stopped the guest program with a &lt;code&gt;next_pc&lt;&#x2F;code&gt; value pointing to the start of main, the first shard &lt;code&gt;s1&lt;&#x2F;code&gt; has a non-zero &lt;code&gt;next_pc&lt;&#x2F;code&gt; value. However, since the &lt;code&gt;is_complete&lt;&#x2F;code&gt; flag is &lt;code&gt;true&lt;&#x2F;code&gt;, SP1-2.2 implies that the &lt;code&gt;CompressProver&lt;&#x2F;code&gt; does not constrain the equality &lt;code&gt;next_pc ==0&lt;&#x2F;code&gt;, resulting in an &lt;code&gt;SP1ReduceProof&lt;&#x2F;code&gt; proof generated without errors. When de-serialized by an honest prover and submitted for verification, this &lt;code&gt;SP1ReduceProof&lt;&#x2F;code&gt; then passes &lt;em&gt;honest&lt;&#x2F;em&gt; verification for the guest program.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;exploit-demonstration&quot;&gt;Exploit demonstration&lt;&#x2F;h3&gt;
&lt;p&gt;We accompanied the bug report with two artefacts that demonstrate how the two bugs can be exploited to provide valid proofs of invalid execution of arbitrary programs. See the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;PoC-exploit-SP1&quot;&gt;repo for the code&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The is-prime directory contains the source files and compiled ELF version of a program(&lt;code&gt;.&#x2F;is-prime&#x2F;program&lt;&#x2F;code&gt;) which checks primality of a number read from &lt;code&gt;sp1_zkvm::io&lt;&#x2F;code&gt;, together with a script(&lt;code&gt;.&#x2F;is-prime&#x2F;script&lt;&#x2F;code&gt;) which demonstrates that &lt;code&gt;42-is-prime.proof&lt;&#x2F;code&gt;(&lt;code&gt;.&#x2F;is-prime&#x2F;script&#x2F;42-is-prime.proof&lt;&#x2F;code&gt;) is a valid proof that executing the program results in 42 being verified as a prime number.&lt;&#x2F;p&gt;
&lt;p&gt;The i-am-satoshi(&lt;code&gt;.&#x2F;i-am-satoshi&#x2F;&lt;&#x2F;code&gt;) directory contains a example of the transferability of this technique. Here, the guest program uses the independent &lt;code&gt;bitcoin&lt;&#x2F;code&gt; crate to compute the Bitcoin address corresponding to the secret key given as input, and then commits to the resulting address with &lt;code&gt;sp1_zkvm::io::commit()&lt;&#x2F;code&gt;. Running the corresponding &lt;code&gt;verifier program&lt;&#x2F;code&gt;(&lt;code&gt;.&#x2F;i-am-satoshi&#x2F;script&#x2F;src&#x2F;main.rs&lt;&#x2F;code&gt;) reveals that the proof demonstrates knowledge of the secret key behind the “genesis Satoshi address” &lt;code&gt;1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;This proof of concept illustrates arbitrary statement proving for the SP1 verifier, by verifying knowledge of the secret key to the reward address in the bitcoin genesis block. To perform these exploits, the prover client needs to be modified locally.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;consequences-and-limitations&quot;&gt;Consequences and Limitations&lt;&#x2F;h2&gt;
&lt;p&gt;While the first program presented in this exploit is innocent enough (42 is obviously not prime), the second one exemplifies more serious consequences.&lt;br &#x2F;&gt;
Proof of ownership of any address on any blockchain can be forged and would be accepted by a naïve verifier. We draw the attention to the fact that the program itself &lt;em&gt;was not modified&lt;&#x2F;em&gt;. All of the modifications to create the proof forgery were performed &lt;strong&gt;locally to the proving client&lt;&#x2F;strong&gt; which implies that this forgery methodology is generalizable to arbitrary guest programs.&lt;&#x2F;p&gt;
&lt;p&gt;We note that SP1-2.2 is a bug that is restricted to the first layer of the recursion tree, and that subsequent recursive proving of the proof would fail, because the &lt;code&gt;ShrinkProver&lt;&#x2F;code&gt; properly constrains the &lt;code&gt;next_pc == 0&lt;&#x2F;code&gt; check when &lt;code&gt;is_complete == true&lt;&#x2F;code&gt;.&lt;br &#x2F;&gt;
Nonetheless, the honest verifier code(&lt;code&gt;.&#x2F;is-prime&#x2F;script&#x2F;src&#x2F;bin&#x2F;verifier.rs&lt;&#x2F;code&gt;) is &lt;em&gt;agnostic&lt;&#x2F;em&gt; to the kind of proof that it deserializes which implies that the malicious prover is not forced to further reduce or wrap the forged proof before submitting it for verification to a system that runs the Rust verifier from the &lt;code&gt;sp1-sdk&lt;&#x2F;code&gt; crate.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;possible-mitigations&quot;&gt;Possible Mitigations&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;mitigating-sp1-2-1&quot;&gt;Mitigating SP1-2.1&lt;&#x2F;h3&gt;
&lt;p&gt;Mitigating SP1-2.1 requires making sure that the &lt;code&gt;committed_value_digest&lt;&#x2F;code&gt; is constrained within the proof system, even if no &lt;code&gt;COMMIT&lt;&#x2F;code&gt; syscalls are made.&lt;&#x2F;p&gt;
&lt;p&gt;Any implementation of this mitigation would conflict with the current implementation which assumes that &lt;code&gt;committed_value_digest&lt;&#x2F;code&gt; is written to only once. A concrete proposal requires further exploration of the possibilities which is outside of the scope of this report.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;mitigating-sp1-2-2&quot;&gt;Mitigating SP1-2.2&lt;&#x2F;h3&gt;
&lt;p&gt;Ultimately, the code for the recursion program should be patched so that the &lt;code&gt;next_pc == 0&lt;&#x2F;code&gt; constraint (and the other related constraints for complete programs) is applied by the &lt;code&gt;CompressProver&lt;&#x2F;code&gt; in the first layer of the recursion tree, just like it is in the other recursion programs.&lt;&#x2F;p&gt;
&lt;p&gt;As a hot fix which would not be a breaking change to currently accepted verification keys, since the &lt;code&gt;next_pc&lt;&#x2F;code&gt; value is accessible as part of a proof’s&lt;br &#x2F;&gt;
public values, the Rust code of the verifier should check that it is &lt;code&gt;0&lt;&#x2F;code&gt;, even if this isn’t constrained within the proof system. This hot fix would further enable existing verifiers to check whether this bug was triggered by proofs that are still in storage.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;Together with 3MI Labs and Aligned, we found two security bugs in Succinct’s SP1 zkVM, and showed how to use them to perform an exploit to generate false proofs that an honest verifier would accept. Since these exploits do not require to change the code of the program and are done locally, they could be used without naïve verifiers even suspecting it is a malicious proof. We think that the complexity and length of the codebase, as well as unclear documentation contribute to the proliferation of bugs, and that we should be working harder on simplifying the codebases and on security, instead of rushing into production due to business concerns, especially when funds could be at risk.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>LogUp lookup argument and its implementation using Lambdaworks for continuous read-only memory</title>
          <pubDate>Fri, 27 Dec 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/logup-lookup-argument-and-its-implementation-using-lambdaworks-for-continuous-read-only-memory/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/logup-lookup-argument-and-its-implementation-using-lambdaworks-for-continuous-read-only-memory/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/logup-lookup-argument-and-its-implementation-using-lambdaworks-for-continuous-read-only-memory/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;In a &lt;a href=&quot;&#x2F;continuous-read-only-memory-constraints-an-implementation-using-lambdaworks&#x2F;&quot;&gt;previous post&lt;&#x2F;a&gt;, we explained how to define constraints for a &lt;strong&gt;continuous read-only memory&lt;&#x2F;strong&gt; , presenting it as an example to understand how constraints are defined in general. This time, we will continue digging into this example to introduce the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2022&#x2F;1530&quot;&gt;LogUp&lt;&#x2F;a&gt; construction, adapted to univariate polynomials, and explain how we implemented it.&lt;&#x2F;p&gt;
&lt;p&gt;In what follows, we will assume that you have a notion of the concepts of constraints, a continuous read-only memory, and an idea of how they are implemented. To go deeper into these topics, we recommend reading the previously mentioned post, as this one will be its continuation.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-logup&quot;&gt;What is LogUp?&lt;&#x2F;h2&gt;
&lt;p&gt;LogUp is a case of a &lt;strong&gt;Lookup Argument&lt;&#x2F;strong&gt;. But what exactly are lookup arguments? They serve as a tool that allows us to prove efficiently that a specific value $v$ belongs to a table of values $T$ without revealing the entire table. This concept is handy for improving the efficiency of arguments for statements that are otherwise quite expensive to arithmetize.&lt;&#x2F;p&gt;
&lt;p&gt;In essence, a lookup argument enables the prover to convince the verifier that every element of a given set $A$ (often represented as a column of a trace table) is contained within another set $T$ (the lookup table). In this way, instead of having to arithmetize many constraints to ensure that $A$ satisfies certain conditions and is in a certain way, we precompute all the valid values that $A$ can have, write them in the table $T$ and then use a lookup argument to prove that all the elements of $A$ belong to $T$ (i.e., they are valid elements). In other words, we achieve to verify the relationship between data while preserving privacy or optimizing computation.&lt;&#x2F;p&gt;
&lt;p&gt;An example of a Lookup argument can be found in the &lt;a href=&quot;&#x2F;continuous-read-only-memory-constraints-an-implementation-using-lambdaworks&#x2F;&quot;&gt;post mentioned above&lt;&#x2F;a&gt;. Let’s quickly check what we did there: given two columns, $a$ (addresses) and $v$ (values), we needed to create their corresponding sorted columns $a’$ and $v’$. We used a Lookup argument known as &lt;strong&gt;Grand Product&lt;&#x2F;strong&gt; to prove that they were permutations of the original ones.&lt;br &#x2F;&gt;
Using two random elements $z$ and $\alpha$, sampled from an extension of $\mathbb{F}$, we constructed an auxiliary column $p$ using:&lt;&#x2F;p&gt;
&lt;p&gt;$$p_{i + 1} = p_i \cdot \frac {z - (a_{i + 1} + \alpha v_{i + 1})} {z - (a^\prime_{i + 1} + \alpha v^\prime_{i + 1})},$$&lt;&#x2F;p&gt;
&lt;p&gt;The goal was to verify that the last element of this column equals one:&lt;&#x2F;p&gt;
&lt;p&gt;$$p_{n - 1} = \prod_{i = 0}^{n - 1} \frac {z - (a_i + \alpha v_i)} {z - (a^\prime_i + \alpha v^\prime_i)} = 1.$$&lt;&#x2F;p&gt;
&lt;p&gt;This guarantees that $a’$ and $v’$ are permutations of $a$ and $v$, ensuring the correctness of the table.&lt;&#x2F;p&gt;
&lt;p&gt;The idea behind &lt;strong&gt;LogUp&lt;&#x2F;strong&gt; is to replace these products with their &lt;strong&gt;logarithmic derivatives&lt;&#x2F;strong&gt; , or more simply, to transform the product into a sum of fractions. This approach reduces the computational effort for both the prover and the verifier. The method gets its name because the logarithmic derivative converts products like $\prod_{i = 1}^n X - y_i$ into sums:&lt;&#x2F;p&gt;
&lt;p&gt;$$\sum_{i = 1}^n \frac{1}{X - y_i}.$$&lt;&#x2F;p&gt;
&lt;p&gt;So, suppose we have a column $a = (a_0, \ldots, a_n)$ from the main trace containing repeated elements and a column $t = (t_0, \ldots, t_m)$ from the lookup table without duplicates, and we want to demonstrate that all the elements of $a$ belong to $t$. In that case, it is enough to prove the equality:&lt;&#x2F;p&gt;
&lt;p&gt;$$\sum_{i = 0}^n \frac{1}{\alpha - a_i} = \sum_{i = 0}^m \frac{m_i}{\alpha - t_i}$$&lt;&#x2F;p&gt;
&lt;p&gt;where $\alpha$ is a random element, and $m_i$ is the multiplicity of $t_i$ in $a$, that is, the number of times $t_i$ appears in $a$.&lt;&#x2F;p&gt;
&lt;p&gt;A natural question might arise at this point: is it still more efficient to replace products with sums, mainly since doing so introduces fractions? We won’t work directly with these fractions, as we’ll see later. Instead, we’ll multiply both sides of the equation by the common denominator.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;continuous-read-only-memory-example&quot;&gt;Continuous read-only memory example&lt;&#x2F;h2&gt;
&lt;p&gt;To understand how the constraints of a LogUp argument are written, let’s go back to our example of a continuous read-only memory. To follow this example, we recommend accompanying it with the corresponding &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;blob&#x2F;logup-mem-example&#x2F;provers&#x2F;stark&#x2F;src&#x2F;examples&#x2F;read_only_memory_logup.rs&quot;&gt;implementation made in Lambdaworks&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;main-trace&quot;&gt;Main Trace&lt;&#x2F;h3&gt;
&lt;p&gt;First of all, we need to understand how the columns of the main trace are defined in the case of wanting to use a LogUp argument. We will proceed similarly to what we did in the first post. Given the address column $a$ and the value column $v$ of our memory, we will add three additional columns to the main trace: $a’,$ $v’$, and $m$. The $a’$ and $v’$ columns will contain the same values as $a$ and $v$ but will be sorted in ascending order without duplicating values. The column $m$ will represent the multiplicity of these values in the original columns. Since these columns do not have duplicates, they will be smaller. To ensure all columns have the same length and fit into a single table, we will pad $a’$ and $v’$ by repeating their last value and assigning a multiplicity of $0$ to these padded rows in the $m$ column.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s see an example. If our original table was:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;$a$&lt;&#x2F;th&gt;&lt;th&gt;$v$&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;30&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;20&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;40&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;30&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;30&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;The main trace would become:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;$a$&lt;&#x2F;th&gt;&lt;th&gt;$v$&lt;&#x2F;th&gt;&lt;th&gt;$a’$&lt;&#x2F;th&gt;&lt;th&gt;$v’$&lt;&#x2F;th&gt;&lt;th&gt;$m$&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;30&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;20&lt;&#x2F;td&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;20&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;40&lt;&#x2F;td&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;40&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;30&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;30&lt;&#x2F;td&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;30&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;30&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Notice that the original table does not represent a valid read-only memory (since address 2 has two different values, 20 and 40), we can still construct the main trace. Later, the &lt;code&gt;SingleValueConstraint&lt;&#x2F;code&gt; transition constraint will ensure that such tables are invalid.&lt;&#x2F;p&gt;
&lt;p&gt;In our implementation, the function &lt;code&gt;read_only_logup_trace()&lt;&#x2F;code&gt; handles the construction of the main trace. It returns a &lt;code&gt;TraceTable&lt;&#x2F;code&gt; containing the five main columns described above and an auxiliary column initially filled with zeros, which will later be replaced with the appropriate values.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; Return a trace table with an auxiliary column full of zeros (that will be then replaced with the correct values by the air) and&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; and the following five main columns: &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; The original addresses and values, the sorted addresses and values without duplicates, and&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; the multiplicities of each sorted address and value in the original ones (i.e., how many times they appear in the original address and value columns).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn read_only_logup_trace&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    F: IsPrimeField + IsFFTField + IsSubFieldOf&amp;lt;E&amp;gt; + Send + Sync,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    E: IsField + Send + Sync,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    addresses: Vec&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    values: Vec&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; TraceTable&amp;lt;F, E&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; We order the addresses and values.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut address_value_pairs: Vec&amp;lt;_&amp;gt; = addresses.iter().zip(values.iter()).collect();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    address_value_pairs.sort_by_key(|(addr, _)| addr.representative());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;We define the main columns that will be added to the original ones &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut multiplicities = Vec::new();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut sorted_addresses = Vec::new();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut sorted_values = Vec::new();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for (key, group) in &amp;amp;address_value_pairs.into_iter().group_by(|&amp;amp;(a, v)| (a, v)) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let group_vec: Vec&amp;lt;_&amp;gt; = group.collect();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        multiplicities.push(FieldElement::&amp;lt;F&amp;gt;::from(group_vec.len() as u64));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        sorted_addresses.push(key.0.clone());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        sorted_values.push(key.1.clone());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; We resize the sorted addresses and values with the last value of each one so they have the&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; same number of rows as the original addresses and values. However, their multiplicity should be zero.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    sorted_addresses.resize(addresses.len(), sorted_addresses.last().unwrap().clone());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    sorted_values.resize(addresses.len(), sorted_values.last().unwrap().clone());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    multiplicities.resize(addresses.len(), FieldElement::&amp;lt;F&amp;gt;::zero());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let main_columns = vec![&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        addresses.clone(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        values.clone(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        sorted_addresses,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        sorted_values,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        multiplicities,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; We create a vector of the same length as the main columns full with zeros from de field extension and place it as the auxiliary column.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let zero_vec = vec![FieldElement::&amp;lt;E&amp;gt;::zero(); main_columns[0].len()];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    TraceTable::from_columns(main_columns, vec![zero_vec], 1)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;auxiliary-trace&quot;&gt;Auxiliary Trace&lt;&#x2F;h3&gt;
&lt;p&gt;Now, let’s see how to construct the auxiliary column. The auxiliary column, which we’ll call $s$, should accumulate the sums of the fractions corresponding to each row of the main table as follows:&lt;&#x2F;p&gt;
&lt;p&gt;$$ \begin{align} s_0 &amp;amp;= \frac {m_0} {z - (a^\prime_0 + \alpha v^\prime_0)} - \frac {1} {z - (a_0 + \alpha v_0)},&lt;br &#x2F;&gt;
\ \newline&lt;br &#x2F;&gt;
s_1 &amp;amp;= s_0 + \frac { m_1 } {z - (a^\prime_1 + \alpha v^\prime_1)} - \frac {1} {z - (a_1 + \alpha v_1)} \end{align}$$&lt;&#x2F;p&gt;
&lt;p&gt;And so on, obtaining:&lt;&#x2F;p&gt;
&lt;p&gt;$$s_{i + 1} = s_i + \frac {m_{i + 1}} {z - (a^\prime_{i + 1} + \alpha v^\prime_{i + 1})} - \frac {1} {z - (a_{i + 1} + \alpha v_{i + 1})} \text{ with } i \in {0, \ldots, n - 2}.$$&lt;&#x2F;p&gt;
&lt;p&gt;As an example, if our main trace was:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;$a$&lt;&#x2F;th&gt;&lt;th&gt;$v$&lt;&#x2F;th&gt;&lt;th&gt;$a’$&lt;&#x2F;th&gt;&lt;th&gt;$v’$&lt;&#x2F;th&gt;&lt;th&gt;$m$&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;30&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;20&lt;&#x2F;td&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;20&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;30&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;20&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;30&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Then, our auxiliary column trace $s$ would look like this:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;$a$&lt;&#x2F;th&gt;&lt;th&gt;$v$&lt;&#x2F;th&gt;&lt;th&gt;$a’$&lt;&#x2F;th&gt;&lt;th&gt;$v’$&lt;&#x2F;th&gt;&lt;th&gt;$m$&lt;&#x2F;th&gt;&lt;th&gt;$s$&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;30&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;$\frac {1} {z - (1 + \alpha 10)} - \frac {1} {z - (3 + \alpha 30)}$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;20&lt;&#x2F;td&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;$s_0 + \frac {2} {z - (2 + \alpha 20)} - \frac {1} {z - (1 + \alpha 10)}$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;20&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;30&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;$s_1 + \frac {1} {z - (3 + \alpha 30)} - \frac {1} {z - (2 + \alpha 20)}$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;20&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;30&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;$s_2 + \frac {0} {z - (3 + \alpha 30)} - \frac {1} {z - (2 + \alpha 20)}$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Observe that if the main trace indeed represents a permutation with multiplicities, then the last element of $s$ (that is $s_{n - 1}$) should reflect the accumulation of all sums, canceling each other out and resulting in $0$ (i.e. $s_{n - 1} = 0$). This is analogous to what happens with the Grand Product, where we verify that the final product cancels out and results in 1 (i.e. $p_{n - 1} = 1$). Let’s see this in the context of the example from the table above:&lt;&#x2F;p&gt;
&lt;p&gt;$$ \begin{align}&lt;br &#x2F;&gt;
s_{n - 1} &amp;amp;= {\style{color: orange} {\frac {1} {z - (1 + \alpha 10)}}} - \style{color: cyan} {\frac {1} {z - (3 + \alpha 30)}}&lt;br &#x2F;&gt;
\newline&lt;br &#x2F;&gt;
&amp;amp;+ \style{color: magenta} {\frac {2} {z - (2 + \alpha 20)}} - {\style{color: orange} {\frac {1} {z - (1 + \alpha 10)}}}&lt;br &#x2F;&gt;
\newline&lt;br &#x2F;&gt;
&amp;amp;+ \style{color: cyan} {\frac {1} {z - (3 + \alpha 30)}} - \style{color: magenta} {\frac {1} {z - (2 + \alpha 20)}}&lt;br &#x2F;&gt;
\newline&lt;br &#x2F;&gt;
&amp;amp;+ \frac {0} {z - (3 + \alpha 30)} - \style{color: magenta} {\frac {1} {z - (2 + \alpha 20)}}&lt;br &#x2F;&gt;
\ \newline&lt;br &#x2F;&gt;
&amp;amp;= 0&lt;br &#x2F;&gt;
\end{align}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;Now, let’s see how this is implemented in our code. In Lambdaworks, the construction of the auxiliary trace is handled within the AIR implementation. Specifically, in the implementation of &lt;code&gt;LogReadOnlyRAP&lt;&#x2F;code&gt;, you can find the following function &lt;code&gt;build_auxiliary_trace()&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn build_auxiliary_trace(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;amp;self,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    trace: &amp;amp;mut TraceTable&amp;lt;Self::Field, Self::FieldExtension&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    challenges: &amp;amp;[FieldElement&amp;lt;E&amp;gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) where&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Self::FieldExtension: IsFFTField,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Main table&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let main_segment_cols = trace.columns_main();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let a = &amp;amp;main_segment_cols[0];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let v = &amp;amp;main_segment_cols[1];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let a_sorted = &amp;amp;main_segment_cols[2];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let v_sorted = &amp;amp;main_segment_cols[3];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let m = &amp;amp;main_segment_cols[4];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Challenges&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let z = &amp;amp;challenges[0];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let alpha = &amp;amp;challenges[1];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let trace_len = trace.num_rows();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut aux_col = Vec::new();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; s_0 = m_0&#x2F;(z - (a&amp;#39;_0 + α * v&amp;#39;_0) - 1&#x2F;(z - (a_0 + α * v_0)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let unsorted_term = (-(&amp;amp;a[0] + &amp;amp;v[0] * alpha) + z).inv().unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let sorted_term = (-(&amp;amp;a_sorted[0] + &amp;amp;v_sorted[0] * alpha) + z).inv().unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    aux_col.push(&amp;amp;m[0] * sorted_term - unsorted_term);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Apply the same equation given in the permutation transition constraint to the rest of the trace.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; s_{i+1} = s_i + m_{i+1}&#x2F;(z - (a&amp;#39;_{i+1} + α * v&amp;#39;_{i+1}) - 1&#x2F;(z - (a_{i+1} + α * v_{i+1})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for i in 0..trace_len - 1 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let unsorted_term = (-(&amp;amp;a[i + 1] + &amp;amp;v[i + 1] * alpha) + z).inv().unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let sorted_term = (-(&amp;amp;a_sorted[i + 1] + &amp;amp;v_sorted[i + 1] * alpha) + z)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .inv()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        aux_col.push(&amp;amp;aux_col[i] + &amp;amp;m[i + 1] * sorted_term - unsorted_term);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for (i, aux_elem) in aux_col.iter().enumerate().take(trace.num_rows()) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        trace.set_aux(i, 0, aux_elem.clone())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;transition-constraints&quot;&gt;Transition constraints&lt;&#x2F;h3&gt;
&lt;p&gt;Now, let’s look at how we should define the transition constraints for a continuous read-only memory using LogUp. The first two transition constraints explained in the previous post remain unchanged. That is, we don’t need to make any modifications to &lt;code&gt;ContinuityConstraint&lt;&#x2F;code&gt; and &lt;code&gt;SingleValueConstraint&lt;&#x2F;code&gt;, as the method for verifying that the memory is read-only and continuous using the $a’$ and $v’$ columns remains the same.&lt;&#x2F;p&gt;
&lt;p&gt;However, modifying the third constraint, called &lt;code&gt;PermutationConstraint&lt;&#x2F;code&gt; is essential. This constraint ensures that the auxiliary column $s$ is constructed correctly. It must be checked that $s_i$ satisfies the equation mentioned before:&lt;&#x2F;p&gt;
&lt;p&gt;$$s_{i+1} = s_i + \frac {m_{i+1}} {z - (a^\prime_{i + 1} + \alpha v^\prime_{i + 1})} - \frac {1} {z - (a_{i+1} + \alpha v_{i+1})} \text{ with } i \in {0, \ldots, n - 2}.$$&lt;&#x2F;p&gt;
&lt;p&gt;Since constraints must be expressed without division, we will multiply both sides of the equality by the common denominator. This transforms the constraint into the following form:&lt;&#x2F;p&gt;
&lt;p&gt;$$\begin{align}s_{i+1} &amp;amp;\cdot (z - (a^\prime_{i+1} + \alpha v^\prime_{i+1})) \cdot (z - (a_{i+1} + \alpha v_{i+1})) =&lt;br &#x2F;&gt;
\ \newline&lt;br &#x2F;&gt;
&amp;amp;=s_i \cdot (z - (a^\prime_{i+1} + \alpha v^\prime_{i+1})) \cdot (z - (a_{i+1} + \alpha v_{i+1}))&lt;br &#x2F;&gt;
\ \newline&lt;br &#x2F;&gt;
&amp;amp;+ m_{i+1} \cdot (z - (a_{i+1} + \alpha v_{i+1}))&lt;br &#x2F;&gt;
\ \newline&lt;br &#x2F;&gt;
&amp;amp;- (z - (a^\prime_{i+1} + \alpha v^\prime_{i+1}))&lt;br &#x2F;&gt;
\end{align}$$&lt;&#x2F;p&gt;
&lt;p&gt;Additionally, we will move the left-hand side of the equality to the right, subtracting it so that it can be interpreted as a polynomial in the variables $s$, $a$, $a’$, $v$ and $v’$ that is equal to zero:&lt;&#x2F;p&gt;
&lt;p&gt;$$\begin{align} 0 &amp;amp;=s_i \cdot (z - (a^\prime_{i+1} + \alpha v^\prime_{i+1})) \cdot (z - (a_{i+1} + \alpha v_{i+1}))&lt;br &#x2F;&gt;
\ \newline&lt;br &#x2F;&gt;
&amp;amp;+ m_{i+1} \cdot (z - (a_{i+1} + \alpha v_{i+1}))&lt;br &#x2F;&gt;
\ \newline&lt;br &#x2F;&gt;
&amp;amp;- (z - (a^\prime_{i+1} + \alpha v^\prime_{i+1}))&lt;br &#x2F;&gt;
\ \newline&lt;br &#x2F;&gt;
&amp;amp;- s_{i+1} \cdot (z - (a^\prime_{i+1} + \alpha v^\prime_{i+1})) \cdot (z - (a_{i+1} + \alpha v_{i+1}))&lt;br &#x2F;&gt;
\end{align}$$&lt;&#x2F;p&gt;
&lt;p&gt;This equation can be found inside the function &lt;code&gt;evaluate()&lt;&#x2F;code&gt; in the implementation of &lt;code&gt;PermutationConstraint&lt;&#x2F;code&gt;. It is worth mentioning that both the prover and verifier must evaluate the polynomial constraint in the same way. However, we are forced to separate this evaluation into two cases because the &lt;code&gt;frames&lt;&#x2F;code&gt; used by each one are of different types.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn evaluate(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;amp;self,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    evaluation_context: &amp;amp;TransitionEvaluationContext&amp;lt;F, E&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transition_evaluations: &amp;amp;mut [FieldElement&amp;lt;E&amp;gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; In both evaluation contexts, Prover and Verfier will evaluate the transition polynomial in the same way.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; The only difference is that the Prover&amp;#39;s Frame has base field and field extension elements,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; while the Verfier&amp;#39;s Frame has only field extension elements.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    match evaluation_context {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        TransitionEvaluationContext::Prover {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            frame,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            periodic_values: _periodic_values,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            rap_challenges,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        } =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let first_step = frame.get_evaluation_step(0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let second_step = frame.get_evaluation_step(1);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; Auxiliary frame elements&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let s0 = first_step.get_aux_evaluation_element(0, 0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let s1 = second_step.get_aux_evaluation_element(0, 0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; Challenges&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let z = &amp;amp;rap_challenges[0];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let alpha = &amp;amp;rap_challenges[1];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; Main frame elements&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let a1 = second_step.get_main_evaluation_element(0, 0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let v1 = second_step.get_main_evaluation_element(0, 1);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let a_sorted_1 = second_step.get_main_evaluation_element(0, 2);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let v_sorted_1 = second_step.get_main_evaluation_element(0, 3);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let m = second_step.get_main_evaluation_element(0, 4);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let unsorted_term = -(a1 + v1 * alpha) + z;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let sorted_term = -(a_sorted_1 + v_sorted_1 * alpha) + z;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; We are using the following LogUp equation:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; s1 = s0 + m &#x2F; sorted_term - 1&#x2F;unsorted_term.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; Since constraints must be expressed without division, we multiply each term by sorted_term * unsorted_term:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let res = s0 * &amp;amp;unsorted_term * &amp;amp;sorted_term + m * &amp;amp;unsorted_term&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                - &amp;amp;sorted_term&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                - s1 * unsorted_term * sorted_term;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; The eval always exists, except if the constraint idx was incorrectly defined.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            if let Some(eval) = transition_evaluations.get_mut(self.constraint_idx()) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                *eval = res;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        TransitionEvaluationContext::Verifier {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            frame,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            periodic_values: _periodic_values,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            rap_challenges,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        } =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let first_step = frame.get_evaluation_step(0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let second_step = frame.get_evaluation_step(1);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; Auxiliary frame elements&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let s0 = first_step.get_aux_evaluation_element(0, 0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let s1 = second_step.get_aux_evaluation_element(0, 0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; Challenges&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let z = &amp;amp;rap_challenges[0];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let alpha = &amp;amp;rap_challenges[1];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; Main frame elements&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let a1 = second_step.get_main_evaluation_element(0, 0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let v1 = second_step.get_main_evaluation_element(0, 1);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let a_sorted_1 = second_step.get_main_evaluation_element(0, 2);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let v_sorted_1 = second_step.get_main_evaluation_element(0, 3);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let m = second_step.get_main_evaluation_element(0, 4);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let unsorted_term = z - (a1 + alpha * v1);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let sorted_term = z - (a_sorted_1 + alpha * v_sorted_1);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; We are using the following LogUp equation:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; s1 = s0 + m &#x2F; sorted_term - 1&#x2F;unsorted_term.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; Since constraints must be expressed without division, we multiply each term by sorted_term * unsorted_term:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let res = s0 * &amp;amp;unsorted_term * &amp;amp;sorted_term + m * &amp;amp;unsorted_term&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                - &amp;amp;sorted_term&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                - s1 * unsorted_term * sorted_term;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; The eval always exists, except if the constraint idx was incorrectly defined.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            if let Some(eval) = transition_evaluations.get_mut(self.constraint_idx()) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                *eval = res;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Another noteworthy change is that the polynomial associated with this constraint is now of degree 3. This is easy to understand if we observe that in the zero-equality equation mentioned earlier, there are terms containing the product of three factors, resulting in three variables multiplied together.&lt;&#x2F;p&gt;
&lt;p&gt;It’s worth highlighting that, up until now, both in the previous post and in the other two transition constraints, we had only worked with polynomials of degree 2. This change is reflected in the code in two places. First, we must specify the degree of a transition constraint when defining it:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;impl&amp;lt;F, E&amp;gt; TransitionConstraint&amp;lt;F, E&amp;gt; for PermutationConstraint&amp;lt;F, E&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;where&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    F: IsSubFieldOf&amp;lt;E&amp;gt; + IsFFTField + Send + Sync,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    E: IsField + Send + Sync,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    fn degree(&amp;amp;self) -&amp;gt; usize {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In the second place, when implementing the AIR, we must specify the degree bound of the composition polynomial. In previous implementations, this number was set equal to the length of the trace. However, it is important to make it twice as large in this case. This ensures that when the prover defines the composition polynomial, she can split it into two parts. If we didn’t do this, the prover and verifier would work with the entire composition polynomial without splitting it, increasing the number of FRI rounds (optimization)&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn composition_poly_degree_bound(&amp;amp;self) -&amp;gt; usize {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    self.trace_length() * 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;boundary-constraints&quot;&gt;Boundary Constraints&lt;&#x2F;h3&gt;
&lt;p&gt;Finally, let’s discuss how to define the boundary constraints. All boundary constraints related to the main trace will remain the same: we need to ensure that $a_0$, $a^\prime_0$, $v_0$, and $v^\prime_0$ match the values specified in the public inputs. Additionally, we need to include one more constraint to verify that $m_0$ is correctly defined according to the value described in the public input.&lt;&#x2F;p&gt;
&lt;p&gt;Now, the constraints on the auxiliary trace will change slightly compared to those used in the Grand Product. Following the same logic as we did that time, we must ensure, on one hand, that the first element of the auxiliary column $s$ is correctly constructed—that is, $s_0$ satisfies the equation described earlier in the &lt;em&gt;Auxiliary Trace&lt;&#x2F;em&gt; section. On the other hand, we need to check that the last element $s_{n-1}$ equals zero, ensuring that all terms cancel out and verifying that the trace corresponds to a permutation.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn boundary_constraints(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;amp;self,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    rap_challenges: &amp;amp;[FieldElement&amp;lt;Self::FieldExtension&amp;gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; BoundaryConstraints&amp;lt;Self::FieldExtension&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let a0 = &amp;amp;self.pub_inputs.a0;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let v0 = &amp;amp;self.pub_inputs.v0;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let a_sorted_0 = &amp;amp;self.pub_inputs.a_sorted_0;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let v_sorted_0 = &amp;amp;self.pub_inputs.v_sorted_0;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let m0 = &amp;amp;self.pub_inputs.m0;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let z = &amp;amp;rap_challenges[0];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let alpha = &amp;amp;rap_challenges[1];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Main boundary constraints&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let c1 = BoundaryConstraint::new_main(0, 0, a0.clone().to_extension());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let c2 = BoundaryConstraint::new_main(1, 0, v0.clone().to_extension());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let c3 = BoundaryConstraint::new_main(2, 0, a_sorted_0.clone().to_extension());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let c4 = BoundaryConstraint::new_main(3, 0, v_sorted_0.clone().to_extension());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let c5 = BoundaryConstraint::new_main(4, 0, m0.clone().to_extension());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Auxiliary boundary constraints&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let unsorted_term = (-(a0 + v0 * alpha) + z).inv().unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let sorted_term = (-(a_sorted_0 + v_sorted_0 * alpha) + z).inv().unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let p0_value = m0 * sorted_term - unsorted_term;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let c_aux1 = BoundaryConstraint::new_aux(0, 0, p0_value);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let c_aux2 = BoundaryConstraint::new_aux(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        0,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        self.trace_length - 1,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        FieldElement::&amp;lt;Self::FieldExtension&amp;gt;::zero(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    BoundaryConstraints::from_constraints(vec![c1, c2, c3, c4, c5, c_aux1, c_aux2])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;In this post, we explore the lookup argument method LogUp, using the example of a continuous read-only memory explained in a previous post. By changing the construction of some columns of the trace table, the permutation transition constraint, and some other small details, we adapted the implementation we already had for that same example using this new method.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>The future of ZK is in RISC-V zkVMs, but the industry must be careful: how Succinct&#x27;s SP1&#x27;s departure from standards causes bugs</title>
          <pubDate>Sat, 21 Dec 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/the-future-of-zk-is-in-risc-v-zkvms-but-the-industry-must-be-careful-how-succincts-sp1s-departure-from-standards-causes-bugs/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/the-future-of-zk-is-in-risc-v-zkvms-but-the-industry-must-be-careful-how-succincts-sp1s-departure-from-standards-causes-bugs/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/the-future-of-zk-is-in-risc-v-zkvms-but-the-industry-must-be-careful-how-succincts-sp1s-departure-from-standards-causes-bugs/">&lt;h2 id=&quot;why-you-should-avoid-having-complex-codebases-and-departing-from-standards-when-developing-zero-knowledge-virtual-machines&quot;&gt;Why you should avoid having complex codebases and departing from standards when developing zero-knowledge virtual machines&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;&#x2F;strong&gt; : We found a subtle bug in Succinct’s SP1 virtual machine, which allows a malicious user to prove the validity of false statements by subtly manipulating register 0 in the guest code&lt;&#x2F;p&gt;
&lt;p&gt;This was found thanks to a collaboration between &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.3milabs.tech&#x2F;&quot;&gt;3MI Labs&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.alignedlayer.com&#x2F;&quot;&gt;Aligned&lt;&#x2F;a&gt;, and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;lambdaclass.com&#x2F;&quot;&gt;LambdaClass&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;LambdaClass and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;fuzzinglabs.com&#x2F;&quot;&gt;Fuzzing Labs&lt;&#x2F;a&gt; will invest in further investigating critical security bugs in zkvms. We believe that codebases have become too complex and over-engineered and this gives rise to lots of bugs. We think that the industry is at risk if we do not invest, add more eyes and simplify codebases. The industry has become complacent when it comes to security and is being pushed by business decisions to rush into production use, leaving aside these security issues, which could lead to very serious consequences. In this post, we analyze the case of SP1, but we think that all zkvm’s codebases need to be simplified and follow the standards, lowering the attack surface. As mentioned, we will conduct a more thourough research on different zkvms.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;We have seen the development of long and complex codebases in several engineering projects, with too many features and poor documentation and testing. Some people believe that having such codebases shows that you are smart, have excellent coding skills, and have given a lot of thought to everything. We think otherwise: the proof of mastery lies in simplicity. Bugs will always happen in any project, but the chance of having critical bugs increases with codebase complexity and length in a nonlinear way: the longer and more complex, the more bugs and hard-to-predict behaviors you can have.&lt;&#x2F;p&gt;
&lt;p&gt;During our analysis of zk virtual machines and proof systems, we found a bug in Succinct’s SP1 virtual machine, which allows a malicious actor to generate a valid proof of malicious programs (proving that a false statement is true). We disclosed our concerns to Succinct’s team, and they replied that this was &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;x.com&#x2F;jtguibas&#x2F;status&#x2F;1862301417870148082&quot;&gt;within their security assumptions&lt;&#x2F;a&gt; and is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;succinctlabs&#x2F;sp1&#x2F;blob&#x2F;dev&#x2F;book&#x2F;docs&#x2F;developers&#x2F;rv32im-deviations.md&quot;&gt;currently included in their documentation&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;We discussed these issues with several auditors and concluded that the most important thing is that this deviation was well-documented and communicated, so we’re updating our docs to reflect that. We do not believe this is a security concern since programs proven in our zkVM are already assumed to be well-formed and not malicious. In other words, while you can prove the execution of the malicious program, the resulting proof is meaningless if the program is corrupt.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;We like Succinct’s work and think their virtual machine has sparked a lot of good competition to improve current zkvm designs and helped show that the future of ZK is in RISC-V virtual machines. We have been playing and experimenting with it a lot and are considering using it in some of our projects. We also liked that they responded fast to our findings, and although we disagreed with their criteria, they took our concerns seriously.&lt;&#x2F;p&gt;
&lt;p&gt;From our point of view, this bug arises from a departure from the RISC-V specs and the complexity of the codebase. We think that more care needs to be taken when designing, developing, and testing zk virtual machines that could be used in real-world applications, and try to minimize the attack surface by not going into unchartered territory.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;description-of-the-bug&quot;&gt;Description of the bug&lt;&#x2F;h2&gt;
&lt;p&gt;This example shows that an SP1 proof can be glitched with an appropriately targeted memory write. We will use this to prove that 42 is prime using a simple primality test:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Returns if divisible via immediate checks than 6k ± 1.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Source: https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Primality_test#Rust&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn is_prime(n: u64) -&amp;gt; bool {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if n &amp;lt;= 1 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return false;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if n &amp;lt;= 3 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return true;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if n % 2 == 0 || n % 3 == 0 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return false;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut i = 5;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    while i * i &amp;lt;= n {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        if n % i == 0 || n % (i + 2) == 0 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            return false;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        i += 6;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Using the following guest program (using i&#x2F;o is unnecessary for the bug):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn main() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let what: u8 = sp1_zkvm::io::read();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let where_: u32 = sp1_zkvm::io::read();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let n = sp1_zkvm::io::read::&amp;lt;u64&amp;gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; We can have a little write, as a treat&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    unsafe {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        *(where_ as *mut u8) = what;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let is_prime = is_prime(n);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    sp1_zkvm::io::commit(&amp;amp;n);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    sp1_zkvm::io::commit(&amp;amp;is_prime);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then the proving script is executed,&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;! A program that takes a number `n` as input and writes if `n` is prime as an output.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;use sp1_sdk::{utils, ProverClient, SP1Stdin};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Generated with `cargo prove build --docker --elf-name is-prime-write --output-directory elf`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; in the program directory&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;const ELF: &amp;amp;[u8] = include_bytes!(&amp;quot;..&#x2F;..&#x2F;..&#x2F;program&#x2F;elf&#x2F;is-prime-write&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;const FILENAME: &amp;amp;&amp;#39;static str = &amp;quot;is-prime-write.proof&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn main() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Setup a tracer for logging.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    utils::setup_logger();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Generate and verify the proof&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let client = ProverClient::new();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let (pk, vk) = client.setup(ELF);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Create an input stream and write &amp;#39;29&amp;#39; to it&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let n = 42u64;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut stdin = SP1Stdin::new();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    stdin.write(&amp;amp;1u8); &#x2F;&#x2F; what&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    stdin.write(&amp;amp;0u32); &#x2F;&#x2F; where&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    stdin.write(&amp;amp;n);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut proof = client.prove(&amp;amp;pk, stdin).compressed().run().unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let _ = proof.public_values.read::&amp;lt;u64&amp;gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let is_prime = proof.public_values.read::&amp;lt;bool&amp;gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    println!(&amp;quot;Is {n} prime? {}&amp;quot;, is_prime);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    client.verify(&amp;amp;proof, &amp;amp;vk).expect(&amp;quot;verification failed&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    proof.save(FILENAME).expect(&amp;quot;saving proof failed&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This program reads three inputs: the content of the memory write (what), the target address of the memory write (where), and a number for primality testing. (It also contains the ELF compiled version as program&#x2F;elf&#x2F;is-prime-write.). Register 0 should always be zero, and cannot be changed according to RISC-V specs. Due to the bug, we can change it in the guest code, making statements that should be false to change to true.&lt;&#x2F;p&gt;
&lt;p&gt;After performing the memory write of the given content at the given address, the program tests whether the given input &lt;code&gt;n&lt;&#x2F;code&gt; is a prime number. The &lt;code&gt;is_prime()&lt;&#x2F;code&gt; function in &lt;code&gt;main.rs&lt;&#x2F;code&gt;(.&#x2F;program&#x2F;src&#x2F;main.rs) is a correct primality test that should return &lt;code&gt;false&lt;&#x2F;code&gt; on input &lt;code&gt;42&lt;&#x2F;code&gt;. The program finally commits to the input &lt;code&gt;n&lt;&#x2F;code&gt; that it was given, as well as the result of the primality test; these are the public values displayed by the verifier binary, showing that the &lt;code&gt;is_prime()&lt;&#x2F;code&gt; function incorrectly returned &lt;code&gt;true&lt;&#x2F;code&gt; when the program’s input was &lt;code&gt;42&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;script&lt;&#x2F;code&gt; directory contains the minimal rust binary &lt;code&gt;verifier.rs&lt;&#x2F;code&gt;(.&#x2F;script&#x2F;src&#x2F;bin&#x2F;verifier.rs), which verifies that the proof given in &lt;code&gt;script&#x2F;is-prime-write.proof&lt;&#x2F;code&gt; declares that 42 is a prime number. This can be checked by running the following commands.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cd script&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cargo run&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;! A program that takes a number `n` as input and writes if `n` is prime as an output.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;use sp1_sdk::{utils, ProverClient, SP1ProofWithPublicValues};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Generated with `cargo prove build --docker --elf-name is-prime-write --output-directory elf`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; in the program directory&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;const ELF: &amp;amp;[u8] = include_bytes!(&amp;quot;..&#x2F;..&#x2F;..&#x2F;program&#x2F;elf&#x2F;is-prime-write&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;const FILENAME: &amp;amp;&amp;#39;static str = &amp;quot;is-prime-write.proof&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn main() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Setup a tracer for logging.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    utils::setup_logger();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Generate and verify the proof&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let client = ProverClient::new();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let (_, vk) = client.setup(ELF);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Verifier code&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut deserialized_proof =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        SP1ProofWithPublicValues::load(FILENAME).expect(&amp;quot;loading proof failed&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Verify the deserialized proof.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    client&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .verify(&amp;amp;deserialized_proof, &amp;amp;vk)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .expect(&amp;quot;verification failed&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Now that it&amp;#39;s accepted&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let n: u64 = deserialized_proof.public_values.read();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let is_prime: bool = deserialized_proof.public_values.read();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    println!(&amp;quot;Verifier: Is {n} prime? {is_prime}&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;While this example is naïf (since we can easily see that 42 is not prime due to it being an even number), this idea could be exploited for more subtle attacks, including supply chain attacks. While the change in the guest program is pretty obvious in this case, in others where the codebase is more complex and there are multiple dependencies it can be way harder to detect.&lt;br &#x2F;&gt;
The assumption that programs are always correctly generated and do not have bugs is against common sense in the software industry and could result in serious vulnerabilities. Moreover, departing from well-established standards makes the reasoning over expected behavior difficult and can lead to more complex and subtle bugs.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;Working with 3MI Labs and Aligned, we found a bug in how SP1 handles the memory register (in particular, register 0), which can allow an attacker to prove a false statement. This results from a departure of the RISC-V specs and a complex codebase. This makes reasoning over expected behavior very difficult, as it could also give rise to unexpected and subtle bugs, which can have critical consequences in real-world settings. We must continue testing, analyzing, and trying to find bugs and unexpected behaviors in zk virtual machines to minimize risks when used in real-world use cases.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Introducing DeMo: Decoupled Momentum Optimization for efficient distributed LLM training</title>
          <pubDate>Fri, 06 Dec 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/introducing-demo-decoupled-momentum-optimization-for-efficient-distributed-llm-training/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/introducing-demo-decoupled-momentum-optimization-for-efficient-distributed-llm-training/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/introducing-demo-decoupled-momentum-optimization-for-efficient-distributed-llm-training/">&lt;h2 id=&quot;tl-dr&quot;&gt;TL;DR&lt;&#x2F;h2&gt;
&lt;p&gt;Training Large Language Models (LLM) with billions of parameters is computationally intensive and involves large communication in specialized data centers. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;nousresearch.com&#x2F;&quot;&gt;Nous Research&lt;&#x2F;a&gt; released DeMo, showing how to reduce these communication costs by orders of magnitude, decreasing costs and enabling training with poorer connections and less expensive hardware. This post introduces basic concepts and discusses &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;pdf&#x2F;2411.19870&quot;&gt;the paper&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;The problem of machine learning consists of finding a function (or mapping) from a set of inputs, $X$, to a set of outputs, $Y$. This relationship can be quite complex, and we want to approximate it by having information on samples $(x , y)$. For example, we could be interested in the response of the length of a hanging spring to adding weight; to that end, we would measure the weight we are adding, $w$, and record the variation in length, $\Delta x$. Another example could be correlating the energy expenditure by a person based on information such as heart rate, weight, height, and amount of skeletal muscle mass. We could also want to train an agent to recognize an image. While the underlying relationships and objectives could be very different, they can be treated by some families of mathematical methods. Before diving into specifics of large language models (LLM) and artificial intelligence (AI), let us focus on simpler problems, such as measuring the spring’s elongation with weight or the current circulating in a wire due to the application of a given voltage.&lt;&#x2F;p&gt;
&lt;p&gt;In the case of the spring, we get some weights (for example, 25 g, 50 g, 100 g, 200 g). We measure the resulting elongation once the movement of the spring finishes, say 1, 2, 4 and 8 cm. Using empirical knowledge from Physics, as long as we are in an elastic regime, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Hooke%27s_law&quot;&gt;Hooke’s law&lt;&#x2F;a&gt; holds: the weight (applied force) is proportional to the elongation, $k \Delta x = w$, where $k$ is the stiffness of the spring. The relationship is not always like this because if we add too much weight, the spring is deformed significantly and loses its behavior. The problem we want to solve is, therefore,&lt;&#x2F;p&gt;
&lt;p&gt;Find $k$ such that $k \Delta x_i = w_i$ for $i = 0, 1, 2, … n$. This is a system of linear equations, and should there be no measurement errors and this relationship be the true mapping, then $k = w_i &#x2F; \Delta x_i$.&lt;&#x2F;p&gt;
&lt;p&gt;Some problems we face are:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. The relation&#x2F;mapping we are using may be an approximation of the true relationship.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. There are errors associated with the measurements (we can assume for the time being that these errors are random and not introduced systematically by the observer).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. We don&amp;#39;t have lots of measurements $(\Delta x , w)$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This makes things quite harder. To start with, the system of equations $k \Delta x_j = w_j$ could no longer have a valid solution. For example, we could have $(1 , 25)$ and $(2.01 , 49.9)$, which translates to:&lt;br &#x2F;&gt;
$k. 1 = 25$&lt;br &#x2F;&gt;
$k. 2.01 = 49.9$&lt;br &#x2F;&gt;
The first equation yields $k = 25$, while the second gives $k = 24.82$. This system of equations has no solution, but we could still be interested in estimating $k$ from the information available (the two values are not too far apart, so maybe we can do something). We could define a new function that measures the difference between the observed output $w_j$ and the predicted output $\Delta x_j$. We call this function the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Loss_function&quot;&gt;loss function&lt;&#x2F;a&gt;. For example,&lt;br &#x2F;&gt;
$L(k) = (k \Delta x_0 - w_0 )^2 + (k \Delta x_1 - w_1 )^2 = (\hat{w}_0 - w_0 )^2 + (\hat{w}_1 - w_1 )^2$&lt;&#x2F;p&gt;
&lt;p&gt;The function measures the quadratic error between the weight predicted by Hooke’s law and our measurements. Our objective is to find $k$ such that the loss function is minimal,&lt;br &#x2F;&gt;
$\min_{k \in K} L(k)$&lt;&#x2F;p&gt;
&lt;p&gt;Calculus tells us that the function (assuming it is “nice”) attains an extremal value if the derivative with respect to $k$ is zero,&lt;br &#x2F;&gt;
$dL&#x2F;dk = 0$&lt;&#x2F;p&gt;
&lt;p&gt;Using the chain rule for derivatives,&lt;br &#x2F;&gt;
$dL&#x2F;dk = 2(k \Delta x_0 - w_0 )\Delta x_0 + 2(k \Delta x_1 - w_1 ) \Delta x_1 = 0$&lt;&#x2F;p&gt;
&lt;p&gt;This equation is linear, and we can solve it directly. Let us complicate the problem a little bit, assuming&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. We have several parameters, $k_0, k_1 , ... , k_m$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. That the equations to find the parameters are non-linear.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The procedure can be generalized using multivariate calculus if we have several parameters. We ask for the partial derivatives with respect to each parameter to be zero:&lt;br &#x2F;&gt;
$\partial L &#x2F; \partial k_0 = 0$&lt;br &#x2F;&gt;
$\partial L &#x2F; \partial k_1 = 0$&lt;br &#x2F;&gt;
$\partial L &#x2F; \partial k_2 = 0$&lt;br &#x2F;&gt;
$\vdots$&lt;br &#x2F;&gt;
$\partial L &#x2F; \partial k_m = 0$&lt;&#x2F;p&gt;
&lt;p&gt;The vector containing all these partial derivatives is the gradient of $L$. We have a system of several equations with as many variables to solve.&lt;&#x2F;p&gt;
&lt;p&gt;What happens when the equations above are not easy to solve? We have two facts:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. The gradient should be zero at the minimum.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. The gradient&amp;#39;s direction gives the direction of the greatest increase in a function (so following the opposite direction should give the steepest descent).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is the working principle of the steepest descent search. Starting for a set of parameters $k^0$, we recursively set&lt;br &#x2F;&gt;
$k^{n + 1} = k^n - \gamma \nabla L$&lt;br &#x2F;&gt;
where $\gamma$ is a parameter (called the learning rate). High values of $\gamma$ generate instability and convergence issues, whereas low values of $\gamma$ mean we move slowly toward the minimum.&lt;&#x2F;p&gt;
&lt;p&gt;We now face some further questions which we did not address before:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. A function can have several (local) minima, so how can we ensure that we find the true (global) minimum?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Is there a way we can adapt the learning rate $\gamma$ so that we can achieve convergence faster?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. What happens if the number of observations $(x_i , y_i )$ is very large and the loss function has a complicated or expensive to evaluate expression?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We will first address the third question and then try to solve the others. We have an expression of the form:&lt;br &#x2F;&gt;
$L (k) = \sum_j E_j (x_j, y_j , k)$&lt;br &#x2F;&gt;
For example, $E_j = ( f(x_j , k) - y_j )^2$ could be the quadratic error for each observation, and $f$ is the function giving the relationship between input and output. Computing the whole gradient involves the (partial) derivative of each $E_j (x_j , y_j )$ and summing over all values of $j$, making the evaluation of the gradient expensive. We could try to reduce the number of terms just by choosing one observation and approximate the true gradient by this value:&lt;br &#x2F;&gt;
$\nabla L \approx \nabla E_j$&lt;br &#x2F;&gt;
This reduces the computational burden at the expense of accuracy. We could also try to estimate the gradient using a subset of the observations or mini-batch. This is the idea of the stochastic gradient descent.&lt;&#x2F;p&gt;
&lt;p&gt;Since we are dealing with approximations, the learning rate may need to be readjusted and decreased at a specific rate, making it $\gamma^n$.&lt;&#x2F;p&gt;
&lt;p&gt;We can improve the method by introducing momentum, which keeps track of previous gradients when updating it for the next iteration. Basically,&lt;br &#x2F;&gt;
$\Delta k^n = \alpha \Delta k^{n - 1} - \gamma (\nabla L)^n$&lt;br &#x2F;&gt;
$k^{n + 1} = k^n + \Delta k^n$&lt;br &#x2F;&gt;
We can see that if $\alpha = 0$, we recover the original gradient descent. If $\alpha$ is different from zero, we accumulate the previous gradients and, considering the directions given by earlier steps. This will ensure that if we were going in a given direction for some time, we will continue going that way, avoiding sudden changes in direction.&lt;&#x2F;p&gt;
&lt;p&gt;Since gradients can have components with very different values, we can adjust learning rates for each variable, as in the case of the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;pdf&#x2F;1412.6980&quot;&gt;Adam optimizer&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The problem with local minima can be solved by means of this momentum method (which would prevent us from being trapped in shallow minima), trying different starting points and also &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Simulated_annealing&quot;&gt;annealing methods&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;We can create or approximate more complex behaviors by using neural networks. Given the input variables $x_1, … x_m$, we can form a linear combination, using weights $w_{j0}$ and apply an activation function $f$, obtaining new values $z_{11}, … z_{1m}$ as follows:&lt;br &#x2F;&gt;
$a_{1j} = \sum_l w_{jl} x_l + w_{j0}$&lt;br &#x2F;&gt;
$z_{1j} = f(\sum_l w_{jl} x_l + w_{j0})$&lt;br &#x2F;&gt;
We can add a new layer, using the output above, by performing linear combinations and applying an activation function&lt;br &#x2F;&gt;
$z_{2j} = f(\sum_l w_{jl}^{(2)} z_{1l} + w_{j0}^{(2)})$&lt;br &#x2F;&gt;
We can similarly add other layers until we get the output of the neural network,&lt;br &#x2F;&gt;
$z_{3j} = f(\sum_l w_{jl}^{(3)} z_{2l} + w_{j0}^{(3)})$&lt;&#x2F;p&gt;
&lt;p&gt;Gradients can be computed efficiently using backpropagation. We will start again with our loss function as a sum of terms, each corresponding to one sample,&lt;br &#x2F;&gt;
$L (k) = \sum_j E_j (x_j, y_j , k)$&lt;br &#x2F;&gt;
We will focus on computing the derivative of one $E_j$ with respect to each of the parameters,&lt;br &#x2F;&gt;
$$\frac{\partial E_j}{ \partial w_{ji} } = \frac{\partial E_j}{\partial a_j} \frac{\partial a_j }{\partial w_{ij}}$$&lt;&#x2F;p&gt;
&lt;p&gt;The second partial derivative on the right-hand side is straightforward since $a_j$ is a linear combination of $w_{ij}$,&lt;br &#x2F;&gt;
$$\frac{\partial a_j }{\partial w_{ij}} = z_i$$&lt;br &#x2F;&gt;
For the other derivative, we will just call it&lt;br &#x2F;&gt;
$$\frac{\partial E_j}{\partial a_j} = \delta_j$$&lt;br &#x2F;&gt;
so that&lt;br &#x2F;&gt;
$$\frac{\partial E_j}{ \partial w_{ji} } = z_i \delta_j$$&lt;&#x2F;p&gt;
&lt;p&gt;The derivatives for each layer can be computed by evaluating $\delta_j$ and using the formula provided. For the hidden layers,&lt;br &#x2F;&gt;
$$\delta_j = \sum_m \frac{\partial E_j}{\partial a_m} \frac{\partial a_m}{\partial a_k}$$&lt;br &#x2F;&gt;
We can finally arrive at the backpropagation formula for $\delta_j$,&lt;br &#x2F;&gt;
$\delta_j = f^\prime (a_j ) \sum_m w_{mj} \delta_m$&lt;&#x2F;p&gt;
&lt;p&gt;The basic procedure to evaluate the derivatives would be to first compute the $a_j$ for all the layers and the output, evaluate $\delta_j$ for the output, and use the last formula using backpropagation to obtain each $\delta_j$ for each inner layer.&lt;&#x2F;p&gt;
&lt;p&gt;Many Large Language Models (LLM) are based on neural networks. They have shown good performance in different fields, such as translation and conversational AI. These can be in the order of trillions of parameters. Therefore, in order to attain reasonable training times, we need accelerators, such as GPU and TPU. We often encounter heterogeneity in GPU clusters, and interconnects are partitioned into high-bandwidth islands in each machine and low-bandwidth across machines, limiting training speeds and suboptimal hardware utilization. This also affects memory planning, and frequent memory defragmentations significantly slow training. This also translates into capital and operational costs.&lt;&#x2F;p&gt;
&lt;p&gt;Strategies such as Distributed Data Parallelism and Fully Sharded Data Parallelism have the accelerators split the weights and synchronize the gradients, with communication volumes proportional to the size of the model (For example, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;proceedings.mlr.press&#x2F;v202&#x2F;wang23t&#x2F;wang23t.pdf&quot;&gt;training a GPT-J-6B with 10B tokens on 4 machines would require 915 TB of data transferred!&lt;&#x2F;a&gt;. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;pdf&#x2F;2403.03507&quot;&gt;LlaMa pre-training with 7 billion parameters uses over 58 GB of memory to store parameters, activations, and gradients&lt;&#x2F;a&gt;). This makes gradient synchronization require expensive high-speed interconnects, forcing all devices to be in the same physical space. Reducing communication costs by over an order of magnitude could not only reduce costs or training times, but also allow for the use of more distributed hardware.&lt;&#x2F;p&gt;
&lt;p&gt;Some techniques used to reduce memory footprint and communication costs are:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Sparsification and compression](https:&#x2F;&#x2F;proceedings.mlr.press&#x2F;v202&#x2F;wang23t&#x2F;wang23t.pdf)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Low-rank projection of gradients](https:&#x2F;&#x2F;arxiv.org&#x2F;pdf&#x2F;2403.03507)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Federated averaging](https:&#x2F;&#x2F;proceedings.mlr.press&#x2F;v54&#x2F;mcmahan17a&#x2F;mcmahan17a.pdf)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this blog post, we will discuss &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;pdf&#x2F;2411.19870&quot;&gt;DeMo&lt;&#x2F;a&gt;, recently released by &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;nousresearch.com&#x2F;&quot;&gt;Nous Research&lt;&#x2F;a&gt;, which provides significant savings in communication and memory use, allowing to train LLMs with poorer connections and less powerful hardware.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;nous-research&quot;&gt;Nous Research&lt;&#x2F;h2&gt;
&lt;p&gt;Nous Research is dedicated to researching human-centric language models and simulators, focusing on areas including model architecture, data synthesis, fine-tuning, and reasoning, all aimed at aligning AI systems with real-world user experiences. Four months ago, they released a preliminary report on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;NousResearch&#x2F;DisTrO&#x2F;blob&#x2F;main&#x2F;A_Preliminary_Report_on_DisTrO.pdf&quot;&gt;DisTro&lt;&#x2F;a&gt;, a family of architecture-agnostic and network-agnostic optimizers, significantly reducing the communication costs by several orders of magnitude, which enables efficient distributed training of AI.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;working-hypothesis&quot;&gt;Working hypothesis&lt;&#x2F;h2&gt;
&lt;p&gt;The paper shows that gradients for very large LLM exhibit both redundancy and high compressibility. This is the core insight enabling DeMo. It is based on the following three observations:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. The fast-moving components of momentum exhibit high spatial auto-correlation with a small number of principal components.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Fast-moving momentum components show low temporal variance and should be used to update the parameters immediately. The slow-moving components exhibit high temporal variance and benefit from temporal smoothing.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Slow-moving momentum components are crucial for long-term convergence and should be preserved rather than filtered out.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Using these conjectures, the authors modify the SGD method with momentum to decouple momentum between the different accelerators. After updating the momentum, the fast components $q$ of momentum are extracted using a discrete cosine transform (DCT), and these components are shared with minimal communication.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-does-demo-work&quot;&gt;How does DeMo work?&lt;&#x2F;h2&gt;
&lt;p&gt;The starting point is the Stochastic Gradient Descent (SGD) with momentum algorithm. Instead of computing the overall gradient, we will compute local gradients and use them to update the (decoupled) momentum. Then, we will extract the $k$ fastest components for each momentum and subtract them from the decoupled momentum. Finally, we will communicate and synchronize all the fast components and update the parameters using this synchronized gradient. This is the algorithm as described in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;pdf&#x2F;2411.19870&quot;&gt;paper&lt;&#x2F;a&gt;:&lt;br &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;SJeEXz07ye.png&quot; alt=&quot;Screenshot 2024-12-04 at 2.35.32 PM&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The extraction of the fast components is critical for the algorithm’s performance. While the Kosambi–Karhunen–Loève Transform provides a way to achieve the decorrelation, separation, and extraction of the main components, the DCT offers an excellent approximation under the hypothesis provided above. The advantages of DCT lie in its efficient computation and high degree of parallelization. Besides, it is computed on a fixed orthogonal basis, which allows us to decode a DCT-encoded signal efficiently without additional information.&lt;&#x2F;p&gt;
&lt;p&gt;We can work with each momentum tensor as a d-dimensional autocorrelated signal, chunk them, and apply the DCT to each, extracting the highest $k$ values and their frequencies. This creates two tensors, one containing the frequencies (using an index) and the other keeping the amplitude (using a floating point number). In the DCT, the frequencies are given by $2\pi i&#x2F;N$, so giving $i$ suffices to specify the frequency, so we would get pairs $(i, A)$ indicating the frequency and amplitude of the fastest components. We can then perform the inverse DCT with these tensors to recover the values of the components, $q_t$, and remove these values from the momentum (fourth step of the algorithm).&lt;&#x2F;p&gt;
&lt;p&gt;After gathering all the fastest local components, we are ready to synchronize them. The first step is to average the amplitudes over repeated frequencies (if the frequency given by the index 11, corresponding to $2\pi 11&#x2F;N$, is repeated in the fastest components of a local gradient). In the second step, we perform the inverse DCT to recover the values of the fastest components of the global gradient, $Q_t$. The advantage is that if we choose the parameters appropriately, the number of fastest components we have to share is significantly smaller than the gradient.&lt;&#x2F;p&gt;
&lt;p&gt;The experimental results show that DeMo can reduce communication costs by at least one order of magnitude compared to AdamW, without noticeable changes in convergence.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;This post introduced basic concepts related to machine learning and LLM, explaining the objectives, strategies, and challenges that arise when training very large models. The need to split parameters and computation among several accelerators introduces the need for specialized connections, having all devices in the same physical place. Using empirical observations from training LLMs, Nous Research proposed DeMo, leveraging the DCT to extract the fastest components and reduce the amount of data the accelerators have to share. The experimental results show a reduction of at least an order of magnitude with respect to AdamW (depending on the choice of parameters, it can be higher), allowing for the use of networks with poorer bandwidth and heterogeneous hardware to train LLMs, reducing both capital and operational costs.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Continuous Read-Only Memory Constraints: An implementation using Lambdaworks</title>
          <pubDate>Mon, 02 Dec 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/continuous-read-only-memory-constraints-an-implementation-using-lambdaworks/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/continuous-read-only-memory-constraints-an-implementation-using-lambdaworks/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/continuous-read-only-memory-constraints-an-implementation-using-lambdaworks/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;When we first explored the world of STARKs, one of the most confusing concepts we encountered was constraints. We kept asking ourselves: How is it possible to summarize highly complex relationships between trace values using just a few polynomials? It wasn’t until we started implementing some examples that we truly understood the clever, almost magical techniques employed in this domain.&lt;&#x2F;p&gt;
&lt;p&gt;In this post, we aim to share part of that journey, explaining the insights we’ve gained in a hands-on, practical manner. We firmly believe that the best way to learn is through doing, and we’ll guide you through a concrete example: implementing the constraints for Cairo’s non-deterministic continuous read-only memory using the Lambdaworks library. These constraints are detailed in Section 9.7 of the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2021&#x2F;1063&quot;&gt;Cairo whitepaper&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;We won’t explain the basic concepts from the protocol, as we assume that if you’re reading this, you already have some understanding of the STARK protocol, the idea of an execution trace, and the purpose of defining constraints. For a deeper understanding or to reinforce some concepts, check out &lt;a href=&quot;&#x2F;diving-deep-fri&#x2F;&quot;&gt;diving DEEP-FRI&lt;&#x2F;a&gt;, &lt;a href=&quot;&#x2F;how-to-code-fri-from-scratch&#x2F;&quot;&gt;FRI from scratch&lt;&#x2F;a&gt; and &lt;a href=&quot;&#x2F;overview-of-the-stone-prover&#x2F;&quot;&gt;Stone prover&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-a-continuous-read-only-memory&quot;&gt;What is a Continuous Read-Only Memory?&lt;&#x2F;h2&gt;
&lt;p&gt;So, what do we mean by “continuous, non-deterministic, read-only memory”?&lt;&#x2F;p&gt;
&lt;p&gt;The definition from the paper is as follows:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;9.7.1 Definition&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
&lt;strong&gt;Definition 4.&lt;&#x2F;strong&gt; A memory access is a pair $(a, v)\in \mathbb{F}^2$ where $a$ represents an address and $v$ represents the value of the memory at a. A list of memory accesses $(a_i, v_i)$ for $i \in [0, n)$ ($1 \leq n \leq P$) is said to form a &lt;em&gt;read-only memory&lt;&#x2F;em&gt; if for all $i, j \in [0, n)$, if $a_i = a_j,$ then $v_i = v_j$ . It is said to be &lt;em&gt;continuous&lt;&#x2F;em&gt; if the set ${a_i: i \in [0, n)}$ equals $[m_0, m_1)$ for some $m_0, m_1 \in \mathbb{F}$ that satisfy $m_1 = m_0 + t$ for a natural number $t &amp;lt; P$ . In particular, for a given continuous read-only memory list of accesses, we can define a function $f: [m_0, m_1) \to \mathbb{F}$ such that $f(a_i) = v_i$ for all $i \in [0, n)$. Any function $m: \mathbb{F} → \mathbb{F}$ extending $f$ is said to be a memory function for the list of memory accesses.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Let’s simplify this long and complex definition. Imagine a trace with two columns and $n$ rows. The rows represent each step of execution. The first column indicates the memory address accessed during that step, and the second column indicates the value retrieved from that address.&lt;&#x2F;p&gt;
&lt;p&gt;For a memory to be &lt;strong&gt;read-only&lt;&#x2F;strong&gt; , the same addresses must always have the same value. If two rows in the trace reference the same address, the value in those rows must be the same.&lt;&#x2F;p&gt;
&lt;p&gt;For example, consider the following trace:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Address&lt;&#x2F;th&gt;&lt;th&gt;Value&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;56&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;34&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;5&lt;&#x2F;td&gt;&lt;td&gt;97&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;25&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;5&lt;&#x2F;td&gt;&lt;td&gt;41&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;34&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;This trace is invalid because address 5 has two different values: 97 in the first occurrence and 41 in the second. This is not allowed in read-only memory.&lt;&#x2F;p&gt;
&lt;p&gt;For a memory to be &lt;strong&gt;continuous&lt;&#x2F;strong&gt; , every memory address from the starting point (e.g., address 1) to the last address must appear at least once.&lt;&#x2F;p&gt;
&lt;p&gt;The trace is also invalid in the example above because there is no entry for address 2.&lt;&#x2F;p&gt;
&lt;p&gt;Then, to validate a trace, we need to ensure:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Read-only property** : The same address always maps to the same value.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Continuity property** : Every memory address in the range appears at least once.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It’s worth noting that addresses can appear multiple times in any order.&lt;&#x2F;p&gt;
&lt;p&gt;The hard part is figuring out how to transform these two conditions into equations, which can then be expressed as polynomials.&lt;&#x2F;p&gt;
&lt;p&gt;Like any engineering problem, there are trade-offs: keeping the trace simple can make the constraints more complex, and using more straightforward constraints can require adding more information to the trace.&lt;&#x2F;p&gt;
&lt;p&gt;If we examine the conditions mentioned earlier, it becomes clear that validating them would be easier if the rows were sorted by address. For example, it’s challenging for a human to determine if a sequence like $(7, 5, 12, 4, 5, 11, 9, 10, 4, 4, 11, 7, 8)$ is continuous, but much more straightforward if we sort it: $(4, 4, 5, 5, 7, 7, 8, 9, 10, 11, 11, 12)$.&lt;&#x2F;p&gt;
&lt;p&gt;For this reason, Cairo’s VM adds two additional columns to the trace: the sorted versions of the address and value columns.&lt;&#x2F;p&gt;
&lt;p&gt;For example:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;address $(a)$&lt;&#x2F;th&gt;&lt;th&gt;value $(v)$&lt;&#x2F;th&gt;&lt;th&gt;sorted_address $(a’)$&lt;&#x2F;th&gt;&lt;th&gt;sorted_value $(v’)$&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;56&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;56&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;5&lt;&#x2F;td&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;56&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;25&lt;&#x2F;td&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;34&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;25&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;25&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;44&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;25&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;56&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;44&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;34&lt;&#x2F;td&gt;&lt;td&gt;5&lt;&#x2F;td&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Although this duplicates the trace columns, it significantly simplifies verifying the continuity and read-only properties, as we’ll see next.&lt;&#x2F;p&gt;
&lt;p&gt;However, adding these two columns introduces a new challenge: We need a way to verify that the new columns are permutations of the original ones. We’ll handle this with &lt;strong&gt;Permutation Constraints&lt;&#x2F;strong&gt; (spoiler alert: this requires the prover to add another column to the trace).&lt;&#x2F;p&gt;
&lt;p&gt;Thus, by adding these new columns, validating the memory properties boils down to proving these simpler way constraints:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Continuity Constraint**&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Single Value Constraint**&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Permutation Constraints**&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;constraints&quot;&gt;Constraints&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;continuity-constraint&quot;&gt;Continuity Constraint&lt;&#x2F;h3&gt;
&lt;p&gt;Our first constraint will ensure that memory addresses form a continuous range without gaps. For instance, if address 5 appears, addresses 4 and 6 must also appear to maintain continuity.&lt;&#x2F;p&gt;
&lt;p&gt;A valid example of continuous memory:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;sorted_addresses $(a’)$&lt;&#x2F;th&gt;&lt;th&gt;sorted_values $(v’)$&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;…&lt;&#x2F;td&gt;&lt;td&gt;…&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;100&lt;&#x2F;td&gt;&lt;td&gt;42&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;101&lt;&#x2F;td&gt;&lt;td&gt;17&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;102&lt;&#x2F;td&gt;&lt;td&gt;35&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;103&lt;&#x2F;td&gt;&lt;td&gt;22&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;104&lt;&#x2F;td&gt;&lt;td&gt;88&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;…&lt;&#x2F;td&gt;&lt;td&gt;…&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;An invalid example:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;sorted_addresses $(a’)$&lt;&#x2F;th&gt;&lt;th&gt;sorted_values $(v’)$&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;…&lt;&#x2F;td&gt;&lt;td&gt;…&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;100&lt;&#x2F;td&gt;&lt;td&gt;42&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;101&lt;&#x2F;td&gt;&lt;td&gt;17&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;103&lt;&#x2F;td&gt;&lt;td&gt;22&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;104&lt;&#x2F;td&gt;&lt;td&gt;88&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;…&lt;&#x2F;td&gt;&lt;td&gt;…&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Here, address 102 is missing, breaking continuity.&lt;&#x2F;p&gt;
&lt;p&gt;To check continuity, we examine the sorted address column, ensuring that the difference between consecutive addresses is always 0 (if they are the same) or 1 (if they are consecutive). The following Cairo constraint captures this:&lt;&#x2F;p&gt;
&lt;p&gt;$$(a_{i+1}^\prime - a_i^\prime )(a_{i+1}^\prime - a_i^\prime - 1) = 0 \text{ for all } i \in [0,n - 1]$$&lt;&#x2F;p&gt;
&lt;p&gt;Where $a_i^\prime$ represents the address in the $i$-th row of the sorted address column, and $v’_i$ represents the corresponding value.&lt;&#x2F;p&gt;
&lt;p&gt;In this equation:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The first factor, $(a&amp;#39;_{i+1} - a&amp;#39;_i)$ equals zero when addresses are the same.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The second factor, $(a&amp;#39;_{i+1} - a&amp;#39;_i - 1)$ equals zero when addresses differ by 1.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Since the product must equal zero, the addresses must be identical or differ by exactly 1, ensuring continuity.&lt;&#x2F;p&gt;
&lt;p&gt;Here’s how this is implemented in Rust:&lt;br &#x2F;&gt;
add code&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn evaluate(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;amp;self,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    frame: &amp;amp;Frame&amp;lt;F, F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transition_evaluations: &amp;amp;mut [FieldElement&amp;lt;F&amp;gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    _periodic_values: &amp;amp;[FieldElement&amp;lt;F&amp;gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    _rap_challenges: &amp;amp;[FieldElement&amp;lt;F&amp;gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transition_evaluations&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .get_mut(self.constraint_idx())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .map(|transition_eval| {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let first_step = frame.get_evaluation_step(0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let second_step = frame.get_evaluation_step(1);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let a_sorted_0 = first_step.get_main_evaluation_element(0, 2);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let a_sorted_1 = second_step.get_main_evaluation_element(0, 2);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let res = (a_sorted_1 - a_sorted_0)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                * (a_sorted_1 - a_sorted_0 - FieldElement::&amp;lt;F&amp;gt;::one());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            *transition_eval = res;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;where:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let first_step = frame.get_evaluation_step(0); &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;gives us access to the first row of the trace and&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let a_sorted_0 = first_step.get_main_evaluation_element(0, 2); &#x2F;&#x2F;a&amp;#39;_0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;will give access to the second third column which is element 2&lt;&#x2F;p&gt;
&lt;p&gt;Then the equation looks kike&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let res = (a_sorted_1 - a_sorted_0)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* (a_sorted_1 - a_sorted_0 - FieldElement::&amp;lt;F&amp;gt;::one());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;*transition_eval = res;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;single-value-constraint&quot;&gt;Single-Value Constraint&lt;&#x2F;h3&gt;
&lt;p&gt;This constraint ensures that each memory address has a single, consistent value. Even if the same address is accessed multiple times, the value must always remain the same.&lt;br &#x2F;&gt;
A valid example:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Address&lt;&#x2F;th&gt;&lt;th&gt;Value&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;…&lt;&#x2F;td&gt;&lt;td&gt;…&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;101&lt;&#x2F;td&gt;&lt;td&gt;17&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;101&lt;&#x2F;td&gt;&lt;td&gt;17&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;104&lt;&#x2F;td&gt;&lt;td&gt;88&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;…&lt;&#x2F;td&gt;&lt;td&gt;…&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;An invalid example:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Address&lt;&#x2F;th&gt;&lt;th&gt;Value&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;…&lt;&#x2F;td&gt;&lt;td&gt;…&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;101&lt;&#x2F;td&gt;&lt;td&gt;17&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;101&lt;&#x2F;td&gt;&lt;td&gt;42&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;102&lt;&#x2F;td&gt;&lt;td&gt;88&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;…&lt;&#x2F;td&gt;&lt;td&gt;…&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Here, address 101 has two different values, violating the constraint.&lt;&#x2F;p&gt;
&lt;p&gt;With an analogous logic to the one used in the continuity constraint, the Cairo paper defines the single-value constraint as:&lt;&#x2F;p&gt;
&lt;p&gt;$$(v_{i+1}^\prime - v_i^\prime )(a_{i+1}^\prime - a_i^\prime - 1) = 0 \quad \text{for all } i \in [0, n - 1]$$&lt;&#x2F;p&gt;
&lt;p&gt;In this equation:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The first factor, $(v&amp;#39;_{i+1} - v&amp;#39;_i)$ ensures that the values for identical addresses are the same.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The second factor, $(a&amp;#39;_{i+1} - a&amp;#39;_i - 1)$ ensures this check only applies to identical addresses.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here’s the implementation in Rust&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn evaluate(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;amp;self,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    frame: &amp;amp;Frame&amp;lt;F, F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transition_evaluations: &amp;amp;mut [FieldElement&amp;lt;F&amp;gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    _periodic_values: &amp;amp;[FieldElement&amp;lt;F&amp;gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    _rap_challenges: &amp;amp;[FieldElement&amp;lt;F&amp;gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transition_evaluations&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .get_mut(self.constraint_idx())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .map(|transition_eval| {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let first_step = frame.get_evaluation_step(0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let second_step = frame.get_evaluation_step(1);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let a_sorted_0 = first_step.get_main_evaluation_element(0, 2);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let a_sorted_1 = second_step.get_main_evaluation_element(0, 2);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let v_sorted_0 = first_step.get_main_evaluation_element(0, 3);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let v_sorted_1 = second_step.get_main_evaluation_element(0, 3);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let res = (v_sorted_1 - v_sorted_0)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                * (a_sorted_1 - a_sorted_0 - FieldElement::&amp;lt;F&amp;gt;::one());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            *transition_eval = res;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As with the continuity constraint, we extract the relevant rows and elements:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let a_sorted_0 = first_step.get_main_evaluation_element(0, 2); &#x2F;&#x2F; a&amp;#39;_i&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let a_sorted_1 = second_step.get_main_evaluation_element(0, 2); &#x2F;&#x2F; a&amp;#39;_{i+1}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let v_sorted_0 = first_step.get_main_evaluation_element(0, 3); &#x2F;&#x2F; v&amp;#39;_i&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let v_sorted_1 = second_step.get_main_evaluation_element(0, 3); &#x2F;&#x2F; v&amp;#39;_{i+1}`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The evaluation results ensure that if two addresses are equal, their corresponding values are consistent.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;permutation-constraint&quot;&gt;Permutation Constraint&lt;&#x2F;h3&gt;
&lt;p&gt;Now that we know that $a’$ and $v’$ represent a continuous read-only memory, we must prove that $a’$ and $v’$ are a permutation of the original $a$ and $v$ columns. We’ll achieve this using an interactive protocol:&lt;&#x2F;p&gt;
&lt;p&gt;First, the verifier sends the prover two random field elements $z, \alpha \in \mathbb{F}$, known as &lt;em&gt;challenges&lt;&#x2F;em&gt;. One detail to remember is that if we work with a small field $\mathbb{F}$, these elements should be sampled from an extension field, so all the following permutation constraints will be over the extension.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;&#x2F;strong&gt; In practice, the protocol is not interactive; instead, the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Fiat%E2%80%93Shamir_heuristic&quot;&gt;Fiat-Shamir heuristic&lt;&#x2F;a&gt; is used to obtain random values, enabling a non-interactive approach.&lt;&#x2F;p&gt;
&lt;p&gt;secondly, using these challenges, the prover constructs an auxiliary column $p$, which is added to the main trace table. This column is computed as:&lt;&#x2F;p&gt;
&lt;p&gt;$$ \begin{align} p_0 &amp;amp;= \frac {z - (a_0 + \alpha v_0)} {z - (a’_0 + \alpha v’_0)},&lt;br &#x2F;&gt;
\ \newline&lt;br &#x2F;&gt;
p_1 &amp;amp;= \frac {z - (a_0 + \alpha v_0)} {z - (a’_0 + \alpha v’_0)} \cdot \frac {z - (a_1 + \alpha v_1)} {z - (a’_1 + \alpha v’_1)} = p_0 \cdot \frac {z - (a_1 + \alpha v_1)} {z - (a’_1 + \alpha v’_1)},&lt;br &#x2F;&gt;
\ \newline&lt;br &#x2F;&gt;
p_2 &amp;amp;= p_1 \cdot \frac {z - (a_2 + \alpha v_2)} {z - (a’_2 + \alpha v’_2)}. \end{align}$$&lt;&#x2F;p&gt;
&lt;p&gt;Continuing with this procedure we get:&lt;&#x2F;p&gt;
&lt;p&gt;$$p_{i+1} = p_i \cdot \frac {z - (a_{i+1} + \alpha v_{i+1})} {z - (a_{i+1}^\prime + \alpha v_{i+1}^\prime )} \text{ with } i \in {0, \ldots, n - 2}$$&lt;&#x2F;p&gt;
&lt;p&gt;For example, if the main trace table is:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;$a$&lt;&#x2F;th&gt;&lt;th&gt;$v$&lt;&#x2F;th&gt;&lt;th&gt;$a’$&lt;&#x2F;th&gt;&lt;th&gt;$v’$&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;20&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;20&lt;&#x2F;td&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;then the table with the auxiliary column $p$ will look like this:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;$a$&lt;&#x2F;th&gt;&lt;th&gt;$v$&lt;&#x2F;th&gt;&lt;th&gt;$a’$&lt;&#x2F;th&gt;&lt;th&gt;$v’$&lt;&#x2F;th&gt;&lt;th&gt;$p$&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;td&gt;$\frac {z - (2 + \alpha 10)} {z - (0 + \alpha 7)}$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;td&gt;$\frac {z - (2 + \alpha 10)} {z - (0 + \alpha 7)} \cdot \frac {z - (0 + \alpha 7)} {z - (0 + \alpha 7)}$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;20&lt;&#x2F;td&gt;&lt;td&gt;$\frac {z - (2 + \alpha 10)} {z - (0 + \alpha 7)} \cdot \frac {z - (0 + \alpha 7)} {z - (0 + \alpha 7)} \cdot \frac {z - (0 + \alpha 7)} {z - (1 + \alpha 20)}$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;20&lt;&#x2F;td&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;td&gt;$\frac {z - (2 + \alpha 10)} {z - (0 + \alpha 7)} \cdot \frac {z - (0 + \alpha 7)} {z - (0 + \alpha 7)} \cdot \frac {z - (0 + \alpha 7)} {z - (1 + \alpha 20)} \cdot \frac {z - (1 + \alpha 20)} {z - (2 + \alpha 10)}$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Looking at the example, let us observe that the last value in column $p$ gives us the product of all the previous ones. Since the values indeed come from a permutation, each factor in the numerator (originated from $a$ and $v$) must appear once in the denominator (originated from $a’$ and $v’$), canceling each other out and resulting in the entire product equaling $1$. For instance, in the table above, the first numerator (orange) cancels out with the last denominator (orange):&lt;&#x2F;p&gt;
&lt;p&gt;$$\frac { {\style{color: orange} {z - (2 + \alpha 10)}}} {\style{color: cyan} {z - (0 + \alpha 7)}} \cdot \frac { \style{color: magenta} {z - (0 + \alpha 7)}} { \style{color: magenta} {z - (0 + \alpha 7)}} \cdot \frac { \style{color: cyan} {z - (0 + \alpha 7)}} { \style{color: lime} {z - (1 + \alpha 20)}} \cdot \frac { \style{color: lime} {z - (1 + \alpha 20)}} { \style{color: orange} {z - (2 + \alpha 10)}} = 1$$&lt;&#x2F;p&gt;
&lt;p&gt;Generalizing it to any trace with $n$ rows, we get the following last value, called &lt;em&gt;Grand Product&lt;&#x2F;em&gt; :&lt;&#x2F;p&gt;
&lt;p&gt;$$p_{n - 1} = \frac {z - (a_0 + \alpha v_0)} {z - (a_0^\prime + \alpha v_0^\prime )} \cdot \frac {z - (a_1 + \alpha v_1)} {z - (a_1^\prime + \alpha v_1^\prime )} \ldots \frac {z - (a_{n - 1} + \alpha v_{n - 1})} {z - (a_{n - 1}^\prime + \alpha v_{ n - 1 }^\prime )}$$&lt;&#x2F;p&gt;
&lt;p&gt;Then, using the randomness of $z$ and $\alpha$ (and the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Schwartz%E2%80%93Zippel_lemma&quot;&gt;Schwartz–Zippel Lemma&lt;&#x2F;a&gt;), we know that to prove that $a’$ and $v’$ are a permutation of $a$ and $v$, it suffices to check that:&lt;br &#x2F;&gt;
$$ p_{n-1} = 1$$&lt;&#x2F;p&gt;
&lt;p&gt;In this way, the constraints that guarantee the correct permutation are reduced to two boundary constraints and one transition constraint (you can find them in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2021&#x2F;1063.pdf&quot;&gt;Cairo Paper&lt;&#x2F;a&gt;, Section 9.7.2):&lt;&#x2F;p&gt;
&lt;h4 id=&quot;1-initial-value-boundary-constraint&quot;&gt;1. Initial Value Boundary Constraint:&lt;&#x2F;h4&gt;
&lt;p&gt;$$p_0 = \frac {z - (a_0 + \alpha v_0)} {z - (a_0^\prime + \alpha v_0^\prime )}$$ We check that the first value in the auxiliary column is correct.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;2-final-value-boundary-constraint&quot;&gt;2. Final Value Boundary Constraint:&lt;&#x2F;h4&gt;
&lt;p&gt;$$p_{n - 1} = 1$$ We check that the Grand Product equals 1.&lt;&#x2F;p&gt;
&lt;p&gt;In our code, these two Boundary Constraints are located in the &lt;code&gt;boundary_constraints()&lt;&#x2F;code&gt; function of the &lt;code&gt;AIR&lt;&#x2F;code&gt; implementation for &lt;code&gt;ReadOnlyRAP&amp;lt;F&amp;gt;&lt;&#x2F;code&gt;. You can see them below, after the comment &lt;code&gt;&#x2F;&#x2F;Auxiliary boundary constraints&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn boundary_constraints(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;amp;self,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    rap_challenges: &amp;amp;[FieldElement&amp;lt;Self::FieldExtension&amp;gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; BoundaryConstraints&amp;lt;Self::FieldExtension&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let a0 = &amp;amp;self.pub_inputs.a0;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let v0 = &amp;amp;self.pub_inputs.v0;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let a_sorted0 = &amp;amp;self.pub_inputs.a_sorted0;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let v_sorted0 = &amp;amp;self.pub_inputs.v_sorted0;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let z = &amp;amp;rap_challenges[0];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let alpha = &amp;amp;rap_challenges[1];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Main boundary constraints&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let c1 = BoundaryConstraint::new_main(0, 0, a0.clone());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let c2 = BoundaryConstraint::new_main(1, 0, v0.clone());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let c3 = BoundaryConstraint::new_main(2, 0, a_sorted0.clone());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let c4 = BoundaryConstraint::new_main(3, 0, v_sorted0.clone());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Auxiliary boundary constraints&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let num = z - (a0 + alpha * v0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let den = z - (a_sorted0 + alpha * v_sorted0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let p0_value = num &#x2F; den;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let c_aux1 = BoundaryConstraint::new_aux(0, 0, p0_value);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let c_aux2 = BoundaryConstraint::new_aux(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        0,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        self.trace_length - 1,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        FieldElement::&amp;lt;Self::FieldExtension&amp;gt;::one(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    BoundaryConstraints::from_constraints(vec![c1, c2, c3, c4, c_aux1, c_aux2])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note that the values of $a$, $a’$, $v$, $v’$ from the first row of the trace must also be known by the verifier to perform the check for the Initial Value constraint. This is a problem we did not have before (the rest of the constraints do not depend on the trace) since the verifier only has access to the commitment of the trace, not its elements. Therefore, this first row must be part of the public input.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;3-permutation-transition-constraint&quot;&gt;3. Permutation Transition Constraint:&lt;&#x2F;h4&gt;
&lt;p&gt;$$(z - (a_{i+1}^\prime + \alpha v_{i + 1}^\prime )) \cdot p_{i+1} - (z - (a_{i+1} + \alpha v_{i+1})) \cdot p_i = 0$$ for all $i \in {0, \ldots, n-2}$.&lt;&#x2F;p&gt;
&lt;p&gt;In this way, we check that each element of $p$ was constructed correctly, with the last element being the Grand Product. In our code, we call this transition constraint &lt;code&gt;PermutationConstraint&lt;&#x2F;code&gt;. When implementing its corresponding &lt;code&gt;evaluate()&lt;&#x2F;code&gt; function (link), the use of this equation can be seen:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn evaluate(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;amp;self,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    frame: &amp;amp;Frame&amp;lt;F, F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transition_evaluations: &amp;amp;mut [FieldElement&amp;lt;F&amp;gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    _periodic_values: &amp;amp;[FieldElement&amp;lt;F&amp;gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    rap_challenges: &amp;amp;[FieldElement&amp;lt;F&amp;gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let first_step = frame.get_evaluation_step(0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let second_step = frame.get_evaluation_step(1);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let p0 = first_step.get_aux_evaluation_element(0, 0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let p1 = second_step.get_aux_evaluation_element(0, 0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let z = &amp;amp;rap_challenges[0];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let alpha = &amp;amp;rap_challenges[1];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let a1 = second_step.get_main_evaluation_element(0, 0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let v1 = second_step.get_main_evaluation_element(0, 1);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let a_sorted_1 = second_step.get_main_evaluation_element(0, 2);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let v_sorted_1 = second_step.get_main_evaluation_element(0, 3);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let res = (z - (a_sorted_1 + alpha * v_sorted_1)) * p1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        - (z - (a1 + alpha * v1)) * p0;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transition_evaluations[self.constraint_idx()] = res;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;By introducing sorted columns and auxiliary columns, we reduce the problem of validating a continuous read-only memory to proving three simpler constraints:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Continuity that ensures all memory addresses form a complete range.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Single-Value that ensures each address always returns the same value.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Permutation that ensures the sorted columns are permutations of the original columns.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;These constraints demonstrate the simplicity of STARKs in encoding complex relationships as polynomial equations.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>lambdaworks - recap and updated roadmap</title>
          <pubDate>Tue, 24 Sep 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/lambdaworks-recap-and-updated-roadmap/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/lambdaworks-recap-and-updated-roadmap/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/lambdaworks-recap-and-updated-roadmap/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;It has been over a year and a half since we launched &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&quot;&gt;lambdaworks&lt;&#x2F;a&gt;, our cryptography library for zero-knowledge (ZK) proofs. We built it focusing on performance, ease of use, support for hardware acceleration, and teaching others how to develop and understand ZK.&lt;&#x2F;p&gt;
&lt;p&gt;Several advances in ZK in the last year have offered incredible performance gains over previous schemes. For example, circle STARKs has allowed to prove over &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;x.com&#x2F;StarkWareLtd&#x2F;status&#x2F;1807776563188162562&quot;&gt;620k Poseidon2 hashes per second on consumer-end hardware&lt;&#x2F;a&gt;. Binius allows us to leverage the power of binary fields. Their performance can be greatly increased by using specialized hardware. We have seen new lookup arguments that depend only on the number of lookups used. We also have more efficient hash functions. Last year, we also saw the development and release of general proving zk virtual machines (zkvm). These allow us to write ordinary code (for example, in Rust), execute it on top of the virtual machine, and generate a proof of the execution. This simplifies the development of verifiable applications, abstracting developers from the low-level details of ZK. With the introduction of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.alignedlayer.com&#x2F;&quot;&gt;Aligned&lt;&#x2F;a&gt;, we expect proof verification costs to go consistently down, enabling new verifiable applications built on top of Ethereum. We can predict that ZK will become more and more important in the coming years, and it is necessary, therefore, to have many of the essential tools in our library.&lt;&#x2F;p&gt;
&lt;p&gt;Before jumping into the future, let us recap some of the features and numbers of lambdaworks:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * 493 pull requests merged.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * 73 contributors.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * 14 releases.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Over 185k downloads.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * 4 proof systems (STARKs, Cairo, Groth16, Plonk) and two additional example implementations (Pinocchio and BabySNARK).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * 2 editions of the Sparkling Water Bootcamp in Cryptography, with 30 bootcampers from different countries.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Backend for finite fields](https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;tree&#x2F;main&#x2F;math&#x2F;src&#x2F;field) using Montgomery arithmetic, plus specialized backends for fields with simpler reduction formulae.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Backend for elliptic curve operations](https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;tree&#x2F;main&#x2F;math&#x2F;src&#x2F;elliptic_curve), with different coordinate systems.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Backend for Univariate polynomials](https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;tree&#x2F;main&#x2F;math&#x2F;src&#x2F;polynomial) and Fast Fourier Transform (FFT).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Several cryptographic tools, such as hash functions (Poseidon and Pedersen), Merkle trees, KZG commitments, and Fiat-Shamir transformation.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Examples and exercises.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Considering all the recent advances and trends, as well as the experience we got from users and friends, we will incorporate new features and improve existing ones according to the following roadmap.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;roadmap&quot;&gt;Roadmap&lt;&#x2F;h2&gt;
&lt;p&gt;The following is a list of features and updates we want to incorporate into lambdaworks. We may change some or include new ones according to the latest developments in ZK technology:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Improve field backends using assembly.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Improve field extension backends.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Provide new backend implementation for Mersenne primes.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Incorporate binary fields.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Improve and add features on multilinear and multivariate polynomials.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Improve the performance of BLS12-381 and BLS12-377 pairings.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Add new hash functions: Rescue, [XHash8 and XHash12](https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2023&#x2F;1045.pdf), Poseidon 2.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Add [logUp with GKR](https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2023&#x2F;1284).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Add [Binius](https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2023&#x2F;1784).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Add [Circle STARKs](https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2024&#x2F;278).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Provide tools for efficient proof recursion.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Provide more documentation, examples, use cases, etc.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Add more theoretical background to the library.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Finish integration with [Icicle](https:&#x2F;&#x2F;github.com&#x2F;ingonyama-zk&#x2F;icicle).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Add bindings for Python and other programming languages.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;Over the last year and a half, we have seen many new developments in ZK, improving the performance of proof systems while greatly simplifying the development of verifiable applications. The introduction of ZK verification layers will lead to lower verification costs and new applications.&lt;&#x2F;p&gt;
&lt;p&gt;lambdaworks has incorporated many proof systems and different cryptographic primitives to help developers build applications and understand how things work under the hood. We present the new roadmap for the library, hoping to incorporate new proof systems, such as Circle STARKS and Binius while maintaining simplicity and providing clear and straightforward documentation. That way, we hope to bring ZK to developers worldwide, helping them adopt and make this transformative technology available to everybody.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>How we implemented the BN254 Ate pairing in lambdaworks</title>
          <pubDate>Tue, 20 Aug 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/how-we-implemented-the-bn254-ate-pairing-in-lambdaworks/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/how-we-implemented-the-bn254-ate-pairing-in-lambdaworks/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/how-we-implemented-the-bn254-ate-pairing-in-lambdaworks/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;The elliptic curve BN254 is currently the only curve with precompiled contracts on Ethereum, making it the most practical choice of a pairing-friendly curve suitable for on-chain &lt;a href=&quot;&#x2F;pinocchio-verifiable-computation-revisited&#x2F;&quot;&gt;zk-SNARK&lt;&#x2F;a&gt; verification with proof systems such as &lt;a href=&quot;&#x2F;groth16&#x2F;&quot;&gt;Groth16&lt;&#x2F;a&gt; and &lt;a href=&quot;&#x2F;all-you-wanted-to-know-about-plonk&#x2F;&quot;&gt;PlonK&lt;&#x2F;a&gt;. This work arises from the need to have our &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;blob&#x2F;main&#x2F;math&#x2F;src&#x2F;elliptic_curve&#x2F;short_weierstrass&#x2F;curves&#x2F;bn_254&#x2F;pairing.rs&quot;&gt;own implementation of the BN254 Ate pairing&lt;&#x2F;a&gt;. The idea of this post is to serve as a companion for our implementation, explaining the mathematical theory and algorithms needed to understand it. Several papers and articles present different algorithms for this pairing and its functions, so we thought organizing all that information into a single post would be helpful.&lt;&#x2F;p&gt;
&lt;p&gt;Regarding the mathematical background necessary to follow this reading, we only assume a slight notion of Groups, Finite Fields, and Elliptic Curves. If you do not feel confident in those topics we recommend reading our posts &lt;a href=&quot;&#x2F;math-survival-kit-for-developers&#x2F;&quot;&gt;Math Survival Kit for Developers&lt;&#x2F;a&gt; and &lt;a href=&quot;&#x2F;what-every-developer-needs-to-know-about-elliptic-curves&#x2F;&quot;&gt;What Every Developer Needs to Know About Elliptic Curves&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;curve-parameters&quot;&gt;Curve Parameters&lt;&#x2F;h2&gt;
&lt;p&gt;The BN254 (in Lambdaworks &lt;code&gt;BN254Curve&lt;&#x2F;code&gt;) is the Barreto-Naehrig pairing friendly elliptic curve $E$ of the form&lt;br &#x2F;&gt;
$$y^2 = x^3 + 3$$&lt;br &#x2F;&gt;
over a finite field $\mathbb{F_p}$ where:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $p = 36x^4 + 36x^3 + 24x^2 + 6x + 1$ is the 254-bit prime number:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;p = 21888242871839275222246405745257275088696311157297823662689037894645226208583&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;x = 4965661367192848881&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $t = 6x^2 + 1$ is the trace of Frobenius.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $r = 36x^4 + 36x^3 + 18x^2 + 6x + 1 = p + 1 - t$ is the number of points in the curve $E(\mathbb{F_p })$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;point-coordinates&quot;&gt;Point Coordinates&lt;&#x2F;h2&gt;
&lt;p&gt;Since we define the elliptic curve as the set of points that satisfy the equation written above, it is natural to think of an element $P \in E(\mathbb{F_p })$ using two coordinates $P = (x, y)$. This representation is called &lt;em&gt;Affine Representation&lt;&#x2F;em&gt; and its coordinates are known as &lt;em&gt;Affine Coordinates&lt;&#x2F;em&gt;. However, many times to optimize the arithmetic, it will be convenient to use what is known as &lt;em&gt;Projective Coordinates&lt;&#x2F;em&gt; , which represent the points with three coordinates $x,$ $y,$ $z$, and is constructed in the following way:&lt;br &#x2F;&gt;
If $P = (x, y)$ is a point in affine coordinates, then $(x, y, 1)$ is its projective representation. And if $P = (x, y, z)$ is a point in projective coordinates, then $(\frac{x}{z}, \frac{y}{z})$ is its affine representation. You’ll see in our implementation that we use both representations depending on what we need in each case, using functions like &lt;code&gt;to_affine()&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;There is a third representation that we won’t use, but you may find in some papers, called &lt;em&gt;Jacobian Coordinates&lt;&#x2F;em&gt; : If $P = (x, y, z)$ is a point in Jacobian coordinates, then $(\frac{x}{z}, \frac{y}{z^2 }, z)$ and $(\frac{x}{z^2 }, \frac{y}{z^3 })$ are its projective and affine coordinates respectively.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;field-extension-tower&quot;&gt;Field Extension Tower&lt;&#x2F;h2&gt;
&lt;p&gt;A pairing is a map $e: \mathbb{G_1 } \times \mathbb{G_2 } \to \mathbb{G_t }$, and this means that it takes as input two points, each from a group with the same number of points (or order) $r$. This number $r$ must be prime, and to guarantee security, it must be large. Also, for rather technical reasons, these two groups need to be distinct. So, to define a pairing, we need to choose these domains and codomain groups. The group $\mathbb{G_1 }$ will be the curve $E(\mathbb{F_p })$, but to define $\mathbb{G_2 }$ and $\mathbb{G_t }$ we’ll need to &lt;em&gt;extend&lt;&#x2F;em&gt; the field $\mathbb{F_p }$. We are not going to stop to explain in detail what field extensions are and how they are built, so if you are looking for a better understanding, we recommend reading the section &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;hackmd.io&#x2F;@benjaminion&#x2F;bls12-381#Field-extensions&quot;&gt;Field Extensions&lt;&#x2F;a&gt; from &lt;em&gt;BLS12-381 For the Rest of US&lt;&#x2F;em&gt;. Here, we’ll summarize the basic concepts necessary to understand our implementation and the algorithms we use.&lt;&#x2F;p&gt;
&lt;p&gt;Roughly speaking, our goal is to extend the field $\mathbb{F_p }$ to $\mathbb{F_{ p^{12} }}$, and we will do it in the following way. First, we extend $\mathbb{F_p }$ to $\mathbb{F_{ p^2 }}$ in the same way that the field of real numbers $\mathbb{R}$ is extended to the field of complex numbers $\mathbb{C}$: We define $$\mathbb{F_{ p^2 }} = \mathbb{F_p } [u] &#x2F; (u^2 + 1).$$ That’s a lot of symbols to process. The good news is that all we need to understand is that $F_{ p^2 }$ is a finite field whose elements are polynomials of degree 1 and variable $u$; that is, they have the form $$a + bu \quad \text{ with } a, b \in \mathbb{F_p }.$$ If we think it as complex numbers, $a$ would be the real part and $b$ the imaginary one. Note that $\mathbb{F_p } \subseteq \mathbb{F_{ p^2 }}$ because we can think of the elements of the left one as elements of the right one with “imaginary part” zero or $b = 0$. So, $\mathbb{F_{ p^2 } }$ is indeed an extension of $\mathbb{F_p }.$&lt;br &#x2F;&gt;
Secondly, we extend $\mathbb{F_{ p^2 }}$ in a similar way defining $$\mathbb{F_{ p^6 }} = \mathbb{F_{ p^2 }} [v] &#x2F; (v^3 - (9 + u)).$$ In this case, since $v^3 - (9 + u)$ is a polynomial of degree 3, the elements of $\mathbb{F_{ p^6 }}$ will be polynomials of degree 2 and variable $v$ of the form $$a + bv + cv^2 \quad \text{ with } a, b, c \in \mathbb{F_{ p^2 }}.$$ Finally, we extend $\mathbb{F_{ p^6 }}$ defining $$\mathbb{F_{ p^{12} }} = \mathbb{F_{ p^6 }} [w] &#x2F; (w^2 - v),$$ that is, its elements are again polynomials of degree 1 with variable $w$ of the form $$a + bw \quad \text{ with } a, b \in \mathbb{F_{ p^6 } }.$$&lt;br &#x2F;&gt;
Now, in practice, using lambdaworks, we have two different ways to define an element $f = a + bw \in \mathbb{F_{ p^{12} }}$. We can use &lt;code&gt;new()&lt;&#x2F;code&gt;,&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let f = Fp12E::new([a, b])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;or we can use &lt;code&gt;from_coefficients()&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let f = Fp12E::from_coefficients([&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;quot;a_00&amp;quot;, &amp;quot;a_01&amp;quot;, &amp;quot;a_10&amp;quot;, &amp;quot;a_11&amp;quot;, &amp;quot;a_20&amp;quot;, &amp;quot;a_21&amp;quot;, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;quot;b_00&amp;quot;, &amp;quot;b_01&amp;quot;, &amp;quot;b_10&amp;quot;, &amp;quot;b_11&amp;quot;, &amp;quot;b_20&amp;quot;, &amp;quot;b_21&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In the last case we use 12 coefficients to define $f$ because $f = a + bw$, where $a, b \in \mathbb{F_{ p^6 }}$. Then, $$a = \style{color: magenta} {a_0} + \style{color: magenta} {a_1}v + \style{color: magenta}{a_2}v^2 \quad \text{and} \quad b = \style{color: orange}{b_0} + \style{color: orange}{b_1}v + \style{color: orange}{b_2}v^2,&lt;br &#x2F;&gt;
$$ with $a_i, b_i \in \mathbb{F_{ p^2 }}$. And therefore, $$\style{color: magenta}{a_i} = a_{i0} + a_{i1} u \quad \text{and} \quad \style{color: orange}{b_i} = b_{i0} + b_{i1} u,$$ thus reaching the 12 coefficients.&lt;&#x2F;p&gt;
&lt;p&gt;There is another representation of the elements of $\mathbb{F_{ p^{12} }}$ that you could find in papers and algorithms that we used in our implementation. Since $v^3 = 9 + u$ and $w^2 = v$, we have that $w^6 = 9 + u$ and then, $$\mathbb{F_{ p^{12} }} = \mathbb{F_{ p^2 }} [w] &#x2F; (w^6 - (9 + u)).$$ Again, you don’t have to understand the previous sentence; the important thing is that we can not only represent $f$ as a polynomial of degree 1 and as a polynomial of degree 11 but also as a polynomial of degree 5 using $a_i$ and $b_i$ in the following way:&lt;br &#x2F;&gt;
$$ f = \style{color: magenta}{a_0} + \style{color: orange}{b_0} w + \style{color: magenta}{a_1} w^2 + \style{color: orange}{b_1} w^3 + \style{color: magenta}{a_2} w^4 + \style{color: orange}{b_2} w^5.$$ So every time you see an element of $\mathbb{F_{ p^{12} }}$ represented as a polynomial of degree 5, you will know how to write it as $a + bw$, constructing $a = \style{color: magenta}{a_0} + \style{color: magenta}{a_1}v + \style{color: magenta}{a_2}v^2$ and $b = \style{color: orange}{b_0} + \style{color: orange}{b_1}v + \style{color: orange}{b_2}v^2$ using its coefficients (and vice versa). Having different representations of the same extension field will allow us to apply some optimizations when implementing the pairing (see the section &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;hackmd.io&#x2F;@Wimet&#x2F;ry7z1Xj-2#Tower-of-Extension-Fields&quot;&gt;Tower of Extension Fields&lt;&#x2F;a&gt; of &lt;em&gt;Computing the Optimal Ate Pairing Over the BN254 Curve&lt;&#x2F;em&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;This may be a lot of new information, but don’t worry; you don’t need to understand it in detail. When reading the implementation, the idea is to have these equalities at hand to recognize where each variable belongs and how many coefficients it has. In lambdaworks &lt;code&gt;bn_254&lt;&#x2F;code&gt; you’ll find these fields $\mathbb{F_p} ,$ $\mathbb{F_{ p^2 }},$ $\mathbb{F_{ p^6 }}$ and $\mathbb{F_{ p^{12} }}$ (with their operations implemented) as &lt;code&gt;BN254PrimeField&lt;&#x2F;code&gt;, &lt;code&gt;Degree2ExtensionField&lt;&#x2F;code&gt;, &lt;code&gt;Degree6ExtensionField&lt;&#x2F;code&gt; and &lt;code&gt;Degree12ExtensionField&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;twist&quot;&gt;Twist&lt;&#x2F;h2&gt;
&lt;p&gt;Since doing arithmetic in $\mathbb{F_{ p^{12} }}$ is complicated and inefficient, we will use a &lt;em&gt;twist&lt;&#x2F;em&gt; that is like a coordinate conversion which tranforms our $E(\mathbb{F_{ p^{12} }})$ curve into the following curve $E’$ defined over $\mathbb{F_{ p^2 }}$:&lt;br &#x2F;&gt;
$$y^2 = x^3 + \frac{3}{9 + u} .$$&lt;br &#x2F;&gt;
We will call $b = \frac{3}{9 + u}$ implemented as &lt;code&gt;BN254TwistCurve::b()&lt;&#x2F;code&gt; .&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;b = 19485874751759354771024239261021720505790618469301721065564631296452457478373 &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    + 266929791119991161246907387137283842545076965332900288569378510910307636690 &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * u&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So, in summary, we will use the following subgroups as inputs for the pairing:&lt;br &#x2F;&gt;
$$\mathbb{G_1} = E (\mathbb{F_p} ),$$&lt;br &#x2F;&gt;
$$\mathbb{G_2} \subseteq E^\prime ( \mathbb{F_{ p^2 }}) .$$&lt;br &#x2F;&gt;
And the output:&lt;br &#x2F;&gt;
$$\mathbb{G_t} \subseteq \mathbb{F_{ p^{12} } }^{\star} ,$$ where $\mathbb{F_{ p^{12} } }^{\star} = \mathbb{F_{ p^{12} } } - {0}$ (the multiplicative group of the field).&lt;&#x2F;p&gt;
&lt;p&gt;Knowing precisely which subgroups $\mathbb{G_2 }$ and $\mathbb{G_t }$ we should take is not relevant to understand our implementation. We will just say for those who have the mathematical background or are interested in going deeper into those topics, that $\mathbb{G_1 }$ and $\mathbb{G_2 }$ are the $r$-&lt;em&gt;torsion groups&lt;&#x2F;em&gt; (i.e. the set of elements of &lt;em&gt;order&lt;&#x2F;em&gt; $r$), while $\mathbb{G_t }$ is the set of the $r$-&lt;em&gt;th roots of unity&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-pairing&quot;&gt;The Pairing&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;what-is-a-pairing&quot;&gt;What is a pairing?&lt;&#x2F;h3&gt;
&lt;p&gt;Let’s better understand it now that we have defined everything necessary to build our pairing. A pairing is a bilinear map $e: \mathbb{G_1 } \times \mathbb{G_2 } \to \mathbb{G_t }$. &lt;em&gt;Bilinear&lt;&#x2F;em&gt; means that it has the following property: For all points $P_1, P_2 \in \mathbb{G_1 }$ and $Q_1, Q_2 \in \mathbb{G_2 }$,&lt;br &#x2F;&gt;
$$\begin{align} e(P_1, Q_1 + Q_2) &amp;amp;= e(P_1, Q_1) \cdot e(P_1, Q_2) \newline&lt;br &#x2F;&gt;
e(P_1 + P_2, Q_1) &amp;amp;= e(P_1, Q_1) \cdot e(P_2, Q_1)\end{align}$$ And from this property, it can be deduced the next one: For all $n, m \in \mathbb{N}$,&lt;br &#x2F;&gt;
$$e(nP, mQ) = e(mQ, nP) = e(P, mQ)^n = e(nP, Q)^m = e(P, Q)^{nm}.$$ Recall that in general, the additive notation $+$ is used to denote the operation of the groups $\mathbb{G_1 }$ and $\mathbb{G_2 }$, and multiplicative notation $\cdot$ is used to denote the operation of $\mathbb{G_t }$.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ate-pairing-algorithm&quot;&gt;Ate Pairing Algorithm&lt;&#x2F;h3&gt;
&lt;p&gt;We will use the algorithm of the Ate pairing from &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2010&#x2F;354.pdf&quot;&gt;this paper&lt;&#x2F;a&gt; (Page 4, Algorithm 1):&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;Inputs&lt;&#x2F;strong&gt; : $P \in \mathbb{G}_1$ and $Q \in \mathbb{G}_2$&lt;br &#x2F;&gt;
&lt;strong&gt;Output:&lt;&#x2F;strong&gt; $f \in \mathbb{G}_t$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. define $T \in \mathbb{G}_2$;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. $T \leftarrow Q$;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. define $f \in \mathbb{G}_t$;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. $f \leftarrow 1$;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. for $i =$ `miller_length` $- 2$ to 0 do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    6.      $f \leftarrow f^2$;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    7.      $T \leftarrow 2T$;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    8.      if `MILLER_CONSTANT`$[i] = -1$ then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    9.          $f \leftarrow f \cdot l_{T, -Q}(P)$;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    10.          $T \leftarrow T - Q$;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    11.      else if `MILLER_CONSTANT`$[i] = 1$ then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    12.          $f \leftarrow f \cdot l_{T, Q}(P)$;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    13.          $T \leftarrow T + Q$;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    14.      end if&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    15. end for&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    16. $Q_1 \leftarrow \varphi(Q)$;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    17. $f \leftarrow f \cdot l_{T, Q_1 }(P)$;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    18. $T \leftarrow T + Q_1$;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    19. $Q_2 \leftarrow \varphi(Q_1)$;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    20. $f \leftarrow f \cdot l_{T, - Q_2}(P)$;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    21. $f \leftarrow f^{ \frac{ p^{12} - 1 }{r}}$;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    22. return f;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;where:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The number `MILLER_CONSTANT` $=6x + 2$ with $x$ as the curve parameter we mentioned before. However, we need a particular representation of this number using powers of 2 and the coefficients $\\{- 1, 0, 1 \\}$. This representation is similar to a [NAF representation](https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Non-adjacent_form#:~:text=The%20non%2Dadjacent%20form%20\(NAF,8%20%E2%88%92%202%20%2B%201%20%3D%207\)), although it isn&amp;#39;t a NAF because it has non-zero values adjacent.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          &#x2F;&#x2F; MILLER_CONSTANT = 6x + 2 = 29793968203157093288 =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          &#x2F;&#x2F; 2^3 + 2^5 - 2^7 + 2^10 - 2^11 + 2^14 + 2^17 + 2^18 - 2^20 + 2^23 &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          &#x2F;&#x2F; - 2^25 + 2^30 + 2^31 + 2^32 - 2^35 + 2^38 - 2^44 + 2^47 + 2^48 &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          &#x2F;&#x2F; - 2^51 + 2^55 + 2^56 - 2^58 + 2^61 + 2^63 + 2^64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          pub const MILLER_CONSTANT: [i32; 65] = [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;              0, 0, 0, 1, 0, 1, 0, -1, 0, 0, 1, -1, 0, 0, 1, 0, 0, 1, 1, 0, -1, 0, 0, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;              1, 0, -1, 0, 0, 0, 0, 1, 1, 1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;              0, 1, 1, 0, 0, -1, 0, 0, 0, 1, 1, 0, -1, 0, 0, 1, 0, 1, 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          ];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          let miller_length = MILLER_CONSTANT.len()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The function $l_{T, Q}(P)$ is the line that passes through $T$ and $Q$ evaluated in $P$. We&amp;#39;ll see how to compute it later.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The Frobenius morphism $\varphi: E&amp;#39;(\mathbb{F_{ p^2 } }) \to E&amp;#39;(\mathbb{F_{ p^2 }})$ is defined as $\varphi(x, y) = (x^p, y^p)$. We&amp;#39;ll also see it later.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;batch&quot;&gt;Batch&lt;&#x2F;h3&gt;
&lt;p&gt;We will divide the algorithm presented into Miller Loop and Final Exponentiation to implement it. The &lt;code&gt;miller()&lt;&#x2F;code&gt; function does all the work from lines 1 to 20 of the algorithm, while &lt;code&gt;final_exponentiation()&lt;&#x2F;code&gt; computes only the last line 21 (which is a computation that requires some work). However, if we have different pairs of points $(P, Q)$ and we want to calculate each of their pairings to multiply all the results together (and see, for example, if it equals $1$), the most efficient way to do it is first to execute the Miller Loop for each pair of points, multiply the results and then apply the Final Exponentiation to the final result. The function that does this procedure is called &lt;code&gt;compute_batch()&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn compute_batch(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pairs: &amp;amp;[(&amp;amp;Self::G1Point, &amp;amp;Self::G2Point)],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; Result&amp;lt;FieldElement&amp;lt;Self::OutputField&amp;gt;, PairingError&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut result = Fp12E::one();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for (p, q) in pairs {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F; do some checks before computing the Miller loop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        if !p.is_neutral_element() &amp;amp;&amp;amp; !q.is_neutral_element() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let p = p.to_affine();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let q = q.to_affine();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            result *= miller(&amp;amp;p, &amp;amp;q);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Ok(final_exponentiation(&amp;amp;result))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;subgroup-check&quot;&gt;Subgroup Check&lt;&#x2F;h2&gt;
&lt;p&gt;Before applying the pairing to a given pair of points $(P, Q)$, it is necessary to check that the points belong to its domain. In other words, we need to see that $P \in \mathbb{G_1 }$ and $Q \in \mathbb{G_2 }$. Since $\mathbb{G_1 } = E(\mathbb{F_p })$, there is nothing to check about $P$. But, since $\mathbb{G_2 }$ is distinct from $E’(\mathbb{F_{ p^2 }})$, we need an efficient way to check that $Q$ belongs to the subgroup.&lt;&#x2F;p&gt;
&lt;p&gt;We’ll use &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;hackmd.io&#x2F;@Wimet&#x2F;ry7z1Xj-2#Subgroup-Checks&quot;&gt;this post&lt;&#x2F;a&gt; that states that a point $Q \in E’(\mathbb{F_{ p^2 }})$ belongs to $\mathbb{G_2 }$ if and only if&lt;br &#x2F;&gt;
$$(x + 1)Q + \varphi (xQ) + \varphi^2 (xQ) = \varphi^3 (2xQ).$$ Recall that $x$ is one of the curve’s parameters and $\varphi$ is the Frobenius Morphism mentioned before. So first, we need to implement this morphism efficiently, avoiding powering elements to $p$ (because $p$ is a very large number). For that, we’ll use two constants $\gamma_{1,2}, \gamma_{1,3} \in \mathbb{F_{ p^2 }}$ (later on, we’ll see them in more detail).&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub const GAMMA_12: Fp2E = Fp2E::const_from_raw([&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    FpE::from_hex_unchecked(&amp;quot;2FB347984F7911F74C0BEC3CF559B143B78CC310C2C3330C99E39557176F553D&amp;quot;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    FpE::from_hex_unchecked(&amp;quot;16C9E55061EBAE204BA4CC8BD75A079432AE2A1D0B7C9DCE1665D51C640FCBA2&amp;quot;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub const GAMMA_13: Fp2E = Fp2E::const_from_raw([&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    FpE::from_hex_unchecked(&amp;quot;63CF305489AF5DCDC5EC698B6E2F9B9DBAAE0EDA9C95998DC54014671A0135A&amp;quot;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    FpE::from_hex_unchecked(&amp;quot;7C03CBCAC41049A0704B5A7EC796F2B21807DC98FA25BD282D37F632623B0E3&amp;quot;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Having these constants, it’s very easy to compute $\varphi$. We simply use that $$\varphi(x, y) = (\gamma_{1,2} \bar x, \gamma_{1,3} \bar y),$$ where $\bar x$ is the notation for the conjugate of $x$: If $x = a + bw \in \mathbb{F_{ p^2 }}$, then $\bar x = a - b w.$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn phi(&amp;amp;self) -&amp;gt; Self {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let [x, y, z] = self.coordinates();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Self::new([&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        x.conjugate() * GAMMA_12,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        y.conjugate() * GAMMA_13,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        z.conjugate(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now that we have $\varphi$, we can implement a function that determines if a certain point $Q$ of the twist curve $E’(\mathbb{F_{ p^2 }})$ belongs to the subgroup $\mathbb{G_2 }$.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn is_in_subgroup(&amp;amp;self) -&amp;gt; bool {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let q_times_x = &amp;amp;self.operate_with_self(X);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let q_times_x_plus_1 = &amp;amp;self.operate_with(q_times_x);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let q_times_2x = q_times_x.double();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    q_times_x_plus_1.operate_with(&amp;amp;q_times_x.phi().operate_with(&amp;amp;q_times_x.phi().phi()))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        == q_times_2x.phi().phi().phi()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;the-line&quot;&gt;The Line&lt;&#x2F;h2&gt;
&lt;p&gt;Let’s see now how to implement for all $T, Q \in \mathbb{G_2 }$ and $P \in \mathbb{G_1 }$ the line $l_{T, Q}(P)$, called in lambdaworks &lt;code&gt;line()&lt;&#x2F;code&gt;, the fundamental function of the Miller Loop. First, we could have two cases: $T = Q$ or $T \neq Q$. In the first case, $l_{T, T} (P)$ is the tangent line of $T$ evaluated in $P$. In the second case, it is the line that passes through $T$ and $Q$ evaluated in $P.$&lt;&#x2F;p&gt;
&lt;p&gt;For our implementation, we relied on the algorithm proposed in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2013&#x2F;722.pdf&quot;&gt;The Realm of the Pairings&lt;&#x2F;a&gt;. We use equation 11 on page 13 for the case $T = Q$ and the first equation on page 14 for the case $T \neq Q.$ You can also see the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;arkworks-rs&#x2F;algebra&#x2F;blob&#x2F;master&#x2F;ec&#x2F;src&#x2F;models&#x2F;bn&#x2F;g2.rs#L25&quot;&gt;Arkworks implementation&lt;&#x2F;a&gt; of the same algorithm, where the function that computes the case $T=Q$ is called &lt;code&gt;double_in_place()&lt;&#x2F;code&gt;, and the one for the case $T \neq Q$ is called &lt;code&gt;add_in_place()&lt;&#x2F;code&gt;. You will see that both the paper and Arkworks define more variables than we do. That’s because those functions compute the line and $2T$ (in the first case) and $T + Q$ (in the second case), necessary values for the lines 7, 10, 13, and 18 of the Ate pairing algorithm. We didn’t have to do it that way because in those lines, to double an element or to add two elements of a group, we used the lambdaworks functions &lt;code&gt;operate_with_self()&lt;&#x2F;code&gt; and &lt;code&gt;operate_with()&lt;&#x2F;code&gt;. To simplify understanding, we kept the same variable names appearing in the paper and Arkworks. Notice that adding or duplicating points the way they do it there only requires including a couple of lines to our function &lt;code&gt;line()&lt;&#x2F;code&gt;, so it’s straightforward to compare both implementations and optimize ours if needed.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, it’s helpful to remark that the paper gives the result of the line as a polynomial of degree 5, while in lambdaworks, the elements of $\mathbb{F_{ p^{12} }}$ have another representation. So, we need to use the transformation explained in the Field Extensions Towers section.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn line(p: &amp;amp;G1Point, t: &amp;amp;G2Point, q: &amp;amp;G2Point) -&amp;gt; Fp12E {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let [x_p, y_p, _] = p.coordinates();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if t == q {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let b = t.y().square();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let c = t.z().square();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F;Define all the variables necessary&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F; We transform one representation of Fp12 into another one:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Fp12E::new([&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            Fp6E::new([y_p * (-h), Fp2E::zero(), Fp2E::zero()]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            Fp6E::new([x_p * (j.double() + &amp;amp;j), i, Fp2E::zero()]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    } else {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let [x_q, y_q, _] = q.coordinates();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let theta = t.y() - (y_q * t.z());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let lambda = t.x() - (x_q * t.z());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let j = &amp;amp;theta * x_q - (&amp;amp;lambda * y_q);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Fp12E::new([&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            Fp6E::new([y_p * lambda, Fp2E::zero(), Fp2E::zero()]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            Fp6E::new([x_p * (-theta), j, Fp2E::zero()]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;final-exponentiation&quot;&gt;Final Exponentiation&lt;&#x2F;h2&gt;
&lt;p&gt;The last thing we need is to compute efficiently $f^{ \frac{ p^{12} - 1}{r}}.$ We took the final exponentiation algorithm from &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;hackmd.io&#x2F;@Wimet&#x2F;ry7z1Xj-2#Final-Exponentiation&quot;&gt;here&lt;&#x2F;a&gt;, which divides the exponent in the following way:&lt;br &#x2F;&gt;
$$\frac{ p^{12} - 1 }{r} = ( p^6 - 1) ( p^2 + 1) \frac{ p^4 - p^2 + 1}{r}$$&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-easy-part&quot;&gt;The Easy Part&lt;&#x2F;h3&gt;
&lt;p&gt;We want to compute&lt;br &#x2F;&gt;
$$f^{ ( p^6 - 1)( p^2 + 1)} = (f^{ p^6 } f^{ - 1})^{ p^2 } \cdot (f^{ p^6 } f^{- 1 }) .$$&lt;br &#x2F;&gt;
This will be easy to do using:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $f^{ p^6 } = \bar f$ and we can calculate it using `conjugate()`. This is true because $f \in \mathbb{F_{ p^{12} }}$ and this property follows from the [Frobenius morphism as seen here](https:&#x2F;&#x2F;github.com&#x2F;mratsim&#x2F;constantine&#x2F;blob&#x2F;master&#x2F;constantine%2Fmath%2Fpairings%2Fcyclotomic_subgroups.nim#L154).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The function `inv()` computes $f^{ - 1}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * To compute $(f^{ p^6 } f^{ - 1})^{ p^2 }$ we can use the Frobenius squared morphism $\pi_p^2 : \mathbb{F_{ p^{12} }} \to \mathbb{F_{ p^{12} }},$ defined as $$\pi_p^2 (f) = \pi_p ( \pi_p (f)) = f^{ p^2 }.$$ In the last section, we explain how to implement it.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let f_easy_aux = f.conjugate() * f.inv().unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let f_easy = &amp;amp;frobenius_square(&amp;amp;f_easy_aux) * f_easy_aux;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;the-hard-part&quot;&gt;The Hard Part&lt;&#x2F;h3&gt;
&lt;p&gt;Now we need to raise the result of the easy part to the power $\frac{p^4 - p^2 + 1}{r}.$ We took the exact algorithm presented &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;hackmd.io&#x2F;@Wimet&#x2F;ry7z1Xj-2#The-Hard-Part&quot;&gt;here&lt;&#x2F;a&gt; as four steps, where &lt;code&gt;f_easy&lt;&#x2F;code&gt; is called there $m$. As explained in that post, this algorithm can be improved using a vectorial addition chain technique.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;frobenius-morphism&quot;&gt;Frobenius Morphism&lt;&#x2F;h2&gt;
&lt;p&gt;Finally, let’s see how to implement the Frobenius morphisms $\pi_p$, $\pi_p^2$, and $\pi_p^3$ used in the Final Exponentiation.&lt;&#x2F;p&gt;
&lt;p&gt;You may remember that we have already implemented a Frobenius morphism $\varphi$. Although they have the same name, there is a slight difference between $\varphi$ and $\pi_p$: The function $\pi_p$ raises elements of $\mathbb{F_{ p^{12} }}$ to the power $p$, while $\varphi$ raises the coordinates of the twisted curve points to the power $p$. In other words, $\pi_p : \mathbb{F_{ p^{12} }} \to \mathbb{F_{ p^{12} }}$ while $\varphi : E’(\mathbb{F_{ p^2 }}) \to E’(\mathbb{F_{ p^2 }})$. That is why their implementations are not exactly the same.&lt;&#x2F;p&gt;
&lt;p&gt;To implement these morphisms we need to define for all $j = 1, \ldots 5$, the constants $$\begin{align}\gamma_{ 1 , j } &amp;amp;= (9 + u)^{ \frac{ j ( p - 1) }{6}} \&lt;br &#x2F;&gt;
\gamma_{2,j} &amp;amp;= \gamma_{1,j} \cdot \overline{\gamma_{1,j}} \newline&lt;br &#x2F;&gt;
\gamma_{3,j} &amp;amp;= \gamma_{1,j} \cdot \gamma_{2,j}\end{align}$$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub const GAMMA_11: Fp2E = Fp2E::const_from_raw([&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    FpE::from_hex_unchecked(&amp;quot;1284B71C2865A7DFE8B99FDD76E68B605C521E08292F2176D60B35DADCC9E470&amp;quot;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    FpE::from_hex_unchecked(&amp;quot;246996F3B4FAE7E6A6327CFE12150B8E747992778EEEC7E5CA5CF05F80F362AC&amp;quot;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub const GAMMA_12: Fp2E = Fp2E::const_from_raw([&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    FpE::from_hex_unchecked(&amp;quot;2FB347984F7911F74C0BEC3CF559B143B78CC310C2C3330C99E39557176F553D&amp;quot;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    FpE::from_hex_unchecked(&amp;quot;16C9E55061EBAE204BA4CC8BD75A079432AE2A1D0B7C9DCE1665D51C640FCBA2&amp;quot;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; etc.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now, we use that if $f = a + bw$, then&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn frobenius(f: &amp;amp;Fp12E) -&amp;gt; Fp12E {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let [a, b] = f.value();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let [a0, a1, a2] = a.value(); &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let [b0, b1, b2] = b.value(); &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let c1 = Fp6E::new([&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        a0.conjugate(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        a1.conjugate() * GAMMA_12,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        a2.conjugate() * GAMMA_14,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let c2 = Fp6E::new([&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        b0.conjugate() * GAMMA_11,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        b1.conjugate() * GAMMA_13,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        b2.conjugate() * GAMMA_15,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Fp12E::new([c1, c2])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; similarly, frobenius_square and frobenius_cube.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Lastly, if we apply twelve times $\pi_p$, six times $\pi_p^2$, or four times $\pi_p^3$ to $f$, we get $f$ (i.e., they become the identity function). That’s because $f \in \mathbb{F_{ p^{12} }}$, and then $f^{ p ^{12} } = f.$ This property will help us test if we implemented these morphisms correctly.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;This post explored how we combined various works and papers to implement our pairing. In doing so, we successfully integrated algorithms from different implementations by making transformations between point coordinates or different representations of the same extension of fields.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-s-next&quot;&gt;What’s next?&lt;&#x2F;h4&gt;
&lt;p&gt;Now that we have a pairing working, the next step is to know how this implementation compares with others. So, we will perform some benchmarks and make some optimizations that we are already aware of. As it’s written in &lt;a href=&quot;&#x2F;lambdas-engineering-philosophy&#x2F;&quot;&gt;Lambda’s Engineering Philosophy&lt;&#x2F;a&gt;:, “Make it work, then make it beautiful, then if you really, really have to, make it fast.”&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>How we created a research fast VM for ZKsync</title>
          <pubDate>Mon, 05 Aug 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/how-we-created-a-research-fast-vm-for-zksync/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/how-we-created-a-research-fast-vm-for-zksync/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/how-we-created-a-research-fast-vm-for-zksync/">&lt;p&gt;For the past few weeks we have been working on a reimplementation of ZKsync’s (out of circuit) EraVM. The goal is to improve on its current performance and explore the possibility of adding parallel execution through BlockSTM. For that, we first had to make a deep dive into how the EraVM works and how it differs from the EVM.&lt;&#x2F;p&gt;
&lt;p&gt;We want to thank Anthony Rose and the Matter Labs team for all their help on this project, especially their &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matter-labs&#x2F;vm2&quot;&gt;new fastVM implementation&lt;&#x2F;a&gt; which we used a lot as a reference.&lt;&#x2F;p&gt;
&lt;p&gt;You can follow our progress on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;era_vm&quot;&gt;our EraVM repository&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;development-process&quot;&gt;Development Process&lt;&#x2F;h2&gt;
&lt;p&gt;It’s important to state our methodology: even though the main goal here is improving performance, our goal starting out is different: we want a simple implementation working.&lt;&#x2F;p&gt;
&lt;p&gt;We do not care about benchmarks &lt;strong&gt;at first&lt;&#x2F;strong&gt;. We know our initial implementation will be slow, but that’s not the point: the point is to get something simple working to understand all the moving parts. Only after that’s in place we shift our focus to benchmarks and performance.&lt;&#x2F;p&gt;
&lt;p&gt;When we started out we knew very little about the EraVM. We knew it was different from the EVM, and had indirectly used &lt;code&gt;zksolc&lt;&#x2F;code&gt; to compile and deploy contracts to the network, but had not looked much into the underlyings of it.&lt;&#x2F;p&gt;
&lt;p&gt;The first thing we did to get into a working flow was to inspect the VM’s bytecode. We compiled simple contracts into EraVM assembly and started getting familiar with it. The goal when starting out on an unfamiliar VM is to setup a simple &lt;code&gt;fetch-&amp;gt;decode-&amp;gt;execute&lt;&#x2F;code&gt; loop that looks something like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn run(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    vm: VM,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    loop {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let opcode = vm.get_opcode(&amp;amp;opcode_table)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        match opcode {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                Opcode::Add =&amp;gt; todo!(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                Opcode::Sub =&amp;gt; todo!(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                Opcode::Jump =&amp;gt; todo!(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                Opcode::Mul =&amp;gt; todo!(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                Opcode::Div =&amp;gt; todo!(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                ... =&amp;gt; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        vm.pc += 1;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;and then progressively implement all the opcodes. When we started looking at the assembly generated on contracts we realized the EraVM was a lot more complex than the EVM in terms of opcodes; fortunately, Matter Labs has a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matter-labs&#x2F;zksync-era&#x2F;blob&#x2F;main&#x2F;docs&#x2F;specs&#x2F;zk_evm&#x2F;vm_specification&#x2F;zkSync_era_virtual_machine_primer.md&quot;&gt;very good primer on them&lt;&#x2F;a&gt; and a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;matter-labs.github.io&#x2F;eravm-spec&#x2F;spec.html&quot;&gt;full formal specification&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;After reading those and reading their own implementations, we stumbled into their own repo &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matter-labs&#x2F;era-zkevm_opcode_defs&quot;&gt;defining all the VM opcodes&lt;&#x2F;a&gt;, and from there we could setup a proper loop like the above.&lt;&#x2F;p&gt;
&lt;p&gt;With it, we started writing our own simple EraVM assembly programs testing all the different opcodes as we implemented them. Eventually, after getting the basic functionality in place, these simple assembly programs we wrote started becoming insufficient to test complex interactions like contracts calling other contracts, gas management, etc; we needed a proper test suite.&lt;&#x2F;p&gt;
&lt;p&gt;That proper test suite is the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matter-labs&#x2F;era-compiler-tester&quot;&gt;era-compiler-tester&lt;&#x2F;a&gt;, a full test suite for the VM written by Matter Labs (technically this is also a test suite for the &lt;code&gt;zksolc&lt;&#x2F;code&gt; compiler itself, but we care about VM testing here). To get a fully working VM, we realized we needed to make these tests pass.&lt;&#x2F;p&gt;
&lt;p&gt;Before going into detail about them, let’s do a quick overview of the VM we set to reimplement.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;eravm-overview&quot;&gt;EraVM Overview&lt;&#x2F;h2&gt;
&lt;p&gt;ZKsync is a zk-Rollup meant to be EVM compatible. In practice, this can mean a number of different things. For ZKsync, it means that it’s compatible at the programming language level; this is done through &lt;code&gt;zksolc&lt;&#x2F;code&gt;, an LLVM based compiler written by Matter Labs that takes any Solidity, Yul or Vyper contract and compiles it down to the EraVM bytecode.&lt;&#x2F;p&gt;
&lt;p&gt;This might seem like full compatibility, but it’s not. The EraVM has a completely different architecture than the EVM, and some of these differences cannot be fully abstracted away.&lt;&#x2F;p&gt;
&lt;p&gt;As an example, the following Solidity contract:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;contract Test {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    function main(uint256 a, uint256 b) external pure returns(uint256 result) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        result = a + b;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;compiles to an EVM assembly that looks like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PUSH1 0x80&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PUSH1 0x40&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MSTORE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CALLVALUE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DUP1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ISZERO&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PUSH1 0xE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;JUMPI&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;and an EraVM assembly that looks like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;add	 128, r0, r3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;st.1	 64, r3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;and!	1, r2, r0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;jump.ne	@.BB0_1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;add	 r1, r0, r2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;shr.s	96, r2, r2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;and	 @CPI0_0[0], r2, r2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sub.s!	4, r2, r0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;jump.lt	@.BB0_2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ld	r1, r3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Clearly these are very different VMs. This requires getting used to these two different architectures when working at the VM level on ZKsync. A lot of operations that are opcodes on the &lt;code&gt;EVM&lt;&#x2F;code&gt; are not on the &lt;code&gt;EraVM&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;For instance, the EVM has a &lt;code&gt;returndatacopy&lt;&#x2F;code&gt; opcode, which copies the output data from a previous contract call into memory. On the &lt;code&gt;EraVM&lt;&#x2F;code&gt; there is no such thing; a call to &lt;code&gt;returndatacopy&lt;&#x2F;code&gt; on a Yul contract will compile to a block of code that looks like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.BB0_19:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ld.inc	r5, r7, r5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  st.1.inc	r6, r7, r6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  sub!	r6, r4, r0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  jump.ne	@.BB0_19&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We omitted some context, but this is essentially just a loop that will continously load (&lt;code&gt;ld&lt;&#x2F;code&gt;) a word from the called contract’s memory and then store it (&lt;code&gt;st&lt;&#x2F;code&gt;) on the caller contract’s memory, then conditionally jump back (&lt;code&gt;jump.ne&lt;&#x2F;code&gt;) to the loop if the copying is not done yet (i.e. if the &lt;code&gt;sub!&lt;&#x2F;code&gt; instruction does not yield zero).&lt;&#x2F;p&gt;
&lt;p&gt;This is just one example: most complex EVM opcodes work in in a similar fashion on the EraVM.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;era-compiler-test-suite&quot;&gt;Era Compiler Test suite&lt;&#x2F;h2&gt;
&lt;p&gt;There are millions of tests on the &lt;code&gt;era-compiler-tester&lt;&#x2F;code&gt; repo, but they all follow the same structure. Each test is a Solidity, Yul or Vyper contract that is compiled with &lt;code&gt;zksolc&lt;&#x2F;code&gt; and run with certain inputs, in turn expecting certain outputs. As an example, the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matter-labs&#x2F;era-compiler-tests&#x2F;blob&#x2F;fe7d0e86d06130ee266f82b04a549918da615521&#x2F;solidity&#x2F;simple&#x2F;default.sol&quot;&gt;default.sol&lt;&#x2F;a&gt; test looks like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;! { &amp;quot;cases&amp;quot;: [ {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;!     &amp;quot;name&amp;quot;: &amp;quot;first&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;!     &amp;quot;inputs&amp;quot;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;!         {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;!             &amp;quot;method&amp;quot;: &amp;quot;first&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;!             &amp;quot;calldata&amp;quot;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;!             ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;!         }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;!     ],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;!     &amp;quot;expected&amp;quot;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;!         &amp;quot;42&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;!     ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;! }, {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;!     &amp;quot;name&amp;quot;: &amp;quot;second&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;!     &amp;quot;inputs&amp;quot;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;!         {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;!             &amp;quot;method&amp;quot;: &amp;quot;second&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;!             &amp;quot;calldata&amp;quot;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;!             ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;!         }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;!     ],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;!     &amp;quot;expected&amp;quot;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;!         &amp;quot;99&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;!     ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;! } ] }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; SPDX-License-Identifier: MIT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pragma solidity &amp;gt;=0.4.16;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;contract Test {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    function first() public pure returns(uint64) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        uint64 result = 42;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return result;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    function second() public pure returns(uint256) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        uint256 result = 99;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return result;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The comment above it specifies what the test should run and what it expects. In this case, there are two tests, which should run the methods &lt;code&gt;first&lt;&#x2F;code&gt; and &lt;code&gt;second&lt;&#x2F;code&gt; and then get &lt;code&gt;42&lt;&#x2F;code&gt; and &lt;code&gt;99&lt;&#x2F;code&gt; as a result respectively. Most tests have a lot of comments specifying different runs, testing different functions with different inputs&#x2F;outputs and so on.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;deep-dive-into-a-zksync-era-contract&quot;&gt;Deep dive into a ZKsync Era contract&lt;&#x2F;h2&gt;
&lt;p&gt;Let’s compile the &lt;code&gt;default.sol&lt;&#x2F;code&gt; program above and see what it’s doing under the hood. Running&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;zksolc default.sol --asm -o default --optimization 3 --overwrite&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;will place a &lt;code&gt;default.zasm&lt;&#x2F;code&gt; file under the &lt;code&gt;default&lt;&#x2F;code&gt; directory. This is the EraVM assembly for the contract:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	.text&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	.file	&amp;quot;default.sol:Test&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	.globl	__entry&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;__entry:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.func_begin0:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	add	128, r0, r3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	st.1	64, r3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	and!	1, r2, r0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	jump.ne	@.BB0_1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	add	r1, r0, r2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	and!	@CPI0_1[0], r2, r0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	jump.eq	@.BB0_2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	ld	r1, r1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	shr.s	224, r1, r1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	sub.s!	@CPI0_2[0], r1, r0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	jump.eq	@.BB0_10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	sub.s!	@CPI0_3[0], r1, r0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	jump.ne	@.BB0_2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	context.get_context_u128	r1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	sub!	r1, r0, r0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	jump.ne	@.BB0_2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	add	42, r0, r1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	st.1	128, r1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	add	@CPI0_4[0], r0, r1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	ret.ok.to_label	r1, @DEFAULT_FAR_RETURN&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.BB0_1:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	context.get_context_u128	r1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	sub!	r1, r0, r0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	jump.ne	@.BB0_2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	add	32, r0, r1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	st.2	256, r1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	st.2	288, r0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	add	@CPI0_0[0], r0, r1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	ret.ok.to_label	r1, @DEFAULT_FAR_RETURN&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.BB0_10:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	context.get_context_u128	r1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	sub!	r1, r0, r0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	jump.ne	@.BB0_2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	add	99, r0, r1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	st.1	128, r1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	add	@CPI0_4[0], r0, r1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	ret.ok.to_label	r1, @DEFAULT_FAR_RETURN&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.BB0_2:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	add	r0, r0, r1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	ret.revert.to_label	r1, @DEFAULT_FAR_REVERT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.func_end0:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	.note.GNU-stack&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	.rodata&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CPI0_0:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	.cell	53919893334301279589334030174039261352344891250716429051063678533632&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CPI0_1:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	.cell	340282366604025813406317257057592410112&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CPI0_2:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	.cell	1519042605&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CPI0_3:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	.cell	1039457780&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CPI0_4:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	.cell	2535301202817642044428229017600&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;A few things you need to know about the EraVM before diving in:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The native word is a `U256` (256 bit unsigned integer).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * There are 16 registers, `r0` through `r15`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      * `r0` is the zero register: writing to it does nothing, reading from it yields zero.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      * `r1` is used as a pointer to the calldata (i.e. function arguments) when calling other contracts, and to the returndata when returning from calls.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      * `r2` usually stores information about whether the current call is a constructor call, a regular function call, or a system call (a call to a system contract with special privileges).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Every contract call gets its own stack and heap memory.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;step-by-step&quot;&gt;Step by Step&lt;&#x2F;h3&gt;
&lt;p&gt;Let’s do a step by step overview of this assembly.&lt;&#x2F;p&gt;
&lt;p&gt;When someone calls this contract, execution always begins from the &lt;code&gt;__entry&lt;&#x2F;code&gt; symbol. The first two instructions are doing some setup we don’t care much for, storing the value &lt;code&gt;128&lt;&#x2F;code&gt; onto the &lt;code&gt;r3&lt;&#x2F;code&gt; register:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;add	128, r0, r3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;st.1 64, r3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In more detail, &lt;code&gt;add 128, r0, r3&lt;&#x2F;code&gt; adds &lt;code&gt;128&lt;&#x2F;code&gt; to the value in &lt;code&gt;r0&lt;&#x2F;code&gt; and stores it in &lt;code&gt;r3&lt;&#x2F;code&gt;. Because &lt;code&gt;r0&lt;&#x2F;code&gt; is the zero register, this is essentially storing &lt;code&gt;128&lt;&#x2F;code&gt; in &lt;code&gt;r3&lt;&#x2F;code&gt; (this the way &lt;code&gt;mov&lt;&#x2F;code&gt;s to registers are always done in the EraVM).&lt;br &#x2F;&gt;
&lt;code&gt;st.1&lt;&#x2F;code&gt; then stores the value in &lt;code&gt;r3&lt;&#x2F;code&gt; to memory address &lt;code&gt;64&lt;&#x2F;code&gt; (if you’re wondering what the &lt;code&gt;1&lt;&#x2F;code&gt; is in &lt;code&gt;st.1&lt;&#x2F;code&gt;, it’s the type of heap to use; the EraVM has both a regular and a special &lt;em&gt;auxiliary&lt;&#x2F;em&gt; heap).&lt;&#x2F;p&gt;
&lt;p&gt;Then, there’s a check on the &lt;code&gt;r2&lt;&#x2F;code&gt; register and a conditional jump:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;and! 1, r2, r0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;jump.ne	@.BB0_1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;and!&lt;&#x2F;code&gt; instruction is doing a bitwise &lt;code&gt;and&lt;&#x2F;code&gt; between &lt;code&gt;1&lt;&#x2F;code&gt; and &lt;code&gt;r2&lt;&#x2F;code&gt;, storing it to &lt;code&gt;r0&lt;&#x2F;code&gt;, then setting the zero flag accordingly. This is storing to &lt;code&gt;r0&lt;&#x2F;code&gt; because we don’t care about the result. We are just checking whether the &lt;code&gt;r2&lt;&#x2F;code&gt; register is 1 or not. If it is, then this is a constructor call, and we should jump to block &lt;code&gt;@.BB0_1&lt;&#x2F;code&gt;, which contains the constructor logic; if it’s not we should continue.&lt;&#x2F;p&gt;
&lt;p&gt;If the call is not a constructor call, the code will then do&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;add	r1, r0, r2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;and!	@CPI0_1[0], r2, r0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;jump.eq	@.BB0_2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This puts the &lt;code&gt;calldata&lt;&#x2F;code&gt; pointer that’s in &lt;code&gt;r1&lt;&#x2F;code&gt; into &lt;code&gt;r2&lt;&#x2F;code&gt;, then does an &lt;code&gt;and&lt;&#x2F;code&gt; instruction and a conditional jump to make sure it’s not pointing to an invalid address. If it is, then execution jumps to block &lt;code&gt;@.BB0_2&lt;&#x2F;code&gt;, which contains the revert logic:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.BB0_2:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  add	r0, r0, r1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ret.revert.to_label	r1, @DEFAULT_FAR_REVERT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If the address is valid, the code follows like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ld	r1, r1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;shr.s	224, r1, r1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is loading the first 32 bytes the calldata pointer points to through an &lt;code&gt;ld&lt;&#x2F;code&gt; instruction, storing it in &lt;code&gt;r1&lt;&#x2F;code&gt;, then shifting it &lt;code&gt;224&lt;&#x2F;code&gt; bits to the right to keep only its first 4 bytes (&lt;code&gt;256&lt;&#x2F;code&gt;- &lt;code&gt;224&lt;&#x2F;code&gt; = &lt;code&gt;32&lt;&#x2F;code&gt; bits = 4 bytes).&lt;&#x2F;p&gt;
&lt;p&gt;These 4 bytes are the &lt;em&gt;function selector&lt;&#x2F;em&gt; of this contract call. This &lt;code&gt;default.sol&lt;&#x2F;code&gt; contract has two functions&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;function first() public pure returns(uint64)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;function second() public pure returns(uint256)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The selector for the first one is &lt;code&gt;0x3df4ddf4&lt;&#x2F;code&gt;, while for the second one it’s &lt;code&gt;0x5a8ac02d&lt;&#x2F;code&gt; (you can check them yourself &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.evm-function-selector.click&#x2F;&quot;&gt;here&lt;&#x2F;a&gt;). If you convert these values to decimal, you’ll see these are the values for the labels &lt;code&gt;CPI0_3&lt;&#x2F;code&gt; and &lt;code&gt;CPI0_2&lt;&#x2F;code&gt; respectively in the assembly. That’s why the code does a &lt;code&gt;sub.s!&lt;&#x2F;code&gt; instruction, comparing the result of this selector in &lt;code&gt;r1&lt;&#x2F;code&gt; against &lt;code&gt;CPIO_2&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sub.s!	@CPI0_2[0], r1, r0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;jump.eq	@.BB0_10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If the value matches, execution jumps to block &lt;code&gt;.BB0_10&lt;&#x2F;code&gt;, containing the logic for the &lt;code&gt;second&lt;&#x2F;code&gt; function that just returns &lt;code&gt;99&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.BB0_10:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  context.get_context_u128	r1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  sub!	r1, r0, r0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  jump.ne	@.BB0_2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  add	99, r0, r1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  st.1	128, r1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  add	@CPI0_4[0], r0, r1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ret.ok.to_label	r1, @DEFAULT_FAR_RETURN&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can see the &lt;code&gt;add 99, r0, r1&lt;&#x2F;code&gt; followed by &lt;code&gt;st.1 128, r1&lt;&#x2F;code&gt; to store the return value into memory. The code before it is just checking whether the caller passed any &lt;code&gt;wei&lt;&#x2F;code&gt; using the &lt;code&gt;context.get_context_u128 r1&lt;&#x2F;code&gt; instruction, and reverting if so (this function is not payable).&lt;&#x2F;p&gt;
&lt;p&gt;If the selector did not match &lt;code&gt;CPI0_2&lt;&#x2F;code&gt; (the selector for the &lt;code&gt;second()&lt;&#x2F;code&gt; function), then the code checks against the &lt;code&gt;first()&lt;&#x2F;code&gt; selector (label &lt;code&gt;CPIO_3&lt;&#x2F;code&gt;):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sub.s!	@CPI0_3[0], r1, r0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;jump.ne	@.BB0_2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this case, because it’s the last valid function selector for the contract, if the value does not match we just go to the revert block &lt;code&gt;BB0_2&lt;&#x2F;code&gt;. If it does match we continue with the logic for the &lt;code&gt;first()&lt;&#x2F;code&gt; function, doing the same but returning &lt;code&gt;42&lt;&#x2F;code&gt; instead of &lt;code&gt;99&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;context.get_context_u128	r1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sub!	r1, r0, r0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;jump.ne	@.BB0_2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;add	42, r0, r1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;st.1	128, r1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;add	@CPI0_4[0], r0, r1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ret.ok.to_label	r1, @DEFAULT_FAR_RETURN&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And that’s it, that’s the entire EraVM assembly code for this contract. To summarize, the code is organized as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The `__entry` block is the entrypoint for any call to this contract.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Block `BB0_1` contains the contract&amp;#39;s constructor logic (the default one in this case, since we didn&amp;#39;t write one ourselves).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Block `BB0_10` contains the code for the `second()` function.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Block `BB0_2` just has the revert logic.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * When someone calls this contract the code will do, in order, the following:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      * Check whether this is a constructor call and jump to `BB0_10` if so.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      * Read from the `calldata` pointer, revert by jumping to `BB0_2` if the address it points to is invalid.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      * Get the first 4 bytes of calldata to obtain the function selector.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      * Check the provided selector against the `second()` selector stored in `CPI0_2`. Jump to block `BB0_10` if it matches.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      * Check whether the selector matches `first()`. Revert if it does not, run the code for `first()` otherwise.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;current-status-and-next-steps&quot;&gt;Current status and next steps&lt;&#x2F;h2&gt;
&lt;p&gt;We are working on the last stretch of fixes to make all tests pass. Once that’s done, our focus will shift entirely to benchmarking the VM and start making optimizations. In anticipation for this, we started integrating with the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matter-labs&#x2F;zksync-era&#x2F;tree&#x2F;main&#x2F;core&#x2F;tests&#x2F;vm-benchmark&quot;&gt;ZKsync Era benchmarks&lt;&#x2F;a&gt;. This work requires &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;zksync-era&#x2F;pull&#x2F;225&quot;&gt;integrating the VM with the &lt;code&gt;bootloader&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, the contract in ZKsync that executes blocks (essentially the network’s main execution entrypoint).&lt;&#x2F;p&gt;
&lt;p&gt;This bootloader integration will also allow us to get our VM plugged into a ZKsync operator and start playing around with optimistic parallel execution ideas. Actually, getting parallel execution will probably involve modifying the bootloader or getting rid of it altogether when executing on the operator, but that’s a topic for another post.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Giving Back: The Rust Foundation</title>
          <pubDate>Wed, 31 Jul 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/giving-back-the-rust-foundation/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/giving-back-the-rust-foundation/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/giving-back-the-rust-foundation/">&lt;p&gt;We recently contributed $100,000 to the Rust Foundation and would like to share the reasoning behind our decision and the process that led us to this commitment.&lt;&#x2F;p&gt;
&lt;p&gt;A slice of Lambda’s history is that it started as a group of engineers with experience working on scalable and fault-tolerating systems. One of our main tools was (and still is) the Erlang&#x2F;Elixir ecosystem, which is an extraordinary solution for certain categories of problems, and allows easy extension via writing C and an FFI. However, many of the fault-tolerant properties provided by the platform are put at risk when linking with C code. We viewed Rust as an excellent complement which would allow us to get the best of both worlds.&lt;br &#x2F;&gt;
In time, we found the areas Rust excells in, and today many of our production system rely on the language and community behind the tools and libraries we use.&lt;&#x2F;p&gt;
&lt;p&gt;Another slice of our history is that Lambda hails from South America and specifically from Argentina, a place where tech companies are a bit of underdogs at times. What many people do not know is that some of our strengths are directly related to this. Argentina boasts a public education system allowing anyone to get higher education. Many of Lambda’s employees are also professors and work at several universities. We work together with them to teach Rust and ensure a healthy hiring pool and improve future possibilities for all students.&lt;&#x2F;p&gt;
&lt;p&gt;In short, we are proud to give back to the community that helped us grow, grateful to the Rust Foundation for channeling contributions, and we hope to continue contributing as our means allow.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2025&#x2F;12&#x2F;rustlatam-everyone.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Pinocchio: verifiable computation revisited</title>
          <pubDate>Wed, 31 Jul 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/pinocchio-verifiable-computation-revisited/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/pinocchio-verifiable-computation-revisited/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/pinocchio-verifiable-computation-revisited/">&lt;h2 id=&quot;1-introduction&quot;&gt;1. Introduction&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;1-1-motivation&quot;&gt;1.1 Motivation&lt;&#x2F;h3&gt;
&lt;p&gt;Imagine you want to do a complex computation, that you cannot carry out in your computer, or you need to get the results from a computer that you don’t trust. How can you be sure it was done correctly without redoing it yourself or understanding the intricate details? Introduced in 2013, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2013&#x2F;279.pdf&quot;&gt;Pinocchio&lt;&#x2F;a&gt; provides a solution using SNARKs. This technology enables a prover to demonstrate the correctness of their computations succinctly and be able to verify them, without revealing the details. Although Pinocchio itself has evolved and is no longer used in its original form, understanding it helps us appreciate the SNARKs that power today’s blockchain technologies, including ZK Rollups, enhancing scalability and privacy.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1-2-what-is-a-snark&quot;&gt;1.2 What is a SNARK?&lt;&#x2F;h3&gt;
&lt;p&gt;So, Pinocchio is a SNARK protocol, but what is a SNARK? SNARK stands for Succinct, Non-Interactive Argument of Knowledge. &lt;em&gt;Succinct&lt;&#x2F;em&gt; , because we will have small proofs which are easy to verify. &lt;em&gt;Non-Interactive&lt;&#x2F;em&gt; , because the proof generated can be used to convince any number of verifiers without requiring direct interactions with the prover. &lt;em&gt;Arguments of Knowledge&lt;&#x2F;em&gt; , because we know with very high probability that the prover is not cheating. Essentially, SNARK protocols offer us a method to “compress” a complex computation into a small, easy-to-verify proof.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1-3-why-do-we-need-snarks&quot;&gt;1.3 Why do we need SNARKs?&lt;&#x2F;h3&gt;
&lt;p&gt;It sounds cool to be able to prove the validity of a computation without having to give its code, but what are the applications in the real world? Where is it used?&lt;&#x2F;p&gt;
&lt;p&gt;A prime example are &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;ethereum.org&#x2F;es&#x2F;developers&#x2F;docs&#x2F;scaling&#x2F;zk-rollups&#x2F;&quot;&gt;ZK Rollups&lt;&#x2F;a&gt;. Blockchains are verifiable computers; they achieve this verifiability by having each node re-execute every transaction and reach a consensus. The problem is that the weakest devices become the bottleneck. Adding more hardware does not make them faster, contrary to what happens in web2: the system becomes more robust and reliable, but the weakest devices continue limiting it. Using SNARKs, we can replace the re-execution with the verification of a proof, which is significantly faster (increasing throughput). Moreover, we can create proofs containing entire blocks of transactions, leading to effective scaling. In summary, we can move the execution off-chain to rollups and verify their proofs on-chain, allowing the system to scale.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2-protocol-s-preliminaries-from-code-to-qap&quot;&gt;2. Protocol’s Preliminaries: From code to QAP&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;2-1-arithmetic-circuits&quot;&gt;2.1 Arithmetic Circuits&lt;&#x2F;h3&gt;
&lt;p&gt;The first thing we must do to be able to use any SNARK protocol is to find an efficient and systematic way to represent a computational code. And that’s what arithmetic circuits do: An arithmetic circuit is a computational model used to represent arithmetic operations in a structured way. It provides a systematic way to describe and compute complex mathematical functions. To learn more about arithmetic circuits you can see our post &lt;a href=&quot;&#x2F;how-to-transform-code-into-arithmetic-circuits&#x2F;&quot;&gt;How to transform code into arithmetic circuits&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Now, if the prover wanted to demonstrate that given specific inputs, a particular code returns certain outputs, she could simply send the corresponding arithmetic circuit to the verifier, without any other protocol needed. The problem is that such a test would not be succinct at all, in fact it would practically be like sending the inputs and the code completely. That is why, in order to achieve a succinct proof, we will have to convert the arithmetic circuit to what we call a R1CS and then transform the R1CS obtained into a QAP.&lt;&#x2F;p&gt;
&lt;p&gt;Below we will broadly explain what R1CSs and QAPs are. Note that it may be constructive to accompany this explanation with its respective implementations that can be found in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;884&quot;&gt;Pinocchio from Lambdaworks library&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2-2-r1cs&quot;&gt;2.2 R1CS&lt;&#x2F;h3&gt;
&lt;p&gt;R1CS stands for Rank-1 Constraint System. It allows us to express relationships between the circuit’s variables in a structured way using &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Matrix_(mathematics)&quot;&gt;matrix&lt;&#x2F;a&gt; equations. More specifically, given an arithmetic circuit with a valid solution $c$, our goal will be to create a system of equations of the form $Ac \odot Bc = Cc$ with $A$, $B$ and $C$ matrices:&lt;&#x2F;p&gt;
&lt;p&gt;To fully understand what R1CS are and how to build them, we recommend reading &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.rareskills.io&#x2F;post&#x2F;rank-1-constraint-system&quot;&gt;this article&lt;&#x2F;a&gt;. Nevertheless, we enumerate here the steps to transform an arithmetic circuit into an R1CS.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Identify all the variables used in the circuit. Let&amp;#39;s call them $c = (1, c_1 , \ldots, c_N , c_{N + 1}, \ldots, c_m)$ where $\\{ c_1, \ldots, c_N \\}$ are the public variables and $\\{c_{ N + 1}, \ldots, c_m \\}$ are the intermediate and private variables of the circuit.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Represent the circuit as a system of equations with variables $\\{ c_i \\}_{i = 1}^{m}$ and just one multiplication per equation. We will call each equation a _constraint_ and $n$ the number of constraints.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Construct matrix $A \in { \mathbb{F_p} }^{n \times m}$ in the following way: $a_{ik}$ is the coefficient of the variable $c_k$ at the left entry of the constraint $i$.  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;(If you don’t know what ${ \mathbb{F_p} }^{n \times m}$ means, don’t worry you could think it as ${\mathbb{R}}^{n \times m}$, so $A$ is just a matrix of numbers).
4. Analogously, construct matrix $B$ whose rows represent the right side of the multiplication of each constraint.
5. Construct matrix $C$ whose rows represent the result value of each constraint.
6. Finally, $c$ is a solution of the arithmetic circuit if and only if $Ac \odot Bc = Cc$, where $\odot$ represents the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Hadamard_product_(matrices)&quot;&gt;Hadamard Product&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2-3-qap&quot;&gt;2.3 QAP&lt;&#x2F;h3&gt;
&lt;p&gt;So now we know that programs can be represented as arithmetic circuits and further converted into an R1CS. However, directly evaluating R1CS for verification purposes still isn’t succinct due to the large number of operations required, especially for complex computations. Quadratic Arithmetic Programs (QAPs) address this issue by providing a more efficient representation.&lt;&#x2F;p&gt;
&lt;p&gt;QAPs encode the constraints of an R1CS into sets of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Polynomial&quot;&gt;polynomials&lt;&#x2F;a&gt;. This allows multiple constraints to be batched into a single polynomial equation. But why does using polynomials make the proof succinct? It’s all thanks to the mathematical result known as the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Schwartz%E2%80%93Zippel_lemma&quot;&gt;Schwartz-Zippel Lemma&lt;&#x2F;a&gt;. To see in detail why this lemma makes the proof succinct and how we transform an R1CS into a QAP we recommend reading &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.rareskills.io&#x2F;post&#x2F;quadratic-arithmetic-program&quot;&gt;this chapter&lt;&#x2F;a&gt; of The RareSkills Book of ZK. Our goal is to be able to test the validity of a solution of the R1CS, checking that a certain polynomial has a given property. We leave here the steps with the notation that we will use below in the protocol:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Recieve the R1CS: $Ac \odot Bc = Cc$ where $A, B, C \in {\mathbb{F }_p }^{n \times m}$ and $c \in {\mathbb{F }_p }^m$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Transform each column of $A$, $B$ and $C$ into polynomials:  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For each $k \in {1, \ldots, m}$, interpolate $(1, \ldots, n)$ with $(a_{1k} , \ldots , a_{nk} )$ the column $k$ of $A$. We will call the resulting polynomial $v_k(x)$.&lt;br &#x2F;&gt;
Analogously, $w_k(x)$ and $y_k(x)$ interpolate the columns of $B$ and $C$ respectively.
3. Define the polynomials $$\begin{align}&lt;br &#x2F;&gt;
p(x) &amp;amp;= \left(\sum_{k = 1 }^m c_k v_k(x) \right) \left(\sum_{k = 1 }^m c_k w_k(x) \right) - \sum_{k = 1 }^m c_k y_k(x), \ \newline&lt;br &#x2F;&gt;
t(x) &amp;amp;= (x - 1)( x - 2)\ldots( x - n).&lt;br &#x2F;&gt;
\end{align}$$We will call $t(x)$ the &lt;em&gt;vanishing polynomial&lt;&#x2F;em&gt;.
4. Finally, $c$ is a solution of the R1SC if and only if there exists a polynomial $h$ such that $p(x) = h(x)t(x)$. This can be checked by choosing a random $s$ and verifying that $p(s) = h(s)t(s)$.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;3-pinocchio-s-protocol&quot;&gt;3. Pinocchio’s Protocol&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;3-1-the-idea-behind&quot;&gt;3.1 The idea behind&lt;&#x2F;h3&gt;
&lt;p&gt;Now we are ready to understand the protocol. It starts with a one-time setup, where two keys are generated for proving and verifying these computations. The prover, who performs the computation, uses her key to create a proof that is small and constant in size, regardless of the computation’s complexity. This proof is then verified efficiently through mathematical checks that ensure the computation was done correctly. The system not only supports public verification, allowing anyone with the verification key to check the proof, but it can also be extended to provide privacy-protecting zero-knowledge proofs.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;3-2-math-prelimenaries&quot;&gt;3.2 Math Prelimenaries&lt;&#x2F;h3&gt;
&lt;p&gt;Understanding Pinocchio’s protocol requires familiarity with key mathematical concepts, primarily elliptic curves, finite fields, and group theory. These form the foundation of the cryptographic operations and security proofs in Pinocchio (and SNARK protocols in general). For a detailed exploration of elliptic curves, refer to our &lt;a href=&quot;&#x2F;what-every-developer-needs-to-know-about-elliptic-curves&#x2F;&quot;&gt;post&lt;&#x2F;a&gt; where we talk about them. For a primer on fundamental structures like groups and fields, see our &lt;a href=&quot;&#x2F;math-survival-kit-for-developers&#x2F;&quot;&gt;Math Survival Kit for Developers&lt;&#x2F;a&gt;. These resources provide the necessary background to appreciate Pinocchio’s intricate design.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;3-3-some-observations-to-understand-the-protocol&quot;&gt;3.3 Some observations to understand the protocol&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The prover and verifier agree on a pairing-friendly elliptic curve and generators of the groups $G_1$ and $G_2$ denoted by $g_1$ and $g_2$, respectively. In our case, we choose BLS12-381.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Technically, it is not necessary to work with two groups to implement the protocol. That is, the entire implementation can be interpreted using $G_1 = G_2 = G$ and $g_1 = g_2 = g$. In fact in the original Pinocchio&amp;#39;s Paper you can find it that way. However, Type I pairings (that is, those whose domain is of the form $G \times G$) are very inefficient. Furthermore, BLS12-381 and BN254 are curves that have relevance for Ethereum and that is why we choose to work on them in general.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * We are using $+$ to denote the operation of the groups $G_1$ and $G_2$. For example, $\alpha_v \cdot g_2 = \underbrace{g_2 + \ldots + g_2}_{\alpha_v \text{ times}}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;3-4-the-protocol&quot;&gt;3.4 The protocol&lt;&#x2F;h3&gt;
&lt;p&gt;In the following section we present the protocol with some code snipets from the &lt;a href=&quot;https:&#x2F;&#x2F;lambdaclass.github.io&#x2F;lambdaclass_blog&#x2F;posts&#x2F;pinocchio-verifiable-computation-revisited&#x2F;link-here&quot;&gt;implementation&lt;&#x2F;a&gt; we made using the Lambdaworks library.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;setup&quot;&gt;Setup&lt;&#x2F;h4&gt;
&lt;p&gt;Select eight private random elements $s$, $\alpha_v$, $\alpha_w$, $\alpha_y$, $\beta$, $r_v$, $r_w$, $\gamma$ from $\mathbb{F_p}$, and set $r_y = r_v \cdot r_w$. This set of elements are called &lt;em&gt;toxic waste&lt;&#x2F;em&gt; and should be discarded and wholly forgotten once the keys have been generated.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub struct ToxicWaste {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    rv: FE,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    rw: FE,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    s: FE,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; .... (other elements)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;impl ToxicWaste {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub fn sample() -&amp;gt; Self {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Self {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            s: sample_fr_elem(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            alpha_v: sample_fr_elem(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; ... (other elements)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub fn ry(&amp;amp;self) -&amp;gt; FE {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;self.rv * &amp;amp;self.rw&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Two public keys are generated in the Setup: the evaluation key, that is sent to the prover and the verification key, that is send to the verifier.&lt;&#x2F;p&gt;
&lt;h5 id=&quot;the-verification-key&quot;&gt;The verification key&lt;&#x2F;h5&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. $g_2$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. $\alpha_v \cdot g_2$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. $\alpha_w \cdot g_2$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. $\alpha_y \cdot g_2$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. $\gamma \cdot g_2$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    6. $\beta \gamma \cdot g_2$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    7. $r_y t(s) \cdot g_1$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    8. $\\{r_v v_k(s) \cdot g_1 \\}_{k \in \\{0,\ldots, N \\} }$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    9. $\\{r_w w_k(s) \cdot g_2 \\}_{k \in \\{0,\ldots, N \\} }$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    10. $\\{r_y y_k(s) \cdot g_1 \\}_{k \in \\{0,\ldots, N \\} }$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To implement this in rust, we first need to create a struct VerificationKey with each element and then generate it.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub struct VerificationKey {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub g2: G2Point,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub g2_alpha_v: G2Point,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub g2_alpha_w: G2Point,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn generate_verification_key(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    qap: QuadraticArithmeticProgram,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    toxic_waste: &amp;amp;ToxicWaste,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; VerificationKey {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let g1: G1Point = Curve::generator();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let g2: G2Point = TwistedCurve::generator();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; declare the rest of the variables needed&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    VerificationKey {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        g2: g2.clone(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        g2_alpha_v: g2.operate_with_self(toxic_waste.alpha_v.representative()),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F; ... &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h5 id=&quot;the-evaluation-key&quot;&gt;The evaluation key&lt;&#x2F;h5&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. $\\{r_v v_k(s) \cdot g_1 \\}_{k \in \\{N + 1, \ldots, m \\}}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. $\\{r_w w_k(s) \cdot g_1 \\}_{k \in \\{N + 1, \ldots, m \\}}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. $\\{r_w w_k(s) \cdot g_2 \\}_{k \in \\{N + 1, \ldots, m \\}}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. $\\{r_y y_k(s) \cdot g_1 \\}_{k \in \\{N + 1, \ldots, m \\}}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. $\\{r_v \alpha_v v_k(s) \cdot g_1 \\}_{k \in \\{N + 1, \ldots, m \\}}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    6. $\\{r_w \alpha_w w_k(s) \cdot g_1 \\}_{k \in \\{N + 1, \ldots, m \\}}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    7. $\\{r_y \alpha_y y_k(s) \cdot g_1 \\}_{k \in \\{N + 1, \ldots, m \\}}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    8. $(r_v \beta v_k(s) + r_w \beta w_k(s) + r_y \beta y_k(s)) \cdot g_1$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    9. $\\{ s^i \cdot g_2 \\}_{i \in \\{ 1,\ldots,d \\} }$ where $d$ is the degree of $t(x) = (x - 1) \ldots (x - n)$. That is, $d = n$ the number of raws of the R1SC matrices (i.e. the number of constraints).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub struct EvaluationKey {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub g1_vk: Vec&amp;lt;G1Point&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub g1_wk: Vec&amp;lt;G1Point&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub g2_wk: Vec&amp;lt;G2Point&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; ... &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn generate_evaluation_key(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    qap: &amp;amp;QuadraticArithmeticProgram,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    toxic_waste: &amp;amp;ToxicWaste,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; EvaluationKey {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let g1: G1Point = Curve::generator();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let g2: G2Point = TwistedCurve::generator();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let (v_mid, w_mid, y_mid) = (qap.v_mid(), qap.w_mid(), qap.y_mid());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; declare the rest of the variables needed&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    EvaluationKey {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        g1_vk: vs_mid.iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .map(|vk| g.operate_with_self((rv * vk.evaluate(&amp;amp;s))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .representative()))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .collect(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F; ... &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Having EvaluationKey and VeifiationKey, we can then implement the setup:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn setup(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    qap: &amp;amp;QuadraticArithmeticProgram,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    toxic_waste: ToxicWaste,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; (EvaluationKey, VerificationKey) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    (generate_evaluation_key(&amp;amp;qap, &amp;amp;toxic_waste),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     generate_verification_key(qap.clone(), &amp;amp;toxic_waste))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;prove&quot;&gt;Prove&lt;&#x2F;h4&gt;
&lt;p&gt;The steps for the prover are as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Evaluate the circuit with the input values and obtain ${c_{N + 1}, \ldots, c_m }$ the intermediate values.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Compute the polynomial $$p(x) = \left(\sum_{k = 1}^m c_k v_k(x) \right) \left(\sum_{k = 1}^m c_k w_k(x) \right) - \sum_{k = 1}^m c_k y_k(x).$$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Calculate the polynomial $h(x) = \frac{p(x)}{t(x)}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Produce the proof $$\pi = (V, W_1, W_2, Y, V&amp;#39;, W&amp;#39;, Y&amp;#39;, Z, H),$$ computing its elements:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * $V = \sum\limits_{k = N + 1}^m c_k \cdot \underbrace{\style{color: olive;}{r_v v_k(s) \cdot g_1}}_{\style{color: olive;}{\begin{array}{c} \text{From the} \ \text{evaluation key} \end{array}}}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * $W_1 = \sum\limits_{k = N + 1}^m c_k \cdot \style{color: olive;}{r_w w_k(s) \cdot g_1}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * $W_2 = \sum\limits_{k = N + 1}^m c_k \cdot \style{color: olive;}{r_w w_k(s) \cdot g_2}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * $Y = \sum\limits_{k = N + 1}^m c_k \cdot \style{color: olive;}{r_y y_k(s) \cdot g_1}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * $V&amp;#39; = \sum\limits_{k = N + 1}^m c_k \cdot \style{color: olive;}{r_v \alpha_v v_k(s) \cdot g_1}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * $W&amp;#39; = \sum\limits_{k = N + 1}^m c_k \cdot \style{color: olive;}{r_w \alpha_w w_k(s) \cdot g_1}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * $Y&amp;#39; = \sum\limits_{k = N + 1}^m c_k \cdot \style{color: olive;}{r_y \alpha_y y_k(s) \cdot g_1}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * $Z = \sum\limits_{k = N + 1}^m c_k \cdot \style{color: olive;}{(r_v \beta v_k(s) + r_w \beta w_k(s) + r_y \beta y_k(s)) \cdot g_1}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       * $H = h(s) \cdot g_2 = \sum\limits_{i = 1 }^d h_i \cdot \style{color: olive;} {s^i \cdot g_2}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. Send the public values $(c_1, \ldots, c_N)$ and the proof $\pi$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn generate_proof(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    evaluation_key: &amp;amp;EvaluationKey,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    qap: &amp;amp;QuadraticArithmeticProgram,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    qap_c_coefficients: &amp;amp;[FE],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; Proof {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; We will call {c_{N+1}, ... , c_m} cmid.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let cmid = &amp;amp;qap_c_coefficients[qap.number_of_inputs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ..qap_c_coefficients.len() - qap.number_of_outputs];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; We transform each FieldElement of the cmid into an UnsignedInteger so we can multiply them to g1.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let c_mid = cmid&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .map(|elem| elem.representative())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .collect::&amp;lt;Vec&amp;lt;_&amp;gt;&amp;gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let h_polynomial = qap.h_polynomial(qap_c_coefficients);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let h_coefficients = h_polynomial.coefficients&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .map(|elem| elem.representative())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .collect::&amp;lt;Vec&amp;lt;_&amp;gt;&amp;gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let h_degree = h_polynomial.degree();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Proof {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        v: msm(&amp;amp;c_mid, &amp;amp;evaluation_key.g2_vk_s).unwrap(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        w1: msm(&amp;amp;c_mid, &amp;amp;evaluation_key.g2w_wk).unwrap(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        w2: msm(&amp;amp;c_mid, &amp;amp;evaluation_key.g2w_wk).unwrap(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;verify&quot;&gt;Verify&lt;&#x2F;h4&gt;
&lt;p&gt;So that no malicious prover deceives the verifier, he has to ensure two things: Firstly, that the requested condition (number 4) of the QAP’s polynomial is satisfied; and secondly, that the proof’s elements have been generated from the QAP correctly. To achieve this, the verifier will do three checks. The first check will ensure the validity of the QAP and the other two checks, the correct construction of the proof’s elements.&lt;&#x2F;p&gt;
&lt;p&gt;We will denote $e$ to the pairing whose first argument is a point from $G_1,$ and the second from $G_2$.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Check 1: Correctness of the QAP&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
To be sure that the provided proof corresponds to a valid solution of the QAP, and thus a correct computation result, the verifier needs to be convinced that $p(s) = h(s)t(s)$. To achieve this he can simply check $$e(V_{io} + V, W_{io} + W_2 ) = e( \style{color: teal}{r_y t(s) \cdot g_1} , H ) e(Y_{io} + Y, \style{color: teal}{g_2} ),$$ where to simplify the notation we call&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $V_{io} = \style{color: teal}{r_v v_0(s) \cdot g_1} + \sum\limits_{k=1}^N c_k \style{color: teal} {r_v v_k(s) \cdot g_1}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $W_{io} = \style{color: teal}{r_w w_0(s) \cdot g_2} + \sum\limits_{k=1}^N c_k \style{color: teal} {r_w w_k(s) \cdot g_2}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $Y_{io} = \style{color: teal}{r_y y_0(s) \cdot g_1} + \sum\limits_{k=1}^N c_k \style{color: teal} {r_y y_k(s) \cdot g_1}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn check_divisibility(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    verification_key: &amp;amp;VerificationKey,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    proof: &amp;amp;Proof,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    c_io: &amp;amp;[FE],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; bool {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; We will use hiding_v, hiding_w and hiding_y as arguments of the pairings.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; We transform the c_io into UnsignedIntegers.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let c_io = c_io&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .map(|elem| elem.representative())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .collect::&amp;lt;Vec&amp;lt;_&amp;gt;&amp;gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let v_io = verification_key.g1_vk[0]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .operate_with(&amp;amp;msm(&amp;amp;c_io, &amp;amp;verification_key.g1_vk[1..]).unwrap());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; The same with w_io and y_io.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Pairing::compute(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;v_io.operate_with(proof.v), &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;w_io.operate_with(proof.w)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ).unwrap()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    == Pairing::compute( ... , ...).unwrap() &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Pairing::compute( ... , ...).unwrap()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Correct construction of $V$, $W$ and $Y$:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Check 2:&lt;&#x2F;strong&gt; The veifier checks that the prover used the polynomials of the QAP to construct $V$, $W$ and $Y$, and that he didn’t provide arbitrary values that simply pass the previous check.&lt;&#x2F;p&gt;
&lt;p&gt;So, in this check the goal is to verify that $V$ is $g_1$ multiplied by some linear combination of ${v_k(s)}_{k \in {1,\ldots,m}}$, and analogously, with $W$ and $Y$:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $e(V&amp;#39;, \style{color: teal} {g_2}) = e(V, \style{color: teal} {\alpha_v \cdot g_2})$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $e(W&amp;#39;, \style{color: teal} {g_2}) = e(W, \style{color: teal} {\alpha_w \cdot g_2})$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $e(Y&amp;#39;, \style{color: teal} {g_2}) = e(Y, \style{color: teal} {\alpha_y \cdot g_2})$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn check_appropriate_spans(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    verification_key: &amp;amp;VerificationKey,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    proof: &amp;amp;Proof&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; bool {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let b1 = Pairing::compute(&amp;amp;proof.v_prime, &amp;amp;verification_key.g2) &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        == Pairing::compute(&amp;amp;proof.v, &amp;amp;verification_key.g2_alpha_v);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let b2 = Pairing::compute( ... , ... ) &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        == Pairing::compute(... , ... );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let b3 = &#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    b1 &amp;amp;&amp;amp; b2 &amp;amp;&amp;amp; b3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Why does this work?&lt;&#x2F;p&gt;
&lt;p&gt;If this check passes, the verifier can be sure that, for example, $V’ = \alpha_v V$. Looking at the evaluation key, he sees that the prover doesn’t know the raw value of $\alpha_v$. So the only way the prover could have constructed $V$ and $V’$ such that they satisfy this equality is using a linear combination of ${v_k(s)}_{k \in {1,\ldots,m }}$. Similarly, he can be convinced that $W$ and $Y$ were constructed that way.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Check 3:&lt;&#x2F;strong&gt; The previous check is not enough to ensure that the proof elements were constructed correctly. We also need to verify that the prover used the same set of coefficients ${c_1,\ldots,c_m}$ in each linear combination $V$, $W$ and $Y$ of the previous check.&lt;&#x2F;p&gt;
&lt;p&gt;$$e(Z, \style{color: teal} {\gamma \cdot g_2}) = e(V+W+ Y, \style{color: teal} {\beta \gamma \cdot g_2}) $$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn check_same_linear_combinations(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    verification_key: &amp;amp;VerificationKey,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    proof: &amp;amp;Proof&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; bool {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Pairing::compute(&amp;amp;proof.z, &amp;amp;verification_key.g2_gamma)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    == Pairing::compute(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;proof.v&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .operate_with(&amp;amp;proof.w)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .operate_with(&amp;amp;proof.y),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;verification_key.g2_beta_gamma&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Putting it all together&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn verify(verification_key:&amp;amp;VerificationKey,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    proof: &amp;amp;Proof,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    c_inputs_outputs: &amp;amp;[FE]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; bool {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let b1 = check_divisibility(verification_key, proof, c_inputs_outputs);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let b2 = check_appropriate_spans(verification_key, proof);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let b3 = check_same_linear_combinations(verification_key, proof);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    b1 &amp;amp;&amp;amp; b2 &amp;amp;&amp;amp; b3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;6-turning-a-snark-into-a-zk-snark&quot;&gt;6. Turning a SNARK into a ZK-SNARK&lt;&#x2F;h2&gt;
&lt;p&gt;What does it mean zero-knowledge? We would like to be impossible for the verifier to gain any information from the proof, as it appears indistinguishable from random data.&lt;&#x2F;p&gt;
&lt;p&gt;To make it zero-knowledge, the prover has to sample some random values $\delta_v,\delta_w,\delta_y$ and make the following changes to the polynomials:&lt;&#x2F;p&gt;
&lt;p&gt;$v_{mid}(x) + \delta_v t(x), v(x) + \delta_v t(x),w(x) + \delta_w t(x) \text{ and } y(x) + \delta_y t(x).$&lt;&#x2F;p&gt;
&lt;p&gt;You can see in detail the zk adaptation of the protocol in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;abs&#x2F;1906.07221&quot;&gt;Chapter 4.13&lt;&#x2F;a&gt; of &lt;em&gt;Why and How zk-SNARK Works&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;7-summary&quot;&gt;7. Summary&lt;&#x2F;h2&gt;
&lt;p&gt;In this post we covered the main ideas behind Pinocchio’s protocol and our implementation using Lambdaworks library. We first saw the steps to transform code into a QAP. Then, we presented the actual protocol explaining how it works and why we need each different check to achieve security. Finally, we observed that while its primary objective is to achieve verifiable computation, it can incorporate zero-knowledge properties with minimal additional effort.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>An introduction to circle STARKs</title>
          <pubDate>Thu, 25 Jul 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/an-introduction-to-circle-starks/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/an-introduction-to-circle-starks/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/an-introduction-to-circle-starks/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;Scalable, transparent arguments of knowledge (STARKs) have gained widespread attention due to their applications in verifiable computing and blockchain scalability. We can use STARKs to generate a short string that attests to the integrity of a computation and a verifier can verify it very fast. The steps to generate a STARK proof consist of the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Represent the computation as a system of polynomial constraints&#x2F;equations. This could be the Algebraic Intermediate Representation (AIR) or Plonkish arithmetization. We will use AIR for the remainder of the post.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Obtain the execution trace for the program.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Interpret each column of the execution trace as the evaluations of a univariate polynomial over some smooth domain $D$ (this step is called interpolation).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Evaluate the trace polynomials over a larger and disjoint domain $D_0$ and build a Merkle tree using the evaluations.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. Enforce the constraints on the trace polynomials.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    6. To ensure that the constraints are satisfied, divide each polynomial in step 5 by the vanishing polynomial on the set where the constraints hold. The constraints are fulfilled if the result of the division is a polynomial.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    7. If there are many polynomials, get random values from the verifier to perform a linear combination; with high probability the constraints hold if the result is a polynomial.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    8. Evaluate the resulting function over $D_0$ and build a Merkle tree from those evaluations.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    9. To show that the evaluations belong to a polynomial of at most degree $n$ (and not a higher degree or rational function), apply the [FRI protocol](&#x2F;how-to-code-fri-from-scratch&#x2F;).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The efficiency of STARKs depends on working over smooth fields, where we can use the radix-2 Cooley-Tukey Fast Fourier Transform (FFT) to perform fast interpolation and evaluation. We say that the field is smooth if $p - 1 = 2^m c$, where $m$ is sufficiently large and $c$ is an odd number. Examples of fields having this property are STARK-252, $2^{64} - 2^{32} + 1$ (sometimes called Mini-Goldilocks or oxfoi prime), $2^{31} - 2^{27} + 1$ (Baby Bear).&lt;&#x2F;p&gt;
&lt;p&gt;One of the main advantages of STARKs is that we can work over “small fields” (their size is smaller than needed for cryptographic security), reducing the overhead needed to represent variables in the execution trace&#x2F;virtual machine. We can then sample randomness from an extension field to achieve cryptographic security. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2023&#x2F;1784&quot;&gt;Binius&lt;&#x2F;a&gt; shows how we can represent variables with zero overhead using binary fields.&lt;&#x2F;p&gt;
&lt;p&gt;In this post we will provide an explanation of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2024&#x2F;278.pdf&quot;&gt;Circle STARKs&lt;&#x2F;a&gt;, how we can use the circle group to access very fast modular arithmetic and why we need certain properties to be able to perform STARKs over the circle group. To do so, we need to develop the circle analogues of classical STARKs: bivariate polynomials, smooth domains, circle codes, vanishing polynomials, FFT and FRI. While many things seem quite close to their classical analogues, there are some subtleties that arise and special limits or points where we should be careful. If you want to see how these primitives are implemented, you can check &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stwo&#x2F;tree&#x2F;dev&quot;&gt;Starkware’s prover Stwo&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Plonky3&#x2F;Plonky3&#x2F;tree&#x2F;main&#x2F;circle&#x2F;src&quot;&gt;Polygon’s Plonky3&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ethereum&#x2F;research&#x2F;tree&#x2F;master&#x2F;circlestark&quot;&gt;Vitalik’s python implementation&lt;&#x2F;a&gt;. If you need a recap on classical STARKs, see &lt;a href=&quot;&#x2F;diving-deep-fri&#x2F;&quot;&gt;post 1&lt;&#x2F;a&gt; and &lt;a href=&quot;&#x2F;how-to-code-fri-from-scratch&#x2F;&quot;&gt;post 2&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;mersenne-primes&quot;&gt;Mersenne primes&lt;&#x2F;h2&gt;
&lt;p&gt;Mersenne primes have the form $2^p - 1$, where $p$ is prime ($2^p - 1$ is not always prime for every prime $p$). They have nice reduction formulae (since $2^p \equiv 1 \pmod{2^p - 1}$) and lead to very fast modular arithmetic (which in turn is crucial to performance in STARKs). Some Mersenne primes are:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $2^2 -1 = 3$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $2^3 - 1 = 7$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $2^5 - 1 = 31$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $2^7 - 1 = 127$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $2^{31} - 1 = 2147483647$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $2^{61} - 1$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $2^{127} - 1$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The problem with using Mersenne primes with STARKs is that $p - 1 = 2c$, where $c$ is odd, meaning that they are not smooth. This way, we cannot perform interpolation efficiently using the FFT. A way to circumvent this is to have the interpolation domain live in a quadratic extension of a Mersenne prime, as explained &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2023&#x2F;824.pdf&quot;&gt;here&lt;&#x2F;a&gt;. However, this approach is not well suited for constraint evaluations (quotient computations), limiting performance for traces frequently encountered in zkvms.&lt;&#x2F;p&gt;
&lt;p&gt;This shortcomings can be avoided by switching to the circle curve $x^2 + y^2 = 1$ over the field given by the Mersenne prime. The circle, equipped with the operation inherited from the rotation group over the field, is a cyclic group. Moreover, the number of elements is equal to $q + 1$. For a Mersenne prime, this means that $q + 1 = 2^p$.&lt;&#x2F;p&gt;
&lt;p&gt;Mersenne primes satisfy also that $q \equiv 3 \pmod {4}$, which implies that $x^2 + 1$ is irreducible over $q$. We will have $i$ satisfy $i^2 = -1$ and work with extensions $F$ of $F_q$. To keep with the notation of the paper, $F(i)$ is a quadratic extension of the base field $F$.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;polynomials&quot;&gt;Polynomials&lt;&#x2F;h2&gt;
&lt;p&gt;We will denote $F[x]^d$ the univariate polynomials of degree at most $d$ and $F[x,y]^d$ the bivariate polynomials of degree at most $d$. For example, $x + 2x^5 + x^{34}$ is in $F_q [x]^{36}$ but $x^{56} + 1$ is not. Similarly, $1 + x y^2 + x^{34} + y^{35} + x^{12} y^{12}$ is in $F_q [x,y]^{64}$ but not $x^{32} y^{34} + x^{12} + 25$.&lt;&#x2F;p&gt;
&lt;p&gt;In circle STARKs, we will work with bivariate polynomials modulo $x^2 + y^2 - 1$. Since $y^2 = x^2 - 1$, we can always express a polynomial $F[x,y]^d$ as&lt;br &#x2F;&gt;
$f(x,y) = f_0 (x) + y f_1 (x)$&lt;br &#x2F;&gt;
which we call the canonical representation of the polynomial. As an example, say we have the polynomial&lt;br &#x2F;&gt;
$p(x,y) = x + 4 y^3 + 5 x^2 y^5 + x y^6$&lt;br &#x2F;&gt;
We can replace $y^2 = x^2 - 1$ and get&lt;br &#x2F;&gt;
$p(x,y) = x + 4 y (x^2 - 1) + 5x^2 y (x^2 - 1)^2 + x (x^2 - 1)^3$&lt;br &#x2F;&gt;
From this, we get that&lt;br &#x2F;&gt;
$f_0 (x) = x + x (x^2 - 1)^3$&lt;br &#x2F;&gt;
$f_1 (x) = 4 (x^2 - 1) + 5x^2 (x^2 - 1)^2$&lt;&#x2F;p&gt;
&lt;p&gt;This decomposition is useful to compute the circle FFT and FRI. Something nice about $f_0 (x)$ and $f_1 (x)$ is that they are both univariate, which will lead to additional simplicity and performance for the subsequent steps (the only thing we need to be careful about is the structure of the squaring map for $x$. Instead of having $x \rightarrow x^2$ we have $x \rightarrow 2x^2 - 1$).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-circle-group&quot;&gt;The circle group&lt;&#x2F;h2&gt;
&lt;p&gt;Circle points are pairs $(x_0 , y_0)$ (with coordinates in the field $F$) satisfying the equation $x_0^2 + y_0^2 = 1$. We can induce a group structure by considering the following operation,&lt;br &#x2F;&gt;
$(x_0 , y_0 ) \cdot (x_1 , y_1 ) = (x_0 x_1 - y_0 y_1 , x_0 y_1 + x_1 y_0 )$&lt;br &#x2F;&gt;
If we fix $P = (P_x , P_y)$ we can define the rotation by $P$, $T_P (x , y) = (x_0 P_x - y_0 P_y , x_0 P_y + P_x y_0 )$. This operation is important when we need to evaluate transition constraints. For example, if we want to check that we are computing a Fibonacci sequence, we need to show that $a_{n + 2} = a_{n + 1} + a_{n}$. If we have the trace polynomial $t(x)$, we can get the next element to $x$ just by multiplying by $\omega$, the generator of the interpolation domain and have the Fibonacci constraint be $t(\omega^2 x) = t(\omega x) + t(x)$. If we choose $P$ as the generator of the (circle) interpolation domain, we can use the same idea to write these constraints.&lt;&#x2F;p&gt;
&lt;p&gt;Inverses can be calculated pretty straightforward: if $P = (x , y)$, then $-P = (x, -y)$.&lt;&#x2F;p&gt;
&lt;p&gt;An important map is the square mapping, $\pi (x,y) = (x^2 - y^2 , 2xy) = (2x^2 - 1, 2xy)$. We can see that the first component depends only on $x$. The square map produces a two-to-one reduction when acting over subgroups or special cosets (called twin position cosets). Operations over the circle are implemented here in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stwo&#x2F;blob&#x2F;dev&#x2F;crates&#x2F;prover&#x2F;src&#x2F;core&#x2F;circle.rs&quot;&gt;Stwo&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;To learn more about the domains over the circle or types of cosets, see &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Plonky3&#x2F;Plonky3&#x2F;blob&#x2F;main&#x2F;circle&#x2F;src&#x2F;domain.rs&quot;&gt;Plonky3’s implementation&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;circle-codes&quot;&gt;Circle codes&lt;&#x2F;h2&gt;
&lt;p&gt;The circle code is obtained by evaluating a polynomial $f(x,y)$ over a proper subset $D$ of the circle group over $F_q$. It can be proven that there is a one-to-one correspondence with Reed-Solomon codes (basically, circle codes are Reed-Solomon codes).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;vanishing-polynomials&quot;&gt;Vanishing polynomials&lt;&#x2F;h2&gt;
&lt;p&gt;In classical STARKs, we need to compute the vanishing polynomials over a set to then produce quotients. We need to find what these vanishing polynomials will look like in circle STARKs. The interesting result is that vanishing polynomials will be univariate, $v(x)$. Vanishing polynomials of order $n$ can be computed efficiently in $\log (n)$ operations: a squaring, a doubling and a subtraction by one. The vanishing polynomials are:&lt;br &#x2F;&gt;
$v_1 (x) = x$&lt;br &#x2F;&gt;
$v_2 (x) = 2x^2 - 1$&lt;br &#x2F;&gt;
$v_3 (x) = 2(x^2 - 1)^2 - 1$&lt;br &#x2F;&gt;
$v_4 (x) = 2((x^2 - 1)^2 - 1)^2 - 1$&lt;br &#x2F;&gt;
$v_5 (x) = 2(((x^2 - 1)^2 - 1)^2 - 1)^2 - 1$&lt;&#x2F;p&gt;
&lt;p&gt;You can check how to evaluate the vanishing polynomials in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stwo&#x2F;blob&#x2F;be265626f064ac1fcc82b1bf13e28f83023a505a&#x2F;crates&#x2F;prover&#x2F;src&#x2F;core&#x2F;constraints.rs#L11-L34&quot;&gt;Stwo&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;As in the case of classical STARKs, if $v_H (x)$ and $v_J (x)$ are vanishing polynomials over the sets $H$ and $J$, the quotient $v_H (x) &#x2F; v_J (x)$ is a vanishing polynomial over $H \backslash J$. This way, we can compute efficiently constraints that apply over $H \backslash J$.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;circle-fft&quot;&gt;Circle FFT&lt;&#x2F;h2&gt;
&lt;p&gt;The inverse FFT takes a vector of evaluations and produces the coordinates of a polynomial over some basis. The FFT takes the coordinates over the basis and produces a set of evaluations. We are used to the monomial basis, $1, x, x^2 , x^3 , … x^n$, but there are other options available. In the case of the circle FFT, the basis looks more complicated, but remember that what we want is just to encode values into polynomials and then evaluate them over a larger domain. For an FFT involving $n$ elements, let $j_0 j_1 j_2 \dots j_{n - 1}$ be the binary decomposition of $0 \leq k \leq n - 1$, that is $k= j_0 + 2j_1 + 4j_2 + \dots 2^{n - 1} j_{n - 1}$. The $k$-th basis polynomial is given by:&lt;br &#x2F;&gt;
$b_k (x , y) = y^{j_0} v_1 (x)^{j_1} v_2 (x)^{j_2} \dots v_{n - 1} (x)^{j_{ n - 1} }$&lt;br &#x2F;&gt;
To clarify the expression, here we have the first basis polynomials,&lt;br &#x2F;&gt;
$b_0 (x) = 1$&lt;br &#x2F;&gt;
$b_1 (x) = y$&lt;br &#x2F;&gt;
$b_2 (x) = v_1 (x) = x$&lt;br &#x2F;&gt;
$b_3 (x) = y v_1(x) = x y$&lt;br &#x2F;&gt;
$b_4 (x) = v_2 (x) = 2x^2 - 1$&lt;br &#x2F;&gt;
$b_5 (x) = y v_2 (x) = y( 2x^2 - 1)$&lt;br &#x2F;&gt;
$b_6 (x) = v_1 (x) v_2 (x) = x (2x^2 - 1)$&lt;&#x2F;p&gt;
&lt;p&gt;If we need to evaluate a polynomial of degree $n$ over $\beta n$ points $\beta \geq 2$, we can zero-pad the polynomial with no problem.&lt;&#x2F;p&gt;
&lt;p&gt;In the first step of the FFT, we use the split of the canonical representation of the polynomial, $p(x, y) = f_0 (x) + y f_1 (x)$. The following steps deal with a univariate polynomial $f_j (x)$, where we can apply the even-odd decomposition, taking into account that the square mapping follows the circle operation. In other words,&lt;br &#x2F;&gt;
$f_{j,e} (2x^2 - 1) = (f_j (x) + f_j (- x))&#x2F;2$&lt;br &#x2F;&gt;
$f_{j,o} (2x^2 - 1) = (f_j (x) - f_j (- x))&#x2F;2x$&lt;&#x2F;p&gt;
&lt;p&gt;We can continue breaking everything down until we can solve the FFT directly, using the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stwo&#x2F;blob&#x2F;dev&#x2F;crates&#x2F;prover&#x2F;src&#x2F;core&#x2F;fft.rs&quot;&gt;butterflies&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The twiddle factors for the first step are different from those used on the second.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;other-changes-in-circle-starks&quot;&gt;Other changes in circle STARKs&lt;&#x2F;h2&gt;
&lt;p&gt;When we impose the constraints on the trace polynomials and compute the quotients, we arrive at the composition polynomial. Its degree depends on the maximum degree of the constraints, and we may need to split it in several chuncks. In the univariate case, we can do this decomposition as follows:&lt;br &#x2F;&gt;
$p(x) = p_0 (x) + x^{n + 1} p_1 (x) + x^{2n + 2} p_2 (x)$&lt;br &#x2F;&gt;
Each $p_k (x)$ has a degree at most $n$. In circle STARKs, decompose into functions $q_1 , q_2 , … q_d$ and a parameter $\lambda$ such that&lt;br &#x2F;&gt;
$p = \lambda v_H (x) + \sum_k v_{ H } q_k &#x2F; v_{ H_k }$&lt;br &#x2F;&gt;
where the $H_k$ are disjoint twin cosets of size $n$ and their union yields $H$. The additional parameter $\lambda$ is needed because of the dimension gap discussed on the paper.&lt;&#x2F;p&gt;
&lt;p&gt;Circle FRI faces some modifications with respect to classical FRI. First, we need to decompose the function to which we will apply FRI as $f = g + \lambda v_n (x)$. This decomposition is crucial to ensure that the function spaces halve at every folding step, reaching the space of constant functions at the end of the protocol. The folding follows a similar procedure to the one we encountered in the circle FFT; after the first folding, we have to deal with univariate functions and the square mapping $x \rightarrow 2x^2 - 1$.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;Circle STARKs have shown &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;x.com&#x2F;StarkWareLtd&#x2F;status&#x2F;1807776563188162562&quot;&gt;amazing performance&lt;&#x2F;a&gt; by leveraging Mersenne primes, which have the fastest known finite field arithmetic. They are able to work around the non-smooth structure of fields defined over Mersenne primes by moving to the circle group but closely follow their classical STARKs analogues (albeit with some subtleties). Luckily, most of these subtleties are hidden from developers and circle STARKs, together with efficient lookups (such as those based on LogUp and GKR), can help improve the performance of general-purpose zkvms.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>EVM performance boosts with MLIR</title>
          <pubDate>Fri, 14 Jun 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/evm-performance-boosts-with-mlir/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/evm-performance-boosts-with-mlir/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/evm-performance-boosts-with-mlir/">&lt;p&gt;We implemented 75% of the functionality of the Ethereum Virtual Machine, in two weeks, with five new hires, compiling the VM opcode logic to native machine code with a state of the art compiler backend. Why did we do this? How?&lt;br &#x2F;&gt;
The TL;DR is: to get a performance boost (recent benchmark results show a throughput 300% to 600% times higher than &lt;em&gt;revm&lt;&#x2F;em&gt; , when running factorial and fibonacci programs), to increase implementation diversity, and to use it in our upcoming implementation of an Ethereum Execution client.&lt;&#x2F;p&gt;
&lt;p&gt;Seeing as many other VMs compile bytecode to native instructions, it struck us as odd that Ethereum Virtual Machine (EVM) implementations don’t do the same. Doing Cairo Native we &lt;a href=&quot;&#x2F;cairo-and-mlir&#x2F;&quot;&gt;learned a lot about MLIR&#x2F;LLVM&lt;&#x2F;a&gt;, and so we started the EVM-MLIR project with the objective of having a faster alternative to &lt;em&gt;revm&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;We wanted to get a sense of feasibility as soon as possible, so we started by specifying the problem (and solution) well, laying out the project skeleton and utilities, and making sure the new team had a solid base to work on. With clear tasks ready to be assigned, we managed to implement 111 out of 149 opcodes from mainnet in two weeks!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;applying-mlir-to-the-evm&quot;&gt;Applying MLIR to the EVM&lt;&#x2F;h2&gt;
&lt;p&gt;The EVM is a stack-based virtual machine whose compiled bytecode represents a sequence of instructions consisting of 1-byte opcodes with implicit parameters. Push operations also include up to 32 bytes of extra data (the number to push to the stack).&lt;&#x2F;p&gt;
&lt;p&gt;Its memory architecture consists of five components:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Stack: stores up to 1024 256-bit wide integers. Each operation pops operands from it, and&#x2F;or pushes results to it. If a program runs out of stack it terminates.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Memory: byte array, which allows random addressing by byte. Used for storing and accessing volatile data in an ordered manner.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Calldata: a read-only byte array similar to the _Memory_ sent as input on each transaction. Some operands allow copying data from the calldata to the stack or memory.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Storage: dictionary with 256-bit keys and values. Changes are persisted, unless the transaction is reverted.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Transient storage: similar to _Storage_ , but changes are discarded at the end of a transaction.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can see that the execution model of the EVM is exceedingly simple, on purpose.&lt;&#x2F;p&gt;
&lt;p&gt;A naive interpreter loop on the instruction sequence is simple to implement but difficult to optimize. There are many approaches to implementing bytecode interpreters (it’s a fun and educating project!) but removing interpreter overhead by directly translating each opcode to machine instructions is very efficient. The only difficulty is needing a compiler backend and a way to link and invoke the generated code.&lt;&#x2F;p&gt;
&lt;p&gt;We decided to take advantage of our recent experience with MLIR and write a library to translate each operation to a sequence of MLIR blocks containing the MLIR operations that implement each opcode’s behaviour, string them up by connect each one to the next. Finally this representation can be translated to LLVM IR and be put through LLVM’s optimizer passes.&lt;&#x2F;p&gt;
&lt;p&gt;Not only did we have to translate each opcode’s logic in terms of MLIR operations, we also needed to translate the memory architecture:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Stack: we pre-allocate the max stack size (1024 elements) before starting the aforementioned sequence. Current and base pointers are used to maintain the stack and check for overflows or underflows.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Memory: we handle the memory allocation in Rust, extended as needed by FFI callbacks.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Calldata: we store it on Rust&amp;#39;s side, and give it as input to the EVM.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Storage&#x2F;Transient storage: will be handled via syscalls, with an API similar to _revm_.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;benchmarks&quot;&gt;Benchmarks&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;factorial&quot;&gt;Factorial&lt;&#x2F;h4&gt;
&lt;p&gt;This program computed the Nth factorial number, with N passed via calldata. We chose 1000 as N and ran the program on a loop 100,000 times.&lt;&#x2F;p&gt;
&lt;h5 id=&quot;macbook-air-m1-16-gb-ram&quot;&gt;MacBook Air M1 (16 GB RAM)&lt;&#x2F;h5&gt;
&lt;p&gt;| Mean [s] | Min [s] | Max [s] | Relative&lt;br &#x2F;&gt;
—|—|—|—|—&lt;br &#x2F;&gt;
EVM-MLIR | 1.062 ± 0.004 | 1.057 | 1.070 | 1.00&lt;br &#x2F;&gt;
revm | 6.747 ± 0.190 | 6.497 | 7.002 | 6.36 ± 0.18&lt;&#x2F;p&gt;
&lt;h5 id=&quot;amd-ryzen-9-5950x-16-core-processor-128-gb-ram&quot;&gt;AMD Ryzen 9 5950X 16-Core Processor (128 GB RAM)&lt;&#x2F;h5&gt;
&lt;p&gt;| Mean [s] | Min [s] | Max [s] | Relative&lt;br &#x2F;&gt;
—|—|—|—|—&lt;br &#x2F;&gt;
EVM-MLIR | 1.363 ± 0.151 | 1.268 | 1.691 | 1.00&lt;br &#x2F;&gt;
revm | 5.081 ± 0.685 | 4.839 | 7.025 | 3.73 ± 0.65&lt;&#x2F;p&gt;
&lt;h4 id=&quot;fibonacci&quot;&gt;Fibonacci&lt;&#x2F;h4&gt;
&lt;p&gt;This program computed the Nth fibonacci number, with N passed via calldata. Again, we chose 1000 as N and ran the program on a loop 100,000 times.&lt;&#x2F;p&gt;
&lt;h5 id=&quot;macbook-air-m1-16-gb-ram-1&quot;&gt;MacBook Air M1 (16 GB RAM)&lt;&#x2F;h5&gt;
&lt;p&gt;| Mean [s] | Min [s] | Max [s] | Relative&lt;br &#x2F;&gt;
—|—|—|—|—&lt;br &#x2F;&gt;
EVM-MLIR | 1.010 ± 0.016 | 0.990 | 1.040 | 1.00&lt;br &#x2F;&gt;
revm | 6.192 ± 0.119 | 6.094 | 6.374 | 6.13 ± 0.15&lt;&#x2F;p&gt;
&lt;h5 id=&quot;amd-ryzen-9-5950x-16-core-processor-128-gb-ram-1&quot;&gt;AMD Ryzen 9 5950X 16-Core Processor (128 GB RAM)&lt;&#x2F;h5&gt;
&lt;p&gt;| Mean [s] | Min [s] | Max [s] | Relative&lt;br &#x2F;&gt;
—|—|—|—|—&lt;br &#x2F;&gt;
EVM-MLIR | 1.496 ± 0.236 | 1.243 | 1.756 | 1.00&lt;br &#x2F;&gt;
revm | 4.586 ± 0.066 | 4.537 | 4.727 | 3.07 ± 0.49&lt;&#x2F;p&gt;
&lt;p&gt;Code for these benchmarks can be seen in our repo: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;evm_mlir&quot;&gt;lambdaclass&#x2F;evm_mlir&lt;&#x2F;a&gt;, along with documentation on how to reproduce them. We’re currently running them on our CI to detect performance regressions, and we’ll be adding more complex programs in the near future.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;next-steps&quot;&gt;Next steps&lt;&#x2F;h3&gt;
&lt;p&gt;We now leave a skeleton crew to finish the remaining functionality and to continue optimizations, and focus on our new Execution Client – nicknamed &lt;em&gt;ethrex&lt;&#x2F;em&gt; after ETHereum Rust EXecution.&lt;&#x2F;p&gt;
&lt;p&gt;As said, our objective for our new Execution Client is giving the Ethereum ecosystem an alternative Rust Execution client with simple, straightforward code in the coming two months. After the MLIR EVM is ready, we intend to integrate it to &lt;em&gt;ethrex&lt;&#x2F;em&gt; , as part of a dog-fooding effort.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Aligned Layer: First Aligned Testnet in EigenLayer</title>
          <pubDate>Fri, 03 May 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/aligned-layer-first-aligned-testnet-in-eigenlayer/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/aligned-layer-first-aligned-testnet-in-eigenlayer/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/aligned-layer-first-aligned-testnet-in-eigenlayer/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;Zero-knowledge and validity proofs have gained attention due to their capabilities in decentralized private computation, scaling blockchains, identity protocols, and verifiable machine learning, among others. They allow one party, the prover, to show to other parties, the verifiers, that a given statement is true in a time- and memory-efficient way. Zero-knowledge proofs allow us to prove the statement without revealing anything else other than its validity. They are becoming one of the main building blocks in web3. However, even though the technology has been around since the mid 1980’s, it was not at the heart of Bitcoin and Ethereum due to the lack of efficient constructions for such applications. This leads to restrictions in the types of proof systems we can verify, introduces overhead in verification time and costs in Ethereum, and also increases development and go-to-market times, since we have to optimize the verification contracts to reduce gas usage (and, therefore, costs). &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;whitepaper.alignedlayer.com&#x2F;&quot;&gt;Aligned Layer&lt;&#x2F;a&gt;, powered by EigenLayer, provides a decentralized network of verifiers that can check proofs from any proof system in a fast and cost-effective way.&lt;&#x2F;p&gt;
&lt;p&gt;With the introduction of zk-rollups and identity protocols, the demand for on-chain verification of zero-knowledge proofs has increased dramatically. These verifications compete for blockspace with other applications in Ethereum, such as DeFi and NFTs, leading to increasing costs. Luckily, there are ways of reducing on-chain verification, at the expense of time overhead, and a low marginal off-chain cost. Aligned Layer offers a solution without introducing time overhead, and lets developers choose whether they want to wait for the proof to be verified on Ethereum before proceeding further.&lt;&#x2F;p&gt;
&lt;p&gt;This post will explain what are succinct, non-interactive arguments of knowledge, how proofs are verified in Ethereum, strategies to reduce costs, what can Aligned Layer offer to Ethereum and how it differs from aggregation layers, with the capacity to verify several orders of magnitude more proofs than Ethereum.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;succinct-non-interactive-arguments-of-knowledge-snarks&quot;&gt;Succinct, Non-Interactive Arguments of Knowledge (SNARKs)&lt;&#x2F;h2&gt;
&lt;p&gt;Succinct, non-interactive arguments of knowledge (SNARKs) allow us to prove the validity of a statement in a way that is much faster than it would take to check it naïvely. For example, say we wanted to show that we computed the 1,073,741,824th Fibonacci number correctly. The simplest way anyone could check the calculation is by recomputing the whole sequence, $a_0 = 1$, $a_1 = 1$, $a_2 = 2$, $a_3 = 3$, $a_{n + 2} = a_{n + 1} + a_n$, which is reexecuting the computation we did. This is how blockchains solved the issue of agreement between different parties: reexecution and consensus. However, this proves computationally intensive and it is problematic if we want to check computations we cannot check by ourselves due to limited computing power. SNARKs achieve sublinear verification (typically, logarithmic time verification), which means that we need to perform less work. It also means that we do not need to know all the steps in the computation (more precisely, we do not need the whole witness). Using STARKs, proof sizes and verification times are in the order of $\log^2 n$, where $n$ is the length of the program. In the case of our Fibonacci, $n = 2^{30}$, so proof sizes and times would be some constants times $30^2 = 900$, which is way smaller than $2^{30}$. So, instead of reexecution, we verify proofs, saving huge amounts of time and memory.&lt;&#x2F;p&gt;
&lt;p&gt;There are different SNARK constructions, based on either linear probabilistically checkable proofs (PCP) -such as Groth 16- and interactive oracles proofs (IOP) -such as Plonk or STARKs-, using different cryptographic assumptions and commitment schemes (collision resistant hash functions, hardness of the discrete log problem, knowledge of exponent), presence or absence of trusted ceremonies, arithmetization schemes, using multivariate or univariate polynomials, etc. This results in a wide variety of SNARKs, with different trade-offs in proof size, verification time, prover time, and the types of applications they are suited for. At the beginning the construction of SNARKs involved expressing the computations as circuits, which was a developer intensive operation, requiring expert knowledge and error&#x2F;bug prone. With the advent of general purpose zkvms this task has been greatly simplified, allowing developers to write their programs in a higher level language, such as Rust, and prove them without having to write the circuits themselves.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;verification-in-ethereum&quot;&gt;Verification in Ethereum&lt;&#x2F;h2&gt;
&lt;p&gt;We have several options to prove computations, depending on our needs. However, not all proof systems are easy or cheap to verify in Ethereum, due to two factors: storage and gas costs associated with running the verification algorithm. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;a16zcrypto.com&#x2F;posts&#x2F;article&#x2F;measuring-snark-performance-frontends-backends-and-the-future&#x2F;&quot;&gt;For example&lt;&#x2F;a&gt;, the cost of verifying a STARK is around 5,000,000 gas, while Plonk based proofs are below 1,000,000 gas. Due to precompiles, SNARKs based on pairings (such as Groth 16 and proof systems using the KZG commitment scheme) tend to be less expensive, since the pairing operation costs around 200,000 gas and elliptic curve operations of the BN254 elliptic curve, such as addition and scalar multiplication are rather cheap.&lt;&#x2F;p&gt;
&lt;p&gt;There are several limitations to the proof systems we can verify directly in Ethereum. For example, inner product argument based proof systems such as Mina’s Kimchi (which has efficient recursion via Pickles) or Brakedown-based such as Binius (with square root sized proofs) become very expensive to verify, either because of the number of operations they involve or because of proof size.&lt;&#x2F;p&gt;
&lt;p&gt;In order to verify these proofs, we need to wrap them using a more cost effective solution for Ethereum, such as KZG Kimchi for Mina. However, this comes at the expense of simulating costly operations such as foreign field arithmetic and lots of elliptic curve operations, taking a lot of effort in terms of development and go-to-market time. Besides, if you invent a new proof system which is very efficient but not EVM-friendly, you need to spend a lot of time developing the wrapper to make it cheap to verify in the EVM.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;amortizing-costs&quot;&gt;Amortizing costs&lt;&#x2F;h2&gt;
&lt;p&gt;The best ways to reduce costs in Ethereum are related to shrinking proof and public input size (thus reducing storage) and proving large computations instead of shorter ones (for example, verifying a proof for all the transactions in one block is way less expensive than verifying each transaction separately). The first strategy involves using constant proof size SNARKs, such as Groth 16 or Plonk, and providing a commitment to the public input, instead of the whole public input. The second one involves bundling several computations in one, such as all the transactions in one block. This idea was used in Starknet, proving the execution of the bootlader program in the Cairo-vm. However, many proof systems have greater memory use when proving larger computations, limiting the size of the computations we can prove using this approach. To deal with these issues, we can use recursive proof composition to aggregate several proofs into one; thus, the cost of verification in Ethereum will be split between the different computations we checked.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;batch-verification&quot;&gt;Batch verification&lt;&#x2F;h2&gt;
&lt;p&gt;Some schemes allow for batch verification: by doing some extra operations, we can check several proofs together, splitting most of the cost between the proofs. For example, if we have several evaluation proofs from a KZG commitment scheme, we can check them together by sampling random scalars, instead of verifying each separately. Even though one KZG verification can be expensive (it involves one pairing operation), by batching several proofs together, the cost per proof becomes negligible. BLS signatures exploit this property, too. Even though the BLS signatures are more expensive to check than ECDSA signatures, with batch verification we can make overall verification costs much smaller.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aggregation&quot;&gt;Aggregation&lt;&#x2F;h2&gt;
&lt;p&gt;Proof aggregation is usually carried out by recursive verification, using an n-ary tree structure (one common case is a binary tree, taking 2 proofs and producing a proof of the correctness of the verification of the two proofs). However, this is not the only technique available. For an overview of some techniques, see our &lt;a href=&quot;&#x2F;proof-aggregation-techniques&#x2F;&quot;&gt;previous blog post&lt;&#x2F;a&gt;. Proof recursion is a good technique for aggregation, but it usually involves expensive operations. For example, it may involve non-native arithmetic (the proof we want to verify is over some finite field, but the verification’s proof is over a different field), performing expensive elliptic curve operations such as pairings or calculating many hashes (in hash-based systems, such as STARKs).&lt;&#x2F;p&gt;
&lt;p&gt;Some projects focus on reducing costs by providing proof aggregation, either as a service or as part of their protocol (for example, rollups). However, proof aggregation is limited to a few proof systems, and they incur in some overhead. Since they want to achieve cheap verification in Ethereum, they have to end up wrapping their proofs into an EVM-friendly proof.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;looking-for-speed&quot;&gt;Looking for speed?&lt;&#x2F;h2&gt;
&lt;p&gt;The main drawbacks with proof aggregation are the overhead associated with the aggregation and the need for several proofs to bundle together. This means that we have an increase in latency (which could make some applications infeasible) and that some applications may have trouble in scaling (for example, you are just starting a new protocol which is not widely used yet, or you offer a very valuable service but does not have many users).&lt;&#x2F;p&gt;
&lt;p&gt;Aligned Layer offers fast and cheap verification, which is different from proof aggregation. Aligned Layer can be faster than Ethereum because of the following reasons:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Aligned Layer does not run the verification on top of the EVM. It just runs the code natively in CPUs or even in GPUs.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Aligned Layer can leverage parallelization, which is something Ethereum cannot.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. The EVM cannot process operations exceeding 30,000,000 gas per block, even if there is unused computing capacity.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Ethereum verifiers are optimized for gas usage, whereas verification in Aligned Layer can be optimized for speed. Use of faster finite field arithmetic, more efficient elliptic curve operations or faster hashing will result in higher throughput in Ethereum.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. Aligned Layer can use other DA layers to further reduce storage costs.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    6. Aligned Layer can verify proof systems that are not feasible in Ethereum, either because their proof size is large or the operations involved are expensive in Ethereum (such as Kimchi or Binius).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    7. Since verification costs in Aligned Layer are smaller than Ethereum, the demand for ZK verification is very likely to increase due to lower entry costs.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To see the potential advantages of Aligned Layer for verification over Ethereum, we will do some rough estimates of performance. The numbers are summarized in the following table:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Proof System&lt;&#x2F;th&gt;&lt;th&gt;Groth 16&lt;&#x2F;th&gt;&lt;th&gt;STARKs&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Gas cost Ethereum&lt;&#x2F;td&gt;&lt;td&gt;220,000&lt;&#x2F;td&gt;&lt;td&gt;5,000,000&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Proofs per block in Ethereum&lt;&#x2F;td&gt;&lt;td&gt;136&lt;&#x2F;td&gt;&lt;td&gt;6&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Verification time, consumer-end hardware (ms)&lt;&#x2F;td&gt;&lt;td&gt;1-3&lt;&#x2F;td&gt;&lt;td&gt;&amp;lt;25&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Proofs per block time&lt;&#x2F;td&gt;&lt;td&gt;4000&lt;&#x2F;td&gt;&lt;td&gt;480&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Improvement over Ethereum&lt;&#x2F;td&gt;&lt;td&gt;29x&lt;&#x2F;td&gt;&lt;td&gt;80x&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;A Groth16 proof costs between 220,000 gas and 300,000 gas; using the full capacity of Ethereum, this amounts to at most 136 verifications every 12 seconds. Verification of the same proofs in consumer grade hardware, without parallelization, takes between 1 and 3 ms, leading to at least 4,000 Groth16 proofs over the same period of time, nearly 30 times more proofs. For STARK proofs, which cost around 5,000,000 gas, it is just 6 proofs per block. STARK verification over CPUs depend on program size, but could be below 25 ms, leading to at least 480 proofs, an 80x improvement. The numbers of Ethereum represent its maximum nominal capacity and will not improve unless the gas limit is increased or proof gas use is further reduced (however, there are other applications running on Ethereum, which compete for this limited verification capacity). Aligned Layer can use more powerful devices, optimize code for speed and leverage a high degree of parallelization. Moreover, since Aligned Layer only verifies proofs, its computing power is not shared with other applications.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;advantages-of-having-a-fast-and-a-slow-mode&quot;&gt;Advantages of having a fast and a slow mode&lt;&#x2F;h2&gt;
&lt;p&gt;Aligned Layer offers the best of both worlds with its fast and slow modes. Aligned Layer’s goal is to verify any proof system quickly and new proof systems can be incorporated easily. After getting Aligned Layer’s verification, which is backed by a subset of Ethereum’s validators, developers can use the result to move forward. It is also cheaper since it is not constrained by the EVM. Besides, if you develop a new proof system, you just need to provide the verifier code in Rust and have no need to code a wrapper, reducing development time.&lt;&#x2F;p&gt;
&lt;p&gt;Having cheap verification makes easier for protocols and applications to adopt zero-knowledge proofs, reducing the barrier of entry. Besides, it helps scale zero-knowledge proofs since the amount of proofs per unit time increases, making it easier to achieve a reasonable number of proofs to aggregate and check in Ethereum, leading to a reduction in the cost of verification per proof. The slow mode adds additional security since the final verification is done in Ethereum. Moreover, if the validators misbehaved in the fast mode, the slow mode will override any results they provided and lead to slashing.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;&#x2F;h2&gt;
&lt;p&gt;There has been a growing demand for zero-knowledge proofs due to their applications in decentralized private computing, blockchain scalability, verifiable machine learning and identity protocols. The demand for on-chain verification in Ethereum has grown, but single proof verification costs remain high and compete with other applications. Proof aggregation reduces costs by bundling several proofs into one, at the expense of higher latency, and a small marginal off-chain cost, which is expected to go down as prover technology improves. However, the overhead introduced and the need for a sufficiently large number of proofs limit the types of applications that can effectively leverage zero-knowledge proofs, due to latency requirements or scale. Aligned Layer provides a decentralized network of verifiers, backed by the trust of Ethereum via EigenLayer, providing fast and cheap verification of proofs, providing low latency verification and low costs. It is different from aggregation layers, since its main goal is to verify proofs and allow developers to choose the best proof system for their needs. Aggregation works by bundling proofs and dividing the fixed cost of verification between the proofs but developers must wait until settlement in Ethereum. In Aligned Layer, it is up to developers to choose whether they prefer the fast or the slow mode. We think Aligned Layer will accelerate the adoption of zero-knowledge proofs in applications and, together will EigenLayer, will help bring further innovation to Ethereum.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Proof aggregation techniques</title>
          <pubDate>Mon, 25 Mar 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/proof-aggregation-techniques/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/proof-aggregation-techniques/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/proof-aggregation-techniques/">&lt;h1 id=&quot;proof-aggregation-techniques&quot;&gt;Proof aggregation techniques&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;SNARKs (succinct, non-interactive arguments of knowledge) and STARKs (scalable, transparent arguments of knowledge) have gained widespread attention due to their applications in decentralized private computation and scaling blockchains. They are tools that allow us to prove to another party that we did a computation correctly so that the verification is much faster than re-executing the computation. The size of the proof is much smaller than all the information needed to prove it. For example, we can prove that we know the solution to a Sudoku game without fully providing it. In the case of the execution of a virtual machine, to prove correctness, we should see how the machine’s registers change at every cycle; the verifier does not need to know it completely but rather queries the registers at some point. For a discussion on the impact of SNARKs&#x2F;STARKs, see our &lt;a href=&quot;&#x2F;transforming-the-future-with-zero-knowledge-proofs-fully-homomorphic-encryption-and-new-distributed-systems-algorithms&#x2F;&quot;&gt;post&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Proving large programs or computations can be expensive since this introduces an overhead in running them. In some cases, the computation can be broken down into several smaller computations (for example, proving the transactions inside a block can be done by proving each transaction separately), but this has two drawbacks: proof size and verification time scale linearly with the number of components. Both hurt scalability because we need more time to verify the entire computation, and it increases memory use. We can solve this by bundling all the proofs and doing just one verification. We can use several techniques; the best one will depend on the type of proof system we use and our particular needs. This post will discuss some of the alternatives we have and their tradeoffs in terms of prover time, verification time, and proof size.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aggregation-techniques&quot;&gt;Aggregation techniques&lt;&#x2F;h2&gt;
&lt;p&gt;These techniques will allow us to prove several statements together, reducing the blowup in proof size and verification time introduced by checking several statements. For an explanation of some techniques, see the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=0LW-qeVe6QI&quot;&gt;following video&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;proof-recursion&quot;&gt;Proof recursion&lt;&#x2F;h2&gt;
&lt;p&gt;SNARKs&#x2F;STARKs let us check the validity of any NP statement in a time- and memory-efficient way. The amount of information needed to prove a statement is much smaller than the size of the required witness to check the statement. For example, in STARKs, the verifier does not need to see the whole execution trace of the program; it just needs some random queries. In Plonk, the verifier has the evaluations of the trace polynomials at a random point, which is much less than the $3n$ values in the trace.&lt;&#x2F;p&gt;
&lt;p&gt;How does recursion work? The prover proves that he verified a proof $\pi$ corresponding to some computation with public input $u$. The image below shows the flow for recursion.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;SkeEGSDap.png&quot; alt=&quot;rec&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The prover takes the public input, the witness, and the program and generates the proof $\pi$ attesting to the validity of the computation. The prover then takes the proof $\pi$ and original circuit as witnesses, the public input, and the verification circuit (the operations the verifier would have to do to check the statement) and obtains a new proof $\pi^\prime$, showing that the prover knows the proof $\pi$ which fulfills the verification circuit with the given input. The verifier can check the proof $\pi^\prime$, which shows that the verification done by the prover is valid, which in turn implies the correctness of the first computation. In the case of STARKs, if the trace for the verification operation is shorter than the trace for the original program, proof size and verification time are reduced (since they depend on the trace length, $n$).&lt;&#x2F;p&gt;
&lt;p&gt;We can also use two different provers. For example, we can prove the first program with STARKs, which is fast but has larger proofs, and then use Groth 16&#x2F;Plonk, which has smaller proof sizes. The advantage is that the second case does not need to handle arbitrary computations, so we can have just one optimized circuit for STARK verification. The result is one small proof with fast verification.&lt;&#x2F;p&gt;
&lt;p&gt;We can also use the same structure and prove the verification of several proofs.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;H1sLvrwp6.png&quot; alt=&quot;0proofs&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;One problem we face is that even though the proof size is reduced, the public input increases linearly. We can solve this by providing a hash&#x2F;commitment to all the public input and passing it as part of the witness. During the verification, we have to check that the hash of the public input in the witness corresponds to the hash&#x2F;commitment of the public input. Proof recursion can be handled more efficiently by building a tree structure, increasing the degree of parallelization.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;Bye7stwpa.png&quot; alt=&quot;0trees&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Proof recursion is used in several projects to reduce proof size and make verification cheaper, such as &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;starkware&#x2F;recursive-starks-78f8dd401025&quot;&gt;Starknet&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;polygon.technology&#x2F;blog&#x2F;the-go-fast-machine-adding-recursion-to-polygon-zkevm&quot;&gt;Polygon ZKEVM&lt;&#x2F;a&gt;, and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;blog.matter-labs.io&#x2F;zksync-v1-1-reddit-edition-recursion-up-to-3-000-tps-subscriptions-and-more-fea668b5b0ff&quot;&gt;zkSync&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Even though proof recursion has many advantages, it adds workload to the prover. In proof systems such as STARKs, the prover has to compute lots of hashes, which are expensive operations. Luckily, there have been advances in algebraic hash functions (less costly to prove) and protocols such as &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2024&#x2F;390&quot;&gt;STIR&lt;&#x2F;a&gt; that reduce the number of hashes needed to generate proofs (post coming soon). In SNARKs working over elliptic curves, the proofs consist of elements in the curve (with coordinates over a field $F_p$) and scalar represented in $F_q$ (the scalar field). This generates a problem since we have to do operations over $F_p$ to compute operations over the curve. Still, the scalars in the circuit live in $F_r$, leading to non-native field operations. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yi-sun&#x2F;circom-pairing&#x2F;blob&#x2F;master&#x2F;circuits&#x2F;bn254&#x2F;groth16.circom&quot;&gt;Here&lt;&#x2F;a&gt; you can find a circuit to verify Groth 16 proofs, taking around 20 million constraints. As discussed in the following section, curve cycles are a nicer alternative to avoid field emulation.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;cycles-of-curves&quot;&gt;Cycles of curves&lt;&#x2F;h3&gt;
&lt;p&gt;We have the problem that coordinates for the curve $E$ live in $F_p$, but the scalar field is $F_r$. If we can find a curve $E^\prime$ defined over $F_r$ and scalar field $F_p$, then we could check proofs over $E$ using $E^\prime$. Pairs of curves with these characteristics are called a cycle of curves. Fortunately, some curves of the form $y^2 = x^3 + b$ satisfy the conditions. Pallas and Vesta curves (known together as Pasta curves) form a cycle and are used in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.minaprotocol.com&#x2F;zkapps&#x2F;o1js&#x2F;recursion&quot;&gt;Mina’s Pickles&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;zcash&#x2F;halo2&#x2F;tree&#x2F;main&quot;&gt;Halo 2&lt;&#x2F;a&gt;. We covered some of the basics of Pickles in our &lt;a href=&quot;&#x2F;mina-to-ethereum-bridge&#x2F;&quot;&gt;previous post&lt;&#x2F;a&gt;. Pickles uses two accumulators (each using a different curve) and defers some checks to the next step. This way, it can avoid expensive verifications and efficiently deliver incrementally verifiable computation.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;S1JbEKDpp.png&quot; alt=&quot;0cycles&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;folding-and-accumulation-schemes&quot;&gt;Folding and accumulation schemes&lt;&#x2F;h2&gt;
&lt;p&gt;One of the drawbacks of full recursion is that we need to prove the whole verification, which can be very expensive. For example, in recursive STARKs, we must compute all the hashes and verify all algebraic operations to get to a new proof. Folding schemes provide an alternative to full verification by combining several instances and accumulating them. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2021&#x2F;370.pdf&quot;&gt;Nova&lt;&#x2F;a&gt; introduced a folding scheme for R1CS. The key idea is that if we have two solutions $(u_1 , w_1 )$ and $(u_2 , w_2 )$ for R1CS, we can combine them into a single claim $(u , w)$ for a committed relaxed-R1CS (a generalization of R1CS).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;SJhStYv66.png&quot; alt=&quot;0folding&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We can then generate a proof for the unified claim, which amounts to the validity of all instances.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;snarkpack&quot;&gt;SNARKPack&lt;&#x2F;h2&gt;
&lt;p&gt;Some proof systems have proofs that can be aggregated by other methods, such as &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2021&#x2F;529.pdf&quot;&gt;SNARKPack&lt;&#x2F;a&gt; for Groth 16. The proof for &lt;a href=&quot;&#x2F;groth16&#x2F;&quot;&gt;Groth 16&lt;&#x2F;a&gt; consists of three elements $\Pi = (\pi_1 , \pi_2 , \pi_3)$, where $\pi_1, \pi_3$ belong to the group $G_1$ of an elliptic curve and $\pi_2$ belongs to $G_2$. The check in Groth 16 is the following pairing equation,&lt;br &#x2F;&gt;
$e(\pi_{1} , \pi_{2} ) = Y e(\pi_3 , D)$&lt;br &#x2F;&gt;
where $Y$ depends on the public input and the parameters of the ceremony, and $D$ is part of the parameters. If we have several proofs $\Pi_k = (\pi_{1k} ,\pi_{2k}, \pi_{3k} )$, we can combine the different checks,&lt;br &#x2F;&gt;
$e(\pi_{1k} , \pi_{2k} ) = Y_k e(\pi_{3k} , D)$&lt;br &#x2F;&gt;
using random numbers $r_k$ such that&lt;br &#x2F;&gt;
$\prod e(\pi_{1k} , \pi_{2k} )^{ r_k } = \prod Y_k^{ r_k } \prod e(\pi_{3k} , D)^{ r_k }$&lt;&#x2F;p&gt;
&lt;p&gt;We can rewrite this as&lt;br &#x2F;&gt;
$Z_{AB} = Y^\prime e(Z_C , D)$&lt;br &#x2F;&gt;
where&lt;br &#x2F;&gt;
$Z_{AB} = \prod e(\pi_{1k} , \pi_{2k} )^{ r_k }$&lt;br &#x2F;&gt;
$Y^\prime = \prod Y_k^{ r_k }$&lt;br &#x2F;&gt;
$Z_C = \prod \pi_{3k}^{ r_k }$&lt;br &#x2F;&gt;
The verifier needs to check that $Z_{AB}$ and $Z_C$ are consistent with the proof triples $\Pi_k$ provided. This is done via a target inner pairing product and a multiexponentiation inner product. The advantage is that the combined proof size is practically independent of the number of proofs aggregated.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;continuations&quot;&gt;Continuations&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.risczero.com&#x2F;blog&#x2F;continuations&quot;&gt;Continuations&lt;&#x2F;a&gt; are a mechanism by which we can split a complex computation into smaller segments that can be computed and proven separately. This enables faster proving by leveraging parallelization and reducing the provers’ memory footprint. The downside is a blowup in proof size unless implemented in rollup form. However, let’s take advantage of the independent proofs and use a folding scheme to combine all the claims to the same verification circuit or recursive proving. We can wrap all the segments into a single proof (which could also be a SNARK with constant proof size).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;Over the last decade, we have seen the development of new proof systems and techniques to show the validity of computations in a memory- and time-efficient way. However, we need to break down large computations into smaller, independent computations (for example, proving a block of transactions by proving each transaction separately). The downside is that we have a blowup in proof size and verification time, which can hurt scalability or increase costs. Luckily, there are several techniques for aggregating proofs, so verifying a single proof implies the validity of all the other proofs. While proof recursion offers a highly parallelizable way to aggregate proofs, it involves costly operations, such as field emulation and hash functions. Accumulation or folding schemes provide an alternative to full verification by deferring some checks until a final verification step.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Beyond Single-Core: Enhancing VM Efficiency in Parallel Environments</title>
          <pubDate>Fri, 22 Mar 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/beyond-single-core-enhancing-vm-efficiency-in-parallel-environments/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/beyond-single-core-enhancing-vm-efficiency-in-parallel-environments/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/beyond-single-core-enhancing-vm-efficiency-in-parallel-environments/">&lt;p&gt;At LambdaClass, benchmarks and performance analysis are critical aspects of our development process. We always perform performance analysis in every PR via our CI pipelines to spot any performance issues.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;cairo-vm&quot;&gt;Cairo virtual machine&lt;&#x2F;a&gt; is not an exception since it is a core part of the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.starknet.io&#x2F;en&quot;&gt;Starknet&lt;&#x2F;a&gt; network. In this post, we will delve into how we investigated a performance regression and then optimized a core data structure in the library to improve its multicore performance.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;Ske40pOAa.png&quot; alt=&quot;Screenshot 2024-03-15 at 17.58.47&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-first-look&quot;&gt;A first look&lt;&#x2F;h2&gt;
&lt;p&gt;Some background: Not long ago, we introduced an optional feature, &lt;code&gt;lambdaworks-felt,&lt;&#x2F;code&gt; which marked a significant improvement in our performance metrics. It uses the Felt (field element) implementation from our cryptography library, &lt;a href=&quot;&#x2F;lambdaworks-design-and-usage-part-1-finite-fields&#x2F;&quot;&gt;LambdaWorks&lt;&#x2F;a&gt;, which replaced a more naive implementation using &lt;code&gt;BigInt&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Last week, the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;eqlabs&#x2F;pathfinder&quot;&gt;Pathfinder&lt;&#x2F;a&gt; team from Equilibrium (as always, we want to thank them for finding and raising this issue) observed an unexpected scaling behavior when they tried to re-execute some Sepolia testnet blocks using their &lt;code&gt;re_execute&lt;&#x2F;code&gt; tool that spins up several CairoVMs to run the block’s transactions in parallel.&lt;&#x2F;p&gt;
&lt;p&gt;When several instances of the CairoVM with the lambda works-felt feature enabled are executed on a hyperthreading-enabled processor, execution time does not scale with the number of enabled threads as well as without the lambda works-felt feature.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;ByrB06O0T.png&quot; alt=&quot;Untitled (2)&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The figure, contributed by the Pathfinder team, shows the results of a benchmark performed on a Ryzen 5900X. As you can see, the CairoVM with the lambdaworks-felt feature performs better when you execute it with fewer threads. Still, the run with defaults implementation (Felt type implemented using the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;num-bigint&#x2F;latest&#x2F;num_bigint&#x2F;&quot;&gt;num_bigint&lt;&#x2F;a&gt; crate) scales better as the number of threads increases.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;digging-deeper&quot;&gt;Digging deeper&lt;&#x2F;h2&gt;
&lt;p&gt;Our first task was to reproduce what had been reported. Once we saw the same results as the Pathfinder team, we could start investigating possible causes. After that, we started investigating this behavior and found that we had many cache misses when using the lambdaworks-based felt.&lt;&#x2F;p&gt;
&lt;p&gt;VM with Bigint felt:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ perf stat -e cache-misses .&#x2F;binaries&#x2F;re_execute_main sepolia-testnet_0.11.0_47191.sqlite 47000 47191&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Performance counter stats for &amp;#39;.&#x2F;binaries&#x2F;re_execute_main sepolia-testnet_0.11.0_47191.sqlite 47000 47191&amp;#39;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        2094269051      cache-misses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       5.926431912 seconds time elapsed&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     168.877378000 seconds user&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       3.675086000 seconds sys&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;VM with Lambdaworks felt:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ perf stat -e cache-misses .&#x2F;binaries&#x2F;re_execute_main_lambdaworks sepolia-testnet_0.11.0_47191.sqlite 47000 47191&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Performance counter stats for &amp;#39;.&#x2F;binaries&#x2F;re_execute_main_lambdaworks sepolia-testnet_0.11.0_47191.sqlite 47000 47191&amp;#39;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        2426557083      cache-misses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       6.931543878 seconds time elapsed&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     197.086250000 seconds user&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       6.588698000 seconds sys&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So, here we can see that the lambdaworks felt has 16% more cache misses than the BigInt implementation.&lt;&#x2F;p&gt;
&lt;p&gt;How does this inform our search for a cause? We talked to the team member who originally benchmarked the CairoVM and its relation to memory allocation when running and integrated lambdaworks-felt into the CairoVM. When we showed him these results, he mentioned that looking at the felt layout in memory when the VM is running would be a good idea.&lt;&#x2F;p&gt;
&lt;p&gt;When the CairoVM runs a program, it stores the felt values in its memory representation, which encodes the rules and guarantees necessary for proving. So for a running program, memory is a collection of &lt;code&gt;MemoryCell&lt;&#x2F;code&gt;s, which in turn wraps a boolean that signals if the memory cell was accessed during the program execution and a &lt;code&gt;MaybeRelocatable&lt;&#x2F;code&gt; value, an enum that can be either a felt or a Relocatable value:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub(crate) struct MemoryCell(MaybeRelocatable, bool);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub enum MaybeRelocatable {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    RelocatableValue(Relocatable),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Int(Felt252),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When looking at cache issues, one usually looks at the shape or layout that values take when in memory. We noticed that when using the &lt;code&gt;lambdaworks-felt&lt;&#x2F;code&gt; feature, the &lt;code&gt;MemoryCell&lt;&#x2F;code&gt; structure size increased from 40 to 48 bytes, which was the root cause of the increase in cache misses when running parallel workloads.&lt;&#x2F;p&gt;
&lt;p&gt;We can guess that since multiple VMs are trying to populate the cache with their values, felts running over a line would cause more cache thrashing.&lt;&#x2F;p&gt;
&lt;p&gt;Another factor to take into account is the use of SMT (Simultaneous multithreading,** also known as Hyper-Threading) in AMD and Intel CPUs. This technique basically runs two logical cores inside a single physical core, which usually improves overall performance.&lt;&#x2F;p&gt;
&lt;p&gt;But that’s not always the case; sometimes, it gets in the way. For example, one logical core can evict cached items that later the other logical core will need, leading to more cache misses.&lt;&#x2F;p&gt;
&lt;p&gt;Just guessing is magical thinking, which is for astrologists, so we decided to implement a change and measure the impact.&lt;&#x2F;p&gt;
&lt;p&gt;To address this, we refactored that structure to a more cache-friendly representation. The new optimized &lt;code&gt;MemoryCell&lt;&#x2F;code&gt; can now fit in half a 64-byte cache line instead of almost a full cache line. The new structure now stores the data and metadata in a raw form using the spare bits in the felt representation, and the &lt;code&gt;MaybeRelocatable&lt;&#x2F;code&gt; instances are built as needed from it.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; [`MemoryCell`] represents an optimized storage layout for the VM memory.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; It&amp;#39;s specified to have both size an alignment of 32 bytes to optimize cache access.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; Typical cache sizes are 64 bytes; a few cases might be 128 bytes, meaning 32 bytes aligned to&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; 32 bytes boundaries will never get split into two separate lines, avoiding double stalls and&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; reducing false sharing and evictions.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; The trade-off is extra computation for conversion to our &amp;quot;in-flight&amp;quot; `MaybeRelocatable` and&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; `Felt252` as well as some extra copies. Empirically, this seems to be offset by the improved&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; locality of the bigger structure for Lambdaworks. There is a big hit from the conversions when&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; using the `BigUint` implementation, since those force allocations on the heap, but since that&amp;#39;s&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; dropped in later versions anyway it&amp;#39;s not a priority. For Lambdaworks, the new copies are mostly&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; to the stack, which is typically already in the cache.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; The layout uses the 4 MSB in the first `u64` as flags:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; - BIT63: NONE flag, 1 when the cell is actually empty.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; - BIT62: ACCESS flag, 1 when the cell has been accessed in a way observable to Cairo.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; - BIT61: RELOCATABLE flag, 1 when the contained value is a `Relocatable`, 0 when it is a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; `Felt252`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; `Felt252` values are stored in big-endian order to keep the flag bits free.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; `Relocatable` values are stored as native endian, with the 3rd word storing the segment index&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; and the 4th word storing the offset.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#[repr(align(32))]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub(crate) struct MemoryCell([u64; 4]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After this change, when we re-execute some old Sepolia testnet blocks, we can see that the new cache-friendly &lt;code&gt;MemoryCell&lt;&#x2F;code&gt; scales better when using hyper threading. Outperforming both the old &lt;code&gt;MemoryCell&lt;&#x2F;code&gt; with a &lt;code&gt;BigUint&lt;&#x2F;code&gt; -backed Felt and our previous implementation of the &lt;code&gt;MemoryCell&lt;&#x2F;code&gt; with the &lt;code&gt;Lambdaworks&lt;&#x2F;code&gt; felt.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;HkqL06d0a.png&quot; alt=&quot;benchs_x86 (2)&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Benchmarks run on AMD Ryzen 9 5950X 16-Core Processor, Architecture:x86, CPU(s): 32&lt;&#x2F;p&gt;
&lt;p&gt;That figure was generated with the data extracted by running hyperfine, a CLI-based benchmarking tool, with different number of threads so we can get how each change performed as we increase the number of threads.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Running benchmark for 1 threads&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Benchmark 1: re_execute_main threads: 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Time (abs ≡):        57.351 s               [User: 55.107 s, System: 2.174 s]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Benchmark 2: re_execute_fixed_felt threads: 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Time (abs ≡):        44.760 s               [User: 42.510 s, System: 2.197 s]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Benchmark 3: re_execute_main_lambdaworks threads: 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Time (abs ≡):        47.458 s               [User: 45.454 s, System: 1.948 s]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Summary&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  re_execute_fixed_felt threads: 1 ran&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1.06 times faster than re_execute_main_lambdaworks threads: 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1.28 times faster than re_execute_main threads: 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Running benchmark for 2 threads&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Benchmark 1: re_execute_main threads: 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Time (abs ≡):        28.247 s               [User: 54.708 s, System: 1.647 s]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Benchmark 2: re_execute_fixed_felt threads: 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Time (abs ≡):        21.625 s               [User: 41.931 s, System: 1.231 s]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Benchmark 3: re_execute_main_lambdaworks threads: 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Time (abs ≡):        23.607 s               [User: 45.111 s, System: 1.987 s]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Summary&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  re_execute_fixed_felt threads: 2 ran&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1.09 times faster than re_execute_main_lambdaworks threads: 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1.31 times faster than re_execute_main threads: 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Running benchmark for 4 threads&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Benchmark 1: re_execute_main threads: 4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Time (abs ≡):        14.718 s               [User: 56.848 s, System: 1.445 s]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Benchmark 2: re_execute_fixed_felt threads: 4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Time (abs ≡):        11.516 s               [User: 44.374 s, System: 1.264 s]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Benchmark 3: re_execute_main_lambdaworks threads: 4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Time (abs ≡):        12.472 s               [User: 47.662 s, System: 1.627 s]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Summary&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  re_execute_fixed_felt threads: 4 ran&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1.08 times faster than re_execute_main_lambdaworks threads: 4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1.28 times faster than re_execute_main threads: 4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Running benchmark for 8 threads&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Benchmark 1: re_execute_main threads: 8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Time (abs ≡):         7.904 s               [User: 61.202 s, System: 0.705 s]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Benchmark 2: re_execute_fixed_felt threads: 8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Time (abs ≡):         6.186 s               [User: 47.780 s, System: 0.771 s]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Benchmark 3: re_execute_main_lambdaworks threads: 8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Time (abs ≡):         6.800 s               [User: 52.407 s, System: 0.947 s]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Summary&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  re_execute_fixed_felt threads: 8 ran&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1.10 times faster than re_execute_main_lambdaworks threads: 8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1.28 times faster than re_execute_main threads: 8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Running benchmark for 16 threads&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Benchmark 1: re_execute_main threads: 16&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Time (abs ≡):         5.248 s               [User: 77.844 s, System: 1.159 s]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Benchmark 2: re_execute_fixed_felt threads: 16&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Time (abs ≡):         4.443 s               [User: 65.118 s, System: 1.575 s]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Benchmark 3: re_execute_main_lambdaworks threads: 16&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Time (abs ≡):         5.456 s               [User: 80.535 s, System: 1.852 s]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Summary&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  re_execute_fixed_felt threads: 16 ran&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1.18 times faster than re_execute_main threads: 16&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1.23 times faster than re_execute_main_lambdaworks threads: 16&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Running benchmark for 32 threads&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Benchmark 1: re_execute_main threads: 32&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Time (abs ≡):         5.967 s               [User: 168.953 s, System: 3.411 s]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Benchmark 2: re_execute_fixed_felt threads: 32&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Time (abs ≡):         5.345 s               [User: 149.728 s, System: 4.033 s]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Benchmark 3: re_execute_main_lambdaworks threads: 32&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Time (abs ≡):         7.010 s               [User: 199.011 s, System: 5.984 s]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Summary&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  re_execute_fixed_felt threads: 32 ran&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1.12 times faster than re_execute_main threads: 32&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1.31 times faster than re_execute_main_lambdaworks threads: 32&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1.32 times faster than re_execute_main_lambdaworks threads: 48&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We also ran &lt;code&gt;perf stat&lt;&#x2F;code&gt; to check the cache misses using this new version, and it is indeed more cache efficient, reducing the cache misses by %21 concerning the old MemoryCell implementation with Lambdaworks and 9% less cache misses than the one with Bigints.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ perf stat -e cache-misses .&#x2F;binaries&#x2F;re_execute_fixed_felt sepolia-testnet_0.11.0_47191.sqlite 47000 47191&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Performance counter stats for &amp;#39;.&#x2F;binaries&#x2F;re_execute_fixed_felt sepolia-testnet_0.11.0_47191.sqlite 47000 47191&amp;#39;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        1906296012      cache-misses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       5.278474869 seconds time elapsed&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     148.647511000 seconds user&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       4.168127000 seconds sys&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;arm-architecture-considerations&quot;&gt;&lt;strong&gt;ARM Architecture Considerations&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;While we have seen a performance regression related to cache misses in multi-threaded environments for x86_64 architectures, it’s important to note that this issue is not prevalent in systems utilizing ARM CPUs. Our benchmarks, conducted on a MacBook M3 Pro equipped with 18 GB of RAM and 11 cores, showcase a different performance profile.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;S1tUaVi0p.png&quot; alt=&quot;benchs_mac_2 (1)&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In the image, you can notice that:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * In an SMT context, the ARM-based system displays superior scalability when using the lambdaworks-based MemoryCell struct instead of the BigInt implementation.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The MemoryCell modifications don&amp;#39;t impact the execution performance on ARM systems.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This distinction in performance between ARM and more traditional x86_64 processors (such as those from Intel or AMD) can be attributed to architectural differences in cache management and bigger cache line sizes (128 bytes in the Apple Silicon processors). ARM processors are designed with a unique approach to cache utilization, wherein individual cores possess dedicated cache resources. This design choice prevents the scenario of cache contention where two cores compete for the same cache lines, a situation that can lead to increased cache misses.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;So all is well and nice, but two questions remain: Why didn’t we see this before, and how do we ensure we see it in the future? How can we improve our engineering processes by considering what we learned?&lt;&#x2F;p&gt;
&lt;p&gt;Our benchmarks modeled a workload without the necessary concurrency to surface the issue.&lt;&#x2F;p&gt;
&lt;p&gt;To ensure a performance regression test, we need to write some code that will trigger it in the right circumstances, a minimal version of &lt;code&gt;re_execute&lt;&#x2F;code&gt; that will allow us to vary parameters to cover a broader area of the problem space (number of VMs running in parallel, number of threads, number of processors used, processor architecture, etc.).&lt;&#x2F;p&gt;
&lt;p&gt;Two lessons learned (or rather, reinforced) are:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Don’t assume your code will only run under specific workloads. Try to model the real world as much as possible and measure to make sure.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Don’t assume that a change to the code that shows a performance improvement measured “locally” will positively impact the overall performance of the entire program.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This experience highlights that achieving maximum performance in Rust often requires consideration of lower-level details beyond merely using enums. It underscores the importance of understanding and optimizing CPU cache behavior in performance-sensitive applications.&lt;&#x2F;p&gt;
&lt;p&gt;By rethinking our approach to data storage and access and getting a little creative with our structures, we’ve reduced cache misses and significantly improved the scaling of our VMs on multicore systems.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Implementing BabySNARK in lambdaworks in our internal bootcamp</title>
          <pubDate>Wed, 28 Feb 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/implementing-babysnark-in-our-internal-bootcamp/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/implementing-babysnark-in-our-internal-bootcamp/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/implementing-babysnark-in-our-internal-bootcamp/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;We started with an internal bootcamp two weeks ago to onboard new engineers to our team. We wanted to give the basic building blocks in cryptography and also an introduction to zero-knowledge proofs (ZKP) using &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&quot;&gt;lambdaworks&lt;&#x2F;a&gt;. Zero-knowledge proofs are a powerful technology that could &lt;a href=&quot;&#x2F;transforming-the-future-with-zero-knowledge-proofs-fully-homomorphic-encryption-and-new-distributed-systems-algorithms&#x2F;&quot;&gt;shape the future in many different ways&lt;&#x2F;a&gt;. For an introduction and a bit of history on the topic, see our &lt;a href=&quot;&#x2F;our-highly-subjective-view-on-the-history-of-zero-knowledge-proofs&#x2F;&quot;&gt;previous blog post&lt;&#x2F;a&gt;. Modern proof systems use several tricks and optimizations for increased performance. However, this complicates the learning process since we have to separate the main logic (arithmetization, interpolation, imposing constraints, committing to polynomials) from improvements, some of which are difficult to grasp. We focused on a more straightforward construction, following &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;initc3&#x2F;babySNARK&#x2F;blob&#x2F;master&#x2F;babysnark.py&quot;&gt;BabySNARK&lt;&#x2F;a&gt;. During the first week, we covered the basics of finite fields, notions of groups, elliptic curves, hash functions, signatures, public key encryption, and symmetric key encryption schemes. If you are unfamiliar with some topics, we recommend you read our &lt;a href=&quot;&#x2F;math-survival-kit-for-developers&#x2F;&quot;&gt;math survival kit&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;This blog post will explain the working principle of the proof system and its implementation using lambdaworks (you can check the work in progress &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;tree&#x2F;babysnark&#x2F;examples&#x2F;baby-snark&#x2F;src&quot;&gt;here&lt;&#x2F;a&gt;). We hope this will help onboard new people to the fantastic field of ZKP.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;working-principle&quot;&gt;Working principle&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;programs-as-relationships-between-polynomials&quot;&gt;Programs as relationships between polynomials&lt;&#x2F;h3&gt;
&lt;p&gt;BabySNARK is based on this &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2014&#x2F;718&quot;&gt;NIZK&lt;&#x2F;a&gt; proposed in 2014. It works with square span programs, which are similar to, yet simpler than, quadratic arithmetic programs (used in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2013&#x2F;279&quot;&gt;Pinocchio&lt;&#x2F;a&gt;). The representation of the circuit is done with a matrix $U$ (belonging to $F^{m \times n}$) and a vector $z = (1 , u , w)^t$ (containing the instance $u$ and witness $w$),&lt;br &#x2F;&gt;
$(U.z) \circ (U.z) = 1$&lt;&#x2F;p&gt;
&lt;p&gt;We can express any boolean circuit using these types of constraints. Let us rewrite the equations in a different form that will be convenient for later purposes:&lt;br &#x2F;&gt;
$\left(\sum_j u_{ij} z_j \right)^2 = 1$&lt;br &#x2F;&gt;
which should be valid for every $i = 0, 1, 2, …$. We can encode these equations using polynomials. Suppose that $m = 2^k$ for some $k$ and that we are working with a nice field $F$ containing a subgroup $D_i$ of size $2^k$. We can take $\omega$ as an $m$-th primitive root of unity ($\omega$ generates the whole subgroup) and find the polynomials $U_j (x)$ which satisfy&lt;br &#x2F;&gt;
$U_j (\omega^i ) = u_{ij}$&lt;br &#x2F;&gt;
By doing this, we are encoding our equations as relations over polynomials. Thus, we can replace the problem equivalently,&lt;br &#x2F;&gt;
$\left(\sum_j U_{j} (x) z_j \right)^2 - 1 = p(x)$&lt;br &#x2F;&gt;
If we evaluate the polynomials at $\omega^i$, then we get $U_j (\omega^i ) = u_{ij}$, and $p(\omega^i )$ evaluates to $0$ at every $\omega^i$. A theorem says that if $\omega^i$ is a root&#x2F;zero of a polynomial $p(x)$, then $x - \omega^i$ divides $p(x)$. In other words, there is some $q (x)$ such that $p(x) = (x - \omega^i )q(x)$.&lt;&#x2F;p&gt;
&lt;p&gt;If the polynomial has multiple zeros, then it must be divisible by each $x - \omega^i$. Let us define $Z(x)$ as the vanishing polynomial over $D_i$&lt;br &#x2F;&gt;
$Z(x) = \prod_j (x -\omega^j ) = x^m - 1$&lt;br &#x2F;&gt;
where we used in the last equality that $\omega$ is a primitive $m$-th root of unity (this trick is also used in &lt;a href=&quot;&#x2F;diving-deep-fri&#x2F;&quot;&gt;STARKs&lt;&#x2F;a&gt;). Therefore, if all the constraints hold, we have a polynomial $q(x)$ which fulfills this equality&lt;br &#x2F;&gt;
$p(x) = Z(x) q(x)$&lt;&#x2F;p&gt;
&lt;p&gt;One way to show that the computation described by the system of equations is valid is by providing $p(x)$ and $q(x)$ and letting the verifier check the equality by himself. The problem is that we have to pass all the coefficients of both polynomials (which are as long as the computation) and let him compute the right-hand side and assert whether it equals the polynomial on the left-hand side. Besides, we also leak information on the witness! How can we turn this into something succinct and not leak information?&lt;&#x2F;p&gt;
&lt;h3 id=&quot;polynomial-commitment-schemes&quot;&gt;Polynomial commitment schemes&lt;&#x2F;h3&gt;
&lt;p&gt;A polynomial commitment scheme is given by four algorithms: setup, commit, open, and evaluate. The commitment allows us to bind ourselves to a given polynomial using short data and later be able to prove things about that polynomial. The commitment scheme must satisfy the following two properties:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Hiding: the commitment does not reveal anything about the committed polynomial.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Binding: given the commitment to $p(x)$, $\mathrm{cm} (p)$, it is infeasible to find another $q(x)$, such that $\mathrm{cm} (p) = \mathrm{cm} (q)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;One way to build a PCS is by using a pairing-friendly elliptic curve, such as BN254 or BLS12-381. We will work here with type-3 pairings, which are functions $e: G_1 \times G_2 \rightarrow G_t$ with the following properties:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Bilinearity: $e(a g_1 , b g_2) = e(g_1 , g_2 )^{ab}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Non-degeneracy: If $e(P,Q) = 1$, then either $P = \mathcal{O}$ or $Q = \mathcal{O}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;mina-to-ethereum-bridge&#x2F;&quot;&gt;KZG commitment scheme&lt;&#x2F;a&gt; works in this setting, which is the tool we will use. Why are pairings useful? Because they provide us with a way of multiplying things hidden inside an elliptic curve group.&lt;&#x2F;p&gt;
&lt;p&gt;We pick a random $s$ (which is unknown to both the prover and verifier), and we generate the following points in the elliptic curve&lt;br &#x2F;&gt;
$\{ P_0 , P_1 , …, P_n \} = \{ g_1 , s g_1 , …, s^n g_n \}$&lt;br &#x2F;&gt;
These points contain the powers of $s$ hidden inside a group of the elliptic curve. Given any $P_k$, recovering $s$ is computationally intractable due to the hardness of the discrete log problem over elliptic curves.&lt;&#x2F;p&gt;
&lt;p&gt;We commit to the polynomial by computing&lt;br &#x2F;&gt;
$p(s) g_1 = \sum a_k (s^k g_1 ) = \sum a_k P_k$&lt;br &#x2F;&gt;
where $g_1$ is a generator of the group&#x2F;subgroup of prime order $r$ of the elliptic curve. We could also commit using elements in $G_2$, where we have $g_2$ as a subgroup generator.&lt;&#x2F;p&gt;
&lt;p&gt;Using pairings, we could prove the relationship between the polynomial $p(x)$ and the quotient $q(x)$ by computing two pairings and checking their equality:&lt;br &#x2F;&gt;
$e( p(s) g_1 , g_2) = e(g_1 , g_2 )^{p(s)}$&lt;br &#x2F;&gt;
$e(q(s) g_1 , s^m g_2 - g_2) = e(g_1 , g_2 )^{ q(s)(s^m - 1)}$&lt;br &#x2F;&gt;
Since $s$ is chosen at random, if $p(s) = q(s) Z(s)$, then with overwhelming probability, we have that $p(x) = q(x) Z(x)$.&lt;&#x2F;p&gt;
&lt;p&gt;With this construction, we do not need to supply the verifier with the coefficients of the polynomials, only their commitments. This solves part of the problem but not everything.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;intuition-for-the-protocol&quot;&gt;Intuition for the protocol&lt;&#x2F;h3&gt;
&lt;p&gt;The program&#x2F;circuit that we want to prove is defined by the matrix $U$. When we define a particular instance&#x2F;public input $u$ to the circuit, if $u$ is valid, we should be able to find some $w$ that solves the system of equations. To make the proof succinct, we should send much less information than the full witness (besides, if we want zero-knowledge, the witness should be kept secret).&lt;&#x2F;p&gt;
&lt;p&gt;We have the polynomial $p(x)$ of the problem, the vanishing polynomial $Z(x)$, and the quotient $q(x)$. In the end we want to prove that&lt;br &#x2F;&gt;
$p(x) = Z(x)q(x)$&lt;br &#x2F;&gt;
if the computation is valid. $Z(x)$ is known to both the prover and the verifier, and we could even commit to $Z(x)$ as part of the public information. We can reduce this check to just one point $x = s$ and verify this using pairings. However, this check alone would be insufficient since the prover could provide any polynomial $p(x)$. If we recall how we build $p(x)$,&lt;br &#x2F;&gt;
$\left(\sum_j U_{j} (x) z_j \right)^2 - 1 = p(x)$&lt;br &#x2F;&gt;
Some terms in the summation can be computed by the verifier (since these are public). However, the verifier does not know the witness’s terms, and we do not want to give him access to that data in total. The solution would be for the prover to give the summation, including only the values of the witness,&lt;br &#x2F;&gt;
$$V_w (x) = \sum_{j \in w} w_j U_j(x)$$&lt;br &#x2F;&gt;
Moreover, we can provide a commitment to $V_w (x)$ using the commitment scheme we had before, $V_w (s) g_1$ and $V_w (s) g_2$ (we will show why we need both soon). The verifier can then compute&lt;br &#x2F;&gt;
$$V_u (x) = \sum_{k \in u} u_j U_j(x)$$&lt;br &#x2F;&gt;
and get $V_u (s) g_1$ and $V_u (s) g_2$. The verifier can compute the pairing involving $e( p(s) g_1 , g_2)$ in an equivalent way,&lt;br &#x2F;&gt;
$$e ( V_u (s) g_1 + V_w(s) g_1 , V_u (s) g_2 + V_w(s) g_2 ) e ( g_1 , g_2 )^{ - 1 } = e( p(s) g_1 , g_2)$$&lt;br &#x2F;&gt;
This looks odd, but if we take all the scalars to the exponent, we have $(V_u (s) + V_w (s))(V_u (s) + V_w (s)) - 1$, and the verifier can get the polynomial of the circuit. So, we get the first check,&lt;br &#x2F;&gt;
$$e ( V_u (s) g_1 + V_w(s) g_1 , V_u (s) g_2 + V_w(s) g_2 ) e ( g_1 , g_2 )^{ - 1 } = e( q(s) g_1 , Z(s)g_2)$$&lt;&#x2F;p&gt;
&lt;p&gt;We have one problem, though. How do we know that the prover used the same $V_w (x)$ in both commitments? Luckily, we can solve this with another pairing check,&lt;br &#x2F;&gt;
$e( V_w (s) g_1 , g_2 ) = e( g_1 , V_w(s) g_2 )$&lt;&#x2F;p&gt;
&lt;p&gt;We got another check. Finally, how do we know that the verifier computed $V_w (x)$ correctly and did not do some random linear combination that will cancel out with the public input and yield something nice?&lt;&#x2F;p&gt;
&lt;p&gt;We could force the prover to provide the same linear combination, but with the points all shifted by some constant $\beta$, unknown to the parties. We define&lt;br &#x2F;&gt;
$B_w (x) = \sum \beta w_j U_j (x) = \beta V_w (x)$&lt;br &#x2F;&gt;
We can do one final check for this relationship using pairings,&lt;br &#x2F;&gt;
$e( B_w (s) g_1 , \gamma g_2 ) = e( \gamma \beta g_1 , V_w (s) g_2 )$&lt;br &#x2F;&gt;
where $\gamma$ is also unknown to the parties. This makes it impossible for the prover to build fake polynomials for $V_w (x)$. We can see that if this condition did not exist, we could create any $V_w (x) = C Z(x) - V_u (x) + 1$, which would pass all the other checks for any $C$ of our choice. In fact,&lt;br &#x2F;&gt;
$V_w (x) + V_u (x) = C Z(x) + 1$&lt;br &#x2F;&gt;
But $p(x) = (V_w (x) + V_u (x))^2 - 1$, so&lt;br &#x2F;&gt;
$p(x) = C^2 Z(x)Z(x) + C Z(x) = Z(x) (C^2 Z(x) + C)$&lt;br &#x2F;&gt;
and we find that $q(x) = (C^2 Z(x) + C)$, even though we do not know the witness.&lt;&#x2F;p&gt;
&lt;p&gt;The proof $\pi$ will consist of:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. The commitment to $V_w (x)$ using $g_1$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. The commitment to $V_w (x)$ using $g_2$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. The commitment to the quotient polynomial $q(x)$ using $g_1$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. The commitment to $B_w (x)$ using $g_1$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The verification involves six pairings (the pairing $e(g_1 , g_2)^{ - 1}$ can be precomputed since it is a constant), to check the three conditions we mentioned.&lt;&#x2F;p&gt;
&lt;p&gt;To compute the commitments, we need parameters $s , \beta , \gamma$ to be unknown to both parties (hence, they are toxic waste). We need to generate a reference string, which will be circuit dependent (that is because we need to provide $\beta U_j(s) g_1$). With all this, we can jump into the implementation.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;implementation&quot;&gt;Implementation&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;setup&quot;&gt;Setup&lt;&#x2F;h3&gt;
&lt;p&gt;Prover and verifier agree on a pairing-friendly elliptic curve and generators of the groups $G_1$ and $G_2$, denoted by $g_1$ and $g_2$, respectively. In our case, we choose BLS12-381. The proving key consists of the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. $\\{s^k g_1 \\}$ for $k = 0, 1, 2 , ... m$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. $\\{U_j (s) g_1 \\}$ for $j = l , l + 1 , ... m$ ($l$ being the number of public inputs).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. $\\{U_j (s) g_2 \\}$ for $j = l , l + 1 , ... m$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. $\\{\beta U_j (s) g_1 \\}$ for $j = l , l + 1 , ... m$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The verifying key consists of the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. $\\{U_j (s) g_1 \\}$ for $j = 0 , 1 , ... l - 1$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. $\\{U_j (s) g_2 \\}$ for $j = 0 , 1 , ... l - 1$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. $[Z^\prime ] = (s^m - 1)g_2$ (commitment to the vanishing polynomial)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. $e(g_1 , g_2)^{ - 1}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. $\beta \gamma g_1$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    6. $\gamma g_2$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;prove&quot;&gt;Prove&lt;&#x2F;h3&gt;
&lt;p&gt;The steps for the prover are as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Compute $[V_w ] = V_w (s) g_1$, $[V_w^\prime ] = V_w (s) g_2$, and $[B_w ] = B_w (s) g_1$ using the proving key.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Compute the polynomial quotient polynomial $q(x)$ from the zerofier $Z(x)$, the vector of witness and instance, and the polynomials describing the circuit $U_j (x)$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Compute $[q ] = q(s) g_1$ using the proving key.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Produce the proof $\pi = ( [q] , [V_w ] , [V_w^\prime ] , [B_w ])$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;verify&quot;&gt;Verify&lt;&#x2F;h3&gt;
&lt;p&gt;The verifier has the following steps:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Parse the proof $\pi$ as $[q] , [V_w ] , [V_w^\prime ] , [B_w ]$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Check $e( [V_w ] , g_2 ) = e( g_1 , [V_w^\prime ])$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Check $e( [B_w] , \gamma g_2) = e( \beta \gamma g_1 , [V_w^\prime ])$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Compute $[V_u ] = V_u (s) g_1$, and $[V_u^\prime ] = V_u (s) g_2$ using the verifying key.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. Check $e([V_u ] + [V_w ] , [V_u^\prime ] + [V_w^\prime ])e(g_1 , g_2)^{ - 1} = e( [q] , [Z^\prime])$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If all checks pass, the proof is valid.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;optimizations&quot;&gt;Optimizations&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Interpolation is done using the Fast Fourier Transform (FFT). This is possible because BLS12-381&amp;#39;s scalar field has $2^{32}$ as one of its factors.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. The quotient is calculated in evaluation form, using the FFT. We need to evaluate the polynomials at $\mu \omega^k$, where $\mu$ is the offset (we want to evaluate on cosets because if we evaluate directly over $D_i$, we get $0&#x2F;0$).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. The evaluation of the vanishing polynomial is straightforward: $Z(\mu \omega^k ) = (\mu \omega^k )^m - 1 = \mu^m - 1$, because $\omega$ has order $m$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Compute multiscalar multiplications using Pippenger&amp;#39;s algorithm.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;turning-the-snark-into-a-zk-snark&quot;&gt;Turning the SNARK into a zk-SNARK.&lt;&#x2F;h3&gt;
&lt;p&gt;The protocol above is not zero-knowledge since $V_w (x)$ can be distinguished from a random-looking $V (x)$. To make it zero-knowledge, the prover has to sample a random value $\delta$ and make the following changes to the polynomials:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. The polynomial $p(x) = \left(\sum_k z_j U_j(x) + \delta Z(x) \right)^2 - 1$. Note that adding $Z(x)$ does not change the main condition, which is that the constraints are satisfied if and only if $p(x)$ is divisible by $Z(x)$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Compute $[V_w ] = (V_w (s) + \delta Z(s)) g_1$, $[V_w^\prime ] = (V_w (s) + \delta Z(s)) g_2$, and $[B_w ] = (B_w (s) + \beta \delta Z(s)) g_1$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The verifier’s steps are unchanged.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;This post covered implementing a simple SNARK based on square span problems. We gave an intuition on how the protocol works and why we need different checks to achieve security. We hope this will enable newcomers to learn some of the basic concepts and workflow for ZKPs.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Our highly subjective view on the history of Zero-Knowledge Proofs</title>
          <pubDate>Sat, 17 Feb 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/our-highly-subjective-view-on-the-history-of-zero-knowledge-proofs/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/our-highly-subjective-view-on-the-history-of-zero-knowledge-proofs/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/our-highly-subjective-view-on-the-history-of-zero-knowledge-proofs/">&lt;p&gt;Zero-knowledge, Succinct, Non-interactive ARguments of Knowledge (zk-SNARKs) are powerful cryptographic primitives that allow one party, the prover, to convince another party, the verifier, that a given statement is true without revealing anything else other than the validity of the statement. They have gained widespread attention due to their applications in verifiable private computation, providing proof of the correctness of the execution of computer programs and helping scale blockchains. We think SNARKs will have a significant impact in shaping our world, as we describe in our &lt;a href=&quot;&#x2F;transforming-the-future-with-zero-knowledge-proofs-fully-homomorphic-encryption-and-new-distributed-systems-algorithms&#x2F;&quot;&gt;post&lt;&#x2F;a&gt;. SNARKs acts as an umbrella for different types of proof systems, using different polynomial commitment schemes (PCS), arithmetization schemes, interactive oracle proofs (IOP) or probabilistically checkable proofs (PCP). However, the basic ideas and concepts date back to the mid-1980’s. The development significantly accelerated after the introduction of Bitcoin and Ethereum, which proved to be an exciting and powerful use case since you can scale them by using Zero-Knowledge proofs (generally called Validity Proofs for this particular usecase). SNARKs are an essential tool for blockchain scalability. As Ben-Sasson describes, the last years have seen a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;starkware&#x2F;cambrian-explosion-of-cryptographic-proofs-5740a41cdbd2&quot;&gt;cambrian explosion of cryptographic proofs&lt;&#x2F;a&gt;. Each proof system offers advantages and disadvantages and was designed with certain tradeoffs in mind. Advances in hardware, better algorithms, new arguments, and gadgets result in enhanced performance and the birth of new systems. Many of them are used in production, and we keep pushing the boundaries. Will we have a general proof system for all applications or several systems suited for different needs? We think that it is unlikely that one proof system will rule them all because:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. The diversity of applications.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. The types of constraints we have (regarding memory, verification times, proving times).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. The need for robustness (if one proof system gets broken, we still have others).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Even if proof systems change a lot, they all offer a significant property: proofs can be verified quickly. Having a layer that verifies proofs and can be easily adapted to handle new proof systems solves the difficulties associated with changing the base layer, such as Ethereum. To give an overview of the different characteristics of SNARKs:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Cryptographic assumptions: collision-resistant hash functions, discrete log problem over elliptic curves, knowledge of exponent.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Transparent vs trusted setup.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Prover time: linear vs superlinear.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Verifier time: constant time, logarithmic, sublinear, linear.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Proof size.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Ease of recursion.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Arithmetization scheme.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Univariate vs multivariate polynomials.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This post will look into the origins of SNARKs, some fundamental building blocks, and the rise (and fall) of different proof systems. The post does not intend to be an exhaustive analysis of proof systems. We focus instead on those that had an impact on us. Of course, these developments were only possible with the great work and ideas of the pioneers of this field.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;fundamentals&quot;&gt;Fundamentals&lt;&#x2F;h2&gt;
&lt;p&gt;As we mentioned, zero-knowledge proofs are not new. The definitions, foundations, important theorems, and even important protocols were established from mid-1980s. Some of the key ideas and protocols that we use to build modern SNARKs were proposed in 1990s (the sumcheck protocol) or even before the advent of Bitcoin (GKR in 2007). The main problems with its adoption were related to the lack of a powerful usecase (internet was not as developed in the 1990s), and the amount of computational power needed.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;zero-knowledge-proofs-the-origins-1985-1989&quot;&gt;Zero-knowledge proofs: the origins (1985&#x2F;1989)&lt;&#x2F;h3&gt;
&lt;p&gt;The field of zero-knowledge proofs made its appearance in academic literature with the paper by &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;people.csail.mit.edu&#x2F;silvio&#x2F;Selected%20Scientific%20Papers&#x2F;Proof%20Systems&#x2F;The_Knowledge_Complexity_Of_Interactive_Proof_Systems.pdf&quot;&gt;Goldwasser, Micali and Rackoff&lt;&#x2F;a&gt;. For a discussion on the origins, you can see the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=uchjTIlPzFo&quot;&gt;following video&lt;&#x2F;a&gt;. The paper introduced the notions of completeness, soundness, and zero-knowledge, providing constructions for quadratic residuosity and quadratic non-residuosity.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;sumcheck-protocol-1992&quot;&gt;Sumcheck protocol (1992)&lt;&#x2F;h3&gt;
&lt;p&gt;The &lt;a href=&quot;&#x2F;have-you-checked-your-sums&#x2F;&quot;&gt;sumcheck protocol&lt;&#x2F;a&gt; was proposed by &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;dl.acm.org&#x2F;doi&#x2F;pdf&#x2F;10.1145&#x2F;146585.146605&quot;&gt;Lund, Fortnow, Karloff, and Nisan&lt;&#x2F;a&gt; in 1992. It is one of the most important building blocks for succinct interactive proofs. It helps us reduce a claim over the sum of a multivariate polynomial’s evaluations to a single evaluation at a randomly chosen point.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;goldwasser-kalai-rothblum-gkr-2007&quot;&gt;Goldwasser-Kalai-Rothblum (GKR) (2007)&lt;&#x2F;h3&gt;
&lt;p&gt;The &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.microsoft.com&#x2F;en-us&#x2F;research&#x2F;wp-content&#x2F;uploads&#x2F;2016&#x2F;12&#x2F;2008-DelegatingComputation.pdf&quot;&gt;GKR protocol&lt;&#x2F;a&gt; is an interactive protocol that has a prover that runs linearly in the number of gates of a circuit, while the verifier runs sublinearly in the size of the circuit. In the protocol, the prover and verifier agree on an arithmetic circuit of fan-in-two over a finite field of depth $d$, with layer $d$ corresponding to the input layer and layer $0$ being the output layer. The protocol starts with a claim regarding the output of the circuit, which is reduced to a claim over the values of the previous layer. Using recursion, we can turn this into a claim over the circuit’s inputs, which can be checked easily. These reductions are achieved via the sumcheck protocol.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;kzg-polynomial-commitment-scheme-2010&quot;&gt;KZG polynomial commitment scheme (2010)&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.iacr.org&#x2F;archive&#x2F;asiacrypt2010&#x2F;6477178&#x2F;6477178.pdf&quot;&gt;Kate, Zaverucha, and Goldberg&lt;&#x2F;a&gt; introduced in 2010 a commitment scheme for polynomials using a bilinear pairing group. The commitment consists of a single group element, and the committer can efficiently open the commitment to any correct evaluation of the polynomial. Moreover, due to batching techniques, the opening can be done to several evaluations. KZG commitments provided one of the basic building blocks for several efficient SNARKs, such as Pinocchio, Groth16, and Plonk. It is also at the heart of the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ethereum&#x2F;EIPs&#x2F;blob&#x2F;master&#x2F;EIPS&#x2F;eip-4844.md&quot;&gt;EIP-4844&lt;&#x2F;a&gt;. To get an intuition on batching techniques, you can see our post on the &lt;a href=&quot;&#x2F;mina-to-ethereum-bridge&#x2F;&quot;&gt;Mina-Ethereum bridge&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;practical-snarks-using-elliptic-curves&quot;&gt;Practical SNARKs using elliptic curves&lt;&#x2F;h2&gt;
&lt;p&gt;The first practical constructions for SNARKs appeared in 2013. These required a preprocessing step to generate the proving and verifying keys, and were program&#x2F;circuit specific. These keys could be quite large, and depended on secret parameters which should remain unknown to the parties; otherwise, they could forge proofs. Transforming code into something that could be proven required compiling the code to a system of polynomial constraints. At first, this had to be done in a manual way, which is time-consuming and error-prone. The advances in this area tried to remove some of the main problems:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Have more efficient provers.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Reduce the amount of preprocessing.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Having universal rather than circuit specific setups.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Avoid having trusted setups.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. Developing ways to describe circuits using a high-level language, instead of writing the polynomial constraints manually.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;pinocchio-2013&quot;&gt;Pinocchio (2013)&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2013&#x2F;279&quot;&gt;Pinocchio&lt;&#x2F;a&gt; is the first practical, usable zk-SNARK. The SNARK is based on quadratic arithmetic programs (QAP). The proof size was originally 288 bytes. Pinocchio’s toolchain provided a compiler from C code to arithmetic circuits, which was further transformed into a QAP. The protocol required that the verifier generate the keys, which are circuit-specific. It used elliptic curve pairings to check the equations. The asymptotics for proof generation and key setup were linear in the computation size, and the verification time was linear in the size of the public inputs and outputs.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;groth-16-2016&quot;&gt;Groth 16 (2016)&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2016&#x2F;260.pdf&quot;&gt;Groth&lt;&#x2F;a&gt; introduced a &lt;a href=&quot;&#x2F;groth16&#x2F;&quot;&gt;new argument of knowledge with increased performance&lt;&#x2F;a&gt; for problems described by an R1CS. It has the smallest proof size (only three group elements) and fast verification involving three pairings. It also involves a preprocessing step to obtain the structured reference string. The main drawback is that it requires a different trusted setup per program that we want to prove, which is inconvenient. Groth16 was used in ZCash.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;bulletproofs-ipa-2016&quot;&gt;Bulletproofs &amp;amp; IPA (2016)&lt;&#x2F;h3&gt;
&lt;p&gt;One of the weak points of the KZG PCS is that it requires a trusted setup. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2016&#x2F;263&quot;&gt;Bootle et al.&lt;&#x2F;a&gt; introduced an efficient zero-knowledge argument system of openings of Pedersen commitments that satisfy an inner product relation. The inner product argument has a linear prover, with logarithmic communication and interaction, but with linear time verification. They also developed a polynomial commitment scheme that does not require a trusted setup. PCS using these ideas are used by Halo 2 and Kimchi.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;sonic-marlin-and-plonk-2019&quot;&gt;Sonic, Marlin, and Plonk (2019)&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2019&#x2F;099&quot;&gt;Sonic&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2019&#x2F;953&quot;&gt;Plonk&lt;&#x2F;a&gt;, and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2019&#x2F;1047&quot;&gt;Marlin&lt;&#x2F;a&gt; solve the problem of the trusted setup per program that we had in Groth16, by introducing universal and updatable structured reference strings. Marlin provides a proof system based on R1CS and is at the core of Aleo.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;all-you-wanted-to-know-about-plonk&#x2F;&quot;&gt;Plonk&lt;&#x2F;a&gt; introduced a new arithmetization scheme (later called Plonkish) and the use of the grand-product check for the copy constraints. Plonkish also allowed the introduction of specialized gates for certain operations, the so-called custom gates. Several projects have customized versions of Plonk, including Aztec, zkSync, Polygon ZKEVM, Mina’s Kimchi, Plonky2, Halo 2, and Scroll, among others.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;lookups-2018-2020&quot;&gt;Lookups (2018&#x2F;2020)&lt;&#x2F;h3&gt;
&lt;p&gt;Gabizon and Williamson introduced &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2020&#x2F;315&quot;&gt;plookup&lt;&#x2F;a&gt; in 2020, using the grand product check to prove that a value is included in a precomputed value table. Though lookup arguments were previously presented in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2018&#x2F;380&quot;&gt;Arya&lt;&#x2F;a&gt;, the construction required the determination of the multiplicities for the lookups, which makes the construction less efficient. The &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2022&#x2F;086&quot;&gt;PlonkUp&lt;&#x2F;a&gt; paper showed how to introduce the plookup argument into Plonk. The problem with these lookup arguments was that they forced the prover to pay the price for the whole table, independently of his number of lookups. This implies a considerable cost for large tables, and a lot of effort has been devoted to reducing the cost of the prover to just the number of lookups he uses.&lt;br &#x2F;&gt;
Haböck introduced &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2022&#x2F;1530&quot;&gt;LogUp&lt;&#x2F;a&gt;, which uses the logarithmic derivative to turn the grand-product check into a sum of reciprocals. LogUp is crucial for performance in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;toposware.medium.com&#x2F;beyond-limits-pushing-the-boundaries-of-zk-evm-9dd0c5ec9fca&quot;&gt;Polygon ZKEVM&lt;&#x2F;a&gt;, where they need to split the whole table into several STARK modules. These modules have to be linked correctly, and cross-table lookups enforce this. The introduction of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2023&#x2F;1284&quot;&gt;LogUp-GKR&lt;&#x2F;a&gt; uses the GKR protocol to increase the performance of LogUp. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2022&#x2F;621&quot;&gt;Caulk&lt;&#x2F;a&gt; was the first scheme with prover time sublinear in the table size by using preprocessing time $\mathcal{O}(N \log N)$ and storage $\mathcal{O}(N)$, where $N$ is the table size. Several other schemes followed, such as &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2022&#x2F;1565&quot;&gt;Baloo&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2022&#x2F;1447&quot;&gt;flookup&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2022&#x2F;1763&quot;&gt;cq&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2022&#x2F;957&quot;&gt;caulk+&lt;&#x2F;a&gt;. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2023&#x2F;1216&quot;&gt;Lasso&lt;&#x2F;a&gt; presents several improvements, avoiding committing to the table if it has a given structure. Besides, Lasso’s prover only pays for table entries accessed by the lookup operations. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2023&#x2F;1217&quot;&gt;Jolt&lt;&#x2F;a&gt; leverages Lasso to prove the execution of a virtual machine via lookups&lt;&#x2F;p&gt;
&lt;h3 id=&quot;spartan-2019&quot;&gt;Spartan (2019)&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2019&#x2F;550&quot;&gt;Spartan&lt;&#x2F;a&gt; provides an IOP for circuits described using R1CS, leveraging the properties of multivariate polynomials and the sumcheck protocol. Using a suitable polynomial commitment scheme, it results in a transparent SNARK with a linear time prover.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;hyperplonk-2022&quot;&gt;HyperPlonk (2022)&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2022&#x2F;1355.pdf&quot;&gt;HyperPlonk&lt;&#x2F;a&gt; builds on the ideas of Plonk using multivariate polynomials. Instead of quotients to check the constraints’ enforcement, it relies on the sumcheck protocol. It also supports constraints of a high degree without harming the running time of the prover. Since it relies on multivariate polynomials, there is no need to carry out FFTs, and the prover’s running time is linear in the circuit size. HyperPlonk introduces a new permutation IOP suitable for smaller fields and a sum check-based batch opening protocol, which reduces the prover’s work, proof size, and the verifier’s time.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;folding-schemes-2008-2021&quot;&gt;Folding schemes (2008&#x2F;2021)&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2021&#x2F;370&quot;&gt;Nova&lt;&#x2F;a&gt; introduces the idea of a folding scheme, which is a new approach to achieve incrementally verifiable computation (IVC). The concept of IVC dates back to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;https:&#x2F;&#x2F;iacr.org&#x2F;archive&#x2F;tcc2008&#x2F;49480001&#x2F;49480001.pdf&quot;&gt;Valiant&lt;&#x2F;a&gt; who showed how to merge two proofs of length $k$ into a single proof of length $k$. The idea is that we can prove any long-running computation by recursively proving that the execution from step $i$ to step $ I + 1$ is correct and verifying a proof that shows that the transition from step $i - 1$ to step $i$ was correct. Nova deals well with uniform computations; it was later extended to handle different types of circuits with the introduction of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2022&#x2F;1758&quot;&gt;Supernova&lt;&#x2F;a&gt;. Nova uses a relaxed version of R1CS and works over amicable elliptic curves. Working with amicable cycles of curves (for example, the Pasta curves) to achieve IVC is also used in Pickles, Mina’s main building block to achieve a succinct state. However, the idea of folding differs from recursive SNARK verification. The accumulator idea is more deeply connected to the concept of batching proofs. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2019&#x2F;1021.pdf&quot;&gt;Halo&lt;&#x2F;a&gt; introduced the notion of accumulation as an alternative to recursive proof composition. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2023&#x2F;620&quot;&gt;Protostar&lt;&#x2F;a&gt; provides a non-uniform IVC scheme for Plonk that supports high-degree gates and vector lookups.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;using-collision-resistant-hash-functions&quot;&gt;Using collision-resistant hash functions&lt;&#x2F;h2&gt;
&lt;p&gt;Around the same time that Pinocchio was developed, there were some ideas to generate circuits&#x2F;arithmetization schemes that could prove the correctness of the execution of a virtual machine. Even though developing the arithmetization of a virtual machine could be more complex or less efficient than writing dedicated circuits for some programs, it offered the advantage that any program, no matter how complicated, could be proven by showing that it was executed correctly in the virtual machine. The ideas in TinyRAM were later improved with the design of the Cairo vm, and subsequent virtual machines (such as zk-evms or general purpose zkvms). The use of collision-resistant hash functions removed the need for trusted setups or use of elliptic curve operations, at the expense of longer proofs.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;tinyram-2013&quot;&gt;TinyRAM (2013)&lt;&#x2F;h3&gt;
&lt;p&gt;In &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2013&#x2F;507&quot;&gt;SNARKs for C&lt;&#x2F;a&gt;, they developed a SNARK based on a PCP to prove the correctness of the execution of a C program, which is compiled to TinyRAM, a reduced instruction set computer. The computer used a Harvard architecture with byte-level addressable random-access memory. Leveraging nondeterminism, the circuit’s size is quasilinear in the size of the computation, efficiently handling arbitrary and data-dependent loops, control flow, and memory accesses.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;starks-2018&quot;&gt;STARKs (2018)&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2018&#x2F;046&quot;&gt;STARKs&lt;&#x2F;a&gt; were introduced by Ben Sasson et al. in 2018. They achieve $\mathcal{O}(\log^2 n )$ proof sizes, with fast prover and verifier, do not require a trusted setup, and are conjectured to be post-quantum secure. They were first used by Starkware&#x2F;Starknet, together with the Cairo vm. Among its key introductions are the algebraic intermediate representation (AIR) and the &lt;a href=&quot;&#x2F;how-to-code-fri-from-scratch&#x2F;&quot;&gt;FRI protocol&lt;&#x2F;a&gt; (Fast Reed-Solomon Interactive Oracle Proof of Proximity). It is also used by other projects (Polygon Miden, Risc0, Winterfell, Neptune) or has seen adaptations of some components (zkSync’s Boojum, Plonky2, Starky).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ligero-2017&quot;&gt;Ligero (2017)&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2022&#x2F;1608&quot;&gt;Ligero&lt;&#x2F;a&gt; introduces a proof system that achieves proofs whose size is $\mathcal{O}(\sqrt{n})$, where $n$ is the size of the circuit. It arranges the polynomial coefficients in matrix form and uses linear codes.&lt;br &#x2F;&gt;
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2021&#x2F;1043&quot;&gt;Brakedown&lt;&#x2F;a&gt; builds on Ligero and introduces the idea of field-agnostic polynomial commitment schemes.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;some-new-developments&quot;&gt;Some new developments&lt;&#x2F;h2&gt;
&lt;p&gt;The use of different proof systems in production showed the merits of each of the approaches, and led to new developments. For example, plonkish arithmetization offers a simple way to include custom gates and lookup arguments; FRI has shown great performance as PCS, leading to Plonky. Similarly, the use of the grand product check in AIR (leading to randomized AIR with preprocessing) improved its performance and simplified memory access arguments. Commitments based on hash functions have gained popularity, based on the speed of hash functions in hardware or the introduction of new SNARK-friendly hash functions.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;new-polynomial-commitment-schemes-2023&quot;&gt;New polynomial commitment schemes (2023)&lt;&#x2F;h3&gt;
&lt;p&gt;With the advent of efficient SNARKs based on multivariate polynomials, such as Spartan or HyperPlonk, there has been an increased interest in new commitment schemes suited for this kind of polynomials. &lt;a href=&quot;&#x2F;snarks-on-binary-fields-binius&#x2F;&quot;&gt;Binius&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2023&#x2F;917&quot;&gt;Zeromorph&lt;&#x2F;a&gt;, and &lt;a href=&quot;&#x2F;how-does-basefold-polynomial-commitment-scheme-generalize-fri&#x2F;&quot;&gt;Basefold&lt;&#x2F;a&gt; all propose new forms to commit to multilinear polynomials. Binius offers the advantage of having zero overhead to represent data types (whereas many proof systems use at least 32-bit field elements to represent single bits) and works over binary fields. The commitment adapts brakedown, which was designed to be field agnostic. Basefold generalizes FRI to codes other than Reed-Solomon, leading to a field-agnostic PCS.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;customizable-constraint-systems-2023&quot;&gt;Customizable Constraint Systems (2023)&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2023&#x2F;552&quot;&gt;CCS&lt;&#x2F;a&gt; generalizes R1CS while capturing R1CS, Plonkish, and AIR arithmetization without overheads. Using CCS with Spartan IOP yields SuperSpartan, which supports high-degree constraints without having the prover to incur cryptographic costs that scale with the degree of the constraint. In particular, SuperSpartan yields a SNARK for AIR with a linear time prover.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;This post describes the advances of SNARKs since their introduction in the mid-1980s. Advances in computer science, mathematics, and hardware, together with the introduction of blockchain, have led to new and more efficient SNARKs, opening the door for many applications that could transform our society. Researchers and engineers have proposed improvements and adaptations to SNARKs according to their needs, focusing on proof size, memory use, transparent setup, post-quantum security, prover time, and verifier time. While there were originally two main lines (SNARKs vs STARKs), the boundary between both has begun to fade, trying to combine the advantages of the different proof systems. For example, combining different arithmetization schemes with new polynomial commitment schemes. We can expect that new proof systems will continue to rise, with increased performance, and it will be hard for some systems that require some time to adapt to keep up with these developments unless we can easily use these tools without having to change some core infrastructure.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>How does Basefold polynomial commitment scheme generalize FRI</title>
          <pubDate>Fri, 09 Feb 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/how-does-basefold-polynomial-commitment-scheme-generalize-fri/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/how-does-basefold-polynomial-commitment-scheme-generalize-fri/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/how-does-basefold-polynomial-commitment-scheme-generalize-fri/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&quot;&gt;lambdaworks&lt;&#x2F;a&gt; is a library designed to provide efficient proof systems. We want it to support state of the art provers and associated primitives so that people can use them to build new applications. Among those primitives we have polynomial commitment schemes (PCS). These are a powerful cryptographic tool that allows us to bind ourselves to a given polynomial by means of a small data structure (such as the root of a Merkle tree or a point over an elliptic curve) and prove its evaluations at some points. Polynomial commitment schemes consist of the following five algorithms:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Setup: given a security parameter, $\lambda$, it generates the public parameters (pp) for the PCS.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Commit: taking the pp and a polynomial, $p$, outputs a commitment to the polynomial $\mathrm{cm}(p)$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Open: given the pp, a polynomial $p$ and a commitment to $p$, $\mathrm{cm}(p)$, checks whether $\mathrm{cm}(p)$ is the commitment to $p$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Prove evaluation: given the pp, a polynomial $p$, a point $z$ and a claimed evaluation $v$, outputs a proof $\pi$ that the $p(z) = v$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Verify evaluation: given the pp, the commitment to $p$, the proof $\pi$, the point $z$ and the claimed value $v$, checks whether the evaluation proof is valid.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Polynomial commitment schemes are one of the basic building blocks of modern SNARKs. Some commitment schemes require a trusted setup (such as &lt;a href=&quot;&#x2F;mina-to-ethereum-bridge&#x2F;&quot;&gt;KZG&lt;&#x2F;a&gt;), while others are transparent (such as FRI, Brakedown and IPA). Different PCS offer trade-offs between evaluation proof sizes, evaluation times, security assumptions, and other algebraic properties (for example, being additively homomorphic).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2023&#x2F;1705.pdf&quot;&gt;Basefold&lt;&#x2F;a&gt; generalizes the &lt;a href=&quot;&#x2F;how-to-code-fri-from-scratch&#x2F;&quot;&gt;FRI commitment scheme&lt;&#x2F;a&gt; to other codes different from Reed-Solomon. These codes need to have certain properties, though. This post will discuss the basics of coding theory and explain how basefold works.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;coding-theory&quot;&gt;Coding theory&lt;&#x2F;h2&gt;
&lt;p&gt;Error-correcting codes are ways of representing data so that we can recover the information even if parts of it were corrupted. We do this by introducing redundancy, and the message can be recovered even if parts of the redundant data are corrupted. There is a trade-off between maximizing error correction and redundancy: codes with higher redundancy should be able to tolerate a higher number of errors.&lt;&#x2F;p&gt;
&lt;p&gt;A code of block length $n$ over an alphabet $\Sigma$ is a subset of $\Sigma^n$. In our case, we will be interested in codes where the alphabet $\Sigma$ is some finite field $\mathbb{F}$ and $\vert \Sigma \vert = q$.&lt;&#x2F;p&gt;
&lt;p&gt;The rate of a code of dimension $k$ and block size $n$ is given by $\rho = k &#x2F; n$ and is a measure of the amount of redundancy introduced in the code.&lt;&#x2F;p&gt;
&lt;p&gt;Given a code, the Hamming distance, $d$, between two code words is given by the number of positions they differ at. The relative distance is the ratio between the distance and the block length, $\delta = d &#x2F; n$.&lt;&#x2F;p&gt;
&lt;p&gt;A code over $\Sigma^n$ of dimension $k$ and distance $d$ is called an $(n , k , d )_{\Sigma}$ - code. A linear code is such that any linear combination of codewords results in a codeword (that is, if $c_0$ and $c_1$ are the encoding of $m_0$ and $m_1$, then $\alpha_0 c_0 + \alpha_1 c_1$ is also a codeword, specifically, the codeword associated with $\alpha_0 m_0 + \alpha_1 m_1$).&lt;&#x2F;p&gt;
&lt;p&gt;For linear codes, the encoding function can be represented as a vector-matrix product using a generator matrix, $G$, that is&lt;br &#x2F;&gt;
$\mathrm{Enc}(v) = v . G$&lt;&#x2F;p&gt;
&lt;p&gt;For example, Reed-Solomon codes use a Vandermondian matrix with points $\alpha_0, \alpha_1, … , \alpha_{n - 1}$:&lt;br &#x2F;&gt;
$$\begin{align}&lt;br &#x2F;&gt;
V(\alpha_0 , \alpha_1 , … , \alpha_{n - 1}, k)_{i,j} = \alpha_j^i&lt;br &#x2F;&gt;
\end{align}$$&lt;&#x2F;p&gt;
&lt;p&gt;Reed-Solomon codes work by interpreting the message as the coefficients of a degree $k - 1$ polynomial. If the message is $(m_0 , m_1 , … , m_{k - 1})$, we can think of them as $m_0 + m_1 x + … + m_{k - 1} x^{ k - 1}$ and provide the evaluations over $n$ distinct points. Since the polynomial is at most of degree $k - 1$, it has at most $k - 1$ zeros, making two different codewords coincide at most in $k - 1$ places, so $d = n - k + 1$. Codes which satisfy $d = n - k + 1$ are called maximum distance separable codes.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;basefold&quot;&gt;Basefold&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=OuKUqPbHLQ0&quot;&gt;Basefold&lt;&#x2F;a&gt; works with foldable linear codes. Remember that we can represent linear codes via the generator matrix, $G$. The generator matrix, $G_{k , n}$ of the foldable linear $(n, k, d )$ - code has the following block matrix structure:&lt;br &#x2F;&gt;
$$G_{k,n} = \begin{bmatrix}&lt;br &#x2F;&gt;
G_{k&#x2F;2,n&#x2F;2} &amp;amp; G_{k&#x2F;2,n&#x2F;2} \newline&lt;br &#x2F;&gt;
G_{k&#x2F;2,n&#x2F;2} T_{k&#x2F;2,n&#x2F;2} &amp;amp; G_{k&#x2F;2,n&#x2F;2}T^\prime_{k&#x2F;2,n&#x2F;2}&lt;br &#x2F;&gt;
\end{bmatrix}$$&lt;br &#x2F;&gt;
where $G_{k&#x2F;2,n&#x2F;2}$ is the generator matrix of the foldable linear $[n&#x2F;2, k&#x2F;2, d^\prime ]_\Sigma$-code.&lt;&#x2F;p&gt;
&lt;p&gt;For example, Reed-Solomon codes satisfy this property, when instantiated over a multiplicative subgroup of size $n = 2^m$ (we also assume that $\rho = 2^{- \beta}$). If we choose a generator $g$ of the subgroup and represent the points as $\{ 1, g, g^2 , … g^{m - 1} \}$, we have&lt;br &#x2F;&gt;
$$G_{k,n} = \begin{bmatrix}&lt;br &#x2F;&gt;
1 &amp;amp; 1 &amp;amp; 1 &amp;amp; 1 &amp;amp; \dots &amp;amp; 1 \newline&lt;br &#x2F;&gt;
1 &amp;amp; g &amp;amp; g^2 &amp;amp; g^3 &amp;amp; \dots &amp;amp; g^{m - 1} \newline&lt;br &#x2F;&gt;
1 &amp;amp; g^2 &amp;amp; g^4 &amp;amp; g^6 &amp;amp; \dots &amp;amp; g^{2(m - 1)} \newline&lt;br &#x2F;&gt;
1 &amp;amp; g^3 &amp;amp; g^6 &amp;amp; g^9 &amp;amp; \dots &amp;amp; g^{3(m - 1)} \newline&lt;br &#x2F;&gt;
\vdots &amp;amp; \vdots &amp;amp; \vdots &amp;amp; \vdots &amp;amp; \ddots &amp;amp; \vdots \newline&lt;br &#x2F;&gt;
1 &amp;amp; g^{k - 1} &amp;amp; g^{2(k - 1)} &amp;amp; g^{3(k - 1)} &amp;amp; \dots &amp;amp; g^{(k - 1) (m - 1)}&lt;br &#x2F;&gt;
\end{bmatrix}$$&lt;&#x2F;p&gt;
&lt;p&gt;Let’s reorder the matrices rows by placing first all the even-numbered rows, in increasing order, followed by all the odd-numbered rows. We get,&lt;br &#x2F;&gt;
$$G_{k,n} = \begin{bmatrix}&lt;br &#x2F;&gt;
1 &amp;amp; 1 &amp;amp; 1 &amp;amp; 1 &amp;amp; \dots &amp;amp; 1 \newline&lt;br &#x2F;&gt;
1 &amp;amp; g^2 &amp;amp; g^4 &amp;amp; g^6 &amp;amp; \dots &amp;amp; g^{2(m - 1)} \newline&lt;br &#x2F;&gt;
1 &amp;amp; g^4 &amp;amp; g^8 &amp;amp; g^{12} &amp;amp; \dots &amp;amp; g^{4(m - 1)} \newline&lt;br &#x2F;&gt;
\vdots &amp;amp; \vdots &amp;amp; \vdots &amp;amp; \vdots &amp;amp; \ddots &amp;amp; \vdots \newline&lt;br &#x2F;&gt;
1 &amp;amp; g &amp;amp; g^2 &amp;amp; g^3 &amp;amp; \dots &amp;amp; g^{m - 1} \newline&lt;br &#x2F;&gt;
1 &amp;amp; g^3 &amp;amp; g^6 &amp;amp; g^9 &amp;amp; \dots &amp;amp; g^{3(m - 1)} \newline&lt;br &#x2F;&gt;
1 &amp;amp; g^5 &amp;amp; g^{10} &amp;amp; g^{15} &amp;amp; \dots &amp;amp; g^{15(m - 1)} \newline&lt;br &#x2F;&gt;
\vdots &amp;amp; \vdots &amp;amp; \vdots &amp;amp; \vdots &amp;amp; \ddots &amp;amp; \vdots \newline&lt;br &#x2F;&gt;
1 &amp;amp; g^{k - 1} &amp;amp; g^{2(k - 1)} &amp;amp; g^{3(k - 1)} &amp;amp; \dots &amp;amp; g^{(k - 1) (m - 1)}&lt;br &#x2F;&gt;
\end{bmatrix}$$&lt;&#x2F;p&gt;
&lt;p&gt;We can see that the lower block (the odd rows) looks a bit similar to the upper block, except that most columns are shifted by a similar amount. For example, column one there is a factor $g$ missing, column two, a factor $g^2$, column three, $g^3$ and so on. We have therefore broken the matrix into upper and lower parts. We need to break each part into right and left parts.&lt;&#x2F;p&gt;
&lt;p&gt;If $g$ is a generator of a group of order $m$, then $\omega = g^2$ is a generator of a subgroup of order $m&#x2F;2$. As soon as we have something like $\omega^{m&#x2F;2}$ we wrap back to $1$. This breaks the upper half into two identical matrices, which correspond to $G_{k&#x2F;2, n&#x2F;2}$. In the lower half, the diagonal matrices are:&lt;br &#x2F;&gt;
$T_{ii} = g^i$&lt;br &#x2F;&gt;
$T^\prime_{ii} = g^{m&#x2F;2} g^i$&lt;br &#x2F;&gt;
But $g^{m&#x2F;2} = - 1$, so $T = - T^\prime$.&lt;&#x2F;p&gt;
&lt;p&gt;We see that linear foldable codes generalize this property we had in Reed-Solomon codes. There are, however, no restrictions on the generator matrices, other than fulfilling the foldable linear code definition. This lets us choose the diagonal matrices $T, T^\prime$ more freely and be able to use non FFT-friendly fields (this makes basefold PCS field-agnostic). In basefold, they set the matrices $T = - T^\prime$, and their elements are sampled at random from the multiplicative group of the base field. We can construct the generator matrices inductively, by choosing $G_0$ and $T_0 , T_0^\prime$ and get $G_1$, which, together with $T_1 , T_1^\prime$ leads to $G_2$, etc. To encode a message $v$, we just have to do $v.G_d$. We can also encode $v$ in a recursive fashion,&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. If $d = 0$, $\mathrm{enc}_0 ( v ) = v.G_0$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Otherwise, split $v = (w_0 , w_1)$ in the first and second halves. Let $c_0 = \mathrm{enc}( w_0 )$, $c_1 = \mathrm{enc}( w_1 )$, $t = \mathrm{diagonal}(T)$ and compute $\mathrm{enc}(v) = (m_0 + m_1 \times t , m_0 - m_1 \times t)$, where $\times$ is the componentwise (Hadamard) product.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The evaluation of a multilinear polynomial $p$ at $z$ can be turned into an evaluation check of $p$ at a random point via the &lt;a href=&quot;&#x2F;have-you-checked-your-sums&#x2F;&quot;&gt;sumcheck protocol&lt;&#x2F;a&gt;. FRI works in a similar way: the last value sent in FRI corresponds to the encoding of a random evaluation of the polynomial of the first round. Therefore, a PCS can be constructed by using a Merkle tree commitment to the encoding of some polynomial $p$. During evaluation, prover and verifier run in parallel the proximity test and the sumcheck protocol using the same set of challenges. The verifier can check that the evaluation of the polynomial corresponds to the last message of the prover in the proximity test.&lt;&#x2F;p&gt;
&lt;p&gt;Basefold’s proximity test works in the same way as FRI. We have a commit phase where the prover commits to lists of codewords&#x2F;evaluations and a query phase, where the verifier checks the consistency between the codewords. During the commitment phase,&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. The prover starts with $\pi_d$, the encoding of some polynomial.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. For i = $d - 1$ to $0$  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;a. Samples $\alpha_i$ from the verifier.&lt;br &#x2F;&gt;
b. For every $j$ in $n_i$ the prover computes the line $l_j (x)$ passing through $(T_i [j,j] , \pi_{i+1} [j])$ and $(-T_i [j,j] , \pi_{i+1} [j + n_i ])$ and sets $\pi_i [j] = l(\alpha_j )$&lt;br &#x2F;&gt;
c. The prover commits to $\pi_i$.&lt;&#x2F;p&gt;
&lt;p&gt;This commit phase is, in fact, identical to FRI. We start with the evaluations of the composition polynomial, $f$ (which is the Reed-Solomon encoding of the polynomial) and to which we committed previously. We sample the folding challenge $\alpha_i$ and then obtain the following function, $l(x) = (f(x_0 ) + f( - x_0 ))&#x2F;2 + x (f( x_0 ) - f( - x_0))&#x2F;2x_0$. We can see that $l(x_0 ) = f( x_0 )$ and $l( - x_0) = f (- x_0 )$, which is essentially the line passing through those two points.&lt;&#x2F;p&gt;
&lt;p&gt;During the query phase,&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. The verifier samples an index $i$ in $[0, n_d - 1]$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. For $j = d - 1$ to $0$,  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;a. Queries $\pi_{j + 1} [i]$ and $\pi_{j + 1} [i + n_i &#x2F; 2]$&lt;br &#x2F;&gt;
b. Computes the line $l_i(x)$ passing through those two points.&lt;br &#x2F;&gt;
c. Checks that $\pi_j [i] = l(\alpha_j )$&lt;br &#x2F;&gt;
d. If $j &amp;gt; 0$ and $i &amp;gt; n_{i - 1}$, set $i = i - n_{i - 1}$.
3. Finally, check whether $\pi_0$ is a valid codeword using the generator matrix $G_0$.&lt;&#x2F;p&gt;
&lt;p&gt;To reduce the soundness error, the verifier can query more indexes, as we did in FRI. We are only lacking the evaluation protocols (prove and verify). To construct it, we need to use the sumcheck protocol, together with the proximity test.&lt;&#x2F;p&gt;
&lt;p&gt;At the start of the protocol, the verifier has access to $\pi_d$, the encoding of the polynomial, the evaluation point, $z$ and the claimed evaluation, $v$. The protocol proceeds as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. The prover sends the univariate polynomial $h_d (x) = \sum_b f(b,x) eq_z (b,x)$ to the verifier.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. For $i = d - 1$ to $0$,  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;a. The prover runs the commit phase steps 2.a, 2.b, 2.c.&lt;br &#x2F;&gt;
b. If $i &amp;gt; 0$, the prover sends $h_i = \sum_b f(b,x, r_i , … , r_{d - 1} ) eq_z (b,x, r_i , … , r_{d - 1} )$.
3. The verifier:&lt;br &#x2F;&gt;
a. Checks query phase of the proximity test.&lt;br &#x2F;&gt;
b. Performs all the checks in the sumcheck protocol&lt;br &#x2F;&gt;
c. Verifies that $\mathrm{enc_0} (h_1 ( r_0 ) &#x2F; eq_z (r_0 , … r_{d - 1} )) = \pi_0$&lt;&#x2F;p&gt;
&lt;p&gt;We see that the evaluation protocol basically consists of the sumcheck and proximity tests run concurrently.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;This post discussed a new commitment scheme, basefold, which generalizes FRI. The main advantanges over FRI are that the new commitment works better with multilinear polynomials and is field agnostic. The construction can be instantiated with any foldable linear code. These are codes whose generator matrix has a given block structure. We will be adding this new commitment scheme to lambdaworks in the coming future and compare its performance with other constructions.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Mina to Ethereum ZK bridge</title>
          <pubDate>Mon, 05 Feb 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/mina-to-ethereum-bridge/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/mina-to-ethereum-bridge/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/mina-to-ethereum-bridge/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;During the last few months, we have been developing a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;mina_bridge&quot;&gt;bridge between Mina and Ethereum&lt;&#x2F;a&gt;. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;minaprotocol.com&#x2F;&quot;&gt;Mina&lt;&#x2F;a&gt; is a layer-1 blockchain that uses zero-knowledge proofs (zk-SNARKs) to maintain its &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;minaprotocol.com&#x2F;blog&#x2F;22kb-sized-blockchain-a-technical-reference&quot;&gt;size at 22 kB&lt;&#x2F;a&gt;. The bridge serves two purposes:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Allowing cross-chain transactions seamlessly.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Allowing applications to leverage Mina&amp;#39;s zero-knowledge capabilities and expand their functionalities across multiple chains.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Due to $2$, users can simply prove things off-chain and verify them on-chain in Ethereum.&lt;&#x2F;p&gt;
&lt;p&gt;At its core, Mina uses a proof system called &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;o1-labs.github.io&#x2F;proof-systems&#x2F;specs&#x2F;kimchi.html&quot;&gt;Kimchi&lt;&#x2F;a&gt;, which is a variant of Plonk with many optimizations and uses an inner product argument (IPA) polynomial commitment scheme. Its key optimizations are custom gates for foreign field addition and multiplication, Keccak, Poseidon, and lookup arguments. Above that, we have Pickles, which is Mina’s inductive SNARK composition, enabling a flexible way to have &lt;a href=&quot;&#x2F;incrementally-verifiable-computation-nova&#x2F;&quot;&gt;incrementally verifiable computation&lt;&#x2F;a&gt;. This construction allows us to generate a proof that attests to the validity of the transition from state $S_n$ to state $S_{n + 1}$ while checking a proof that the previous step was correct. While this helps Mina achieve its succinctness, verifying these proofs in Ethereum is very expensive.&lt;&#x2F;p&gt;
&lt;p&gt;Currently, pairing-based SNARKs (such as those using KZG) have cheaper verification costs in Ethereum, which makes this option attractive. To “wrap” Mina state proofs, we can generate a SNARK to verify a Mina proof obtained with IPA, using a variant of Kimchi with the KZG commitment scheme. To do so, we must first express all the verification logic of the Kimchi-IPA proof as a circuit, then use this circuit, the proof, and other public input and generate a proof using Kimchi-KZG. This is more easily said than done. First, we must express all the verification operations as an arithmetic circuit. The good thing is that we can express even complex operations such as MSM using elliptic curve gates and lookup arguments. The bad thing is that the equations are expressed over Ethereum’s BN-254 scalar field, which differs from the Pasta fields. This means we will have to do many foreign field operations, making the SNARK quite expensive.&lt;&#x2F;p&gt;
&lt;p&gt;This post will provide an overview of the bridge, Kimchi, and the KZG verifier. For an introduction to some of the topics, see &lt;a href=&quot;&#x2F;all-you-wanted-to-know-about-plonk&#x2F;&quot;&gt;Plonk&lt;&#x2F;a&gt;, &lt;a href=&quot;&#x2F;ipa-and-a-polynomial-commitment-scheme&#x2F;&quot;&gt;IPA&lt;&#x2F;a&gt;, and &lt;a href=&quot;&#x2F;lookups&#x2F;&quot;&gt;lookups&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-bridge&quot;&gt;The Bridge&lt;&#x2F;h2&gt;
&lt;p&gt;The bridge has the following components:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. A backend service periodically wraps and posts Mina&amp;#39;s state proofs to an EVM chain.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. A &amp;quot;wrapping&amp;quot; module for Mina&amp;#39;s proofs to make them easy to verify on the EVM.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. The solidity logic for verifying the wrapped Mina state proofs in the EVM.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Browser utility for smart contracts.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. A solidity contract utility that smart contract developers or users can execute on an EVM chain to feed in a Mina state lookup proof that will check the state lookup against the latest posted Mina state proof to verify that this Mina state is valid.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The flow is shown in the following picture. For more details related to the architecture, see the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;mina_bridge&#x2F;blob&#x2F;main&#x2F;README.md&quot;&gt;bridge’s readme&lt;&#x2F;a&gt;.&lt;br &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;HJ6DjwYcT.jpg&quot; alt=&quot;flow&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;snarks&quot;&gt;SNARKs&lt;&#x2F;h2&gt;
&lt;p&gt;As mentioned, Mina’s proof system is Kimchi, a modified version of Plonk, using IPA and working over a pair of elliptic curves, Pallas and Vesta (shortened to Pasta curves). IPA and Pasta curves enable easy recursion but at the expense of longer proofs than KZG-based SNARKs. Verifying and storing these proofs in Ethereum is expensive, so we need to obtain a new type of proof that can be checked less expensively in Ethereum. Let’s dive into Kimchi, Pickes, and KZG commitments.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;kimchi&quot;&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;o1-labs.github.io&#x2F;proof-systems&#x2F;kimchi&#x2F;overview.html&quot;&gt;Kimchi&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;This is a modified version of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2019&#x2F;953&quot;&gt;Plonk&lt;&#x2F;a&gt;. There are three types of arguments:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Custom gates.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Permutation.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Lookups.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;These arguments are translated into several polynomials, which must evaluate to zero over some set. Luckily, we can check that all the polynomials evaluate to zero over the set by doing a random linear combination. Say, for example, that $p_1 , p_2 … p_n$ all evaluate to zero over the set $S = { 1, 2, … , m}$. We can have the verifier sample $\alpha$ and obtain&lt;br &#x2F;&gt;
$p (x) = \alpha p_1 (x) + \alpha^2 p_2 (x) + \dots + \alpha^n p_n (x)$&lt;br &#x2F;&gt;
which should also evaluate to zero. To see that the polynomial has that property, we can show that $p(x)$ is divisible by the polynomial vanishing on S, $Z_S (x)$. Another way to state this is that there is some polynomial $q(x)$ such that $p(x) = Z_S (x) q(x)$. Moreover, if we decide to perform this check at just one random point $\zeta$ from a very large set, then, with high probability, we have that the previous equality holds for all the set.&lt;&#x2F;p&gt;
&lt;p&gt;The ingredients are the circuit specification (the gates and the connections&#x2F;wirings) and the execution trace. The execution trace in Kimchi has input&#x2F;output registers (7) plus advice registers (8). The circuit is known beforehand and represents a given program&#x2F;computation. The execution trace depends on the particular execution of the program (for example, we can run the same program with different inputs).&lt;&#x2F;p&gt;
&lt;p&gt;The following tables describe the circuit:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Gates: Generic, Poseidon, Elliptic Curve Addition, Endo Scalar, Endo Scalar Multiplication, Scalar Multiplication, Range Check, Foreign Field Addition, Foreign Field Multiplication, Rotation, and XOR.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Coefficients. These are only used in Poseidon and generic gates.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Wirings (also Permutations or Sigmas)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Lookup tables&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Lookup selectors&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub struct CircuitGate&amp;lt;F: PrimeField&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;&#x2F; type of the gate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub typ: GateType,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;&#x2F; gate wiring (for each cell, what cell it is wired to)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub wires: GateWires,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;&#x2F; public selector polynomials that can used as handy coefficients in gates&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    #[serde_as(as = &amp;quot;Vec&amp;lt;o1_utils::serialization::SerdeAs&amp;gt;&amp;quot;)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub coeffs: Vec&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Kimchi contains three main algorithms:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Setup: takes the circuit and produces the prover and verifier indexes.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Proof creation: takes the circuit and the prover index and outputs a proof.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Proof verification: takes the proof and the verifier index and checks the proof.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The steps performed by the prover to obtain the proof are listed &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;o1-labs.github.io&#x2F;proof-systems&#x2F;specs&#x2F;kimchi.html#proof-creation&quot;&gt;here&lt;&#x2F;a&gt;. The verification follows the steps shown &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;o1-labs.github.io&#x2F;proof-systems&#x2F;specs&#x2F;kimchi.html#proof-verification&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pickles&quot;&gt;Pickles&lt;&#x2F;h2&gt;
&lt;p&gt;Pickles uses the Pasta curves to deliver incrementally verifiable computation efficiently. The Pasta curves are also known as:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Tick&#x2F;Step (Vesta), handling blocks and transactions&amp;#39; proofs.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Tock&#x2F;Wrap (Pallas), handling signatures and performing recursive verifications.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Tock is used to prove the verification of a Tick proof and outputs a Tick proof. Tick is used to prove the verification of a Tock proof and outputs a Tock proof.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $\mathrm{Prove_{tock} ( Verify(Tick) ) = Tick_{proof}}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $\mathrm{Prove_{tick} (Verify(Tock) ) = Tock_{proof}}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Both Tick and Tock can verify at most two proofs of the opposite kind. Pickles contains two components: fast (1 - 30 ms) and slow (100 ms - 1 s) verifiers. Given a proof $\pi_1$, we first execute the fast verifier, and the update algorithm takes the previous proof state, $S_0$, and $\pi_1$ and generates the next proof state, $S_1$. If we have an incoming $\pi_2$, we do not execute the slow verifier, beginning a new cumulative phase. We run the fast verifier on $\pi_2$ and update the proof state from $S_1$ to $S_2$. If there are no more incoming proofs, we use the slow verifier to check the last state proof $S_n$.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;kzg-verifier-solidity&quot;&gt;KZG verifier solidity&lt;&#x2F;h2&gt;
&lt;p&gt;The code for the verifier in solidity is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;mina_bridge&#x2F;blob&#x2F;main&#x2F;eth_verifier&#x2F;src&#x2F;Verifier.sol&quot;&gt;here&lt;&#x2F;a&gt;. The verifier can be divided into two large parts:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Partial verification.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Final verification.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The first handles checks such as the correct length of evaluations and commitments regenerates the random challenges using Fiat-Shamir and uses the claimed evaluations to see whether the gate and permutation constraints are valid. The second part checks the commitments by calling the pairing check function. In a naïve KZG verification, we must compute one pairing for every evaluation we want to check. However, we can randomly combine the commitments and evaluations to perform just one pairing check.&lt;&#x2F;p&gt;
&lt;p&gt;The working principle behind the verification of the KZG evaluation proof is the following: we have a commitment to a polynomial, $p(x)$, an evaluation point, $\zeta$, a claimed evaluation, $v = p(\zeta)$, and the evaluation proof, $\pi = \mathrm{cm}(q)$, which is the commitment to a quotient polynomial, $q(x)$. If the evaluation is correct, then $p(x) - v$ should be divisible by $x - \zeta$, that is&lt;br &#x2F;&gt;
$p(x) - v = (x - z) q(x)$&lt;br &#x2F;&gt;
We cannot do this check directly since we have access only to the commitments and not the whole polynomials. We have $\mathrm{cm}(p) = p(s) g_1$ and $\mathrm{cm}(q) = q(s) g_1$, which are points on an elliptic curve. We could attempt to check everything at just one point, $s$, and, if the two sides match, then with overwhelming probability, the polynomial was evaluated correctly. The pairing is a function $e(x,y)$ with two properties:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Bilinear: $e(x_1+x_2,y_1+y_2) = e(x_1 , y_1 )e(x_2 , y_2 )e(x_1 , y_2 )e(x_2 ,y_1 )$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Non-degenerate: if $e(x,y) = 1$, then $x$ or $y$ are the point at infinity (neutral element for elliptic curve addition).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It follows from the bilinearity property that&lt;br &#x2F;&gt;
$e( p(s) g_1 - v g_1 , g_2 ) = e(g_1 , g_2 )^{p(s) - v}$&lt;br &#x2F;&gt;
Similarly,&lt;br &#x2F;&gt;
$e( q(s) g_1 , s g_2 - \zeta g_2 ) = e(g_1 , g_2 )^{q(s)(s - \zeta)}$&lt;br &#x2F;&gt;
Since neither $g_1$ nor $g_2$ are the point at infinity (because they are generators of the whole group), $e (g_1 , g_2) \neq 1$, and therefore, if both pairings are equal, then it follows that&lt;br &#x2F;&gt;
$p(s) - v = q(s) (s - \zeta)$&lt;br &#x2F;&gt;
The EVM has a function, pairing check, which computes the product of both pairings and verifies that it is equal to one. Because of this condition, we rewrite the second pairing, negating the commitment to the quotient,&lt;br &#x2F;&gt;
$e( - q(s) g_1 , s g_2 - \zeta g_2 ) = e(g_1 , g_2 )^{ - q(s)(s - \zeta)}$&lt;&#x2F;p&gt;
&lt;h3 id=&quot;batching-evaluation-at-point-zeta-for-several-polynomials&quot;&gt;Batching evaluation at point $\zeta$ for several polynomials&lt;&#x2F;h3&gt;
&lt;p&gt;If we have several polynomials $p_1, p_2, … p_n$ and we want to check the evaluation at the same point $\zeta$, we just need to perform a random linear combination for each of these elements:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Commitments to $p_k$: $\mathrm{cm}(p) = \sum \alpha^k \mathrm{cm}(p_k )$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Commitments to quotients $q_k$: $\mathrm{cm}(q) = \sum \alpha^k \mathrm{cm}(q_k )$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Evaluations: $v = \sum \alpha^k v_k$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;batching-evaluations-at-several-points-zeta-k-for-one-polynomial&quot;&gt;Batching evaluations at several points $\zeta_k$ for one polynomial&lt;&#x2F;h3&gt;
&lt;p&gt;If we need to check that a polynomial evaluates at $\zeta_1$ to $v_1$, at $\zeta_2$ to $v_2$, … and at $\zeta_n$ to $v_n$, we can fuse all these checks into a single one. The steps are as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Compute the polynomial of degree $n - 1$, $I(x)$, that interpolates the points $(\zeta_k , v_k )$. This means that $I( \zeta_k ) = v_k$ for $k = 1, 2, ... n$. If we have two points only, $I(x) = (v_2 - v_1 ) (\zeta_2 - \zeta_1 )^{- 1} (x - \zeta_1 ) + v_1$, which is the line passing through those two points.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The polynomial $p(x) - I(x)$ evaluates to $0$ at $\zeta_k$, which means that $p(x) - I(x)$ is divisible by the polynomial $D(x) = \prod (x - \zeta_k )$(in our two-dimensional case, this is $(x - \zeta_1 )(x - \zeta_2 )$). Compute the quotient $q(x)$ of $p(x) - I(x)$ by $D(x)$ and commit to it.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can combine this idea with batch verification for several polynomials and just pay for one pairing check!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;&#x2F;h2&gt;
&lt;p&gt;This post presented the bridge between the succinct blockchain Mina and Ethereum, allowing seamless cross-chain transactions and dApps to leverage Mina’s zk capabilities. One of the main challenges is related to the verification of Mina’s proofs in Ethereum since they rely on IPA, which is more expensive than those based on KZG. To deal with this, we have to create a wrapper (a program that proves the verification of Mina proofs) to obtain new proofs that can be verified in Ethereum more cost-effectively. We covered the basics of Kimchi (Mina’s proof system) and Pickles (which allows Mina to deliver incrementally verifiable computation, the key component for succinctness) and how KZG commitments work. We also discussed some of the challenges related to foreign field operations. In upcoming posts, we will discuss some of the bridge’s components and the project’s milestones and advances in more depth.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Happy birthday, lambdaworks!</title>
          <pubDate>Tue, 30 Jan 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/happy-birthday-lambdaworks/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/happy-birthday-lambdaworks/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/happy-birthday-lambdaworks/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;It’s been almost a year since we started building &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&quot;&gt;lambdaworks&lt;&#x2F;a&gt;! lambdaworks is our library that implements efficient cryptographic primitives to build proof systems. Along with it, many backends for proof systems are shipped, and compatibility with different frontends is supported. We wanted to give an overview of what we have done over the last year and the roadmap for the future. Why did we choose to embark on this journey? We are truly bullish on zero-knowledge&#x2F;validity proofs and their potential to solve many problems and create new applications, as we stated in our &lt;a href=&quot;&#x2F;transforming-the-future-with-zero-knowledge-proofs-fully-homomorphic-encryption-and-new-distributed-systems-algorithms&#x2F;&quot;&gt;previous post&lt;&#x2F;a&gt; and &lt;a href=&quot;&#x2F;lambda-crypto-doctrine&#x2F;&quot;&gt;crypto doctrine&lt;&#x2F;a&gt;. We decided to work in this challenging environment, where math, distributed systems, and cryptography meet. The first challenge we faced was the lack of performant and developer-friendly libraries, though there are some exceptions. Some have nice APIs and are easy to use but not written in Rust; others are written in Rust but have poor programming practices. So, we decided with a team of engineers and mathematicians to build a new library, written in Rust, focusing on performance and developer-friendliness. We also wanted to make all this knowledge available to other developers and help onboard new people to this space by writing clear documentation and explaining how each of the parts and proof systems work. Open source and decentralization are necessary practical conditions to build crypto, and we cannot think of decentralization as the knowledge and tools to build things are centralized in a few players. Let’s jump into our plans for the future and some numbers.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;some-numbers&quot;&gt;Some numbers:&lt;&#x2F;h2&gt;
&lt;p&gt;Here we give some figures to understand all the work we have been doing in the library and the contributions from the community:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * 464 PRs merged.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * 60 contributors.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * 8 releases.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * 49k lines of code in Rust&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Several posts on finite fields, cryptography, and proof systems.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Use of lambdaworks in 2 CTF events and Lambda ZK Week.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * 800+ members in lambdaworks channel.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * One cryptography bootcamp with 21 interns from 12 countries&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;objectives&quot;&gt;Objectives:&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Reference library for cryptography and proof systems.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Written in Rust.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * To be used in production, not just for academic research. However, we also want to enable researchers to write their papers in our library easily.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Support for GPU acceleration (Metal, CUDA).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Simple to use, developer-focused.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Clear documentation, plenty of examples.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;what-do-we-still-have-to-work-on&quot;&gt;What do we still have to work on&lt;&#x2F;h2&gt;
&lt;p&gt;We have added several tools and proof systems to the library, but we still have a long way to go:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Integration into other provers, VMs, and cryptography projects.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Documentation. We still need to improve the project documentation, add more examples, and enhance user experience.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Create a grant and bounty program&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Support the use of Icicle.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Towers of binary fields.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * New polynomial commitment schemes: basefold, brakedown, inner product argument (IPA), Binius.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * New layouts for Cairo STARK Platinum.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Lookup arguments (for example, Plookup, and Lasso)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * New proof systems: Hyperplonk, Spartan, Marlin, GKR.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Folding schemes.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Supporting new elliptic curves.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * New hash functions.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Improve performance of FFT, elliptic curves, polynomials, and general finite field arithmetic.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Add new coordinate systems for elliptic curves.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Second edition of the cryptography bootcamp.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;what-we-accomplished&quot;&gt;What we accomplished?&lt;&#x2F;h2&gt;
&lt;p&gt;Over the year, we have implemented different core math, crypto building blocks, and proof systems. We have received contributions from the community, not only in the form of PRs but also as issues and bug reports.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;main-crates&quot;&gt;Main crates:&lt;&#x2F;h3&gt;
&lt;p&gt;The main crates we have implemented are:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Finite Fields: all the mathematical building blocks for cryptography and proof systems. This is used by the Cairo VM in production in Starknet.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Crypto: hash functions, Merkle trees, polynomial commitment schemes.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Provers (&amp;amp; verifiers): STARK Platinum, Groth 16, Plonk. Adapters for Cairo, Winterfell, Miden (STARKs), Circom, and Arkworks (Groth 16).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;fields&quot;&gt;Fields:&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Optimized Montgomery backend.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Specialized backends for Mersenne-31 and Mini-Goldilocks ($2^{64} - 2^{32} +1$).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Field extensions.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Radix-2 and radix-4 fast Fourier Transform.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Elliptic curves.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Multiscalar multiplication.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Pairings.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Univariate polynomials.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Multivariate polynomials.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;crypto&quot;&gt;Crypto:&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Fiat Shamir transformation.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Hash functions: Poseidon, Pedersen&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Merkle trees&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * KZG commitment scheme&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;provers&quot;&gt;Provers:&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * General STARK prover&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Groth 16&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Plonk with KZG commitment&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Adapters&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</description>
      </item>
      <item>
          <title>A fast trust minimized intent based bridge solution for Ethereum and L2s powered by multi-proof storage proofs</title>
          <pubDate>Sun, 28 Jan 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/a-fast-trust-minimized-intent-based-bridge-solution-for-ethereum-and-l2s-powered-by-multi-proof-storage-proofs/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/a-fast-trust-minimized-intent-based-bridge-solution-for-ethereum-and-l2s-powered-by-multi-proof-storage-proofs/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/a-fast-trust-minimized-intent-based-bridge-solution-for-ethereum-and-l2s-powered-by-multi-proof-storage-proofs/">&lt;p&gt;&lt;strong&gt;Authors:&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;thisisrj&quot;&gt;Roberto Catalan&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;federicocarrone&quot;&gt;Federico Carrone&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Bridges are generally insecure and economically inefficient. They exhibit an asymmetry between users and bridge operators, where users can easily lose funds. We propose a bridge design that is simple, modular, and utilizes multi-storage proofs and the native messaging system between Ethereum and Layer 2 networks (L2s) as a fallback mechanism.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bridging-is-a-trust-issue&quot;&gt;Bridging is a trust issue&lt;&#x2F;h2&gt;
&lt;p&gt;How can we offer a system where the users don’t have to trust a facilitator to exchange their assets from an L2 to Ethereum?&lt;&#x2F;p&gt;
&lt;p&gt;We propose a simple protocol that follows these steps:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. The user specifies a destination address on Ethereum and locks the tokens X to be bridged into an L2 escrow smart contract.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. A market maker monitors a change of state in the escrow smart contract.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. a. The market maker calls the transfer function of the PaymentRegistry Contract in Ethereum.  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;b. The transfer function of the PaymentRegistry contract in Ethereum pays the tokens X to the User.
4. A storage proof is generated, containing evidence of a transfer from the market maker’s Ethereum account to the user-specified address in Ethereum.
5. Ethereum PaymentRegistry storage information is used as part of a storage proof.
6. L2 Escrow contract verifies the storage proof of the PaymentRegistry contract in Ethereum and pays the MM with the initial tokens locked by the user.
&lt;img src=&quot;&#x2F;images&#x2F;2024&#x2F;01&#x2F;image.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The same design can be expanded to be used to bridge tokens from an L2 to another L2. The same design can include multi-proof storage proofs instead of using only one. We also have implemented a fallback mechanism using the native message mechanism between Ethereum and L2s in case the storage proof providers are offline.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Fallback mechanism&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
If the storage proof providers are not available, the market maker can prove to the Escrow contract that they fulfilled the user’s intent through the rollup’s native messaging system. Using this messaging system has the same trust assumptions as the L2s used in the transfer.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;risks&quot;&gt;Risks&lt;&#x2F;h2&gt;
&lt;p&gt;For the user, the risks include the existence of a bug in the code of the smart contract, the existence of a bug in the circuits of the ZK&#x2F;validity proof verification and the fact that the storage proof provider can go offline. The first risk is mitigated by having a very simple smart contract. The second risk is mitigated by using multi-proof storage proofs and multiple ZK&#x2F;validity proof implementations or TEEs. If the storage proof provider goes offline the fallback mechanism can be used.&lt;&#x2F;p&gt;
&lt;p&gt;The risks for market makers are the same as for users, plus the risk of reorganization of the chain and the fact that the market maker receives the same tokens on the L2s rather than on Ethereum.&lt;&#x2F;p&gt;
&lt;p&gt;Since the capital is locked for a short period (until the proof is generated or the message arrives), the risks are minimized and the attack surface is smaller for the market maker.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;questions&quot;&gt;Questions&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;What are our disadvantages?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
The biggest disadvantage of this solution is that users can only bridge tokens that are present in both the origin and destination chains.&lt;br &#x2F;&gt;
Another disadvantage is that the risks don’t disappear; they are simply transferred to the market maker.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;How can users cancel their order?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Initially, we are not going to offer the ability to cancel orders. The main reason is to avoid any timing attacks. For instance, a user could create an order and cancel it right after the market maker has paid them on the destination chain, thereby stealing funds from the market maker.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Is there any real-world implementation of this bridge?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Yes. We have already implemented this between Starknet and Ethereum. We plan to integrate zkSync, Arbitrum, Optimism, Scroll, Base, and Linea next.&lt;br &#x2F;&gt;
All integrations require the same codebase with a few modifications, except for Starknet, which is not EVM compatible.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;How fast is it?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
From the user’s perspective, the bridging is completed in less than 30 seconds, as quickly as the time it takes the market maker to observe the user’s deposit and execute a transfer.&lt;br &#x2F;&gt;
From the market maker’s perspective, they will be able to withdraw the money after paying the user and generating the storage proof. This normally takes between 5 and 15 minutes. It’s important to also consider that the market maker will need to rebalance their liquidity using the native bridge and wait for the finality of the native bridge to rebalance their portfolio.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;How cheap is it?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
The cost of this bridge is similar to an ERC20 transfer plus the cost of proving the state of the L1 and L2. This second cost tends towards zero since it’s amortized by multiple calls that use the same proof, and the proving cost is minimal compared to on-chain transfers.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is new in this design? Didn’t storage proofs solve this problem already?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Storage proofs alone don’t fundamentally change the design of a traditional bridge. They merely enable a safer coordination mechanism.&lt;br &#x2F;&gt;
Locking the user’s capital first provides guarantees to the market maker that they will receive the funds in exchange for fulfilling the user’s intent.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Couldn’t you solve this problem without Storage Proofs? What do they add to the table?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Yes, Storage Proofs are not 100% necessary to solve this problem. But they are a key technological component for a future proof architecture. If we want this protocol to scale, storage proofs are the best way to do this. It will allow us to prove many orders together.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What are the benefits against an Optimistic Oracle?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Optimistic Oracles were a great solution before Storage Proofs were a feasible solution, their main disadvantages are:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Optimistic Oracles relay in Game Theory to work and it&amp;#39;s difficult to bootstrap an ecosystem to make them robust.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Codebases are complex&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The settlement period takes a few hours (depending on the solution) and end up creating inefficiencies for the market makers.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;On the other hand our protocol with the native messaging and storage proofs takes no longer than 15 minutes (between Ethereum and L2) to unlock the funds. The protocol codebase is no more than 500 lines of code and the risks are easy to understand by all the players and therefore easy to come up with ways to mitigate them.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Did anybody do something similar beforehand?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Hop Protocol was one of the first bridges to allow cross-chain swaps between rollups and Ethereum with an AMM-based design using multiple messaging systems (native and optimistic). The main issue lies in the capital inefficiency of an AMM model and the significant security risks of locking large amounts of capital in complex cross-chain communications.&lt;&#x2F;p&gt;
&lt;p&gt;Across was the first bridge to leverage intents for a faster bridge experience and lower capital costs per transaction. However, by using an Optimistic Oracle, it naturally has a challenging period that the market has to wait to get its funds back. To optimize some of the problems their settlement mechanism introduces, they offer financial products around their main bridge solution, such as Liquidity Pools that front the capital to the market makers.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What are our advantages?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Our bet is that zero-knowledge proofs will continue to improve, becoming faster and safer, thus enhancing our solution and allowing us to offer better prices by lowering risks and shortening the repayment period.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Fast and cheap bridging experience for the user&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Short capital lock-up period for the market maker&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Low on-chain complexity. The smart contracts in total are not larger than 300 lines of code.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Speeding up message passing with EigenLayer to allow cross-chain swap settlements between L2s. The protocol should have the option to send faster messages between rollups and Ethereum with similar trust assumptions of the native messaging system.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Introducing Partially Filled Orders, offering cheaper but slower transfers with batching.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Intent-based DeFi Pooling.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Unified wallet abstraction across multiple L2s.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</description>
      </item>
      <item>
          <title>Deep dive into Cairo&#x27;s AIR and the changes we had to do in Lambdaworks to be compatible with Starknet Stone Prover</title>
          <pubDate>Thu, 25 Jan 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/deep-dive-into-cairos-air-and-the-changes-we-had-to-do-in-lambdaworks-to-be-compatible-with-starknet-stone-prover/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/deep-dive-into-cairos-air-and-the-changes-we-had-to-do-in-lambdaworks-to-be-compatible-with-starknet-stone-prover/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/deep-dive-into-cairos-air-and-the-changes-we-had-to-do-in-lambdaworks-to-be-compatible-with-starknet-stone-prover/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;During the last months, we have been working to make &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&quot;&gt;Lambdaworks&lt;&#x2F;a&gt; STARK Platinum prover with Starknet’s Stone prover. We also want STARK Platinum to be flexible enough to be used as a drop-in replacement for other STARK provers, such as Winterfell (employed as the default prover in Miden). One of the main difficulties is related to how we provide the algebraic intermediate representation (AIR) and constraints in a simple yet expressible way and be able to try and test several trace configuration layouts. In a &lt;a href=&quot;&#x2F;comparing-stark-provers&#x2F;&quot;&gt;previous post&lt;&#x2F;a&gt;, we discussed different design choices for STARK provers, such as using virtual columns, built-ins, and chiplets and their tradeoffs. We would like the prover to be as modular as possible so that we can try different design options, incorporate new tools or fields, and assess performance. One inconvenience with previous approaches was that changes in the AIR or selecting a new layout needed extensive rewriting. Moreover, when using virtual columns, the prover must supply the zerofiers for each constraint, which depends on how the columns are interleaved, making it difficult and error-prone.&lt;&#x2F;p&gt;
&lt;p&gt;In this post, we will cover the new way of implementing transition constraints and AIRs in STARK Platinum, which should give us more freedom to test and move things around, making it more straightforward to add new layouts. We also provide tools to evaluate the zerofiers without the user giving the exact expression. If you are unfamiliar with some of the concepts, you can take a look at our posts on STARKs &lt;a href=&quot;&#x2F;diving-deep-fri&#x2F;&quot;&gt;1&lt;&#x2F;a&gt; and &lt;a href=&quot;&#x2F;comparing-stark-provers&#x2F;&quot;&gt;2&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;transition-constraints&quot;&gt;Transition constraints&lt;&#x2F;h2&gt;
&lt;p&gt;We define the public trait &lt;code&gt;pub trait TransitionConstraint&amp;lt;F, E&amp;gt;: Send + Sync where F: IsSubFieldOf&amp;lt;E&amp;gt; + IsFFTField + Send + Sync, E: IsField + Send + Sync,&lt;&#x2F;code&gt;, which contains all the methods we need to deal with transition constraints. It is generic over two fields, &lt;code&gt;F&lt;&#x2F;code&gt;, the base field, and &lt;code&gt;E&lt;&#x2F;code&gt;, which could be a field extension of &lt;code&gt;F&lt;&#x2F;code&gt;. If we do not need an extension field, we will simply have &lt;code&gt;E&lt;&#x2F;code&gt; equal to &lt;code&gt;F&lt;&#x2F;code&gt;. The base field should also be an FFT-friendly field, that is, it should contain a multiplicative subgroup of size $2^m$ (for example, $p = 2^{64} - 2^{32} +1$ has a multiplicative group of size $2^{64} - 2^{32}$, which is divisible by $2^{32}$). Below, we list the main methods:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `fn degree` gives the degree of the transition constraint. All the constraints for the Cairo vm are at most degree 3. The higher the degree of the constraint, the larger the evaluation domain needed to calculate the transition constraints.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `fn constraint_idx` gives the constraint identifier, a unique integer between 0 and the total number of transition constraints.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `fn evaluate` provides how to evaluate the constraint over the trace&amp;#39;s low-degree extension (LDE). Depending on the constraint, `periodic_values` or `rap_challenges` may be needed. The values are stored in the `transition_evaluations` vector, in the position corresponding to the`constraint_idx`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `fn period` indicates how often a constraint is applied. If the constraint is applied at each step, it is set to $1$. Some constraints may apply every several steps (for example, 16 or 256), which is necessary to evaluate the zerofier correctly.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `fn offset` indicates where we start applying the constraint, beginning from the first step. If the constraint applies from the first step, we set it to $0$. If a constraint starts at $1$ and has a period of $16$, this means that the constraint is valid for steps 1, 17, 33, 49, etc. We need this to evaluate the zerofier correctly.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `fn end_exemptions` indicates whether the constraint applies to the trace&amp;#39;s last $n$ steps. If it applies to every step, it is set to $0$. If the last two steps do not enforce the constraint, we put it to $2$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `fn exemptions_period` and `fn periodic_exemptions_offset` are necessary to remove several intermediate steps from a constraint. All the exemptions are needed to evaluate the zerofier correctly.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Several methods to evaluate the zerofier for the constraint `fn end_exemptions_poly`, `fn zerofier_evaluations_on_extended_domain` and `fn evaluate_zerofier`. The second function is needed to evaluate the composition polynomial, while the third one is required to evaluate at the out-of-domain point, $z$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;understanding-exemptions-and-zerofiers&quot;&gt;Understanding exemptions and zerofiers&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;fibonacci-sequence&quot;&gt;Fibonacci sequence&lt;&#x2F;h3&gt;
&lt;p&gt;To fix how exemptions work, let us look at some examples. The easiest to grasp is &lt;code&gt;end_exemptions&lt;&#x2F;code&gt;. These appear, for example, in the case of the calculation of the Fibonacci sequence:&lt;br &#x2F;&gt;
$a_0 = a_1 = 1$&lt;br &#x2F;&gt;
$a_{n + 2} = a_{n + 1} + a_n$&lt;br &#x2F;&gt;
A single trace column can represent this and can be expressed by the following polynomial relationship:&lt;br &#x2F;&gt;
$t(g^2 x) - t(g x) - t(x) = 0$&lt;br &#x2F;&gt;
This constraint is valid for all computation steps except the last two. Remember that we represent each step by a power of $g$, an $n$-th primitive root of unity ($n$ is equal to the trace length). Thus, the zerofier would look like&lt;br &#x2F;&gt;
$$Z_C (x) = \prod_{i = 0}^{ n - 3} (x - g^i ) = \frac{\prod_{i = 0}^{ n - 1} (x - g^i )}{(x - g^{n - 2} )( x - g^{n - 1} )}$$&lt;br &#x2F;&gt;
The zerofier is&lt;br &#x2F;&gt;
$Z (x) = \prod_{i = 0}^{ n - 1} (x - g^i ) = x^n - 1$&lt;br &#x2F;&gt;
while the exemptions are just&lt;br &#x2F;&gt;
$E (x) = (x - g^{n - 2} )( x - g^{n - 1} )$&lt;br &#x2F;&gt;
The combination of both gives the zerofier for the constraint. To represent these constraints, we will have &lt;code&gt;fn end_exemptions&lt;&#x2F;code&gt; return $2$, &lt;code&gt;fn period&lt;&#x2F;code&gt; return $1$, and &lt;code&gt;fn offset&lt;&#x2F;code&gt; yield $0$.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;cairo-flags-example&quot;&gt;Cairo Flags example&lt;&#x2F;h3&gt;
&lt;p&gt;This example follows the constraints in the virtual column containing all the flags in the Cairo vm. The AIR is provided &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;blob&#x2F;87915f06dab3a899d6e967766c0097a89d8d633b&#x2F;provers&#x2F;stark&#x2F;src&#x2F;examples&#x2F;bit_flags.rs#L18&quot;&gt;here&lt;&#x2F;a&gt;. The column consists of repetitions of 15 binary values, followed by a zero value. There are two transition constraints:&lt;br &#x2F;&gt;
$t (1 - t) = 0$&lt;br &#x2F;&gt;
$t = 0$&lt;&#x2F;p&gt;
&lt;p&gt;The first constraint holds for all values except every 16th value. On the other hand, the second constraint holds only every 16 rows, starting from row 15. Let’s compute the zerofier for the second constraint first:&lt;br &#x2F;&gt;
$Z_C (x) = (x - g^{15} )(x - g^{31} )(x - g^{47} )…$&lt;br &#x2F;&gt;
The number of terms is $n&#x2F;16$. We can take the $g^{15}$ as common factor and call $y = x&#x2F;g^{15}$. Thus,&lt;br &#x2F;&gt;
$Z_C (x) = g^{15 n&#x2F;16} \prod_{j = 0}^{ n&#x2F;16 - 1} (y - g^{ 16j} )$&lt;br &#x2F;&gt;
Remember that, if $g$ is an $n$-th root of unity, $g^{16}$ is an $n&#x2F;16$-th root of unity. Since we are multiplying all the $n&#x2F;16$ roots of unity, we get&lt;br &#x2F;&gt;
$Z_C (y) = g^{15 n&#x2F;16} (y^{n&#x2F;16} - 1)$&lt;br &#x2F;&gt;
Distributing and remembering the relationship between $x$ and $y$&lt;br &#x2F;&gt;
$Z_C (x) = x^{n&#x2F;16} - g^{ 15n&#x2F;16 }$&lt;br &#x2F;&gt;
This zerofier is compatible with &lt;code&gt;fn offset&lt;&#x2F;code&gt; equal to $15$ and &lt;code&gt;fn period&lt;&#x2F;code&gt; equal to $16$, with no exemptions present.&lt;&#x2F;p&gt;
&lt;p&gt;The zerofier for the first constraint can be calculated by knowing the zerofiers for the whole trace and the zerofier for the zero flag constraint. This is,&lt;br &#x2F;&gt;
$$Z_F (x) = \frac{x^n - 1}{x^{n&#x2F;16} - g^{ 15n&#x2F;16 }}$$&lt;&#x2F;p&gt;
&lt;p&gt;The first constraint has &lt;code&gt;fn periodic_exemptions_offset&lt;&#x2F;code&gt; equal to $15$ and &lt;code&gt;fn exemptions_period&lt;&#x2F;code&gt; equal to $16$, essentially computing the same zerofier as the zero flag and taking it from the full trace zerofier.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;algebraic-intermediate-representation&quot;&gt;Algebraic Intermediate Representation&lt;&#x2F;h2&gt;
&lt;p&gt;We established an AIR trait, which contains all the methods we need to represent the trace, the constraints, and their evaluation.&lt;&#x2F;p&gt;
&lt;p&gt;The method &lt;code&gt;fn trace_layout(&amp;amp;self) -&amp;gt; (usize, usize)&lt;&#x2F;code&gt; provides the number of columns of the main and auxiliary traces (if it exists). The main trace contains elements in the base field (for example, Stark252 or Mini-Goldilocks). In contrast, if needed, the auxiliary trace may have elements from an extension field to achieve cryptographic security.&lt;&#x2F;p&gt;
&lt;p&gt;To evaluate transition constraints, we have the methods &lt;code&gt;fn compute_transition_prover&lt;&#x2F;code&gt;, &lt;code&gt;fn compute_transition_verifier&lt;&#x2F;code&gt;, &lt;code&gt;fn transition_constraints&lt;&#x2F;code&gt; and &lt;code&gt;fn transition_zerofier_evaluations&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;fn transition_zerofier_evaluations&lt;&#x2F;code&gt; has a default implementation. Given that some constraints might share the same zerofier (because they apply at the same steps of the execution trace), we avoid recomputing zerofiers by checking with a &lt;code&gt;zerofier_group_key&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn transition_zerofier_evaluations(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;self,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        domain: &amp;amp;Domain&amp;lt;Self::Field&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ) -&amp;gt; Vec&amp;lt;Vec&amp;lt;FieldElement&amp;lt;Self::Field&amp;gt;&amp;gt;&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let mut evals = vec![Vec::new(); self.num_transition_constraints()];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let mut zerofier_groups: HashMap&amp;lt;ZerofierGroupKey, Vec&amp;lt;FieldElement&amp;lt;Self::Field&amp;gt;&amp;gt;&amp;gt; =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            HashMap::new();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        self.transition_constraints().iter().for_each(|c| {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let period = c.period();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let offset = c.offset();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let exemptions_period = c.exemptions_period();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let periodic_exemptions_offset = c.periodic_exemptions_offset();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let end_exemptions = c.end_exemptions();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; This hashmap is used to avoid recomputing with an fft the same zerofier evaluation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; If there are multiple domains and subdomains they can be further optimized&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; as to share computation between them&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let zerofier_group_key = (&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                period,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                offset,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                exemptions_period,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                periodic_exemptions_offset,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                end_exemptions,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            zerofier_groups&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                .entry(zerofier_group_key)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                .or_insert_with(|| c.zerofier_evaluations_on_extended_domain(domain));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let zerofier_evaluations = zerofier_groups.get(&amp;amp;zerofier_group_key).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            evals[c.constraint_idx()] = zerofier_evaluations.clone();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        evals&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;implementing-the-cairoair&quot;&gt;Implementing the CairoAIR&lt;&#x2F;h2&gt;
&lt;p&gt;The implementation of the CairoAIR starts &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;blob&#x2F;f271ed876cfa3aa58e36a29e22430eef3703fdc8&#x2F;provers&#x2F;cairo&#x2F;src&#x2F;air.rs#L535&quot;&gt;here&lt;&#x2F;a&gt;. We begin by defining the &lt;code&gt;fn new&lt;&#x2F;code&gt;, which contains the 64 constraints, the transition exemptions and the AIRContext. Since the Stone Prover uses virtual columns, the final number of constraints (counting transition and boundary constraints) will be 46. The main trace has six columns, and the auxiliary trace has 2. The plain layout for one step can be found in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;blob&#x2F;main&#x2F;docs&#x2F;src&#x2F;starks&#x2F;stone_prover&#x2F;trace_plain_layout.md&quot;&gt;documentation of our prover&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The implementation of the &lt;code&gt;TransitionConstraint&lt;&#x2F;code&gt; trait for each of the constraints is done &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;blob&#x2F;main&#x2F;provers&#x2F;cairo&#x2F;src&#x2F;transition_constraints.rs#L8&quot;&gt;here&lt;&#x2F;a&gt;. This is the list of transition constraints for the CairoAIR using the plain layout:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * BitPrefixFlag0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * BitPrefixFlag1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * BitPrefixFlag2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * BitPrefixFlag3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * BitPrefixFlag4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * BitPrefixFlag5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * BitPrefixFlag6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * BitPrefixFlag7&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * BitPrefixFlag8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * BitPrefixFlag9&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * BitPrefixFlag10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * BitPrefixFlag11&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * BitPrefixFlag12&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * BitPrefixFlag13&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * BitPrefixFlag14&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * ZeroFlagConstraint&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * InstructionUnpacking&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * CpuOperandsMemDstAddr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * CpuOperandsMem0Addr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * CpuOperandsMem1Addr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * CpuUpdateRegistersApUpdate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * CpuUpdateRegistersFpUpdate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * CpuUpdateRegistersPcCondPositive&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * CpuUpdateRegistersPcCondNegative&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * CpuUpdateRegistersUpdatePcTmp0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * CpuUpdateRegistersUpdatePcTmp1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * CpuOperandsOpsMul&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * CpuOperandsRes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * CpuOpcodesCallPushFp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * CpuOpcodesCallPushPc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * CpuOpcodesAssertEq&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * MemoryDiffIsBit0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * MemoryDiffIsBit1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * MemoryDiffIsBit2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * MemoryDiffIsBit3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * MemoryDiffIsBit4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * MemoryIsFunc0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * MemoryIsFunc1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * MemoryIsFunc2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * MemoryIsFunc3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * MemoryIsFunc4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * MemoryMultiColumnPermStep0_0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * MemoryMultiColumnPermStep0_1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * MemoryMultiColumnPermStep0_2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * MemoryMultiColumnPermStep0_3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * MemoryMultiColumnPermStep0_4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Rc16DiffIsBit0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Rc16DiffIsBit1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Rc16DiffIsBit2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Rc16DiffIsBit3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Rc16PermStep0_0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Rc16PermStep0_1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Rc16PermStep0_2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Rc16PermStep0_3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * FlagOp1BaseOp0BitConstraint&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * FlagResOp1BitConstraint&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * FlagPcUpdateRegularBit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * FlagFpUpdateRegularBit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * CpuOpcodesCallOff0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * CpuOpcodesCallOff1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * CpuOpcodesCallFlags&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * CpuOpcodesRetOff0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * CpuOpcodesRetOff2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * CpuOpcodesRetFlags&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We will take a look at the implementation for &lt;code&gt;BitPrefixFlag0&lt;&#x2F;code&gt; constraint, which we reproduce below:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;impl TransitionConstraint&amp;lt;Stark252PrimeField, Stark252PrimeField&amp;gt; for BitPrefixFlag0 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    fn degree(&amp;amp;self) -&amp;gt; usize {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    fn constraint_idx(&amp;amp;self) -&amp;gt; usize {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    fn evaluate(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;self,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        frame: &amp;amp;stark_platinum_prover::frame::Frame&amp;lt;Stark252PrimeField, Stark252PrimeField&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        transition_evaluations: &amp;amp;mut [Felt252],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        _periodic_values: &amp;amp;[Felt252],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        _rap_challenges: &amp;amp;[Felt252],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let current_step = frame.get_evaluation_step(0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let constraint_idx = self.constraint_idx();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let current_flag = current_step.get_main_evaluation_element(0, constraint_idx);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let one = Felt252::one();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let two = Felt252::from(2);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let bit = current_flag - two * next_flag;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let res = bit * (bit - one);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        transition_evaluations[constraint_idx] = res;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    fn end_exemptions(&amp;amp;self) -&amp;gt; usize {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This constraint shows that the variable corresponding to Flag0 is binary, that is, $b \in {0 , 1}$. Mathematically, this condition is expressed as $b (1 - b) = 0$.&lt;&#x2F;p&gt;
&lt;p&gt;First, we define the degree of the constraint. Since the polynomial defining the constraint $b (1 - b) = 0$ is quadratic, the degree function will return $2$. Next, we define the constraint index or identifier, which has to be between 0 and 63. We choose 0 for this constraint (but we could change it if we want the constraints to be in another order, which is convenient if we have to rearrange the constraints for compatibility). In this case, since the variable has to be binary at every execution step, the &lt;code&gt;end_exemptions&lt;&#x2F;code&gt; is simply 0.&lt;&#x2F;p&gt;
&lt;p&gt;We can now jump to the &lt;code&gt;evaluate&lt;&#x2F;code&gt; function for the constraint. To evaluate the constraint, we need the &lt;code&gt;frame&lt;&#x2F;code&gt; (containing the elements from the LDE of the main and auxiliary traces) and &lt;code&gt;transition_evaluations&lt;&#x2F;code&gt;, which we will modify to add the value corresponding to the constraint. Line 17 gets the evaluation frame for the current step, and with the constraint index, we search for the current and next flags (this is an optimization used in the Stone Prover). We get the bit for the flag in line 27 and compute the constraint expression in line 29 (this should be zero if we evaluate it using the values of a valid trace). Finally, we store the value in &lt;code&gt;transition_evaluations&lt;&#x2F;code&gt; at position &lt;code&gt;constraint_idx&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;In this post, we covered the changes introduced in STARK Platinum to deal with transition constraints and AIR definition. This will help us play more easily with different layouts and avoid having the user define the zerofiers by providing explicit expressions. We covered how zerofiers are defined and how constraint evaluations are carried out. We also think the changes will help test other features, such as using smaller fields in Starknet (though this may need further changes).&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Comparing STARK provers: Miden and Starknet</title>
          <pubDate>Fri, 12 Jan 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/comparing-stark-provers/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/comparing-stark-provers/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/comparing-stark-provers/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;STARKs (scalable transparent arguments of knowledge) have gained widespread attention due to their ability to help scale Ethereum. They allow one party, the prover, to show to a verifier that a given program execution is correct by submitting proof that can be verified much faster than naïve re-execution by the verifier. The proof size is also smaller, of order $\mathcal{O} (\log^2 (n))$, where $n$ is the number of steps in the computation. Starknet and Polygon Miden use STARKs in their protocols to generate these proofs, using their customized versions. Starknet uses the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;tree&#x2F;main&#x2F;src&#x2F;starkware&quot;&gt;Stone Prover&lt;&#x2F;a&gt;, while Miden uses &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;facebook&#x2F;winterfell&#x2F;tree&#x2F;main&#x2F;prover&quot;&gt;Winterfell&lt;&#x2F;a&gt;. Our prover, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;tree&#x2F;main&#x2F;provers&#x2F;stark&quot;&gt;STARK Platinum&lt;&#x2F;a&gt; in lambdaworks, is a general prover that we want to use as a drop-in replacement for any of these provers. If you want to understand how STARKs work, you can see our previous posts on &lt;a href=&quot;&#x2F;lambdaworks-or-how-we-decided-to-created-our-zksnarks-library-and-a-stark-prover&#x2F;&quot;&gt;STARKs&lt;&#x2F;a&gt;, the &lt;a href=&quot;&#x2F;overview-of-the-stone-prover&#x2F;&quot;&gt;Stone prover&lt;&#x2F;a&gt; and &lt;a href=&quot;&#x2F;how-to-code-fri-from-scratch&#x2F;&quot;&gt;FRI&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;general-steps&quot;&gt;General steps&lt;&#x2F;h2&gt;
&lt;p&gt;In a nutshell, STARKs represent a computation using an execution trace (a large table containing the values of the registers during the computation), and an algebraic intermediate representation (AIR), which is a set of polynomial constraints that should be enforced over the trace. STARKs have been improved by leveraging a preprocessing stage and getting randomness from the verifier, turning the AIR into a randomized AIR with preprocessing. This way, we can extend the trace with additional variables that will be useful for memory checks or communicating with a coprocessor. The main steps are:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Interpolate the trace columns to get the trace polynomials.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Commit to the trace polynomials by evaluating over a larger domain (low-degree extension) and using these evaluations as leaves in a Merkle tree.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Optional: sample randomness from the verifier and extend the trace to the auxiliary trace. Interpolate the auxiliary trace columns and commit to these polynomials following the strategy in step 2.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Sample randomness from the verifier and compute the composition polynomial using the AIR constraints and the whole trace. Commit to the composition polynomial.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. Get out-of-domain point $z$ from the verifier, evaluate the trace polynomials and composition polynomial at $z$, and send them to the verifier.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    6. Build the DEEP composition polynomial, which will let us check that the evaluations of the polynomials in point 5 are correct.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    7. Apply the FRI protocol to the DEEP composition polynomial and get the proof.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;checking-constraints&quot;&gt;Checking constraints&lt;&#x2F;h2&gt;
&lt;p&gt;The way we check that the constraints are enforced is as follows: let’s denote the rows of the trace as $x_0, x_1, … x_N$. An element of the trace is simply $x_{ij}$, which is a field element. An AIR constraint is some multivariate polynomial $P(u, v, w)$ where $u$, $v$, and $w$ can be elements from different rows or columns. Each of these constraints also has a validity range. Here there are some examples of constraints:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Simple boundary constraints: these enforce that a given position in the trace $x_{ij}$ has a prescribed value. For example, we want register $2$ in row $0$ to be equal to 5. The constraint polynomial will be $P (x) = x_2 - 5$. If the trace is valid, when we plug $x_0$ into $P$, we will have $x_{02} - 5 = 0$. If we use some other row, then the polynomial would not necessarily evaluate to $0$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Consistency constraints: these enforce that the values of some register satisfy a given condition. For example, if we want register $4$ to be a boolean variable, we need that $x_{k4} (1 - x_{k4} ) = 0$ for all $k$. The constraint polynomial is therefore $P (x) = x_{4} (1 - x_4 )$ and this should hold for all rows.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Simple transition constraints: show that the value for a register in a row is compatible with the values in the previous row, as dictated by the computation. For example, if we have a sequence $x_{0, n + 1} = x_{0,n}^2 + x_{1 n}$, the constraint polynomial is $P(x_{k + 1}, x_k ) = x_{0,k + 1} - x_{0,k}^2 - x_{1,k}$. The constraints hold for all the computation, except in the last row.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * More complex constraints: these can involve more rows, or be applied only at specific points, which makes their description a bit more complicated.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To enforce the constraints, we need to compose the trace polynomials (obtained by interpreting the trace as evaluations of polynomials over some set $D$) with the constraint polynomials, obtaining as many $C_i (x)$ as constraints we have, and dividing each $C_i (x)$ by their corresponding zerofier, $Z_i (x)$, which is a polynomial that is $0$ where the constraint is enforced. Some zerofiers are:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Simple boundary constraint: $Z(x) = x - g^k$, where $g$ spans the domain $D$ ($D = { g^0, g , g^2 ... g^{n - 1}} )$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Consistency constraints: $Z(x) = x^n - 1$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Simple transition constraint: $Z(x) = (x^n - 1)&#x2F;(x - g^{n - 1})$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The efficiency of the STARK prover depends partly on being able to compute these zerofiers in a fast way. If a constraint were to apply in steps $1, 3, 4, 6, 7, 9, 12, 14, … n-1$ with no clear pattern, we would have to spend almost linear time trying to evaluate the polynomial. If one wanted to have the simplest prover, it would be best to work with constraints involving at most two consecutive rows and being either boundary, consistency, or simple transition constraints. This helps us reduce the number of zerofiers we need to calculate and the number of multiplications.&lt;&#x2F;p&gt;
&lt;p&gt;The AIR we use and how we organize the trace is important in terms of performance and usability. High-degree constraints in the AIR are going to make the evaluation of the composition polynomial more expensive. On the other hand, having a rigid organization of the trace (trace layout) adds overhead to the proving of general programs and makes it difficult to make changes to the prover. Miden has been developing &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;0xPolygonMiden&#x2F;air-script&#x2F;&quot;&gt;AIRScript&lt;&#x2F;a&gt;, which is designed to make AIR description and evaluation simple and performant. In Lambdaworks, we are also working to make the definition of AIRs and the evaluation of constraints simpler, leading to faster provers and easier maintenance or updates.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;different-algebraic-intermediate-representations&quot;&gt;Different Algebraic Intermediate Representations&lt;&#x2F;h2&gt;
&lt;p&gt;The AIR for the Miden vm is contained &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;0xPolygonMiden&#x2F;miden-vm&#x2F;tree&#x2F;main&#x2F;air&quot;&gt;here&lt;&#x2F;a&gt;. The Stone prover’s AIR is dependent on the type of layout; the generalities of the AIR are &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;tree&#x2F;main&#x2F;src&#x2F;starkware&#x2F;air&quot;&gt;here&lt;&#x2F;a&gt;. This is a list of the different layouts in Starknet:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Plain&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Small&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Dex&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Recursive&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Starknet&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * StarknetWithKeccak&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * RecursiveLargeOutput&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * AllCairo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * AllSolidity&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Dynamic&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here we show the diagram of a single step of the main trace for the plain layout in Starknet, without the auxiliary trace (for more information, see &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;blob&#x2F;main&#x2F;docs&#x2F;src&#x2F;starks&#x2F;stone_prover&#x2F;trace_plain_layout.md&quot;&gt;our analysis&lt;&#x2F;a&gt;):&lt;br &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;ry0W20A_T.png&quot; alt=&quot;main_trace&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The Stone Prover packs several registers in a single column, creating virtual columns. For example, all 16 flags are grouped under one column. The memory’s addresses and values are also grouped in an interleaved way in another column. This reduces the amount of columns in the trace (we merge $16$ columns in $1$), but the trace length becomes $16$ times larger. When we want to find the trace polynomials, we perform one Fast Fourier Transform (FFT) of size $16n$, instead of $16$ FFT of size $n$.&lt;&#x2F;p&gt;
&lt;p&gt;Using virtual columns can be useful if some of the registers are updated only a few times, since we will still have to pad them to full length, reducing memory use in the trace. However, this comes with a big disadvantage: we have to keep different zerofiers and the evaluation frames (which we use to compute constraints efficiently) become more complex. Let’s see the difference between both approaches:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;16-columns&quot;&gt;16 columns&lt;&#x2F;h3&gt;
&lt;p&gt;To evaluate each of the constraints, we need to take just the elements of one row. The trace has length $n$, so the zerofier is $Z (x) = x^n - 1$. 15 flags have the constraint $x (1 - x) = 0$, while the last one has $x = 0$.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;single-virtual-column&quot;&gt;Single virtual column&lt;&#x2F;h3&gt;
&lt;p&gt;To evaluate each constraint, we need to take just one element from the row. The problem is that the constraint $x (1 - x)$ is valid for all rows, except every $16$-th row, while constraint $x = 0$ is valid only for every $16$ rows. This way, we have to maintain two zerofiers, one for each constraint:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $Z (x) = (x^{16n} - 1) &#x2F; (x^n - g^{15n&#x2F;16})$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $Z (x) = x^n - g^{15n&#x2F;16}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The other problem is that, if a constraint involves several flags, we need to pass several rows to be able to evaluate it. It is worth noting that $g$ in this case is different from the previous case, as the interpolation now takes place over a domain of size $16n$.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;built-ins-and-chiplets&quot;&gt;Built-ins and chiplets&lt;&#x2F;h2&gt;
&lt;p&gt;Having a general-purpose CPU for proving comes with a cost: the virtual machine is not optimized for some commonly used operations. To deal with this, the Cairo vm (Starknet) and Miden vm introduce coprocessors to deal with these operations and then communicate the results to the CPU.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;chiplets-and-the-miden-vm&quot;&gt;Chiplets and the Miden vm&lt;&#x2F;h3&gt;
&lt;p&gt;Miden uses dedicated components to accelerate complex computations, called &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.polygon.technology&#x2F;miden&#x2F;vm&#x2F;architecture&#x2F;chiplets&#x2F;&quot;&gt;chiplets&lt;&#x2F;a&gt;. Each chiplet handles a unique computation and is responsible for proving the correctness of the computation and its internal consistency. Currently supported chiplets are:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Hash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Bitwise&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Memory&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Kernel ROM&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Range checker (it works as a chiplet, but it is handled separately)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The chiplets execution trace is built by stacking the execution traces of each of the chiplets. This is an optimization since each chiplet is likely to generate fewer cells than other components of the vm, avoiding significant padding to take them to the same length and reducing the number of columns. It uses a similar reasoning to virtual columns in Stone, but it does not interleave them.&lt;&#x2F;p&gt;
&lt;p&gt;Chiplets are identified by selectors. The total degree of the constraints is between $5$ and $9$ and each chiplet takes between 6 and 17 columns. The selectors are:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $1$: hash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $1,0$: bitwise&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $1,1,0$: Memory&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $1,1,1,0$: Kernel ROM&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $1,1,1,1$: padding&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Stacking the traces of the chiplets has some difficulties, though, since the consistency and transition constraints in the last row of one chiplet may conflict with the first row of the next chiplet. This is the case of the memory and kernel ROM chiplets, where selector flags solve the conflicts.&lt;&#x2F;p&gt;
&lt;p&gt;The chiplets are connected to the rest of the VM using a bus, which can send requests to any of the chiplets and receive a response. It is implemented as a running product column and, if the requests and responses match, the bus will begin and end with $1$.&lt;&#x2F;p&gt;
&lt;p&gt;One of the main drawbacks of this approach is that the constraints have a rather large degree, which makes constraint evaluation more expensive. On the other hand, the construction does not require handling several zerofiers and looks simpler to implement and understand.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;built-ins-and-cairo-vm&quot;&gt;Built-ins and Cairo vm&lt;&#x2F;h3&gt;
&lt;p&gt;Built-ins are application-specific AIRs that can reduce the size of the execution trace of a given computation. For example, expressing the Poseidon hash function using Cairo needs 35k cells in the trace, while the Poseidon built-in reduces this to roughly 600-650 cells. Among the built-ins, we have:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Poseidon&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Pedersen&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Elliptic curve operation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Keccak&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Bitwise&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * ECDSA&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Range check&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The integration of the built-ins needs some care, though, as naïve ways may result in wasting cells, reducing the efficiency of the construction. Layouts specify the amount of cells and positions that are allocated to each component. Depending on the type of program we want to prove, we can select from the different layouts offered in Starknet to achieve the most cost-effective solution. However, it may be the case that the existing layouts provide significant overhead to prove our program, as noted in the discussion of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;starkware.co&#x2F;resource&#x2F;builtins-and-dynamic-layouts&#x2F;&quot;&gt;dynamic layouts&lt;&#x2F;a&gt;. Adding new layouts needs expert knowledge and careful analysis; it may also be confusing to users, who need to understand the differences between the layouts.&lt;&#x2F;p&gt;
&lt;p&gt;Each built-in has a memory segment. To check that there is no overflow from the memory segment, there are two pointers (start and stop) that are exported via the public memory mechanism. Since the constraints for each built-in apply every several rows, we are forced to compute different zerofiers and handle more complex evaluation frames.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;In this post, we discussed the characteristics of STARK provers and some implementation trade-offs. We analyzed how the Miden and Cairo VMs handle their execution traces and the description of the AIR. We also discussed the main types of constraints and the way to enforce them over the execution trace. The use of virtual columns (grouping several registers in one column) reduces the number of FFTs we have to perform, but it comes at the expense of more complex evaluation frames and keeping several zerofiers. However, this strategy is necessary when several components have fewer trace cells and padding is necessary. Miden uses this type of strategy when dealing with chiplets, but it chooses to stack the traces instead of interleaving them. This introduces several selector variables, which increase the degree of the constraints, adding an extra cost to constraint evaluation. On the other hand, evaluation frames are simpler and we do not have to compute several zerofiers. The use of layouts could lead to a more cost-effective solution, though at the expense of a larger overhead to prove some types of programs. Besides, adding more layouts increases complexity and makes things harder to maintain. We like analyzing the different solutions and their trade-offs, as they could lead to new designs that can help us improve general-purpose provers.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Sparkling Water Bootcamp on Cryptography in a nutshell</title>
          <pubDate>Thu, 11 Jan 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/sparkling-water-bootcamp/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/sparkling-water-bootcamp/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/sparkling-water-bootcamp/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;16 weeks ago, we started the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;blob&#x2F;main&#x2F;bootcamp&#x2F;README.md&quot;&gt;Sparkling Water Bootcamp&lt;&#x2F;a&gt; to teach cryptography and zero-knowledge proofs to a group of engineers and students from around the world, focusing on applications and coding. We started with a team of 21 people, with backgrounds in Computer Science, Physics, Mathematics, Engineering, and Architecture, among others. Our bootcampers came from several countries: India, Turkey, USA, Nigeria, Brazil, Venezuela, Ecuador, Paraguay, Cuba, France, Serbia, and Costa Rica. Given the different backgrounds and time zones, it has been a challenging experience (since it involves coordination, logistics, and adopting the best strategies to teach concepts to people with different learning styles and objectives) but we greatly enjoyed it and it taught us many things while making new friends and acquaintances. If you want to know more or keep with the latest developments, join our &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;t.me&#x2F;lambdaworks&quot;&gt;telegram channel&lt;&#x2F;a&gt; or see the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&quot;&gt;Lambdaworks repo&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The contents of the bootcamp included finite field arithmetics, elliptic curves, polynomials, SNARKs, STARKs, symmetric encryption, public key cryptography, signatures, as well as an intro to Fully Homomorphic Encryption (FHE). We also discussed new papers, including &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2023&#x2F;1784&quot;&gt;Succinct Arguments over Towers of Binary Fields&lt;&#x2F;a&gt;. We hosted several lectures, discussion sessions, workshops, and guest lectures.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;guest-lectures-and-workshops&quot;&gt;Guest Lectures and workshops&lt;&#x2F;h2&gt;
&lt;p&gt;We had the opportunity to invite several speakers from different projects to talk about their work and discuss topics in cryptography. We were lucky to have Immanuel Segol from Ingonyama, Robert Remen from MatterLabs&#x2F;ZKSync, and Alan Szepieniec from Neptune.&lt;&#x2F;p&gt;
&lt;p&gt;We also had workshops taught by engineers at LambdaClass, on Rust (Pablo Deymonnaz), and Cairo Native (Iñaki Garay). You can have a look at all the talks and workshops on the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;playlist?list=PLFX2cij7c2Pwm2XHBijKZ6Eh97BOqtGBh&quot;&gt;YouTube channel&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;exercises&quot;&gt;Exercises&lt;&#x2F;h2&gt;
&lt;p&gt;During the first weeks, we had some practice exercises and challenges, such as naïve implementations of RSA, elliptic curve cryptography, and Shamir secret sharing. Some of the exercises and answers are contained in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;tree&#x2F;main&#x2F;bootcamp&quot;&gt;Sparkling Water Bootcamp readme&lt;&#x2F;a&gt;. We also reviewed some challenges from the &lt;a href=&quot;&#x2F;first-lambda-ingo-zk-ctf-zk-challenges-using-lambdaworks&#x2F;&quot;&gt;Lambda&#x2F;Ingo ZK CTF&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;coding-new-features-in-lambdaworks&quot;&gt;Coding - new features in Lambdaworks&lt;&#x2F;h2&gt;
&lt;p&gt;We were able to put everything we learned into practice by adding new features and proof systems to Lambdaworks. We want to thank our bootcampers for all the hard work they have done during these weeks. Among the additions, we have:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Groth 16 backend, [PR-612](https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;612).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Arkworks adapter for Groth 16, [PR-701](https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;701)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Added Starknet curve, and Pedersen hash, [PR-597](https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;597)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Changing Serialization by AsBytes, [PR-747](https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;747).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. Affine serialization for elliptic curve points, [PR-687](https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;687)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    6. Pasta curves, [PR-690](https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;690), [PR-698](https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;698), and [PR-714](https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;714).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    7. Specific backend for the 31-bit Mersenne prime, [PR-669](https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;669)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    8. Fuzzer for the BLS12-381 elliptic curve, [PR-664](https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;664)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    9. Subgroup checks for BLS12-381 elliptic curve using Frobenius endomorphism, [PR-649](https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;649)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    10. New CLI command to be able to prove traces using STARK Platinum, [PR-634](https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;634)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    11. Adding support for BabyBear field, [PR-549](https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;549), [PR-576](https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;576), [PR-629](https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;629)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    12. Specialized backend for Mini-Goldilocks field ($2^{64} - 2^{32} + 1$), [PR-622](https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;622)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    13. Refactor the field benchmarks, [PR-606](h%5Bttps:&#x2F;&#x2F;%5D\(https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;606\))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    14. Bug fixes, [PR-575](https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;575)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    15. Adding Ed448 elliptic curve, [PR-546](https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;546), [PR-557](https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;557)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    16. Proptest for unsigned integers, [PR-526](https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;526)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There is still ongoing work on multivariate polynomials (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;726&quot;&gt;PR-726&lt;&#x2F;a&gt;, the Sumcheck Protocol (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;739&quot;&gt;PR-739&lt;&#x2F;a&gt;), inner product arguments (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;743&quot;&gt;PR-743&lt;&#x2F;a&gt;), adding BN254 elliptic curve (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;646&quot;&gt;PR-646&lt;&#x2F;a&gt;) and an adapter for Circom (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;752&quot;&gt;PR-752&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;hacking-in-buenos-aires-and-visiting-friends-abroad&quot;&gt;Hacking in Buenos Aires and visiting friends abroad&lt;&#x2F;h2&gt;
&lt;p&gt;During the first weeks of December, we hosted an event and hacking house in Buenos Aires, where we received many engineers, researchers, and friends. It was a great opportunity to meet in person, discuss on cryptography, distributed systems, and engineering, and have a good time. We also had the opportunity to visit several landmarks in the city and outskirts, enjoy asados and dinners, as well as a short trip to the city of Bariloche.&lt;&#x2F;p&gt;
&lt;p&gt;We also met with many bootcampers in several events we participated, such as DevConnect at Istanbul or ZK Summit.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;&#x2F;h2&gt;
&lt;p&gt;We have greatly enjoyed the whole experience and are grateful to our bootcampers for their commitment and hard work. We have learned a lot from them and the experience, and this will help us improve our hacking learning path to cryptography and zero-knowledge proofs. We will take more time to analyze the whole experience and we will be releasing new blog posts on different proof systems and how to use the different tools and features in Lambdaworks.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>SNARKs on binary fields: Binius - Part 2</title>
          <pubDate>Fri, 05 Jan 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/binius-part-2/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/binius-part-2/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/binius-part-2/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;This post is a continuation of our discussion on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gitlab.com&#x2F;UlvetannaOSS&#x2F;binius&quot;&gt;Binius&lt;&#x2F;a&gt;, a new proof system that works over binary fields. Before continuing, see the &lt;a href=&quot;&#x2F;snarks-on-binary-fields-binius&#x2F;&quot;&gt;first part&lt;&#x2F;a&gt; if you are unfamiliar with some of the concepts or &lt;a href=&quot;&#x2F;binius-moving-zk-forward&#x2F;&quot;&gt;our post&lt;&#x2F;a&gt; on why we think this proof system can help move the industry forward.&lt;&#x2F;p&gt;
&lt;p&gt;In this part, we will focus on the concatenated codes (which will allow us to extend the polynomial commitment scheme for small fields) and the different protocols to check statements over multivariate polynomials.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;concatenated-codes&quot;&gt;Concatenated Codes&lt;&#x2F;h2&gt;
&lt;p&gt;In our previous post, we covered the polynomial commitment scheme for small fields. To develop the general commitment scheme, we first need to introduce the packing scheme and concatenated codes. Remember that in this setting we are working with a tower of fields, $\tau_0 \subset \tau_1 \subset \dots \subset \tau_t$. We work with a $[n_0 , k_0 , d_0]$ linear outer code with a $[n_i , k_i , d_i]$ linear inner code. The outer code works over $\tau_{i + k}$, while the inner code works over $\tau_i$.&lt;&#x2F;p&gt;
&lt;p&gt;The whole construction depends on packing several elements from a field, and interpreting them as elements from an extension field. We can view $2^k$ elements from $\tau_i$ as a single element from $\tau_{i + k}$ (we can view it as a $\tau_i$ vector space, as we can see the complex numbers as a two dimensional vector space over the real numbers).&lt;&#x2F;p&gt;
&lt;p&gt;The concatenated code’s encoding procedure works as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Pack the initial message over $\tau_i$ into elements of $\tau_{i+k}$. For example, we have four bit variables from $\tau_0$, $0, 1, 1, 1$ and we can group then as an element $0111$ from $\tau_2$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Encode the packed message using the outer code. For example, we can use Reed-Solomon encoding.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Unpack each symbol in the codeword into a message over $\tau_i$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Encode using the inner code and concatenate the elements. This encoding may be the trivial one, that is, applying the identity code.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;One problem we face is that we have to use the extension code. We have an interplay between different fields: the field representing the coefficients of the polynomial, the field for the alphabet of the code, the intermediate field and the extension field which we use for cryptographic security (here, $\tau_t$). To work with the extension code, we define a structure containing elements from $\tau_i$ in a rectangular array (of $2^{\tau - i} \times 2^k$ elements). Each row contains $2^k$ elements, which can be interpreted as a $\tau_{i + k}$ element. Analogously, the $2^{\tau - i}$ elements in a column can be interpreted as a single element in $\tau_t$. The structure has a dual view: as a vector space over $\tau_t$ of dimension $2^k$ (viewing the columns) or as a vector space over $\tau_{i + k}$ of dimension $2^{t - i}$. Multiplication of the array by an element from $\tau_i$ is interpreted as multiplication elementwise. If we want to multiply by an element over $\tau_t$, we take each column (which is a single element from $\tau_t$) and perform the multiplication of each column by the element. In an analogous way, we can multiply by an element in $\tau_{i + k}$ by multiplying each row.&lt;&#x2F;p&gt;
&lt;p&gt;The block level encoding-based polynomial commitment scheme’s procedure is:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Commit($p$): Arrange the coefficients of the polynomial into an $m_0 \times m_1$ matrix, with entries in $\tau_i$. Group the elements taking chunks of $2^\kappa$ and interpret them as elements in $\tau_{i + k}$ and apply the extended encoding row-wise, obtaining a matrix of size $m_0 \times n$ with elements over $\tau_\tau$. Build a Merkle tree from the columns and output the root as commitment.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Prove($p$,$s$): The prover arranges the coefficients into an $m_0 \times m_1$ matrix $t$ with entries in $\tau_i$. He computes and sends in the clear $t^\prime = \otimes_{ i = l_1 }^\ell (1 - r_i , r_i ) . T$ to the verifier. The verifier samples $\rho$ indexes $j_0 , j_1 , ... j_{\rho - 1}$. The prover sends the columns of the encoded matrix $U$ with their accompanying Merkle paths.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Verify($\pi , r , s$): The verifier checks that $t^\prime \otimes_{ i = 0}^{l_1} .(1 - r_i , r_i ) = s$. Then, the verifier interprets $t^\prime$ as chunks of size $2^k$ and applies the extended code, unpacking all the elements to get $u^\prime$. The verifier checks that all the columns supplied are included in the Merkle tree, and checks that $\otimes_{ i = l_1 }^\ell ( 1 - r_i , r_i ).u$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The size of the proof can be calculated from $t^\prime$ ($m_1$ elements from $\tau_t$), the columns (consisting of $\rho m_0$ elements from $\tau_{i + k}$) plus the authentication paths for the $\rho$ columns. Assuming a digest size of $256$ bits, we have $2^\tau m_1 + 2^{i + k} \rho m_0 + 2^8 \rho \log_2 {n}$ bits.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;protocols&quot;&gt;Protocols&lt;&#x2F;h2&gt;
&lt;p&gt;Binius contains a list of key polynomial predicates, based on those proposed by &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2022&#x2F;1355.pdf&quot;&gt;HyperPlonk&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Query&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Sum&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Zero&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Product&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. Multiset&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    6. Permutation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    7. LookUp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Almost all of the protocols boil down to a sumcheck. For the basics of the sumcheck protocol, see our &lt;a href=&quot;&#x2F;have-you-checked-your-sums&#x2F;&quot;&gt;previous post&lt;&#x2F;a&gt; or &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;people.cs.georgetown.edu&#x2F;jthaler&#x2F;ProofsArgsAndZK.pdf&quot;&gt;Thaler’s book&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The zerocheck protocol is useful, for example, to prove that the gate constraints are enforced in HyperPlonk. In that protocol, we have a multilinear polynomial $M$ (which encodes the trace) and selector multilinear polynomials $S_1$, $S_2$, $S_3$, such that, for every point in ${0, 1 }^n$, we have&lt;br &#x2F;&gt;
$0 = S_1 (M_0 + M_1 ) + S_2 M_0 M_1 + S_3 G(M_0 ,M_1 ) - M_2 + I$&lt;br &#x2F;&gt;
where $M_0 (x) = M(0,0,x)$, $M_1 (x) = M(0,1,x)$, and $M_2 (x) = M(1,0,x)$.&lt;&#x2F;p&gt;
&lt;p&gt;How can we prove that the multivariate polynomial, $P = S_1 (M_0 + M_1 ) + S_2 M_0 M_1 + S_3 G(M_0 ,M_1 ) - M_2 + I$ is equal to zero for every value in ${0, 1 }^n$ ? We let the verifier supply a random point $r_{zc}$ from $\mathbb{F}^n$ and build the multivariate polynomial&lt;br &#x2F;&gt;
$P^\prime (x) = eq(r_{zc} , x) P(x)$&lt;br &#x2F;&gt;
with $eq(x,y) = \prod ( x_i y_i + (1 - x_i ) (1 - y_i ))$ and we run the sumcheck protocol for $P^\prime (x)$, using as sum value $0$. The verifier will only need to do one evaluation of $P^\prime (x)$ at $x = r_{s}$.&lt;&#x2F;p&gt;
&lt;p&gt;The use of the sumcheck with $P^\prime (x)$ involves multivariate polynomials which are not multilinear; this means that the prover has to send at each round a polynomial of at most degree $d$. HyperPlonk has an optimization for this case: the prover sends a commitment to a univariate polynomial of degree at most $d$ and provides an evaluation at a single point (instead of at least 3 points).&lt;&#x2F;p&gt;
&lt;p&gt;Since most of the protocols end up in a sumcheck, we can batch the polynomials using a random linear combination and reduce all the checks to a single sumcheck. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gitlab.com&#x2F;UlvetannaOSS&#x2F;binius&#x2F;-&#x2F;tree&#x2F;main?ref_type=heads&quot;&gt;Binius’s repo&lt;&#x2F;a&gt; contains the implementation of the zero, sum and evaluation checks.&lt;&#x2F;p&gt;
&lt;p&gt;Binius proposes the use of Plonkish arithmetization; the main difference with HyperPlonk lies in the fact that the trace contains elements belonging to different subfields. Therefore, the gate constraints will express relations over different subfields. An execution is valid if&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. All gate constraints hold.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. All global copy constraints are satisfied.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Every witness variable lies inside its prescribed subfield.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The first two conditions hold for any of the variants of Plonk; the last one is introduced because we work with extension towers.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;&#x2F;h2&gt;
&lt;p&gt;In this post, we covered how the commitment scheme developed in the first part is extended to work with packed fields. We can view arrays of field elements in a dual way, packing the elements column or row-wise. The paper later presents some key protocols to prove predicates over polynomials, such as evaluation, sum and product check; these boil down to doing several sumchecks, which can be batched conveniently. These, together with some arithmetization scheme (such as Plonkish) can be used to yield a SNARK. Tha main difference between HyperPlonk and Binius lies in the fact that the trace elements in Binius may belong to different subfields. However, this does not add a new check. Rather, this could replace what could be additional checks in HyperPlonk. These subfield checks are guaranteed by the security property of the small-field polynomial commitment scheme.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Lambdaworks Design and Usage: Part 1 - Finite Fields</title>
          <pubDate>Tue, 02 Jan 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/lambdaworks-design-and-usage-part-1-finite-fields/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/lambdaworks-design-and-usage-part-1-finite-fields/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/lambdaworks-design-and-usage-part-1-finite-fields/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;In this series of blog posts, we will see how Lambdaworks is implemented and the standard tools needed to develop provers. This first part will briefly overview the library and then focus on the finite field design and usage.&lt;&#x2F;p&gt;
&lt;p&gt;Lambdaworks at its core is a library to create proving systems, and a collection of associated provers and verifiers ready to use. In this blog post, we will explore the building blocks of the proving systems and the Lambdaworks library.&lt;&#x2F;p&gt;
&lt;p&gt;The most relevant sections of the library are:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Math&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Crypto&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Provers&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Provers has a collection of proof systems. Crypto contains some primitives like MSM, hashes, and Merkle trees. Math has logic related to finite fields and elliptic curves.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;math&quot;&gt;Math&lt;&#x2F;h2&gt;
&lt;p&gt;At the core of the Math library are finite fields, the main building block of all the constructions we use in Lambdaworks.&lt;&#x2F;p&gt;
&lt;p&gt;The basic structure is designed under a relationship between a &lt;code&gt;Field&lt;&#x2F;code&gt; and its &lt;code&gt;FieldElement&lt;&#x2F;code&gt;. Let’s see how it works.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;field-and-elements-main-ideas&quot;&gt;Field and Elements: Main Ideas&lt;&#x2F;h3&gt;
&lt;p&gt;A &lt;code&gt;Field&lt;&#x2F;code&gt; is an abstract definition. It knows the modulus and defines how the operations are performed.&lt;&#x2F;p&gt;
&lt;p&gt;We usually create a new &lt;code&gt;Field&lt;&#x2F;code&gt; by instantiating an optimized backend. For example, this is the definition of the Pallas field:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; 4 is the number of 64-bit limbs needed to represent the field&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;type PallasMontgomeryBackendPrimeField&amp;lt;T&amp;gt; = MontgomeryBackendPrimeField&amp;lt;T, 4&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#[derive(Debug, Clone, PartialEq, Eq)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub struct MontgomeryConfigPallas255PrimeField;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;impl IsModulus&amp;lt;U256&amp;gt; for MontgomeryConfigPallas255PrimeField {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    const MODULUS: U256 = U256::from_hex_unchecked(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;quot;40000000000000000000000000000000224698fc094cf91b992d30ed00000001&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub type Pallas255PrimeField =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    PallasMontgomeryBackendPrimeField&amp;lt;MontgomeryConfigPallas255PrimeField&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As it can be seen, it is enough to define its modulus and instantiate it over a &lt;code&gt;PallasMontgomeryBackendPrimeField&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Internally, it resolves all the constants needed and creates all the required operations for the field. Notice that there are no macros involved. This holds for all the Lambdaworks code.&lt;&#x2F;p&gt;
&lt;p&gt;Generics and traits are the only tools used to have genericity. This makes the job easier for the compiler to suggest possible functions to be called and makes the code easier to understand. Moreover, minimal traits are used to make the code easier to understand.&lt;&#x2F;p&gt;
&lt;p&gt;Back to the fields, you will notice that other backends can be more efficient for some fields. For example, Mersenne31 and Goldilocks are defined over their backend.&lt;&#x2F;p&gt;
&lt;p&gt;Back to the usage, suppose we want to create a &lt;code&gt;FieldElement&lt;&#x2F;code&gt;. This is as easy as instantiating the &lt;code&gt;FieldElement&lt;&#x2F;code&gt; over a &lt;code&gt;Field&lt;&#x2F;code&gt; and calling a &lt;code&gt;from_hex&lt;&#x2F;code&gt; function.&lt;&#x2F;p&gt;
&lt;p&gt;For example:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let an_element = FieldElement::&amp;lt;Stark252PrimeField&amp;gt;::from_hex_unchecked(&amp;quot;030e480bed5fe53fa909cc0f8c4d99b8f9f2c016be4c41e13a4848797979c662&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Notice we can alias the &lt;code&gt;FieldElement&lt;&#x2F;code&gt; to something like&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;type FE = FieldElement::&amp;lt;Stark252PrimeField&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;if we want to shorten the code and do not care about being explicit with the field.&lt;&#x2F;p&gt;
&lt;p&gt;Once we have a field, we can make all the operations. We usually suggest working with references, but copies work too.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let field_a = FE::from_hex(&amp;quot;3&amp;quot;).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let field_b = FE::from_hex(&amp;quot;7&amp;quot;).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; We can use pointers to avoid copying the values internally&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let operation_result = &amp;amp;field_a * &amp;amp;field_b&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; But all the combinations of pointers and values works&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let operation_result = field_a * field_b&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Sometimes, optimized operations are preferred. For example,&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; We can make a square multiplying two numbers&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let squared = field_a * field_a;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Using exponentiation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let squared = &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;field_a.pow(FE::from_hex(&amp;quot;2&amp;quot;).unwrap())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Or using an optimized function&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let squared = field_a.square()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;all compute the square of a number, but performance-wise, there is quite a big difference.&lt;&#x2F;p&gt;
&lt;p&gt;Some useful instantiation methods are also provided for common constants and whenever const functions can be called. This is when creating functions that do not rely on the &lt;code&gt;IsField&lt;&#x2F;code&gt; trait since Rust does not support const functions in traits yet,&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Defined for all field elements&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Efficient, but nonconst for the compiler&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let zero = FE::zero() &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let one = FE::one()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Const alternatives of the functions are provided, &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; But the backend needs to be known at compile time. &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; This requires adding a where clause to the function&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let zero = F::ZERO&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let one = F::ONE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let const_intstantiated = FE::from_hex_unchecked(&amp;quot;A1B2C3&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For many use cases, we can treat these fields as a &lt;code&gt;PrimeField&lt;&#x2F;code&gt; instead of treating them as a &lt;code&gt;Field&lt;&#x2F;code&gt;. If the word &lt;code&gt;FieldExtension&lt;&#x2F;code&gt; is irrelevant, &lt;code&gt;PrimeField&lt;&#x2F;code&gt; is the right choice.&lt;&#x2F;p&gt;
&lt;p&gt;You will notice traits are followed by an &lt;code&gt;Is&lt;&#x2F;code&gt;, so instead of accepting something of the form &lt;code&gt;IsField&lt;&#x2F;code&gt;, you can use &lt;code&gt;IsPrimeField&lt;&#x2F;code&gt; and access more functions. The most relevant is &lt;code&gt;.representative()&lt;&#x2F;code&gt;. This function returns a canonical representation of the element as a number, not a field.&lt;&#x2F;p&gt;
&lt;p&gt;If the internal number is in Montgomery form, this function will reverse it.&lt;&#x2F;p&gt;
&lt;p&gt;This allows us to make comparisons where it makes sense. Since fields work like circular lists of elements, order doesn’t make much sense.&lt;&#x2F;p&gt;
&lt;p&gt;If we are in $\mathbb{F_3}$, for example, $4$ may look bigger than $2$, but $4$ is also $1$, and $1$ seems smaller than $2$. The question of “which element is bigger” doesn’t make much sense. This gets even messier if we interpret some numbers as negatives as other libraries.&lt;&#x2F;p&gt;
&lt;p&gt;For this reason, comparisons are only allowed when we interpret the &lt;code&gt;FieldElement&lt;&#x2F;code&gt; as a number through the &lt;code&gt;representative()&lt;&#x2F;code&gt; function.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;field-and-elements-serialization-and-deserialization&quot;&gt;Field and Elements: Serialization and Deserialization&lt;&#x2F;h3&gt;
&lt;p&gt;For serialization, we recommend using Serde with bincode. This has given the best results all around while maintaining good usability. By default, the serialization is done in the most compact mode possible and is not human-readable.&lt;&#x2F;p&gt;
&lt;p&gt;To enable a human-readable serialization, where fields are written as strings, the feature &lt;code&gt;lambdaworks-serde-string&lt;&#x2F;code&gt; can be enabled.&lt;&#x2F;p&gt;
&lt;p&gt;Serde is available at all levels of the library. So, if you have a FieldElements struct, you can simply derive a serialization.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;FieldElements&lt;&#x2F;code&gt; also have different algorithms to transform into bytes in the &lt;code&gt;ByteConversion&lt;&#x2F;code&gt; trait. This is a &lt;code&gt;from_bytes_le&lt;&#x2F;code&gt;, &lt;code&gt;from_bytes_be&lt;&#x2F;code&gt;, &lt;code&gt;to_bytes_le&lt;&#x2F;code&gt; and &lt;code&gt;to_bytes_be&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;These smaller conversions to bytes are helpful when doing small tasks like appending data to a transcript but can become cumbersome when you have to serialize complex structures.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;field-and-elements-advanced-usage-extensions-and-internals-deep-dive&quot;&gt;Field and Elements: Advanced usage, Extensions, and Internals deep dive&lt;&#x2F;h3&gt;
&lt;p&gt;Field extensions are used in two scenarios requiring slightly different properties: pairing computations and working with small fields with proof systems.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;pairings&quot;&gt;Pairings&lt;&#x2F;h4&gt;
&lt;p&gt;When doing pairings, a degree $12$ extension is commonly used. This extension is usually created with a tower of extensions, where we make a degree $2$ extension of a degree $2$ extension of a degree $3$ extension. This is a non-naïve of making a degree $12$ extension.&lt;&#x2F;p&gt;
&lt;p&gt;For example, we can see on the code:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub type Degree12ExtensionField = QuadraticExtensionField&amp;lt;Degree6ExtensionField, LevelThreeResidue&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub type Degree6ExtensionField = CubicExtensionField&amp;lt;Degree2ExtensionField, LevelTwoResidue&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Using quadratic and cubic extensions, we are building the tower of fields. The key design for this to work is in the internal structure of the &lt;code&gt;IsField&lt;&#x2F;code&gt;. A field internally has a &lt;code&gt;BaseType&lt;&#x2F;code&gt; that, in practice, can either be a BigInteger, which we call &lt;code&gt;UnsignedInteger&lt;&#x2F;code&gt; to enable multiple backends of BigInts, or another &lt;code&gt;FieldElement.&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This works nicely for this scenario, but there is another to handle.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;working-with-smaller-fields&quot;&gt;Working with smaller fields&lt;&#x2F;h4&gt;
&lt;p&gt;When working with proving systems that use small fields, like it could be a Stark with a 32-bit BabyBear, we need an extension to avoid security being broken. This is because we need to sample a random challenge from a much larger set than the degree of the polynomials involved. We will also use an extension to sample random challenges from a bigger set in this case.&lt;&#x2F;p&gt;
&lt;p&gt;But this time, the critical issue is that we will be doing a lot of operations between the field and its subfield. These operations can be solved more efficiently than just doing them naïvely. Think of it as multiplying a complex number for a real one when needed instead of constantly multiplying complex numbers even when the imaginary part is 0.&lt;&#x2F;p&gt;
&lt;p&gt;We define each &lt;code&gt;Field&lt;&#x2F;code&gt; as a &lt;code&gt;SubField&lt;&#x2F;code&gt; of another &lt;code&gt;Field&lt;&#x2F;code&gt; to solve this issue. For an unextended field, we define it as a subfield of itself, which is a true statement that you will not notice. When working with an extension, two sets of operations are defined—one for the field and one for the field against its subfield.&lt;&#x2F;p&gt;
&lt;p&gt;The resolution of which operation to use is done with the type system, and so these optimizations are invisible when using the library. When using an operator, Lambdaworks picks the correct operation by itself.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;Finite Fields are at the core of many proving systems, and having optimized backends is necessary for performance. Lambdaworks has developed its own backend, emphasizing performance and usability. The library also has other features, such as cryptographic primitives and different proof systems. In future blog posts, we will cover these parts, show how to use them, and explain some of the design decisions and the advantages that they may offer.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Lambdaworks as a drop-in replacement for Winterfell to prove the Miden-VM</title>
          <pubDate>Wed, 27 Dec 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/lambdaworks-as-a-drop-in-replacement-for-winterfell/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/lambdaworks-as-a-drop-in-replacement-for-winterfell/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/lambdaworks-as-a-drop-in-replacement-for-winterfell/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&quot;&gt;Lambdaworks&lt;&#x2F;a&gt; is our library for finite fields, elliptic curves, and proof systems. Among them, we have a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;tree&#x2F;main&#x2F;provers&#x2F;stark&quot;&gt;STARK&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;tree&#x2F;main&#x2F;provers&#x2F;plonk&quot;&gt;Plonk&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;tree&#x2F;main&#x2F;provers&#x2F;groth16&quot;&gt;Groth 16&lt;&#x2F;a&gt; provers and we are on the way to having a fully compatible &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;tree&#x2F;main&#x2F;provers&#x2F;cairo&quot;&gt;Cairo prover using STARKs&lt;&#x2F;a&gt;. We want to continue adding new proof systems and polynomial commitment schemes so that users have a library suited to their particular needs and where experimentation is easy.&lt;&#x2F;p&gt;
&lt;p&gt;During the last months, we have been working towards compatibility with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;facebook&#x2F;winterfell&#x2F;tree&#x2F;main&quot;&gt;Winterfell&lt;&#x2F;a&gt;, a popular general-purpose STARK prover. Polygon uses Winterfell to prove the execution of the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;0xPolygonMiden&#x2F;miden-vm&quot;&gt;Miden-VM&lt;&#x2F;a&gt;, which is a ZK-friendly VM to enable features and benefits that EVM-based L1s and L2s do not currently offer.&lt;&#x2F;p&gt;
&lt;p&gt;Even though the main components are the same, such as execution trace, auxiliary trace, using Merkle trees for commitments, and the FRI protocol, there are some parts where it was not straightforward to use Lambdaworks as a drop-in replacement for Winterfell. One obstacle is related to the field backend. Miden was designed to work over the prime $2^{64} - 2^{32} + 1$ (known by some as Mini-Goldilocks) and has to deal with extension fields to achieve cryptographic security, whereas our STARK prover worked with a 252-bit field. In this first part, we focused purely on compatibility and left behind optimizations that we could add to improve the performance.&lt;&#x2F;p&gt;
&lt;p&gt;In this post, we will cover the major work we have been doing toward compatibility with Winterfell so that you can replace it in your project if needed. This adds redundancy and robustness since we have different provers with different design choices and can help detect bugs.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;fields-and-traces&quot;&gt;Fields and Traces&lt;&#x2F;h2&gt;
&lt;p&gt;To work with Winterfell, we implemented the field trait from Lambdaworks to the native fields of Winterfell. In other words, we are running our STARK prover with Winterfell fields.&lt;&#x2F;p&gt;
&lt;p&gt;Since Miden works with mini-Goldilocks, the auxiliary trace and the random challenges drawn from the verifier belong to a field extension. One easy way to deal with this is by having all the elements belong to the extension field, which would add overhead to the elements of the main trace (since they live in the smaller base field).&lt;&#x2F;p&gt;
&lt;p&gt;To solve this issue, we split the trace in two, with one part belonging to the main trace and using the small field and the extension belonging to the larger field.&lt;&#x2F;p&gt;
&lt;p&gt;Moreover, we added some useful generalizations. Since, a lot of times, elements from the extension field are multiplied by elements belonging to the base field, the operation can be improved. This is similar to what we do, for example, in the complex numbers when we multiply it by a real. If we want to compute $2\times (1 + i)$, we distribute and do two multiplications instead of doing a naive multiplication with the formula $(2 + 0i) \times (1 + i)$).&lt;&#x2F;p&gt;
&lt;p&gt;To handle this case, we implemented the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;709&quot;&gt;subfield logic&lt;&#x2F;a&gt;. This allows us to define the operations between field elements and exceptional cases for when a subfield element operates with its parent field element. And since it’s just a matter of picking the correct operation in compilation time, there is no overhead. All this extra logic adds no overhead to the fields, as it can be measured in our benchmarks.&lt;&#x2F;p&gt;
&lt;p&gt;Along with the changes in the fields, we also introduced changes to the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;711&quot;&gt;FFT so that it works over extension fields&lt;&#x2F;a&gt;. Now, the interpolation of the auxiliary trace and computation of the composition polynomial has to work over larger fields.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;winterfell-adapter&quot;&gt;Winterfell adapter&lt;&#x2F;h2&gt;
&lt;p&gt;The Winterfell Adapter transforms a Winterfell AIR (algebraic intermediate representation) into a Lambdaworks AIR.&lt;&#x2F;p&gt;
&lt;p&gt;Internally, it creates a new implementation of the Air trait, using all the configurations from Winterfell. One detail is that the evaluation of constraints is delegated here to the implementation in Winterfell to avoid a redefinition that would take longer for someone who already has the Air defined in Winterfell.&lt;&#x2F;p&gt;
&lt;p&gt;To see it working, we can check the following link, which contains an example of how to generate proof for the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;tree&#x2F;main&#x2F;winterfell_adapter&quot;&gt;Fibonacci AIR&lt;&#x2F;a&gt;. Let’s check it.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;code-and-examples&quot;&gt;Code and Examples&lt;&#x2F;h3&gt;
&lt;p&gt;Let’s see how the Winterfell adapter is used with a simple Air.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;fibonacci-air&quot;&gt;Fibonacci Air&lt;&#x2F;h4&gt;
&lt;p&gt;Suppose you want to run Lambdaworks prover with a &lt;code&gt;WinterfellFibonacciAIR.&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;use winterfell::Air;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;struct WinterfellFibonacciAIR {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;impl Air for WinterfellFibonacciAIR {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h5 id=&quot;step-1-convert-your-winterfell-trace-table&quot;&gt;Step 1: Convert your Winterfell trace table&lt;&#x2F;h5&gt;
&lt;p&gt;Use the Lambdaworks &lt;code&gt;AirAdapter&lt;&#x2F;code&gt; to convert your Winterfell trace:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let trace = &amp;amp;AirAdapter::convert_winterfell_trace_table(winterfell_trace)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h5 id=&quot;step-2-convert-your-public-inputs&quot;&gt;Step 2: Convert your public inputs&lt;&#x2F;h5&gt;
&lt;p&gt;Create the &lt;code&gt;AirAdapterPublicInputs&lt;&#x2F;code&gt; by supplying your &lt;code&gt;winterfell_public_inputs&lt;&#x2F;code&gt; and the additional parameters required by the Lambdaworks prover:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let pub_inputs = AirAdapterPublicInputs {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    winterfell_public_inputs: AdapterFieldElement(trace.columns()[1][7]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transition_degrees: vec![1, 1],    &#x2F;&#x2F;&#x2F; The degrees of each transition&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transition_exemptions: vec![1, 1], &#x2F;&#x2F;&#x2F; The steps at the end where the transitions do not apply.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transition_offsets: vec![0, 1],    &#x2F;&#x2F;&#x2F; The size of the frame. This is probably [0, 1] for every Winterfell AIR.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    composition_poly_degree_bound: 8,  &#x2F;&#x2F;&#x2F; A bound over the composition degree polynomial is used for choosing the number of parts for H(x).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    trace_info: TraceInfo::new(2, 8),  &#x2F;&#x2F;&#x2F; Your winterfell trace info.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note that you might have to also convert your field elements to &lt;code&gt;AdapterFieldElement,&lt;&#x2F;code&gt; as in this case.&lt;&#x2F;p&gt;
&lt;h5 id=&quot;step-3-make-the-proof&quot;&gt;Step 3: Make the proof&lt;&#x2F;h5&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let proof = Prover::prove::&amp;lt;AirAdapter&amp;lt;FibonacciAIR, TraceTable&amp;lt;_&amp;gt;&amp;gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;amp;trace,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;amp;pub_inputs, &#x2F;&#x2F;&#x2F; Public inputs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;amp;proof_options,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    StoneProverTranscript::new(&amp;amp;[]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;TraceTable&lt;&#x2F;code&gt; is the Winterfell type that represents your trace table. You can see the &lt;code&gt;examples&lt;&#x2F;code&gt; folder inside this crate to check more examples.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;miden-air&quot;&gt;Miden Air&lt;&#x2F;h3&gt;
&lt;p&gt;Let’s see how it is used with an actual Miden AIR and program.&lt;&#x2F;p&gt;
&lt;p&gt;First, we must compile and run the code to generate a trace. This is done in the same manner as Miden does it.&lt;&#x2F;p&gt;
&lt;p&gt;The whole code is a bit long, but it starts like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let fibonacci_number = 16;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let program = format!(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;quot;begin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                repeat.{}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    swap dup.1 add&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            end&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            fibonacci_number - 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let program = Assembler::default().compile(program).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;... &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Some more code goes in the middle until we generate the trace&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let winter_trace = processor::execute(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;amp;program,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    stack_inputs.clone(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    DefaultHost::default(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    *ProvingOptions::default().execution_options(),)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After generating the trace from Miden, the real work for the prover starts. But the code is not that different from the Fibonacci case; it just has a more complex AIR, but the user is abstracted from that.&lt;&#x2F;p&gt;
&lt;p&gt;To generate the proof, we run the following code:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let pub_inputs = AirAdapterPublicInputs {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    winterfell_public_inputs: pub_inputs,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transition_exemptions: vec![2; 182],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transition_offsets: vec![0, 1],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    trace_info: winter_trace.get_info(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    metadata: winter_trace.clone().into(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let trace =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MidenVMQuadFeltAir::convert_winterfell_trace_table(winter_trace.main_segment().clone());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let proof = Prover::&amp;lt;MidenVMQuadFeltAir&amp;gt;::prove(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;amp;trace,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;amp;pub_inputs,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;amp;lambda_proof_options,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    QuadFeltTranscript::new(&amp;amp;[]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally, to verify it, it is enough to call the verify function with the proof and the public inputs:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Verifier::&amp;lt;MidenVMQuadFeltAir&amp;gt;::verify(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;amp;proof,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;amp;pub_inputs,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;amp;lambda_proof_options,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            QuadFeltTranscript::new(&amp;amp;[]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;benchmarks&quot;&gt;Benchmarks&lt;&#x2F;h3&gt;
&lt;p&gt;To run the Fibonacci Miden benchmark run:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cargo bench&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To run it with parallelization, run:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cargo bench --features stark-platinum-prover&#x2F;parallel,winter-prover&#x2F;concurrent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Several PRs added support for extension fields for the prover and verifier (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;716&quot;&gt;716&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;717&quot;&gt;717&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;724&quot;&gt;724&lt;&#x2F;a&gt;). These allow us to represent the trace in the base field (which has faster operations and less memory use) and have a different frame for the auxiliary trace over the extension. There were some modifications in the constraint calculations, such as being able to use different fields.&lt;&#x2F;p&gt;
&lt;p&gt;There is also a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;blob&#x2F;main&#x2F;winterfell_adapter&#x2F;src&#x2F;examples&#x2F;miden_vm.rs&quot;&gt;Miden adapter&lt;&#x2F;a&gt; containing some example tests, such as Fibonacci and readme example.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;adding-periodic-columns&quot;&gt;Adding periodic columns&lt;&#x2F;h2&gt;
&lt;p&gt;Winterfell also uses periodic columns, so we had to add them and test their use in this &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;pull&#x2F;685&#x2F;files&quot;&gt;PR&lt;&#x2F;a&gt;. These have uses for hash function calculations or supporting constants that we need.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;&#x2F;h2&gt;
&lt;p&gt;Lambdaworks has been growing over the last year. We have added several proof systems and commitment schemes to give users an easy-to-use library to experiment with and build applications. We have also been working to make the provers compatible with our libraries, giving the users a drop-in replacement. We decided to work towards compatibility with Winterfell&#x2F;Miden VM since we like many design choices and the work done to generalize AIRs in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;0xPolygonMiden&#x2F;air-script&quot;&gt;AIRscript&lt;&#x2F;a&gt;. We will continue improving the performance of our provers and supporting new proof systems as part of our roadmap.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Interview with Fernando Borretti about Austral - a systems programming language with linear types</title>
          <pubDate>Sun, 24 Dec 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/austral/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/austral/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/austral/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;It has been many moons since we interviewed a language creator, and are very excited to present a few questions to and share the answers from Fernando Borretti, the creator of the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;austral-lang.org&#x2F;&quot;&gt;Austral&lt;&#x2F;a&gt; (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;austral&#x2F;austral&quot;&gt;Github&lt;&#x2F;a&gt;) language. As it says on the tin:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;“&lt;strong&gt;Austral&lt;&#x2F;strong&gt;  is a new systems programming language. It uses linear types to provide memory safety and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Capability-based_security&quot;&gt;capability-secure code&lt;&#x2F;a&gt;, and is designed to be simple enough to be understood by a single person, with a focus on readability, maintainability, and modularity.”&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Just as Pascal introduced modules, and Lisp garbage collection, to a generation of programmers; Rust introduced using the type system to enforce rules on resource usage &lt;em&gt;into the mainstream&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;It has sparked a very interesting and ongoing discussion about memory usage, resource handling, and linear type systems which are inspiring many other languages. We ourselves at Lambda hope to present our own take on this in the future.&lt;&#x2F;p&gt;
&lt;p&gt;Without further ado, here is the interview.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why did you create Austral? Doesn’t Rust solve the same type of problems?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I think it was Manuel Simoni who said: the most important thing about a programming language is how it makes you feel.&lt;&#x2F;p&gt;
&lt;p&gt;And to many people that sounds like a joke but I take it very seriously. Programming language design is an affective thing. I stopped working with Python because it made me feel like I was always standing atop a house of cards in a strong wind. It made me feel anxious. JavaScript is a lot like that.&lt;&#x2F;p&gt;
&lt;p&gt;There’s something akin to the extended phenotype in biology for programming languages: beyond the core language and the standard library you have the “extended language”, the tooling, the ecosystem, the community, the culture. And all of those things come together and define your experience of the language. Some languages like OCaml have a lot of technical merit, but the tooling is horrible and the community has no interest in improving, and so you persist in using it for its technical beauty and then inevitably burn out. And the further away from the core language you go, the less control there is (it’s hard to socially engineer an entire language community) but there’s a lot of things the language creators have control over, like setting the tone of the community, expectations around documentation, the quality of the tooling.&lt;&#x2F;p&gt;
&lt;p&gt;I wanted a language (and an extended language) that I would feel happy using. I wanted a small, simple language. Simple in the sense of Kolmogorov complexity: it fits in your head and there’s not reams and reams of edge cases you need to understand it. I wanted a slow-moving, conservative language, in the spirit of Common Lisp, where code bitrots very very slowly and you can confidently write code today knowing it will compile and run in thirty or more years. And I want to build an extended language to support that: high quality tooling and high quality docs to set the tone and create a community where people value quality, taste, and craftsmanship.&lt;&#x2F;p&gt;
&lt;p&gt;Re: Rust, I like Rust a lot. I work with it professionally. The tooling is a joy to use (after years of being tormented by pip and dune and pretty much everything else). And it’s infinitely better designed than most other languages you can find. I will even defend async.&lt;&#x2F;p&gt;
&lt;p&gt;But Rust is a very pragmatic language, and the problem with pragmatism is that it never ends*. Pragmatism has no natural stopping point. Rust is already pretty complex and I expect it will continue to grow as people demand more from the language. And the thing about programming languages is you can’t really take features off. And this isn’t necessarily wrong: I don’t think Rust would be as successful if it didn’t have a thousand little ergonomic features, and certainly if it didn’t have async there’d be a lot less of an impetus to adopt it for building servers.&lt;&#x2F;p&gt;
&lt;p&gt;There’s two ways to build a general-purpose language: one is to make it so that it is not specialized to any one thing, and that’s the Austral approach; and one is to make it specialized to every one thing. And things tend to evolve towards the latter, because large companies – the ones whose employees sit on the boards of programming language foundations, and the ones who pay people to work on the compilers and tooling and such – have very specific needs, and they’re always lobbying to have the language solve their specific problem. So languages grow and accumulate all these features because Google needs to reduce global latency by 0.02%.&lt;&#x2F;p&gt;
&lt;p&gt;*Philip K. Dick originally said this of introspection, and he was right.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Which languages inspired you the most?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Rust gets a lot of credit because it’s the only industrial language to have anything like linear types.&lt;&#x2F;p&gt;
&lt;p&gt;Cyclone, which also inspired Rust, was a research language, a better dialect of C, didn’t take off but they published a few papers about it. There were very interesting ideas about region-based memory management there.&lt;&#x2F;p&gt;
&lt;p&gt;Haskell for type classes done right. Haskell 98 type classes in particular are a jewel of good design. Standard ML for its module system. Ada for the syntax, module system, and ideas about security.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is a linear type system, why is it useful? What type of software do you think that can be improved by using a linear type system?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I’ve written a bit about this in different places:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;borretti.me&#x2F;article&#x2F;type-systems-memory-safety&quot;&gt;https:&#x2F;&#x2F;borretti.me&#x2F;article&#x2F;type-systems-memory-safety&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;borretti.me&#x2F;article&#x2F;how-australs-linear-type-checker-works&quot;&gt;https:&#x2F;&#x2F;borretti.me&#x2F;article&#x2F;how-australs-linear-type-checker-works&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;borretti.me&#x2F;article&#x2F;introducing-austral&quot;&gt;https:&#x2F;&#x2F;borretti.me&#x2F;article&#x2F;introducing-austral&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;austral-lang.org&#x2F;linear-types&quot;&gt;https:&#x2F;&#x2F;austral-lang.org&#x2F;linear-types&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Part of me wants to consolidate these into one “definitive” explanation, but another part thinks it’s valuable to have different approaches to the same idea. So I have a number of different elevator pitches:&lt;&#x2F;p&gt;
&lt;p&gt;One way to think about it is linear types let you enforce protocols at compile time. There’s two kinds of values in programming: plain data and protocol handles. The latter are things like sockets, file objects, database handles, IPC channels. In languages with manual memory management they include heap-allocated objects.&lt;&#x2F;p&gt;
&lt;p&gt;These have to conform to a particular protocol, with the right state transitions. No double-free (you can’t free memory twice) and no use-after-free. Linear types allow you to enforce this at compile time. This is the main benefit: you get manual memory management with high performance and without safety footguns.&lt;&#x2F;p&gt;
&lt;p&gt;But you can also make your own protocols for your own types and enforce higher-level API contracts than what a normal type system allows.&lt;&#x2F;p&gt;
&lt;p&gt;Another way to think about it is that linear types make values work like real-world objects. In reality things can only ever be in one place. They move, but can’t be copied. In computers, copying is the primitive operation. Values can be aliased because pointers are unrestricted.&lt;&#x2F;p&gt;
&lt;p&gt;It turns out a lot of the problems with mutation are really problems with aliasing. And when you restrict pointer aliasing through linear types, you get referential transparency with pervasive mutation. You get code that is easy to reason about and very high performance.&lt;&#x2F;p&gt;
&lt;p&gt;As for what kinds of software could be improved: mainly, anything that manually-manages memory or uses external resources that need to respect protocols. That’s the main improvement. But when you start to think about designing APIs with linear types from the ground up, it becomes a lot more general, because a whole lot of APIs can be improved by using linear types to enforce high-level contracts and protocols.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What are the disadvantages of using a linear type system? Do you think that developer experience or the learning curve are necessarily impacted?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;There are two main disadvantages:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Explicitness and verbosity: you have to call destructors by hand, and a lot more things require destruction (e.g. any string).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Linear types are incompatible with traditional exception handling techniques: &amp;lt;https:&#x2F;&#x2F;borretti.me&#x2F;article&#x2F;linear-types-exceptions&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Your post explaining the linearity checker details the implementation. Some modern languages are exploring implementing their type systems as rule sets in logic inference engines e.g. Datalog. Do you have thoughts on this trend?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I don’t know enough logic programming to implement the type checker in it. There’s this Racket tool called Redex which I’m aware of but haven’t played with, it basically lets you write typing judgments in Gentzen notation (like PLT papers) but have those judgements type-checked. Which is a vast improvement over writing the type system in LaTeX.&lt;&#x2F;p&gt;
&lt;p&gt;Another thing is that the type system is not too complicated. The goal is to be simple in the C. A. R. Hoare sense of “simple enough that there are obviously no bugs”.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Incremental compilation is also a hot topic today. In your post explaining the design of the Austral compiler you mention that for simplicity it does batch compilation. Have you considered incremental compilation an interesting feature or do you see it as an implementation detail?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Incremental and separate compilation are a must have in a production compiler but I think you can live without them in the early days, particularly because there’s just not that much code written in the language in the first place. You could take the entire ecosystem, 10x it in volume, and still not suffer from slow compile times.&lt;&#x2F;p&gt;
&lt;p&gt;I think this is an area where there’s room for improvement relative to other languages like Rust, because in Austral the module is the compilation unit, while in Rust the crate is the compilation unit. In Rust, all the modules that make up a crate are loaded at once, and only then compiled, so you can have e.g. circular dependencies between modules within a crate. The problem is build times are the main complaint people have about Rust, and people have to turn to bad solutions like manually splitting codebases into multiple crates.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;In your introduction to Austral, you mention that type inference is an anti-feature. Can you expand on what led you to this decision?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I feel that type inference is a science experiment that broke its cage and escaped the lab, to the detriment of many people. As in, it should have remained an academic curiosity.&lt;&#x2F;p&gt;
&lt;p&gt;The fundamental problem is that type inference doesn’t know whether the input you give it is correct or a mistake, but it will use it as a constraint in inference anyways. I had this problem in OCaml constantly: I’d make a mistake where in Java I’d get an error message saying “you made a mistake”, while in OCaml the compiler would make a best-effort inference, propagating my mistake upwards and sideways and every which way, and then I’d get an incomprehensible type error, sometimes many tens or hundreds of lines removed from the place where I made the actual mistake.Sometimes the only solution to such errors is to start adding type annotations (to function signatures, to variables) to constrain the inference process, and this can take a long time. And then you find the error and it was the most trivial thing, and in a less bigbrained language it would not have happened in the first place.&lt;&#x2F;p&gt;
&lt;p&gt;The next problem is languages that infer too much. Again, in OCaml (and unlike Rust) you can leave the parameters to a function unannotated. You save microseconds of typing, and for the rest of the lifetime of that codebase you will spend multiple minutes trying to figure out what the type of something is. And you can say, well, simply annotate all your function signatures. But that’s why languages have to have hard rules: if something is optional, people will take the shortcut and not do it all the time.&lt;&#x2F;p&gt;
&lt;p&gt;So type inference in ML family languages is a failed idea because you end up annotating the types anyways: you have to annotate the types of functions for documentation, and you frequently end up annotating the types of local variables for both readability and to constrain the type inference engine and make the errors easier. It’s just this really frustrating, circuitous way of doing what in Java you’d be forced to do in the first place. And I see people using VS Code with an LSP set up to display the types of the variables over the code and think, well, why not just have them written? Then you can read the code outside your dev environment, like in a GitHub diff for example.&lt;&#x2F;p&gt;
&lt;p&gt;I’ve found that type inference is only useful in a very narrow set of circumstances where type information doesn’t flow strictly downwards and annotations would be cumbersome. The best example of this is the &lt;code&gt;Option&lt;&#x2F;code&gt; type. If you have this in Rust:&lt;&#x2F;p&gt;
&lt;p&gt;enum Option&lt;T&gt; {&lt;br &#x2F;&gt;
Some(T),&lt;br &#x2F;&gt;
None,&lt;br &#x2F;&gt;
}&lt;&#x2F;p&gt;
&lt;p&gt;Then in the &lt;code&gt;Some&lt;&#x2F;code&gt; constructor, there’s no need for inference, because type information flows downwards: &lt;code&gt;Some: T -&amp;gt; Option&amp;lt;T&amp;gt;&lt;&#x2F;code&gt;. But without type inference the &lt;code&gt;None&lt;&#x2F;code&gt; constructor is harder: it doesn’t take a value, so in a language without type inference, you have to tell the compiler which type should be used in place of &lt;code&gt;T&lt;&#x2F;code&gt;. But a general type inference engine is such a complex piece of machinery for such a narrow use case.&lt;&#x2F;p&gt;
&lt;p&gt;And then there’s the performance cost. The more advanced the type system, the more expensive inference becomes . There’s also the fact that type inference wastes a lot of academic effort. Academic papers on PLT will introduce a new type system, and then spend pages and pages describing the type reconstruction algorithm. And I’m like, this is the least interesting part of it! Let me annotate things manually and show me what this thing can do to solve real problems!&lt;&#x2F;p&gt;
&lt;p&gt;So in Austral type information flows in one direction only, and variables and everything require annotations everywhere. The cost is you spend unobservable extra milliseconds writing. The gain is the code is instantly more readable and you never again have to deal with weird inference bugs.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Macros are also mentioned as an anti-feature but in your writings you mention Lisp. Do you consider there are valid use cases in general or in Austral for metaprogramming, and for which kinds of metaprogramming?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I used to write Common Lisp a lot. And macros work decently well in CL*. One of the things that attracted me to Lisp is that every programmer is a language designer. I used to think that was a very good thing: you can implement language features in a few seconds that Java programmers have been begging for in mailing lists for years. But then I saw what people do with macros and changed my mind.&lt;&#x2F;p&gt;
&lt;p&gt;This is part of a general pattern that when I was younger I wanted expressive power, and I was attracted to Common Lisp because in Common Lisp you can wave your magic wand and change the world. But after 10y of cleaning up people’s horrible code I realize what I want are fewer nightmares. Macros make everyone a language designer, and that, I realize, is a very bad thing because most people should not be anywhere near language design. Macros might work in a language that is only used by like, insane PL geniuses who also have great communication skills and write lots of docs, but “this feature can only be used by discerning geniuses with great taste” is not sustainable in the real world.&lt;&#x2F;p&gt;
&lt;p&gt;What do people use macro systems (and related things like Java-style annotations) for? Largely to build nightmares: codebases shot through with magic, where every type has like seven different annotations involving serialization, RPC, SQL mappings and the like. The code you see on the page is not what’s running: it’s an input to a vast, ill-defined, ad-hoc programming language made up of third-party macros that transforms the code in unpredictable ways. Errors become impossible to trace because nobody can tell you concretely what control flow looks like. Changes to the codebase become unpredictable.&lt;&#x2F;p&gt;
&lt;p&gt;So macros are kind of a bait and switch. The bait is, “it would be nice to have to have a shorthand way to write this common code”. The switch is you end up with a codebase nobody can understand.&lt;&#x2F;p&gt;
&lt;p&gt;And the solution is build-time code generation. It’s a lot like macros, but you can inspect the generated code, commit it to version control, debug it, and it is cleanly separate from the rest of the code you write.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * I wrote about why here: &amp;lt;https:&#x2F;&#x2F;borretti.me&#x2F;article&#x2F;why-lisp-syntax-works&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;The capability-based security description sounds strikingly similar to OpenBSD’s  &lt;code&gt;pledge&lt;&#x2F;code&gt;. Did you take inspiration from them?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This is one area where I wish I’d kept something like a lab notebook while iterating on the language design. It would be invaluable to be able to go back and see what I was aware of and when, which papers I read and such. I think I was aware of pledge and how it works at the time. I really like the pledge API. Linux and FreeBSD capabilities are hellishly complicated when compared to the bare-bones simplicity of pledge. Austral’s capability security is similar to pledge in that in both systems, you start with infinite capabilities, and you can then surrender those capabilities, irreversibly, one at a time. But Austral’s system is more granular because it doesn’t rely on a hardcoded list of syscalls, but, rather, you get pledge() at the value level, you can pledge individual files and other objects.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is the most difficult part of designing a programming a new programming language like Austral?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I should say building a community, getting people interested, but honestly the most frustrating thing has been writing the compiler.&lt;&#x2F;p&gt;
&lt;p&gt;There’s this tension between, on the one hand, you want the simplest, most MVP, most prototype bootstrapping compiler so you can get to the stage where you can write real running programs and actually start playing with the language. That tells you a lot about ergonomics, about possible soundness issues. Because when things are vague and ill-defined they’re always great, it’s only when you concretize things (by implementing them) that you start to notice the flaws and the tradeoffs.&lt;&#x2F;p&gt;
&lt;p&gt;But if the compiler is too MVP you will have bugs you can’t easily figure out, because the error reporting is very poor for example. Compilers are really uniquely hellish to test and debug.&lt;&#x2F;p&gt;
&lt;p&gt;So you’re always changing course between “build a simple MVP compiler so I can quickly iterate on it” and “build something with production-grade diagnostics and error reporting”.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Are you planning on building a community or userbase? How do you think you can generate momentum to attract Rust or C programmers to develop with Austral?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I have a little Discord. I want to do more work to have something more substantial especially around the standard library and build tooling before spending much more effort on marketing. I think a lot of programmers are very tired of language churn and framework churn and library churn, and the idea of a small, simple, conservative, slow-moving language is appealing. Here’s a thing you can learn in an afternoon, and the code you write will compile and run thirty years from now, and you won’t have to jump ship in horror in a decade.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Do you think you can reuse existing tooling from other languages (like gdb, or rust-analyzer)? What is the state of the standard library and how do you see it evolving?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The current compiler spits out C. I don’t want that to become a trait of the language (“Austral compiles to C”), since it’s just an implementation detail of the compiler. So gdb and valgrind should be usable.&lt;&#x2F;p&gt;
&lt;p&gt;rust-analyzer, I doubt it. It’s a huge thing and is essentially the most complex parts of a compiler frontend specifically for Rust.&lt;&#x2F;p&gt;
&lt;p&gt;I think it would be a good idea to write the production compiler with a view towards making it usable also as an LSP.&lt;&#x2F;p&gt;
&lt;p&gt;The standard library is very minimal: simple containers and typeclasses. I see myself making small additions to it. A lot of people hate dependencies but I’m a big believer in lots of small libraries actually, so I like the idea of the standard library being just code that is either “eternal” (e.g. a resizable array type) or pervasive (e.g. date and time) or binding some platform-specific thing (e.g. file I&#x2F;O).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Is interoperability with other languages (e.g. FFI) part of the roadmap? How would it interact with linear types and capabilities?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Interoperability with C is already there. That’s the most useful one because the C calling convention is basically the lingua franca of every language.&lt;&#x2F;p&gt;
&lt;p&gt;Some languages advertise e.g. automatic interoperability with C++. That is vastly more effort and I think it’s entirely misguided. e.g. the Clasp compiler for Common Lisp was built essentially so the author could access C++ libraries that use templates and such from Common Lisp. It’s a tremendous amount of effort when you can simply write a light extern C wrapper around the C++ code you need (in Common Lisp you can even automate much of this). So I’m not too worried about C++ interop. In the future we’ll just have an LLM port the entire C++ codebase over no problem.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What are your future plans for Austral? Do you plan to grow the language and add new features like concurrency primitives?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Standard library, build system and package manager, better docs. That’s the first thing.&lt;&#x2F;p&gt;
&lt;p&gt;I’m procrastinating on concurrency models because I don’t know enough about them, and I don’t want to prematurely specialize the language to an approach that might not pan out. Go has green threads and goroutines and that hasn’t worked out for them, the design gives up a lot of performance. OCaml has green threads now and that seems to be working out for them so far. I think Rust-style async is very unfairly maligned, but it also has practical problems in that, because of the way it interacts with lifetimes, everyone ends up putting all of their shared resources under reference-counted pointers. And so in theory the perf ceiling is very high but in practice people will leave a lot of performance on the table to get code that can be feasibly written and refactored.&lt;&#x2F;p&gt;
&lt;p&gt;So I’m happy to sit back and let the world define itself for me, and when there’s a clear and compelling right thing to do, I’ll implement it in Austral in the simplest, most orthogonal way possible.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;If you enjoy interviews to programming language creators, you might also enjoy these previous ones:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Dec 8, 2014 [https:&#x2F;&#x2F;blog.lambdaclass.com&#x2F;indie-languages-interview-pixie-and-timothy-baldridge&#x2F;](&#x2F;indie-languages-interview-pixie-and-timothy-baldridge&#x2F;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Aug 26, 2015 [https:&#x2F;&#x2F;blog.lambdaclass.com&#x2F;interview-with-brian-mckenna-about-roy-purescript-haskell-idris-and-dependent-types&#x2F;](&#x2F;interview-with-brian-mckenna-about-roy-purescript-haskell-idris-and-dependent-types&#x2F;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Aug 28, 2015 [https:&#x2F;&#x2F;blog.lambdaclass.com&#x2F;interview-with-nenad-rakocevic-about-red-a-rebol-inspired-programming-language&#x2F;](&#x2F;interview-with-nenad-rakocevic-about-red-a-rebol-inspired-programming-language&#x2F;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Nov 27, 2015 [https:&#x2F;&#x2F;blog.lambdaclass.com&#x2F;efene-an-erlang-vm-language-that-embraces-the-python-zen&#x2F;](&#x2F;efene-an-erlang-vm-language-that-embraces-the-python-zen&#x2F;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Dec 28, 2015 [https:&#x2F;&#x2F;blog.lambdaclass.com&#x2F;interview-with-jesper-louis-andersen-about-erlang-haskell-ocaml-go-idris-the-jvm-software-and&#x2F;](&#x2F;interview-with-jesper-louis-andersen-about-erlang-haskell-ocaml-go-idris-the-jvm-software-and&#x2F;) Dec 29, 2015 [https:&#x2F;&#x2F;blog.lambdaclass.com&#x2F;interview-with-jesper-louis-andersen-about-erlang-haskell-ocaml-go-idris-the-jvm-software-and-60901251608c356716f2f92e&#x2F;](&#x2F;interview-with-jesper-louis-andersen-about-erlang-haskell-ocaml-go-idris-the-jvm-software-and-60901251608c356716f2f92e&#x2F;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Feb 29, 2016 [https:&#x2F;&#x2F;blog.lambdaclass.com&#x2F;interview-with-robert-virding-creator-lisp-flavored-erlang-an-alien-technology-masterpiece&#x2F;](&#x2F;interview-with-robert-virding-creator-lisp-flavored-erlang-an-alien-technology-masterpiece&#x2F;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Feb 12, 2018 [https:&#x2F;&#x2F;blog.lambdaclass.com&#x2F;interview-with-brad-chamberlain-about-chapel-a-productive-parallel-programming-language&#x2F;](&#x2F;interview-with-brad-chamberlain-about-chapel-a-productive-parallel-programming-language&#x2F;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Apr 1, 2019 [https:&#x2F;&#x2F;blog.lambdaclass.com&#x2F;an-interview-with-the-creator-of-gleam-an-ml-like-language-for-the-erlang-vm-with-a-compiler&#x2F;](&#x2F;an-interview-with-the-creator-of-gleam-an-ml-like-language-for-the-erlang-vm-with-a-compiler&#x2F;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</description>
      </item>
      <item>
          <title>How Binius is helping move the ZK industry forward</title>
          <pubDate>Tue, 12 Dec 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/binius-moving-zk-forward/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/binius-moving-zk-forward/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/binius-moving-zk-forward/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;Zero-knowledge and validity proofs, often abbreviated as ZK, represent a fascinating field within the realms of cryptography, mathematics, and computer science. They allow one party, the prover, to convince other parties, termed verifiers, that a specific statement (such as the execution of a computer program) is true in a time- and space-efficient way. This means that the proof can be verified much faster than if the verifiers were to perform the computation directly and need less information, with the possibility that the proof does not leak sensitive data.&lt;&#x2F;p&gt;
&lt;p&gt;The consequences of practical zero-knowledge proofs for engineering are many and far-reaching, as we discussed in our previous &lt;a href=&quot;&#x2F;transforming-the-future-with-zero-knowledge-proofs-fully-homomorphic-encryption-and-new-distributed-systems-algorithms&#x2F;&quot;&gt;blog post&lt;&#x2F;a&gt;. One of those areas is crypto (see &lt;a href=&quot;&#x2F;lambda-crypto-doctrine&#x2F;&quot;&gt;our crypto doctrine&lt;&#x2F;a&gt;). Still, it extends to content creation platforms, identity and authentication, national security, distributed computing, etc.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;current-developments-in-zk&quot;&gt;Current developments in ZK&lt;&#x2F;h2&gt;
&lt;p&gt;To prove the execution of arbitrary computer programs, we need to transform them into a form amenable to ZK; this process is called arithmetization and consists of expressing the program as a bunch of equations defined over integers&#x2F;finite fields. There are differences in how we express and think in computer programs, using bytes and binary operations. For example, if our program has a boolean variable, we must ensure that the variable takes only the values 0 or 1. Since we work with integers, this condition adds an equation of the form $b(1 - b) = 0$. The problem is that this variable is represented with a large integer (at least 64 bits long), which adds significant overhead in memory use and computational time since we now work with operations over finite fields (not bits). Operations such as bitwise operations or showing the binary decomposition of an integer are costly.&lt;&#x2F;p&gt;
&lt;p&gt;Since performance in ZK involves different tradeoffs than ordinary programming, developers need to have a deeper understanding of cryptography and learn to code differently. The tooling for developers is still being created and depends, in some cases, on writing arithmetic circuits directly, which is time-consuming and prone to bugs. Besides, proving adds significant overhead, both in memory and time use. Therefore, ZK introduces difficulties both in developer and user experiences. It means more time and money spent on training developers and lower availability of skilled programmers.&lt;&#x2F;p&gt;
&lt;p&gt;During the last years, the zk space has advanced really fast, and we have seen efforts going in various directions to increase the performance of the proof systems:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. STARKs using small field sizes, such as mini-Goldilocks and the 31-bit Mersenne prime.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Folding schemes, such as Nova, Protostar, and Protogalaxy.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Lookup arguments, with Jolt aiming to reduce everything to just looking up any operation over a pre-computed table of valid input&#x2F;output pairs.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Each system has advantages and disadvantages regarding proof size, prover time, verifier time, and the type of computations that can be easily supported. There have been efforts on the hardware side to accelerate these proof systems, but they all pay the price for representing bits in terms of field elements.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;binius-and-the-use-of-binary-fields&quot;&gt;Binius and the use of binary fields&lt;&#x2F;h2&gt;
&lt;p&gt;Using smaller fields in STARKs reduced the overhead in representing variables and led to lower proving times. The question arises naturally: can we do better than this? Near the end of the year, Ulvetanna released a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2023&#x2F;1784.pdf&quot;&gt;paper&lt;&#x2F;a&gt; showing that we can work over smaller fields and open-sourced an implementation, Binius. A first analysis of Binius can be found &lt;a href=&quot;&#x2F;snarks-on-binary-fields-binius&#x2F;&quot;&gt;here&lt;&#x2F;a&gt;. We will release the second part of the post soon, diving deeper into the construction and its uses.&lt;&#x2F;p&gt;
&lt;p&gt;Binius’s contributions can be summarized in three main points:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Working with binary fields -this is essentially working with bitstrings of various sizes. It is possible to adjust the size to represent variables with no overhead.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. A commitment scheme for small fields. It is based on hash functions, which are faster than those based on elliptic curves and do not need a trusted setup. It draws heavily on [Brakedown](https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2021&#x2F;1043.pdf).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. A SNARK built on top of 1 and 2, based on the ideas of HyperPlonk, but which could be extended to other arithmetization schemes.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The main advantage of the whole construction is that it handles bit operations more naturally (for example, the exclusive OR between two bitstrings is just the addition over the field) and eliminates the overhead associated with the representation of data types. For instance, boolean variables can be represented by just one field element of size 1 bit! This reduced the memory footprint of the whole proof system (though we will need to work with larger fields to achieve cryptographic security).&lt;&#x2F;p&gt;
&lt;p&gt;Another advantage is that operations are really fast and hardware-friendly. In the case of adding field elements, it is just the XOR operation, avoiding carry and overflow. There are also very efficient algorithms to work with binary fields, such as an additive Fast Fourier Transform (FFT), which is used to produce the Reed-Solomon encoding.&lt;&#x2F;p&gt;
&lt;p&gt;The main drawbacks are related to proof size (it is significantly larger than most SNARKs and STARKs, in the order of a few MB) and verifier time. However, the verifier’s time is on par with most proof systems, and the prover is significantly faster. Besides, smaller proof sizes in SNARKs come at the cost of a trusted setup, which makes the whole system rely on the integrity of a parameter initialization ceremony, generally using several GB of memory.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;applications&quot;&gt;Applications&lt;&#x2F;h2&gt;
&lt;p&gt;The original paper shows how to arithmetize the Keccak and Grøstl hash functions, which involve many bitwise operations, making them hard to work using other proof systems. The performance analysis offers an idea of the capabilities of the new construction and what we can gain by adopting it. The ability to handle bitwise operations more naturally also allows us to use these hash functions for commitments and prove them easily.&lt;&#x2F;p&gt;
&lt;p&gt;We could build a virtual machine and prove the correctness of its execution using Binius. This could make proving general computer programs very efficient, at least in terms of the time needed to generate the proof. We could solve the problem of proof size by wrapping the proofs with a SNARK&#x2F;STARK, which will only need to verify Binius’s proofs, leading to more lightweight and efficient constructions.&lt;&#x2F;p&gt;
&lt;p&gt;Reducing the prover’s memory and time use can enable provable fully homomorphic encryption (FHE), which lets users delegate expensive computations to untrusted servers without compromising the data. FHE allows users to compute over encrypted data without decrypting it first.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;&#x2F;h2&gt;
&lt;p&gt;We think that Binius can be a game changer when it comes to scaling provable computations, which can spark significant changes in different areas of software engineering and finance. The reduction in memory use and hardware friendliness of the operations and the development of a virtual machine could make provable computations in consumer-end hardware a reality while enhancing the developer experience, and reducing the resources and training needed. We are one step closer to the mass adoption of zk technology. Lambdaclass is interested in this new proof system and its capabilities and we would like to start implementing and developing it in 2024.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>SNARKs on binary fields: Binius - Part 1</title>
          <pubDate>Fri, 01 Dec 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/snarks-on-binary-fields-binius/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/snarks-on-binary-fields-binius/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/snarks-on-binary-fields-binius/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;ZK-SNARKs (zero-knowledge, succinct, non-interactive arguments of knowledge) and STARKs (scalable, transparent arguments of knowledge) have gained widespread attention due to their applications in distributed private computing and blockchain scaling. Over the years, we have seen several performance improvements thanks to new proof systems, new lookup arguments, and smaller fields. One of the biggest challenges is related to the arithmetization of programs, that is, the transformation of a given program into a system of polynomial relations. This represents a considerable overhead, as we have to represent variables, such as bits, by elements in a finite field. In the case of SNARKs over elliptic curves, the field is given by the elliptic curve used, which means that to represent simple bit operations, we have to use (at least) 256-bit field elements. In the case of STARKs, we can use smaller fields (such as mini Goldilocks or Mersenne 31), which gives a smaller overhead, but then we have to work over extension fields to achieve cryptographic security. Typical hash functions involve lots of bitwise operations, which makes their arithmetization costly (and therefore proving things that involve computing hashes). This has led to the use of SNARK-friendly hashes such as Poseidon or Tip5.&lt;&#x2F;p&gt;
&lt;p&gt;A recent &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2023&#x2F;1784.pdf&quot;&gt;line of work by Ulvetanna&lt;&#x2F;a&gt; proposes using binary fields with the brakedown polynomial commitment scheme to obtain a new SNARK, which can represent bitwise operations more naturally. It also has the advantage that it is hardware-friendly and has a lower memory footprint. This post will explain some key concepts, such as binary fields and the brakedown commitment scheme. We will use these concepts later to understand the working principle of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gitlab.com&#x2F;UlvetannaOSS&#x2F;binius&#x2F;-&#x2F;tree&#x2F;main&#x2F;src?ref_type=heads&quot;&gt;Binius&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;binary-fields&quot;&gt;Binary fields&lt;&#x2F;h2&gt;
&lt;p&gt;Binary fields are fields of characteristic two. They are of the form $\mathbb{F_{ 2^n }}$ for some $n$. The simplest binary field is $\mathbb{F_2}$ whose elements are just $\{ 0, 1 \}$ with the operations done modulo $2$. Addition corresponds to bitwise exclusive OR, and multiplication corresponds to bitwise AND. Given that $2^n$ is not prime, we need to do some work to turn it into a field. First, we are going to consider the polynomials over $\mathbb{F_2}$, that is, polynomials whose coefficients are either $0$ or $1$, such as $p(x) = x^7 + x^5 + x^2 + 1$. Then, we select an irreducible polynomial $m(x)$ over $\mathbb{F_2}$ and consider the equivalence classes by taking the remainder of any polynomial by $m(x)$. For example, the polynomial $m(x) = x^2 + x + 1$ is irreducible; the remainder is always a polynomial of at most degree one $r(x) = a x + b$, where $a$ and $b$ is either zero or one. The resulting field is $\mathbb{F_{ 2^2 }}$, which contains $4$ elements, $0 + 0x$, $1 + 0x$, $0 + x$, $1 + 1x$, which we can represent as $00$, $10$, $01$ and $11$. We can always represent unambiguously an element in $\mathbb{F_{ 2^n }}$ by a bitstring of length $n$. A list of irreducible polynomials over $\mathbb{F_2}$ can be found &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.hpl.hp.com&#x2F;techreports&#x2F;98&#x2F;HPL-98-135.pdf&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The polynomial $m(x) = x^3 + x + 1$ is also irreducible, so we can use it to build a different extension, $\mathbb{F_{ 2^3 }}$, containing $8$ other elements. A different approach to constructing $\mathbb{F_{ 2^3 }}$ is using extension towers. Binius uses the construction proposed by &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.fq.math.ca&#x2F;Scanned&#x2F;26-4&#x2F;wiedemann.pdf&quot;&gt;Wiedemann&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;We can use the multilinear Lagrange polynomials as a base for the tower of extensions. This has the advantage that embedding one extension into the others is achieved trivially by padding zero coefficients. The construction proceeds inductively:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Start from $\tau_0 = \mathbb{F_2}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Set $\tau_1 = \mathbb{F_2} [ x_0 ] &#x2F; (x_0^2 + x_0 + 1)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Continue $\tau_k = \mathbb{F_2} [ x_{ k - 1} ] &#x2F; ( x_{ k - 1 }^2 + x_{ k - 1} x_{ k - 2} +1)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We have $\tau_0 \subset \tau_1 \subset \tau_2 \subset \dots \subset \tau_m$.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s take a look at the elements to see how this works:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. For $\tau_0$ this is straightforward, since we have either $0$ or $1$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. For $\tau_1$, the elements are $0 + 0x_0$, $1 + 0x_0$, $0 + 1x_0$, $1 + 1x_0$. We can identify the elements of $\tau_0$ with the first two, $00$ and $10$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. For $\tau_2$, we have $0 + 0 x_0 + 0 x_1 + 0 x_0 x_1$, $1 + 0 x_0 + 0 x_1 + 0 x_0 x_1$, $0 + 1 x_0 + 0 x_1 + 0 x_0 x_1$, $1 + 1 x_0 + 0 x_1 + 0 x_0 x_1$, $1 + 0 x_0 + 1 x_1 + 0 x_0 x_1$, $0 + 1 x_0 + 1 x_1 + 0 x_0 x_1$, $1 + 1 x_0 + 1 x_1 + 0 x_0 x_1$, etc, which we identify with all bitstring of size 4. The elements of $\tau_1$ can be seen as the elements in $\tau_2$ of the form $b_0 b_1 00$. This way of sorting the elements corresponds to lexicographic ordering.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It’s also worth noting that given an element $b_0 b_1 b_2 … b_{ 2^k - 1}$ from $\tau_k$, we can break it into halves, which satisfy $b_{lo} + X_{k - 1} b_{hi}$, where $b_{hi}$ and $b_{lo}$ are from $\tau_{ k - 1}$. The addition is just XOR, which has several advantages from the hardware point of view, including the fact that we don’t need to worry about carry. Multiplication can be carried out in a recursive fashion using the decomposition we saw. If we have $a_{hi} x_k + a_{lo}$ and $b_{hi} x_k + b_{lo}$ we get&lt;br &#x2F;&gt;
$a_{hi} b_{hi} x_k^2 + (a_{hi} b_{lo} + a_{lo} b_{hi}) x_k + a_{lo} b_{lo}$&lt;br &#x2F;&gt;
But we know that $x_k^2 = x_{k-1} x_k + 1$. We then have to compute products in $\tau_{ k - 1}$, where we can apply the same strategy until we can solve them either because it’s a trivial operation (operation over $\mathbb{F_2}$) or because we have a lookup table to get the values. There are also efficient multiplication techniques to multiply elements from a field by an element in a subfield. For example, an element from $\tau_{ k + j}$ can be multiplied by an element of $\tau_k$ in just $2^j$ multiplications.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;coding-theory&quot;&gt;Coding Theory&lt;&#x2F;h2&gt;
&lt;p&gt;A code of block $n$ over an alphabet $A$ is a subset of $A^n$, that is, vectors with $n$ elements belonging to $A$. The Hamming distance between two codes is the number of components in which they differ.&lt;&#x2F;p&gt;
&lt;p&gt;A $[k, n , d]$ code over a field $\mathbb{F}$ is a $k$-dimensional linear subspace of $\mathbb{F}^n$ such that the distance between two different elements is at least $d$. Reed-Solomon codes are examples of these types of codes. Given a vector of size $k$, $(a_0, a_1, … , a_{ k - 1})$, its Reed-Solomon encoding consists in interpreting each $a_k$ as the evaluation of a $k - 1$ degree polynomial and then evaluating this polynomial over $n$ points (we used this encoding when working with STARKs). The code is called systematic if the first $k$ elements correspond to the original vector. The ratio $\rho = k &#x2F; n$ is the rate of the code (we worked with its inverse, the blow-up factor). In this case, the distance is $n - k + 1$ since degree $k - 1$ polynomials can coincide at most in $k - 1$ points.&lt;&#x2F;p&gt;
&lt;p&gt;The $m$-fold interleaved code of block length can be seen as the linear code of size $n$ defined over the alphabet $A^m$. We can view the code as rows with elements in $A^m$.&lt;&#x2F;p&gt;
&lt;p&gt;Given a $[n,k,d]$ linear code $C$ over $\mathbb{F}$ with generating matrix $M$ and a vector space $V$ over $\mathbb{F}$, the extension code $C^\prime$ of $C$ is the image of the mapping $M x$, where $x$ is in $V^k$.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;polynomial-commitment-scheme&quot;&gt;Polynomial Commitment Scheme&lt;&#x2F;h2&gt;
&lt;p&gt;The polynomial’s coefficients and code field size $\mathbb{F}$ can be as small as needed, but they should be the same. The security can be added by sampling elements from an extension field $\mathbb{E}$.&lt;&#x2F;p&gt;
&lt;p&gt;The prover starts with a vector $(t_0, t_1, … t_n)$, which he interprets as the coefficients in the Lagrange basis over ${0 , 1}^{\log n}$. Then, he organizes the coefficients in an $m_0 \times m_1$ matrix $T$, with rows $\mathrm{row_i}$ and encodes $\mathrm{row_i}$ to obtain $u_i$ (there are $m_0$ rows of length $\rho^{ - 1 } m_1$). We call the matrix containing the $u_i$ as rows, $U$. Build a Merkle tree using each column as a leaf and output the root as the commitment.&lt;&#x2F;p&gt;
&lt;p&gt;The verifier selects an evaluation point $r = (r_0, r_1 , \dots, r_{ \log (n) - 1})$, and the prover will provide $s$ as the evaluation of the polynomial over $r$. To generate the evaluation proof,&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. The prover sends the vector - matrix product $R.T$, where $R$ is the tensor product of the last $\log (m_0 )$ components of $r$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. The verifier samples $i$ queries (which depend on the security level), selecting one column of $U$ each time.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. The prover sends the requested columns and their corresponding authentication paths.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The proof consists of the evaluation, $s$, the Merkle root, $\mathrm{root}$, the vector-matrix product $R.T$, the $i$ columns, and their corresponding authentication paths.&lt;&#x2F;p&gt;
&lt;p&gt;To check the proof:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. The verifier checks that the Merkle tree contains the columns.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. The verifier computes the encoding of $R.T$ and checks that the product of the selected columns of $U$ by $R$ correspond to the columns of encoding of $R.T$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. The verifier checks that $s$ is the proper evaluation using $R.T$ and the tensor product of first $\log (m_1)$ components of $r$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;A key concept to building the commitment scheme is that of packing. Given m elements $\tau_{ k }$, we can group then into $m&#x2F;2^j$ elements of $\tau_{ k + j}$. Similarly, the rows can be packed into elements of $\tau_r$. The polynomial commitment is modified to have the verifier test blocks of columns instead of single columns.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;In this post, we covered the basic concepts behind Binius. The construction takes advantage of binary fields built using extension towers, which leads to hardware-friendly operations. The construction also lets us concatenate several elements and interpret them as elements of an extension field. The commitment scheme is based on brakedown, which uses Merkle trees and Reed-Solomon encoding. The scheme results in larger proofs and longer verification times than FRI, but the prover’s time is significantly reduced. However, the benefits in terms of prover time generally outweigh those of longer verification times. Besides, using recursive proofs can further reduce the proof size, or we could use one final SNARK, such as Groth16 or Plonk, to achieve smaller proofs to post to L1. In the following posts, we will look deeper at the commitment scheme and the different protocols for the SNARK.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>If you don&#x27;t know, look it up or how to create lookup tables for zero knowledge proofs</title>
          <pubDate>Thu, 02 Nov 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/lookups/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/lookups/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/lookups/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;ZK-SNARKs (zero-knowledge succinct, non-interactive arguments of knowledge) and STARKs (scalable transparent arguments of knowledge) are powerful cryptographic constructions with applications in decentralized private computing and blockchain scaling. They allow one party, the prover, to show that he carried a computation correctly to a second party, the verifier, in a way that is both memory and time-efficient. In other words, the prover can submit a short proof (more concise than sending all the values involved in the calculation), which can be verified in less time than we would need for the independent re-execution of the computation. These constructions rely on encoding the information as polynomials, committing to them (via a polynomial commitment scheme, such as FRI or KZG), and showing that certain relationships hold between polynomials. For an introduction to these concepts, see our previous posts on &lt;a href=&quot;&#x2F;diving-deep-fri&#x2F;&quot;&gt;STARKs&lt;&#x2F;a&gt;, &lt;a href=&quot;&#x2F;all-you-wanted-to-know-about-plonk&#x2F;&quot;&gt;Plonk&lt;&#x2F;a&gt;, &lt;a href=&quot;&#x2F;groth16&#x2F;&quot;&gt;Groth 16&lt;&#x2F;a&gt; or the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;zkhack.dev&#x2F;whiteboard&#x2F;&quot;&gt;introductory videos by Dan Boneh&lt;&#x2F;a&gt; at zkhack.&lt;&#x2F;p&gt;
&lt;p&gt;The first step is transforming code into a system of polynomial equations over a finite field. This is known as arithmetization, and typical arithmetization schemes are R1CS (rank one constraint system), Plonkish, and AIR (algebraic intermediate representation). Some operations are expensive to arithmetize, which can lead to signficant costs for the prover. Lookup arguments are a powerful technique that helps us solve this problem by having a precomputed table of values (it can also be dynamic). In this blog post, we will cover the basics of lookup arguments and describe the PlookUp scheme. The topic has been discussed in the ongoing &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;sparkling_water_bootcamp&#x2F;blob&#x2F;main&#x2F;README.md&quot;&gt;Sparkling Water Bootcamp&lt;&#x2F;a&gt;, where we will provide an implementation of the different lookups in our library, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&quot;&gt;Lambdaworks&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;examples-and-working-principle&quot;&gt;Examples and working principle&lt;&#x2F;h2&gt;
&lt;p&gt;Suppose we want to check that a variable $a$ has to be in a prescribed range, such as a &lt;code&gt;u8&lt;&#x2F;code&gt;. One simple yet ineffective way to do so is to express $a$ in its binary form $a_0 a_1 a_2 a_3 a_4 a_5 a_6 a_7$ and check that:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Every variable is boolean $a_i (1 - a_i ) = 0$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. $a = \sum a_k 2^k$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This approach makes us add several additional constraints, which scale proportionally with the number of bits. Another approach could be showing that the number is contained in the list of all valid values for the variable. This is an example of a lookup operation. The first lookup arguments depended on the table size (we paid the price both for the lookup operations we did and for the whole table). At the same time, newer constructions make us pay the price only for the number of lookup operations (plus some preprocessing). If we have to do just a few lookup operations, then using these arguments does not pay off (we could accept having more constraints). Still, as the number or complexity of the operations increases, it makes sense to support lookups.&lt;&#x2F;p&gt;
&lt;p&gt;We can prove bitwise operations using lookup tables. For example, for the exclusive or between two bytes $a$ and $b$, $c = a \oplus b$, we can use the arithmetic constraints to represent the operations,&lt;br &#x2F;&gt;
$a_i (1 - a_i ) = 0$&lt;br &#x2F;&gt;
$b_i (1 - b_i ) = 0$&lt;br &#x2F;&gt;
$a_i + b_i - 2a_i b_i - c_i = 0$&lt;br &#x2F;&gt;
We could also have a list with all possible combinations, $a$, $b$, and $c$. Given that each byte takes 256 different values ($2^8$), we could have a table listing all valid input&#x2F;output trios ($2^{ 16 } = 65536$) and check that our $(a , b, c)$ are in that list.&lt;&#x2F;p&gt;
&lt;p&gt;To prove inclusion, we will use tricks similar to those we applied for the &lt;a href=&quot;&#x2F;all-you-wanted-to-know-about-plonk&#x2F;&quot;&gt;permutation arguments&lt;&#x2F;a&gt;. We will first reduce the claim of our tuple $(a , b , c)$ being in table $\mathcal{T}$ to a relationship between two vectors. We will show that, for every component in the vector $f$, there exists some component in the vector $t$ such that $f_i = t_k$. We can zip the table into a single vector by performing a random folding of the columns,&lt;br &#x2F;&gt;
$t = col_0 (\mathcal{T}) + \zeta col_1 (\mathcal{T}) + \zeta^2 col_2 (\mathcal{T})$&lt;br &#x2F;&gt;
We can reduce our tuple $(a, b , c)$ to the vector $f$ by doing the same operation,&lt;br &#x2F;&gt;
$f = a +\zeta b + \zeta^2 c$&lt;&#x2F;p&gt;
&lt;p&gt;To be able to apply a kind of permutation argument, we should know the number of times every element in $f$ appears in $t$, which can be something problematic. Instead, we can work with randomized differences over sorted vectors. This method was introduced in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2020&#x2F;315.pdf&quot;&gt;PlookUp paper&lt;&#x2F;a&gt;. We build a vector $s$, which results from concatenating the vectors $f$ and $t$ and sorting them by the order they appear in $t$. If the set of non-zero consecutive differences in $s$ is the same as $t$, then this proves that $f$ has all its values in the set given by $t$. If the values of $t$ appear more than once in $f$, the consecutive differences will yield $0$ for equal elements, thus eliminating them from the checks. The randomized differences avoid having to check the initial values,&lt;br &#x2F;&gt;
$\Delta s_i = s_i + \beta’ s_{i + 1}$&lt;br &#x2F;&gt;
$\Delta t_i = t_i + \beta’ t_{i + 1}$&lt;br &#x2F;&gt;
In the case of randomized differences, even if the consecutive elements are the same, the difference will be non-zero. However, we know that the differences will be multiples of $1 + \beta’$, which allows us to identify them. The check involves two bivariate polynomials, $F$ and $G$,&lt;br &#x2F;&gt;
$F = (1 + \beta’)^n \prod (\gamma’ + f_j) \prod (\gamma’ (1 + \beta’ ) + \Delta t_i )$&lt;br &#x2F;&gt;
$G = \prod (\gamma’ (1 + \beta’ ) + \Delta s_i )$&lt;br &#x2F;&gt;
If these two polynomials are the same, we have proven that all the values of $f$ are contained in the set given by $t$.&lt;br &#x2F;&gt;
As in the permutation check, it is useful to define the vector $z$, defined by:&lt;br &#x2F;&gt;
$$z_0 = 1$$&lt;br &#x2F;&gt;
$$z_i = \prod \frac{(1 + \beta’)(\gamma’ + f_i )(\gamma’(1 + \beta’) + \Delta t_i )}{(\gamma’ (1 + \beta’ ) + s_{2i - 1} + \beta’ s_{2i } )(\gamma’ (1 + \beta’ ) + s_{2i} + \beta’ s_{2i + 1} )}$$&lt;br &#x2F;&gt;
We can then interpolate the values of $z$ to obtain the polynomial $z (x)$ which must satisfy the conditions:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. $z (x = 1) = 1$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. $z (x = g^N ) = 1$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. $z(x) U(x) - z(gx) V(x) = 0$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;where the polynomials $U(x)$ and $V(x)$ result from the interpolation of the polynomials $F$ and $G$, respectively. These constraints must be added to the constraints of the proof system we are using.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;plonk-and-lookup-tables&quot;&gt;Plonk and Lookup tables&lt;&#x2F;h2&gt;
&lt;p&gt;For a recap of the Plonk protocol, we recommend reading our &lt;a href=&quot;&#x2F;all-you-wanted-to-know-about-plonk&#x2F;&quot;&gt;previous post&lt;&#x2F;a&gt; or the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;tree&#x2F;main&#x2F;docs&#x2F;src&#x2F;plonk&quot;&gt;Lambdaworks docs&lt;&#x2F;a&gt;. Plonk’s arithmetization used selector variables $q_l , q_r , q_m , q_o , q_c$ to describe the different types of gates, which for a valid execution $(a , b , c)$ should satisfy the following equations:&lt;br &#x2F;&gt;
$q_l (x) a(x) + q_r (x) b(x) + q_m a(x) b(x) + q_o (x) c(x) + q_c (x) + pi(x) = 0$&lt;br &#x2F;&gt;
When introducing lookups into Plonk, we add a new selector variable, $q_{lu}$. This variable will equal $1$ when the values of $(a, b, c)$ must be checked to belong to a given table. The other selectors will be zero in that case, which will trivially satisfy the equations for the other types of gates. We recommend following the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2022&#x2F;086.pdf&quot;&gt;PlonkUp paper&lt;&#x2F;a&gt; for further details.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;setup-and-preprocessed-input&quot;&gt;Setup and preprocessed input&lt;&#x2F;h3&gt;
&lt;p&gt;In Plonk we start with the common preprocessed input, which consists of the selector polynomials, $q_l(x) , q_r (x), q_m (x), q_o (x) , q_C (x)$, plus the copy constraint polynomials $S_{\sigma 1} (x) , S_{\sigma 2} (x) , S_{\sigma 3} (x)$. In the case of lookups, we have more preprocessed information, such as $q_{lu} (x)$, $col_0 (\mathcal{T}) (x) , col_1 (\mathcal{T}) (x) , col_2 (\mathcal{T}) (x)$.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;round-1-committing-to-an-execution-of-the-circuit&quot;&gt;Round 1 - Committing to an execution of the circuit&lt;&#x2F;h3&gt;
&lt;p&gt;Round 1 in the Plonk protocol consists of interpolating the column polynomials $a(x)$, $b(x)$, and $c(x)$ and committing to them. This way, the prover commits to a given execution of the circuit, and he won’t be able to change the values of the execution trace.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;round-2-enter-lookups&quot;&gt;Round 2 - Enter Lookups&lt;&#x2F;h3&gt;
&lt;p&gt;When we have lookups, we add a new round. We will call it Round 2. Here, the prover will zip the table into a vector and start all the work to prove the lookup arguments. The prover samples the folding coefficient $\zeta$ for the table and wirings and obtains the compressed table and queries,&lt;br &#x2F;&gt;
$t = col_0 (\mathcal{T}) + \zeta col_1 (\mathcal{T}) + \zeta^2 col_2 (\mathcal{T})$&lt;br &#x2F;&gt;
$f^\prime = a +\zeta b + \zeta^2 c$&lt;br &#x2F;&gt;
This last polynomial needs blindings to make them zero-knowledge, following the same recipe from Round 1:&lt;br &#x2F;&gt;
$f(x) = f^\prime (x) + Z_H (x) (b_7 + b_8x)$&lt;br &#x2F;&gt;
After that, the prover builds the vector $s$, sorted by $t$. Since this vector’s length is greater than the size of the domain $H$ over which we interpolated $t$ and $f$, we break it down into two parts, $h_1$ and $h_2$, and we create the polynomials $h_1 (x)$ and $h_2 (x)$. Two common approaches exist for breaking the polynomial: take the first half and interpolate and then the second half or split into odd and even terms. The second approach needs one check less, so we will adopt that strategy here, following &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2022&#x2F;086.pdf&quot;&gt;PlonkUp&lt;&#x2F;a&gt;. Since the polynomials $h_1 (x)$ and $h_2 (x)$ contain information about the witness, we also add blindings to these polynomials.&lt;&#x2F;p&gt;
&lt;p&gt;The round ends with the commitment of the queries’s polynomial, $f(x)$, and the parts of the sorted vector $h_1 (x)$, and $h_2 (x)$.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;round-3-computing-the-permutation-and-plookup-polynomials&quot;&gt;Round 3 - Computing the permutation and Plookup polynomials&lt;&#x2F;h3&gt;
&lt;p&gt;Round 3 involves the calculation of the copy constraint polynomial, $z_1 (x)$, and the Plookup polynomial, $z_2 (x)$. The permutation argument polynomial, $z_1 (x)$ is given by the following three terms:&lt;br &#x2F;&gt;
$$z_{11} = (b_{14} x^2 + b_{15} x + b_{16} ) Z_H (x)$$&lt;br &#x2F;&gt;
$$z_{12} = L_{1} (x)$$&lt;br &#x2F;&gt;
$$z_{13} = \sum L_{i + 1} (x) \prod \frac{(\gamma + \beta \omega^i + a_i )(\gamma + k_1 \beta\omega^i + b_i )(\gamma + k_2 \beta\omega^i + c_i )}{(\gamma + \beta S_{\sigma 1,i} + a_i )(\gamma + k_1 \beta S_{\sigma 2, i} + b_i )(\gamma + k_2 \beta S_{\sigma 3,i} + c_i )}$$&lt;br &#x2F;&gt;
The first term corresponds to the blinding polynomial, the second is the first Lagrange basis polynomial (it is one if $x = g$ and zero elsewhere), and the third one contains the grand product.&lt;&#x2F;p&gt;
&lt;p&gt;The Plookup polynomial $z_2 (x)$ looks very similar, given by three terms,&lt;br &#x2F;&gt;
$$z_{21} = (b_{17} x^2 + b_{18} x + b_{19} ) Z_H (x)$$&lt;br &#x2F;&gt;
$$z_{22} = L_{1} (x)$$&lt;br &#x2F;&gt;
$$z_{23} = \sum L_{i + 1} (x) \prod \frac{( 1 + \beta’ )( \gamma’ + f_i )(\gamma’(1 + \beta’) + t_i + \beta’ t_{i + 1} )}{(\gamma’ (1 + \beta’ ) + s_{2i - 1} + \beta’ s_{ 2i } )(\gamma’ (1 + \beta’ ) + s_{2i} + \beta’ s_{2i + 1} )}$$&lt;&#x2F;p&gt;
&lt;p&gt;These polynomials are best calculated by obtaining the components for the grand product check (in evaluation form) and then interpolating using the fast Fourier transform. The prover commits to these two polynomials.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;round-4-transforming-into-quotients&quot;&gt;Round 4 - Transforming into Quotients&lt;&#x2F;h3&gt;
&lt;p&gt;Round 4 computes the linear combination of the constraint polynomial, the copy constraint polynomial, and the Plookup constraints. We have the following constraints:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. All the assignments have to satisfy the general gates equations.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. The permutation check polynomial $z_1 (x)$ should equal one at the first evaluation point. Using the machinery we learned in STARKs, we could translate the condition as  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$\frac{z_1 (x) - 1}{x - g^1}$$&lt;br &#x2F;&gt;
should be a polynomial. We can transform it into a more suitable form (so that all the constraints have the same vanishing polynomial)&lt;br &#x2F;&gt;
$$L_1 (x) (z_1 (x) - 1)$$
3. The permutation argument’s constraints&lt;br &#x2F;&gt;
$$\begin{align}&lt;br &#x2F;&gt;
(\gamma + \beta x + a (x) )(\gamma + k_1 \beta x + b (x) )(\gamma + k_2 \beta (x) + c (x) )z_1 (x) &amp;amp;- \newline&lt;br &#x2F;&gt;
(\gamma + \beta S_{\sigma 1} (x) + a (x) )(\gamma + k_1 \beta S_{\sigma 2} (x) + b (x) )(\gamma + k_2 \beta S_{\sigma 3} (x) + c (x) )z_1 (g x)&lt;br &#x2F;&gt;
\end{align}$$
4. Enforcing the lookup gates,&lt;br &#x2F;&gt;
$q_{lu} (x) ( a(x) + \zeta b(x) + \zeta^2 c(x) - f (x) )$
5. The product check for the Plookup polynomial&lt;br &#x2F;&gt;
$$\begin{align}&lt;br &#x2F;&gt;
(1 + \beta’)(\gamma’ + f(x) )(\gamma’(1 + \beta’) + t(x) + \beta’ t(g x)) z_2 (x) &amp;amp;- \newline&lt;br &#x2F;&gt;
(\gamma’ (1 + \beta’ ) + h_{1} (x) + \beta’ h_{2} (x) )(\gamma’ (1 + \beta’ ) + h_{2} (x) + \beta’ h_1 (gx) )z_2 (g x)&lt;br &#x2F;&gt;
\end{align}$$
6. The Plookup polynomial should be equal to one at the first point,&lt;br &#x2F;&gt;
$L_1 (x) (z_2 (x) - 1)$&lt;&#x2F;p&gt;
&lt;p&gt;All the constraints should hold over the interpolation domain. Each polynomial is divisible then by $Z_H (x)$, and so is the random linear combination of the polynomials. The result is the quotient polynomial, $q (x)$, which is split into three parts, each of at most degree $N + 1$&lt;br &#x2F;&gt;
$q (x) = q_{lo} (x) + x^{N + 2} q_{mid} (x) + x^{2N + 4} q_{hi} (x)$&lt;&#x2F;p&gt;
&lt;p&gt;The prover commits to each of the parts.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;round-5-evaluations&quot;&gt;Round 5 - Evaluations&lt;&#x2F;h3&gt;
&lt;p&gt;Round 5 computes the evaluations of several polynomials at a random point $z$ and sends them to the verifier so that he has enough information to check the relationship between the quotient and the original polynomial. The prover samples from the transcript $z$ and computes:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $a(z)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $b(z)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $c(z)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $S_{\sigma 1} (z)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $S_{\sigma 2} (z)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $f(z)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $t(z)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $t (gz)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $z_1 (gz)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $z_2 (gz)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $h_1 (gz)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $h_2 (z)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;round-6-wrapping-the-proof&quot;&gt;Round 6 - Wrapping the proof&lt;&#x2F;h3&gt;
&lt;p&gt;Round 6 performs the linearizations and generates the opening proof. So far, the prover has given commitments to polynomials and their evaluations at some point. It’s time to link both and produce the evaluation proof. First, the prover computes the linearization polynomial, $r (x)$, which should equal $0$ at $z$. The prover computes the proof for the evaluation of all the polynomials listed in round 5 at $z$,&lt;br &#x2F;&gt;
$$W_z (x) = \frac{1}{x - z}(r(x) + \sum \alpha^i (p_i(x) - p_i (z)))$$&lt;br &#x2F;&gt;
He does the same for the polynomials at $gz$,&lt;br &#x2F;&gt;
$$W_{gz} (x) = \frac{1}{x - gz}(\sum \alpha^i (p_i(x) - p_i (gz)))$$&lt;&#x2F;p&gt;
&lt;p&gt;The prover commits to these quotient polynomials.&lt;&#x2F;p&gt;
&lt;p&gt;All the evaluations at Round 5 give the proof, plus the commitments to all the polynomials from Rounds 1, 2, 3, 4, and 6.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;In this post, we covered the basics of lookup arguments, which let us prove that specific calculations are correct by checking their results in a table that contains all valid input&#x2F;output relations. These techniques can result in significant savings when we try to prove difficult or expensive operations to arithmetize, such as range checks or bitwise operations (which can be extensively used). We described the working principles of Plookup, which was among the first arguments to be presented. It can be integrated very neatly into the Plonk protocol, but it results in an extra cost since we have the calculation time increases with table size. Recent constructions reduce the cost associated with the size of the table, paying just a price proportional to the number of lookups. In upcoming posts, we will cover how to code the Plookup protocol and newer lookup arguments.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Have you checked your sums?</title>
          <pubDate>Thu, 26 Oct 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/have-you-checked-your-sums/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/have-you-checked-your-sums/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/have-you-checked-your-sums/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;There has recently been a growing interest in zk-SNARKs (zero-knowledge, succinct, non-interactive arguments of knowledge) due to their capabilities in decentralized private computations and scaling blockchains. These constructions involve a protocol between two parties, a prover and a verifier, where the former attempts to convince the latter of the validity of a given statement. Sometimes, the prover tries to do this without revealing sensitive information. We want the work needed for the verifier to check the statement to be significantly smaller than just doing it himself. For example, we would like to delegate an expensive computation to an untrusted server (for which we do not have the necessary resources) and be able to verify the correctness of the computation using a smartphone. The zero-knowledge property allows us to prove the possession of some secret (such as a private key or the preimage of some hash) without giving that information to the verifier. At the heart of these constructions, we have polynomials and can reduce the statement to some relation between polynomials. For example, &lt;a href=&quot;&#x2F;lambdaworks-or-how-we-decided-to-created-our-zksnarks-library-and-a-stark-prover&#x2F;&quot;&gt;STARKs&lt;&#x2F;a&gt; uses univariate polynomials and the FRI protocol to prove the correctness of a given computation. The sumcheck protocol, which involves polynomials in several variables, can be used to build SNARKs.&lt;&#x2F;p&gt;
&lt;p&gt;In this post, we will first describe how to encode vectors as multilinear polynomials (similar to how we encoded vectors as univariate polynomials) and how the sumcheck protocols work. We are currently implementing the sumcheck protocol and multilinear polynomials as part of the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;sparkling_water_bootcamp&#x2F;tree&#x2F;main&quot;&gt;learning path of the Sparkling Water Bootcamp&lt;&#x2F;a&gt;; you can follow the development at &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&quot;&gt;Lambdaworks&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;encoding-vectors-as-multilinear-polynomials&quot;&gt;Encoding vectors as multilinear polynomials&lt;&#x2F;h2&gt;
&lt;p&gt;A polynomial $p$ in $n$ variables is called multilinear if the degree of each variable $x_i$ is at most one in every term. For example, $p_1 (x_1 , x_2 , x_3 , x_4 ) = x_1 + 2 x_2 + x_1 x_2 x_4 x_3$ is a multilinear polynomial because the power of each $x_i$ is either $0$ or $1$ in each term. The polynomial $p_2 (x_1 , x_2 ) = x_1 x_2^2$ is not, since the degree of $x_2$ is $2$. The total degree of a multilinear polynomial is the highest sum of all the powers of a term (monomial). For $p_1$, this is 4. For multilinear polynomials, the maximum degree is at most $m$.&lt;&#x2F;p&gt;
&lt;p&gt;We will restrict ourselves now to polynomials defined over the set $D = { 0 , 1 }^m$. Given a function $f$ defined over $D$, we can define a multilinear polynomial $p(x_1, x_2, … , x_m )$ such that $p$ coincides with $f$ over the set $D$, that is $p(x) = f (x)$ for every $x \in D$. Since this polynomial is unique, the polynomial $p$ is called the multilinear extension of $f$.&lt;&#x2F;p&gt;
&lt;p&gt;We can use the multilinear extension to represent a vector $v$ containing $2^m$ elements. Suppose the vector $v$ ’s elements belong to some finite field $\mathbb{F}$. We first create the function $f: D \rightarrow \mathbb{F}$, which maps each element of $D$ into an element of $v$. One easy way to do this is by representing the position in the vector $k$ in its bit form. For example, if the vector has 256 elements, we need $8$ variables (bits), and we can define the map as:&lt;br &#x2F;&gt;
$f(0, 0, 0, 0, 0, 0, 0, 0) = v_0$&lt;br &#x2F;&gt;
$f(0, 0, 0, 0, 0, 0, 0, 1) = v_1$&lt;br &#x2F;&gt;
$f(0, 0, 0, 0, 0, 0, 1, 0) = v_2$&lt;br &#x2F;&gt;
$f(0, 0, 0, 0, 0, 0, 1, 1) = v_3$&lt;br &#x2F;&gt;
$\vdots$&lt;br &#x2F;&gt;
$f(1, 1, 1, 1, 1, 1, 1, 1) = v_{255}$&lt;br &#x2F;&gt;
In general form, we assign to a tuple $(x_0, x_1, … x_{m - 1} )$ the value corresponding to index $k = x_0 + 2 x_1 + 4x_2 + \dots + 2^{m - 1} x_{ m - 1 }$. Then, we can use the fact that the multilinear extension of $f$ exists and create it by Lagrange interpolation, for example. Thus,&lt;br &#x2F;&gt;
$p(x_0 , x_1 , … x_{m - 1} ) = \sum_{ x_0 , …, x_{ m -1} } f(k) B_k (x_0 , x_1 , … , x_{ m - 1} )$&lt;br &#x2F;&gt;
where $B_k$ is the Lagrange basis polynomial, which equals one when $(x_0 , x_1 , … , x_{ m -1 })$ corresponds to the binary representation of $k$ and zero otherwise. If we represent $k = (k_0, k_1 , … k_{ m - 1})$ (remember each $k_i$ is either 0 or 1), the function $B_k(x_0, x_1, … x_{ m - 1 })$ has the explicit expression&lt;br &#x2F;&gt;
$B_k (x_0 , x_1 , …, x_{ m - 1}) = \prod ( x_i k_i + (1 - x_i ) (1 - k_i))$&lt;&#x2F;p&gt;
&lt;p&gt;For example, if we have the vector $v = ( 2, 5, 7, 8)$, we have four Lagrange basis polynomials:&lt;br &#x2F;&gt;
$B_0 (x_0 , x_1 ) = (1 - x_0) (1 - x_1 ) = 1 - x_1 - x_0 + x_1 x_0$&lt;br &#x2F;&gt;
$B_1 (x_0 , x_1 ) = x_0 (1 - x_1 ) = x_0 - x_0 x_1$&lt;br &#x2F;&gt;
$B_2 (x_0 , x_1 ) = (1 - x_0 ) x_1 = x_1 - x_0 x_1$&lt;br &#x2F;&gt;
$B_3 (x_0 , x_1 ) = x_0 x_1$&lt;br &#x2F;&gt;
and&lt;br &#x2F;&gt;
$p(x_0 , x_1) = 2 B_0 + 5 B_1 + 7 B_2 + 8 B_3$&lt;br &#x2F;&gt;
Replacing everything,&lt;br &#x2F;&gt;
$p(x_0 , x_1) = 2 + 3 x_0 + 5 x_1 - 2 x_0 x_1$&lt;&#x2F;p&gt;
&lt;p&gt;This way, we have encoded our vector as a multilinear polynomial in two variables. We could generally encode a vector of length $n$ as a polynomial in $\lceil{\log_2 (n)} \rceil$ variables. We can then use this encoding to reduce the validity of some calculation to the sum of this polynomial over all possible values of $x_0, x_1 … x_n$.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-sumcheck-protocol&quot;&gt;The sumcheck protocol&lt;&#x2F;h2&gt;
&lt;p&gt;The sumcheck protocol is an interactive proof introduced in 1992 with a fundamental role in the theory of probabilistic proofs in complexity theory and cryptography, leading to the construction of succinct arguments. One of its essential properties is that the prover can be implemented in a number of operations that scale linearly (that is, its running time is $\mathcal{O} (n)$), which has a better asymptotic complexity than algorithms based on the Fast Fourier Transform ($\mathcal{O} (n \log n)$). It also provides the basis for folding techniques for Pedersen commitments in the discrete logarithm setting. For an in-depth explanation of the protocol, look at &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;people.cs.georgetown.edu&#x2F;jthaler&#x2F;ProofsArgsAndZK.pdf&quot;&gt;proofs, arguments and zero-knowledge&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2021&#x2F;333.pdf&quot;&gt;sumcheck arguments and their applications&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The sumcheck protocol yields an interactive proof for statements of the form&lt;br &#x2F;&gt;
$$\sum_{ x \in H^m } p(x) = S$$&lt;br &#x2F;&gt;
that is, the sum of all the evaluations of an $m$-variate polynomial over a domain equals $S$. The prover is given the polynomial $p(x)$, and the verifier will send him random challenges, $r_k$, from a set $\mathcal{C}$ and receive polynomials $q_k(x)$, which will allow him to be convinced that the statement is true. The protocol will reduce the workload of the verifier from having to evaluate the $m$-variate polynomial over $\vert H \vert^m$ (for example, if the size of $H$, $\vert H\vert$, is two and we have 16 variables, we need to do $2^{16}$ evaluations) to a single evaluation over a random point over $\mathbb{F}^m$, plus some additional smaller operations.&lt;&#x2F;p&gt;
&lt;p&gt;The protocol proceeds in rounds and works as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. The prover sends to the verifier the polynomial  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$q_k (x) = \sum_{ a_j \in H , j \geq k + 1 } p(r_1, r_2, …, r_{ k - 1 }, x, a_{ k + 1}, … a_{m})$$
2. The verifier checks that $\sum_{a_1 \in H} q_1 (a_1) = S$ and $\sum_{a_k \in H} q_k ( a_k ) = q_{ k - 1 }( r_{k - 1})$.
3. If all checks pass, the verifier outputs $v = q_m ( r_m )$ and outputs $r_1 , r_2 , …, r_m , v$.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s explain the protocol in simple terms. In the first round, the prover sends the verifier a polynomial $q_1 (x_1 )$ by summing over all possible values of the rest of the variables. This way, the verifier can check the sum by evaluating the polynomial $q_1 (x_1)$ over all its values, which is much faster than summing over all the variables. However, how does the verifier know that the prover did not cheat and send some fake polynomial $q_1 (x_1)$? The verifier sends a random challenge $r_1$, and the prover responds with a new polynomial of one variable, $q_2 (r_1, x_2)$, which is obtained by fixing the first coordinate and summing over all the other variables except $x_2$. If we evaluate $q_1 (r_1 )$, we should get the same as adding over all possible values of $q_2 (x_2 )$ (because $q_1$ was obtained by summing over all values of $x_2$). The verifier always has to do a few evaluations of a univariate polynomial.&lt;&#x2F;p&gt;
&lt;p&gt;If the challenge subset $\mathcal{C}$ is a sampling subset, then the sumcheck protocol satisfies:&lt;&#x2F;p&gt;
&lt;p&gt;a. Completeness.&lt;br &#x2F;&gt;
b. Soundness, where the soundness error is bounded by $m d&#x2F; \vert \mathcal{C} \vert$ (the number of variables, the maximum degree in the polynomial, and the number of elements in the challenge subset).&lt;&#x2F;p&gt;
&lt;p&gt;In many cases, we would like to work with $H^m = \{ 0,1 \}^m$, so that $x = (x_1 , x_2 , … , x_m)$ is the collection of all bitstrings of length $m$ and we can use the encoding for vectors as multilinear polynomials.&lt;&#x2F;p&gt;
&lt;p&gt;To make the sumcheck protocol zero-knowledge, we need to mask the polynomial. We can achieve this by adding a random polynomial.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;In this post, we covered the sumcheck protocol, which is at the heart of some SNARKs. It allows the verifier to check that the sum of the evaluations of some multivariate polynomial over a set is equal to some number by delegating most of the computational burden to the prover. The protocol involves a number of rounds equal to the number of variables, where the prover sends at each round a univariate polynomial, and the verifier responds by sending a random challenge. The verifier’s highest cost is involved in evaluating the multivariate at one random point, significantly less than trivial verification. In an upcoming post, we will cover how to implement the sumcheck protocol from scratch.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>An overview of the Groth16 proof system</title>
          <pubDate>Tue, 17 Oct 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/groth16/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/groth16/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/groth16/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;Over the last decade, SNARKs (succinct, non-interactive arguments of knowledge) and STARKs (scalable, transparent arguments of knowledge) have been gaining attention due to their applications in verifiable private computation and scalability of blockchains.&lt;&#x2F;p&gt;
&lt;p&gt;Groth introduced this &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2016&#x2F;260.pdf&quot;&gt;proof system&lt;&#x2F;a&gt; in 2016 and saw an early application in ZCash. The protocol relies on pairing-friendly elliptic curves, such as BN254, BLS12-381, and BLS12-377 (more later). Its proof size is among the smallest (consisting of only three elliptic curve elements) and fastest to verify. The main drawback is that it needs a trusted setup per program. In other words, we need to regenerate all the parameters whenever we want to prove a new program (or change the original one).&lt;&#x2F;p&gt;
&lt;p&gt;In this post, we will describe the main ingredients of Groth16 and how it works. As stated in the roadmap, we are implementing the protocol in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&quot;&gt;Lambdaworks library&lt;&#x2F;a&gt;. It is also used as a project in the ongoing &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;sparkling_water_bootcamp&#x2F;tree&#x2F;main&quot;&gt;Sparkling Water Bootcamp&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;arithmetization&quot;&gt;Arithmetization&lt;&#x2F;h2&gt;
&lt;p&gt;To prove the execution of a given program, we have to transform it to a SNARK (succinct, non-interactive argument of knowledge) friendly form. One of such forms is arithmetic circuit satisfiability, where one can prove knowledge of a valid circuit assignment. This first step, known as arithmetization, is the program’s transformation into an arithmetic circuit or equivalent form.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;r1cs&quot;&gt;R1CS&lt;&#x2F;h2&gt;
&lt;p&gt;Arithmetic circuits can be expressed equivalently as (quadratic) rank one constraint systems (R1CS), which are systems of equations of the form:&lt;br &#x2F;&gt;
$$(Az)\times (Bz) = Cz$$&lt;br &#x2F;&gt;
where $A, B, C$ are matrices of size $m + 1$ rows by $n + 1$ columns, $z$ is a (column) vector of size $n + 1$ and $\times$ indicates the componentwise product of the resulting vectors.&lt;&#x2F;p&gt;
&lt;p&gt;We can alternatively view this compact form as&lt;br &#x2F;&gt;
$\left( \sum_k a_{0k} z_k \right) \left( \sum_k b_{0k} z_k \right) - \left( \sum_k c_{0k} z_k \right) = 0$&lt;br &#x2F;&gt;
$\left( \sum_k a_{1k} z_k \right) \left( \sum_k b_{1k} z_k \right) - \left( \sum_k c_{1k} z_k \right) = 0$&lt;br &#x2F;&gt;
$\left( \sum_k a_{2k} z_k \right) \left( \sum_k b_{2k} z_k \right) - \left( \sum_k c_{2k} z_k \right) = 0$&lt;br &#x2F;&gt;
$\vdots$&lt;br &#x2F;&gt;
$\left( \sum_k a_{mk} z_k \right) \left( \sum_k b_{mk} z_k \right) - \left( \sum_k c_{mk} z_k \right) = 0$&lt;&#x2F;p&gt;
&lt;p&gt;We could express these equations more compactly by using polynomials and prove the solution of the R1CS system more concisely. To this end, we will introduce quadratic arithmetic programs, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;vitalik.ca&#x2F;general&#x2F;2016&#x2F;12&#x2F;10&#x2F;qap.html&quot;&gt;QAP&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;quadratic-arithmetic-program&quot;&gt;Quadratic Arithmetic Program&lt;&#x2F;h2&gt;
&lt;p&gt;We can interpret each column of the $A$ matrix as evaluations of some polynomial over some suitable domain. This is a common practice in many SNARKs, where we try to encode a vector as a polynomial; see, for example, our &lt;a href=&quot;&#x2F;diving-deep-fri&#x2F;&quot;&gt;post about STARKs&lt;&#x2F;a&gt;. We sample $D_0 = { x_0 , x_1 , … , x_n }$ over the finite field and define the polynomial $A_i (x)$ as the polynomial of at most degree $n$ such that $A_i ( x_k ) = a_{ki}$.&lt;&#x2F;p&gt;
&lt;p&gt;For performance reasons, it is convenient to select as interpolation domain $D_0$ the n-th roots of unity since we can use the Fast Fourier Transform to interpolate. Similarly, we can interpret the columns of $B$ and $C$ as polynomials $B_k (x)$ and $C_k (x)$. Taking advantage of these polynomials, we can express the R1CS system in polynomial form,&lt;br &#x2F;&gt;
$P (x) = \left( \sum_k A_{k} (x) z_k \right) \left( \sum_k B_{k} (x) z_k \right) - \left( \sum_k C_{k} (x) z_k \right)$&lt;&#x2F;p&gt;
&lt;p&gt;We can see that if we have a valid solution for the R1CS, the polynomial $P (x)$ evaluates to $0$ over $D_0$ (since we require the polynomial to interpolate the values of the columns of the matrices). Therefore, we can express the condition as&lt;br &#x2F;&gt;
$P (x) = 0$ for $x \in D_0$&lt;br &#x2F;&gt;
We now introduce the vanishing polynomial over the set $D_0$, $Z_D (x) = \prod_k (x - x_k )$&lt;br &#x2F;&gt;
So, if the polynomial $P (x)$ evaluates to $0$ over $D_0$, it is divisible by $Z_D (x)$. This can be written as there is some polynomial $h (x)$ such that&lt;br &#x2F;&gt;
$P (x) = h(x) Z_D (x)$&lt;br &#x2F;&gt;
The degree of the polynomial $h(x)$ is the degree of $P$ minus the degree of $Z_D$. An honest prover should be able to find the resulting quotient and use it to show that he correctly executed the program.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;transforming-qap-into-a-zero-knowledge-proof&quot;&gt;Transforming QAP into a zero-knowledge proof&lt;&#x2F;h2&gt;
&lt;p&gt;We need to make some transformation to the above problem if we want to turn it into a zero-knowledge proof. For a more detailed description of this process, see &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.rareskills.io&#x2F;post&#x2F;groth16&quot;&gt;here&lt;&#x2F;a&gt;. We must ensure that the prover cannot cheat and that the verifier cannot learn anything about the private input or witness. One key ingredient is a polynomial commitment scheme (PCS): we can make the prover commit to a given polynomial so that he cannot change it later. One such commitment scheme is the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;dankradfeist.de&#x2F;ethereum&#x2F;2020&#x2F;06&#x2F;16&#x2F;kate-polynomial-commitments.html&quot;&gt;KZG commitment&lt;&#x2F;a&gt;, where we use &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;static1.squarespace.com&#x2F;static&#x2F;5fdbb09f31d71c1227082339&#x2F;t&#x2F;5ff394720493bd28278889c6&#x2F;1609798774687&#x2F;PairingsForBeginners.pdf&quot;&gt;pairing-friendly elliptic curves&lt;&#x2F;a&gt; to bind the prover to a polynomial. The scheme’s security relies on the hardness of the discrete logarithm problem over the curve. Pairings can be considered an operation that allows a one-time multiplication between points in an elliptic curve. In our case, we will work over type3 III pairings, $\dagger : G_1 \times G_2 \rightarrow G_t$, which have the following nice property (bilinearity):&lt;br &#x2F;&gt;
$(a g_1 ) \dagger (b g_2 ) = (ab) (g_1 \dagger g_2)$&lt;br &#x2F;&gt;
To commit to a polynomial using KZG, we need to sample a random scalar $\tau$ (which is considered toxic waste and should be forgotten, or we could forge proofs) and generate the following sequence of points in the elliptic curve, whose generator is $g_1$,&lt;br &#x2F;&gt;
$P_0 = g_1$,&lt;br &#x2F;&gt;
$P_1 = \tau g_1$&lt;br &#x2F;&gt;
$P_2 = \tau^2 g_1$&lt;br &#x2F;&gt;
$\vdots$&lt;br &#x2F;&gt;
$P_n = \tau^n g_1$&lt;br &#x2F;&gt;
Then, given a polynomial $p(x) = a_0 + a_1 x + a_2 x^2 + … + a_n x^n$ we compute the commitment as&lt;br &#x2F;&gt;
$\mathrm{cm} (p) = a_0 P_0 + a_1 P_1 + … + a_n P_n$&lt;br &#x2F;&gt;
which is the same as $\mathrm{cm} (p) = p(\tau) g_1$, that is, hiding the evaluation of $p(x)$ inside the elliptic curve. Because the discrete log problem is hard, we cannot use our knowledge of $g_1$ and $\mathrm{cm} (p)$ to obtain $p(\tau)$.&lt;&#x2F;p&gt;
&lt;p&gt;To check that the polynomial $p(x)$ evaluates to $v$ at $z$ we can use the fact that&lt;br &#x2F;&gt;
$p(x) - v = (x - z)q(x)$&lt;br &#x2F;&gt;
where $q(x)$ is the quotient polynomial of the division of $p(x)$ by $x - z$. The prover can produce proof of such evaluation by committing to $q(x)$ using the same trick. Still, the verifier will need some additional information (included in the verifying key), $g_2$ (the generator of the group $G_2$), and $\tau g_2$ (remember, nobody must know $\tau$). Then, using pairings, the verifier can check the evaluation using the points in the elliptic curves,&lt;br &#x2F;&gt;
$(\mathrm{cm} (p) - vg_1 \dagger g_2) = a = p(\tau) (g_1 \dagger g_2)$&lt;br &#x2F;&gt;
$\mathrm{cm} (q) \dagger (\tau g_2 - z g_2) = b = q(\tau) ( \tau - z)(g_1 \dagger g_2)$&lt;br &#x2F;&gt;
If $a$ and $b$ are the same, and since $\tau$ is a random point with high probability, we assume that $p(z) = v$ (This depends on the Schwartz-Zippel lemma).&lt;&#x2F;p&gt;
&lt;p&gt;Remember that we want to prove that the verifier knows some $w$ and a polynomial $h(x)$ of degree $m - 1$ such that if $z= (1, x, w)$, the following condition holds&lt;br &#x2F;&gt;
$\left( \sum_k A_{k} (x) z_k \right) \left( \sum_k B_{k} (x) z_k \right) = \left( \sum_k C_{k} (x) z_k \right) + h(x)Z_D (x)$&lt;&#x2F;p&gt;
&lt;p&gt;If we force the prover first to commit to the polynomials $A_k (x)$ and $B_k (x)$ and then produce the quotient polynomial, we have to make sure that he cannot forge $C_k (x)$ to fulfill the previous condition. To do so, we are going to introduce random shifts ($\alpha$ and $\beta$) to the evaluations:&lt;br &#x2F;&gt;
$\mathrm{cm} (\sum A_i z_i ) = \sum (A_i (\tau) z_i) g_1 + \alpha g_1$&lt;br &#x2F;&gt;
$\mathrm{cm} (\sum B_i z_i) = \sum (B_i (\tau) z_i) g_2 + \beta g_2$&lt;br &#x2F;&gt;
The $B_i (x)$ are committed to using group $G_2$ so that we can compute the product on the left-hand side through a pairing,&lt;br &#x2F;&gt;
$(\mathrm{cm} (\sum A_i z_i )) \dagger ( \mathrm{cm} (\sum B_i z_i )) = (\sum A_i (\tau) z_i )(\sum B_i (\tau) z_i ) (g_1 \dagger g_2)$&lt;&#x2F;p&gt;
&lt;p&gt;Because we introduce these shifts, we need to modify the $C_k$ term accordingly,&lt;br &#x2F;&gt;
$\begin{equation}\left( \alpha + \sum_k A_{k} (x) z_k \right) \left( \beta + \sum_k B_{k} (x) z_k \right) = \ \alpha \beta + \left( \sum_k (C_{k} (x) + \beta A_k (x) + \alpha B_k (x)) z_k \right) + h(x)Z_D (x) \end{equation}$&lt;br &#x2F;&gt;
Since the prover cannot know $\alpha$ and $\beta$, we need to provide them hidden as part of the trusted setup, as $\alpha g_1$ and $\beta g_2$, so that we can compute&lt;br &#x2F;&gt;
$(\alpha g_1) \dagger (\beta g_2) = \alpha \beta (g_1 \dagger g_2)$&lt;br &#x2F;&gt;
so that we can compare this result to the pairing between the shifted $A_i$ and $B_i$.&lt;&#x2F;p&gt;
&lt;p&gt;Also, since the prover does not have $\alpha$ and $\beta$, he needs to be supplied with all the elements of the form $C_{k} (x) + \beta A_k (x) + \alpha B_k (x)$. However, when we want to calculate the product between these terms and $z$, we must recall that $z$ contains both the public input and the witness. The verifier cannot learn anything about the witness (therefore, the evaluations involving the witness should be provided by the prover). We introduce two additional variables, $\gamma$, and $\delta$, to split the variable $z$ between public input and witness. The first $k$ terms correspond to the public input, and these are encoded as&lt;br &#x2F;&gt;
$K_i^v = \gamma^{- 1} (C_{i} (\tau) + \beta A_i (\tau) + \alpha B_i (\tau)) g_1$&lt;br &#x2F;&gt;
for $i = 0, 1, 2 … , k$. For the witness, we have&lt;br &#x2F;&gt;
$K_i^p = \delta^{- 1} (C_{i} (\tau) + \beta A_i (\tau) + \alpha B_i (\tau)) g_1$&lt;br &#x2F;&gt;
With these new parameters, we get&lt;br &#x2F;&gt;
$\begin{equation}\left( \alpha + \sum_j A_{j} (x) z_j \right) \left( \beta + \sum_j B_{j} (x) z_j \right) = \ \alpha \beta + \gamma \left( \sum_i^k \gamma^{- 1} (C_{i} (x) + \beta A_i (x) + \alpha B_i (x)) x_i \right) + \&lt;br &#x2F;&gt;
\delta \left( \sum_{j = k + 1}^n \delta^{- 1} (C_{i} (x) + \beta A_i (x) + \alpha B_i (x)) x_i \right) + h(x)Z_D (x) \end{equation}$&lt;br &#x2F;&gt;
We can combine the last two terms into one (since they contain all the information that the verifier must not learn)&lt;br &#x2F;&gt;
$D = \left( \sum_{j = k + 1}^n \delta^{- 1} (C_{i} (x) + \beta A_i (x) + \alpha B_i (x)) x_i \right) + h(x)Z_D (x)\delta^{- 1}$&lt;&#x2F;p&gt;
&lt;p&gt;Since we want to compute the product $h(x) Z_D(x)$ with the help of one pairing, we can compute the following group elements,&lt;br &#x2F;&gt;
$Z_0 = \delta^{ - 1} Z_D (\tau)$&lt;br &#x2F;&gt;
$Z_1 = \delta^{ - 1} \tau Z_D (\tau)$&lt;br &#x2F;&gt;
$Z_2 = \delta^{ - 1} \tau^2 Z_D (\tau)$&lt;br &#x2F;&gt;
$\vdots$&lt;br &#x2F;&gt;
$Z_{m - 1} = \delta^{ - 1} \tau^{ m - 1 } Z_D (\tau)$&lt;&#x2F;p&gt;
&lt;p&gt;With these changes, the right-hand side of the QAP is the sum of 3 terms:&lt;br &#x2F;&gt;
A constant (related to the random shifts).&lt;br &#x2F;&gt;
A term involving the public input.&lt;br &#x2F;&gt;
A term that contains the secret terms (known only to the prover).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;setup&quot;&gt;Setup&lt;&#x2F;h2&gt;
&lt;p&gt;Groth16 requires sampling five random field elements to generate the proving and verifying key, $t, \alpha, \beta, \gamma, \delta$. These are toxic waste and should be discarded and wholly forgotten once the keys have been generated.&lt;&#x2F;p&gt;
&lt;p&gt;We will use a pairing-friendly elliptic curve (with type III pairing), with subgroups $G_1$ and $G_2$ of prime order $r$. We will call the generators $g_1$ and $g_2$, respectively. To make notation easier, we will write&lt;br &#x2F;&gt;
$[x]_1 = x g_1$&lt;br &#x2F;&gt;
$[x]_2 = x g_2$&lt;br &#x2F;&gt;
to denote points in $G_1$ and $G_2$, where $x g$ means the scalar product of $x$ and the generator of the group (i.e., applying x times the elliptic curve group operation to the generator). We will follow the notation given by &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2018&#x2F;691.pdf&quot;&gt;DIZK&lt;&#x2F;a&gt;. First, we compute the following vectors,&lt;br &#x2F;&gt;
$K_i^v (t) = \gamma^{-1} \left( \beta A_i(t) + \alpha B_i (t) + C_i (t)\right)$&lt;br &#x2F;&gt;
for $i = 0, 1, 2 , … k$,&lt;br &#x2F;&gt;
$K_i^p (t) = \delta^{-1} \left( \beta A_i(t) + \alpha B_i (t) + C_i (t)\right)$&lt;br &#x2F;&gt;
for $i = k+1, 1, 2 , … n$ and&lt;br &#x2F;&gt;
$Z_k (t) = t^k Z_D (t) \delta^{-1}$&lt;br &#x2F;&gt;
for $k = 0, 1, 2, … m - 1$.&lt;br &#x2F;&gt;
The proving key consists of the following elements:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. $[\alpha]_1$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. $[\beta]_1$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. $[\beta]_2$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. $[\delta]_1$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. $[\delta]_2$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    6. $[A_0 (t) ]_1, [A_1 (t) ]_1 , ... , [A_n (t) ]_1$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    7. $[B_0 (t) ]_1, [B_1 (t) ]_1 , ... , [B_n (t) ]_1$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    8. $[B_0 (t) ]_2, [B_1 (t) ]_2 , ... , [B_n (t) ]_2$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    9. $[K_{ k + 1 }^p (t)] , [ K_{ k + 2 }^p (t)] , ... , [K_n^p (t)]$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    10. $[Z_0 (t)] , [Z_1 (t)] , ... , [ Z_{ m - 1 } (t)]$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The verifying key is much shorter and will contain in addition the value of one pairing because that value is constant:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. $[\alpha]_1 \dagger [\beta]_2$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. $[\gamma]_2$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. $[\delta]_2$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. $[K_0^v (t)]_1 , [K_1^v (t)]_1 , ... , [K_k^v (t)]_1$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;proof-generation&quot;&gt;Proof generation&lt;&#x2F;h2&gt;
&lt;p&gt;The prover receives the proving key and knows the polynomials representing the program and the public input, and he wants to prove that he has a witness satisfying that program. First, the prover needs to calculate the quotient polynomial $h(x)$ or, more precisely, its coefficients. The prover has to calculate&lt;br &#x2F;&gt;
$$h(x) = \frac{\sum A_k(x) z_k \sum B_k (x) z_k - \sum C_k (x) z_k}{Z_D (X) }$$&lt;&#x2F;p&gt;
&lt;p&gt;The best way to evaluate this quotient is by choosing a domain $D_{ev}$, of size at least the degree of the quotient polynomial plus one and not containing elements from $D_0$ (the interpolation domain) and evaluating numerator and denominator at all the elements of $D_{ev}$. Since we have at least as many evaluations of the polynomial $h (x)$ as its degree plus one, we can reconstruct $h(x)$ via interpolation. In practice, the fastest way to do this is by using the Fast Fourier Transform for evaluation and interpolation. The prover now possesses a vector of coefficients $h_0 , h_1 , h_2 , … , h_m$.&lt;&#x2F;p&gt;
&lt;p&gt;To ensure that the proof is zero-knowledge, the prover sample two random scalars, $r$ and $s$.&lt;&#x2F;p&gt;
&lt;p&gt;The prover can compute the three elements of the proof, $\pi = ([\pi_1 ]_1 , [\pi_2 ]_2 , [\pi_3 ]_1)$ by doing the following calculations,&lt;br &#x2F;&gt;
$[\pi_1 ]_1 = [\alpha]_1 + \sum z_k [A_k (t) ]_1 + r [\delta]_1$&lt;br &#x2F;&gt;
$[\pi_2 ]_2 = [\beta]_2 + \sum z_k [B_k (t) ]_2 + s[\delta]_2$&lt;br &#x2F;&gt;
$[\pi_2 ]_1 = [\beta]_1 + \sum z_k [B_k (t) ]_1 + s[\delta]_1$&lt;br &#x2F;&gt;
$[h(t)z(t)]_1 = \sum h_i [Z_i (t)]_1$&lt;br &#x2F;&gt;
$[\pi_3 ]_1 = \sum w_i [K_i^p ]_1 + [h(t)z(t)]_1 + s[\pi_1 ]_1 + r [\pi_2 ]_1 - rs [\delta]_1$&lt;&#x2F;p&gt;
&lt;h2 id=&quot;verification&quot;&gt;Verification&lt;&#x2F;h2&gt;
&lt;p&gt;The verifier has the verifying key, the public input and parses the proof as $[\pi_1 ]_1, [\pi_2 ]_2, [\pi_3 ]_1$ and computes the following:&lt;br &#x2F;&gt;
$[\pi_1 ]_1 \dagger [\pi_2 ]_2 = P_1$&lt;br &#x2F;&gt;
$[\pi_3 ]_1 \dagger [\delta]_2 + [\alpha]_1 \dagger [\beta]_2 + \left(\sum x_i [K_i^v ]_1 \right) \dagger [\gamma]_2 = P_2$&lt;&#x2F;p&gt;
&lt;p&gt;The proof is valid if $P_1$ and $P_2$ coincide. This is equivalent to checking the modified QAP.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;In this post, we covered the Groth16 protocol, which provides a framework to prove the correctness of a computation without revealing sensitive information. It has concise proofs and an elegant verification but requires a trusted setup for every program we want to prove. We saw the steps to transform the program into arithmetic circuits or their equivalent R1CS, which can then be compiled into a quadratic arithmetic program. We explained how the protocol transforms the basic equations to ensure that the prover cannot cheat and the verifier does not learn anything about the private data. In an upcoming post, we will cover how to code Groth16 from scratch.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>An overview of the Stone Cairo STARK Prover</title>
          <pubDate>Thu, 28 Sep 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/overview-of-the-stone-prover/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/overview-of-the-stone-prover/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/overview-of-the-stone-prover/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;About one month ago, Starkware open-sourced its Stone Prover, which is currently in production in Starknet. It is a library that allows one to produce proofs of computational integrity using STARKs (Scalable Transparent Arguments of Knowledge).&lt;&#x2F;p&gt;
&lt;p&gt;The codebase has around 100k lines of code, written mainly in C++. It has the following main components:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * AIR: contains the constraints of the algebraic intermediate representation of CAIRO.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Channel (transcript in STARK Platinum): contains the interactions between the prover and verifier and gives methods to sample random challenges.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Composition polynomial. The constraints of the AIR are enforced over the trace polynomials and randomly combined into a single polynomial.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Commitment schemes: contains the methods to (cryptographically) commit to a series of polynomial evaluations.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * FRI, Fast Reed Solomon interactive oracle proofs of proximity: performs the low-degree testing that allows one to prove that a function is close to a low-degree polynomial.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;At Lambdaclass, we are working on our Cairo prover, STARK Platinum (written in Rust), being compatible with the Stone Prover so that anyone can use the Rust version to generate valid proofs for different applications built on top of Starknet. We hope that the performance and usability of our prover helps the community to adopt it.&lt;&#x2F;p&gt;
&lt;p&gt;In this post, we will analyze some of the components of the Stone Prover and explain how they work and their implementation. For an introduction to STARKs, see our &lt;a href=&quot;&#x2F;diving-deep-fri&#x2F;&quot;&gt;previous posts&lt;&#x2F;a&gt; or the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;tree&#x2F;main&#x2F;docs&#x2F;src&#x2F;starks&quot;&gt;STARK Platinum docs&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;domains&quot;&gt;Domains&lt;&#x2F;h2&gt;
&lt;p&gt;Every implemented field $\mathbb{F}$ has a generator $\omega$ of the unit groups $\mathbb{F}^\times$. They can be obtained by calling the class method &lt;code&gt;Generator&lt;&#x2F;code&gt; of &lt;code&gt;PrimeFieldElement&lt;&#x2F;code&gt;. The generator for the &lt;code&gt;Stark252Field&lt;&#x2F;code&gt; is $\omega = 3$ (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;algebra&#x2F;fields&#x2F;prime_field_element.h#L138-L140&quot;&gt;here&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;algebra&#x2F;fields&#x2F;big_prime_constants.h#L61&quot;&gt;here&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;The class representing a domain is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;algebra&#x2F;domains&#x2F;list_of_cosets.h#L34&quot;&gt;&lt;code&gt;ListOfCosets&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;. The method &lt;code&gt;TraceGenerator&lt;&#x2F;code&gt; returns a primitive root of unity $g$ of the order of the trace length $2^n$ that generates a domain $D$. It is computed as $g = \omega^{ ( p - 1 ) &#x2F; 2^n }$. The LDE is then represented as a list of cosets ${h^i w D: i = 0, \dots , k - 1 }$ all of the same size as $D$, such that their union is the actual LDE domain:&lt;&#x2F;p&gt;
&lt;p&gt;$$D_{\text{LDE}} = w D , \cup , h w D , \cup , h^2 w D , \cup , \cdots , \cup , h^{k-1} w D,$$&lt;br &#x2F;&gt;
where $h = w^{( p - 1 ) &#x2F; 2^{ n + k }}$.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;transcript&quot;&gt;Transcript&lt;&#x2F;h2&gt;
&lt;p&gt;The stone prover uses a &lt;code&gt;NonInteractiveProverChannel&lt;&#x2F;code&gt; class to handle its interactions with the transcript. There are two basic operations:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `SendBytes`: the prover appends bytes to the transcript.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `ReceiveBytes`: the prover receives bytes from the transcript.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;These operations are building blocks for more complex operations, such as sampling a &lt;code&gt;FieldElement&lt;&#x2F;code&gt; or a number. Several hash functions can be used to interact with the transcript (e.g., Keccak, Pedersen).&lt;&#x2F;p&gt;
&lt;p&gt;These operations are mainly implemented in the &lt;code&gt;HashChain&lt;&#x2F;code&gt; class, with other classes just delegating to it. It has the following attributes:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `self.counter`: counts how many blocks of $K$ bytes have been consumed.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `self.hash`: holds the current state of the hash function.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `self.spare_bytes`: when a user asks for $T$ bytes where $T$ is not multiple of $K$, it stores them to use them later on.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here, $K$ is the number of bytes needed to store the output of the chosen hash functions (e.g., 32 bytes for Keccack256).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;appending-to-the-transcript&quot;&gt;Appending to the transcript&lt;&#x2F;h3&gt;
&lt;p&gt;When bytes $X$ are appended to the transcript, the current digest $D$ is obtained and interpreted as a BigInt. Then, a seed increment is added to it. The concatenation of this new seed and $X$ is the latest state of the hash function.&lt;&#x2F;p&gt;
&lt;p&gt;Pseudocode:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;def append(new_bytes, seed_increment):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    digest = self.hash.digest()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    new_seed = digest + self.seed_increment&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    self.hash = Hash(new_seed || bytes)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here, &lt;code&gt;||&lt;&#x2F;code&gt; is the concatenation operator.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;sampling-from-the-transcript&quot;&gt;Sampling from the transcript&lt;&#x2F;h3&gt;
&lt;p&gt;Pseudocode:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;def sample_block():&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    counter_bytes = | 24 bytes of 0x00 | counter as u64 | # This depends on the &amp;quot;block&amp;quot; size, the hash size.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    self.counter++&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return Hash(self.hash.digest() || counter).digest()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;def sample(number_bytes):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for chunk32 in split(number_bytes, 32):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        result = result + sample_block()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return result&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is a simplified version of the code. Here, the hash size is assumed to be 32 bytes (256 bits). Also, this pseudocode does not handle the case where a programmer asks for a number of bytes that’s not a multiple of the hash size.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;transcript-initialization-strong-fiat-shamir&quot;&gt;Transcript initialization (Strong Fiat-Shamir)&lt;&#x2F;h3&gt;
&lt;p&gt;The main prover and verifier executables initialize the transcript using a Fiat-Shamir strategy. This means that the hash function is updated using the public parameters.&lt;&#x2F;p&gt;
&lt;p&gt;There are two implementations of this: the Fibonacci AIR and the Cairo AIR (&lt;code&gt;CpuAir&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Fibonacci](https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;statement&#x2F;fibonacci&#x2F;fibonacci_statement.inl#L40-L52): the transcript is initialized with `claimed_index_in_64_bit_big_endian || claimed_value_in_montgomery_form`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Cairo](https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;statement&#x2F;cpu&#x2F;cpu_air_statement.cc#L99): the transcript is initialized with the `n_steps`, `rc_min`, `rc_max`, and the public memory. The layout is described [here](https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;statement&#x2F;cpu&#x2F;cpu_air_statement.cc#L127-L135).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;logging-interactions&quot;&gt;Logging interactions&lt;&#x2F;h3&gt;
&lt;p&gt;The flag &lt;code&gt;-generate_annotations&lt;&#x2F;code&gt; can be enabled when the main prover is executed. This logs the interactions between the prover and the verifier and can help debug and address compatibility issues. The annotations are added to the output JSON file of the proof.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;r15g0-BAn.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;hash-functions&quot;&gt;Hash functions&lt;&#x2F;h3&gt;
&lt;p&gt;By default, the &lt;code&gt;keccak256&lt;&#x2F;code&gt; hash function is used.&lt;&#x2F;p&gt;
&lt;p&gt;This is the list of supported options:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;using HashTypes = InvokedTypes&amp;lt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Blake2s256, Keccak256, Pedersen, MaskedHash&amp;lt;Keccak256, 20, true&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MaskedHash&amp;lt;Blake2s256, 20, true&amp;gt;, MaskedHash&amp;lt;Blake2s256, 20, false&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MaskedHash&amp;lt;Keccak256, 20, false&amp;gt;&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;composition-polynomial&quot;&gt;Composition polynomial&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;schouhy&#x2F;64fd2fca56e6776d16eb8df3437a0816&quot;&gt;Here&lt;&#x2F;a&gt; is an example of how to instantiate a composition polynomial and compute evaluations of it. It can be run like the Fibonacci example.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;relevant-classes&quot;&gt;Relevant classes&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [`CompositionPolynomial`](https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;composition_polynomial&#x2F;composition_polynomial.h#L55): Abstract class defining interface. It has only two child classes &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      * [`CompositionPolynomialImpl`](https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;composition_polynomial&#x2F;composition_polynomial.h#L81): Concrete implementation of the above. It does NOT follow the pimpl pattern. It&amp;#39;s just a child class.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      * `CompositionPolynomialMock`: Used for testing.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [`CompositionOracleProver`](https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;stark&#x2F;composition_oracle.h#L44): A wrapper around a `CompositionPolynomial` that also knows the polynomial interpolating the trace (called `traces`), the domains of interpolation, and the transcript.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;notes&quot;&gt;Notes&lt;&#x2F;h3&gt;
&lt;p&gt;Despite the name, the class &lt;code&gt;CompositionPolynomialImpl&lt;&#x2F;code&gt; is not responsible for the actual computation of the composition polynomial. It does not handle the logic of collecting all individual evaluations of the constraints and gluing them together to form the composition poly. It handles parallelization and formats all inputs to pass them to &lt;code&gt;Air::ConstraintsEval&lt;&#x2F;code&gt;. This is the method where constraints are both evaluated &lt;strong&gt;and&lt;&#x2F;strong&gt; aggregated to obtain the evaluation of the composition polynomial. So, every implementation of &lt;code&gt;Air&lt;&#x2F;code&gt; is responsible for the correct aggregation step of all the constraint evaluations.&lt;&#x2F;p&gt;
&lt;p&gt;Two things stand out:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * There is no degree adjustment. This is seen in the [Fibonacci Air](https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;air&#x2F;fibonacci&#x2F;fibonacci_air0.inl#L83-L164) and the [Cairo Air](https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;air&#x2F;cpu&#x2F;board&#x2F;cpu_air_definition0.inl#L302-L309).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The coefficients used to aggregate all terms [are all powers of a single challenge](https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;stark&#x2F;stark.cc#L44-L58).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;evaluation&quot;&gt;Evaluation&lt;&#x2F;h3&gt;
&lt;p&gt;For computing the composition polynomial evaluations, the prover calls &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;stark&#x2F;stark.cc#L327C49-L327C49&quot;&gt;&lt;code&gt;CompositionOracleProver::EvalComposition(n_tasks)&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;. This will return the set of evaluations of the composition polynomial in the $d$ cosets, where $d$ is chosen as the minimum integer such that the degree bound of the composition polynomial is less than $2^n d$ (see the Domains section for details about domains and cosets). The oracle then uses its pointers to the trace polynomials to evaluate them at the LDE domain (or use cached computations from the previous commitment phase). The oracle then passes this to &lt;code&gt;CompositionPolynomial::EvalOnCosetBitReversedOutput()&lt;&#x2F;code&gt; along with coset offsets and other domain relevant data. This method launches multiple tasks that call &lt;code&gt;Air::ConstraintEval&lt;&#x2F;code&gt; to compute a single evaluation at a point of the LDE. This is the method where the computation is ultimately done.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;breaking-the-composition-polynomial&quot;&gt;Breaking the composition polynomial&lt;&#x2F;h3&gt;
&lt;p&gt;The composition polynomial $H$ is always broken into $d = \deg(H) &#x2F; 2^n$ parts, where $2^n$ is the trace length,&lt;&#x2F;p&gt;
&lt;p&gt;$$H = H_0 ( X^d ) + X H_1 ( X^d ) + \cdots + X^{ d - 1 } H_{ d - 1 }( X^d ).$$&lt;&#x2F;p&gt;
&lt;p&gt;To do so, after computing the evaluation of $H$, one way to calculate each $H_i$ would be to interpolate $H$ and then split its coefficients on a monomial basis. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;composition_polynomial&#x2F;breaker.cc#L64-L66&quot;&gt;The approach&lt;&#x2F;a&gt; in the Stone prover is an optimization of this. Instead of running a full IFFT to interpolate $H$, they do only $\log(d)$ steps of IFFT, resulting in the evaluations of each $H_i$ if $d$ is a power of two.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;deep-composition-polynomial&quot;&gt;DEEP composition polynomial&lt;&#x2F;h2&gt;
&lt;p&gt;One strange design choice is reusing the AIR and composition polynomial machinery to build the &lt;strong&gt;DEEP&lt;&#x2F;strong&gt; composition polynomial. The deep composition polynomial is seen as a composition polynomial of a particular AIR, called &lt;code&gt;BoundaryAIR&lt;&#x2F;code&gt; (see &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;stark&#x2F;stark.cc#L349-L370&quot;&gt;here&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;air&#x2F;boundary&#x2F;boundary_air.h#L34&quot;&gt;here&lt;&#x2F;a&gt;). It has nothing to do with boundary constraints. It is only used for building the DEEP composition poly. It is the same class, independently of whether the FibonacciAIR, CpuAir or any other AIR is being used to arithmetize the program being proven. The deep composition polynomial is called &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;stark&#x2F;stark.cc#L450&quot;&gt;&lt;code&gt;oods_composition_oracle&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; in the main &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;stark&#x2F;stark.cc#L383&quot;&gt;&lt;code&gt;ProveStark&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; method.&lt;&#x2F;p&gt;
&lt;p&gt;A side effect of this is cluttering the annotations. It looks like the verifier chooses two times the challenge used for building the composition polynomial:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;V-&amp;gt;P: &#x2F;STARK&#x2F;Out Of Domain Sampling: Constraint polynomial random element&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;V-&amp;gt;P: &#x2F;STARK&#x2F;Out Of Domain Sampling: Constraint polynomial random element&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The first time refers to the challenge of the composition polynomial. The second time refers to the challenge to build the DEEP composition polynomial.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;commitment-scheme&quot;&gt;Commitment Scheme&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Here&amp;#39;s](https:&#x2F;&#x2F;gist.github.com&#x2F;ajgara&#x2F;c9ef34a8b2af614db026dc56c929509b) an example Python code.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The commitment algorithm is simple at its core, but many classes interact with each other to produce a commitment. Also, there are settings and other factors that can change the way the commitment is made. For example, the trace evaluated at the LDE may not fit into RAM due to its size, changing the commitment strategy. Let’s first analyze the core algorithm, assuming the LDE fits in RAM and no special settings are used.&lt;&#x2F;p&gt;
&lt;p&gt;The strategy here is to build a Merkle tree. To produce this Merkle tree, we need to know how to make the leaves of the tree and how to merge two nodes into a node for the next layer.&lt;&#x2F;p&gt;
&lt;p&gt;Suppose we want to commit the following trace:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Evaluations of column 1 on LDE&lt;&#x2F;th&gt;&lt;th&gt;Evaluations of column 2 on LDE&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;$t_0 ( wh^0 g^0 )$&lt;&#x2F;td&gt;&lt;td&gt;$t_1 ( wh^0 g^0 )$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$t_0 ( wh^0 g^1 )$&lt;&#x2F;td&gt;&lt;td&gt;$t_1 ( wh^0 g^1 )$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$t_0 ( wh^0 g^2 )$&lt;&#x2F;td&gt;&lt;td&gt;$t_1 ( wh^0 g^2 )$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$t_0 ( wh^0 g^3 )$&lt;&#x2F;td&gt;&lt;td&gt;$t_1 ( wh^0 g^3 )$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$t_0 ( wh^1 g^0 )$&lt;&#x2F;td&gt;&lt;td&gt;$t_1 ( wh^1 g^0 )$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$t_0 ( wh^1 g^1 )$&lt;&#x2F;td&gt;&lt;td&gt;$t_1 ( wh^1 g^1 )$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$t_0 ( wh^1 g^2 )$&lt;&#x2F;td&gt;&lt;td&gt;$t_1 ( wh^1 g^2 )$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$t_0 ( wh^1 g^3 )$&lt;&#x2F;td&gt;&lt;td&gt;$t_1 ( wh^1 g^3 )$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;We refer to the Domains section for domain details and cosets. The whole LDE domain is shifted by $w$, the powers of $h$ denote in which coset the value sits, and the powers of $g$ denote the index inside that coset. Before committing the trace, the stone prover permutes the order of the rows.&lt;&#x2F;p&gt;
&lt;p&gt;First, the cosets are permutated following &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Bit-reversal_permutation&quot;&gt;bit reverse order&lt;&#x2F;a&gt;. For example, if we had:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;| coset 1 | coset 2 | coset 3 | coset 4 |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Applying the bit reverse permutation:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;| coset 1 | coset 3 | coset 2 | coset 4 |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then, the bit reverse order is applied again but inside each coset separately. The final permuted trace would look like this:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Evaluations of column 1 on LDE&lt;&#x2F;th&gt;&lt;th&gt;Evaluations of column 2 on LDE&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;$t_0 (wh^0 g^0 )$&lt;&#x2F;td&gt;&lt;td&gt;$t_1 (wh^0 g^0 )$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$t_0 (wh^0 g^2 )$&lt;&#x2F;td&gt;&lt;td&gt;$t_1 (wh^0 g^2 )$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$t_0 (wh^0 g^1 )$&lt;&#x2F;td&gt;&lt;td&gt;$t_1 (wh^0 g^1 )$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$t_0 (wh^0 g^3 )$&lt;&#x2F;td&gt;&lt;td&gt;$t_1 (wh^0 g^3 )$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$t_0 (wh^1 g^0 )$&lt;&#x2F;td&gt;&lt;td&gt;$t_1 (wh^1 g^0 )$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$t_0 (wh^1 g^2 )$&lt;&#x2F;td&gt;&lt;td&gt;$t_1 (wh^1 g^2 )$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$t_0 (wh^1 g^1 )$&lt;&#x2F;td&gt;&lt;td&gt;$t_1 (wh^1 g^1 )$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$t_0 (wh^1 g^3 )$&lt;&#x2F;td&gt;&lt;td&gt;$t_1 (wh^1 g^3 )$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;In this case, we only have two cosets, so applying the bit reverse order does nothing, and the two cosets stay in the same place. Then, the elements inside each coset are reordered. Now that we have the correct order, we can start building the leaves of the Merkle tree.&lt;&#x2F;p&gt;
&lt;p&gt;Each leave will correspond to one row. This is because each time the prover opens $t_i(z)$, it will open all of the other columns $t_j(z)$ at the same value $z$, so it makes sense to store them at the same leaf and using the same authentication path for them.&lt;&#x2F;p&gt;
&lt;p&gt;If each column has $|LDE|$ rows, we’ll have $|LDE|$ leaves, each with its hash. The $i$-th leaf is the hash that results from hashing the concatenation of all the columns at the $i$-th row. So, for example, the first leaf in this case is $H( t_0 (w h^0 g^0 ) || t_1 ( w h^0 g^0 ))$.&lt;&#x2F;p&gt;
&lt;p&gt;Note that the stone prover stores its field elements in Montgomery form to enhance the performance of its operations. When using the bytes of a field element to hash them, the field element stays in the Montgomery form (it is not translated to standard format). Also, the limbs representing the field element are stored from least significant at position 0 to most significant at the end.&lt;&#x2F;p&gt;
&lt;p&gt;Now that we have the leaves, our first layer of the tree, we can build the next layer by merging nodes. To do this, the Stone Prover connects two consecutive nodes by concatenating their hashes and obtaining the hash of the new parent. Repeating this operation halves the number of nodes at each step until the Merkle tree is complete.&lt;&#x2F;p&gt;
&lt;p&gt;For a simple example, check out the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;ajgara&#x2F;c9ef34a8b2af614db026dc56c929509b&quot;&gt;python code&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Check out the Fibonacci &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;schouhy&#x2F;216f5de449481701d36ab99df86bc081#file-fibonacci_stone_prover-cc-L136-L144&quot;&gt;example&lt;&#x2F;a&gt; to see how to instantiate the classes relevant to commitments.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;tableprover&quot;&gt;TableProver&lt;&#x2F;h3&gt;
&lt;p&gt;The &lt;code&gt;TableProver&lt;&#x2F;code&gt; abstract class and its implementation &lt;code&gt;TableProverImpl&lt;&#x2F;code&gt; are high-level interfaces for dealing with commitments and decommitments of 2-dimensional arrays of field elements. It consists mainly of a commitment scheme but also has a pointer to a ProverChannel to send and receive elements from the verifier.&lt;&#x2F;p&gt;
&lt;p&gt;There is a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;commitment_scheme&#x2F;table_prover.h#L102-L109&quot;&gt;TableProverFactory&lt;&#x2F;a&gt; and a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;stark&#x2F;utils.inl#L26-L30&quot;&gt;utils function&lt;&#x2F;a&gt; to instantiate it. There’s also a helper used in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;stark&#x2F;stark_test.cc#L64-L72&quot;&gt;tests&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;TableProverImpl&lt;&#x2F;code&gt; has a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;commitment_scheme&#x2F;table_prover_impl.cc#L117&quot;&gt;&lt;code&gt;Commit&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; method that in turn calls the &lt;code&gt;Commit&lt;&#x2F;code&gt; method of its &lt;code&gt;commitment_scheme_&lt;&#x2F;code&gt; member, which is a pointer to a &lt;code&gt;CommitmentSchemeProver&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;commitmentschemeprover&quot;&gt;CommitmentSchemeProver&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;commitment_scheme&#x2F;commitment_scheme.h#L67&quot;&gt;This class&lt;&#x2F;a&gt; implements the logic of the commitment scheme.&lt;&#x2F;p&gt;
&lt;p&gt;There is a commitment scheme &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;commitment_scheme&#x2F;commitment_scheme_builder.inl#L177-L195&quot;&gt;builder&lt;&#x2F;a&gt; that calls another method &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;commitment_scheme&#x2F;commitment_scheme_builder.inl#L56-L70&quot;&gt;here&lt;&#x2F;a&gt; that constructs a &lt;code&gt;CommitmentSchemeProver&lt;&#x2F;code&gt; by &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;commitment_scheme&#x2F;commitment_scheme_builder.inl#L106-L124&quot;&gt;alternately calling&lt;&#x2F;a&gt; &lt;code&gt;PackagingCommitmentSchemeProver&lt;&#x2F;code&gt; and &lt;code&gt;CachingCommitmentSchemeProver&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;segments&quot;&gt;Segments&lt;&#x2F;h4&gt;
&lt;p&gt;There are several details to consider when dealing with traces or LDEs that are so large they do not fit into RAM.&lt;&#x2F;p&gt;
&lt;p&gt;Evaluations of a polynomial over the LDE are split into segments. Each segment contains a continuous subset of the rows. One Merkle tree is built for each part. Then, another Merkle tree is built on top of that, where the leaves are the roots of the Merkle trees of each segment.&lt;&#x2F;p&gt;
&lt;p&gt;Two comments help a bit in understanding &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;commitment_scheme&#x2F;commitment_scheme.h#L47-L55&quot;&gt;here&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;commitment_scheme&#x2F;commitment_scheme_builder.inl#L63-L65&quot;&gt;here&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;cachingcommitmentschemeprover&quot;&gt;CachingCommitmentSchemeProver&lt;&#x2F;h3&gt;
&lt;p&gt;The prover may want to store the entire MerkleTree once it’s committed so that when openings are performed, there’s no need to recalculate them. However, if this is too memory-consuming, the prover might choose not to store it and recalculate it later on. The &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;3d5bb8bd991b7809a6d379c123c902667bac600f&#x2F;src&#x2F;starkware&#x2F;commitment_scheme&#x2F;caching_commitment_scheme.h#L31-L40&quot;&gt;CachingCommitmentSchemeProver&lt;&#x2F;a&gt; implements this logic.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;packagingcommitmentschemeprover&quot;&gt;PackagingCommitmentSchemeProver&lt;&#x2F;h3&gt;
&lt;p&gt;It has an inner commitment scheme, which separates things into packages and passes them to the internal commitment scheme.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;fri&quot;&gt;FRI&lt;&#x2F;h2&gt;
&lt;p&gt;The FRI part is responsible for generating the FRILayers, generating the query points, and producing the proof. The proof consists of several elements from the Merkle trees from every layer, plus inclusion proofs (authentication paths).&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;blob&#x2F;main&#x2F;src&#x2F;starkware&#x2F;fri&#x2F;fri_folder.h&quot;&gt;Frifolder&lt;&#x2F;a&gt; takes two evaluations from the previous layer and computes an evaluation of the current layer using the &lt;code&gt;FriFolderBase&lt;&#x2F;code&gt; class. The FRI protocol allows one to commit to a certain subgroup of layers (for example, every second layer). There is the possibility of varying the number of layers one commits to, but this makes the logic more complicated. The recommendation is to commit every third layer in this &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&#x2F;issues&#x2F;4&quot;&gt;issue&lt;&#x2F;a&gt;. However, the FRI step vector makes it harder for a new user to work with the prover and we don’t believe it particulary offers an advantage in performance.&lt;&#x2F;p&gt;
&lt;p&gt;The protocol distinguishes between data and integrity queries; if an evaluation is part of the integrity queries, it is not supplied as part of the proof. This is because the integrity query can be deduced from elements from the previous layers. We don’t need to check the value directly; if we correctly computed the value, the inclusion proof should pass. More concretely, if the prover sends the values corresponding to $p_k ( x_i )$ and $p_k ( - x_i )$, the verifier can compute $p_{ k + 1 }( x_i^2 )$. This value is needed to check the inclusion proof in the Merkle tree; if we use a wrong value, the validation should fail (unless there is a collision for the hash function).&lt;&#x2F;p&gt;
&lt;p&gt;The protocol finishes when the size of a layer is smaller than a threshold value; the prover supplies the polynomial representing those evaluations by performing an interpolation over those values. This optimization reduces the proof length, as we avoid sending several values from many Merkle trees and their authentication paths.&lt;&#x2F;p&gt;
&lt;p&gt;The protocol is optimized for proof size since it avoids sending unnecessary information from the integrity queries, the pairs of values are grouped in the same branch in the Merkle tree, and the protocol finishes before reaching degree zero.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;&#x2F;h2&gt;
&lt;p&gt;In this post, we covered different components of the Stone prover, how they work, and some of their consequences in proof size. Starkware has done a great job developing the prover and open-sourcing it. There a few parts that still need an improvement but that is always the case with software.&lt;&#x2F;p&gt;
&lt;p&gt;We are currently working towards achieving compatibility between Stone and STARK Platinum. To reach this goal, we need to adapt different parts so that the challenges we generate are the same and the proof we get (from sampling the queries) and its serialization and deserialization are precisely the same. We will continue explaining how the Stone Prover works and the optimizations we are adding to STARK Platinum to enhance its performance while maintaining compatibility.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Lambda’s engineering philosophy</title>
          <pubDate>Wed, 27 Sep 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/lambdas-engineering-philosophy/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/lambdas-engineering-philosophy/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/lambdas-engineering-philosophy/">&lt;h2 id=&quot;what-makes-lambda-different&quot;&gt;What makes Lambda different&lt;&#x2F;h2&gt;
&lt;p&gt;We often hear that Lambda has a different way of operating compared with other companies. Many people we’ve worked with have praised the speed and quality of our delivery. We attribute that to a set of principles that anyone can apply, and might benefit others. It can be summed up as: observe, iterate, simplify, have a close relationship with your code both in its static and dynamic form, and incorporate process at the correct times to serve the needs of engineering and not management. Let’s break this down:&lt;&#x2F;p&gt;
&lt;h2 id=&quot;be-curious-be-attached-to-learning-and-solving&quot;&gt;Be curious, be attached to learning and solving&lt;&#x2F;h2&gt;
&lt;p&gt;We promote a culture where engineers can feel the joy of putting things into production and applying their skills to interesting challenges.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;observe-and-measure&quot;&gt;Observe and Measure&lt;&#x2F;h2&gt;
&lt;p&gt;Engineering is applying knowledge to solve problems under a given cost&#x2F;benefit tradeoff. You cannot solve a problem you cannot see. Seeing is measuring. Use your tools to diagnose the problem, have a metric for success, then measure again after applying your solution.&lt;&#x2F;p&gt;
&lt;p&gt;Build observability into your system. The sooner you see, the sooner you can react, to both changing requirements and changing metrics.&lt;&#x2F;p&gt;
&lt;p&gt;This also applies to performance engineering. Optimization is premature (thus evil) only when it occurs before it is a requirement and before measuring.&lt;&#x2F;p&gt;
&lt;p&gt;Iterate frequently in your perceive-act loop to shorten feedback.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;speak-openly-about-engineering-problems&quot;&gt;Speak openly about engineering problems&lt;&#x2F;h2&gt;
&lt;p&gt;Once a problem has been identified, speak openly about it. Of course &lt;em&gt;how&lt;&#x2F;em&gt; one communicates is all important when talking to other humans, but if framed correctly a technical discussion should not offend anyone, as the merits or faults of any technical solution only reflect on the thing itself, and not the value of the human or group implementing it.&lt;&#x2F;p&gt;
&lt;p&gt;The earlier a problem (or solution) is communicated and discussed, the better the final solution will be, the lower the risk and cost.&lt;&#x2F;p&gt;
&lt;p&gt;“Pride is not the opposite of shame, but its source. True humility is the only antidote to shame.”&lt;&#x2F;p&gt;
&lt;h2 id=&quot;relationship-with-complexity-or-lack-thereof&quot;&gt;Relationship with complexity (or lack thereof)&lt;&#x2F;h2&gt;
&lt;p&gt;If there is one mantra we repeat and can apply in any context, it is KISS, Keep It Simple, Silly.&lt;br &#x2F;&gt;
Much has been written about this, and there are echoes of it in many other wise reflections, such as Joe Armstrong’s famous quote &lt;em&gt;“Make it work, then make it beautiful, then if you really, really have to, make it fast. 90% of the time, if you make it beautiful, it will already be fast. So really, just make it beautiful!”&lt;&#x2F;em&gt; ; or in some of the tenets of the Zen of Python:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Beautiful is better than ugly.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Explicit is better than implicit.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Simple is better than complex.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Complex is better than complicated.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Flat is better than nested.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Sparse is better than dense.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Readability counts.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Such general maxims are something that may seem truisms, or tautological sometimes. Their value is in keeping them constantly in mind and asking “how does this apply &lt;em&gt;in this context&lt;&#x2F;em&gt;?”.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;dogfooding&quot;&gt;Dogfooding&lt;&#x2F;h2&gt;
&lt;p&gt;Repositories should build easily and cleanly on all of the target environments. A newcomer to the project should be able to set it up with no hassle. Take pride in having an up-to-date readme that people can follow and have your code working on their machine in no time. Open-source as much as you can. Put your code out into the world.&lt;&#x2F;p&gt;
&lt;p&gt;Developers should be hands-on about infra, not only familiar with the usual tooling for development but also with the pipelines and code which puts it into production. Your pipelines should be clean and as observable and debuggable as the product code.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;generalization-should-be-end-game&quot;&gt;Generalization should be end game&lt;&#x2F;h2&gt;
&lt;p&gt;Do not generalize until you absolutely need it. Repeating code two or three times can be fine. Solve the problem you need to solve, don’t get tangled up in how to abstract or generalize the solution, just get it done in the simplest way possible. Generalizations and abstractions arise naturally with time.&lt;&#x2F;p&gt;
&lt;p&gt;Most new challenging projects usually have two different phases:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;first-few-weeks-experiment-and-prototype&quot;&gt;First few weeks: experiment and prototype&lt;&#x2F;h3&gt;
&lt;p&gt;Things are just starting out. The problem being solved is not yet well understood, there’s a lot of uncertainty; some people know just enough about the problem to recognize it’s a difficult task, but not enough to go ahead and tackle it. This creates a lot of anxiety around how things should be done and what the best way forward is; endless debates that go nowhere ensue. Sometimes some knowledge is worse than knowing nothing at all.&lt;&#x2F;p&gt;
&lt;p&gt;Getting through this requires recognizing that you don’t fully know how to do things and that’s fine; you have to figure it out through trial and error. The mantra here is &lt;em&gt;Go fast, try things out, fail quickly, figure it out&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Introducing a lot of process at this stage is counter-productive, you can’t make a gantt and plan things out with deadlines when you’re not even sure what it is you are building. Doing so just slows you down, or set you on the wrong path.&lt;&#x2F;p&gt;
&lt;p&gt;Morale at this stage is also very important; people are anxious that the project might not pan out, that the problem is not solvable. If there’s too much time without any update or any sort of progress, they get demoralized. The antidote is quickly coding something that performs some basic form of the final desired behavior, and each passing week should expand and improve upon functionality. Don’t let weeks pass by creating lots of code that still doesn’t perform a basic function. Showing regular updates, merging changes quickly and trying them out, deploying regularly and all around having a fast feedback loop is essential to keep people excited and focused.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;settling-down&quot;&gt;Settling down&lt;&#x2F;h3&gt;
&lt;p&gt;After a few weeks of work, the project begins to take shape, the problem is better understood and the solution is working out well. People start developing a common vocabulary around the project, they know what problem needs to be solved next and how to do it. Anxiety wears off.&lt;&#x2F;p&gt;
&lt;p&gt;At this point, two things become important:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Organizing the work that’s yet to come. The project is no more than a prototype right now, and there is a ton of work to be done to make it production ready.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Documenting the progress so far. A lot of knowledge was accumulated in the first few weeks&#x2F;months of work as ideas were tried out and discarded. It’s important for it not to get lost.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Solving these issues (especially the first one) requires introducing &lt;em&gt;process&lt;&#x2F;em&gt;. Writing down all the tasks left, making a gantt, defining milestones and distributing work accordingly are now necessary to continue. The main obstacle is not so much uncertainty anymore, but rather correct planning and execution.&lt;&#x2F;p&gt;
&lt;p&gt;As the project continues to take shape and grow, merging new changes becomes more and more difficult; its complexity starts making it impossible for you to know every nook and cranny. Also, breaking things has a higher cost both in development time and perhaps money if you’re in production. Thorough testing and code review thus become key.&lt;&#x2F;p&gt;
&lt;p&gt;Process is the sign of a &lt;em&gt;mature&lt;&#x2F;em&gt; project. It is very important, but it should not be introduced before it’s necessary.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;back-and-forth&quot;&gt;Back and forth&lt;&#x2F;h3&gt;
&lt;p&gt;Most projects go through these phases more than once. In general, any time a project gets a new requirement that involves a challenging task, a part of it has to revert to the experimentation phase.&lt;&#x2F;p&gt;
&lt;p&gt;The key here is &lt;em&gt;uncertainty&lt;&#x2F;em&gt;. When you detect that a given task is hard and people are spending way too much time arguing about how to solve it, without ever trying things out (for fear of breaking things or making the wrong move) you need to revert back to the first phase. This doesn’t mean throwing all the process out the window; people who are working on other regular tasks can continue as usual. It’s just the part of the team tackling this new challenge that needs to change its approach.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;incorporating-process&quot;&gt;Incorporating process&lt;&#x2F;h2&gt;
&lt;p&gt;Of all the infinite process management tools and diagrams under the sun, the one we find most useful is the Gantt chart.&lt;br &#x2F;&gt;
Here is an outline of how we go about making one, once the project requires it.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Understand what areas there are in the project in a very broad way. E.g. networking, state transitions, api, db, external services, infra. Architecture diagrams might help at this stage.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Divide areas into tasks.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Repeat step 2 a couple of times. This refining will help direct research and prevent the “I want to know everything before coding”.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Research doesn’t mean just reading, this is a good stage to start with some very small PoCs of things you don’t understand. Some PoCs can even be a good task to delegate to other team members while still figuring out tasks. You’ll need to review those in depth later on though.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. Track dependencies between tasks. A dependency graph might be a good output here.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    6. Use the dependencies to prioritize (order), and group tasks in vertical slices. These are E2E integrations that provide some high-level feature and usually include a bit of all areas.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    7. The first vertical slice should be bare bones, maybe providing a dumb useless feature, but should give you “something” working. It should have a db, api, networking, ci, testing and linting (and other tools if necessary). This will force you to forever be in a production mindset from day 1 and avoid giant integrations later on. It also forces you to start doing PoCs of different tools early to reduce uncertainty and unblock as many independent paths as possible for next slices.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    8. Make a release plan using these slices. Roughly estimate a number of weeks for each. This is not the time for precise estimations. Also, multiply that number by 1.5 or 2 depending on how optimist you tend to be and how little you still know about the project.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    9. Now you can make a Gantt reflecting the release plan and according to the amount of people you have.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</description>
      </item>
      <item>
          <title>Don&#x27;t trust, verify or why you should care about benchmarks</title>
          <pubDate>Sat, 02 Sep 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/dont-trust-verify-or-why-you-should-you-care-about-benchmarks/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/dont-trust-verify-or-why-you-should-you-care-about-benchmarks/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/dont-trust-verify-or-why-you-should-you-care-about-benchmarks/">&lt;p&gt;Recently, there has been quite a lot of debate between researchers and engineers on the best proof system. For example, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;SuccinctJT&#x2F;status&#x2F;1696877149251055834&quot;&gt;Justin Thaler&lt;&#x2F;a&gt; and Srinath Setty have been discussing whether FRI or KZG based SNARKs are better in computational terms, following some calculations by &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;PapiniShahar&#x2F;status&#x2F;1696327688192237999&quot;&gt;Eli Ben-Sasson during SBC&lt;&#x2F;a&gt;. Before jumping into the details and our view on benchmarks, we want to say that we really like all the work developed by the authors, bringing new ideas and debates that can help expand and improve zero-knowledge schemes and their applications. We learned from all of them but think that we should have some clearer criteria on what makes something more performant or useful in engineering terms. Besides, performance and suitability are sometimes application dependent, as &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;Zac_Aztec&#x2F;status&#x2F;1696673331116638382&quot;&gt;Zac Williamson&lt;&#x2F;a&gt; pointed out in an exchange on X, indicating that SNARKs could be more advantageous in client side proving.&lt;&#x2F;p&gt;
&lt;p&gt;Nowadays the performance side of things three big strategies are being publicly discussed:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Folding schemes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Lookup singularity&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * STARKs with small fields&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With time some ideas might be combined. In the meantime, we need to have a way of analyzing their practical potential. We can use back of the envelope calculations to analyze these different strategies and proving system. But they are just estimations of the total number of operations, and as such should always be taken with a grain of salt. They may be useful to assess whether some system or algorithm could outperform another, but not as a final measure of performance. Something similar happens with asymptotic complexity; we know of algorithms that may be optimal from their complexity point of view, but have no practical applications (the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Galactic_algorithm&quot;&gt;famous galactic algorithms&lt;&#x2F;a&gt;). Besides, in engineering, problems are multidimensional and there is a lot of interaction between different parts.&lt;&#x2F;p&gt;
&lt;p&gt;There are constraints regarding memory, data communication, having hardware acceleration, code maintainability, economics, etc. For example, memory access patterns can cause a program with less instructions to run slower, if it isn’t suited for cache algorithms, data prefetching and other memory optimizations. Complexity increases if we have to additionally consider the degree of parallelization of the algoritms and GPUs, and even more when we can distribute computation between many machines. An efficient algorithm that can be run only in one machine may be worse in some scenarios than other one that is less efficient and can be distributed in multiple devices. This is, once again, something really similar to what Zac has mentioned. There may be different criteria for selecting algorithms depending on the use case. Most of the times in software, multiple solutions for one problem are used depending on the scenario, and even mixed together when it’s required. To think we already have a grand solution for all the problems, that’s optimal in all scenarios, may be overestimating the complexities of the applied world. There are claims about the number of operations not taking into account the constraints imposed by hardware or use special field families to count the number of operations, which are not applicable to the kind of elliptic curve chosen. For example, commonly used pairing-friendly elliptic curves are defined over primes that don’t have the same type of efficient arithmetic such as Mersenne primes or the “MiniGoldilocks” prime.&lt;&#x2F;p&gt;
&lt;p&gt;Another example of that the complexity of real engineering systems is seen from our point of view in this &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;SuccinctJT&#x2F;status&#x2F;1696883492380979257&quot;&gt;tweet by Thaler&lt;&#x2F;a&gt;. He asked why Starkware continues to use a rather large finite field despite it not offering any advantages over smaller ones. The reason is quite simple: the SHARP was developed before many improvements and has been in production for many years. Evenmore, for production ready software we need more than a prover. We need languages, compilers, VMs, tools for developers and sequencers for blockchains. There is a lot of work, and rushing to improve the prover with each possible upgrade, on a system that’s in production with a lot of value, may be reckless. From a brilliant idea in paper to a production ready system, there is a lot of engineering work and we always find many more difficulties along the way, that were not originally considered or could have been difficult to foresee.&lt;&#x2F;p&gt;
&lt;p&gt;Critical analysis, with measurements and a good understanding of the possible solutions, is key. We have seen claims such as a STARKs use over 100 GBs of RAM for small programs. It’s not clear what is the criteria of comparison and how many GBs would the alternatives would use. It is important to take advantage of open source software and play with the tools developed by others, to check whether they work as stated and corroborate numbers.&lt;&#x2F;p&gt;
&lt;p&gt;We think that Nova and Lasso bring interesting ideas, which can spark new solutions to other proof systems. We wrote a &lt;a href=&quot;&#x2F;incrementally-verifiable-computation-nova&#x2F;&quot;&gt;post on Nova&lt;&#x2F;a&gt; and we plan to have one on Jolt and Lasso. We even had discussions on whether we could adapt some of the ideas behind to a STARKs prover. Folding schemes such as Nova can help solve many problems related to SNARKs based on Plonkish or R1CS arithmetization. In the case of the Cairo prover, there is a strategy that zips the constraints. The Cairo AIR contains the constraints for all the instructions of a Turing-complete virtual machine. The number of constraints does not change with the computation size, as opposed to the execution trace, which grows linearly with the size of the program. The trace is then interpolated and the constraints are enforced via quotients. So, the relevant measure here is the number of steps of the program and not the number of constraints. Fair measurements should be conducted over some commonly used calculations or transactions, for example, an ERC-20 contract. We should also be careful to see speed in a single task as the only thing that matters. Clean codebases, easy to maintain and update, robustness, security, memory use, and auditability are also factors to take into account.&lt;&#x2F;p&gt;
&lt;p&gt;We like the work done in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;blog.celer.network&#x2F;2023&#x2F;08&#x2F;04&#x2F;the-pantheon-of-zero-knowledge-proof-development-frameworks&#x2F;&quot;&gt;benchmarks by Celer Network&lt;&#x2F;a&gt; trying to give a fair comparison between different proof systems, using SHA-256 as example circuit. That said we have to always keep in mind that it can become tempting for a project or a particular team to over optimize it’s codebase for a particular benchmark. It’s good to see that the Celer benchmark points out, however, that it is quite difficult to establish a comparison for Nova, as they mention “It’s important to recognize that Nova cannot be directly compared with other frameworks in terms of time and computation. This uniqueness stems from the incremental computing capabilities enabled by Nova. To put it simply, breaking down the entire computation into more detailed steps naturally leads to a decrease in memory consumption, even though it may cause an increase in computation time.” We point out that some of the proof systems are not fully optimized and that could change the trends. The memory vs speed trade-off may be convenient for some use cases, but not in others.&lt;&#x2F;p&gt;
&lt;p&gt;Another point worth noting is that some people tend to add constraints that in practice do not exist, or tend to generalize the strategies that one company uses to all other possible implementations. For example, if A uses Poseidon as hash function, they assume that B, C and D should also use Poseidon, even though that may not fit their particular application. In a recursive environment, we can prove with a SNARK that we verified a STARK proof, which has a lot of usecases. Of course, if we have a tree of recursive proofs of verifications, there is no inconvenient in using a faster hash function for the leaves, such as Blake2, then proving in the second layer that we verified proofs that used Blake2, with Poseidon or other hash.&lt;&#x2F;p&gt;
&lt;p&gt;We think that we should have clear benchmarks, with code used in production. There are, of course, new technologies or ideas that may be promising and we should explore, but we should never be too hasty to jump into the next boat, especially when users assets or privacy are at stake. We will be implementing the different proving systems into the Lambdaworks library, so that anyone can run the benches easily and check which one suits him best. Moreover, if there are optimizations for any of the systems, anyone can submit their PR to improve them. We are not maximalists on any proof system; what we want is this technology to succeed and develop applications on top of it. If a particular system works better, we will learn it and work with it.&lt;&#x2F;p&gt;
&lt;p&gt;We think that debate and having different points of view is important to bring new ideas and improvements to the table, from which we can all benefit. Having open source code, and not only papers, available to tweak, analyze, and play with proving systems is crucial to be able to do comparison. Starkware just open sourced its battle tested &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;stone-prover&quot;&gt;Stone prover&lt;&#x2F;a&gt; and this will help a lot to do improvements and comparison between startegies. We also like a lot initiatives such as &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.zprize.io&#x2F;&quot;&gt;ZPrize&lt;&#x2F;a&gt;, where teams propose open source optimizations to common problems in zero-knowledge proofs. This can give us the opportunity to explore different strategies and arrive at algorithms that work best in practice.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Inner Product Argument (IPA) and a Polynomial Commitment Scheme</title>
          <pubDate>Fri, 25 Aug 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/ipa-and-a-polynomial-commitment-scheme/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/ipa-and-a-polynomial-commitment-scheme/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/ipa-and-a-polynomial-commitment-scheme/">&lt;p&gt;In this blogpost, we’ll take a closer look at the Inner Product Argument. We’ll start by understanding the basics of this technique and then shift our focus to its variant within the Halo2 proving system. Specifically, we’ll explore how Halo2 ingeniously employs the Inner Product Argument as a polynomial commitment scheme.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s first fix some notation that will be used throughout the text.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;notation&quot;&gt;Notation&lt;&#x2F;h2&gt;
&lt;p&gt;The symbol $\mathbb{F}$ always denotes a prime field of order $p$. Given two vectors $A=(a_1,\dots,a_n)$ and $B=(b_1,\dots,b_n)$ of elements of $\mathbb{F}$ of the same length, the inner product between $A$ and $B$ is the element $a_1b_1 + \cdots + a_nb_n \in \mathbb{F}$. It is denoted by $\langle A, B\rangle$.&lt;&#x2F;p&gt;
&lt;p&gt;The symbol $\mathbb{G}$ denotes a commutative group of order $p$. We always use additive notation. If $A=(a_1,\dots,a_n)$ is a vector of elements of $\mathbb{F}$ and $G=(G_1, \dots, G_n)$ is a sequence of elements of $\mathbb{G}$, then $\langle A, G\rangle$ denotes the element $a_1G_1 + \cdots + a_nG_n \in\mathbb{G}$.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;the-inner-product-argument&quot;&gt;The inner product argument&lt;&#x2F;h1&gt;
&lt;p&gt;To understand what this is all about, let’s go straight to its description. This is a sort of commitment scheme and there will be a prover and a verifier. The argument has two parts.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Commit&lt;&#x2F;strong&gt; : The prover can commit to a pair of vectors $(A, B)$, where $A \in \mathbb{F}^n$ and $B \in \mathbb{F}^n$ by producing an object that we denote by $P$. This process does not unveil $A$ or $B$, but it is binding. Meaning that any other vectors would produce another commitment with high probability. Usually, the prover sends $P$ to the verifier.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Open&lt;&#x2F;strong&gt; : Assume the verifier already holds a commitment $P$. The open protocol is an interactive protocol in which the prover sends a value $c\in\mathbb{F}$ and convinces the verifier that&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $P$ is a valid commitment of two vectors $A$ and $B$, both of length $n$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The value $c$ is the inner product of $A$ and $B$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;ok-but-why&quot;&gt;Ok, but why?&lt;&#x2F;h3&gt;
&lt;p&gt;This scheme itself might not seem particularly valuable, as $A$ and $B$ can be anything. However, its significance lies in its role as a building block for other proving systems. Within these contexts, additional checks are applied to enforce specific structures upon $A$, $B$, and $c$, all dependent on public parameters. Instead of sending $P$, the prover sends other commitments that make possible the structure checks on $A$ and $B$. From those commitments, the verifier can efficiently reconstruct $P$. This approach imbues the vectors with certain contextual meanings regarding the statement being proven. The requirement that their inner product equals a predetermined value functions as evidence of the prover’s knowledge regarding this fact.&lt;&#x2F;p&gt;
&lt;p&gt;The version we’ll describe next was introduced in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2017&#x2F;1066&quot;&gt;Bulletproofs paper&lt;&#x2F;a&gt;. To gain further insight into its application within a zero-knowledge proof of arithmetic circuits, refer to Section 5 of that paper.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;setup&quot;&gt;Setup&lt;&#x2F;h3&gt;
&lt;p&gt;Both the Commit and Open protocols depend on a few precomputed values. The needed ingredients are:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * A commutative group $\mathbb{G}$ with $p$ elements. We&amp;#39;ll use additive notation.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Two sequences of elements $G=(G_1,\dots, G_n)$ and $H=(H_1,\dots, H_n)$ of elements of $\mathbb{G}$. We may refer to these as _bases_.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here $n$ is the length of the vectors to be committed. We will always assume it is a power of two. If this is not the case, vectors can be padded with zeroes until the next power of two.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;commit&quot;&gt;Commit&lt;&#x2F;h3&gt;
&lt;p&gt;Given vectors $A = (a_1,\dots, a_n)$ and $B=(b_1,\dots, b_n)$, the commitment of the pair $(A, B)$ is:&lt;&#x2F;p&gt;
&lt;p&gt;$$P := \sum_{i=1}^n a_i G_i + \sum_{i=1}^n b_i H_i.$$&lt;&#x2F;p&gt;
&lt;h3 id=&quot;open&quot;&gt;Open&lt;&#x2F;h3&gt;
&lt;p&gt;The Open protocol has $\log_2(n)$ rounds. Let’s start with the easiest example.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;case-n-2&quot;&gt;Case $n=2$.&lt;&#x2F;h4&gt;
&lt;p&gt;In this case $A = (a_1, a_2)$ and $B = (b_1, b_2)$.&lt;&#x2F;p&gt;
&lt;p&gt;The protocol starts with the verifier choosing a random element $U$ in $\mathbb{G}$ and sending it to the prover.&lt;&#x2F;p&gt;
&lt;p&gt;The prover computes the following elements and sends them to the verifier&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $L := a_1G_2 + b_2H_1 + a_1b_2U$ and&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $R := a_2G_1 + b_1H_2 + a_2b_1U$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The verifier chooses a random non-zero value $x\in\mathbb{F}$ and sends it to the prover, who uses it to compute the following elements:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $a&amp;#39; := a_1 x + a_2 x^{-1}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $b&amp;#39; := b_1 x^{-1} + b_2 x$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The prover sends $a’$ and $b’$ to the verifier. Finally, the verifier checks that:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\begin{equation}&lt;br &#x2F;&gt;
x^2 L + P + c U + x^{-2} R = x^{-1} a’ G_1 + xa’ G_2 + x b’ H_1 + x^{-1} b’ H_2 + a’b’U&lt;br &#x2F;&gt;
\end{equation}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;The verifier accepts if and only if the above equality holds.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;completeness-idea&quot;&gt;Completeness idea&lt;&#x2F;h4&gt;
&lt;p&gt;To see why this equality holds, one can expand both sides and check that they have the same terms. Let’s examine for example the first term on the right-hand side:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\begin{aligned}&lt;br &#x2F;&gt;
x^{-1} a’ G_1 &amp;amp;= x^{-1} (a_1 x + a_2 x^{-1}) G_1 \\&lt;br &#x2F;&gt;
&amp;amp;= (a_1 + a_2 x^{-2}) G_1 \\&lt;br &#x2F;&gt;
&amp;amp;= \color{blue}{a_1 G_1} + \color{red}{x^{-2} a_2 G_1}&lt;br &#x2F;&gt;
\end{aligned}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;Notice how this matches part of $P = \color{blue}{a_1G_1} + a_2G_2 + b_1H_1 + b_2H_2$. The other term appears in $x^{-2}R = \color{red}{x^{-2}a_2G_1} + x^{-2} b_1 H_2 + x^{-2}a_2b_1U$. The rest of the terms behave similarly.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;soundness-idea&quot;&gt;Soundness idea&lt;&#x2F;h4&gt;
&lt;p&gt;In the Bulletproofs paper, the authors prove that, under the discrete log assumption, if the prover could successfully respond with $a’,b’$ for at least $4$ different values of $x$, then two vectors $A$ and $B$ can be extracted from them such that $\langle A, B\rangle = c$ and $P$ is the commitment of the pair $(A, B)$.&lt;br &#x2F;&gt;
So if such $A$ and $B$ don’t exist, there are at most $3$ values of $x$ for which the prover knows $a’$ and $b’$ that make the verifier’s check pass. But the chances that the verifier happens to choose a random $x$ that’s one of those $3$ options, is negligible.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;general-case-for-n-2-k&quot;&gt;General case for $n = 2^k$&lt;&#x2F;h4&gt;
&lt;p&gt;It is an iterative application of a process in that in each step the prover takes two vectors $A$ and $B$ of size $2^k$ and produces two more vectors $A’$ and $B’$ each of size $2^{k-1}$. In the subsequent step $A’$ and $B’$ take the role of $A$ and $B$ and repeat until $k=0$. In each intermediate step, the bases $G$ and $H$ are updated to halve their length too.&lt;br &#x2F;&gt;
In the first iteration, $A$ and $B$ are the original vectors and the final step is exactly the base case already described for $n=2$. At the end, $A’$ and $B’$ would be of length $1$, so they are just elements of $\mathbb{F}$. They are the elements we denoted by $a’$ and $b’$ above.&lt;&#x2F;p&gt;
&lt;p&gt;Concretely, the first step is as follows.&lt;&#x2F;p&gt;
&lt;p&gt;Let $n = 2^k$ and suppose $k&amp;gt;1$. Otherwise, we follow the case $n=2$ described above.&lt;br &#x2F;&gt;
Write $A = (a_1,\dots, a_{2^k})$ and define the lower and higher parts of $A$ as $A_{lo} := (a_1,\dots,a_{2^{k-1}})$ and $A_{hi} := (a_{2^{k-1}+1}, \dots, a_{2^k})$. The same for $B$, $B_{lo}$ and $B_{hi}$, $G_{lo}$, $G_{hi}$, $H_{lo}$, $H_{hi}$.&lt;&#x2F;p&gt;
&lt;p&gt;The protocol starts also with the verifier choosing a random element $U$ in $\mathbb{G}$ and sending it to the prover. This only happens at the very first round. The same element $U$ is then used throughout all rounds.&lt;&#x2F;p&gt;
&lt;p&gt;The prover computes the following vectors and sends them to the verifier&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $L := \langle A_{lo}, G_{hi} \rangle + \langle B_{hi}, H_{lo} \rangle + \langle A_{lo}, B_{hi}\rangle U$, and&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $R := \langle A_{hi}, G_{lo} \rangle + \langle B_{lo}, H_{hi} \rangle + \langle A_{hi}, B_{lo}\rangle U$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The verifier chooses a random non-zero value $x\in\mathbb{F}$ and sends it to the prover.&lt;&#x2F;p&gt;
&lt;p&gt;At this point, the next step starts. The prover computes&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $A&amp;#39; := x A_{lo} + x^{-1} A_{hi}$,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $B&amp;#39; := x^{-1} B_{lo} + x B_{hi}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;These will take the roles of $A$ and $B$. The bases are updated similarly to $A$ and $B$. Meaning, in the next step, instead of $G$ and $H$, the following bases are used:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $G&amp;#39; := x^{-1} G_{lo} + x G_{hi}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $H&amp;#39; := x H_{lo} + x^{-1} H_{hi}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally, the verifier accepts if and only if the check at the last step ($n$=2) succeeds.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;polynomial-commitment-scheme&quot;&gt;Polynomial commitment scheme&lt;&#x2F;h1&gt;
&lt;p&gt;There is a polynomial commitment scheme inspired by the IPA protocol. This is used in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;zcash.github.io&#x2F;halo2&#x2F;index.html&quot;&gt;Halo2&lt;&#x2F;a&gt; proving system.&lt;&#x2F;p&gt;
&lt;p&gt;A polynomial commitment scheme has two parts:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Commit** : given a polynomial $p$, the prover produces an object that&amp;#39;s unique to $p$. We denote it here by $[p]$ and is called the _commitment_ of $p$. The prover usually sends $[p]$ to the verifier. The object $[p]$ is a sort of hash of $p$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Open** : This is an interactive protocol between the prover and the verifier. The verifier only holds the commitment $[p]$ of some polynomial and sends a value $z$ to the prover at which he wants to know the value $p(z)$. The prover responds with a value $c$ and then they engage in the _Open_ protocol. As a result of it, the verifier gets convinced that the polynomial that corresponds to the commitment $[p]$ evaluates to $c$ at $z$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The idea to build a polynomial commitment scheme out of IPA is primarily based on two observations.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * A polynomial $p = \sum_{i=0}^{n-1} a_i X^i$ is uniquely determined by the vector of its coefficients $A = (a_0, \dots, a_{n-1})$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The evaluation of $p$ at an element $z$ is precisely the inner product between the vector $A$ of coefficients of $p$ and the vector $B$ of power of $z$. More precisely, if $p = \sum_{i=0}^{n-1} a_i X^i$, then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$ p(z) = \langle A, B\rangle,$$&lt;br &#x2F;&gt;
where $A = (a_0, \dots, a_n)$ and $B = (1, z, z^2, \dots, z^n)$.&lt;&#x2F;p&gt;
&lt;p&gt;As we’ll see shortly, the commitment of the polynomial $p$ is very similar to the commitment $P$ of $(A, B)$ in IPA. The open protocol is very similar too. And it proves that a value $c$ is actually $c = \langle A, B\rangle$, which is $p(z)$ by the way $B$ is defined.&lt;br &#x2F;&gt;
A major difference with IPA is that, in this case, the vector $B$ is always known to the verifier. So the terms that correspond to $B$ in the commitment are unnecessary. This makes the sequence $H_1,\dots, H_n$ unnecessary too. Instead of completely removing those terms, a random value is added by the prover, but with another purpose. It is called the &lt;em&gt;blinding factor&lt;&#x2F;em&gt; and it’s there to add zero knowledge to the protocols.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;setup-1&quot;&gt;Setup&lt;&#x2F;h3&gt;
&lt;p&gt;As with IPA, there is a setup phase where the needed ingredients are produced:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * A commutative group $\mathbb{G}$ with $p$ elements. As before, we&amp;#39;ll use additive notation.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * A sequences of elements $G_0,\dots, G_{n-1} \in \mathbb{G}$ and a single element $H\in\mathbb{G}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;commit-1&quot;&gt;Commit&lt;&#x2F;h3&gt;
&lt;p&gt;Given a polynomial $p = \sum_{i=0}^{n-1} a_i X^i$, to produce the commitment $[p]$ of it, the prover chooses a random value $r\in\mathbb{F}$ and computes&lt;&#x2F;p&gt;
&lt;p&gt;$$[p] := a_0G_0 + \cdots + a_{n-1}G_{n-1} + rH.$$&lt;&#x2F;p&gt;
&lt;p&gt;The value $r$ is called the &lt;em&gt;blinding factor&lt;&#x2F;em&gt;. The prover always keeps track of which values $r$ were used for each of the produced commitments $[p]$. This is because he’ll need them later on for the Open protocol. Formally, what we described is a commitment to the pair $(p, r)$ and we should write it as $[(p,r)]$. But to ease notation we drop the explicit mention to the blinding factor $r$.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;open-1&quot;&gt;Open&lt;&#x2F;h3&gt;
&lt;p&gt;Recall we are assuming here that the verifier already holds a commitment $[p]$ to a polynomial $p$, known to the prover. The prover also knows the value $r$ he used to produce the commitment $[p]$. Also, the verifier has already sent an element $z$ in $\mathbb{F}$ at which he wants to know the value of $p(z)$. The prover responded with a purpoted value $c$. What follows is the Open protocol in which they engage to convince the verifier that $c = p(z)$.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;case-n-2-1&quot;&gt;Case $n=2$&lt;&#x2F;h4&gt;
&lt;p&gt;Let’s begin with the base case. As with IPA, this will be the base case to which all the other cases reduce to.&lt;&#x2F;p&gt;
&lt;p&gt;When $n=2$, the polynomial $p$ is of degree at most $1$, that is, $p=a_0 + a_1 X$. Let $A=(a_0, a_1)$ and $B=(1, z)$. Define $b_0 = 1$ and $b_1=z$.&lt;&#x2F;p&gt;
&lt;p&gt;The interaction starts with the verifier choosing a random element $U$ in $\mathbb{G}$ and sending it to the prover.&lt;&#x2F;p&gt;
&lt;p&gt;The prover chooses random values $s, s’ \in \mathbb{F}$ and responds the verifier with the following elements&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $L := a_0G_1 + sH + a_0b_1U$ and&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $R := a_1G_0 + s&amp;#39;H + a_1b_0U$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The verifier chooses a random non-zero value $x\in\mathbb{F}$ and sends it to the prover, who uses it to compute the following elements.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $a&amp;#39; := a_0 x + a_1 x^{-1}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $b&amp;#39; := b_0 x^{-1} + b_1 x$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The prover sends $a’$ and $b’$ to the verifier along with the element $r’ := sx^2 + r + s’x^{ - 2}$. Finally, the verifier checks that:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\begin{equation}&lt;br &#x2F;&gt;
x^2 L + [p] + x^{-2} R + c U = x^{-1} a’ G_0 + xa’ G_1 + r’ H + a’b’U&lt;br &#x2F;&gt;
\end{equation}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;The verifier accepts if and only if the above equality holds.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;general-case-n-2-k&quot;&gt;General case $n=2^k$&lt;&#x2F;h4&gt;
&lt;p&gt;The idea is the same as in IPA. It is a recursive argument.&lt;&#x2F;p&gt;
&lt;p&gt;Let $n = 2^k$ and suppose $k&amp;gt;1$. If $k=1$, we follow the case $n=2$ described above.&lt;br &#x2F;&gt;
Write $p = \sum_{i=0}^{n-1}a_iX^i$. As before, define $A = (a_0,\dots, a_{2^k-1})$ and $B=(1, z, \dots, z^{n-1})$. Let the lower and higher parts of $A$ be the first and second halves of it. The same for the rest of the vectors involved.&lt;&#x2F;p&gt;
&lt;p&gt;The protocol starts also with the verifier choosing a random element $U$ in $\mathbb{G}$ and sending it to the prover.&lt;&#x2F;p&gt;
&lt;p&gt;The prover chooses random elements $s, s’$ in $\mathbb{F}$. He computes the following vectors and sends them to the verifier&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $L := \langle A_{lo}, G_{hi} \rangle + sH + \langle A_{lo}, B_{hi}\rangle U$, and&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $R := \langle A_{hi}, G_{lo} \rangle + s&amp;#39;H + \langle A_{hi}, B_{lo}\rangle U$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The verifier chooses a random non-zero value $x\in\mathbb{F}$ and sends it to the prover.&lt;&#x2F;p&gt;
&lt;p&gt;At this point, the next step starts. The prover computes&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $A&amp;#39; := x A_{lo} + x^{-1} A_{hi}$,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $B&amp;#39; := x^{-1} B_{lo} + x B_{hi}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;These will take the roles of $A$ and $B$. The following basis is used in the next round instead of $G$:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $G&amp;#39; := x^{-1} G_{lo} + x G_{hi}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The verifier accepts if and only if the check at the last step ($n$=2) succeeds.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;to-be-continued&quot;&gt;To be continued&lt;&#x2F;h1&gt;
&lt;p&gt;In a follow-up blogpost we’ll discuss the complexity of these protocols and we’ll see how they can be optimized and used in recursive arguments of knowledge.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Lambda Crypto Doctrine</title>
          <pubDate>Wed, 23 Aug 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/lambda-crypto-doctrine/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/lambda-crypto-doctrine/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/lambda-crypto-doctrine/">&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2023&#x2F;08&#x2F;image-1.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We believe crypto has been incredibly successful at providing a trustless financial layer for the 21st century. In particular it has found product market fit in two main areas:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * In developing countries providing aids and tools to individuals that need to fight against inflation, censorship and for companies and individuals to be able to business.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Internet native communities that need a financial layer in the web that allows them to express and coordinate at a scale that wasn’t possible before. They have created new financial assets and markets that seem absurd from outside. Many times they are also absurd from the inside.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;People that don’t live in a developing country or that didn’t grow up with the internet have enormous difficulties understanding crypto because they don’t have skin in its game. They believe crypto doesn’t have any “real” use case or that is not serious enough. They are right. The thing is that we are living in a world that’s is becoming more absurd. Memes do not only make you laugh anymore, memes are now winning elections.&lt;&#x2F;p&gt;
&lt;p&gt;We’re sure that these two use cases will grow with time and probably new ones will be found. The world is becoming more chaotic and more divided each day. The stability that existed since the fall of the Soviet Union and the beginning of the pandemic appears to have become a thing of the past. Only change will become the norm. And we love it.&lt;&#x2F;p&gt;
&lt;p&gt;This will make crypto even bigger. One of its prime advantages is that it kills many of the middlemen and allow us to coordinate even in the harshest environments. Trust assumptions are lowered thanks to economic incentives, compilers, distributed systems and cryptography. Crypto lowers the reliance on human beings. This empowers humans. It allows them to concentrate their disputes and efforts in subjectives areas. Crypto creates safe zones where some parts of the human activity becomes non-debatable (until quantum computers solve the discrete log problem).&lt;&#x2F;p&gt;
&lt;p&gt;Most of us are internet natives. We have been using irc, 4chan, reddit, hacker news, twitter, Bitcoin and Ethereum since their beginning and our organization has deep roots in unstable countries. In our roots we have a strange mix of knowing what it is to live in very chaotic societies and how to develop businesses within them and at the same time we are builders that love working in the frontier of engineering and scientific developments. We are the Fremen of crypto, raised in a harsh environment.&lt;&#x2F;p&gt;
&lt;p&gt;Open source and decentralization are not only philosophical ideas but necessary practical conditions to build crypto. Building in the open, helping onboard others and creating movements bigger than the original project are crucial for crypto projects to succeed long term. Sometimes it’s difficult for us to explain our actions to others that don’t follow the same ethos since we are not maximizing the same outcomes.&lt;&#x2F;p&gt;
&lt;p&gt;Our main objective is to help these new internet highways to be built in sustainable ways. Economic sustainability is one key aspect but there are others. We are a force that builds large technological projects but that also counterweights the natural tendency to centralize as a side effect of optimization. Centralization is easier and cheaper in the short run. If we would want to optimize money, there are easier ways to do it. The thing is that is not our main objective. We only see money as a tool to achieve our objectives.&lt;&#x2F;p&gt;
&lt;p&gt;With or without money you will find us building. You are invited to join us in our journey.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;“Top-down management leveraging command-and-control hierarchies are for the mahogany boardrooms of yesteryear. We are navigators, adventurers, and explorers of the future. We are married to the sea” - Yearn’s Blue Pill&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>How to code FRI from scratch</title>
          <pubDate>Fri, 18 Aug 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/how-to-code-fri-from-scratch/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/how-to-code-fri-from-scratch/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/how-to-code-fri-from-scratch/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2018&#x2F;046.pdf&quot;&gt;STARKs&lt;&#x2F;a&gt; (scalable transparent arguments of knowledge) have gained a lot of attention in recent years due to their capacity to help scale Ethereum and other L1s. They provide a way to guarantee the integrity of a computation carried out by an untrusted party via cryptographic proof. This proof can be verified much faster than the trivial check of the computation, that is, rerunning the whole computation by other parties. The key idea is that the whole computation can be expressed as a table of values and a set of polynomial constraints they must satisfy. This set of constraints can be converted into a random linear combination of quotients of polynomials of the form (we will not go into the details of this transformation. For an intro, see &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-industries&#x2F;stark101&quot;&gt;Stark-101&lt;&#x2F;a&gt; or &lt;a href=&quot;&#x2F;diving-deep-fri&#x2F;&quot;&gt;our blog&lt;&#x2F;a&gt;)&lt;br &#x2F;&gt;
$$p_0 (x) = \sum_k \alpha_k \frac{c_k (x)}{z_k (x)}$$&lt;br &#x2F;&gt;
where $c_k (x)$ and $z_k (x)$ are polynomials. The computation is valid if $p_0 (x)$ is a polynomial (if not, it will be a rational function) and will happen if each $c_k (x)$ is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Polynomial_long_division&quot;&gt;divisible&lt;&#x2F;a&gt; by its corresponding $z_k (x)$. How can we convince a verifier quickly that the previous $p_0 (x)$ is a polynomial? The key ingredient is the FRI protocol, which we will cover in the following sections. The code presented is taken from the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks_stark_platinum&#x2F;tree&#x2F;main&quot;&gt;Stark Platinum Prover&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If you want to learn more about the FRI protocol and its properties, we recommend you read &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2018&#x2F;046.pdf&quot;&gt;the original STARKs paper&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2022&#x2F;1216.pdf&quot;&gt;A summary on the FRI low degree test&lt;&#x2F;a&gt;. We want to thank Eli Ben-Sasson and the amazing Starkware team for helping us learn the protocol and in developing the prover.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-idea-behind-fri&quot;&gt;The idea behind FRI&lt;&#x2F;h2&gt;
&lt;p&gt;FRI stands for Fast Reed-Solomon Interactive oracle proof of proximity. It allows us to prove that the evaluations of a given function, $p$, over a domain, $D_0$ correspond to the evaluations of a low-degree polynomial (with respect to the size of $D_0$). Why is this useful?&lt;&#x2F;p&gt;
&lt;p&gt;Suppose we want to convince someone that we have some polynomial, $p_0$ of degree $N$. We could pass all the values of the $N+1$ coefficients or $N+1$ evaluations of the polynomial over some set. The problem is that we must pass $N+1$ numbers (in STARKs, the degree $N$ can be large), and the proof and verification will not be short. We could do better by reducing the degree of the polynomial by some suitable transformation. We can split the polynomial into the odd and even degree powers (we will suppose that $N$ is odd, but this doesn’t matter),&lt;br &#x2F;&gt;
$p_0 (x) = p_{0,e} ( x^2 ) + x p_{0,o} (x^2 )$&lt;br &#x2F;&gt;
where&lt;br &#x2F;&gt;
$p_{0,e} ( x^2 ) = a_0 + a_2 x^2 + a_4 x^4 + … + a_{N-1} x^{N-1}$&lt;br &#x2F;&gt;
and&lt;br &#x2F;&gt;
$p_{0,o} ( x^2 ) = a_1 + a_3 x^2 + a_5 x^4 + … + a_N x^{N-1}$&lt;br &#x2F;&gt;
we can randomly fold the two parts by getting a random $\beta_0$ and create a polynomial of degree $(N - 1) &#x2F; 2$,&lt;br &#x2F;&gt;
$p_1 (y) = (a_0 + \beta_0 a_1 ) + (a_2 + \beta_0 a_3 ) y + … + (a_{N-1} + \beta_0 a_N ) y^{(N - 1)&#x2F;2}$&lt;br &#x2F;&gt;
We could show that we have a polynomial by passing all the $(N + 1)&#x2F;2$ coefficients of $p_1 (y)$ and some evaluations of $p_0 (x)$ to show that we deduced correctly $p_1 (y)$ from $p_0 (x)$.&lt;&#x2F;p&gt;
&lt;p&gt;Of course, why would we stop with $(N + 1)&#x2F;2$ coefficients when we could further reduce the number of coefficients by repeating the same strategy?&lt;br &#x2F;&gt;
$p_1 (y) = p_{1,e} ( y^2 ) + y p_{1,o} (y^2 )$&lt;br &#x2F;&gt;
where&lt;br &#x2F;&gt;
$p_{1,e} ( y^2 ) = b_0 + b_2 y^2 + b_4 y^4 + … + b_{M} y^{M-1}$&lt;br &#x2F;&gt;
and&lt;br &#x2F;&gt;
$p_{1,o} ( y^2 ) = b_1 + b_3 y^2 + b_5 y^4 + … + b_M y^{M-1}$&lt;br &#x2F;&gt;
Then, we sample randomly $\beta_1$ and fold&lt;br &#x2F;&gt;
$p_2 (z) = (b_0 + \beta_1 b_1 ) + (b_2 + \beta_1 b_3 ) z + … + (b_{M-1} + \beta_1 a_M ) z^{(M - 1)&#x2F;2}$&lt;br &#x2F;&gt;
We can do this and reduce the degree of the polynomial by half at each step. After the $\log_2 (N)$ steps, we arrive at a constant polynomial and only need to pass that value. We could be convinced that we were given a polynomial if we could go down these foldings and arrive at the last constant value.&lt;&#x2F;p&gt;
&lt;p&gt;Below we give the rust code to fold a polynomial used in Lambdaworks:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn fold_polynomial&amp;lt;F&amp;gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    poly: &amp;amp;Polynomial&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    beta: &amp;amp;FieldElement&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; Polynomial&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;where&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    F: IsField,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let coef = poly.coefficients();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let even_coef: Vec&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt; = coef.iter().step_by(2).cloned().collect();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; odd coefficients of poly are multiplied by beta&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let odd_coef_mul_beta: Vec&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt; = coef&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .skip(1)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .step_by(2)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .map(|v| (v.clone()) * beta)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .collect();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let (even_poly, odd_poly) = Polynomial::pad_with_zero_coefficients(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;Polynomial::new(&amp;amp;even_coef),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;Polynomial::new(&amp;amp;odd_coef_mul_beta),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    even_poly + odd_poly&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The polynomial &lt;code&gt;poly&lt;&#x2F;code&gt; is a variable that contains the coefficients of the polynomial as a vector of field elements. We collect the values of even degree coefficients in line 9, and we take all the odd degree coefficients and multiply them by $\beta$ in lines 12 to 17 (we could also make it more efficient by zipping the iterators and avoiding collecting the results and then iterating again over the arrays to add the values).&lt;&#x2F;p&gt;
&lt;p&gt;The problem is that we need to ensure that the polynomials cannot be changed to generate random values. One way to bind us to a polynomial is to build a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Merkle_tree&quot;&gt;Merkle tree&lt;&#x2F;a&gt; from the evaluations of the polynomial over a suitable domain (this is the part where Reed-Solomon codes come into play). We take a domain $D_0 = { \omega, \omega g, \omega g^2 , … , \omega g^{\alpha N - 1} }$, where $g$ is a generator of the $\alpha N$ roots of unity and $\omega$ is an element outside the set generated by the powers of $g$. This way, we are forced to provide only values in the tree; the security of this scheme depends on the collision resistance of the hash function used to build the tree. For every folding step, we will have to make a layer containing the values of the evaluations of the polynomial and its corresponding Merkle tree. An advantage of using $D_0$ as a domain is that when we consider the domain $D_1$ for $y = x^2$, its size is exactly half the size of $D_0$. Therefore, the size of the tree for $p_1 (y)$ will be smaller than the size of the one corresponding to $p_0 (x)$ (this is a property of the $n$-th roots of unity, when $n$ is a power of 2. If $x_0$ is in the set, so is $- x_0$ and $x_0^2 = (- x_0)^2 = x_0^2$, so we only have $n&#x2F;2$ different elements).&lt;&#x2F;p&gt;
&lt;p&gt;FRI is also useful for creating a commitment scheme for polynomials using Merkle trees. If we want to show someone that we have a low degree polynomial $p(x)$ such that $p(z) = v$, we can evaluate the following quotient,&lt;br &#x2F;&gt;
$$q (x) = \frac{p(x) - v}{ x - z}$$&lt;br &#x2F;&gt;
and apply the FRI protocol to that quotient to show that it is indeed a low-degree polynomial.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;creating-fri-layers&quot;&gt;Creating FRI layers&lt;&#x2F;h2&gt;
&lt;p&gt;As mentioned before, we need to commit ourselves to our polynomial, and we will do that by creating a Merkle tree with the evaluations over a suitable domain. Below we provide a basic structure for a FriLayer: a vector of evaluations and a Merkle tree (we add the coset offset, $\omega$, and domain size just for convenience).&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#[derive(Clone)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub struct FriLayer&amp;lt;F&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;where&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    F: IsField,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    FieldElement&amp;lt;F&amp;gt;: ByteConversion,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub evaluation: Vec&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub merkle_tree: FriMerkleTree&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub coset_offset: FieldElement&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub domain_size: usize,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;impl&amp;lt;F&amp;gt; FriLayer&amp;lt;F&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;where&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    F: IsField + IsFFTField,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    FieldElement&amp;lt;F&amp;gt;: ByteConversion,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub fn new(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        poly: &amp;amp;Polynomial&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        coset_offset: &amp;amp;FieldElement&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        domain_size: usize,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ) -&amp;gt; Self {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let evaluation = poly&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .evaluate_offset_fft(1, Some(domain_size), coset_offset)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .unwrap(); &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let merkle_tree = FriMerkleTree::build(&amp;amp;evaluation);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Self {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            evaluation,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            merkle_tree,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            coset_offset: coset_offset.clone(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            domain_size,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We also provide a method to create layers, given a polynomial, the domain size, and the domain offset. This will be combined later with the folding function to create new polynomials and obtain the different layers.&lt;&#x2F;p&gt;
&lt;p&gt;Given the polynomial, we can evaluate it efficiently using FFT (due to the particular structure we are using) and obtain a vector of field elements, as shown in line 23. In line 27, we build the Merkle tree from the vector of evaluations (if you want to learn more on how the Merkle tree works behind the scenes, see &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;tree&#x2F;main&#x2F;crypto&#x2F;src&#x2F;merkle_tree&quot;&gt;here&lt;&#x2F;a&gt;). In the next section, we will show how to build and commit to all the FRI layers. After this stage, we can prove we committed to a low-degree polynomial.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;fri-commitment-phase&quot;&gt;FRI commitment phase&lt;&#x2F;h2&gt;
&lt;p&gt;Now that we can fold polynomials and build layers, we can commit to every layer and get the first part of the FRI protocol. The commit phase will give us a vector of layers and the final value of the FRI protocol (when we get to a degree zero polynomial). The function needs to receive the number of layers (which can be obtained from the degree of the polynomial), the polynomial in coefficient form, the transcript of the protocol (we will be appending here the roots of the Merkle trees and use this to generate the random challenges by the Fiat-Shamir transformation), the offset and domain size (we could give the domain $D_0$ instead of these last two). The domain size determines the size of the group of roots of unity, and the offset allows us to shift that group.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn fri_commit_phase&amp;lt;F: IsField + IsFFTField, T: Transcript&amp;gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    number_layers: usize,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    p_0: Polynomial&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transcript: &amp;amp;mut T,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    coset_offset: &amp;amp;FieldElement&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    domain_size: usize,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; (FieldElement&amp;lt;F&amp;gt;, Vec&amp;lt;FriLayer&amp;lt;F&amp;gt;&amp;gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;where&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    FieldElement&amp;lt;F&amp;gt;: ByteConversion,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut domain_size = domain_size;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut fri_layer_list = Vec::with_capacity(number_layers);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut current_layer = FriLayer::new(&amp;amp;p_0, coset_offset, domain_size);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    fri_layer_list.push(current_layer.clone());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut current_poly = p_0;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; &amp;gt;&amp;gt;&amp;gt;&amp;gt; Send commitment: [p₀]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transcript.append(&amp;amp;current_layer.merkle_tree.root);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut coset_offset = coset_offset.clone();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for _ in 1..number_layers {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F; &amp;lt;&amp;lt;&amp;lt;&amp;lt; Receive challenge 𝜁ₖ₋₁&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let zeta = transcript_to_field(transcript);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        coset_offset = coset_offset.square();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        domain_size &#x2F;= 2;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F; Compute layer polynomial and domain&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        current_poly = fold_polynomial(&amp;amp;current_poly, &amp;amp;zeta);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        current_layer = FriLayer::new(&amp;amp;current_poly, &amp;amp;coset_offset, domain_size);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let new_data = &amp;amp;current_layer.merkle_tree.root;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        fri_layer_list.push(current_layer.clone()); &#x2F;&#x2F; TODO: remove this clone&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F; &amp;gt;&amp;gt;&amp;gt;&amp;gt; Send commitment: [pₖ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        transcript.append(new_data);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; &amp;lt;&amp;lt;&amp;lt;&amp;lt; Receive challenge: 𝜁ₙ₋₁&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let zeta = transcript_to_field(transcript);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let last_poly = fold_polynomial(&amp;amp;current_poly, &amp;amp;zeta);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let last_value = last_poly&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .coefficients()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .get(0)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .unwrap_or(&amp;amp;FieldElement::zero())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .clone();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; &amp;gt;&amp;gt;&amp;gt;&amp;gt; Send value: pₙ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transcript.append(&amp;amp;last_value.to_bytes_be());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    (last_value, fri_layer_list)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We start by creating the layer for the first polynomial (which, in the context of a STARK prover, is the DEEP composition polynomial) at line 14. Then, we commit to the polynomial evaluations using the Merkle tree by appending the root to the transcript (line 18).&lt;&#x2F;p&gt;
&lt;p&gt;Afterward, we continue with the recursive part of FRI: we sample the random coefficient ($\zeta$ in the code, line 24), we square the offset and reduce the domain size (so that we can generate the next evaluation domain), and we fold the polynomial in line 29. We obtain the new layer (line 30), add the root to the transcript (so that we commit to the evaluations of the new polynomial) and add the new layer to the vector of FriLayers. After we have gone through the recursive parts, we fold one last time to arrive at the degree zero polynomial and get the final value, which we also append to the transcript (line 50).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;fri-decommitment&quot;&gt;FRI decommitment&lt;&#x2F;h2&gt;
&lt;p&gt;Now that we created all the commitments, we need to generate the proof so that a verifier can check that everything was done correctly. The only things we can pass to the verifier are values that we committed to by using Merkle trees. Any evaluation in a tree can be calculated from the evaluations inside a tree in the previous layers. We can see that:&lt;br &#x2F;&gt;
$$p_{0,e} (x) = \frac{p_0 (x) + p_0( - x )}{2}$$&lt;br &#x2F;&gt;
and&lt;br &#x2F;&gt;
$$p_{0,o} (x) = \frac{p_0 (x) - p_0( - x )}{2x}$$&lt;br &#x2F;&gt;
Luckily, if $p_0 (x_0)$ is in the Merkle tree, so is $p_0 (- x_0 )$, because of how we chose the domain $D_0$ . We can see then that&lt;br &#x2F;&gt;
$$p_1 ( x_0^2 ) = \frac{p_0 ( x_0 ) + p_0( - x_0 )}{2} + \beta_0 \frac{(p_0 ( x_0 ) - p_0( - x_0 ))}{2x_0}$$&lt;br &#x2F;&gt;
Similarly,&lt;br &#x2F;&gt;
$$p_k ( w_0^2 ) = \frac{p_{k - 1} ( w_0 ) + p_{ k - 1}( - w_0 )}{2} + \beta_0 \frac{(p_{ k - 1 } ( w_0 ) - p_{ k - 1}( - w_0 ))}{2w_0}$$&lt;br &#x2F;&gt;
Therefore, we can check a value in a tree if we pass two values from the tree from the previous layer (these have to be the correct pair, which, owing to the structure of the evaluation domain, are always separated by half the length of the size of the tree).&lt;&#x2F;p&gt;
&lt;p&gt;We will let the verifier choose an index in the Merkle tree of $p_0 (x)$. We will provide the verifier with the values of $p_0 (x_0)$ (where $x_0$ is the point in the domain corresponding to the index chosen by the verifier) and $p_0 (-x_0)$, $p_1 ( x_0^2 )$, $p_1 ( - (x_0^2 ))$, $p_2 ( x_0^4 )$, $p_2 ( - (x_0^4 ))$ until $p_{ N - 1 } ( x_0^{ 2^{ N - 1 }} )$, $p_{ N - 1} ( - (x_0^{ 2^{ N - 1 }} ))$. This way, the verifier can go from the first polynomial to the final value and check that we did everything correctly. We must also show him that the values we passed belong to their correspondent Merkle tree. We will do this by providing him with an inclusion proof, given by the authentication paths for each value. If the inclusion proofs and calculations between the layers pass, the verifier will be convinced that we did things correctly for one point. However, passing the test for one point does not mean that the function is indeed a polynomial because FRI has a statistical nature. Of course, the verifier could choose more points, and if the test passes for all points, the verifier could be convinced with a high probability that the function is indeed a polynomial. We will call each point the verifier chooses a query (the higher the number of queries, the more likely the prover will be caught cheating).&lt;&#x2F;p&gt;
&lt;p&gt;To handle each query better, we will have a FriDecommitment structure containing all the evaluation pairs (&lt;code&gt;layers_evaluations&lt;&#x2F;code&gt; and &lt;code&gt;layers_evaluations_sym&lt;&#x2F;code&gt;) and authentication paths for each (&lt;code&gt;layers_auth_paths&lt;&#x2F;code&gt; and &lt;code&gt;layers_auth_paths_sym&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub struct FriDecommitment&amp;lt;F: IsPrimeField&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub layers_auth_paths_sym: Vec&amp;lt;Proof&amp;lt;Commitment&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub layers_evaluations_sym: Vec&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub layers_auth_paths: Vec&amp;lt;Proof&amp;lt;Commitment&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub layers_evaluations: Vec&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can now jump onto the query phase of the protocol and obtain the proof for the FRI protocol. Since we want the protocol to be non-interactive, we need the transcript (to simulate the verifier by Fiat-Shamir transformation), all the information from the FriLayers, and other parameters, such as the number of queries (contained here inside the air).&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn fri_query_phase&amp;lt;F, A, T&amp;gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    air: &amp;amp;A,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    domain_size: usize,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    fri_layers: &amp;amp;Vec&amp;lt;FriLayer&amp;lt;F&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transcript: &amp;amp;mut T,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; (Vec&amp;lt;FriDecommitment&amp;lt;F&amp;gt;&amp;gt;, Vec&amp;lt;usize&amp;gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;where&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    F: IsFFTField,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    A: AIR&amp;lt;Field = F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    T: Transcript,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    FieldElement&amp;lt;F&amp;gt;: ByteConversion,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if !fri_layers.is_empty() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let number_of_queries = air.options().fri_number_of_queries;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let iotas = (0..number_of_queries)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .map(|_| (transcript_to_u32(transcript) as usize) % domain_size)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .collect::&amp;lt;Vec&amp;lt;usize&amp;gt;&amp;gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let query_list = iotas&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .map(|iota_s| {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                &#x2F;&#x2F; &amp;lt;&amp;lt;&amp;lt;&amp;lt; Receive challenge 𝜄ₛ (iota_s)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                let mut layers_auth_paths_sym = vec![];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                let mut layers_evaluations_sym = vec![];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                let mut layers_evaluations = vec![];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                let mut layers_auth_paths = vec![];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                for layer in fri_layers {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    &#x2F;&#x2F; symmetric element&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    let index = iota_s % layer.domain_size;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    let index_sym = (iota_s + layer.domain_size &#x2F; 2) % layer.domain_size;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    let evaluation_sym = layer.evaluation[index_sym].clone();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    let auth_path_sym = layer.merkle_tree.get_proof_by_pos(index_sym).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    let evaluation = layer.evaluation[index].clone();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    let auth_path = layer.merkle_tree.get_proof_by_pos(index).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    layers_auth_paths_sym.push(auth_path_sym);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    layers_evaluations_sym.push(evaluation_sym);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    layers_evaluations.push(evaluation);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    layers_auth_paths.push(auth_path);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                FriDecommitment {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    layers_auth_paths_sym,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    layers_evaluations_sym,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    layers_evaluations,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    layers_auth_paths,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .collect();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        (query_list, iotas)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    } else {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        (vec![], vec![])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In line 15, we sample all the indexed to open in the Merkle tree belonging to $p_0 (x)$. We normalize by the domain size to ensure the queries fall in the range. Once we get all the indexes to query, we can iterate over them as in line 18 (in this case, we could do it in parallel). For each index, we will go through each FriLayer and get the indexes for $p_k ( u )$ and $p_k ( - u)$ (this is done by taking the remainder between the current index and the domain size for the FriLayer), as in lines 29 and 30, and then take the values of the leaves in the Merkle tree (lines 31 and 33), together with the corresponding authentication paths (lines 32 and 34). We then add each to the vectors containing the evaluations and authentication paths for each query. Finally, we get the complete list of queries and all the necessary values.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;verification&quot;&gt;Verification&lt;&#x2F;h2&gt;
&lt;p&gt;If a verifier wants to check our work, he needs to perform both the inclusion proofs (to see all values belong to Merkle trees) and that each layer is obtained from the previous one until we reach degree zero. Since the protocol was done non-interactively, the verifier must replay all the random $\beta_k$. We will only focus on the FRI part, but remember that in a general STARK prover, we have more work before that:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let merkle_roots = &amp;amp;proof.fri_layers_merkle_roots;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let zetas = merkle_roots&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .map(|root| {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; &amp;lt;&amp;lt;&amp;lt;&amp;lt; Receive commitment: [pₖ] (the first one is [p₀])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            transcript.append(root);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F; &amp;gt;&amp;gt;&amp;gt;&amp;gt; Send challenge 𝜁ₖ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            transcript_to_field(transcript)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .collect::&amp;lt;Vec&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt;&amp;gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; &amp;lt;&amp;lt;&amp;lt;&amp;lt; Receive value: pₙ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transcript.append(&amp;amp;proof.fri_last_value.to_bytes_be());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Receive grinding value&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; 1) Receive challenge from the transcript&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let transcript_challenge = transcript.challenge();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let nonce = proof.nonce;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let leading_zeros_count =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        hash_transcript_with_int_and_get_leading_zeros(&amp;amp;transcript_challenge, nonce);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transcript.append(&amp;amp;nonce.to_be_bytes());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; FRI query phase&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; &amp;lt;&amp;lt;&amp;lt;&amp;lt; Send challenges 𝜄ₛ (iota_s)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let iota_max: usize = 2_usize.pow(domain.lde_root_order);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let iotas: Vec&amp;lt;usize&amp;gt; = (0..air.options().fri_number_of_queries)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .map(|_| (transcript_to_u32(transcript) as usize) % iota_max)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .collect();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The verifier appends to the transcript the roots of each Merkle tree, one at a time, and gets the value for $\beta_k$ (lines 2 to 11). Then, the verifier adds the final value of the FRI protocol (line 14); if there is proof of work, after the verifier has checked that the nonce provided is correct (done before), he adds the nonce to the transcript and samples all the indexes.&lt;&#x2F;p&gt;
&lt;p&gt;With this, the verifier can proceed to check all queries,&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn verify_fri&amp;lt;F, A&amp;gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    proof: &amp;amp;StarkProof&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    domain: &amp;amp;Domain&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    challenges: &amp;amp;Challenges&amp;lt;F, A&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; bool&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;where&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    F: IsFFTField,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    FieldElement&amp;lt;F&amp;gt;: ByteConversion,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    A: AIR&amp;lt;Field = F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; verify FRI&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let two_inv = &amp;amp;FieldElement::from(2).inv();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut evaluation_point_inverse = challenges&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .iotas&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .map(|iota| &amp;amp;domain.lde_roots_of_unity_coset[*iota])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .cloned()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .collect::&amp;lt;Vec&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt;&amp;gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    FieldElement::inplace_batch_inverse(&amp;amp;mut evaluation_point_inverse);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    proof&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .query_list&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .zip(&amp;amp;challenges.iotas)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .zip(evaluation_point_inverse)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .fold(true, |mut result, ((proof_s, iota_s), eval)| {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F;&#x2F;This is done in constant time&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            result &amp;amp;= verify_query_and_sym_openings(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                proof,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                &amp;amp;challenges.zetas,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                *iota_s,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                proof_s,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                domain,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                eval,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                two_inv,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            result&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this function, the verifier receives all the FriDecommitment (contained in the StarkProof), the domain $D_0$ (which includes all evaluation points), and the challenges (indexes) sampled by replaying what the prover did. Lines 12 to 19 are just optimizations for performance, where the verifier computes the inverses of the evaluation points in batch (this is to calculate divisions more efficiently). Then, the verifier proceeds to check each query. The function &lt;code&gt;verify_query_and_sym_openings&lt;&#x2F;code&gt; has the following code:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn verify_query_and_sym_openings&amp;lt;F: IsField + IsFFTField&amp;gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    proof: &amp;amp;StarkProof&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    zetas: &amp;amp;[FieldElement&amp;lt;F&amp;gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    iota: usize,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    fri_decommitment: &amp;amp;FriDecommitment&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    domain: &amp;amp;Domain&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    evaluation_point: FieldElement&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    two_inv: &amp;amp;FieldElement&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; bool&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;where&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    FieldElement&amp;lt;F&amp;gt;: ByteConversion,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let fri_layers_merkle_roots = &amp;amp;proof.fri_layers_merkle_roots;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let evaluation_point_vec: Vec&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt; =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        core::iter::successors(Some(evaluation_point), |evaluation_point| {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            Some(evaluation_point.square())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .take(fri_layers_merkle_roots.len())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .collect();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut v = fri_decommitment.layers_evaluations[0].clone();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; For each fri layer merkle proof check:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; That each merkle path verifies&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Sample beta with fiat shamir&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Compute v = [P_i(z_i) + P_i(-z_i)] &#x2F; 2 + beta * [P_i(z_i) - P_i(-z_i)] &#x2F; (2 * z_i)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Where P_i is the folded polynomial of the i-th fiat shamir round&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; z_i is obtained from the first z (that was derived through Fiat-Shamir) through a known calculation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; The calculation is, given the index, index % length_of_evaluation_domain&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Check that v = P_{i+1}(z_i)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; For each (merkle_root, merkle_auth_path) &#x2F; fold&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; With the auth path containing the element that the path proves its existence&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    fri_layers_merkle_roots&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .enumerate()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .zip(&amp;amp;fri_decommitment.layers_auth_paths)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .zip(&amp;amp;fri_decommitment.layers_evaluations)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .zip(&amp;amp;fri_decommitment.layers_auth_paths_sym)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .zip(&amp;amp;fri_decommitment.layers_evaluations_sym)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .zip(evaluation_point_vec)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .fold(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            true,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            |result,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             (&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                (((((k, merkle_root), auth_path), evaluation), auth_path_sym), evaluation_sym),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                evaluation_point_inv,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            )| {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                let domain_length = 1 &amp;lt;&amp;lt; (domain.lde_root_order - k as u32);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                let layer_evaluation_index_sym = (iota + domain_length &#x2F; 2) % domain_length;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                &#x2F;&#x2F; Since we always derive the current layer from the previous layer&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                &#x2F;&#x2F; We start with the second one, skipping the first, so the previous layer is the first one&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                &#x2F;&#x2F; This is the current layer&amp;#39;s evaluation domain length.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                &#x2F;&#x2F; We need to know what the decommitment index for the current&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                &#x2F;&#x2F; layer is so we can check the Merkle paths at the right index.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                &#x2F;&#x2F; Verify opening Open(pₖ(Dₖ), −𝜐ₛ^(2ᵏ))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                let auth_sym = &amp;amp;auth_path_sym.verify::&amp;lt;FriMerkleTreeBackend&amp;lt;F&amp;gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    merkle_root,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    layer_evaluation_index_sym,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    evaluation_sym,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                &#x2F;&#x2F; Verify opening Open(pₖ(Dₖ), 𝜐ₛ)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                let auth_point =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    auth_path.verify::&amp;lt;FriMerkleTreeBackend&amp;lt;F&amp;gt;&amp;gt;(merkle_root, iota, evaluation);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                let beta = &amp;amp;zetas[k];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                &#x2F;&#x2F; v is the calculated element for the co-linearity check&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                v = (&amp;amp;v + evaluation_sym) * two_inv&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    + beta * (&amp;amp;v - evaluation_sym) * two_inv * evaluation_point_inv;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                &#x2F;&#x2F; Check that the next value is given by the prover&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                if k &amp;lt; fri_decommitment.layers_evaluations.len() - 1 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    let next_layer_evaluation = &amp;amp;fri_decommitment.layers_evaluations[k + 1];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    result &amp;amp; (v == *next_layer_evaluation) &amp;amp; auth_point &amp;amp; auth_sym&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                } else {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    result &amp;amp; (v == proof.fri_last_value) &amp;amp; auth_point &amp;amp; auth_sym&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;At each step, we have to divide by $x_0^{ 2^{ k } }$, which is the same as multiplying by the (multiplicative) inverse. We previously precomputed $x_0^{ - 1}$, and all the other inverses can be computed by repeatedly squaring that number (lines 14 to 19). Afterward, the verifier can go through all the FriLayers. We will use a fold iterator to have a constant time implementation (lines 35 to 43). If any check is false, then the proof will fail. The verifier samples the indexes for the current layer (line 51). Then, the verifier checks the inclusion proofs for the values (lines 59 and 65). Then, the verifier computes the value for the next layer from the current one (lines 69-70). If we are not in the last layer, the verifier checks whether this computed value is equal to the value given in the decommitment for the next layer (lines 73-75); if this does not pass, the test will fail. If it is the last layer, the verifier compares the computed value with the last value of the FRI protocol.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;security&quot;&gt;Security&lt;&#x2F;h2&gt;
&lt;p&gt;The security of FRI depends on the size of the finite field, the security of the hash function, and the number of queries. Let’s dive into each aspect:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. The finite field size should be much larger than the degree of the polynomial (which in a STARK prover is related to the trace length). To achieve 128 bits of security, the field size should be at least $2^{128}$. If the maximum trace length is $2^{30}$, the field should be at least $2^{158}$. If the base field is not large enough, we can work with extensions when sampling random challenges. Some common choices are the StarkPrime 252, the prime $2^{64} - 2^{32} + 1$ (often miscalled MiniGoldilocks and using degree 3 extension fields), BabyBear or Mersenne 31 ($2^{31} - 1$, using degree 6 extension).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. The security provided by the hash function should be at least the security level we aim at. For hash functions such as SHA2, SHA3, Blake2, Blake3, and Poseidon, the security is simply the size of the digest (hash) divided by two. Therefore, using digests of 32 bytes (256 bits) achieves the desired security level. If we want to cover ourselves against Grover&amp;#39;s algorithm from quantum computers, we need to double the digest size to 64 bytes (512 bits). This increases the size of the proof.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. The number of queries. Each query provides a certain amount of bits of security, depending on the blowup factor used. The number of queries can be reduced by introducing proof of work into the prover&amp;#39;s protocol, incrementing the cost of generating false proofs. There is a tradeoff between the blowup factor used (which increases the prover&amp;#39;s work and memory use) and the number of queries (which increases the proof size and verifier&amp;#39;s work).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For more discussion into the security of FRI, see &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2021&#x2F;582&quot;&gt;EthSTARK&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2022&#x2F;1216.pdf&quot;&gt;A summary on FRI low degree testing&lt;&#x2F;a&gt;, and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2023&#x2F;1071&quot;&gt;Fiat-Shamir security of FRI&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;FRI is a proximity test that allows us to show that a specific function is close to a low-degree polynomial, which is a helpful tool to build proof systems, such as STARKs or Plonky2.&lt;br &#x2F;&gt;
In this post, we covered how to code the protocol from scratch (except for the necessary Merkle trees and finite field arithmetic) and how to verify a FRI proof. The protocol consists of randomly folding a polynomial and committing to the evaluations of the polynomial over a suitable domain using Merkle trees until the resulting polynomial has degree zero. To show that the protocol was carried out correctly, the prover must supply evaluations of each polynomial and prove that those values are inside the Merkle tree. The protocol’s security relies on the properties of the hash function and depends on the size of the field, the size of the digest, and the number of queries used.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>First Lambda-Ingo ZK CTF: ZK challenges using LambdaWorks</title>
          <pubDate>Sun, 30 Jul 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/first-lambda-ingo-zk-ctf-zk-challenges-using-lambdaworks/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/first-lambda-ingo-zk-ctf-zk-challenges-using-lambdaworks/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/first-lambda-ingo-zk-ctf-zk-challenges-using-lambdaworks/">&lt;h1 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h1&gt;
&lt;p&gt;From July 14th to 16th, we organized, together with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.ingonyama.com&#x2F;&quot;&gt;Ingonyama&lt;&#x2F;a&gt;, the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;ctf.ingonyama.com&#x2F;&quot;&gt;first Lambda-Ingo ZK capture the flag&lt;&#x2F;a&gt; (CTF), where more than 60 teams and 160 people participated. The CTF involved several challenges related to zero-knowledge proofs (using &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&quot;&gt;Lambdaworks&lt;&#x2F;a&gt;) and fully-homomorphic encryption. We are thrilled with the whole experience, especially our second collaboration with Ingonyama and all the sponsors of the Lambda ZK week in Paris.&lt;&#x2F;p&gt;
&lt;p&gt;The challenges were meant as example exercises to learn how to use Lambdaworks (especially the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;starknet_stack_prover_lambdaworks&quot;&gt;Starknet Stack&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks_plonk_prover&quot;&gt;Plonk&lt;&#x2F;a&gt; provers) and get an intuition of different vulnerabilities and bugs that can arise in those systems. If you want to know more about the development of the library or wish to contribute, join our &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;t.me&#x2F;+98Whlzql7Hs0MDZh&quot;&gt;telegram group&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;This post will present the challenges we submitted for the CTF and explain how they can be solved.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;plonk-challenges&quot;&gt;Plonk challenges&lt;&#x2F;h1&gt;
&lt;p&gt;There were two challenges related to Plonk and possible vulnerabilities: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;blog.trailofbits.com&#x2F;2022&#x2F;04&#x2F;18&#x2F;the-frozen-heart-vulnerability-in-plonk&#x2F;&quot;&gt;frozen heart&lt;&#x2F;a&gt; and lack of blinding polynomials.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;obi-wan-s-search&quot;&gt;Obi-Wan’s search&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;challenge&quot;&gt;Challenge&lt;&#x2F;h3&gt;
&lt;p&gt;In his quest to stop the Sith’s menace, Obi-Wan Kenobi finds a (Sith) holocron, giving a zero-knowledge proof of the existence of the Sith’s galactic foundry (using galactic Plonk).&lt;&#x2F;p&gt;
&lt;p&gt;This place is rumored to contain several artifacts that could aid the Galactic Republic in its war efforts. The position, given by $(x , h , y)$, satisfies the equation $y = x \times h + b$.&lt;&#x2F;p&gt;
&lt;p&gt;After some study, Obi-Wan finds the values of $y$ and $b$ (which belong to Sith lore). The only problem is that, even with this knowledge, it may take him quite long to find the mysterious planet, and the situation in the Republic is desperate.&lt;&#x2F;p&gt;
&lt;p&gt;He also finds, together with the Holocron, a second item containing the SRS used to generate the proof, the prover, and a description of the circuit used.&lt;&#x2F;p&gt;
&lt;p&gt;Will he be able to find the position of the foundry before it is too late?&lt;&#x2F;p&gt;
&lt;p&gt;All the additional information is in this &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;obi_wan_search&quot;&gt;repo&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;FLAG FORMAT: XXXX……..XXXX The flag consists of the x and h concatenated and written in hex (for example, x=0x123, h=0x789, the FLAG=123789)&lt;&#x2F;p&gt;
&lt;h3 id=&quot;solution&quot;&gt;Solution&lt;&#x2F;h3&gt;
&lt;p&gt;The challenge is finding the witness variables $x$ and $h$, given the values $y$ and $b$. Usually, we could not get access to these values, given the zero-knowledge property the Plonk system has. However, in this case, there is one fault in the prover: there are no blinding polynomials, and we can exploit this vulnerability to recover the unknowns.&lt;&#x2F;p&gt;
&lt;p&gt;The first round of PLONK reads as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Compute polynomials a&amp;#39;,b&amp;#39;,c&amp;#39; as the interpolation polynomials of the columns of T at the domain H.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Sample random b_1, b_2, b_3, b_4, b_5, b_6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Let&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;a := (b_1X + b_2)Z_H + a&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;b := (b_3X + b_4)Z_H + b&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;c := (b_5X + b_6)Z_H + c&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Compute [a]_1, [b]_1, [c]_1 and add them to the transcript.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The multiples of $Z_H$ added to $ a’, b’, c’$ are called the blindings. In subsequent rounds, the polynomials $a, b, c$ are opened at the verifier’s chosen point.&lt;&#x2F;p&gt;
&lt;p&gt;The polynomials $Z_H$ are the vanishing polynomials over the interpolation domain; they are equal to zero at each point in the set $H$. Therefore, adding that polynomial (or any combination) will not change the value of the $a^\prime$, $b^\prime$, and $c^\prime$ polynomials, which must satisfy the circuit equations. However, at any other point, they will add some randomness and help conceal the values.&lt;&#x2F;p&gt;
&lt;p&gt;By checking the code of the challenge, the participants can find the following in &lt;code&gt;circuit.rs.&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; Witness generator for the circuit `ASSERT y == x * h + b`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn circuit_witness(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    b: &amp;amp;FrElement,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    y: &amp;amp;FrElement,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    h: &amp;amp;FrElement,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    x: &amp;amp;FrElement,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; Witness&amp;lt;FrField&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let z = x * h;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let w = &amp;amp;z + b;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let empty = b.clone();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Witness {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        a: vec![&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            b.clone(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            y.clone(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            x.clone(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            b.clone(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            w.clone(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            empty.clone(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            empty.clone(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            empty.clone(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This code reveals that the way prover constructs the $V$ matrix is&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;A&lt;&#x2F;th&gt;&lt;th&gt;B&lt;&#x2F;th&gt;&lt;th&gt;C&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;b&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;y&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;x&lt;&#x2F;td&gt;&lt;td&gt;h&lt;&#x2F;td&gt;&lt;td&gt;z&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;b&lt;&#x2F;td&gt;&lt;td&gt;z&lt;&#x2F;td&gt;&lt;td&gt;w&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;w&lt;&#x2F;td&gt;&lt;td&gt;y&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;ul&gt;
&lt;li&gt;| - | -&lt;&#x2F;li&gt;
&lt;li&gt;| - | -&lt;&#x2F;li&gt;
&lt;li&gt;| - | -&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Where &lt;code&gt;-&lt;&#x2F;code&gt; are empty values. The PLONK implementation of &lt;code&gt;lambdaworks-plonk&lt;&#x2F;code&gt; requires the empty values to be filled in with the first public input. So, in this case, the values &lt;code&gt;-&lt;&#x2F;code&gt; will be replaced by $b$. This can be seen directly from the code of the challenge.&lt;&#x2F;p&gt;
&lt;p&gt;Therefore, the polynomial $a’$, being the interpolation of the column &lt;code&gt;A&lt;&#x2F;code&gt; is&lt;&#x2F;p&gt;
&lt;p&gt;$$a’ = b L_1 + y L_2 + x L_3 + b L_4 + w L_5 + b L_6 + b L_7 + b L_8,$$&lt;&#x2F;p&gt;
&lt;p&gt;where $L_i$ is the $i$-th polynomial of the Lagrange basis. Also, the value $w$ is equal to $y$. That can be seen from the code and the fact that the last row of the $V$ matrix corresponds to the assertion that the actual output of the circuit is equal to the claimed output $y$.&lt;&#x2F;p&gt;
&lt;p&gt;During the proof, the verifier sends a challenge $\zeta$ and the prover opens, among other things, the polynomial $a$ at $\zeta$. Since the implementation of the challenge omits blindings, $a(\zeta) = a’ (\zeta)$, and we get&lt;&#x2F;p&gt;
&lt;p&gt;$$a(\zeta) = b L_1(\zeta) + y L_2(\zeta) + x L_3(\zeta) + b L_4(\zeta) + y L_5(\zeta) + b L_6(\zeta) + b L_7(\zeta) + b L_8(\zeta).$$&lt;&#x2F;p&gt;
&lt;p&gt;All the terms in this expression are known to the participants except for $x$, which can be cleared from the equation. To do so, the participants need to know how to recover the challenges to get $\zeta$ and how to compute the Lagrange polynomials evaluated at it.&lt;&#x2F;p&gt;
&lt;p&gt;The second private input $h$ can be computed as $h = (y - b) &#x2F; x$. The following piece of code recovers the challenge $\zeta$, computes the Lagrange polynomials at $\zeta$ and recovers $x$ and $h$:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn compute_private_input&amp;lt;F, CS&amp;gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    proof: &amp;amp;Proof&amp;lt;F, CS&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    vk: &amp;amp;VerificationKey&amp;lt;CS::Commitment&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    public_input: &amp;amp;[FieldElement&amp;lt;F&amp;gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    common_preprocessed_input: &amp;amp;CommonPreprocessedInput&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; (FieldElement&amp;lt;F&amp;gt;, FieldElement&amp;lt;F&amp;gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;where&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    F: IsField,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    CS: IsCommitmentScheme&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    CS::Commitment: Serializable,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    FieldElement&amp;lt;F&amp;gt;: ByteConversion,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Replay interactions to recover challenges. We are only interested in \zeta&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut transcript = new_strong_fiat_shamir_transcript::&amp;lt;F, CS&amp;gt;(vk, public_input);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transcript.append(&amp;amp;proof.a_1.serialize());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transcript.append(&amp;amp;proof.b_1.serialize());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transcript.append(&amp;amp;proof.c_1.serialize());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let _beta = FieldElement::from_bytes_be(&amp;amp;transcript.challenge()).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let _gamma = FieldElement::from_bytes_be(&amp;amp;transcript.challenge()).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transcript.append(&amp;amp;proof.z_1.serialize());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let _alpha = FieldElement::from_bytes_be(&amp;amp;transcript.challenge()).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transcript.append(&amp;amp;proof.t_lo_1.serialize());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transcript.append(&amp;amp;proof.t_mid_1.serialize());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transcript.append(&amp;amp;proof.t_hi_1.serialize());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let zeta = FieldElement::from_bytes_be(&amp;amp;transcript.challenge()).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Compute `x` and `h`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let [b, y] = [&amp;amp;public_input[0], &amp;amp;public_input[1]];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let n = common_preprocessed_input.n as u64;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let omega = &amp;amp;common_preprocessed_input.omega;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let domain = &amp;amp;common_preprocessed_input.domain;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Compute L_1(\zeta). This polynomial is equal to zero at&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;each point in the domain, except for the first one&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;where it is equal to unity&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let l1_zeta =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        (zeta.pow(n) - FieldElement::one()) &#x2F; (&amp;amp;zeta - FieldElement::one()) &#x2F; FieldElement::from(n);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut li_zeta = l1_zeta;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut lagrange_basis_zeta = Vec::new();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    lagrange_basis_zeta.push(li_zeta.clone());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Compute all other Lagrange polynomials using&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; the relationship among them&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for i in 1..domain.len() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        li_zeta = omega * &amp;amp;li_zeta * ((&amp;amp;zeta - &amp;amp;domain[i - 1]) &#x2F; (&amp;amp;zeta - &amp;amp;domain[i]));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        lagrange_basis_zeta.push(li_zeta.clone());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Recover x by relating a at \zeta and the public inputs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let x = (&amp;amp;proof.a_zeta&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        - b * &amp;amp;lagrange_basis_zeta[3]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        - y * &amp;amp;lagrange_basis_zeta[4]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        - b * &amp;amp;lagrange_basis_zeta[0]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        - y * &amp;amp;lagrange_basis_zeta[1]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        - b * &amp;amp;lagrange_basis_zeta[5]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        - b * &amp;amp;lagrange_basis_zeta[6]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        - b * &amp;amp;lagrange_basis_zeta[7])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F; &amp;amp;lagrange_basis_zeta[2];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Recover h given that x is known    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let h = (y - b) &#x2F; &amp;amp;x;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    (x, h)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The solution for the coordinates is:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. `x: &amp;quot;2194826651b32ca1055614fc6e2f2de86eab941d2c55bd467268e9&amp;quot;`,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. `h: &amp;quot;432904cca36659420aac29f8dc5e5bd0dd57283a58ab7a8ce4d1ca&amp;quot;`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The flag is the concatenation of the two: &lt;code&gt;FLAG: 2194826651b32ca1055614fc6e2f2de86eab941d2c55bd467268e9432904cca36659420aac29f8dc5e5bd0dd57283a58ab7a8ce4d1ca&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;loki-s-trapdoor&quot;&gt;Loki’s trapdoor&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;challenge-1&quot;&gt;Challenge&lt;&#x2F;h3&gt;
&lt;p&gt;After successfully breaking into Loki’s vault and getting access to some of his finest treasures and weapons, you spot a small trapdoor under a carpet.&lt;&#x2F;p&gt;
&lt;p&gt;The trapdoor is locked and contains a device with a PLONK prover. It says: Prove that the point $( 1 , y)$ belongs to the elliptic curve $y^2 = x^3 + 4$.&lt;&#x2F;p&gt;
&lt;p&gt;You see that, in order to prove this, you need that $y^2 − x^3 − 4$ is equal to zero, which corresponds to the circuit for the prover provided by Loki.&lt;&#x2F;p&gt;
&lt;p&gt;Can you open the trapdoor?&lt;&#x2F;p&gt;
&lt;p&gt;nc 44.203.113.160 4000&lt;&#x2F;p&gt;
&lt;p&gt;Additional information is in this &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ingonyama-zk&#x2F;ZKCTF-lokis-trapdoor&quot;&gt;repo&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;FLAG FORMAT: ZKCTF{XXX…XXX}&lt;&#x2F;p&gt;
&lt;h3 id=&quot;solution-1&quot;&gt;Solution&lt;&#x2F;h3&gt;
&lt;p&gt;This challenge exploits the frozen heart vulnerability, which arises when the Fiat-Shamir transformation is not implemented correctly. The main problem is that $(1,y)$ is not a point belonging to the BLS12-381 elliptic curve. If so, $y^2 = 1^3 + 4 = 5$ but $5$ is not a quadratic residue modulo the BLS12-381 prime. Therefore, the way to solve the challenge must be by creating a false proof.&lt;&#x2F;p&gt;
&lt;p&gt;The circuit is:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PUBLIC INPUT: x&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PUBLIC INPUT: y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ASSERT 0 == y^2 - x^3 - 4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And it instantiated over the &lt;code&gt;BLS12 381&lt;&#x2F;code&gt; scalar field.&lt;&#x2F;p&gt;
&lt;p&gt;The vulnerability stems from a bug in the implementation of strong Fiat-Shamir. A correct implementation should add, among other things, all the public inputs to the transcript at initialization. If a public input is not added to the transcript and is in control of the attacker, they can forge a fake proof. Fixing &lt;code&gt;x=1&lt;&#x2F;code&gt; leaves &lt;code&gt;y&lt;&#x2F;code&gt; under the user’s control. We can see that the Fiat-Shamir transcript does not incorporate the public input, as shown &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ingonyama-zk&#x2F;ZKCTF-lokis-trapdoor&#x2F;blob&#x2F;69eba0d41d56a7831b4532d5adc2c21720764885&#x2F;lambdaworks_plonk_prover&#x2F;src&#x2F;setup.rs#L70C1-L73C23&quot;&gt;here&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn new_strong_fiat_shamir_transcript&amp;lt;F, CS&amp;gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    vk: &amp;amp;VerificationKey&amp;lt;CS::Commitment&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    _public_input: &amp;amp;[FieldElement&amp;lt;F&amp;gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; DefaultTranscript&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The attack is described in Section V of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2023&#x2F;691.pdf&quot;&gt;Weak Fiat-Shamir Attacks on Modern Proof Systems&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Here is a summary of the attack:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;B10en9A93.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Instead of taking random polynomials (steps (1) to (7)), the current solution takes a valid proof for the pair &lt;code&gt;x=0&lt;&#x2F;code&gt;, &lt;code&gt;y=2&lt;&#x2F;code&gt; and uses it to forge a &lt;code&gt;y&lt;&#x2F;code&gt; for &lt;code&gt;x=1&lt;&#x2F;code&gt; that’s compatible with the original proof.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#[allow(unused)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn forge_y_for_valid_proof&amp;lt;F: IsField, CS: IsCommitmentScheme&amp;lt;F&amp;gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    proof: &amp;amp;Proof&amp;lt;F, CS&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    vk: &amp;amp;VerificationKey&amp;lt;CS::Commitment&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    common_preprocessed_input: CommonPreprocessedInput&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; FieldElement&amp;lt;F&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;where&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    CS::Commitment: Serializable,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    FieldElement&amp;lt;F&amp;gt;: ByteConversion,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Replay interactions like the verifier&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut transcript = new_strong_fiat_shamir_transcript::&amp;lt;F, CS&amp;gt;(vk, &amp;amp;[]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transcript.append(&amp;amp;proof.a_1.serialize());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transcript.append(&amp;amp;proof.b_1.serialize());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transcript.append(&amp;amp;proof.c_1.serialize());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let beta = FieldElement::from_bytes_be(&amp;amp;transcript.challenge()).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let gamma = FieldElement::from_bytes_be(&amp;amp;transcript.challenge()).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transcript.append(&amp;amp;proof.z_1.serialize());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let alpha = FieldElement::from_bytes_be(&amp;amp;transcript.challenge()).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transcript.append(&amp;amp;proof.t_lo_1.serialize());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transcript.append(&amp;amp;proof.t_mid_1.serialize());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transcript.append(&amp;amp;proof.t_hi_1.serialize());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let zeta = &amp;amp;FieldElement::from_bytes_be(&amp;amp;transcript.challenge()).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Forge public input&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let zh_zeta = zeta.pow(common_preprocessed_input.n) - FieldElement::one();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let omega = &amp;amp;common_preprocessed_input.omega;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let n = common_preprocessed_input.n as u64;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let one = &amp;amp;FieldElement::one();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let l1_zeta = ((zeta.pow(n) - one) &#x2F; (zeta - one)) &#x2F; FieldElement::from(n);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let l2_zeta = omega * &amp;amp;l1_zeta * (zeta - one) &#x2F; (zeta - omega);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut p_constant_zeta = &amp;amp;alpha&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        * &amp;amp;proof.z_zeta_omega&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        * (&amp;amp;proof.c_zeta + &amp;amp;gamma)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        * (&amp;amp;proof.a_zeta + &amp;amp;beta * &amp;amp;proof.s1_zeta + &amp;amp;gamma)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        * (&amp;amp;proof.b_zeta + &amp;amp;beta * &amp;amp;proof.s2_zeta + &amp;amp;gamma);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    p_constant_zeta = p_constant_zeta - &amp;amp;l1_zeta * &amp;amp;alpha * &amp;amp;alpha;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let p_zeta = p_constant_zeta + &amp;amp;proof.p_non_constant_zeta;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    -(p_zeta + l1_zeta * one - (&amp;amp;zh_zeta * &amp;amp;proof.t_zeta)) &#x2F; l2_zeta&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h1 id=&quot;starks-challenge&quot;&gt;STARKs challenge&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;challenge-2&quot;&gt;Challenge&lt;&#x2F;h2&gt;
&lt;p&gt;Good morning hacker.&lt;&#x2F;p&gt;
&lt;p&gt;If you are reading this, the date should be July 7th, 2023, and you should be checking the Lambda-Ingoyama CTF challenges site.&lt;&#x2F;p&gt;
&lt;p&gt;Hopefully, we managed to hijack the site, and you are reading this now. We are not allowed to say much, but you must know it’s of utmost importance that you win this challenge.&lt;&#x2F;p&gt;
&lt;p&gt;So, we have decided to help. Don’t worry; it should be easy. We have found the right exploit to solve and are forwarding the solution to you.&lt;&#x2F;p&gt;
&lt;p&gt;If something goes wrong, we leave some additional data we have collected. We don’t know if it’s helpful, but we hope it can help.&lt;&#x2F;p&gt;
&lt;p&gt;It’s now up to you to take the flag. We wish you good luck.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ingonyama-zk&#x2F;ZKCTF-ch3-client&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;ingonyama-zk&#x2F;ZKCTF-ch3-client&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;FLAG FORMAT: ZKCTF{XXX…XXX}&lt;&#x2F;p&gt;
&lt;h2 id=&quot;solution-2&quot;&gt;Solution&lt;&#x2F;h2&gt;
&lt;p&gt;The key point here is that the STARK prover does only one query, which makes the soundness error significant. This vulnerability was present in an early implementation of Lambdaworks (see this &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;starknet_stack_prover_lambdaworks&#x2F;pull&#x2F;66&quot;&gt;PR&lt;&#x2F;a&gt;) and was discovered by &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mcarilli&quot;&gt;Michael Carilli&lt;&#x2F;a&gt; (to whom we are really grateful).&lt;&#x2F;p&gt;
&lt;p&gt;The first step is to send the data to an endpoint of the server, which should reply with something like “Expired proof.” After that, the next step is to inspect the proof. Most of the data will not be relevant. Counting the number of queries, we realize there is only 1. Now it remains to see how to exploit it.&lt;&#x2F;p&gt;
&lt;p&gt;Some additional data needs to be used, such as the offset, the constraints, and the blowup factor. Offsets and constraints are hinted at in the data. The blowup factor can be guessed or hinted at.&lt;&#x2F;p&gt;
&lt;p&gt;We can now move to break the STARK protocol, taking advantage of the FRI soundness error, which is quite large for one query. We must first pass the consistency check at the out-of-domain point $z$ between the composition polynomial and the trace polynomials. The verifier performs this check in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;starknet_stack_prover_lambdaworks&#x2F;blob&#x2F;23eb9df082ec4de4f1d44c6760be4b7a13ea24b1&#x2F;src&#x2F;starks&#x2F;verifier.rs#L208&quot;&gt;step 2&lt;&#x2F;a&gt;. We can pass this test automatically if we calculate the value of the polynomial directly from the trace polynomials:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn composition_poly_ood_evaluation_exact_from_trace&amp;lt;F: IsFFTField, A: AIR&amp;lt;Field = F&amp;gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    air: &amp;amp;A,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    trace_ood_frame_evaluations: &amp;amp;Frame&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    domain: &amp;amp;Domain&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    z: &amp;amp;FieldElement&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    rap_challenges: &amp;amp;A::RAPChallenges,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    boundary_coeffs: &amp;amp;[(FieldElement&amp;lt;F&amp;gt;, FieldElement&amp;lt;F&amp;gt;)],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transition_coeffs: &amp;amp;[(FieldElement&amp;lt;F&amp;gt;, FieldElement&amp;lt;F&amp;gt;)],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; FieldElement&amp;lt;F&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let _public_input = air.pub_inputs();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let boundary_constraints = air.boundary_constraints(rap_challenges);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let n_trace_cols = air.context().trace_columns;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let boundary_constraint_domains =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        boundary_constraints.generate_roots_of_unity(&amp;amp;domain.trace_primitive_root, &amp;amp;[n_trace_cols]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let values = boundary_constraints.values(&amp;amp;[n_trace_cols]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Following naming conventions from https:&#x2F;&#x2F;www.notamonadtutorial.com&#x2F;diving-deep-fri&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut boundary_c_i_evaluations = Vec::with_capacity(n_trace_cols);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut boundary_quotient_degrees = Vec::with_capacity(n_trace_cols);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for trace_idx in 0..n_trace_cols {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let trace_evaluation = &amp;amp;trace_ood_frame_evaluations.get_row(0)[trace_idx];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let boundary_constraints_domain = &amp;amp;boundary_constraint_domains[trace_idx];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let boundary_interpolating_polynomial =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;amp;Polynomial::interpolate(boundary_constraints_domain, &amp;amp;values[trace_idx])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                .expect(&amp;quot;xs and ys have equal length and xs are unique&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let boundary_zerofier =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            boundary_constraints.compute_zerofier(&amp;amp;domain.trace_primitive_root, trace_idx);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let boundary_quotient_ood_evaluation = (trace_evaluation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            - boundary_interpolating_polynomial.evaluate(z))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &#x2F; boundary_zerofier.evaluate(z);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let boundary_quotient_degree = air.trace_length() - boundary_zerofier.degree() - 1;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        boundary_c_i_evaluations.push(boundary_quotient_ood_evaluation);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        boundary_quotient_degrees.push(boundary_quotient_degree);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let trace_length = air.trace_length();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let boundary_term_degree_adjustment = air.composition_poly_degree_bound() - trace_length;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let boundary_quotient_ood_evaluations: Vec&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt; = boundary_c_i_evaluations&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .zip(boundary_coeffs)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .map(|(poly_eval, (alpha, beta))| {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            poly_eval * (alpha * &amp;amp;z.pow(boundary_term_degree_adjustment) + beta)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .collect();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let boundary_quotient_ood_evaluation = boundary_quotient_ood_evaluations&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .fold(FieldElement::&amp;lt;F&amp;gt;::zero(), |acc, x| acc + x);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let transition_ood_frame_evaluations =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        air.compute_transition(trace_ood_frame_evaluations, rap_challenges);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let transition_exemptions = air.transition_exemptions();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let x_n = Polynomial::new_monomial(FieldElement::&amp;lt;F&amp;gt;::one(), trace_length);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let x_n_1 = x_n - FieldElement::&amp;lt;F&amp;gt;::one();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let divisors = transition_exemptions&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .into_iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .map(|exemption| x_n_1.clone() &#x2F; exemption)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .collect::&amp;lt;Vec&amp;lt;Polynomial&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt;&amp;gt;&amp;gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut denominators = Vec::with_capacity(divisors.len());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for divisor in divisors.iter() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        denominators.push(divisor.evaluate(z));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    FieldElement::inplace_batch_inverse(&amp;amp;mut denominators);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut degree_adjustments = Vec::with_capacity(divisors.len());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for transition_degree in air.context().transition_degrees().iter() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let degree_adjustment =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            air.composition_poly_degree_bound() - (air.trace_length() * (transition_degree - 1));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        degree_adjustments.push(z.pow(degree_adjustment));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let transition_c_i_evaluations_sum =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ConstraintEvaluator::&amp;lt;F, A&amp;gt;::compute_constraint_composition_poly_evaluations_sum(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;amp;transition_ood_frame_evaluations,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;amp;denominators,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;amp;degree_adjustments,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            transition_coeffs,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;amp;boundary_quotient_ood_evaluation + transition_c_i_evaluations_sum&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The prover splits the composition polynomial between even and odd terms, $H_1 (z^2 )$ and $H_2 (z^2 )$. The verifier has to compute $H(z)$ from the trace polynomials and then check that&lt;br &#x2F;&gt;
$H(z) = H_1 (z^2 ) + z H_2 (z^2 )$&lt;br &#x2F;&gt;
We can enforce this check by making sure that the verifier gets $H_1 (z^2 ) = H(z)$ and $H_2 (z^2 ) = 0$. Of course, this will generate some issues at other parts of the verifier, such as the DEEP composition polynomial. The DEEP composition polynomial allows us to check that all polynomials have been appropriately evaluated at $z$,&lt;br &#x2F;&gt;
$P_0 (x) = \sum_j \gamma_j \frac{t_j (x) - t_j (z)}{x - z} + \sum_j \gamma^\prime_j \frac{t_j (x) - t_j (g z)}{x - gz} + \gamma \frac{H_1 (x) - H_1 (z^2 )}{x - z^2} + \gamma^\prime \frac{H_2 (x) - H_2 (z^2 )}{x - z^2}$&lt;&#x2F;p&gt;
&lt;p&gt;Of course, if we send false evaluations of the polynomials $H_1(x^2 )$ and $H_2 (x^2 )$, the last terms will not be low-degree polynomials and should not satisfy FRI testing. However, we can evaluate exactly the values of $(H_k (\omega_j) - H_k(z^2 ))&#x2F;( \omega_j - z^2 )$ and create a polynomial which passes through as many evaluations as the low-degree test allows us (which is the trace length) by interpolation. The following function computes the DEEP composition polynomial&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn compute_deep_composition_poly_evil&amp;lt;A: AIR, F: IsFFTField&amp;gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    air: &amp;amp;A,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    domain: &amp;amp;Domain&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    trace_polys: &amp;amp;[Polynomial&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    round_2_result: &amp;amp;Round2&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    round_3_result: &amp;amp;Round3&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    z: &amp;amp;FieldElement&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    primitive_root: &amp;amp;FieldElement&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    composition_poly_gammas: &amp;amp;[FieldElement&amp;lt;F&amp;gt;; 2],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    trace_terms_gammas: &amp;amp;[FieldElement&amp;lt;F&amp;gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; Polynomial&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;where&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    lambdaworks_math::field::element::FieldElement&amp;lt;F&amp;gt;: lambdaworks_math::traits::ByteConversion,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Compute composition polynomial terms of the deep composition polynomial.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let h_1 = &amp;amp;round_2_result.composition_poly_even;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let h_1_z2 = &amp;amp;round_3_result.composition_poly_even_ood_evaluation;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let h_2 = &amp;amp;round_2_result.composition_poly_odd;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let h_2_z2 = &amp;amp;round_3_result.composition_poly_odd_ood_evaluation;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let gamma = &amp;amp;composition_poly_gammas[0];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let gamma_p = &amp;amp;composition_poly_gammas[1];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let z_squared = z.square();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; 𝛾 ( H₁ − H₁(z²) ) &#x2F; ( X − z² )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let h_1_term = {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let x = Polynomial::new_monomial(FieldElement::one(), 1);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let h_1_num = gamma * (h_1 - h_1_z2);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let h_1_denom = &amp;amp;x - &amp;amp;z_squared;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        interp_from_num_denom(&amp;amp;h_1_num, &amp;amp;h_1_denom, domain)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; 𝛾&amp;#39; ( H₂ − H₂(z²) ) &#x2F; ( X − z² )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let h_2_term = {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let x = Polynomial::new_monomial(FieldElement::one(), 1);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let h_2_num = gamma_p * (h_2 - h_2_z2);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let h_2_denom = &amp;amp;x - &amp;amp;z_squared;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        interp_from_num_denom(&amp;amp;h_2_num, &amp;amp;h_2_denom, domain)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Get trace evaluations needed for the trace terms of the deep composition polynomial&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let transition_offsets = &amp;amp;air.context().transition_offsets;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let trace_frame_evaluations = &amp;amp;round_3_result.trace_ood_evaluations;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Compute the sum of all the deep composition polynomial trace terms.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; There is one term for every trace polynomial and every row in the frame.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; ∑ ⱼₖ [ 𝛾ₖ ( tⱼ − tⱼ(z) ) &#x2F; ( X − zgᵏ )]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut trace_terms = Polynomial::zero();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for (i, t_j) in trace_polys.iter().enumerate() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let i_times_trace_frame_evaluation = i * trace_frame_evaluations.len();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let iter_trace_gammas = trace_terms_gammas&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .skip(i_times_trace_frame_evaluation);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        for ((evaluations, offset), elemen_trace_gamma) in trace_frame_evaluations&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .zip(transition_offsets)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .zip(iter_trace_gammas)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let t_j_z = evaluations[i].clone();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let z_shifted = z * primitive_root.pow(*offset);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let mut poly = t_j - t_j_z;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            poly.ruffini_division_inplace(&amp;amp;z_shifted);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            trace_terms = trace_terms + poly * elemen_trace_gamma;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    h_1_term + h_2_term + trace_terms&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;which uses the following function to interpolate&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn interp_from_num_denom&amp;lt;F: IsFFTField&amp;gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    num: &amp;amp;Polynomial&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    denom: &amp;amp;Polynomial&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    domain: &amp;amp;Domain&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; Polynomial&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let target_deg = domain.lde_roots_of_unity_coset.len() &#x2F; domain.blowup_factor;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let num_evals = evaluate_polynomial_on_lde_domain(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        num,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        domain.blowup_factor,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        domain.interpolation_domain_size,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;domain.coset_offset,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let denom_evals = evaluate_polynomial_on_lde_domain(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        denom,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        domain.blowup_factor,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        domain.interpolation_domain_size,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;domain.coset_offset,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let evals: Vec&amp;lt;_&amp;gt; = num_evals&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .zip(denom_evals)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .map(|(num, denom)| num &#x2F; denom)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .collect();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Polynomial::interpolate(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;domain.lde_roots_of_unity_coset[..target_deg],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;evals[..target_deg],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .unwrap()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This way, we can choose $n$ points where the fake DEEP composition polynomial will pass all the tests. Since the verifier can choose among $\beta n$ points, the prover gets a $1&#x2F;\beta$ chance to pass the test.&lt;&#x2F;p&gt;
&lt;p&gt;We can now create a malicious prover that will likely pass the verifier’s checks, even if he uses false execution traces. Step_2 is modified to calculate the exact composition polynomial:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn step_2_evil_eval&amp;lt;F: IsFFTField, A: AIR&amp;lt;Field = F&amp;gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    air: &amp;amp;A,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    domain: &amp;amp;Domain&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transition_coeffs: &amp;amp;[(FieldElement&amp;lt;F&amp;gt;, FieldElement&amp;lt;F&amp;gt;)],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    boundary_coeffs: &amp;amp;[(FieldElement&amp;lt;F&amp;gt;, FieldElement&amp;lt;F&amp;gt;)],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    rap_challenges: &amp;amp;A::RAPChallenges,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    z: &amp;amp;FieldElement&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    trace_ood_frame_evaluations: &amp;amp;Frame&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; FieldElement&amp;lt;F&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; BEGIN TRACE &amp;lt;-&amp;gt; Composition poly consistency evaluation check&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; These are H_1(z^2) and H_2(z^2)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let boundary_constraints = air.boundary_constraints(rap_challenges);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;let n_trace_cols = air.context().trace_columns;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; special cases.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let trace_length = air.trace_length();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let composition_poly_degree_bound = air.composition_poly_degree_bound();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let boundary_term_degree_adjustment = composition_poly_degree_bound - trace_length;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let number_of_b_constraints = boundary_constraints.constraints.len();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Following naming conventions from https:&#x2F;&#x2F;www.notamonadtutorial.com&#x2F;diving-deep-fri&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let (boundary_c_i_evaluations_num, mut boundary_c_i_evaluations_den): (&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Vec&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Vec&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ) = (0..number_of_b_constraints)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .map(|index| {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let step = boundary_constraints.constraints[index].step;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let point = &amp;amp;domain.trace_primitive_root.pow(step as u64);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let trace_idx = boundary_constraints.constraints[index].col;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let trace_evaluation = &amp;amp;trace_ood_frame_evaluations.get_row(0)[trace_idx];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let boundary_zerofier_challenges_z_den = z - point;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let boundary_quotient_ood_evaluation_num =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                trace_evaluation - &amp;amp;boundary_constraints.constraints[index].value;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            (&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                boundary_quotient_ood_evaluation_num,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                boundary_zerofier_challenges_z_den,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .collect::&amp;lt;Vec&amp;lt;_&amp;gt;&amp;gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .into_iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .unzip();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    FieldElement::inplace_batch_inverse(&amp;amp;mut boundary_c_i_evaluations_den);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let boundary_degree_z = z.pow(boundary_term_degree_adjustment);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let boundary_quotient_ood_evaluation: FieldElement&amp;lt;F&amp;gt; = boundary_c_i_evaluations_num&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .zip(&amp;amp;boundary_c_i_evaluations_den)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .zip(boundary_coeffs)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .map(|((num, den), (alpha, beta))| num * den * (alpha * &amp;amp;boundary_degree_z + beta))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .fold(FieldElement::&amp;lt;F&amp;gt;::zero(), |acc, x| acc + x);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let transition_ood_frame_evaluations =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        air.compute_transition(trace_ood_frame_evaluations, rap_challenges);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let divisor_x_n = (z.pow(trace_length) - FieldElement::&amp;lt;F&amp;gt;::one()).inv();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let denominators = air&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .transition_exemptions_verifier()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .map(|poly| poly.evaluate(z) * &amp;amp;divisor_x_n)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .collect::&amp;lt;Vec&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt;&amp;gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let degree_adjustments = air&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .context()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .transition_degrees()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .map(|transition_degree| {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let degree_adjustment =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                composition_poly_degree_bound - (trace_length * (transition_degree - 1));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            z.pow(degree_adjustment)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .collect::&amp;lt;Vec&amp;lt;FieldElement&amp;lt;F&amp;gt;&amp;gt;&amp;gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let transition_c_i_evaluations_sum =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ConstraintEvaluator::&amp;lt;F, A&amp;gt;::compute_constraint_composition_poly_evaluations_sum(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;amp;transition_ood_frame_evaluations,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;amp;denominators,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;amp;degree_adjustments,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            transition_coeffs,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;amp;boundary_quotient_ood_evaluation + transition_c_i_evaluations_sum&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then, step_3 is changed to&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn round_3_evil&amp;lt;F: IsFFTField, A: AIR&amp;lt;Field = F&amp;gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    air: &amp;amp;A,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    domain: &amp;amp;Domain&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    round_1_result: &amp;amp;Round1&amp;lt;F, A&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    z: &amp;amp;FieldElement&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    boundary_coeffs: &amp;amp;[(FieldElement&amp;lt;F&amp;gt;, FieldElement&amp;lt;F&amp;gt;)],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transition_coeffs: &amp;amp;[(FieldElement&amp;lt;F&amp;gt;, FieldElement&amp;lt;F&amp;gt;)],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; Round3&amp;lt;F&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;where&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    FieldElement&amp;lt;F&amp;gt;: ByteConversion,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let trace_ood_evaluations = Frame::get_trace_evaluations(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;round_1_result.trace_polys,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        z,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;air.context().transition_offsets,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;domain.trace_primitive_root,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let (composition_poly_even_ood_evaluation, composition_poly_odd_ood_evaluation) = {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let trace_ood_frame_evaluations = Frame::new(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            trace_ood_evaluations.iter().flatten().cloned().collect(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            round_1_result.trace_polys.len(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let hz_exact_from_trace = step_2_evil_eval(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            air,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            domain,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            transition_coeffs,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            boundary_coeffs,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;amp;round_1_result.rap_challenges,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            z,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;amp;trace_ood_frame_evaluations,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        (hz_exact_from_trace, FieldElement::&amp;lt;F&amp;gt;::from(0))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Round3 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        trace_ood_evaluations,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        composition_poly_even_ood_evaluation,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        composition_poly_odd_ood_evaluation,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally, round_4 is&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn round_4_evil&amp;lt;F: IsFFTField, A: AIR&amp;lt;Field = F&amp;gt;, T: Transcript&amp;gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    air: &amp;amp;A,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    domain: &amp;amp;Domain&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    round_1_result: &amp;amp;Round1&amp;lt;F, A&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    round_2_result: &amp;amp;Round2&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    round_3_result: &amp;amp;Round3&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    z: &amp;amp;FieldElement&amp;lt;F&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transcript: &amp;amp;mut T,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; Round4&amp;lt;F&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;where&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    FieldElement&amp;lt;F&amp;gt;: ByteConversion,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let coset_offset_u64 = air.context().proof_options.coset_offset;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let coset_offset = FieldElement::&amp;lt;F&amp;gt;::from(coset_offset_u64);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; &amp;lt;&amp;lt;&amp;lt;&amp;lt; Receive challenges: 𝛾, 𝛾&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let composition_poly_coeffients = [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        transcript_to_field(transcript),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        transcript_to_field(transcript),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; &amp;lt;&amp;lt;&amp;lt;&amp;lt; Receive challenges: 𝛾ⱼ, 𝛾ⱼ&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let trace_poly_coeffients = batch_sample_challenges::&amp;lt;F, T&amp;gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        air.context().transition_offsets.len() * air.context().trace_columns,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        transcript,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Compute p₀ (deep composition polynomial)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let deep_composition_poly = compute_deep_composition_poly_evil(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        air,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        domain,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;round_1_result.trace_polys,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        round_2_result,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        round_3_result,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        z,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;domain.trace_primitive_root,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;composition_poly_coeffients,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;trace_poly_coeffients,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let domain_size = domain.lde_roots_of_unity_coset.len();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; FRI commit and query phases&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let (fri_last_value, fri_layers) = fri_commit_phase(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        domain.root_order as usize,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        deep_composition_poly,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        transcript,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;coset_offset,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        domain_size,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let (query_list, iotas) = fri_query_phase(air, domain_size, &amp;amp;fri_layers, transcript);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let fri_layers_merkle_roots: Vec&amp;lt;_&amp;gt; = fri_layers&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .map(|layer| layer.merkle_tree.root)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .collect();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let deep_poly_openings =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        open_deep_composition_poly(domain, round_1_result, round_2_result, &amp;amp;iotas);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; grinding: generate nonce and append it to the transcript&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let grinding_factor = air.context().proof_options.grinding_factor;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let transcript_challenge = transcript.challenge();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let nonce = generate_nonce_with_grinding(&amp;amp;transcript_challenge, grinding_factor)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .expect(&amp;quot;nonce not found&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    transcript.append(&amp;amp;nonce.to_be_bytes());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Round4 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        fri_last_value,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        fri_layers_merkle_roots,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        deep_poly_openings,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        query_list,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        nonce,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This way, we generate a proof that will always pass the out-of-domain point consistency check and will have a high probability of passing the low-degree test.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h1&gt;
&lt;p&gt;This post covered the challenges we presented at the first Lambda-Ingo ZK CTF and their solutions. The challenges involved some common attacks on Plonk (frozen heart and lack of blinding polynomials) and FRI to generate fake proofs or recover information from the witnesses. We will be adding more exercises and case studies to the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks_exercises&#x2F;tree&#x2F;main&quot;&gt;Lambdaworks exercises repo&lt;&#x2F;a&gt; so that anyone can learn how to build a proving system and some common pitfalls and vulnerabilities that may arise in their implementation. We would like to thank Ingonyama again for their fantastic work and all the sponsors at LambdaZK week in Paris. Stay tuned for more challenges on ZK!&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Please stop drinking the Rust Kool-Aid</title>
          <pubDate>Wed, 24 May 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/please-stop-drinking-the-rust-kool-aid/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/please-stop-drinking-the-rust-kool-aid/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/please-stop-drinking-the-rust-kool-aid/">&lt;p&gt;We’ve been using Rust since 2014. We’re big fans of Rust. This doesn’t imply that Rust is the perfect language that solves all your problems. Security vulnerabilities come in a wide array of flavors. Some of them allow a malicious actor to take over a system. Others allow to peek at information they shouldn’t be able to. Smaller ones, but critical too, allow a malicious actor to shut down a service relatively cheaply. This kind of attack is called DoS, a denial of service. Shutdown systems are expensive for real people.It’s even worse if the system shutdowns without external interference.&lt;&#x2F;p&gt;
&lt;p&gt;Some days ago, Péter Szilágyi, team lead at Ethereum, said that the C version of the KZG library crashed on some systems:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;peter_szilagyi&#x2F;status&#x2F;1650608687810068480&quot;&gt;&lt;img src=&quot;&#x2F;images&#x2F;2023&#x2F;05&#x2F;twitter.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If we want to build safe and robust systems, they need to take into account the possibility of crashes, whether they’re written in C, Rust, Erlang or Java. Rust Language is one of the most used for new performant systems.&lt;&#x2F;p&gt;
&lt;p&gt;Rust introduces a great new concept about memory management and prevents many categories of bugs at compile time. It prevents you from accessing invalid memory positions, a null pointer, double-freeing the memory, or using freed memory.&lt;&#x2F;p&gt;
&lt;p&gt;The concept behind this is excellent: don’t trust the programmer for this memory management when the compiler can do the hard work. The cost to pay here is that it is a bit harder to code.&lt;&#x2F;p&gt;
&lt;p&gt;If you have long-living software, e.g., a web server, a blockchain node, or something like that, a crash means that your system is out of service.&lt;br &#x2F;&gt;
For example, if you have a node receiving a request from the public, when you crash, you get your node off. That’s a vulnerability of your system.&lt;br &#x2F;&gt;
Resiliency comes not only from the lone program processing traffic and data, but also from the surrounding system monitoring it and the state and error management within it. They key in this case is what happens when you hace unexpected failures.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;memory-leaks&quot;&gt;Memory leaks&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;Memory leaks&lt;&#x2F;strong&gt; are a subtle bug that is difficult to see and address.&lt;&#x2F;p&gt;
&lt;p&gt;A memory leak occurs when a program manages memory allocations in a way that memory that is no longer needed is not released.&lt;&#x2F;p&gt;
&lt;p&gt;In Rust, it’s hard to have Reference Cycles. You can do that &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;book&#x2F;ch15-06-reference-cycles.html&quot;&gt;with and &lt;em&gt;Rc &lt;T&gt;&lt;&#x2F;em&gt; and &lt;em&gt;RefCell &lt;T&gt;&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;. Rust does not guarantee the absence of memory leaks, even in safe code. Dealing with Reference Cycles is easy to fall into a leak because neither of the two references is freed.&lt;&#x2F;p&gt;
&lt;p&gt;This situation can be hard to detect by inspecting the source code.&lt;&#x2F;p&gt;
&lt;p&gt;Many other situations can lead to a memory leak, such as functions running in async code (especially when you mix them with threads).&lt;&#x2F;p&gt;
&lt;p&gt;In a long-living program, many memory leaks can lead to a denial of service because the whole system can run out of memory.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;error-handling-and-panic&quot;&gt;Error handling and panic&lt;&#x2F;h2&gt;
&lt;p&gt;Rust has some tools for error handling, encoding the error value in the &lt;em&gt;Result&lt;&#x2F;em&gt; enum. There are no &lt;em&gt;exceptions&lt;&#x2F;em&gt; like in other languages. On the other side, Rust has the concept of panicking.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;kgwvbvw.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Panics terminate the running program.&lt;&#x2F;p&gt;
&lt;p&gt;Rust prefers panics before undefined behaviour, which is hard to track and debug.&lt;&#x2F;p&gt;
&lt;p&gt;That being said, a panic in Rust usually occurs when a condition that absolutely must not happen is reached.&lt;&#x2F;p&gt;
&lt;p&gt;Rust book has a section about panicking:&lt;br &#x2F;&gt;
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;book&#x2F;ch09-03-to-panic-or-not-to-panic.html#to-panic-or-not-to-panic&quot;&gt;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;book&#x2F;ch09-03-to-panic-or-not-to-panic.html#to-panic-or-not-to-panic&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The most obvious (and probably the most used) way of getting a panic is unwrapping a Result when it’s an Err.&lt;&#x2F;p&gt;
&lt;p&gt;Sometimes panics are hidden in harmless operations, like accessing arrays by index with &lt;strong&gt;[ ]&lt;&#x2F;strong&gt; operator (when the index is out of bound) or doing mathematical operations (like diving by zero).&lt;&#x2F;p&gt;
&lt;p&gt;It’s worth mentioning that the std has functions to avoid panics in such operations. For example, the &lt;em&gt;get()&lt;&#x2F;em&gt; accesses an element by index returning an Option value, not panicking.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;threads-safety&quot;&gt;Threads safety&lt;&#x2F;h1&gt;
&lt;p&gt;While Rust provides “ &lt;em&gt;Fearless concurrency&lt;&#x2F;em&gt; ,” the language doesn’t guarantee there won’t be bugs or security issues derived from concurrency.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Concurrency&lt;&#x2F;strong&gt; is about scheduling instructions between threads in the CPU (in one or more cores). This scheduling is arbitrary, and we call a scenario to one possible order of execution of those atomic instructions of different threads.&lt;&#x2F;p&gt;
&lt;p&gt;While we have checks that guarantee each thread has access to the data we intend to, and there isn’t some accidental sharing of memory, we can still write code with Deadlocks or Race Conditions.&lt;&#x2F;p&gt;
&lt;p&gt;Rust compiler can’t check (at compile time) that your multi-thread program has a possible deadlock. So Rust doesn’t guarantee your program will not get stuck in a stalemate. In that situation, your program doesn’t progress.&lt;&#x2F;p&gt;
&lt;p&gt;For example, we could have a channel expecting data that never comes, blocking its thread. While this is easy to spot with one thread, if we have multiple threads using multiple channels and shared data with locks, this can be harder to see. In concurrency, this is called &lt;strong&gt;starvation&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Quoting the Rustonomicon &lt;strong&gt;Rust does not prevent general race conditions.&lt;&#x2F;strong&gt; A typical race condition can occur when you check a system condition and then take action based on that condition. This is called &lt;strong&gt;time-of-check to time-of-use&lt;&#x2F;strong&gt; (TOC&#x2F;TOU). Due to the interleaving of operations between threads, the state of the condition can change with the execution of another thread. So, the action taken by the first thread is invalid (in other words, you decide with &lt;em&gt;old information&lt;&#x2F;em&gt;).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;macros&quot;&gt;Macros&lt;&#x2F;h2&gt;
&lt;p&gt;Rust has a powerful feature of macros. They can expand the possibilities of the language in some places the functionalities are too restrictive. For example, given that Rust has a strongly typed system, the arguments of a function are fixed in the quantity and its type. With macros, we can have a function-style invocation with a variadic quantity and type of arguments. &lt;code&gt;println!&lt;&#x2F;code&gt; is the perfect example of that.&lt;&#x2F;p&gt;
&lt;p&gt;A good characteristic of Rust macros is that they are hygienic. This means that the body of the macro is expanded and executed in the context of the macro itself, without taking extra context of the piece of code where the macro is invoked. This feature prevents dangerous and non-expected behavior that can happen in C programs (and hard to debug), due to the inclusion of other variables.&lt;&#x2F;p&gt;
&lt;p&gt;Having said that, the abuse of macros is harmful. First of all, macros make the compilation time slower. The worst part is that the bad practices about macros can lead to a hard comprehension of the code. In practice, they introduce new “keywords” to the language and a re-definition of some rules. The fact that you can receive multiple types in the same macros can be confusing for the reader of the code.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;unsafe&quot;&gt;Unsafe&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;Unsafe&lt;&#x2F;code&gt; in Rust is the key that opens the door to non-checked memory and variables. One of the strengths of the language is the borrow checker and the restriction about how memory is used. &lt;code&gt;Unsafe&lt;&#x2F;code&gt; gives that power but also the responsibility to the programmer.&lt;&#x2F;p&gt;
&lt;p&gt;There are indeed some circumstances where there is no choice. In the case we have Rust code interfacing with C code, given that C is an “unsafe” language (from Rust’s perspective), FFI invocations are &lt;em&gt;unsafe&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The use of unsafe makes our code more vulnerable (e.g. accessing a non-checked memory position is always dangerous).&lt;br &#x2F;&gt;
&lt;code&gt;Unsafe&lt;&#x2F;code&gt; blocks must be carefully audited.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;Engineering is not a science. Bugs can still occur even with the best practices in place. However, by using languages like Rust and being mindful of potential vulnerabilities like panic situations and concurrency issues, we can minimize the risks of these bugs causing harm to our systems.&lt;&#x2F;p&gt;
&lt;p&gt;It’s important to remember that we are all human, and mistakes can happen. Still, by working together and communicating any bugs or issues in each other’s code, we can create safer and more robust systems for everyone. So let’s keep collaborating and striving towards better, more secure programming practices.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Exciting times at the intersection of Compilers and Applied Cryptography: Cairo and MLIR</title>
          <pubDate>Wed, 03 May 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/cairo-and-mlir/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/cairo-and-mlir/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/cairo-and-mlir/">&lt;p&gt;Making a Cairo&lt;br &#x2F;&gt;
not reinventing the wheel&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;I love jazz.&lt;br &#x2F;&gt;
Of all the jazz styles I love, jazz fusion is the one I enjoy most because I find any fusion of different things more stimulating.&lt;br &#x2F;&gt;
Something exciting is happening at the intersection of programming language theory, compiler implementation, and applied cryptography.&lt;&#x2F;p&gt;
&lt;p&gt;But the thing with jazz fusion is that it’s harder to get into unless you’re familiar with the elements being combined.&lt;br &#x2F;&gt;
Let me show you a few songs and how we’re mixing it up.&lt;br &#x2F;&gt;
If you’re familiar with one of these topics, bear with us; I promise it’s worth it.&lt;&#x2F;p&gt;
&lt;p&gt;Put on your seatbelts.&lt;br &#x2F;&gt;
3, 2, 1…&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;BDuDQ6c.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;intro-beat&quot;&gt;Intro beat&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;compilers-llvm&quot;&gt;Compilers &amp;amp; LLVM&lt;&#x2F;h3&gt;
&lt;p&gt;Some 20-something years ago, a group of compiler researchers at the University of Illinois needed a more flexible infrastructure.&lt;br &#x2F;&gt;
What they developed became known as LLVM and has since become the foremost compiler tooling project.&lt;br &#x2F;&gt;
It powers many of the compilers’ analysis and code generation components for Clang, Swift, Rust, and many more languages.&lt;&#x2F;p&gt;
&lt;p&gt;From the 2004 CGO &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;llvm.org&#x2F;pubs&#x2F;2004-01-30-CGO-LLVM.html&quot;&gt;paper&lt;&#x2F;a&gt; introducing it:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The LLVM compiler framework and code representation combine key capabilities that are important for practical, lifelong analysis and transformation of programs.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;At the heart of LLVM is LLVM IR, its Intermediate Representation.&lt;br &#x2F;&gt;
IRs are a combination of data formats and algorithms that allow the best expression of the properties a tool wishes to guarantee or prove about code.&lt;&#x2F;p&gt;
&lt;p&gt;An example of this is the fact that LLVM IR is what’s known as an SSA form, or Static Single Assignment, in which each variable will have a value assigned only once.&lt;br &#x2F;&gt;
This allows the compiler to reason about it better than others. Otherwise, it enables analysis and optimizations, such as dead code elimination, constant propagation, and constant folding, and facilitates other stages, such as register allocation.&lt;&#x2F;p&gt;
&lt;p&gt;All this to say that IRs are a compiler writer’s way of solving problems by building abstraction ladders, and LLVM became the de facto backend platform for modern compilers.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;rise-of-ai&quot;&gt;Rise of AI&lt;&#x2F;h3&gt;
&lt;p&gt;You may know that machine learning algorithms and their applications are now a big deal.&lt;br &#x2F;&gt;
The driver of many economic fortunes and solutions to problems we only dreamed of solving before, the statistical school of AI has settled (?) on a set of techniques that involve dealing with numerical operations on enormous matrices of numbers and stringing together large numbers of these operations into computation graphs.&lt;br &#x2F;&gt;
These computational graphs’ fundamental elements are matrix multiplications, convolutions, data manipulations, and data movements.&lt;br &#x2F;&gt;
This sounds very computationally expensive, and it is. So the industry has (and is) going to great lengths to scale these approaches, making them cheaper and more effective on ever larger data sets.&lt;&#x2F;p&gt;
&lt;p&gt;A key observation was made at some point: many of the problems these algorithms solve have inherent or given parallelism, and we already had industry-producing machines designed explicitly for embarrassingly parallel numerical problems, namely shaders running on GPUs.&lt;br &#x2F;&gt;
Thus the first wave of this effort was repurposing video graphics card hardware to make them applicable to this new area.&lt;&#x2F;p&gt;
&lt;p&gt;Why did we change the tune from LLVM to AI and graphics card? Because as they matured, these algorithms, models, techniques, tools, and libraries were standardized into frameworks that could be used by many non-specialist programmers and that required appropriate languages in which to express them and their compilers.&lt;&#x2F;p&gt;
&lt;p&gt;Since LLVM had an IR that could, with some effort, be abstracted over GPU processors, it was used in tools such as PyTorch and Tensorflow to produce the code that would run on these graphical processing units.&lt;br &#x2F;&gt;
New hardware was designed, and LLVM was again used to target these new tensor processing units.&lt;&#x2F;p&gt;
&lt;p&gt;As a result, Tensorflow has several compiler components embedded in it, made by different vendors: Google has XLA, NVIDIA has TensorRT, and Intel has NGraph, all of which integrate with the TensorFlow optimizer and code generator and are very hardware specific, but do not share common infrastructure.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;eRktk4K.jpg&quot; alt=&quot;Figure 1 from the paper “MLIR:  A Compiler Infrastructure for the End of Moore’s Law”&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;back-to-languages&quot;&gt;Back to languages&lt;&#x2F;h3&gt;
&lt;p&gt;In these intervening years since the early 2000s, the pendulum has swung back from dynamic to statically typed languages with more advanced type systems and code analysis phases.&lt;br &#x2F;&gt;
LLVM enabled Clang and new languages such as Rust, Julia, and Swift.&lt;br &#x2F;&gt;
Something these projects share in common is that they have found that many language implementation problems are best modeled at higher abstraction levels and implemented their intermediate representations to solve domain-specific problems, like language&#x2F;library-specific optimizations, flow-sensitive type checking (e.g., for linear types), and to improve the implementation of the lowering process.&lt;br &#x2F;&gt;
Swift has SIL, Rust has MIR, and so on.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;5UG47By.jpg&quot; alt=&quot;Figure 2 from the paper “MLIR:  A Compiler Infrastructure for the End of Moore’s Law”&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In other words, people started to realize that the complexity of the software stack above the low-level IR was very high since software reuse was low and quality was so variable.&lt;&#x2F;p&gt;
&lt;p&gt;After twenty years of expanding hardware targets and changing problem spaces, LLVM was found lacking in certain areas.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-mlir&quot;&gt;What (is MLIR?)&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;KKNOAlx.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Out of this came &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mlir.llvm.org&#x2F;&quot;&gt;MLIR&lt;&#x2F;a&gt; (Multi-Level Intermediate Representation), a project started by Chris Lattner et al. to build a common infrastructure to support all these different subsystems and to learn from the mistakes made and lessons learned in the development of LLVM.&lt;&#x2F;p&gt;
&lt;p&gt;I highly encourage you to read the introductory &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;pdf&#x2F;2002.11054.pdf&quot;&gt;paper&lt;&#x2F;a&gt; from whence these graphics came, as it is very readable, or to listen to the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=qzljG6DKgic&quot;&gt;talk&lt;&#x2F;a&gt; Lattner and Shpeisman gave presenting it.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;MLIR aims to address software fragmentation, improve compilation for heterogeneous hardware, significantly reduce the cost of building domain-specific compilers, and aid in connecting existing compilers.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;There are several types of intermediate representations: linear (like assembly, a sequence of instructions), tree-like (like ASTs), and graph-like (like data flow or call graphs).&lt;br &#x2F;&gt;
As the project site states, “MLIR is intended to be a hybrid IR which can support multiple different requirements in a unified infrastructure.”&lt;&#x2F;p&gt;
&lt;p&gt;Unlike LLVM IR, where one central IR contains a complete set of instructions to represent the CPU&#x2F;GPU programs, in MLIR, there is no one IR.&lt;&#x2F;p&gt;
&lt;p&gt;Instead, MLIR provides a set of very abstract concepts: dialects, operations, regions, etc.&lt;&#x2F;p&gt;
&lt;p&gt;From the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mlir.llvm.org&#x2F;getting_started&#x2F;Glossary&#x2F;&quot;&gt;glossary&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; A dialect is a grouping of functionality that can be used to extend the MLIR system.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; A dialect creates a unique namespace within which new operations, attributes, and types are defined.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; This is the fundamental method by which to extend MLIR.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; In this way, MLIR is a meta-IR: its extensible framework allows it to be leveraged in many different ways&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;An &lt;strong&gt;operation&lt;&#x2F;strong&gt; is a unit of code in MLIR.&lt;br &#x2F;&gt;
Operations are the building blocks for all code and computations represented by MLIR.&lt;br &#x2F;&gt;
They are fully extensible (no fixed list of operations) and have application-specific semantics.&lt;&#x2F;p&gt;
&lt;p&gt;When implementing the code emitter, operations could map to processor instructions.&lt;br &#x2F;&gt;
When implementing an AST, nodes representing type conversions, function calls, and language operands could be mapped to operations.&lt;&#x2F;p&gt;
&lt;p&gt;Operations can have an arbitrary number of operands, results, and attributes and may contain an arbitrary number of regions.&lt;&#x2F;p&gt;
&lt;p&gt;A &lt;strong&gt;region&lt;&#x2F;strong&gt; is a control flow graph of MLIR blocks.&lt;&#x2F;p&gt;
&lt;p&gt;A &lt;strong&gt;block&lt;&#x2F;strong&gt; , or basic Block, is a sequential list of operations without control flow.&lt;&#x2F;p&gt;
&lt;p&gt;Note that this creates a nested IR structure, as regions consist of blocks, which in turn, consist of a list of operations.&lt;br &#x2F;&gt;
Regions are a powerful mechanism to allow nested operations and localize information, simplifying code analysis and transformation.&lt;&#x2F;p&gt;
&lt;p&gt;A &lt;strong&gt;module&lt;&#x2F;strong&gt; is an operation containing a single region containing a single block comprised of operations, providing an organizational structure for MLIR operations.&lt;&#x2F;p&gt;
&lt;p&gt;MLIR allows multiple dialects, even those outside of MLIR’s codebase, to co-exist within one module.&lt;&#x2F;p&gt;
&lt;p&gt;In the context of MLIR, conversion is distinct from translation.&lt;br &#x2F;&gt;
The transformation of code represented in a dialect is called conversion. It can be either inter-dialect (when the conversion is into a semantically equivalent representation in another dialect) or intra-dialect. In contrast, translation is a transformation between MLIR and an external representation.&lt;&#x2F;p&gt;
&lt;p&gt;Thus an application using MLIR will typically use a collection of dialects as needed.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-are-the-advantages-of-llvm&quot;&gt;What are the advantages of LLVM?&lt;&#x2F;h3&gt;
&lt;p&gt;So you’re writing a compiler or need to add a backend to an existing compiler.&lt;br &#x2F;&gt;
Aside from code reuse across the industry, what advantages does MLIR provide? Why would you choose it over LLVM?&lt;&#x2F;p&gt;
&lt;p&gt;To begin with, the choice is not that binary since MLIR includes an LLVM IR dialect to which you can convert your application-specific dialect and thus leverage the existing LLVM toolchain.&lt;&#x2F;p&gt;
&lt;p&gt;MLIR also tries to provide universal patterns or passes that can apply to suitable operations without hardcoding them.&lt;&#x2F;p&gt;
&lt;p&gt;So MLIR allows you to easily defined your dialect, pick from a growing ecosystem of middle and low-level dialects targeting different computation models, and integrate them into your domain-specific compiler.&lt;&#x2F;p&gt;
&lt;p&gt;As &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.lei.chat&#x2F;posts&#x2F;compilers-and-irs-llvm-ir-spirv-and-mlir&#x2F;&quot;&gt;Lei Zhang&lt;&#x2F;a&gt; says:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;In other words, if LLVM IR is centralized by nature and favors unified compiler flows, the MLIR infrastructure and its dialect ecosystem are decentralized by nature and favor diverse compiler flows.&lt;br &#x2F;&gt;
What is quite powerful is that MLIR enables different levels to be represented using the same infrastructure; so that the flow between different levels can become seamless.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The UNIX way!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;HNaqpaU.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Other benefits include:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Source code location tracking by default (each operand has a source code memory address attribute, so errors directly point to the line of source code in which the error occurred)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * All functions run on multiple cores by default&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Optimizations done by other languages can be reused&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Reuse LLVM for machine code generation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally, suppose your domain does benefit from running all or some of your code in a GPU, TPU, or ASIC. In that case, MLIR provides a way to reuse an existing dialect targeting that computation model and hardware by writing a conversion to it and plugging in a code generator for final translation.&lt;&#x2F;p&gt;
&lt;p&gt;It includes dialects for SPIR-V, a general &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mlir.llvm.org&#x2F;docs&#x2F;Dialects&#x2F;GPU&#x2F;&quot;&gt;GPU&lt;&#x2F;a&gt; dialect, and specific ones for &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mlir.llvm.org&#x2F;docs&#x2F;Dialects&#x2F;NVGPU&#x2F;&quot;&gt;NVidia&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mlir.llvm.org&#x2F;docs&#x2F;Dialects&#x2F;AMDGPU&quot;&gt;AMD&lt;&#x2F;a&gt; GPUs.&lt;&#x2F;p&gt;
&lt;p&gt;All these advantages are direct results of MLIR’s abstraction level.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why&quot;&gt;Why?&lt;&#x2F;h2&gt;
&lt;p&gt;Let’s change the tune again.&lt;&#x2F;p&gt;
&lt;p&gt;In the land of blockchains, cryptocurrencies, and distributed finance, several developments have converged:&lt;&#x2F;p&gt;
&lt;p&gt;First, the more established blockchains have paralleled the story in the machine learning world, offloading as much hashing as possible to GPUs and later ASICs (facing us mere mortals to scrabbling for the crumbs or resigned to playing emacs Tetris on my Raspberry Pi).&lt;br &#x2F;&gt;
Newer chains and L2s are expected to follow the same path.&lt;&#x2F;p&gt;
&lt;p&gt;Second, as their applications have become more mainstream (albeit with ups and downs), two concerns have taken center stage: scalability and privacy.&lt;br &#x2F;&gt;
Blockchains are not known for their efficiency, so the effort has gone into trying to have the best of both worlds, in part by moving away from Proof of Work, moving work to L2s, and turning back to guarantees provided by cryptographic techniques.&lt;br &#x2F;&gt;
As new techniques have been discovered and older ones have matured, Zero Knowledge Proof systems have emerged as the predominant area from which solutions to these two problems can be built.&lt;&#x2F;p&gt;
&lt;p&gt;But as is well known, despite a good amount of gatekeeping, cryptography is not something one can pick up over the weekend and “roll one’s own,” especially in developing areas such as ZKP.&lt;br &#x2F;&gt;
It’s not &lt;em&gt;just&lt;&#x2F;em&gt; that their proper use is complex or that many components are still in alpha, but because translating computation in a programming language to a form that can be input to these cryptographic primitives takes a lot of work and some ingenuity.&lt;br &#x2F;&gt;
Most ZKP protocols involve arithmetization, which is the process of representing computation in a numerical format that can be used by the proving system, usually by taking the instructions in the computation and building an expression graph of operations on bits called an arithmetic circuit and then generating an &lt;em&gt;execution trace&lt;&#x2F;em&gt; , which very briefly is a matrix of field elements representing the evolution of the computation over time.&lt;br &#x2F;&gt;
This execution trace is fed to the prover.&lt;&#x2F;p&gt;
&lt;p&gt;To encapsulate these processes, virtual machines have been designed and implemented to generate these numerical execution traces and provide computational guarantees, such as &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;0xPolygonMiden&#x2F;miden-vm&quot;&gt;Miden&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;cairo-rs&#x2F;pulls&quot;&gt;cairo-rs&lt;&#x2F;a&gt;.&lt;br &#x2F;&gt;
Once you have a virtual machine, you need a compiler and an intermediate representation.&lt;&#x2F;p&gt;
&lt;p&gt;You also can’t accept just any program since you need to know that its execution is provable unless you’re willing to take the possibility of nonterminating programs, invalid transactions which consume excessive gas, the production of invalid or incomplete traces, and having the prover just quit in the middle.&lt;br &#x2F;&gt;
Type theory and intermediate representations within compilers have become one of the most potent tools for producing code that has properties we can mechanically reason about and check.&lt;&#x2F;p&gt;
&lt;p&gt;So, in short, the need to run on more diverse hardware, to incorporate programming language technology, to enable the easy use of complex cryptographic primitives, to transport guarantees from developer tooling to execution layers have all come together to bring about a small renaissance of language implementation in the crypto world.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;cairo-sierra&quot;&gt;Cairo &amp;amp; Sierra&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;starkware-libs&#x2F;cairo&quot;&gt;Cairo&lt;&#x2F;a&gt; is a “language for creating provable programs for general computation” through the use of STARK-based validity proofs.&lt;br &#x2F;&gt;
If you’re not from a cryptography background, ZKP and STARKS are too deep a rabbit hole for one article spanning so many topics; STARKs enable blockchain scaling by efficiently proving the integrity of computations.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;STARKs (Scalable, Transparent Argument of Knowledge) is a proof system that enables the proving and verification of computations.&lt;br &#x2F;&gt;
It allows processing a big computation, generating proof for the computation’s correctness, and verifying the proof in very few steps.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [www.starknet.io](https:&#x2F;&#x2F;www.starknet.io&#x2F;en&#x2F;posts&#x2F;engineering&#x2F;starks-starkex-and-starknet)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;&#x2F;blockquote&gt;
&lt;p&gt;As Cairo matures, improvements have been added, such as a linear type system implementing ownership similar to Rust and an intermediate representation providing guarantees.&lt;br &#x2F;&gt;
Programming in Cairo is a bit different than your average von Neumann machine-based language: programs written in it run under a nondeterministic, immutable, contiguous memory model to ensure that all relevant memory has proper values and that appropriate values are not destroyed before the proof is generated, i. e. all correct programs are provable.&lt;&#x2F;p&gt;
&lt;p&gt;The Cairo compiler eventually compiles Cairo code to a “Cairo assembly,” which the virtual machines run to compute results and generate traces.&lt;br &#x2F;&gt;
However, as mentioned before, not all representations are adequate for all tasks, so Cairo introduced Sierra (&lt;strong&gt;S&lt;&#x2F;strong&gt; afe &lt;strong&gt;I&lt;&#x2F;strong&gt; nt&lt;strong&gt;E&lt;&#x2F;strong&gt; rmediate &lt;strong&gt;R&lt;&#x2F;strong&gt; ep&lt;strong&gt;R&lt;&#x2F;strong&gt; esent&lt;strong&gt;A&lt;&#x2F;strong&gt; tion).&lt;&#x2F;p&gt;
&lt;p&gt;Sierra’s goal is to guarantee that the generated code is always provable, and it achieves this by several means.&lt;&#x2F;p&gt;
&lt;p&gt;As mentioned, the memory model is immutable and contiguous and guarantees that memory will not be written twice, and thus, dereferences cannot fail.&lt;br &#x2F;&gt;
The linear type system ensures that values are used exactly once,&lt;&#x2F;p&gt;
&lt;p&gt;There are no loops, and recursion is used instead; coupled with a gas meter for operations, this ensures termination.&lt;&#x2F;p&gt;
&lt;p&gt;Assertions and panics are converted to conditional branches.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;why-use-mlir-in-the-context-of-cairo&quot;&gt;Why use MLIR in the context of Cairo?&lt;&#x2F;h3&gt;
&lt;p&gt;Cairo is also being used to build StarkNet, a permissionless Ethereum layer 2 network on which provable smart contracts can be deployed.&lt;br &#x2F;&gt;
Nodes on the network receive transactions and must verify they are valid before going about the business of generating the proof.&lt;br &#x2F;&gt;
The contract code must be run with the transaction inputs to generate the state change, the proof, and verify.&lt;&#x2F;p&gt;
&lt;p&gt;Another motivation is developer experience and tooling quality.&lt;br &#x2F;&gt;
Before deploying said contracts, the code must be written and tested, and being able to run Cairo code faster improves turnaround time in the development loop.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Enable faster checking of Cairo contract TX&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Faster Gas computation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * To enable better L2 sequencers&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * To enable better developer tooling&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;sierra-structure&quot;&gt;Sierra Structure&lt;&#x2F;h3&gt;
&lt;p&gt;So what does Sierra look like?&lt;br &#x2F;&gt;
We’ll see some examples shortly.&lt;br &#x2F;&gt;
Briefly, Sierra is a linear intermediate representation.&lt;br &#x2F;&gt;
A Sierra program consists of four sections:&lt;br &#x2F;&gt;
The types used in a particular program&lt;br &#x2F;&gt;
The &lt;em&gt;libfuncs&lt;&#x2F;em&gt; used&lt;br &#x2F;&gt;
The program statements&lt;br &#x2F;&gt;
The descriptions of the user-defined functions&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; A full Sierra program.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#[derive(Clone, Debug, Eq, PartialEq)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub struct Program {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;&#x2F; Declarations for all the user types.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub type_declarations: Vec&amp;lt;TypeDeclaration&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;&#x2F; Declarations for all the used library functions.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub libfunc_declarations: Vec&amp;lt;LibfuncDeclaration&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;&#x2F; The code of the program.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub statements: Vec&amp;lt;Statement&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;&#x2F; Descriptions of the functions - signatures and entry points.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub funcs: Vec&amp;lt;Function&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Libfuncs (or library functions) are representations of calls to built-in functions whose implementations are vetted to be correct, then compiled to Cairo assembly.&lt;br &#x2F;&gt;
The built-in libfuncs implementation is generic and can be specialized as defined in the libfunc declaration section.&lt;&#x2F;p&gt;
&lt;p&gt;Statements can either invoke a libfunc or return a variable and are executed in sequence:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; A possible statement.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#[derive(Clone, Debug, Eq, PartialEq)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub enum GenStatement&amp;lt;StatementId&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Invocation(GenInvocation&amp;lt;StatementId&amp;gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Return(Vec&amp;lt;VarId&amp;gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;User-defined functions have an identifier, their type signature and parameters, and a statement identifier that marks the function entry point among the program statements.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub type Function = GenFunction&amp;lt;StatementIdx&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F;&#x2F; Represents a function (its name, signature, and entry point).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#[derive(Clone, Debug, Eq, PartialEq)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub struct GenFunction&amp;lt;StatementId&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;&#x2F; The name of the function.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub id: FunctionId,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;&#x2F; The parameter types and return types.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub signature: FunctionSignature,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;&#x2F; The parameters of the function.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub params: Vec&amp;lt;Param&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;&#x2F; The statement id where the function starts.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub entry_point: StatementId,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;how-does-one-use-mlir&quot;&gt;How (does one use MLIR)?&lt;&#x2F;h2&gt;
&lt;p&gt;In our application context, the Cairo &amp;amp; StarkNet software stack, most of it is transitioning to or being developed in Rust, so we would like to integrate with this language seamlessly.&lt;&#x2F;p&gt;
&lt;p&gt;MLIR has a [C-compatible API](&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mlir.llvm.org&#x2F;docs&#x2F;CAPI&#x2F;&quot;&gt;https:&#x2F;&#x2F;mlir.llvm.org&#x2F;docs&#x2F;CAPI&#x2F;&lt;&#x2F;a&gt;, which can be easily interfaced with.&lt;br &#x2F;&gt;
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;mlir-sys&quot;&gt;mlir-sys&lt;&#x2F;a&gt; provides auto-generated bindings to this interface, and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;crates&#x2F;melior-next&quot;&gt;melior&lt;&#x2F;a&gt; provides a somewhat more idiomatic wrapper around it.&lt;&#x2F;p&gt;
&lt;p&gt;MLIR as a library is part of the LLVM distribution, so if you have the latest LLVM as a system library, you will have access to MLIR.&lt;&#x2F;p&gt;
&lt;p&gt;Our project resides at &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;cairo_sierra2mlir&quot;&gt;&lt;code&gt;github.com&#x2F;lambdaclass&#x2F;cairo_sierra2mlir&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.&lt;br &#x2F;&gt;
You can find detailed setup instructions that should leave you with a working development environment. When developing on Apple hardware, if you don’t want to make compile your own, store-bought brew-provided LLVM system libraries are fine.&lt;&#x2F;p&gt;
&lt;p&gt;Our first task is to parse the provided Sierra program.&lt;br &#x2F;&gt;
Fortunately, the Cairo compiler libraries provide excellent functionality:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cairo_lang_sierra::ProgramParser::new()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .parse(fs::read_to_string(input).unwrap().as_str())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .unwrap(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Once we have the Sierra representation in memory, we can start the translation process.&lt;br &#x2F;&gt;
Here is a high-level overview:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;stateDiagram-v2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    direction LR&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    state &amp;quot;Load sierra program&amp;quot; as Sierra&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    state &amp;quot;Initialize compiler&amp;quot; as init&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    state &amp;quot;Initialize execution engine&amp;quot; as engine&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    state if_skip_jit &amp;lt;&amp;lt;choice&amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    state &amp;quot;Load MLIR dialects&amp;quot; as dialects&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    state &amp;quot;Create built-in module&amp;quot; as module&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    state &amp;quot;Create libc wrappers&amp;quot; as libc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    state &amp;quot;Process Types&amp;quot; as types&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    state &amp;quot;Process Library functions&amp;quot; as libfuncs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    state &amp;quot;Save non-flow function info&amp;quot; as func_info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    state &amp;quot;Process functions&amp;quot; as funcs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    state &amp;quot;Calculate block ranges per function&amp;quot; as blocks&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    state &amp;quot;Process statements&amp;quot; as statements&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    state &amp;quot;Apply MLIR passes&amp;quot; as passes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [*] --&amp;gt; Initialize&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    state Initialize {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        sierra --&amp;gt; init&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        init --&amp;gt; if_skip_jit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        if_skip_jit --&amp;gt; engine: if JIT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        if_skip_jit --&amp;gt; dialects: if Compile&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        engine --&amp;gt; dialects&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Initialize --&amp;gt; Compile&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    state Compile {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        module --&amp;gt; libc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        libc --&amp;gt; types&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        types --&amp;gt; libfuncs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        types --&amp;gt; func_info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        func_info --&amp;gt; libfuncs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        libfuncs --&amp;gt; funcs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        funcs --&amp;gt; blocks&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        blocks --&amp;gt; statements&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Compile --&amp;gt; passes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    passes --&amp;gt; Output&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Output --&amp;gt; [*]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The first step is initializing our machinery.&lt;br &#x2F;&gt;
We need to create our dialect and context and register them. A context contains IR, dialects, and passes and owns various objects, such as types, locations, and dialect instances.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let registry = dialect::Registry::new();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;register_all_dialects(&amp;amp;registry);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let context = Context::new();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;context.append_dialect_registry(&amp;amp;registry);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;context.load_all_available_dialects();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;register_all_llvm_translations(&amp;amp;context);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We also need to create a region with a block for the builtin module:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let location = Location::unknown(&amp;amp;context);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let region = Region::new();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let block = Block::new(&amp;amp;[]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;region.append_block(block);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let module_op = operation::Builder::new(&amp;quot;builtin.module&amp;quot;, location)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .add_regions(vec![region])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .build();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let module = Module::from_operation(module_op).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Once initialization is done, we can start converting by processing, in sequence: types, libfuncs, functions, and statements. We won’t go into full detail, but we can look at an exciting example short enough to inspect its transformation process: a program performing addition and subtraction of field elements and see how libruls are processed.&lt;&#x2F;p&gt;
&lt;p&gt;For every function declaration in the libfunc declaration section of our Sierra program, the libfunc name will be matched, and the execution of compilation will be dispatched to the appropriate Rust function.&lt;&#x2F;p&gt;
&lt;p&gt;This simple function takes a Felt (a 252-bit Field Element) and returns a struct with two values:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn something(a: felt252) -&amp;gt; (felt252, felt252) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    (a + 2, a - 2)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The cairo compiler outputs the following Sierra:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;type felt252 = felt252;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;type Tuple&amp;lt;felt252, felt252&amp;gt; = Struct&amp;lt;ut@Tuple, felt252, felt252&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;libfunc felt252_const&amp;lt;2&amp;gt; = felt252_const&amp;lt;2&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;libfunc dup&amp;lt;felt252&amp;gt; = dup&amp;lt;felt252&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;libfunc felt252_add = felt252_add;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;libfunc felt252_sub = felt252_sub;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;libfunc struct_construct&amp;lt;Tuple&amp;lt;felt252, felt252&amp;gt;&amp;gt; = struct_construct&amp;lt;Tuple&amp;lt;felt252, felt252&amp;gt;&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;libfunc store_temp&amp;lt;Tuple&amp;lt;felt252, felt252&amp;gt;&amp;gt; = store_temp&amp;lt;Tuple&amp;lt;felt252, felt252&amp;gt;&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;felt252_const&amp;lt;2&amp;gt;() -&amp;gt; ([1]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dup&amp;lt;felt252&amp;gt;([0]) -&amp;gt; ([0], [3]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;felt252_add([3], [1]) -&amp;gt; ([2]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;felt252_const&amp;lt;2&amp;gt;() -&amp;gt; ([4]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;felt252_sub([0], [4]) -&amp;gt; ([5]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;struct_construct&amp;lt;Tuple&amp;lt;felt252, felt252&amp;gt;&amp;gt;([2], [5]) -&amp;gt; ([6]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;store_temp&amp;lt;Tuple&amp;lt;felt252, felt252&amp;gt;&amp;gt;([6]) -&amp;gt; ([7]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;return([7]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;simple::simple::something@0([0]: felt252) -&amp;gt; (Tuple&amp;lt;felt252, felt252&amp;gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Despite being quite low-level, it is still readable:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * declare a felt constant with value 2 into memory cell 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * duplicate the value in memory cell 0 into cell 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * add the value in the memory cell 1 to the one in cell 3 and put the result in cell 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * declare a felt constant with value 2 into memory cell 4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * subtract the value in the memory cell 4 from the value in cell 0, and put the result in cell 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * construct a tuple of type `&amp;lt;felt252, felt252&amp;gt;` with values from cells 2 and 5, and put it in cell 6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * store this value in cell 7 in preparation for returning it&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * return the value in cell 7&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The meat in this simple example is the “&lt;code&gt;felt252_add&lt;&#x2F;code&gt;” libfunc which implements addition for field elements.&lt;br &#x2F;&gt;
Let’s see how this is implemented in our MLIR dialect:&lt;&#x2F;p&gt;
&lt;p&gt;We’ll need a region with several blocks, one in which the calculation occurs, another in which we’ll return values that result in numbers greater or equal than the field prime, and another for returning values lesser than the field prime.&lt;br &#x2F;&gt;
We obtain the arguments, perform the addition, and check the result against the field prime.&lt;&#x2F;p&gt;
&lt;p&gt;This condition is represented by the &lt;code&gt;op_cond_br&lt;&#x2F;code&gt; conditional branch operation from the MLIR &lt;code&gt;cf&lt;&#x2F;code&gt; dialect, which&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;… contains low-level, i.e., non-region-based, control flow constructs.&lt;br &#x2F;&gt;
These constructs generally represent control flow directly on SSA blocks of a control flow graph.&lt;br &#x2F;&gt;
The cond_br terminator operation represents a conditional branch on a boolean (1-bit integer) value. If the bit is set, then the first destination is jumped to; if it is false, the second destination is chosen.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;In our case, due to how addiction works in the field, if the result is greater than the field prime, we can simply subtract the prime value to wrap around. In other words, if the result is greater, jump to the &lt;code&gt;gte_prime_block&lt;&#x2F;code&gt; or “greater than prime block,” and if not, jump to the &lt;code&gt;in_range_block.&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn create_libfunc_felt_add(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp; &amp;#39;ctx self,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        func_decl: &amp;amp;LibfuncDeclaration,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        parent_block: BlockRef&amp;lt;&amp;#39;ctx&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        storage: &amp;amp;mut Storage&amp;lt;&amp;#39;ctx&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ) -&amp;gt; Result&amp;lt;()&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let id = func_decl.id.debug_name.as_ref().unwrap().to_string();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let sierra_felt_type = SierraType::Simple(self.felt_type());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let felt_type = sierra_felt_type.get_type();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let felt_type_location = sierra_felt_type.get_type_location(&amp;amp;self.context);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let region = Region::new();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F;Block in which the calculation occurs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let entry_block = Block::new(&amp;amp;[felt_type_location, felt_type_location]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F;Block for wrapping values &amp;gt;= PRIME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let gte_prime_block = Block::new(&amp;amp;[]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F;Block for returning values &amp;lt; PRIME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let in_range_block = Block::new(&amp;amp;[]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F; res = lhs + rhs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let lhs = entry_block.argument(0)?.into();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let rhs = entry_block.argument(1)?.into();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let res_op = self.op_add(&amp;amp;entry_block, lhs, rhs);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let res = res_op.result(0)?.into();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F; gt_prime &amp;lt;=&amp;gt; res_result &amp;gt;= PRIME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let prime_op = self.prime_constant(&amp;amp;entry_block);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let prime = prime_op.result(0)?.into();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let gte_prime_op = self.op_cmp(&amp;amp;entry_block, CmpOp::UnsignedGreaterThanEqual, res, prime);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let gte_prime = gte_prime_op.result(0)?.into();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F; if gt_prime&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        self.op_cond_br(&amp;amp;entry_block, gte_prime, &amp;amp;gte_prime_block, &amp;amp;in_range_block, &amp;amp;[], &amp;amp;[]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F; gt prime block&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let wrapped_res_op = self.op_sub(&amp;amp;gte_prime_block, res, prime);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let wrapped_res = wrapped_res_op.result(0)?.into();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        self.op_return(&amp;amp;gte_prime_block, &amp;amp;[wrapped_res]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F; in range block&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        self.op_return(&amp;amp;in_range_block, &amp;amp;[res]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        region.append_block(entry_block);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        region.append_block(in_range_block);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        region.append_block(gte_prime_block);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let func = self.op_func(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;amp;id,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;amp;create_fn_signature(&amp;amp;[felt_type, felt_type], &amp;amp;[felt_type]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            vec![region],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            FnAttributes::libfunc(false, true),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        )?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        parent_block.append_operation(func);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        storage.libfuncs.insert(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            id,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            SierraLibFunc::create_function_all_args(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                vec![sierra_felt_type.clone(), sierra_felt_type.clone()],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                vec![sierra_felt_type],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Ok(())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is the MLIR corresponding to the felt252_add libfunc:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;func.func @felt252_add(%arg0: i256, %arg1: i256) -&amp;gt; i256 attributes {llvm.dso_local, llvm.linkage = #llvm.linkage&amp;lt;internal&amp;gt;, passthrough = [&amp;quot;norecurse,&amp;quot; &amp;quot;alwaysinline,&amp;quot; &amp;quot;nounwind&amp;quot;]} {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    %0 = arith.addi %arg0, %arg1 : i256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    %c3618502788666131213697322783095070105623107215331596699973092056135872020481_i256 = arith.constant 3618502788666131213697322783095070105623107215331596699973092056135872020481 : i256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    %1 = arith.cmpi uge, %0, %c3618502788666131213697322783095070105623107215331596699973092056135872020481_i256 : i256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    cf.cond_br %1, ^bb2, ^bb1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ^bb1:  &#x2F;&#x2F; pred: ^bb0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return %0 : i256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ^bb2:  &#x2F;&#x2F; pred: ^bb0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    %2 = arith.subi %0, %c3618502788666131213697322783095070105623107215331596699973092056135872020481_i256 : i256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return %2 : i256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As you can see, we have three basic blocks, and the last instruction of the first is a conditional jump.&lt;&#x2F;p&gt;
&lt;p&gt;This is the entire resulting MLIR before going the registered passes:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;module {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  func.func @felt252_add(%arg0: i256, %arg1: i256) -&amp;gt; i256 attributes {llvm.dso_local, llvm.linkage = #llvm.linkage&amp;lt;internal&amp;gt;, passthrough = [&amp;quot;norecurse,&amp;quot; &amp;quot;alwaysinline,&amp;quot; &amp;quot;nounwind&amp;quot;]} {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    %0 = arith.addi %arg0, %arg1 : i256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    %c3618502788666131213697322783095070105623107215331596699973092056135872020481_i256 = arith.constant 3618502788666131213697322783095070105623107215331596699973092056135872020481 : i256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    %1 = arith.cmpi uge, %0, %c3618502788666131213697322783095070105623107215331596699973092056135872020481_i256 : i256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    cf.cond_br %1, ^bb2, ^bb1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ^bb1:  &#x2F;&#x2F; pred: ^bb0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return %0 : i256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ^bb2:  &#x2F;&#x2F; pred: ^bb0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    %2 = arith.subi %0, %c3618502788666131213697322783095070105623107215331596699973092056135872020481_i256 : i256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return %2 : i256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  func.func @felt252_sub(%arg0: i256, %arg1: i256) -&amp;gt; i256 attributes {llvm.dso_local, llvm.linkage = #llvm.linkage&amp;lt;internal&amp;gt;, passthrough = [&amp;quot;norecurse,&amp;quot; &amp;quot;alwaysinline,&amp;quot; &amp;quot;nounwind&amp;quot;]} {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    %0 = arith.subi %arg0, %arg1 : i256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    %c0_i256 = arith.constant 0 : i256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    %1 = arith.cmpi slt, %0, %c0_i256 : i256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    cf.cond_br %1, ^bb2, ^bb1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ^bb1:  &#x2F;&#x2F; pred: ^bb0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return %0 : i256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ^bb2:  &#x2F;&#x2F; pred: ^bb0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    %c3618502788666131213697322783095070105623107215331596699973092056135872020481_i256 = arith.constant 3618502788666131213697322783095070105623107215331596699973092056135872020481 : i256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    %2 = arith.addi %0, %c3618502788666131213697322783095070105623107215331596699973092056135872020481_i256 : i256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return %2 : i256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  func.func @&amp;quot;struct_construct&amp;lt;Tuple&amp;lt;felt252, felt252&amp;gt;&amp;gt;&amp;quot;(%arg0: i256, %arg1: i256) -&amp;gt; !llvm.struct&amp;lt;packed (i256, i256)&amp;gt; attributes {llvm.dso_local, llvm.linkage = #llvm.linkage&amp;lt;internal&amp;gt;, passthrough = [&amp;quot;norecurse,&amp;quot; &amp;quot;alwaysinline,&amp;quot; &amp;quot;nounwind&amp;quot;]} {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    %0 = llvm. mir.undef : !llvm.struct&amp;lt;packed (i256, i256)&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    %1 = llvm.insertvalue %arg0, %0[0] : !llvm.struct&amp;lt;packed (i256, i256)&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    %2 = llvm.insertvalue %arg1, %1[1] : !llvm.struct&amp;lt;packed (i256, i256)&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return %2 : !llvm.struct&amp;lt;packed (i256, i256)&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  func.func @&amp;quot;simple::simple::something&amp;quot;(%arg0: i256) -&amp;gt; !llvm.struct&amp;lt;packed (i256, i256)&amp;gt; attributes {llvm.dso_local, llvm.emit_c_interface} {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    cf.br ^bb1(%arg0 : i256)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ^bb1(%0: i256):  &#x2F;&#x2F; pred: ^bb0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    %c2_i256 = arith.constant 2 : i256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    %1 = call @felt252_add(%0, %c2_i256) : (i256, i256) -&amp;gt; i256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    %c2_i256_0 = arith.constant 2 : i256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    %2 = call @felt252_sub(%0, %c2_i256_0) : (i256, i256) -&amp;gt; i256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    %3 = call @&amp;quot;struct_construct&amp;lt;Tuple&amp;lt;felt252, felt252&amp;gt;&amp;gt;&amp;quot;(%1, %2) : (i256, i256) -&amp;gt; !llvm.struct&amp;lt;packed (i256, i256)&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return %3 : !llvm.struct&amp;lt;packed (i256, i256)&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Great, so we have converted Sierra to MLIR using several built-in dialects and our own.&lt;br &#x2F;&gt;
To be able to run our code, we need to lower it to something that can be run.&lt;br &#x2F;&gt;
An excellent choice, for now, is LLVM IR since we want to run our Cairo code as native CPU instructions and can use the very solid LLVM infrastructure to compile LLVM IR to a binary object.&lt;br &#x2F;&gt;
We also want to leverage MLIR and LLVM’s pass manager infrastructure to take advantage of the optimizations it provides.&lt;&#x2F;p&gt;
&lt;p&gt;We create a pass manager and add the passes we want our code to go through:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let pass_manager = pass::Manager::new(&amp;amp;compiler.context);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    register_all_passes();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pass_manager.add_pass(pass::conversion::convert_func_to_llvm());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pass_manager.add_pass(pass::conversion::convert_scf_to_cf());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pass_manager.add_pass(pass::conversion::convert_cf_to_llvm());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pass_manager.add_pass(pass::conversion::convert_arithmetic_to_llvm());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pass_manager.add_pass(pass::conversion::convert_index_to_llvm());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pass_manager.add_pass(pass::conversion::convert_math_to_llvm());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pass_manager.add_pass(pass::conversion::convert_memref_to_llvmconversion_pass());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pass_manager.add_pass(pass::conversion::convert_reconcile_unrealized_casts());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if optimized {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        pass_manager.add_pass(pass::transform::canonicalizer());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        pass_manager.add_pass(pass::transform::inliner());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        pass_manager.add_pass(pass::transform::symbol_dce());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        pass_manager.add_pass(pass::transform::cse());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        pass_manager.add_pass(pass::transform::sccp());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pass_manager.enable_verifier(true);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pass_manager.run(&amp;amp;mut compiler.module)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let op = compiler.module.as_operation();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if op.verify() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        if debug_info {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            Ok(op.debug_print())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        } else {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            Ok(op.to_string())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    } else {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Err(color_eyre::eyre::eyre!(&amp;quot;error verifying&amp;quot;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;What do these passes do?&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * convert_func_to_llvm`: converts the `func`dialect, which contains operations surrounding high-order function abstractions, such as calls, to the`llvm` dialect, which maps LLVM IR into MLIR by defining the corresponding operations and types.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `convert_scf_to_cf`: converts the `scf` (Structured Control Flow, with loops and ifs) dialect to the `cf` (Control Flow) dialect, replacing structured control flow with a CFG. In LLVM, you have to analyze branches to detect loops. SCF is at a higher abstraction.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `convert_cf_to_llvm`: converts the `cf` dialect to the `llvm` dialect.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `convert_arithmetic_to_llvm`: converts the `arith` dialect (which holds basic integer and floating point mathematical operations) to the `llvm` dialect.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `convert_math_to_llvm`: converts the `math` dialect (which holds mathematical operations on integer and floating types beyond simple arithmetics) to the `llvm` dialect.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `convert_index_to_llvm`: converts the `index` dialect (which contains operations for manipulating values of the built-in index type) to the `llvm` dialect.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `convert_memref_to_llvmconversion_pass`: The `member` dialect is intended to hold core member creation and manipulation ops, which are not strongly associated with any particular other dialect or domain abstraction.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `convert_reconcile_unrealized_casts`: this pass simplifies and eliminates unrealized conversion cast operations, commonly introduced by partial dialect conversions, that transitively convert a value to another value of the same type.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The optimization passes we will apply are:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `canonicalize`: Canonicalize operations. This pass performs various types of canonicalizations over a set of operations by iteratively applying the canonicalization patterns of all loaded dialects until either a fixpoint is reached or the maximum number of iterations&#x2F;rewrites is exhausted. Canonicalization is an important part of compiler IR design: it makes it easier to implement reliable compiler transformations and to reason about what is better or worse in the code, and it forces interesting discussions about the goals of a particular level of IR. Most compilers have canonicalization passes, and sometimes they have many different ones (e.g., inst-combine, dag combine, etc, in LLVM). Because MLIR is a multi-level IR, it can provide a single canonicalization infrastructure and reuse it across many different IRs that it represents.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `more inline`: the more inline pass inline function calls.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `symbol_dce`: this pass deletes all symbols that are found to be unreachable.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `cse`: this pass implements a generalized algorithm for common sub-expression elimination.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `sccp`: this pass implements a general algorithm for sparse conditional constant propagation. This algorithm detects values that are known to be constant and optimistically propagates this throughout the IR. Any values proven to be constant are replaced and removed if possible.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;execution&quot;&gt;Execution&lt;&#x2F;h4&gt;
&lt;p&gt;We now have an in-memory representation of our program in optimized MLIR. How can we execute our code?&lt;&#x2F;p&gt;
&lt;p&gt;MLIR provides an ExecutionEngine, which takes a module and expects it to be translatable to LLVM IR, and then uses the LLVM JIT ExecutionEngine to compile and run it.&lt;br &#x2F;&gt;
The engine must also know the entry point for execution, and the following example is from a benchmark of the Fibonacci function:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let program = ProgramParser::new().parse(include_str!(&amp;quot;programs&#x2F;fib.sierra&amp;quot;)).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let engine = ExecutionEngine::new(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;amp;compiler.module,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;amp;[&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;format!(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            &amp;quot;{}&#x2F;libmlir_c_runner_utils.{}&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            run_llvm_config(&amp;amp;[&amp;quot;--libdir&amp;quot;]).trim(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            env!(&amp;quot;SHARED_LIB_EXT&amp;quot;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        env!(&amp;quot;S2M_UTILS_PATH&amp;quot;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    false,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;unsafe {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    engine.invoke_packed(&amp;quot;fib::fib::main&amp;quot;, &amp;amp;mut []).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;&#x2F;h2&gt;
&lt;p&gt;As said, MLIR is a young project.&lt;br &#x2F;&gt;
Although there is a healthy number of case studies and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mlir.llvm.org&#x2F;users&#x2F;&quot;&gt;users&lt;&#x2F;a&gt; enough to look at the sunset sky and muse, “This is the way,” there are a few caveats.&lt;&#x2F;p&gt;
&lt;p&gt;First, although it is clear that the project has made an effort, documentation is scarce.&lt;br &#x2F;&gt;
The API is documented, and there are great getting started tutorials, but if you stray off the signaled path, you end up looking at test code, other projects, and trial and error.&lt;&#x2F;p&gt;
&lt;p&gt;Second, the project is written in C++.&lt;br &#x2F;&gt;
It provides a C-compatible API with which to fashion bindings in your language, but it is under development and unstable.&lt;br &#x2F;&gt;
The Python bindings are also under development and not enabled by default.&lt;br &#x2F;&gt;
The Rust bindings are somewhat auto-generated and not very mature.&lt;br &#x2F;&gt;
You may end up having to build some tools to build this tool to build the tool you want to ship, also known as yak shaving of an especially hairy breed.&lt;&#x2F;p&gt;
&lt;p&gt;Third, like any powerful tool that allows one to operate on a high level of abstraction, it requires you to be able to bridge abstraction layers and truly understand your goals and the obstacles you face in reaching them.&lt;br &#x2F;&gt;
Knowledge of compiler technology and the techniques and vocabulary involved is a must.&lt;br &#x2F;&gt;
Perhaps with more maturity, other tools will be able to be fashioned, which can hide complexity for more specific domains.&lt;&#x2F;p&gt;
&lt;p&gt;We would like to salute and thank the team and community behind LLVM and MLIR, and Cairo.&lt;br &#x2F;&gt;
Foundational technologies are rare, difficult to develop, and require great insight and vision to come to terms with.&lt;br &#x2F;&gt;
These stones feel like the base on which great things will rest.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;iT9Qv1X.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;references-and-resources&quot;&gt;References and Resources&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [MLIR Homepage](https:&#x2F;&#x2F;mlir.llvm.org&#x2F;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * 2019 EuroLLVM Developers’ Meeting: T. Shpeisman &amp;amp; C. Lattner “MLIR: Multi-Level Intermediate Representation Compiler Infrastructure” [Video](https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=qzljG6DKgic) and [Slides](https:&#x2F;&#x2F;llvm.org&#x2F;devmtg&#x2F;2019-04&#x2F;slides&#x2F;Keynote-ShpeismanLattner-MLIR.pdf)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * MLIR Tutorial [Video](https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=Y4SvqTtOIDk) and [Slides](https:&#x2F;&#x2F;llvm.org&#x2F;devmtg&#x2F;2020-09&#x2F;slides&#x2F;MLIR_Tutorial.pdf)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Yizhou Shan&amp;#39;s notes on MLIR](http:&#x2F;&#x2F;lastweek.io&#x2F;notes&#x2F;MLIR&#x2F;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Lei Zhang&amp;#39;s &amp;quot;Compilers and IRs: LLVM IR, SPIR-V, and MLIR&amp;quot;](https:&#x2F;&#x2F;www.lei.chat&#x2F;posts&#x2F;compilers-and-irs-llvm-ir-spirv-and-mlir&#x2F;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Starkware glossary: STARKs, StarkEx, and StarkNet](https:&#x2F;&#x2F;medium.com&#x2F;starkware&#x2F;starks-starkex-and-starknet-9a426680745a)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Starkware: Cairo 1.0](https:&#x2F;&#x2F;medium.com&#x2F;starkware&#x2F;cairo-1-0-aa96eefb19a0)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Starkware: Cairo 1.0 is here](https:&#x2F;&#x2F;medium.com&#x2F;starkware&#x2F;cairo-1-0-is-here-7e1ac8377038)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</description>
      </item>
      <item>
          <title>All you wanted to know about Plonk</title>
          <pubDate>Mon, 01 May 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/all-you-wanted-to-know-about-plonk/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/all-you-wanted-to-know-about-plonk/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/all-you-wanted-to-know-about-plonk/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;Zero-knowledge proofs, also known as ZKPs, are becoming popular due to their numerous applications in delegating computations to untrusted servers and addressing scalability issues in decentralized ledgers. By using ZKPs, we can prove the validity of a given computation without revealing sensitive information, and the proof is short and quickly verifiable. STARKs (scalable transparent arguments of knowledge) and SNARKs (succinct non-interactive arguments of knowledge) are cryptographic primitives that allow us to transform computer programs into relations between polynomials and prove their correct execution, and have numerous applications in decentralized finances, governance, and computation. For more background on these topics, you can look at our previous posts on &lt;a href=&quot;&#x2F;lambdaworks-or-how-we-decided-to-created-our-zksnarks-library-and-a-stark-prover&#x2F;&quot;&gt;STARKs&lt;&#x2F;a&gt; and &lt;a href=&quot;&#x2F;the-hunting-of-the-zk-snark&#x2F;&quot;&gt;SNARKs&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Due to its efficiency and flexibility, PLONK is a popular cryptographic proving system within the Zero Knowledge (ZK) community, having customized versions such as Halo2 and Kimchi. It enables the verification of complex computations executed by untrusted parties through the transformation of programs into circuit representations. The system relies on arithmetization, which converts logical circuits into polynomial expressions. The main idea behind arithmetization is to express the computation as a set of polynomial equations. The solutions to these equations correspond to the outputs of the circuit. In this section, we will delve into how arithmetization works in PLONK and the protocol used to generate and verify proofs.&lt;&#x2F;p&gt;
&lt;p&gt;The original paper can be found &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2019&#x2F;953.pdf&quot;&gt;here&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;notation&quot;&gt;Notation&lt;&#x2F;h2&gt;
&lt;p&gt;We will use the following notation throughout the article. If you are unfamiliar with some of these concepts, you can look at our &lt;a href=&quot;&#x2F;math-survival-kit-for-developers&#x2F;&quot;&gt;math survival kit&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The symbol $\mathbb{F}$ denotes a finite field. It is fixed all along. The symbol $\omega$ represents a primitive root of unity in $\mathbb{F}$, that is, $\omega^n = 1$ and $\omega^k \neq 1$ for $0 &amp;lt; k &amp;lt; n$.&lt;&#x2F;p&gt;
&lt;p&gt;All polynomials have coefficients in $\mathbb{F}$, and the variable is usually denoted by $X$; we denote this set as $\mathbb{F} [X]$. We represent polynomials by single letters like $p, a, b, z$. We only mark them as $z(X)$ when we want to emphasize that it is a polynomial in $X$ or we need to define a polynomial from another one explicitly. For example, when composing a polynomial $z$ with the polynomial $\omega X$, the result is denoted by $z’ := z(\omega X)$. The symbol $’$ is &lt;strong&gt;not&lt;&#x2F;strong&gt; used to indicate derivatives.&lt;&#x2F;p&gt;
&lt;p&gt;When interpolating at a domain $H = \{h_0 , \dots , h_n \} \subset \mathbb{F}$, the symbols $L_i$ denote the Lagrange basis. That is $L_i$ is the polynomial such that $L_i (h_j) = 0$ for all $j\neq i$, and that $L_i (h_i) = 1$.&lt;&#x2F;p&gt;
&lt;p&gt;If $M$ is a matrix, then $M_{i,j}$ denotes the value at the row $i$ and column $j$.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;the-ideas-and-components&quot;&gt;The ideas and components&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;programs-our-toy-example&quot;&gt;Programs. Our toy example&lt;&#x2F;h2&gt;
&lt;p&gt;We’ll use the following toy program throughout this post for better clarity.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;INPUT:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  x&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PRIVATE INPUT:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  e&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;OUTPUT:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  e * x + x - 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The observer would have noticed that we could write this program as $(e + 1) \times x - 1$, which is more sensible. But the way it is written now serves us to explain the arithmetization of PLONK better. So we’ll stick to it.&lt;&#x2F;p&gt;
&lt;p&gt;The idea is that the verifier holds some value $x$, say $x=3$. He gives it to the prover. She executes the program using her chosen value $e$ and sends the output value, say $8$, along with a proof $\pi$ demonstrating the correct execution of the program and obtaining the correct output.&lt;&#x2F;p&gt;
&lt;p&gt;In the context of PLONK, both the inputs and outputs of the program are considered &lt;em&gt;public inputs&lt;&#x2F;em&gt;. This may sound odd, but it is because these are the inputs to the verification algorithm. This is the algorithm that takes, in this case, the tuple $(3, 8, \pi)$ and outputs &lt;em&gt;Accept&lt;&#x2F;em&gt; if the toy program was executed with input $x=3$, some private value $e$ not revealed to the verifier, and out came $8$. Otherwise, it outputs &lt;em&gt;Reject&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;PLONK can be used to delegate program executions to untrusted parties, but it can also be used as proof of knowledge. A prover could use our program to demonstrate that she knows the multiplicative inverse of some value $x$ in the finite field without revealing it. She would do it by sending the verifier the tuple $(x, 0, \pi)$, where $\pi$ is the proof of the execution of our toy program.&lt;&#x2F;p&gt;
&lt;p&gt;This is pointless in our toy example because any verifier efficiently performs the inversion of field elements. But change our program to the following, and you get proof of knowledge of the preimage of SHA256 digests.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PRIVATE INPUT:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  e&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;OUTPUT:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  SHA256(e)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here there’s no input aside from the prover’s private input. As we mentioned, the output $h$ of the program is then part of the inputs to the verification algorithm, which, in this case, takes $(h, \pi)$.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;plonk-arithmetization&quot;&gt;PLONK Arithmetization&lt;&#x2F;h2&gt;
&lt;p&gt;This process takes the circuit of a particular program and produces a set of mathematical tools that we can use to generate and verify proofs of execution. The final result will be a set of eight polynomials. To compute them, we first need to define two matrices. We call them the $Q$ matrix and the $V$ matrix. The polynomials and the matrices depend only on the program and not on any particular execution. So they can be computed once and used for every execution instance. To understand what they are helpful for, we need to start with &lt;em&gt;execution traces&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;circuits-and-execution-traces&quot;&gt;Circuits and execution traces&lt;&#x2F;h3&gt;
&lt;p&gt;See the program as a sequence of gates with a left operand, a right operand, and an output. The two most basic gates are multiplication and addition gates. In our example, one way to see our toy program is as a composition of three gates.&lt;&#x2F;p&gt;
&lt;p&gt;Gate 1: left: $e$, right: $x$, output: $u = e \times x$&lt;br &#x2F;&gt;
Gate 2: left: $u$, right: $x$, output: $v = u + x$&lt;br &#x2F;&gt;
Gate 3: left: $v$, right: $1$, output: $w = v - 1$&lt;&#x2F;p&gt;
&lt;p&gt;On executing the circuit, all these variables will take a concrete value. We can put all that information in table form. It will be a matrix with all left, right, and output values of all the gates—one row per gate. We call the columns of this matrix $L, R, O$. Let’s build them for $x=3$ and $e=2$. We get $u=6$, $v=9$ and $w=5$. So the first matrix is:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;A&lt;&#x2F;th&gt;&lt;th&gt;B&lt;&#x2F;th&gt;&lt;th&gt;C&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;6&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;6&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;9&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;9&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;The last gate subtracts a constant value that is part of the program and is not a variable. So it has only one input instead of two. And the output is the result of subtracting $1$ from it. That’s why it is handled a bit differently from the second gate. The symbol “-” in the $R$ column is a consequence of that. With that, we mean “any value” because it won’t change the result. In the next section, we’ll see how we implement that. Here we’ll use this notation when any value can be put there. If we have to choose some, we’ll default to $0$.&lt;&#x2F;p&gt;
&lt;p&gt;What we got is a valid execution trace. Not all matrices of that shape will be the trace of the execution of the program. The matrices $Q$ and $V$ will be the tools to distinguish between valid and invalid execution traces.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-q-matrix&quot;&gt;The $Q$ matrix&lt;&#x2F;h3&gt;
&lt;p&gt;As we said, it only depends on the program itself and not on any particular evaluation. It has one row for each gate, and its columns are called $Q_L, Q_R, Q_O, Q_M, Q_C$. They encode the rows’ gate type and are designed to satisfy the following.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Claim:&lt;&#x2F;strong&gt; If columns $L, R, O$ correspond to a valid evaluation of the circuit, then for all $i$, the following equality holds $$A_i Q_{Li} + B_i Q_{Ri} + A_i B_i Q_{Mi} + C_i Q_{Oi} + Q_{Ci} = 0$$&lt;&#x2F;p&gt;
&lt;p&gt;This is better seen with examples. The row represents a multiplication gate:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;$Q_L$&lt;&#x2F;th&gt;&lt;th&gt;$Q_R$&lt;&#x2F;th&gt;&lt;th&gt;$Q_M$&lt;&#x2F;th&gt;&lt;th&gt;$Q_O$&lt;&#x2F;th&gt;&lt;th&gt;$Q_C$&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;-1&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;And the row in the trace matrix that corresponds to the execution of that gate is&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;A&lt;&#x2F;th&gt;&lt;th&gt;B&lt;&#x2F;th&gt;&lt;th&gt;C&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;6&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;The equation in the claim for that row is that $2 \times 0 + 3 \times 0 + 2 \times 3 \times 1 + 6 \times (-1) + 0$, which equals $0$. The next is an addition gate. The row represents this:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;$Q_L$&lt;&#x2F;th&gt;&lt;th&gt;$Q_R$&lt;&#x2F;th&gt;&lt;th&gt;$Q_M$&lt;&#x2F;th&gt;&lt;th&gt;$Q_O$&lt;&#x2F;th&gt;&lt;th&gt;$Q_C$&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;-1&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;The corresponding row in the trace matrix its&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;A&lt;&#x2F;th&gt;&lt;th&gt;B&lt;&#x2F;th&gt;&lt;th&gt;C&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;6&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;9&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;And the equation of the claim is $6 \times 1 + 3 \times 1 + 2 \times 3 \times 0 + 9 \times (-1) + 0$, which adds up to $0$. Our last row is the gate that adds a constant. The row can represent addition by constant C&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;$Q_L$&lt;&#x2F;th&gt;&lt;th&gt;$Q_R$&lt;&#x2F;th&gt;&lt;th&gt;$Q_M$&lt;&#x2F;th&gt;&lt;th&gt;$Q_O$&lt;&#x2F;th&gt;&lt;th&gt;$Q_C$&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;-1&lt;&#x2F;td&gt;&lt;td&gt;C&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;In our case, $C=-1$. The corresponding row in the execution trace is&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;A&lt;&#x2F;th&gt;&lt;th&gt;B&lt;&#x2F;th&gt;&lt;th&gt;C&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;9&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;And the equation of the claim is $9 \times 1 + 0 \times 0 + 9 \times 0 \times 0 + 8 \times (-1) + C$. This is also zero.&lt;&#x2F;p&gt;
&lt;p&gt;Putting it all together, the entire $Q$ matrix is&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;$Q_L$&lt;&#x2F;th&gt;&lt;th&gt;$Q_R$&lt;&#x2F;th&gt;&lt;th&gt;$Q_M$&lt;&#x2F;th&gt;&lt;th&gt;$Q_O$&lt;&#x2F;th&gt;&lt;th&gt;$Q_C$&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;-1&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;-1&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;-1&lt;&#x2F;td&gt;&lt;td&gt;-1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;And we saw that the claim is true for our particular execution:&lt;br &#x2F;&gt;
$$ 2 \times 0 + 3 \times 0 + 2 \times 3 \times 1 + 6 \times (-1) + 0 = 0 $$&lt;br &#x2F;&gt;
$$ 6 \times 1 + 3 \times 1 + 6 \times 3 \times 0 + 9 \times (-1) + 0 = 0 $$&lt;br &#x2F;&gt;
$$ 9 \times 1 + 0 \times 0 + 9 \times 0 \times 0 + 8 \times (-1) + (-1) = 0 $$&lt;&#x2F;p&gt;
&lt;p&gt;Not crucial to our example, but multiplication by constant C can be represented by:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;$Q_L$&lt;&#x2F;th&gt;&lt;th&gt;$Q_R$&lt;&#x2F;th&gt;&lt;th&gt;$Q_M$&lt;&#x2F;th&gt;&lt;th&gt;$Q_O$&lt;&#x2F;th&gt;&lt;th&gt;$Q_C$&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;C&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;-1&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;As you might have already noticed, there are several ways to represent the same gate in some cases. We’ll exploit this in a moment.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-v-matrix&quot;&gt;The $V$ matrix&lt;&#x2F;h3&gt;
&lt;p&gt;The claim in the previous section is not an “if and only if” statement because the following trace columns do satisfy the equations but do not correspond to a valid execution:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;A&lt;&#x2F;th&gt;&lt;th&gt;B&lt;&#x2F;th&gt;&lt;th&gt;C&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;6&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;20&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;td&gt;19&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;The $V$ matrix encodes the carry of the results from one gate to the right or left operand of a subsequent one. These are called &lt;em&gt;wirings&lt;&#x2F;em&gt;. Like the $Q$ matrix, it’s independent of the individual evaluation. It consists of indices for all input and intermediate variables. In this case, that matrix is:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;L&lt;&#x2F;th&gt;&lt;th&gt;R&lt;&#x2F;th&gt;&lt;th&gt;O&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Here $0$ is the index of $e$, $1$ is the index of $x$, $2$ is the index of $u$, $3$ is the index of $v$, and $4$ is the index of the output $w$. Now we can update the claim to have an “if and only if” statement.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Claim:&lt;&#x2F;strong&gt; Let $T$ be a matrix with columns $A, B, C$. It corresponds to a proper evaluation of the circuit if and only if&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. for all $i$ the following equality holds $$A_i Q_{Li} + B_i Q_{Ri} + A_i B_i Q_{Mi} + C_i Q_{Oi} + Q_{Ci} = 0,$$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. for all $i,j,k,l$ such that $V_{i,j} = V_{k, l}$ we have $T_{i,j} = T_{k, l}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So now, our malformed example does not pass the second check.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;custom-gates&quot;&gt;Custom gates&lt;&#x2F;h3&gt;
&lt;p&gt;Our matrices are fine now, but they can be optimized. Let’s do that to showcase this flexibility of PLONK and also reduce the size of our example.&lt;&#x2F;p&gt;
&lt;p&gt;PLONK can construct more sophisticated gates as combinations of the five columns. Therefore, the same program can be expressed in multiple ways. In our case, we can merge all three gates into a single custom gate. The $Q$ matrix ends up being a single row.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;$Q_L$&lt;&#x2F;th&gt;&lt;th&gt;$Q_R$&lt;&#x2F;th&gt;&lt;th&gt;$Q_M$&lt;&#x2F;th&gt;&lt;th&gt;$Q_O$&lt;&#x2F;th&gt;&lt;th&gt;$Q_C$&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;-1&lt;&#x2F;td&gt;&lt;td&gt;-1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;and also the $V$ matrix&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;L&lt;&#x2F;th&gt;&lt;th&gt;R&lt;&#x2F;th&gt;&lt;th&gt;O&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;The trace matrix for this representation is just&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;A&lt;&#x2F;th&gt;&lt;th&gt;B&lt;&#x2F;th&gt;&lt;th&gt;C&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;And we check that it satisfies the equation&lt;&#x2F;p&gt;
&lt;p&gt;$$ 2 \times 0 + 3 \times 1 + 2 \times 3 \times 1 + 8 \times (-1) + (-1) = 0$$&lt;&#x2F;p&gt;
&lt;p&gt;Of course, we cannot always squash an entire program into a single gate.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;public-inputs&quot;&gt;Public inputs&lt;&#x2F;h3&gt;
&lt;p&gt;Aside from the gates that execute the program operations, additional rows must be incorporated into these matrices. This is because the prover must demonstrate not only that she ran the program but also that she used the appropriate inputs. Furthermore, the proof must include an assertion of the output value. As a result, a few extra rows are necessary. In our case, these are the first two and the last one. The original one sits now in the third row.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;$Q_L$&lt;&#x2F;th&gt;&lt;th&gt;$Q_R$&lt;&#x2F;th&gt;&lt;th&gt;$Q_M$&lt;&#x2F;th&gt;&lt;th&gt;$Q_O$&lt;&#x2F;th&gt;&lt;th&gt;$Q_C$&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;-1&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;-1&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;-1&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;-1&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;And this is the updated $V$ matrix&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;L&lt;&#x2F;th&gt;&lt;th&gt;R&lt;&#x2F;th&gt;&lt;th&gt;O&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;The first row forces the variable with index $0$ to take the value $3$. Similarly, the second row forces the variable with an index of $1$ to take the value $8$. These two will be the public inputs of the verifier. The last row checks that the program’s output is the claimed one.&lt;&#x2F;p&gt;
&lt;p&gt;And the trace matrix is now&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;A&lt;&#x2F;th&gt;&lt;th&gt;B&lt;&#x2F;th&gt;&lt;th&gt;C&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;With these extra rows, equations add up to zero only for valid executions of the program with input $3$ and output $8$.&lt;&#x2F;p&gt;
&lt;p&gt;An astute observer would notice that the matrix $Q$ is no longer independent of the specific evaluation by incorporating these new rows. This is because the first two rows of the $Q_C$ column contain concrete values specific to a particular execution instance. We can remove these values and consider them as part of an extra one-column matrix called $PI$ (stands for Public Input) to maintain independence. This column has zeros in all rows not related to public inputs. We put zeros in the $Q_C$ columns. The prover and verifier are responsible for filling in the $PI$ matrix. In our example, it is&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pi&quot;&gt;$PI$&lt;&#x2F;h2&gt;
&lt;p&gt;3&lt;br &#x2F;&gt;
8&lt;br &#x2F;&gt;
0&lt;br &#x2F;&gt;
0&lt;&#x2F;p&gt;
&lt;p&gt;And the final $Q$ matrix is&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;$Q_L$&lt;&#x2F;th&gt;&lt;th&gt;$Q_R$&lt;&#x2F;th&gt;&lt;th&gt;$Q_M$&lt;&#x2F;th&gt;&lt;th&gt;$Q_O$&lt;&#x2F;th&gt;&lt;th&gt;$Q_C$&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;-1&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;-1&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;-1&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;-1&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;We ended up with two matrices that depend only on the program, $Q$ and $V$, and two matrices that depend on a particular evaluation, namely the $ABC$ and $PI$ matrices. The updated version of the claim is the following:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Claim:&lt;&#x2F;strong&gt; Let $T$ be a matrix with columns $A, B, C$. It corresponds to an evaluation of the circuit if and only if&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. for all $i$ the following equality holds $$A_i Q_{Li} + B_i Q_{Ri} + A_i B_i Q_{Mi} + C_i Q_{Oi} + Q_{Ci} + PI_i = 0,$$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. for all $i,j,k,l$ such that $V_{i,j} = V_{k,l}$ we have $T_{i,j} = T_{k,l}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;from-matrices-to-polynomials&quot;&gt;From matrices to polynomials&lt;&#x2F;h3&gt;
&lt;p&gt;The previous section showed how the arithmetization process works in PLONK. For a program with $n$ public inputs and $m$ gates, we constructed two matrices $Q$ and $V$ of sizes $(n + m + 1) \times 5$ and $(n + m + 1) \times 3$ that satisfy the following. Let $N = n + m + 1.$&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Claim:&lt;&#x2F;strong&gt; Let $T$ be a $N \times 3$ matrix with columns $A, B, C$ and $PI$ a $N \times 1$ matrix. They correspond to a valid execution instance with public input given by $PI$ if and only if&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. for all $i$ the following equality holds $$A_i Q_{Li} + B_i Q_{Ri} + A_i B_i Q_{Mi} + C_i Q_{Oi} + Q_{Ci} + PI_i = 0,$$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. for all $i,j,k,l$ such that $V_{i,j} = V_{k,l}$ we have $T_{i,j} = T_{k,l}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. $PI_i = 0$ for all $i&amp;gt;n$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Polynomials enter now to squash most of these equations. We will traduce the set of all equations in conditions (1) and (2) to just a few equations on polynomials.&lt;&#x2F;p&gt;
&lt;p&gt;Let $\omega$ be a primitive $N$-th root of unity and let $H = {\omega^i: 0\leq i &amp;lt; N}$. Let $a, b, c, q_L, q_R, q_M, q_O, q_C, pi$ be the polynomials of degree at most $N$ that interpolate the columns $A, B, C, Q_L, Q_R, Q_M, Q_O, Q_C, PI$ at the domain $H$. This means for example that $a(\omega^i) = A_i$ for all $i$, and similarly for all the other columns (see our &lt;a href=&quot;&#x2F;diving-deep-fri&#x2F;&quot;&gt;previous post on STARKs&lt;&#x2F;a&gt; for examples on interpolation).&lt;&#x2F;p&gt;
&lt;p&gt;With this, condition (1) of the claim is equivalent to $$a(x) q_L(x) + b(x) q_R(x) + a(x) b(x) q_M(x) + c(x) q_O(x) + q_c(x) + pi(x) = 0$$ for all $x$ in $H$.This is just by definition of the polynomials. But in polynomials land, this is also equivalent to:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. There exists a polynomial $t$ such that $$a q_L + b q_R + a b q_M + c q_O + q_c + pi = z_H t$$, where $z_H$ is the polynomial $X^N -1$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To reduce condition (2) to polynomial equations, we must introduce the concept of permutation. A permutation is a rearrangement of a set, usually denoted $\sigma$. For finite sets, it is a map from a set to itself that takes all values. In our case, the set will be the set of all pairs&lt;br &#x2F;&gt;
$$I={(i,j): \text{ such that }0\leq i &amp;lt; N, \text{ and } 0\leq j &amp;lt; 3}$$&lt;br &#x2F;&gt;
The matrix $V$ induces a permutation of this set where $\sigma((i,j))$ is equal to the indices of the &lt;em&gt;next&lt;&#x2F;em&gt; occurrence of the value at position $(i,j)$. If you are already at the last occurrence, go to the first one. By &lt;em&gt;next&lt;&#x2F;em&gt; , we mean the following occurrence, as if the columns were stacked on each other. Let’s see how this works in the example circuit. Recall $V$ is&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;L&lt;&#x2F;th&gt;&lt;th&gt;R&lt;&#x2F;th&gt;&lt;th&gt;O&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;The permutation in this case is the map $\sigma((0,0)) = (2,1)$, $\sigma((0,1)) = (0, 3)$, $\sigma((0,2)) = (0,2)$, $\sigma((0,3)) = (0,1)$, $\sigma((2,1)) = (0,0)$, $\sigma((3,1)) = (2,2)$, $\sigma((2,2)) = (3,1)$. The positions with &lt;code&gt;-&lt;&#x2F;code&gt; values don’t matter right now.&lt;&#x2F;p&gt;
&lt;p&gt;It’s not hard to see that condition (2) is equivalent to: for all $(i,j)\in I$, $T_{i,j} = T_{\sigma((i,j))}$.&lt;&#x2F;p&gt;
&lt;p&gt;A little less obvious is that this condition is, in turn, equivalent to checking whether the following sets $A$ and $B$ are equal&lt;br &#x2F;&gt;
$$A = \{((i,j), T_{i,j}): (i,j) \in I\}$$&lt;br &#x2F;&gt;
$$B = \{(\sigma((i,j)), T_{i,j}): (i,j) \in I\}.$$&lt;br &#x2F;&gt;
The proof of this equivalence is straightforward. Give it a try!&lt;&#x2F;p&gt;
&lt;p&gt;In our example, the sets in question are respectively&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
\begin{aligned}&lt;br &#x2F;&gt;
\{((0,0), T_{ 0,0 }), ((0,1), T_{ 0,1 }), ((0,2), T_{ 0,2 }), ((0,3), T_{ 0,3 }), \newline ((2,1), T_{ 2,1 }), ((3,1), T_{ 3,1 }), ((2,2), T_{ 2,2 })\}&lt;br &#x2F;&gt;
\end{aligned}&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
and&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
\begin{aligned}&lt;br &#x2F;&gt;
\{((2,1), T_{0,0}), ((0,3), T_{0,1}), ((0,2), T_{0,2}), ((0,1), T_{0,3}), \newline ((0,0), T_{2,1}), ((2,2), T_{3,1}), ((3,1), T_{2,2}) \}, \end{aligned}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;You can check these sets coincide by inspection. Recall our trace matrix $T$ is&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;A&lt;&#x2F;th&gt;&lt;th&gt;B&lt;&#x2F;th&gt;&lt;th&gt;C&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Checking the equality of these sets can be reduced to polynomial equations. It is a very nice method that PLONK uses. To understand it better, let’s start with a more straightforward case.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;equality-of-sets&quot;&gt;Equality of sets&lt;&#x2F;h4&gt;
&lt;p&gt;Suppose we have two sets $A = \{a_0, a_1 \}$ $B = \{b_0, b_1\}$ of two field elements in $\mathbb{F}$. And we are interested in checking whether they are equal.&lt;&#x2F;p&gt;
&lt;p&gt;One thing we could do is compute $a_0a_1$ and $b_0b_1$ and compare them. If the sets are equal, then those elements are necessarily identical.&lt;&#x2F;p&gt;
&lt;p&gt;But the converse is not true. For example the sets $A = \{4, 15\}$ and $B = \{6, 10\}$ both have $60$ as the result of the product of their elements. But they are not equal. So this is not good for checking equality.&lt;&#x2F;p&gt;
&lt;p&gt;Polynomials come to the rescue here. What we can do instead is consider the following sets &lt;em&gt;of polynomials&lt;&#x2F;em&gt; $A’ = \{a_0 + X, a_1 + X\}$, $B’ = \{b_0 + X, b_1 + X \}$. Sets $A$ and $B$ are equal if and only if sets $A’$, and $B’$ are equal. This is because the equality of polynomials boils down to the equality of their coefficients. But the difference between $A’$ and $B’$ is that the approach of multiplying the elements works now. That is, $A’$ and $B’$ are equal if and only if $(a_0 + X)(a_1 + X) = (b_0 + X)(b_1 + X)$. This is not entirely evident but follows from a property that polynomials have called &lt;em&gt;unique factorization&lt;&#x2F;em&gt;. Here the important fact is that linear polynomials act like prime factors. Anyway, you can take that for granted. The last part of this trick is using the Schwartz-Zippel lemma and returning to the land of field elements. That means, if for some random element $\gamma$ we have $(a_0 + \gamma)(a_1 + \gamma) = (b_0 + \gamma)(b_1 + \gamma)$, then with overwhelming probability the equality $(a_0 + X)(a_1 + X) = (b_0 + X)(b_1 + X)$ holds.&lt;&#x2F;p&gt;
&lt;p&gt;Putting this altogether, if for some random element $\gamma$ we have $(a_0 + \gamma)(a_1 + \gamma) = (b_0 + \gamma)(b_1 + \gamma)$, then the sets $A$ and $B$ are equal. Of course, this also holds for sets with more than two elements. Let’s write that down.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Fact:&lt;&#x2F;em&gt; Let $A = \{a_0, \dots, a_{k-1} \}$ and $B = \{b_0, \dots, b_{k-1} \}$ be sets of field elements. If, for some random $\gamma$ the following equality holds&lt;br &#x2F;&gt;
$$\prod_{i = 0}^{ k - 1}(a_i + \gamma) = \prod_{i = 0}^{ k - 1 }(b_i + \gamma),$$&lt;br &#x2F;&gt;
then with overwhelming probability $A$ is equal to $B$.&lt;&#x2F;p&gt;
&lt;p&gt;And here comes the trick that reduces this check to polynomial equations. Let&lt;br &#x2F;&gt;
$H$ be a domain of the form $\{1, \omega, \dots, \omega^{k - 1} \}$ for some primitive $k$-th root of unity $\omega$. Let $f$ and $g$ be the polynomials that interpolate the following values at $H$.&lt;br &#x2F;&gt;
$$(a_0 + \gamma, \dots, a_{k-1} + \gamma),$$&lt;br &#x2F;&gt;
$$(b_0 + \gamma, \dots, b_{k-1} + \gamma),$$&lt;&#x2F;p&gt;
&lt;p&gt;Then $\prod_{i = 0}^{ k - 1}(a_i + \gamma)$ equals $\prod_{ i = 0}^{ k - 1}(b_i + \gamma)$ if and only if there exists a polynomial $Z$ such that&lt;br &#x2F;&gt;
$$Z(\omega^0) = 1$$&lt;br &#x2F;&gt;
$$Z(h)f(h) = g(h)Z(\omega h)$$&lt;br &#x2F;&gt;
for all $h\in H$.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s see why. Suppose that $\prod_{i = 0}^{ k - 1}(a_i + \gamma)$ equals $\prod_{i = 0}^{ k - 1}(b_i + \gamma)$. Construct $Z$ as the polynomial that interpolates the following values $$(1, \frac{a_0 + \gamma}{b_0 + \gamma}, \frac{(a_0 + \gamma)(a_1 + \gamma)}{(b_0 + \gamma)(b_1 + \gamma)}, \dots, \prod_{i=0}^{k-2} \frac{a_i + \gamma}{b_i + \gamma}),$$&lt;br &#x2F;&gt;
in the same domain as $f$ and $g$. That works. Conversely, suppose such a polynomial $Z$ exists. By evaluating the equation $Z(X)f(X) = g(X)Z(\omega X)$ at $1, \omega, \dots, \omega^{k-2}$ and using recursion we get that $Z(\omega^{k-1}) = \prod_{i = 0}^{k - 2}(a_i + \gamma)&#x2F;\prod_{i = 0}^{k - 2}(b_i + \gamma)$. Moreover, evaluating it at $\omega^{k-1}$ we obtain that $$Z(\omega^{k - 1})\frac{f(\omega^{k - 1} )}{g(\omega^{ k - 1 })} = Z(\omega^k ) = Z(w^0 ) = 1.$$&lt;br &#x2F;&gt;
The second equality holds because $\omega^k = \omega^0$ since it is a $k$-th root of unity. Expanding with the values of $f, g$ and $Z$ one obtains that $\prod_{i = 0}^{k - 1}(a_i + \gamma)&#x2F;\prod_{i = 0}^{k - 1}(b_i + \gamma)$ equals $1$. Which is what we wanted.&lt;&#x2F;p&gt;
&lt;p&gt;In summary. We proved the following:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Fact:&lt;&#x2F;em&gt; Let $A = \{a_0, \dots, a_{k-1} \}$ and $B = \{b_0, \dots, b_{k-1} \}$ be sets of field elements. Let $\gamma$ be a random field element. Let $\omega$ be a primitive $k$-th root of unity and $H = \{1, \omega, \omega^2, \dots, \omega^{k-1} \}$. Let $f$ and $g$ be respectively the polynomials that interpolate the values $\{a_0 + \gamma, \dots, a_{k-1} + \gamma \}$ and $\{ b_0 + \gamma, \dots, b_{k-1} + \gamma \}$ at $H$. If there exists a polynomial $Z$ such that&lt;br &#x2F;&gt;
$$Z(\omega^0 ) = 1$$&lt;br &#x2F;&gt;
$$Z(X)f(X) = g(X)Z(\omega X)$$&lt;br &#x2F;&gt;
for all $h\in H$, then with overwhelming probability the sets $A$ and $B$ are equal.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;sets-of-tuples&quot;&gt;Sets of tuples&lt;&#x2F;h4&gt;
&lt;p&gt;In the previous section, we saw how to check whether two sets of field elements are equal using polynomial equations. To use it in our context, we need to extend it to groups of tuples of field elements. This is pretty straightforward.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s start with the easy case. Let $A = \{(a_0, a_1), (a_2, a_3) \}$ and $B = \{(b_0, b_1), (b_2, b_3)\}$ be two sets of pairs of field elements. That is $a_i, b_i \in \mathbb{F}$ for all $i$. The trick is very similar to the previous section.&lt;br &#x2F;&gt;
$$A’ = \{a_0 + a_1 Y + X, a_2 + a_3 Y + X \}$$&lt;br &#x2F;&gt;
$$B’ = \{b_0 + b_1 Y + X, b_2 + b_3 Y + X \}$$&lt;&#x2F;p&gt;
&lt;p&gt;Just as before, by looking at coefficients, we can see that the sets $A$ and $B$ are equal if and only if $A’$ and $B’$ are equal.&lt;br &#x2F;&gt;
And notice that these are sets of polynomials: we got rid of the tuples! Now, the situation is very similar to the previous section. We have that $A’$ and $B’$ are equal if and only if the product of their elements coincides. This is also true because polynomials in two variables are a unique factorization domain. So as before, we can use the Schwartz-Zippel lemma. Precisely, if for random $\beta, \gamma$, the elements&lt;br &#x2F;&gt;
$$(a_0 + \beta a_1 + \gamma)(a_2 + \beta a_3 + \gamma),$$&lt;br &#x2F;&gt;
and&lt;br &#x2F;&gt;
$$(b_0 + \beta b_1 + \gamma)(b_2 + \beta b_3 + \gamma)$$&lt;br &#x2F;&gt;
coincide, then $A$ and $B$ are equal with overwhelming probability.&lt;&#x2F;p&gt;
&lt;p&gt;Here is the statement for sets of more than two pairs of field elements.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Fact:&lt;&#x2F;em&gt; Let $A = \{\bar a_0, \dots, \bar a_{k-1} \}$ and $B = \{\bar b_0, \dots, \bar b_{k-1} \}$ be sets of pairs of field elements. So that $\bar a_i = (a_{i,0}, a_{i,1})$ and the same for $\bar b_i$. Let $\beta, \gamma$ be random field elements. Let $\omega$ be a $k$-th root of unity and $H = \{1, \omega, \omega^2, \dots, \omega^{k-1} \}$. Let $f$ and $g$ be, respectively, the polynomials that interpolate the values&lt;br &#x2F;&gt;
$$\{a_{i,0} + a_{i,1}\beta + \gamma, \dots, a_{k-1,0} + a_{k-1,1}\beta + \gamma\},$$&lt;br &#x2F;&gt;
and&lt;br &#x2F;&gt;
$$\{b_{i,0} + b_{i,1}\beta + \gamma, \dots, b_{k-1,0} + b_{k-1,1}\beta + \gamma\},$$&lt;br &#x2F;&gt;
at $H$. If there exists a polynomial $Z$ such that&lt;br &#x2F;&gt;
$$Z(\omega^0 ) = 1$$&lt;br &#x2F;&gt;
$$Z(X)f(X) = g(X)Z(\omega X)$$&lt;br &#x2F;&gt;
for all $h\in H$, then with overwhelming probability the sets $A$ and $B$ are equal.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;going-back-to-our-case&quot;&gt;Going back to our case&lt;&#x2F;h4&gt;
&lt;p&gt;Recall we want to rephrase condition (b) in terms of polynomials. We have already seen that condition (b) is equivalent to $A$ and $B$ being equal, where&lt;br &#x2F;&gt;
$$A = \{((i,j), T_{i,j}): (i,j) \in I\}$$&lt;br &#x2F;&gt;
and&lt;br &#x2F;&gt;
$$B = \{(\sigma((i,j)), T_{i,j}): (i,j) \in I\}.$$&lt;&#x2F;p&gt;
&lt;p&gt;We cannot directly use the facts of the previous sections because our sets are not sets of field elements, nor are they sets of pairs of field elements. They are sets of pairs with some indexes $(i,j)$ in the first coordinate and a field element $v$ in the second one. So the solution is to convert them to sets of pairs of field elements and apply the result of the previous section. How do we map an element of the form $((i,j), v)$ to something of the form $(a_0, a_1)$ with $ a_0 $ and $ a_1 $ field elements? The second coordinate is trivial: we can leave $v$ as it is and take $a_1 = v$. There are multiple ways for the indexes pair $(i,j)$. The important thing to achieve here is that different pairs get mapped to different field elements. Recall that $i$ ranges from $0$ to $N-1$ and $j$ ranges from $0$ to $2$. One way is to take a $3N$-th primitive root of unity $\eta$ and define $a_0 = \eta^{3i + j}$. Putting it all together, we are mapping the pair $((i,j), v)$ to the pair $(\eta^{3i + j}, v)$, which is a pair of field elements. Now we can consider the sets&lt;br &#x2F;&gt;
$$A = \{(\eta^{3i + j}, T_{i,j}): (i,j) \in I\}$$&lt;br &#x2F;&gt;
and&lt;br &#x2F;&gt;
$$B = \{(\eta^{3k + l}, T_{i,j}): (i,j) \in I, \sigma((i,j)) = (k, l)\}.$$&lt;br &#x2F;&gt;
We have that condition (b) is equivalent to $A$ and $B$ being equal.&lt;&#x2F;p&gt;
&lt;p&gt;Applying the method of the previous section to these sets, we obtain the following.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Fact:&lt;&#x2F;em&gt; Let $\eta$ be a $3N$-th root of unity and $\beta$ and $\gamma$ random field elements. Let $D = \{1, \eta, \eta^2, \dots, \eta^{3N-1}\}$. Let $f$ and $g$ be the polynomials that interpolate, respectively, the following values at $D$:&lt;br &#x2F;&gt;
$$\{T_{i,j} + \eta^{3i + j}\beta + \gamma: (i,j) \in I\},$$&lt;br &#x2F;&gt;
and&lt;br &#x2F;&gt;
$$\{T_{i,j} + \eta^{3k + l}\beta + \gamma: (i,j) \in I, \sigma((i,j)) = (k,l)\},$$&lt;br &#x2F;&gt;
Suppose there exists a polynomial $Z$ such that&lt;br &#x2F;&gt;
$$Z(\eta^0 ) = 1$$&lt;br &#x2F;&gt;
$$Z(d)f(d) = g(d)Z(\eta d),$$&lt;br &#x2F;&gt;
for all $h\in D$.&lt;br &#x2F;&gt;
Then the sets $A = \{((i,j), T_{i,j}): (i,j) \in I \}$ and $B = \{(\sigma((i,j)), T_{i,j}): (i,j) \in I\}$ are equal with overwhelming probability.&lt;&#x2F;p&gt;
&lt;p&gt;One last-minute definition. Notice that $\omega=\eta^3$ is a primitive $N$-th root of unity. Let $H = \{1, \omega, \omega^2, \dots, \omega^{N-1}\}$.&lt;&#x2F;p&gt;
&lt;p&gt;Define $S_{\sigma 1}$ to be the interpolation at $H$ of&lt;br &#x2F;&gt;
$$\{\eta^{3k + l}: (i,0) \in I, \sigma((i,0)) = (k,l)\},$$&lt;br &#x2F;&gt;
Similarly define $S_{\sigma 2}$ and $S_{\sigma 3}$ to be the interpolation at $H$ of the sets of values&lt;br &#x2F;&gt;
$$\{\eta^{3k + l}: (i,1) \in I, \sigma((i,1)) = (k,l)\},$$&lt;br &#x2F;&gt;
$$\{\eta^{3k + l}: (i,2) \in I, \sigma((i,2)) = (k,l)\},$$&lt;br &#x2F;&gt;
These will be useful during the protocol to work with such polynomials $Z$ and the above equations.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;a-more-compact-form&quot;&gt;A more compact form&lt;&#x2F;h4&gt;
&lt;p&gt;The last fact is equivalent to the following. There’s no new idea here, just a more compact form of the same thing that allows the polynomial $Z$ to be of degree at most $N$.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Fact:&lt;&#x2F;em&gt; Let $\omega$ be a $N$-th root of unity. Let $H = \{1, \omega, \omega^2, \dots, \omega^{N-1}\}$. Let $k_1$ and $k_2$ be two field elements such that $\omega^i \neq \omega^jk_1 \neq \omega^l k_2$ for all $i,j,l$. Let $\beta$ and $\gamma$ be random field elements. Let $f$ and $g$ be the polynomials that interpolate, respectively, the following values at $H$:&lt;br &#x2F;&gt;
$$\{(T_{0,j} + \omega^{i} \beta + \gamma) (T_{1,j} + \omega^{i} k_1 \beta + \gamma) (T_{2,j} + \omega^{i} k_2\beta + \gamma): 0\leq i&amp;lt;N\},$$&lt;br &#x2F;&gt;
and&lt;br &#x2F;&gt;
$$\{(T_{0,j} + S_{\sigma1}(\omega^i)\beta + \gamma)(T_{0,j} + S_{\sigma2}(\omega^i)\beta + \gamma)(T_{0,j} + S_{\sigma3}(\omega^i)\beta + \gamma): 0\leq i&amp;lt;N\},$$&lt;br &#x2F;&gt;
Suppose there exists a polynomial $Z$ such that&lt;br &#x2F;&gt;
$$Z(\omega^0) = 1$$&lt;br &#x2F;&gt;
$$Z(d)f(d) = g(d)Z(\omega d),$$&lt;br &#x2F;&gt;
for all $h\in D$.&lt;br &#x2F;&gt;
Then the sets $A = \{((i,j), T_{i,j}): (i,j) \in I\}$ and $B = \{(\sigma((i,j)), T_{i,j}): (i,j) \in I\}$ are equal with overwhelming probability.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;common-preprocessed-input&quot;&gt;Common preprocessed input&lt;&#x2F;h2&gt;
&lt;p&gt;We have arrived at the eight polynomials we mentioned at the beginning:&lt;br &#x2F;&gt;
$$q_L, q_R, q_M, q_O, q_C, S_{\sigma 1}, S_{\sigma 2}, S_{\sigma 3}.$$&lt;&#x2F;p&gt;
&lt;p&gt;These are what’s called the &lt;em&gt;common preprocessed input&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;wrapping-up-the-whole-thing&quot;&gt;Wrapping up the whole thing&lt;&#x2F;h2&gt;
&lt;p&gt;Let’s wrap up what we have so far. We started with a program. It can be seen as a sequence of gates with left, right, and output values. That’s called a circuit. From this, two matrices, $Q$, and $V$, can be computed to capture the gates logic.&lt;&#x2F;p&gt;
&lt;p&gt;Executing the circuit leaves us with matrices $T$ and $PI$, called the trace matrix and the public input matrix, respectively. Everything we want to prove boils down to verifying that such matrices are valid. And we have the following result.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Fact:&lt;&#x2F;strong&gt; Let $T$ be a $N \times 3$ matrix with columns $A, B, C$ and $PI$ a $N \times 1$ matrix. They correspond to a valid execution instance with public input given by $PI$ if and only if&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. for all $i$ the following equality holds $$A_i Q_{Li} + B_i Q_{Ri} + A_i B_i Q_{Mi} + C_i Q_{Oi} + Q_{Ci} + PI_i = 0,$$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. for all $i,j,k,l$ such that $V_{i,j} = V_{k,l}$ we have $T_{i,j} = T_{k,l}$, c) $PI_i = 0$ for all $i&amp;gt;n$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then we constructed polynomials $q_L, q_R, q_M, q_O, q_C, S_{\sigma1},S_{\sigma2}, S_{\sigma3}$, $f$, $g$ from the matrices $Q$ and $V$. They result from interpolating at a domain $H = \{1, \omega, \omega^2, \dots, \omega^{N-1}\}$ for some $N$-th primitive root of unity and a few random values. We also constructed polynomials $a,b,c, pi$ from the matrices $T$ and $PI$. The above fact can be reformulated in terms of polynomial equations as follows.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Fact:&lt;&#x2F;strong&gt; Let $z_H = X^N - 1$. Let $T$ be a $N \times 3$ matrix with columns $A, B, C$ and $PI$ a $N \times 1$ matrix. They correspond to a valid execution instance with public input given by $PI$ if and only if&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. There is a polynomial $t_1$ such that the following equality holds $$a q_L + b q_R + a b q_M + c q_O + q_C + pi = z_H t_1,$$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. There are polynomials $t_2, t_3$, $z$ such that $zf - gz&amp;#39; = z_H t_2$ and $(z-1)L_1 = z_H t_3$, where $z&amp;#39;(X) = z(X\omega)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You might be wondering where the polynomials $t_i$ came from. Recall that for a polynomial $F$, we have $F(h) = 0$ for all $h \in H$ if and only if $F = z_H t$ for some polynomial $t$.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, both conditions (a) and (b) are equivalent to a single equation (c) if we let more randomness come into play. This is:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Let $\alpha$ be a random field element. There is a polynomial $t$ such that  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\begin{aligned}&lt;br &#x2F;&gt;
z_H t &amp;amp;= a q_L + b q_R + a b q_M + c q_O + q_C + pi \newline&lt;br &#x2F;&gt;
&amp;amp;= \alpha(gz’ - fz) \newline&lt;br &#x2F;&gt;
&amp;amp;= \alpha^2(z-1)L_1 \newline&lt;br &#x2F;&gt;
\end{aligned}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;This last step is not obvious. You can check the paper to see the proof. Anyway, this is the equation you’ll recognize below in the protocol description.&lt;&#x2F;p&gt;
&lt;p&gt;Randomness is a delicate matter, and an essential part of the protocol is where it comes from, who chooses it, and when they choose it. We are now ready to jump into the protocol.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;protocol&quot;&gt;Protocol&lt;&#x2F;h2&gt;
&lt;h2 id=&quot;details-and-tricks&quot;&gt;Details and tricks&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;polynomial-commitment-scheme&quot;&gt;Polynomial commitment scheme&lt;&#x2F;h3&gt;
&lt;p&gt;A polynomial commitment scheme (PCS) is a cryptographic tool that allows one party to commit to a polynomial and later prove some properties of that polynomial.&lt;br &#x2F;&gt;
This commitment polynomial hides the original polynomial’s coefficients and can be publicly shared without revealing any information about the original polynomial.&lt;br &#x2F;&gt;
Later, the party can use the commitment to prove specific properties of the polynomial, such as that it satisfies certain constraints or evaluates to a particular value at a specific point.&lt;&#x2F;p&gt;
&lt;p&gt;For the moment, we only need the following about it:&lt;&#x2F;p&gt;
&lt;p&gt;It consists of a finite group $\mathbb{G}$ and the following algorithms:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Commit($f$)** : This algorithm takes a polynomial $f$ and produces an element of the group $\mathbb{G}$. It is called the commitment of $f$ and is denoted by $[f]$. It is homomorphic in the sense that $[f + g] = [f] + [g]$. The former sum is the addition of polynomials. The latter is the addition operation in the group $\mathbb{G}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Open($f$,$\zeta$)** : It takes a polynomial $f$ and a field element $\zeta$ and produces an element $\pi$ of the group $\mathbb{G}$. This element is an opening proof for $f(\zeta)$. It is the proof that $f$ evaluated at $\zeta$ gives $f(\zeta)$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * **Verify($[f]$, $\pi$, $\zeta$, $y$)** : It takes group elements $[f]$ and $\pi$, and also field elements $\zeta$ and $y$. With overwhelming probability, it outputs _Accept_ if $f(z)=y$ and _Reject_ otherwise.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;By changing the PCS, you can get different versions of PLONK, each with its advantages and disadvantages (such as shorter proofs, plausibly post-quantum secure, lack of trusted setup, etc).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;blindings&quot;&gt;Blindings&lt;&#x2F;h3&gt;
&lt;p&gt;As you will see in the protocol, the prover reveals the value taken by a bunch of the polynomials at a random $\zeta$. For the protocol to be &lt;em&gt;Honest Verifier Zero Knowledge&lt;&#x2F;em&gt; , these polynomials must be &lt;em&gt;blinded&lt;&#x2F;em&gt;. This process makes the values of these polynomials at $\zeta$ seemingly random by forcing them to be of a certain degree. Here’s how it works.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s take, for example, the polynomial $a$ the prover constructs. This results from interpolating the first column of the trace matrix $T$ at the domain $H$.&lt;br &#x2F;&gt;
This matrix has all of the left operands of all the gates. The prover wishes to keep them secret.&lt;br &#x2F;&gt;
Say the trace matrix $T$ has $N$ rows, and so $H$ is $\{1, \omega,\omega^2, \dots, \omega^{N-1} \}$. The invariant that the prover cannot violate is that $a_{\text{blinded}}(\omega^i)$ must take the value $T_{0, i}$, for all $i$. This is what the interpolation polynomial $a$ satisfies and is the unique such polynomial of degree at most $N-1$ with such property. But for higher degrees, there are many such polynomials.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;em&gt;blinding&lt;&#x2F;em&gt; process takes $a$ and a desired degree $M\geq N$ and produces a new polynomial $a_{\text{blinded}}$ of degree exactly $M$. This new polynomial satisfies that $a_{\text{blinded}}(\omega^i) = a(\omega^i)$ for all $i$. But outside $H$ differs from $a$.&lt;&#x2F;p&gt;
&lt;p&gt;This may seem hard, but it’s very simple. Let $z_H$ be the polynomial $z_H = X^N - 1$. If $M=N+k$, with $k\geq 0$, then sample random values $b_0, \dots, b_k$ and define&lt;br &#x2F;&gt;
$$ a_{\text{blinded}} := (b_0 + b_1 X + \cdots + b_k X^k)z_H + a $$&lt;&#x2F;p&gt;
&lt;p&gt;This does the job because $z_H(\omega^i)=0$ for all $i$. Therefore the added term vanishes at $H$ and leaves the values of $a$ at $H$ unchanged.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;linearization-trick&quot;&gt;Linearization trick&lt;&#x2F;h3&gt;
&lt;p&gt;This is an optimization in PLONK to reduce the number of checks of the verifier.&lt;&#x2F;p&gt;
&lt;p&gt;One of the primary checks in PLONK boils down to checking that $p(\zeta) = z_H(\zeta) t(\zeta)$, with $p$ some polynomial that looks like $p = a q_L + b q_R + ab q_M + \cdots$, and so on. In particular, the verifier needs to get the value $p(\zeta)$ from somewhere.&lt;&#x2F;p&gt;
&lt;p&gt;For the sake of simplicity, in this section, assume $p$ is exactly $a q_L + bq_R$. Secret to the prover here is only $a, b$. The polynomials $q_L$ and $q_R$ are also known to the verifier. The verifier will already have the commitments $[a], [b], [q_L]$ and $[q_R]$. So the prover could send just $a(\zeta)$, $b(\zeta)$ along with their opening proofs and let the verifier compute by himself $q_L(\zeta)$ and $q_R(\zeta)$. Then with all these values the verifier could compute $p(\zeta) = a(\zeta)q_L(\zeta) + b(\zeta)q_R(\zeta)$. And also use his commitments to validate the opening proofs of $a(\zeta)$ and $b(\zeta)$.&lt;&#x2F;p&gt;
&lt;p&gt;This has the problem that computing $q_L(\zeta)$ and $q_R(\zeta)$ is expensive. Instead, the prover can save the verifier this by sending $q_L(\zeta), q_R(\zeta)$ along with opening proofs. Since the verifier will have the commitments $[q_L]$ and $[q_R]$ beforehand, he can check that the prover is not cheating and cheaply be convinced that the claimed values are $q_L(\zeta)$ and $q_R(\zeta)$. This is much better. It involves the check of four opening proofs and the computation of $p(\zeta)$ from the values received from the prover. But it can be further improved as follows.&lt;&#x2F;p&gt;
&lt;p&gt;As before, the prover sends $a(\zeta), b(\zeta)$ along with their opening proofs. She constructs the polynomial $f = a(\zeta)q_L + b(\zeta)q_R$. She sends the value $f(\zeta)$ along with an opening proof of it. Notice that the value of $f(\zeta)$ is exactly $p(\zeta)$. The verifier can compute by himself $[f]$ as $a(\zeta)[q_L] + b(\zeta)[q_R]$. The verifier has everything to check all three openings and is convinced that the claimed value $f(\zeta)$ is true, and this value is $p(\zeta)$. So this means no more work for the verifier. And the whole thing got reduced to three openings.&lt;&#x2F;p&gt;
&lt;p&gt;This is called the linearization trick. The polynomial $f$ is called the &lt;em&gt;linearization&lt;&#x2F;em&gt; of $p$.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;setup&quot;&gt;Setup&lt;&#x2F;h2&gt;
&lt;p&gt;There’s a one-time setup phase to compute some values common to any execution and proof of the particular circuit. Precisely, the following commitments are calculated and published.&lt;br &#x2F;&gt;
$$\left[ q_L \right] , \left[ q_R \right] , \left[ q_M \right] , \left[ q_O \right] , \left[ q_C \right] , \left[ S_{ \sigma 1} \right] , \left[ S_{ \sigma 2} \right] , \left[ S_{ \sigma 3} \right]$$&lt;&#x2F;p&gt;
&lt;h2 id=&quot;proving-algorithm&quot;&gt;Proving algorithm&lt;&#x2F;h2&gt;
&lt;p&gt;Next, we describe the proving algorithm for a program of size $N$, that includes public input. Let $\omega$ be a primitive $N$-th root of unity. Let $H = \{1, \omega, \omega^2, \dots, \omega^{N-1} \}$. Define $Z_H := X^N - 1$.&lt;&#x2F;p&gt;
&lt;p&gt;Assume the eight polynomials of common preprocessed input are already given.&lt;&#x2F;p&gt;
&lt;p&gt;The prover computes the trace matrix $T$ as described in the first sections. That means the first rows correspond to the public inputs. It should be a $N \times 3$ matrix.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;round-1&quot;&gt;Round 1&lt;&#x2F;h3&gt;
&lt;p&gt;Add to the transcript the following:&lt;br &#x2F;&gt;
$$[S_{\sigma1}] , [S_{\sigma2}] , [S_{\sigma3} ] , [q_L] , [q_R] , [q_M] , [q_O] , [q_C]$$&lt;&#x2F;p&gt;
&lt;p&gt;Compute polynomials $a’,b’,c’$ as the interpolation polynomials of the columns of $T$ at the domain $H$.&lt;br &#x2F;&gt;
Sample random $b_1, b_2, b_3, b_4, b_5, b_6$&lt;br &#x2F;&gt;
Let&lt;&#x2F;p&gt;
&lt;p&gt;$a := (b_1X + b_2)Z_H + a’$&lt;&#x2F;p&gt;
&lt;p&gt;$b := (b_3X + b_4)Z_H + b’$&lt;&#x2F;p&gt;
&lt;p&gt;$c := (b_5X + b_6)Z_H + c’$&lt;&#x2F;p&gt;
&lt;p&gt;Compute $[a], [b], [c]$ and add them to the transcript.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;round-2&quot;&gt;Round 2&lt;&#x2F;h3&gt;
&lt;p&gt;Sample $\beta, \gamma$ from the transcript.&lt;&#x2F;p&gt;
&lt;p&gt;Let $z_0 = 1$ and define recursively for $0\leq k &amp;lt; N$.&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
z_{k+1} = z_k \frac{(a_k + \beta\omega^k + \gamma)(b_k + \beta\omega^k k_1 + \gamma)(c_k + \beta\omega^k k_2 + \gamma)}{(a_k + \beta S_{\sigma1}(\omega^k) + \gamma)(b_k + \beta S_{\sigma2}(\omega^k) + \gamma)(c_k + \beta S_{\sigma3}(\omega^k) + \gamma)}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;Compute the polynomial $z’$ as the interpolation polynomial at the domain $H$ of the values $(z_0, \dots, z_{N-1})$.&lt;&#x2F;p&gt;
&lt;p&gt;Sample random values $b_7, b_8, b_9$ and let $z = (b_7X^2 + b_8X + b_9)Z_H + z’$.&lt;&#x2F;p&gt;
&lt;p&gt;Compute $[z]$ and add it to the transcript.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;round-3&quot;&gt;Round 3&lt;&#x2F;h3&gt;
&lt;p&gt;Sample $\alpha$ from the transcript.&lt;&#x2F;p&gt;
&lt;p&gt;Let $pi$ be the interpolation of the public input matrix $PI$ at the domain $H$.&lt;&#x2F;p&gt;
&lt;p&gt;Let&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\begin{aligned}&lt;br &#x2F;&gt;
p_1 &amp;amp;= aq_L + bq_R + abq_M + cq_O + q_C + pi \newline&lt;br &#x2F;&gt;
p_2 &amp;amp;= (a + \beta X + \gamma)(b + \beta k_1 X + \gamma)(c + \beta k_2 X + \gamma)z - (a + \beta S_{\sigma1} + \gamma)(b + \beta S_{\sigma2} + \gamma)(c + \beta S_{\sigma3} + \gamma)z(\omega X)\newline&lt;br &#x2F;&gt;
p_3 &amp;amp;= (z - 1)L_1&lt;br &#x2F;&gt;
\end{aligned}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;and define $p = p_1 + \alpha p_2 + \alpha^2 p_3$. Compute $t$ such that $p = t Z_H$. Write $t = t_{lo}’ + X^{N+2} t_{mid}’ + X^{2(N+2)} t_{hi}’$ with $t_{lo} ’, t_{mid} ’$ and $t_{hi} ’$ polynomials of degree at most $N+1$.&lt;&#x2F;p&gt;
&lt;p&gt;Sample random $b_{10}, b_{11}$ and define&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\begin{aligned}&lt;br &#x2F;&gt;
t_{lo} &amp;amp;= t_{lo}’ + b_{10}X^{N+2} \newline&lt;br &#x2F;&gt;
t_{mid} &amp;amp;= t_{mid}’ - b_{10} + b_{11}X^{N+2} \newline&lt;br &#x2F;&gt;
t_{hi} &amp;amp;= t_{hi}’ - b_{11}&lt;br &#x2F;&gt;
\end{aligned}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;Compute $[t_{lo}] , [t_{mid} ] , [t_{hi} ]$ and add them to the transcript.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;round-4&quot;&gt;Round 4&lt;&#x2F;h3&gt;
&lt;p&gt;Sample $\zeta$ from the transcript.&lt;&#x2F;p&gt;
&lt;p&gt;Compute $\bar a = a(\zeta), \bar b = b(\zeta), \bar c = c(\zeta), \bar s_{\sigma1} = S_{\sigma1}(\zeta), \bar s_{\sigma2} = S_{\sigma2}(\zeta), \bar z_\omega = z(\zeta\omega)$ and add them to the transcript.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;round-5&quot;&gt;Round 5&lt;&#x2F;h3&gt;
&lt;p&gt;Sample $\upsilon$ from the transcript.&lt;&#x2F;p&gt;
&lt;p&gt;Let&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\begin{aligned}&lt;br &#x2F;&gt;
\hat p_{nc1} &amp;amp;= \bar aq_L + \bar bq_R + \bar a\bar bq_M + \bar cq_O + q_C \newline&lt;br &#x2F;&gt;
\hat p_{nc2} &amp;amp;=(\bar a + \beta\zeta + \gamma)(\bar b + \beta k_1\zeta + \gamma)(\bar c + \beta k_2\zeta + \gamma)z - (\bar a + \beta \bar s_{\sigma1} + \gamma)(\bar b + \beta \bar s_{\sigma2} + \gamma)\beta \bar z_\omega S_{\sigma3} \newline&lt;br &#x2F;&gt;
\hat p_{nc3} &amp;amp;= L_1(\zeta) z&lt;br &#x2F;&gt;
\end{aligned}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;Define&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\begin{aligned}&lt;br &#x2F;&gt;
p_{nc} &amp;amp;= p_{nc1} + \alpha p_{nc2} + \alpha^2 p_{nc3} \newline&lt;br &#x2F;&gt;
t_{\text{partial}} &amp;amp;= t_{lo} + \zeta^{N+2}t_{mid} + \zeta^{2(N+2)}t_{hi}&lt;br &#x2F;&gt;
\end{aligned}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;The subscript $nc$ stands for “nonconstant,” as it is the part of the linearization of $p$ with nonconstant factors. The subscript “partial” indicates that it is a partial evaluation of $t$ at $\zeta$. Partial means that only some power of $X$ is replaced by the powers of $\zeta$. So in particular $t_{\text{partial}}(\zeta) = t(\zeta)$.&lt;&#x2F;p&gt;
&lt;p&gt;Let $\pi_{\text{batch}}$ be the opening proof at $\zeta$ of the polynomial $f_{\text{batch}}$ defined as&lt;br &#x2F;&gt;
$$t_{\text{partial}} +\upsilon p_{nc} + \upsilon^2 a + \upsilon^3 b + \upsilon^4 c + \upsilon^5 S_{\sigma1} + \upsilon^6 S_{\sigma2}$$&lt;&#x2F;p&gt;
&lt;p&gt;Let $\pi_{\text{single}}$ be the opening proof at $\zeta\omega$ of the polynomial $z$.&lt;&#x2F;p&gt;
&lt;p&gt;Compute $\bar p_{nc} := p_{nc}(\zeta)$ and $\bar t = t(\zeta)$.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;proof&quot;&gt;Proof&lt;&#x2F;h3&gt;
&lt;p&gt;The proof is:&lt;br &#x2F;&gt;
$$[a], [b], [c], [z], [t_{lo}], [t_{mid}], [t_{hi}], \bar a, \bar b, \bar c, \bar s_{\sigma1}, \bar s_{\sigma 2}, \bar z_\omega, \pi_{\text{batch}}, \pi_{\text{single}}, \bar p_{nc}, \bar t$$&lt;&#x2F;p&gt;
&lt;h2 id=&quot;verification-algorithm&quot;&gt;Verification algorithm&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;transcript-initialization&quot;&gt;Transcript initialization&lt;&#x2F;h3&gt;
&lt;p&gt;The first step is to initialize the transcript the same way the prover did, adding to it the following elements.&lt;br &#x2F;&gt;
$$[S_{\sigma1} ], [S_{\sigma2} ], [S_{\sigma3} ], [q_L], [q_R], [q_M], [q_O], [q_C]$$&lt;&#x2F;p&gt;
&lt;h3 id=&quot;extraction-of-values-and-commitments&quot;&gt;Extraction of values and commitments&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;challenges&quot;&gt;Challenges&lt;&#x2F;h4&gt;
&lt;p&gt;Firstly, the verifier needs to compute all the challenges. For that, he follows these steps:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Add $[a], [b], [c]$ to the transcript.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Sample two challenges $\beta, \gamma$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Add $[z]$ to the transcript.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Sample a challenge $\alpha$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Add $[t_{lo} ], [t_{mid} ], [t_{hi} ]$ to the transcript.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Sample a challenge $\zeta$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Add $\bar a, \bar b, \bar c, \bar s_{\sigma 1}, \bar s_{\sigma 2}, \bar z_\omega$ to the transcript.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Sample a challenge $\upsilon$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;compute-pi-zeta&quot;&gt;Compute $pi(\zeta)$&lt;&#x2F;h4&gt;
&lt;p&gt;Also, he needs to compute a few values of all these data. First, he computes the $PI$ matrix with the public inputs and outputs. He needs to compute $pi(\zeta)$, where $pi$ is the interpolation of $PI$ at the domain $H$. But he doesn’t need to compute $pi$. He can instead compute $pi(\zeta)$ as&lt;br &#x2F;&gt;
$$ \sum_{i=0}^n L_i(\zeta) PI_i,$$&lt;br &#x2F;&gt;
where $n$ is the number of public inputs and $L_i$ is the Lagrange basis at the domain $H$.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;compute-claimed-values-p-zeta-and-t-zeta&quot;&gt;Compute claimed values $p(\zeta)$ and $t(\zeta)$&lt;&#x2F;h4&gt;
&lt;p&gt;He computes $\bar p_{c} := pi(\zeta) + \alpha \bar z_\omega (\bar c + \gamma) (\bar a + \beta \bar s_{\sigma1} + \gamma) (\bar b + \beta \bar s_{\sigma2} + \gamma) - \alpha^2 L_1(\zeta)$&lt;&#x2F;p&gt;
&lt;p&gt;This is the &lt;em&gt;constant&lt;&#x2F;em&gt; part of the linearization of $p$. So adding it to what the prover claims to be $\bar p_{nc}$, he obtains&lt;br &#x2F;&gt;
$$p(\zeta) = \bar p_{c} + \bar p_{nc}$$&lt;&#x2F;p&gt;
&lt;p&gt;Concerning $t(\zeta)$, this is actually already $&#x2F;bar t$.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;compute-t-text-partial-and-p-nc&quot;&gt;Compute $[t_{\text{partial}}]$ and $[p_{nc}]$&lt;&#x2F;h4&gt;
&lt;p&gt;He computes these of the commitments in the proof as follows:&lt;br &#x2F;&gt;
$$ [t_{\text{partial}}] = [t_{lo}] + \zeta^{N+2}[t_{mid}] + \zeta^{2(N+2)}[t_{hi}] $$&lt;&#x2F;p&gt;
&lt;p&gt;For $[p_{nc}]$, first compute&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\begin{aligned}&lt;br &#x2F;&gt;
\left[\hat p_{nc1}\right] &amp;amp;= \bar a[q_L] + \bar b[q_R] + (\bar a\bar b)[q_M] + \bar c[q_O] + [q_C] \newline&lt;br &#x2F;&gt;
[\hat p_{nc2}] &amp;amp;= (\bar a + \beta\zeta + \gamma)(\bar b + \beta k_1\zeta + \gamma)(\bar c + \beta k_2\zeta + \gamma)[z] - (\bar a + \beta \bar s_{\sigma1} + \gamma)(\bar b + \beta \bar s_{\sigma2} + \gamma)\beta \bar z_\omega [S_{\sigma3}] \newline&lt;br &#x2F;&gt;
[\hat p_{nc3}] &amp;amp;= L_1(\zeta)[z]&lt;br &#x2F;&gt;
\end{aligned}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;Then $[p_{nc}] = [p_{nc1}] + [p_{nc2}] + [p_{nc3}]$.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;compute-claimed-value-f-text-batch-zeta-and-f-text-batch&quot;&gt;Compute claimed value $f_{\text{batch}}(\zeta)$ and $[f_{\text{batch}}]$&lt;&#x2F;h4&gt;
&lt;p&gt;Compute $f_{\text{batch}}(\zeta)$ as&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
f_{\text{batch}}(\zeta) =&lt;br &#x2F;&gt;
\bar t +\upsilon \bar p_{nc} + \upsilon^2 \bar a + \upsilon^3 \bar b + \upsilon^4 \bar c + \upsilon^5 \bar s_{\sigma1} + \upsilon^6 \bar s_{\sigma2}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;Also, the commitment of the polynomial $f_{\text{batch}}$ is&lt;br &#x2F;&gt;
$$\left[f_{\text{batch}}\right] = \left[ t_{\text{partial}} \right] +\upsilon [p_{nc}] + \upsilon^2 [a] + \upsilon^3 [b] + \upsilon^4 [c] + \upsilon^5 [S_{\sigma1}] + \upsilon^6 [S_{\sigma2}]$$&lt;&#x2F;p&gt;
&lt;h3 id=&quot;proof-check&quot;&gt;Proof check&lt;&#x2F;h3&gt;
&lt;p&gt;Now the verifier has all the necessary values to proceed with the checks.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Check that $p(\zeta)$ equals $(\zeta^N - 1)t(\zeta)$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Verify the opening of $f_{\text{batch}}$ at $\zeta$. That is, check that $\text{Verify}([f_{\text{batch}}], \pi_{\text{batch}}, \zeta, f_{\text{batch}}(\zeta))$ outputs _Accept_.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Verify the opening of $z$ at $\zeta\omega$. That is, check the validity of the proof $\pi_{single}$ using the commitment $[z]$ and the value $\bar z_\omega$.  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That is, check that $\text{Verify}(\left[z\right] , \pi_{\text{single}}, \zeta\omega, \bar z_\omega )$ outputs &lt;em&gt;Accept&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;If all checks pass, he outputs &lt;em&gt;Accept&lt;&#x2F;em&gt;. Otherwise, outputs &lt;em&gt;Reject&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;In this post, we covered the working principles and protocol basics of PLONK, a commonly used ZK-SNARK. We saw how to transform the computation into a group of polynomial constraints over the elements of the computation trace. Then, we saw how to enforce these constraints and how to prove the correct wiring, using a permutation argument. In an upcoming post, we will be covering optimizations to the basic protocol, including custom gates, look-up tables, folding schemes and other commitment schemes.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>How to get a true headache: brute forcing NTRU</title>
          <pubDate>Mon, 24 Apr 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/how-to-get-a-true-headache-brute-forcing-ntru/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/how-to-get-a-true-headache-brute-forcing-ntru/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/how-to-get-a-true-headache-brute-forcing-ntru/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;Lattice cryptography is a type of cryptographic scheme that relies on the hardness of certain computational problems related to lattices, which are geometric structures formed by repeating a pattern of points in space. Lattice-based cryptography is considered a promising candidate for post-quantum cryptography, as it is believed to be resistant to attacks by quantum computers.&lt;&#x2F;p&gt;
&lt;p&gt;The NTRU (N-th degree Truncated polynomial Ring Units) cryptosystem is a lattice-based public-key cryptosystem that was introduced in 1996. It is based on the properties of a specific type of lattice called an ideal lattice, a particular type constructed from the ideals of a polynomial ring. The NTRU cryptosystem uses polynomials with small coefficients to generate public and private keys, which are then used for encryption and decryption. For more details, see our &lt;a href=&quot;&#x2F;i-want-to-break-free-from-lattice-based-cryptography-but-not-even-a-quantum-computer-can-help-me&#x2F;&quot;&gt;previous post&lt;&#x2F;a&gt;. In this post, we will explain how finding the private key is equivalent to finding short vectors on a lattice and give bounds on brute-force attacks.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-public-and-private-keys-in-ntru&quot;&gt;The public and private keys in NTRU&lt;&#x2F;h2&gt;
&lt;p&gt;In our &lt;a href=&quot;&#x2F;i-want-to-break-free-from-lattice-based-cryptography-but-not-even-a-quantum-computer-can-help-me&#x2F;&quot;&gt;previous post&lt;&#x2F;a&gt;, we discussed the NTRU encryption scheme. We now head to show how its keys are related to a specific lattice; the encryption and decryption processes are irrelevant for this purpose; hence they can be left aside.&lt;&#x2F;p&gt;
&lt;p&gt;Recall from our previous post the ring $R = \mathbb Z[X]$ and the ring $R_q = \mathbb Z_q[X]$. The private key in NTRU consists of two polynomials $f,g \in R$ whose coefficients are somehow &lt;em&gt;small&lt;&#x2F;em&gt; : they are allowed to be only equal to 0, 1, or -1. These are called &lt;em&gt;ternary&lt;&#x2F;em&gt; polynomials.&lt;&#x2F;p&gt;
&lt;p&gt;The polynomial $f$ must have an inverse $F \in R_q$. For example, let $N = 5, q = 37$ and&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
f = 1 + x - x^2 + x^4.&lt;br &#x2F;&gt;
$$ Letting $F \in R$ be the polynomial given by&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
F = 29x^4 + 35x^3 + 22x^2 + 12x + 32,&lt;br &#x2F;&gt;
$$ let’s show that $F$ is the inverse of $f$ in $R_q$.&lt;&#x2F;p&gt;
&lt;p&gt;Recall that the product in $R_q$ is explained in our previous post: we multiply as usual, replacing the appearance of $x^N$. Then in our example, we have that&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
\begin{align*}&lt;br &#x2F;&gt;
fF &amp;amp; = 29x^8 + 35x^7 + 30x^6 + 6x^5 + 8x^3 + 2x^2 + 7x + 32 \newline&lt;br &#x2F;&gt;
&amp;amp; = (29+8)x^3 + (35+2)x^2 + (30+7) x + (6+32) \newline&lt;br &#x2F;&gt;
&amp;amp; = 1.&lt;br &#x2F;&gt;
\end{align*}&lt;br &#x2F;&gt;
$$ This example shows that the inverse of $f$ can have arbitrarily large coefficients, even though $f$ is small.&lt;&#x2F;p&gt;
&lt;p&gt;The public key is the polynomial $h \in R_q$ given by $h = Fg$. In our example, if we let&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
g = x - x^3 - x^4&lt;br &#x2F;&gt;
$$ We have that&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
h = 28x^4 + 35x^3 + 22x^2 + 12x + 32.&lt;br &#x2F;&gt;
$$ We see that though $h$ is constructed from ternary polynomials, it is far from being ternary.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-convolution-ring-revisited&quot;&gt;The convolution ring revisited&lt;&#x2F;h2&gt;
&lt;p&gt;By replacing every appereance of $x^N$ with 1, we can write every polynomial $h \in R$ as $h = h_0+\cdots+h_{N-1}x^{N-1}$. Moreover, we will identify the polynomial $h$ with the vector $\mathbf h = (h_0,\dots,h_{N-1})$.&lt;&#x2F;p&gt;
&lt;p&gt;In these terms, the multiplication in $R$ can be stated in matrix form. More precisely, let $M_\mathbf{h} \in \mathbb Z^{N\times N}$ be the matrix given by.&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
M_h = \left(\begin{array}{cccc}h_0 &amp;amp; h_1 &amp;amp; \cdots &amp;amp; h_{N-1} \newline h_{N-1} &amp;amp; h_0 &amp;amp; \cdots &amp;amp; h_{N-2} \newline \vdots &amp;amp; \vdots &amp;amp; \ddots &amp;amp; \vdots \newline h_1 &amp;amp; h_2 &amp;amp; \cdots &amp;amp; h_0\end{array}\right).&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
Then, given a polynomial $f \in R$ and letting $g = fh$, it is not hard to see that we have the equality of vectors&lt;br &#x2F;&gt;
$$\mathbf{g} = \mathbf{f} \cdot M_{\mathbf h}.$$ Regarding the example above, the reader can verify that modulo 37, we have that&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
(0, 1, 0, -1, -1) =&lt;br &#x2F;&gt;
(1, 1, -1, 0, 1)\cdot \left(\begin{array}{rrrrr}&lt;br &#x2F;&gt;
32 &amp;amp; 12 &amp;amp; 22 &amp;amp; 35 &amp;amp; 28 \newline&lt;br &#x2F;&gt;
28 &amp;amp; 32 &amp;amp; 12 &amp;amp; 22 &amp;amp; 35 \newline&lt;br &#x2F;&gt;
35 &amp;amp; 28 &amp;amp; 32 &amp;amp; 12 &amp;amp; 22 \newline&lt;br &#x2F;&gt;
22 &amp;amp; 35 &amp;amp; 28 &amp;amp; 32 &amp;amp; 12 \newline&lt;br &#x2F;&gt;
12 &amp;amp; 22 &amp;amp; 35 &amp;amp; 28 &amp;amp; 32&lt;br &#x2F;&gt;
\end{array}\right).$$&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-ntru-lattice&quot;&gt;The NTRU lattice&lt;&#x2F;h2&gt;
&lt;p&gt;The natural attack involves looking for ternary polynomials $f,g \in R$ such that $fh = g \in R_q$. Equivalently, such that there exists $k \in R$ such that&lt;br &#x2F;&gt;
$$ fh = g + qk \quad \in R.$$&lt;&#x2F;p&gt;
&lt;p&gt;To use the matrix formulation from above, we introduce the block matrix $M_{\mathbf h,q}$ given by&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
M_{\mathbf h,q} = \left(\begin{array}{cc}I_N &amp;amp; M_{\mathbf h} \newline 0 &amp;amp; qI_N \end{array}\right).&lt;br &#x2F;&gt;
$$ Note that it has a nonzero determinant. This means that its rows form a basis of $\mathbb R ^{2N}$. In particular, they span a (public) lattice, which we will denote by $L_{h,q}$.&lt;&#x2F;p&gt;
&lt;p&gt;Considering block multiplication, we see that the equality above is rewritten as&lt;br &#x2F;&gt;
$$ (\mathbf f,-\mathbf k) \cdot M_{\mathbf h,q} = (\mathbf f,\mathbf g).$$ From here on, we can leave polynomials aside.&lt;&#x2F;p&gt;
&lt;p&gt;Note that the vector on the left-hand side is obtained by linearly combining the rows from $M_{\mathbf h,q}$ with the coefficients of $(\mathbf f,- \mathbf k)$, which are integers. In other words, this is a vector in the lattice $L_{h,q}$.&lt;&#x2F;p&gt;
&lt;p&gt;The vector on the right-hand side, being $f$ and $g$ ternary, is a small (or &lt;em&gt;short&lt;&#x2F;em&gt;) vector. Thus, breaking NTRU is equivalent to finding short vectors in the lattice $L_{h,q}$ given by the public key.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;finding-short-vectors-the-rough-way&quot;&gt;Finding short vectors, the rough way&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;lattices-recalling-the-basics&quot;&gt;Lattices: recalling the basics&lt;&#x2F;h3&gt;
&lt;p&gt;Recall that given a basis $v_1 , \dots , v_n$ of $\mathbb R^n$, the lattice $L$ defined by this basis is&lt;br &#x2F;&gt;
$$ L = \{ \sum_{ i = 1 }^n k_i v_i : k_i \in \mathbb Z \}.$$&lt;&#x2F;p&gt;
&lt;p&gt;It is easy to see that if we apply to the given basis a base change given by a matrix with integral coefficients and determinant 1 or -1 (a &lt;em&gt;unimodular&lt;&#x2F;em&gt; matrix), we obtain a different basis for $L$. Moreover, every other basis for $L$ is obtained in this way.&lt;&#x2F;p&gt;
&lt;p&gt;For example, the lattice in the plane defined by the canonical basis $e_1 = (1,0), e_2 = (0,1)$ can also be defined by the basis&lt;br &#x2F;&gt;
$$ v = (-7226, 23423),\quad w = (379835, -1231231). $$ In fact,$$-1231231 v - 379835 w = e_1, \quad -23432 v - 7226 w = e_2,$$ which shows that $e_1$ and $e_2$ (and hence every integral combination of them) can be written as an integral combination of $v$ and $w$.&lt;&#x2F;p&gt;
&lt;p&gt;As we see, the same lattice can have more and less complicated bases.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-volume&quot;&gt;The volume&lt;&#x2F;h3&gt;
&lt;p&gt;The most important invariant of a lattice $L$ is its &lt;em&gt;volume&lt;&#x2F;em&gt; , which is the size of the parallelepiped $\mathcal F$ generated by a basis $\mathcal B$ of $L$.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;srRCpaD.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It can be computed as $$vol (L) = |\det(C)|$$ where $C$ is the matrix having the vectors in $\mathcal B$ as columns (the reader interested in understanding why this computes the volume should consider the case $n = 2$). This number is independent of the chosen basis (i.e., an &lt;em&gt;invariant&lt;&#x2F;em&gt; of $L$) since changing $\mathcal B$ resorts to multiply $C$ by a unimodular matrix.&lt;&#x2F;p&gt;
&lt;p&gt;The volume is essential for our cryptographic interests since it gives a bound for the size of the shortest vector.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;short-vectors-brute-force&quot;&gt;Short vectors: brute force&lt;&#x2F;h3&gt;
&lt;p&gt;Every lattice $L$ contains the zero vector, which is naturally discarded when discussing short vectors. More precisely, a _shortest vector in $L$ is a nonzero vector $v \in L$ such that $\Vert v\Vert$ is minimum. Such a vector exists, though it is not unique: for example, because $\Vert v\Vert = \Vert- v\Vert$.&lt;&#x2F;p&gt;
&lt;p&gt;From a XIX century result due to Hermite, we know that&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The lattice $L$ contains a shortest vector $v$ such that $|v_i| \leq vol(L)^{1&#x2F;n}$ for every $1 \leq i \leq n$.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;This gives us a box $B$ where we can, by brute force, perform a search for shortest vectors.&lt;&#x2F;p&gt;
&lt;p&gt;How expensive would this be? Roughly, $ L \cap B$ should be the number of times $\mathcal F$ fits in $B$. Hence from the result of Hermite, we get that&lt;br &#x2F;&gt;
$$ L \cap B \sim vol(B) &#x2F; vol(L) = ( 2 vol(L)^{ 1&#x2F;n } )^n &#x2F; vol(L) = 2^n,$$ which shows that brute force is impractical for large $n$, independently of $L$. This continues to hold for the slight improvements available for Hermite’s result.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;In this post, we described how to transform the problem of finding the key in NTRU involving polynomials into a matrix problem. We explained the lattice behind the NTRU public key and how finding the private key can be reduced to finding short vectors in that lattice. We also provided some bounds on how hard it is to find short vectors, in general, using brute force attacks, showing that it is impractical for sufficiently large values of $n$, that is, polynomials of very large degrees. In upcoming posts, we will cover the fundamentals of other lattice schemes, such as CRYSTALS Kyber, and those related to fully homomorphic encryption, as well as more efficient lattice reduction techniques.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>I want to break free from Lattice-based cryptography, but not even a quantum computer can help me</title>
          <pubDate>Tue, 18 Apr 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/i-want-to-break-free-from-lattice-based-cryptography-but-not-even-a-quantum-computer-can-help-me/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/i-want-to-break-free-from-lattice-based-cryptography-but-not-even-a-quantum-computer-can-help-me/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/i-want-to-break-free-from-lattice-based-cryptography-but-not-even-a-quantum-computer-can-help-me/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;Public key encryption is a secure way of sending information over the internet. It uses two keys: a public key and a private key. We use the public key to encrypt messages. We can share this key publicly. The private key is kept secret and only known to the owner, who can use it to decrypt messages. This concept was introduced in a groundbreaking paper by Diffie and Hellman in the late 1970s and offered several advantages over previously used methods, including enhanced security, secure key exchange, digital signatures, scalability, and easier key management.&lt;&#x2F;p&gt;
&lt;p&gt;The working principle behind public key cryptography is that some complex mathematical problem (which can be easily verified if we know the solution or some secret information, but it is otherwise computationally expensive) relates the keys. For example, in the RSA cryptosystem, the public key denoted as $e$, and the private key, represented as $d$, are related by the expression $d \times e \equiv 1 (\mod \phi(n))$. This means that $e$ is the multiplicative inverse of $d$ modulo a function called Euler’s totient function evaluated at $n$, denoted as $\phi(n)$. There are efficient algorithms to compute modular inverses. Still, they require knowing the prime factorization of $n$, which is very hard for large numbers and could take longer than our lifespans, even with the fastest supercomputers.&lt;&#x2F;p&gt;
&lt;p&gt;Elliptic curve cryptography is another type of public key cryptography that uses a different mathematical approach. In this system, the secret key, denoted as $sk$, is related to the public key, denoted as $pk$, through a generator of a large subgroup of an elliptic curve, represented as $g$, by the expression $pk = g^{sk}$. We can recover the secret key from the public key if we find the exponent in this expression, known as the discrete logarithm problem. Depending on the properties of the curve and its subgroups, this problem can be tough to solve.&lt;&#x2F;p&gt;
&lt;p&gt;However, there is a potential threat to these public key encryption schemes posed by the advent of quantum computers, which are based on a different technology than conventional computers and can solve specific hard problems much faster. To address this, cryptographers have been working on other encryption schemes that can resist quantum computers, known as post-quantum secure cryptosystems. The NIST (National Institute of Standards and Technology) is standardizing one or more quantum-secure algorithms. Many of these schemes are based on the hardness of specific problems over lattices, leading to lattice-based cryptography.&lt;&#x2F;p&gt;
&lt;p&gt;Lattice-based cryptography is resistant to quantum computers and can also be used to construct fully homomorphic encryption schemes, which have important applications in secure computing and data privacy.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;lattices&quot;&gt;Lattices&lt;&#x2F;h2&gt;
&lt;p&gt;In mathematics, a lattice is a regular arrangement of points in a multi-dimensional space, forming a grid-like structure. Imagine a piece of graph paper where the intersections of the horizontal and vertical lines create a lattice. Depending on the problem being addressed, lattices can have different shapes, sizes, and dimensions depending on the problem being addressed.&lt;&#x2F;p&gt;
&lt;p&gt;Formally, a lattice can be defined as a set of points generated by linear combinations of a set of basis vectors with integer coefficients. These basis vectors define the directions and spacing of the lattice points. The lattice can span multiple dimensions, with each dimension corresponding to a different basis vector. For example, in two-dimensional space, a lattice can be represented by two basis vectors that define the spacing between the lattice points along the horizontal and vertical directions. Below is the image of a hexagonal lattice spanned by two vectors forming a 120° angle.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;6jcGgy3.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Given a set of linearly independent vectors, $\mathbb{V} = { v_1 , v_2 , v_3 , … , v_m }$ in $\mathbb{R}^n$, the lattice generated by $\mathbb{V}$ is given by the set,&lt;&#x2F;p&gt;
&lt;p&gt;$$ L = { a_1 v_1 + a_2 v_2 + \dots + a_m v_m : a_k \in \mathbb{Z}}$$&lt;&#x2F;p&gt;
&lt;p&gt;The dimension of $L$ is the number of vectors in a basis for $L$. We can use other vectors as basis $\mathbb{W} = { w_1 , w_2 , \dots , w_m}$ for $L$. The basis vectors are related by&lt;br &#x2F;&gt;
$w_1 = a_{11} v_1 + a_{12} v_2 + \dots + a_{1m}v_m$&lt;br &#x2F;&gt;
$w_2 = a_{21} v_1 + a_{22} v_2 + \dots + a_{2m}v_m$&lt;br &#x2F;&gt;
$\vdots$&lt;br &#x2F;&gt;
$w_m = a_{m1} v_1 + a_{m2} v_2 + \dots + a_{mm}v_m$&lt;&#x2F;p&gt;
&lt;p&gt;which can be written in matrix form as&lt;br &#x2F;&gt;
$$\mathbf{w} = A \mathbf{v}$$&lt;&#x2F;p&gt;
&lt;p&gt;The matrix $A$ is invertible, and we can also write the relationship between the bases as&lt;br &#x2F;&gt;
$$A^{-1} \mathbf{w} = \mathbf{v}$$&lt;&#x2F;p&gt;
&lt;p&gt;For example, in $\mathbb{R}^3$ we can have a cubic lattice using as vectors three perpendicular vectors, which we can represent as $E = { (1,0,0) , (0,1,0) , (0,0,1) }$; the lattice is given by the triple of integers $(x,y,z)$. We could also select as basis the vectors $B = { (2,1,1), (3,2,1), (1,1,1)}$. The matrix $A$ contains as rows the vectors from $B$.&lt;&#x2F;p&gt;
&lt;p&gt;Some bases are nicer than others. For example, the basis $E$ has three perpendicular (orthogonal) vectors of length 1. On the other hand, the vectors in basis $B$ are more prolonged and not perpendicular. We will shortly see that a nicer basis allows us to solve some lattice problems easily.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;shortest-vector-problem&quot;&gt;Shortest Vector Problem&lt;&#x2F;h2&gt;
&lt;p&gt;Two important mathematical problems in lattices are the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Shortest vector problem (SVP): we want to find a non-zero vector $\mathbf{v}$ in the lattice having the shortest length, $\Vert \mathbf{v} \Vert$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Closest vector problem (CVP): given $\mathbf{w}$ in a lattice, we want to find a vector $\mathbf{v}$ which is closest to $\mathbf{w}$, that is, we want the vector $\mathbf{w} - \mathbf{v}$ to have minimal length.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When we have an orthogonal set of basis vectors (that is, each pair of vectors is orthogonal), we can use the Pythagorean theorem to see that&lt;br &#x2F;&gt;
$$\Vert \mathbf{u} \Vert^2 = a_1^2 \Vert \mathbf{v_1} \Vert^2 + a_2^2 \Vert \mathbf{v_2} \Vert^2 + \dots + a_m^2 \Vert \mathbf{v_m} \Vert^2$$&lt;br &#x2F;&gt;
where all $a_k$ are integers. Therefore, the vectors of minimal length are contained in the set ${ \pm \mathbf{v_1} , \pm \mathbf{v_2} , \dots , \pm \mathbf{v_m}}$&lt;&#x2F;p&gt;
&lt;p&gt;If the basis is not orthogonal but still “nice,” we can use Babai’s algorithm to obtain a “good” approximation to the solution. This strategy fails if the basis vectors are close to each other.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ring-learning-with-errors&quot;&gt;Ring Learning with Errors&lt;&#x2F;h2&gt;
&lt;p&gt;The Learning with Errors (LWE) problem is a mathematical problem used in cryptography to secure communication and protect data. It involves finding a hidden pattern in noisy data. Think of it like trying to solve a puzzle where you are given a bunch of equations with some errors, and you need to figure out the correct relationship between the variables despite the errors. In LWE, the equations are represented as numbers modulo a large prime number, and the goal is to find the hidden linear relationship between them despite the noise.&lt;&#x2F;p&gt;
&lt;p&gt;Formally, given pairs $(\mathbf{a} , b)$ related by some linear function $b_k \approx \mathbf{s^t}.\mathbf{a}$ the goal is to distinguish these pairs from uniformly sampled random points $(\mathbf{x} , y)$. Each pair $(\mathbf{a}_k , b_k)$ contains a random error $e_k$, and we have to find $\mathbf{s}$ despite these errors.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;convolution-polynomial-rings&quot;&gt;Convolution polynomial rings&lt;&#x2F;h2&gt;
&lt;p&gt;Say we are working with the polynomials with coefficients over some ring, such as the integers, $\mathbb{Z}[x]$. The following set gives the $n$-th degree convolution polynomials&lt;br &#x2F;&gt;
$$ R = \mathbb{Z}[x] &#x2F; (x^n - 1) $$&lt;&#x2F;p&gt;
&lt;p&gt;This means we have polynomials modulo $x^n - 1$ analogously as we worked with integers. In integers, we said that $15 \equiv 1 \mod 7$ because it can be written as a multiple of $7$ plus a remainder, that is, $15=2\times 7 + 1$. We could work easily with $1$ instead of $15$ and operate with it. In polynomials, $x^5 + x^2 + 1 \equiv x + 2 \mod x^2 - 1$, because&lt;br &#x2F;&gt;
$$ x^5 + x^2 + 1 = (x^2 - 1)(x^3 + x^2 + x +1) + (x + 2)$$&lt;&#x2F;p&gt;
&lt;p&gt;The exciting property when using $x^n -1$ is that whenever we spot a power $x^n$, we can replace $x^n$ by $1$ (in the case of more complex polynomials, we would have to carry out the division and find the remainder). This also leads to a more straightforward expression for polynomial multiplication. Let’s look at an example first,&lt;br &#x2F;&gt;
$$ (x^2 + 3 x + 5)(2x^2 + 2 x + 7) = p(x) \mod (x^3 - 1)$$&lt;br &#x2F;&gt;
The standard calculation would make us apply distributive property, sum all terms with the same powers and reduce all powers greater than 2:&lt;br &#x2F;&gt;
$$ 2x^4 + 2x^3 + 7x^2 + 6x^3 + 6x^2 + 21x + 10x^2 + 10 x +35 = p(x)$$&lt;br &#x2F;&gt;
Summing,&lt;br &#x2F;&gt;
$$ 2x^4 + 8x^3 + 23 x^2 + 31 x + 35 = p(x)$$&lt;br &#x2F;&gt;
Applying the reduction,&lt;br &#x2F;&gt;
$$p(x) = 23 x^2 + 33 x + 43$$&lt;br &#x2F;&gt;
A more straightforward way would be to realize that the coefficient $p_k$ for term $x^k$ is given by this expression:&lt;br &#x2F;&gt;
$$p_k = \sum_{i+j \equiv k \mod 3} a_i b_j$$&lt;br &#x2F;&gt;
For $x^2$ we have&lt;br &#x2F;&gt;
$$p_2 = a_2 b_0 + a_1 b_1 + a_0 b_2 = 7 + 6 + 10 = 23$$&lt;br &#x2F;&gt;
For $x$ we have&lt;br &#x2F;&gt;
$$p_1 = a_1 b_0 + a_0 b_1 + a_2 b_2 = 2 + 21 + 10 = 33$$&lt;br &#x2F;&gt;
Finally,&lt;br &#x2F;&gt;
$$p_0 = a_0 b_0 + a_2 b_1 + a_1 b_2 = 35 + 2 + 6 = 43$$&lt;&#x2F;p&gt;
&lt;p&gt;In general, we have&lt;br &#x2F;&gt;
$$a(x) \times b(x) = c(x)$$&lt;br &#x2F;&gt;
where&lt;br &#x2F;&gt;
$$ c_k = \sum_{i+j \equiv k \mod n} a_i b_{k-i}$$&lt;&#x2F;p&gt;
&lt;p&gt;If you studied Laplace or Fourier transform, you’ll find that it is the convolution of $a$ and $b$. If the coefficients of the polynomials can only take the values $-1, 0, 1$, then the previous calculation is even faster.&lt;&#x2F;p&gt;
&lt;p&gt;We can work with polynomials defined over some finite field, $\mathbb{Z}_q$. The convolution polynomial ring is&lt;br &#x2F;&gt;
$$R_q = \mathbb{Z_q}[x]&#x2F;(x^n - 1)$$&lt;&#x2F;p&gt;
&lt;p&gt;In $\mathbb{Z}_q$, we saw that an element $a$ had a multiplicative inverse $b$ (such that $a\times b \equiv 1 \mod q$) if and only if $a$ and $q$ are coprime, that is, $gcd(a,q) = 1$ (gcd stands for greatest common divisor). An analogous result exists in $R_q$, stating that a polynomial $p(x)$ has a multiplicative inverse, $q(x)$, ($p(x)q(x) \equiv 1 \mod x^n -1$) if and only if $gcd(p(x) , x^n -1)=1$.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;lattices-and-polynomial-rings&quot;&gt;Lattices and polynomial rings&lt;&#x2F;h2&gt;
&lt;p&gt;We can map elements from a polynomial ring into points of a lattice. The simplest way is via the coefficient embedding: we see the $k$-th coefficient, $p_k$ as the $k-th$ coordinate of a vector in $\mathbb{Z}_q^k$. This embedding has the nice property that adding polynomials corresponds to the component-wise addition of lattice points, but multiplication does not have a nice geometrical interpretation. In an upcoming post, we will explain in more detail how to reduce the NTRU key recovery to the shortest vector problem over some lattice.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ntru&quot;&gt;NTRU&lt;&#x2F;h2&gt;
&lt;p&gt;NTRU (N-th degree Truncated polynomial Ring Units) is a public key encryption scheme that works using three convolution polynomial rings,&lt;br &#x2F;&gt;
$$\mathcal{R} = Z[x]&#x2F;(x^n - 1)$$&lt;br &#x2F;&gt;
$$\mathcal{R_q} = Z_q[x]&#x2F;(x^n - 1)$$&lt;br &#x2F;&gt;
$$\mathcal{R_p} = Z_p[x]&#x2F;(x^n - 1)$$&lt;&#x2F;p&gt;
&lt;p&gt;where $n$ is a prime number and not equal to $q$. A pair of polynomials gives the secret keys in NTRU, whose coefficients can only take the values $-1, 0, 1$. These polynomials are called trinary polynomials and denote their families by $\mathcal{T}(d_1 , d_2)$. $d_1$ is the number of coefficients equal to one, and $d_2$ is the number of coefficients equal to $-1$ (given that the polynomial has degree at most $n$, there are $n - d_1 - d_2$ coefficients equal to zero). For example, $x^3 - x^2 + 1$ is a trinary polynomial ($d_1 = 2$, $d_2 = -1$), while $2x^3 + x - 3$ is not. The private key is given by the pair $f(x)$ and $g(x)$, where&lt;br &#x2F;&gt;
$f(x) \in \mathcal{T}(d+1 , d)$&lt;br &#x2F;&gt;
$g(x) \in \mathcal{T}(d , d)$&lt;&#x2F;p&gt;
&lt;p&gt;The polynomial $f(x)$ has $d+1$ ones, and $d$ coefficients equal $-1$ (If the polynomial has the same amount of $-1$ and $1$, it has no multiplicative inverse).&lt;&#x2F;p&gt;
&lt;p&gt;We next calculate $F_q (x) = {f(x)}^{-1}$ and $F_p (x) = {f(x)}^{-1}$ in the rings $\mathcal{R_q}$ and $\mathcal{R_p}$, respectively and obtain the public key as&lt;br &#x2F;&gt;
$h(x) = F_q (x) g(x)$&lt;br &#x2F;&gt;
in $\mathcal{R_q}$ (If the polynomial $f(x)$ has no inverse, we have to choose another one). This is the key we will use to encrypt messages. The decryption key is given by $(f(x) , F_p(x))$.&lt;&#x2F;p&gt;
&lt;p&gt;We must encode messages as polynomials in the ring $\mathcal{R_p}$ to encrypt messages. As such, they will have coefficients in the range ${ -p&#x2F;2, -(p-1)&#x2F;2, …, -1, 0, 1, …, p&#x2F;2}$. We sample some random polynomial, $r(x)$ in $\mathcal{T}(d,d)$ and compute the ciphertext as&lt;br &#x2F;&gt;
$c(x) = p h(x) r(x) + m(x) \mod q$&lt;br &#x2F;&gt;
We can see we are adding some “random noise” to the plaintext to hide it.&lt;&#x2F;p&gt;
&lt;p&gt;If we want to decrypt, we first compute&lt;br &#x2F;&gt;
$a (x) = f(x) c(x) \mod q$&lt;br &#x2F;&gt;
$b (x) = F_p (x) a(x) \mod p$&lt;&#x2F;p&gt;
&lt;p&gt;If we choose the parameters correctly, then $b(x) = m(x)$, which we can decode to obtain the message. To specify NTRU, we need to set the values $(n, q, p, d)$, where $n$ and $q$ are coprime and $q &amp;gt; (6 d +1 )p$. To understand why this works, we can look at the calculations in more detail:&lt;br &#x2F;&gt;
$a(x) = f(x) c(x) \mod q$&lt;br &#x2F;&gt;
If we expand $c(x)$,&lt;br &#x2F;&gt;
$a(x) = p f(x) F_q (x) g(x) r(x) + f(x)m(x) \mod q$&lt;br &#x2F;&gt;
but $f(x) F_q (x) \equiv 1 \mod q$, so&lt;br &#x2F;&gt;
$a(x) = p g(x) r(x) + f(x)m(x) \mod q$&lt;br &#x2F;&gt;
The assumption $q &amp;gt; (6d + 1)p$ ensures that the polynomial $a(x)$ is computed exactly and there is no wrap-around $q$.&lt;br &#x2F;&gt;
When we apply $F_p (x)$, we get&lt;br &#x2F;&gt;
$b(x) = p F_p (x) g(x) r(x) + F_p (x) f(x) m(x) \mod p$&lt;br &#x2F;&gt;
Given that all the coefficients of $p F_p (x) g(x) r(x)$ are multiples of $p$ (the factor $p$ first ensures this), that polynomial vanishes modulo $p$. We are left with&lt;br &#x2F;&gt;
$b(x) = F_p (x) f(x) m(x) \mod p$&lt;br &#x2F;&gt;
but $F_p (x)$ is the inverse of $f(x)$ in $\mathcal{R_p}$, so&lt;br &#x2F;&gt;
$b(x) = m(x)$&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;Lattice-based cryptography is a promising solution to protect against potential attacks from quantum computers. Lattices are organized arrangements of points in multi-dimensional spaces that form the foundation of lattice-based cryptography. These lattices allow for the construction of encryption schemes. The hardness of specific problems over lattices, such as the Learning With Errors (LWE) problem and the Shortest Vector Problem (SVP), serve as the basis for the security of lattice-based cryptography. These problems are believed to be difficult even for quantum computers, making lattice-based cryptography a compelling option for post-quantum security. In upcoming posts, we will cover more on the fundamentals of lattices and encryption schemes such as CRYSTALs Kyber.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Do You Want Quality Code? Learn How to Use Differential Fuzzers!</title>
          <pubDate>Fri, 14 Apr 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/do-you-want-quality-code-learn-how-to-use-differential-fuzzers/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/do-you-want-quality-code-learn-how-to-use-differential-fuzzers/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/do-you-want-quality-code-learn-how-to-use-differential-fuzzers/">&lt;p&gt;Let’s be honest, who hasn’t missed testing an edge case in their life? Surely it has happened to you, and maybe you realized it months after having implemented it (maybe when it’s already in production!). Some cases escape even the most experienced tester, and to avoid explanations to your manager, today we present the concept of fuzzing, and one of its types: the differential fuzzer.&lt;&#x2F;p&gt;
&lt;p&gt;As stipulated by the OWASP Foundation:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Fuzz testing or Fuzzing is a Black Box software testing technique, which consists in finding implementation bugs using malformed&#x2F;semi-malformed data injection in an automated fashion.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Fuzzing is a very efficient technique when looking for errors in our code. This is achieved by generating a massive set of random entries that are used to test a program. The resulting tests often manage to reach less common cases, the kind that can go usually be overlooked.&lt;br &#x2F;&gt;
If you are interested in learning more about the fuzzer concept in general you can watch the videos we made on the subject, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=z-THCexE4zs&quot;&gt;hacking with fuzzers&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=F3CtyKm7SV4&amp;amp;t=79s&quot;&gt;fuzzing tools&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;However, this tool is not limited to a single program, or to only finding errors that end up causing a crash; we can also compare the outputs of at least two different implementations of the same program and check that they follow the same behavior; this is known as differential fuzzing.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;when-should-we-use-differential-fuzzing&quot;&gt;When should we use differential fuzzing?&lt;&#x2F;h2&gt;
&lt;p&gt;The cases in which we can use the differential fuzzing technique are where we have two different implementations of the same algorithm. For example, let’s think about all the different languages in which the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;ethereum.org&#x2F;en&#x2F;developers&#x2F;docs&#x2F;evm&#x2F;&quot;&gt;Ethereum Virtual Machine&lt;&#x2F;a&gt; is implemented. The simple magic of the differential fuzzer is to test massively with different inputs that all implementations return the same result when running the same process or function. If this is not the case, at least one of the implementations has logic errors and is giving us a result that was not expected.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;structure-of-a-differential-fuzzer&quot;&gt;Structure of a differential fuzzer&lt;&#x2F;h2&gt;
&lt;p&gt;The structure of a differential fuzzer is simple, first, we define which tool we are going to use for fuzzing since we have a large number of tools for this purpose like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;google&#x2F;honggfuzz&quot;&gt;Honggfuzz&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-fuzz&#x2F;cargo-fuzz&quot;&gt;Cargofuzz&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;google&#x2F;atheris&quot;&gt;Atheris&lt;&#x2F;a&gt; and many more.&lt;&#x2F;p&gt;
&lt;p&gt;Whichever tool you choose (we do not judge preferences here), all tools should provide us with the same thing, a series of random inputs that we will inject into the code to be tested.&lt;&#x2F;p&gt;
&lt;p&gt;With the input provided by the fuzzer, we adapt it to each of the implementations. In this way, both should have the same input at the end, and we tell the fuzzer to return an error if the results differ. This will give us a list of inputs where at least one of the implementations has an error in its logic, giving a different result than the expected one.&lt;&#x2F;p&gt;
&lt;p&gt;For this, we may need intermediate functions to ensure that the result returned by both implementations is comparable.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;example-of-a-differential-fuzzer&quot;&gt;Example of a differential fuzzer&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#![no_main]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;use libfuzzer_sys::fuzz_target;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;use std::io::prelude::*;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;use inflate::inflate_bytes;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;use libflate::deflate::Decoder;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; This differential fuzzer panics if two different implementations for deflate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; decode function returns different results &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fuzz_target!(|data: &amp;amp;[u8]| {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut libflate_decoded = Decoder::new(data);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut decoded_data = Vec::new();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let libflate_res = libflate_decoded.read_to_end(&amp;amp;mut decoded_data).is_ok();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let inflate_decoded = inflate_bytes(data).is_ok();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if libflate_res != inflate_decoded {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    panic!(&amp;quot;differential fuzz failed {}-{}&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            libflate_res, inflate_decoded)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In the example, we can see an example of a differential fuzzer. This fuzzer is created using the &lt;code&gt;libfuzzer&lt;&#x2F;code&gt; tool, meant to be used in Rust. the structure of the code is simple and it’s the same for all the fuzzer tools that you want to use.&lt;&#x2F;p&gt;
&lt;p&gt;First, we have the imports that include the implementations we want to compare in our fuzzer. Then we have the function that´s going to run the fuzzer, in this case, is the &lt;code&gt;fuzz_target!()&lt;&#x2F;code&gt; function. This function supplies us with a randomly generated input, in this case, the variable &lt;code&gt;data&lt;&#x2F;code&gt;. With the previous &lt;code&gt;data&lt;&#x2F;code&gt; generated, we run the piece of code that we want to test. In cases like the one in the example code used by &lt;code&gt;libflate,&lt;&#x2F;code&gt; we need to adjust the random &lt;code&gt;data&lt;&#x2F;code&gt; to be received by the code in the first instance. As the last step we do the differential magic, that is, we compare the result returned by the different implementations.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;DzicizT.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In this case, as we can see in the image when we run the fuzzer, it finds a crash because one of the implementations returns a valid result and the other one an error.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;inputs-and-outputs&quot;&gt;Inputs and outputs&lt;&#x2F;h2&gt;
&lt;p&gt;According to every particular case of inputs and outputs, we might need to provide some extra code.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s understand what that means with a simple example. We might be comparing two implementations of some code that receives a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Quadratic_equation&quot;&gt;quadratic equation&lt;&#x2F;a&gt; and an answer and returns if the answers responds to the equation. In this case, one of the implementations receives 4 numbers that correspond to the index of the equation and the answer and the other receives the input as a string with the equation, something like “axx+bx+c=d”.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Implementation 1 &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;def check_if_answer(a,b,c,d, answer):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    result = (a * answer^2) + (b * answer) + c &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if result == d: { &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        True&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    } &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    else: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        False&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Implementation 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;def check_if_anwer(equation, answer):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    string_without_x = remove_x_from_string(equation) # This returns &amp;quot;a+b+c=d&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    array_of_indexes = split_string(string_without_x) # This returns [a,b,c,d]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [a,b,c,d] =  array_of_indexes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    result = (a * answer^2) + (b * answer) + c &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if result == d: { &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        True&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    } &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    else: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        False&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To give the different implementations the “same” input we need to adjust the starting input so it’s the same for both. In the output, we have to do the same. One of the implementations might return True&#x2F; False while the other return 0&#x2F;1, we need to adjust the outputs so the equality works as it has to.&lt;&#x2F;p&gt;
&lt;p&gt;This applies to both regular and differential fuzzers.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;A differential fuzzer is a very valuable tool in case you are implementing a process that already has another implementation to ensure that even the edge cases are handled consistently. This tool can also be used in the case of choosing implementations of a solution that we want to use for our project, by comparing the effectiveness of each one.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Transforming the Future with Zero-Knowledge Proofs, Fully Homomorphic Encryption and new Distributed Systems algorithms</title>
          <pubDate>Thu, 13 Apr 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/transforming-the-future-with-zero-knowledge-proofs-fully-homomorphic-encryption-and-new-distributed-systems-algorithms/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/transforming-the-future-with-zero-knowledge-proofs-fully-homomorphic-encryption-and-new-distributed-systems-algorithms/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/transforming-the-future-with-zero-knowledge-proofs-fully-homomorphic-encryption-and-new-distributed-systems-algorithms/">&lt;p&gt;Disclaimer: To maintain brevity and clarity, we have simplified certain concepts. In this discussion, Zero Knowledge Proofs and Computational Integrity are considered as a single concept, and we will not address the distinct security properties of Proof of Work and Proof of Stake.&lt;&#x2F;p&gt;
&lt;p&gt;The evolution of every scientific discipline or engineering field experiences cycles akin to those observed in economies. Incremental advancements are made daily by corporations, individuals, and academic institutions. Occasionally, a researcher or engineer makes a groundbreaking discovery that alters the course of the field. One such example is Sir Isaac Newton, who made significant contributions to calculus, motion, optics, and gravitation during the time of the bubonic plague, which claimed millions of lives. His relentless pursuit of knowledge throughout the pandemic proved instrumental in shaping the development of mathematics, physics, and engineering. Our comfortable modern lives stand upon the foundation of these monumental discoveries.&lt;&#x2F;p&gt;
&lt;p&gt;The general public is aware of the big breakthroughs made in the aerospatial industry, energy production, internet of things, and last but not least artificial intelligence. However, most don’t know that during the COVID pandemic, enormous advances were made in cryptography. 47 years ago Diffie and Hellman wrote in their famous cryptography paper: “we stand today on the brink of a revolution in cryptography”, which enabled two people to exchange confidential information even when they can only communicate via a channel monitored by an adversary. This revolution enabled electronic commerce and the communication between citizens of the free world. We believe the discoveries made by researchers and engineers in cryptography during this COVID pandemic will be as important as the discoveries made by Diffie and Hellman in the upcoming decades.&lt;&#x2F;p&gt;
&lt;p&gt;One of the big discoveries has been how to make Zero-Knowledge Proofs fast enough for real-world applications. This technology has been around since 1984 but as Diffie also said, “Lots of people working in cryptography have no deep concern with real application issues. They are trying to discover things clever enough to write papers about”. Fortunately for humanity, researchers and engineers have made this technology practical enough in the last decade (especially the last 2 years) to be useful.&lt;&#x2F;p&gt;
&lt;p&gt;The financial system depends on the existence of intermediaries: an army of auditors, regulators, and accountants. The correct working of the financial machine depends on the integrity of its financial institutions. Integrity is maintained due to positive economic incentives and jail time, fines, and costly lawsuits if the intermediaries don’t do what the state and society expect from them. Bitcoin, a result of the 2008 crisis, created a permissionless financial system where its users can send and receive digital money without intermediaries and without anybody being able to block transactions. In countries like Argentina, Nigeria, or Lebanon, where stagnation and inflation erode its citizens’ trust in the financial system and the state, Bitcoin and stablecoins on top of Ethereum are used on a daily basis by the young population to save and avoid capital controls. In developed countries, its usage is not as massive since the traditional financial system and the state is trusted by most citizens. However, the world is becoming more complex. Banks are failing in the US and Europe, a new war is taking place in Europe, debt levels are not sustainable in many countries, the fight between left and the right is retaking the main stage, tension between the West and the East increases, and technological change keeps accelerating.&lt;&#x2F;p&gt;
&lt;p&gt;New applications built on top of unstoppable and trustless technologies that don’t depend on social trust will grow and thrive in this type of environment. Everything is being questioned. Only things that can’t be questioned will fully resist the passage of time. This will happen not only in developing countries but also in developed ones. Systems like Bitcoin, where everyone can verify how it’s running, are more resilient and become more useful by the day in a world that is getting more complex.&lt;&#x2F;p&gt;
&lt;p&gt;Bitcoin’s focus has been to become a new type of monetary asset and financial network. For this reason, the development of more complex programs on top of Bitcoin has always been restricted by design. Newer blockchains like Ethereum added the ability to create new types of applications. DeFi Protocols that enabled lending and borrowing, exchange of digital currencies and the ability to buy, sell and trade digital collectives and arts rapidly grew on top of Ethereum. However the cost of creating and transferring relevant amounts of assets in blockchains is costly. The ability to create more complex applications that sit on top of blockchains is also very limited. Applications can’t run more than a few milliseconds on Ethereum.&lt;&#x2F;p&gt;
&lt;p&gt;These systems do not rely on social integrity like traditional systems. Instead, they operate as a permissionless and censorship-resistant network, allowing anyone to add a node and submit updates to its state. To ensure verification, each node must re-execute all transactions, which makes the system decentralized and secure, albeit slower than centralized systems. Consequently, this imposes a limitation on the types of applications that can be built on blockchains. Applications requiring frequent database state updates, such as those exceeding a few times per second, or machine learning algorithms, are not feasible on blockchain platforms.&lt;&#x2F;p&gt;
&lt;p&gt;This is where Zero Knowledge Proofs (ZKPs) and other cryptographic and distributed systems primitives will help society create tools that can be used by everyone. ZKPs enable a party to demonstrate a statement to other parties without revealing any information beyond the proof. In more concrete terms, this enables a person to show another person that the computation they did is correct without having to redo it and without even having to grant access to the data that was used. An important aspect of this is that the verification is done in a much faster time than the proving. In even simpler terms, it proves that the output of a certain computation is correct. The verification is way easier and faster to do than the execution or proving. Anybody can check the proof, and this saves computing time and money.&lt;&#x2F;p&gt;
&lt;p&gt;At the beginning it’s difficult to grasp, even for engineers, that such a technology is even possible. The mathematics behind it, until recently, seemed magical, and that’s why it was called moon math. Thanks to ZKPs, transferring money in blockchains similar to Bitcoin is cheaper and way faster since there is no need to re-execute each transaction by each node. Only one node is needed to process all the transactions and prove them using a ZKPs, while the rest simply need to verify it, saving valuable computing resources. Among other things, ZKPs enable creating a financial system that doesn’t depend on social trust like traditional finance and that doesn’t depend as much on re-executing algorithms as Bitcoin.&lt;&#x2F;p&gt;
&lt;p&gt;Zero Knowledge Proofs facilitate the development of an entirely new range of applications that are executed and proven on a single computer outside the blockchain, with verification occurring within Ethereum. The verification cost is way cheaper than the time it takes to prove or execute it. Ethereum will evolve from a slow yet secure distributed mainframe, where execution time is shared among all users to run small programs, into a distributed computer that stores and verifies proofs generated externally from the blockchain.&lt;&#x2F;p&gt;
&lt;p&gt;Not only will blockchains benefit from the development of new cryptographic primitives like Zero Knowledge Proofs (ZKPs), but other areas will also be significantly impacted. As AI-generated content begins to overshadow human-generated content on the internet, ZKPs will become essential for verifying that such content was produced by unbiased AI models. “Proof of humanity” systems are already employing ZKPs to ensure the accurate computation of a human accessing specific resources.&lt;&#x2F;p&gt;
&lt;p&gt;Hardware is another area where ZKPs will make an impact. Similar to how graphics cards in the 1990s revolutionized the video game industry, zero-knowledge hardware acceleration will be integrated into computers to enhance efficiency.&lt;&#x2F;p&gt;
&lt;p&gt;ZKPs can also be utilized to balance storage and computation securely. For instance, security cameras generate vast amounts of data. ZKPs can provide a compact proof that AI models did not detect any critical information in the video, allowing the system to delete the footage and save storage space.&lt;&#x2F;p&gt;
&lt;p&gt;ZKPs will even be used for national security purposes. As energy production shifts from centralized power plants to distributed sources like solar panels and wind turbines, verifying the proper execution of software on their controllers becomes vital. In the coming decades, ZKPs will play a crucial role in securing these devices.&lt;&#x2F;p&gt;
&lt;p&gt;Software industry regulations are inevitable, and industries such as online casinos and ad networks using Real-Time Bidding protocols will be legally required to demonstrate that they have not deceived their clients. Laws protecting users from large tech corporations are already in place in Europe, partly due to concerns about data misuse by foreign powers to influence political campaigns.&lt;&#x2F;p&gt;
&lt;p&gt;Requirements for secure storage and processing of encrypted data will become increasingly necessary. Fully Homomorphic Encryption (FHE), a technology akin to ZKPs, will be one of the tools utilized for this purpose. FHE enables computation on encrypted data, ensuring privacy. As FHE becomes more efficient and practical, most databases will integrate some FHE functionality, preventing administrators from accessing user data directly.&lt;&#x2F;p&gt;
&lt;p&gt;Zero-knowledge proofs (ZKPs), which generate evidence for a third party to confirm the accurate execution of a computation, and Fully Homomorphic Encryption (FHE), which enables calculations on encrypted data, will be combined with distributed systems algorithms that are capable of tolerating significant network failures similar to those employed by Bitcoin. Together they will be utilized to comply with regulations while creating trustless applications.&lt;&#x2F;p&gt;
&lt;p&gt;In the past decade, we have successfully launched applications serving dozens of millions of users. Leveraging our expertise, we are now dedicated to providing both technical and financial support to help others create startups focused on developing and implementing these vital technologies. As society grapples with the challenges of our rapidly evolving world these innovations will prove to be indispensable.&lt;&#x2F;p&gt;
&lt;p&gt;Federico Carrone.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>How to use the Consenys&#x27;s Gnark Zero Knowledge Proof library and disclosure of a DoS bug</title>
          <pubDate>Fri, 17 Mar 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/how-to-use-the-consenyss-gnark-zero-knowledge-proof-library-and-disclosure-of-a-ddos-bug/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/how-to-use-the-consenyss-gnark-zero-knowledge-proof-library-and-disclosure-of-a-ddos-bug/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/how-to-use-the-consenyss-gnark-zero-knowledge-proof-library-and-disclosure-of-a-ddos-bug/">&lt;p&gt;Zero Knowledge Proofs (ZKP) are a powerful cryptographic technique that allows two parties to exchange information without revealing any sensitive data. This method has the potential to revolutionize the way we handle privacy and security in various industries, such as finance, healthcare, and government. However, developing ZKP applications has traditionally been a challenging task, requiring a deep understanding of cryptography, programming, and mathematics.&lt;&#x2F;p&gt;
&lt;p&gt;Fortunately, with the advancement of technology and the development of new libraries and frameworks, writing ZKP applications has become much easier. Nowadays, there are several libraries available that can significantly reduce the complexity of developing ZKP applications, such as &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&#x2F;&quot;&gt;LambdaWorks&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;arkworks-rs&#x2F;&quot;&gt;Arkworks&lt;&#x2F;a&gt;, and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ConsenSys&#x2F;gnark&quot;&gt;Gnark&lt;&#x2F;a&gt;. These libraries provide developers with a set of tools and building blocks that simplify the implementation of complex cryptographic protocols.&lt;&#x2F;p&gt;
&lt;p&gt;In this post, we will focus on reviewing Gnark, one of the most powerful and user-friendly libraries available for ZKP development. Gnark is an open-source library that provides developers with a high-level programming language and a set of tools to build efficient and secure ZKP applications. We will explore the features and benefits of gnark and show how it can simplify the process of building ZKP applications.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-gnark&quot;&gt;What is Gnark&lt;&#x2F;h2&gt;
&lt;p&gt;Gnark, written in Go, is a fast ZK-SNARK library that offers both a high-level API and a low-level API to design circuits. The library is open-source and developed under the Apache 2.0 license.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-gnark&quot;&gt;Why Gnark&lt;&#x2F;h2&gt;
&lt;p&gt;We are using Gnark as a backend for &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;noir-lang&#x2F;noir&quot;&gt;Noir&lt;&#x2F;a&gt;. Noir is a domain-specific language for creating and verifying proofs. Noir compiles to an intermediate language which itself can be compiled to an arithmetic circuit or a rank-1 constraint system. This in itself brings up a few challenges within the design process but allows one to decouple the programming language completely from the backend. This is similar in theory to LLVM.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;zk-with-gnark&quot;&gt;ZK with Gnark&lt;&#x2F;h2&gt;
&lt;p&gt;The main flow for generating a ZK-Proof and verifying it would be:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Arithmetization: This is generating the R1CS or Sparse R1CS circuit with its constraints.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Generate a proof of execution for this circuit, given some public and private variables.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Verify said proof with the same public inputs used when generating the proof.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Gnark has both a high level API and a low level API. The main difference relies in the arithmetization. In the high level API you, as a user, are abstracted from the &lt;code&gt;R1CS&lt;&#x2F;code&gt; or &lt;code&gt;SparseR1CS&lt;&#x2F;code&gt; building and in the low level API you need to build them by hand (constraint by constraint).&lt;&#x2F;p&gt;
&lt;p&gt;In the following sections we’re going to explain and show some example usage of the high level and the low level APIs. We’ll start showing the bright side of Gnark which is the high level API.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;always-look-on-the-bright-side&quot;&gt;(Always look on) the bright side&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;Xs1ASoT.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;high-level-api&quot;&gt;High-level API&lt;&#x2F;h3&gt;
&lt;p&gt;Gnark’s high level API lives in the &lt;code&gt;frontend&lt;&#x2F;code&gt; package, you could find it in the root of the repo.&lt;&#x2F;p&gt;
&lt;p&gt;Earlier we said that the main difference relies in the arithmetization, but what does this mean? How so? By arithmetization we basically mean building the circuit with which you’re going to generate your proof.&lt;&#x2F;p&gt;
&lt;p&gt;In the case of the &lt;code&gt;frontend&lt;&#x2F;code&gt; package, building a circuit means to create your circuit struct which fields must be the variables of the circuit (a.k.a. circuit inputs) labeled as public or secret (not labeled fields are assumed secret variables by default). These inputs must be of type &lt;code&gt;frontend.Variable&lt;&#x2F;code&gt; and make up the witness. The witness has a secret part known to the prover only and a public part known to the prover and the verifier.&lt;&#x2F;p&gt;
&lt;p&gt;After you have your circuit structure built you need to define the circuits behaviour. You must do this writing a &lt;code&gt;Define&lt;&#x2F;code&gt; function. &lt;code&gt;Define&lt;&#x2F;code&gt; declares the circuit logic. The compiler then produces a list of constraints which must be satisfied (a valid witness) in order to create a valid ZK-SNARK. The circuit in the example below proves the factorisation of the RSA-250 challenge.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;example-rsa-from-gnark-s-playground&quot;&gt;Example: RSA (from &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;play.gnark.io&#x2F;&quot;&gt;gnark’s playground&lt;&#x2F;a&gt;)&lt;&#x2F;h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;type Circuit struct {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    P   frontend.Variable &#x2F;&#x2F; p  --&amp;gt; secret visibility (default)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Q   frontend.Variable `gnark:&amp;quot;q,secret&amp;quot;` &#x2F;&#x2F; q  --&amp;gt; secret visibility&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    RSA frontend.Variable `gnark:&amp;quot;,public&amp;quot;`  &#x2F;&#x2F; rsa  --&amp;gt; public visibility&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;func (circuit *Circuit) Define(api frontend.API) error {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; ensure we don&amp;#39;t accept RSA * 1 == RSA&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    api.AssertIsDifferent(circuit.P, 1)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    api.AssertIsDifferent(circuit.Q, 1)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; compute P * Q and store it in the local variable res.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    rsa := api.Mul(circuit.P, circuit.Q)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; assert that the statement P * Q == RSA is true.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    api.AssertIsEqual(circuit.RSA, rsa)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return nil&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;join-the-dark-side&quot;&gt;(Join) the dark side&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;P4W3s57.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;low-level-api&quot;&gt;Low-level API&lt;&#x2F;h3&gt;
&lt;p&gt;Located in the &lt;code&gt;constraint&lt;&#x2F;code&gt; module at the root of the repo, we can find almost everything that we need to write an R1CS (for Groth16) or a Sparse R1CS for (Plonk) “by hand”. By hand we mean to build our circuit constraint by constraint. I said almost earlier because we’ll also need some stuff from the &lt;code&gt;gnark-crypto&lt;&#x2F;code&gt; library (provides elliptic curve and pairing-based cryptography and various algorithms of particular interest to zero knowledge proof systems).&lt;&#x2F;p&gt;
&lt;p&gt;We say that the arithmetization here is by hand because both the circuit structure and the constraints need to be writen manually.&lt;&#x2F;p&gt;
&lt;p&gt;To add the circuit inputs you have the methods &lt;code&gt;AddPublicVariable&lt;&#x2F;code&gt;, &lt;code&gt;AddSecretVariable&lt;&#x2F;code&gt; and &lt;code&gt;AddInternalVariable&lt;&#x2F;code&gt;. Calling this methods will return an index which corresponds to the concrete value of that variable in the witness vector. The order in which you all these matters in the way that an internal current witness index (in the circuit that you’re building) is being mutated.&lt;&#x2F;p&gt;
&lt;p&gt;The circuit behaviour, which in the high-level API must be written in the &lt;code&gt;Define&lt;&#x2F;code&gt; function abstracted from the manual constraint generation, is defined constraint by constraint with the method &lt;code&gt;AddConstraint&lt;&#x2F;code&gt;. A constraint can be built initializing a &lt;code&gt;constraint.R1C&lt;&#x2F;code&gt; (in case of Groth16) or a &lt;code&gt;constraint.SparseR1C&lt;&#x2F;code&gt; (in the case of Plonk) term by term. Finally, terms can be created using the &lt;code&gt;MakeTerm&lt;&#x2F;code&gt; method.&lt;&#x2F;p&gt;
&lt;p&gt;After this, the next steps (proving and verifying) are the same as in the high level API.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;example-proving-that-x-cdot-y-z&quot;&gt;Example: proving that $x \cdot y = z$&lt;&#x2F;h4&gt;
&lt;p&gt;The next piece of code that proves that $x \cdot y = z$ where $x, z$ are public variables and $y$ a private variable (witness):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;func Example() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; [Y, Z]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    publicVariables := []fr_bn254.Element{fr_bn254.NewElement(2), fr_bn254.NewElement(6)}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; [X]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    secretVariables := []fr_bn254.Element{fr_bn254.NewElement(3)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;* R1CS Building *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; (X * Y) == Z&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; X is secret&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Y is public&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Z is public&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    r1cs := cs_bn254.NewR1CS(1)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Variables&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    _ = r1cs.AddPublicVariable(&amp;quot;1&amp;quot;) &#x2F;&#x2F; the ONE_WIRE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Y := r1cs.AddPublicVariable(&amp;quot;Y&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Z := r1cs.AddPublicVariable(&amp;quot;Z&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    X := r1cs.AddSecretVariable(&amp;quot;X&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Coefficients&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    COEFFICIENT_ONE := r1cs.FromInterface(1)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Constraints&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; (1 * X) * (1 * Y) == (1 * Z)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    constraint := constraint.R1C{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        L: constraint.LinearExpression{r1cs.MakeTerm(&amp;amp;COEFFICIENT_ONE, X)}, &#x2F;&#x2F; 1 * X&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        R: constraint.LinearExpression{r1cs.MakeTerm(&amp;amp;COEFFICIENT_ONE, Y)}, &#x2F;&#x2F; 1 * Y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        O: constraint.LinearExpression{r1cs.MakeTerm(&amp;amp;COEFFICIENT_ONE, Z)}, &#x2F;&#x2F; 1 * Z&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    r1cs.AddConstraint(constraint)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    constraints, r := r1cs.GetConstraints()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for _, r1c := range constraints {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        fmt.Println(r1c.String(r))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;* Universal SRS Generation *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pk, vk, _ := groth16.Setup(r1cs)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;* Proving *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    rightWitness := buildWitnesses(r1cs, publicVariables, secretVariables)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    p, _ := groth16.Prove(r1cs, pk, rightWitness)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;* Verification *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    publicWitness, _ := rightWitness.Public()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    verifies := groth16.Verify(p, vk, publicWitness)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    fmt.Println(&amp;quot;Verifies with the right public values :&amp;quot;, verifies == nil)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    wrongPublicVariables := []fr_bn254.Element{fr_bn254.NewElement(1), fr_bn254.NewElement(5)}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    wrongWitness := buildWitnesses(r1cs, wrongPublicVariables, secretVariables)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    wrongPublicWitness, _ := wrongWitness.Public()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    verifies = groth16.Verify(p, vk, wrongPublicWitness)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    fmt.Println(&amp;quot;Verifies with the wrong public values :&amp;quot;, verifies == nil)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For you to be able to run this, you’ll need the &lt;code&gt;buildWitness&lt;&#x2F;code&gt; function:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;func buildWitnesses(r1cs *cs_bn254.R1CS, publicVariables fr_bn254.Vector, privateVariables fr_bn254.Vector) witness.Witness {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    witnessValues := make(chan any)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    go func() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        defer close(witnessValues)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        for _, publicVariable := range publicVariables {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            witnessValues &amp;lt;- publicVariable&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        for _, privateVariable := range privateVariables {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            witnessValues &amp;lt;- privateVariable&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    witness, err := witness.New(r1cs.CurveID().ScalarField())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if err != nil {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        log.Fatal(err)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; -1 because the first variable is the ONE_WIRE.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    witness.Fill(r1cs.GetNbPublicVariables()-1, r1cs.GetNbSecretVariables(), witnessValues)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    return witness&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;a-small-bug&quot;&gt;A small bug&lt;&#x2F;h3&gt;
&lt;p&gt;There’s a minor detail when using the low-level API that you have to take into account. Maybe you’ve noticed it but if not, take a look at this line in the example above:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;_ = r1cs.AddPublicVariable(&amp;quot;1&amp;quot;) &#x2F;&#x2F; the ONE_WIRE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You’re probably wondering why this is necessary if we are not using the variable returned by the function. Well, we like to code so, let’s remove the line and the patch for this in the &lt;code&gt;buildWitness&lt;&#x2F;code&gt; function (for this patch, remove the -1 in the &lt;code&gt;witness.Fill&lt;&#x2F;code&gt; line of the function) execute the code.&lt;&#x2F;p&gt;
&lt;p&gt;When doing that you’ll get this error:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;18:32:36 ERR error=&amp;quot;invalid witness size, got 3, expected 2 = 1 (public) + 1 (secret)&amp;quot; backend=groth16 nbConstraints=1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The error says that we are specting 2 variables (1 public and 1 private) when this is wrong. We’ve already declared 3 variables (2 public and 1 private).&lt;&#x2F;p&gt;
&lt;p&gt;The reason why this happens and why the patch works is beyond the scope of this post but it’s a gnark’s implementation detail that leaked into the API. You can read more about that in this &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ConsenSys&#x2F;gnark&#x2F;issues&#x2F;544&quot;&gt;issue&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;infinite-loop-during-the-arithmetization&quot;&gt;Infinite loop during the arithmetization&lt;&#x2F;h2&gt;
&lt;p&gt;We found a small bug in the arithmetization code.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s modify a little bit our earlier Groth16’s example and&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;func Example() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; [Y, Z]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    publicVariables := []fr_bn254.Element{fr_bn254.NewElement(2), fr_bn254.NewElement(5)}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; [X]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    secretVariables := []fr_bn254.Element{fr_bn254.NewElement(5)}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;* R1CS Building *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; (X * Y) == Z + 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; X is secret&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Y is public&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Z is public&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; 5 is constant&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    r1cs := cs_bn254.NewR1CS(1)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Variables&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    _ = r1cs.AddPublicVariable(&amp;quot;1&amp;quot;) &#x2F;&#x2F; the ONE_WIRE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Y := r1cs.AddPublicVariable(&amp;quot;Y&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Z := r1cs.AddPublicVariable(&amp;quot;Z&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    X := r1cs.AddSecretVariable(&amp;quot;X&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Constants&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    FIVE := r1cs.FromInterface(5)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    CONST_FIVE_TERM := r1cs.MakeTerm(&amp;amp;FIVE, 0)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    CONST_FIVE_TERM.MarkConstant()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Coefficients&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    COEFFICIENT_ONE := r1cs.FromInterface(1)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Constraints&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; (1 * X) * (1 * Y) == (1 * Z) + (5 * 1)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    constraint := constraint.R1C{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        L: constraint.LinearExpression{r1cs.MakeTerm(&amp;amp;COEFFICIENT_ONE, X)}, &#x2F;&#x2F; 1 * X&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        R: constraint.LinearExpression{r1cs.MakeTerm(&amp;amp;COEFFICIENT_ONE, Y)}, &#x2F;&#x2F; 1 * Y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        O: constraint.LinearExpression{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            r1cs.MakeTerm(&amp;amp;COEFFICIENT_ONE, Z)}, &#x2F;&#x2F; 1 * Z 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            CONST_FIVE_TERM, &#x2F;&#x2F; 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    r1cs.AddConstraint(constraint)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    constraints, r := r1cs.GetConstraints()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for _, r1c := range constraints {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        fmt.Println(r1c.String(r))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;* Universal SRS Generation *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pk, vk, _ := groth16.Setup(r1cs)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;* Proving *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    rightWitness := buildWitnesses(r1cs, publicVariables, secretVariables)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    p, _ := groth16.Prove(r1cs, pk, rightWitness)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;* Verification *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    publicWitness, _ := rightWitness.Public()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    verifies := groth16.Verify(p, vk, publicWitness)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    fmt.Println(&amp;quot;Verifies with the right public values :&amp;quot;, verifies == nil)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    wrongPublicVariables := []fr_bn254.Element{fr_bn254.NewElement(1), fr_bn254.NewElement(5)}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    wrongWitness := buildWitnesses(r1cs, wrongPublicVariables, secretVariables)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    wrongPublicWitness, _ := wrongWitness.Public()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    verifies = groth16.Verify(p, vk, wrongPublicWitness)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    fmt.Println(&amp;quot;Verifies with the wrong public values :&amp;quot;, verifies == nil)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;At first glance it looks like this should work smoothly, but give it a try and run it. Noticed something wrong? If you tried it your answer’d be yes, because after a while you’ll end up with a &lt;code&gt;signal: killed&lt;&#x2F;code&gt; message.&lt;&#x2F;p&gt;
&lt;p&gt;No problem, let’s fix it. Simply remove the following line:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CONST_FIVE_TERM.MarkConstant()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The difference is just one line; we are making the same as above, only we are not marking the constant term as constant.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-problem&quot;&gt;The problem&lt;&#x2F;h2&gt;
&lt;p&gt;If you run the fix above, you’ll see that execution finishes successfully and everyone is happy. Well, not so fast fren. This means you, as a Gnark user, can bypass the issue and build a working circuit. A malicious user, however, can still create faulty circuits that break execution.&lt;&#x2F;p&gt;
&lt;p&gt;With this exploit, a server running a Gnark prover that accepts arbitrary circuits (Noir and Aleo Instructions are one example of languages that allow this behaviour to happen) can be brought down through a DDoS attack. A user can repeatedly send the faulty circuit shown above for execution, wasting cycles and forcing crashes over and over.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;Gnark is from our point of view one of the best for developing ZKP applications with a lot of pros and cons, depending on what you want to do. In general if you want to develop ZKP apps the high-level API would be good enough for you. In our case, we needed to go a little deeper and because of that we found some flaws.&lt;&#x2F;p&gt;
&lt;p&gt;So if you’re interested in learning more about how to develop ZKP applications using Gnark, stay tuned for our upcoming blog post. We will provide you with a step-by-step guide and show you how easy it can be to build powerful and secure ZKP applications using this amazing library.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Using Metal and Rust to make FFT even faster</title>
          <pubDate>Fri, 17 Mar 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/using-metal-and-rust-to-make-fft-even-faster/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/using-metal-and-rust-to-make-fft-even-faster/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/using-metal-and-rust-to-make-fft-even-faster/">&lt;p&gt;A couple of months ago, we wrote about &lt;a href=&quot;&#x2F;cuda-from-scratch&#x2F;&quot;&gt;CUDA&lt;&#x2F;a&gt;, a programming model developed by NVIDIA to accelerate expensive computations. We explained why, in the context of &lt;a href=&quot;&#x2F;the-hunting-of-the-zk-snark&#x2F;&quot;&gt;ZK-SNARKs&lt;&#x2F;a&gt;, it is useful for performing large multiplications.&lt;&#x2F;p&gt;
&lt;p&gt;Today, we want to discuss another development kit that provides an interface to communicate with the Graphics Processing Unit (GPU) called Metal. Metal was developed by Apple as an alternative for running code on GPUs in Mac systems. It provides its own programming language, called Metal Shading Language (MSL), for writing programs that can be executed by the GPU. Additionally, Metal provides an API designed for Swift or Objective-C to run functions written in MSL and manage resources between the CPU and GPU. In this post, we will use a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.rust-lang.org&#x2F;es&quot;&gt;Rust&lt;&#x2F;a&gt; wrapper of this API called &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gfx-rs&#x2F;metal-rs&quot;&gt;Metal-rs&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;At the time of writing this post, we are building &lt;a href=&quot;&#x2F;lambdaworks-or-how-we-decided-to-created-our-zksnarks-library-and-a-stark-prover&#x2F;&quot;&gt;Lambdaworks&lt;&#x2F;a&gt;, a library that makes it easy to program ZK-SNARKs. One of the essential operations required for using ZK-SNARKs is multiplication of polynomials that are of very high order. We can solve these operations efficently by using the Fast Fourier Transform (FFT) algorithm, which improves the complexity from $O(N^2)$ to $O(N log N)$ ($N$ being the order of the polynomial). Additionally, parallelizing all the work of this algorithm in the GPU could lead to even better results when working with these large polynomials. So that is our end goal.&lt;&#x2F;p&gt;
&lt;p&gt;The goal of this post is to learn the basics of MSL and see how to do simple computations with it. Then, we will provide a general overview of what is needed to implement FFT on the GPU. We will use the Rust Language to execute these functions and manage the resources between the CPU and GPU.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;metal-structures&quot;&gt;Metal Structures&lt;&#x2F;h2&gt;
&lt;p&gt;Metal has some general structures for facilitating communication between the CPU and GPU. To create structures in the app, which can then be passed to the GPU for executing a function, there are some necessary steps. Let’s take a look at how they work.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;metal-thread-hierarchy&quot;&gt;Metal Thread Hierarchy&lt;&#x2F;h3&gt;
&lt;p&gt;The basic idea behind parallel computation in the GPU is to run a massive amount of threads organized in different structures. Each thread is responsible for executing a portion of the overall computation, and all of these threads run simultaneously.&lt;&#x2F;p&gt;
&lt;p&gt;In our previous post about CUDA, we covered in detail &lt;a href=&quot;&#x2F;cuda-from-scratch&#x2F;#building-blocks&quot;&gt;how threads are organized&lt;&#x2F;a&gt;, and Metal’s thread structure is quite similar. To help you understand how it works, we’ll give a brief recap, but if you want to learn more, you can check out that section.&lt;&#x2F;p&gt;
&lt;p&gt;Threads are identified in a grid by a coordinate system that depends on the dimensions of the grid. For a 2D grid, the coordinate system would be (x, y). Threads are primarily grouped in threadgroups, which are further divided into Warps or SIMD groups. Threads in a warp execute the same instructions &lt;strong&gt;concurrently&lt;&#x2F;strong&gt; on different data, meaning that if a single thread in the warp were to &lt;em&gt;diverge&lt;&#x2F;em&gt; (e.g. because of an if statement) then the whole warp will execute both branches and hurt performance&lt;&#x2F;p&gt;
&lt;p&gt;Understanding this structure is essential when deciding how to split computations between threadgroups and which sizes to use for each group. We’ll provide more detail on this topic when we cover some basic examples.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;metal-device&quot;&gt;Metal Device&lt;&#x2F;h3&gt;
&lt;p&gt;The core of the Metal API is the Device, which is an abstraction that represents a GPU in code. You can identify different GPUs and use them for different purposes, but for simplicity’s sake, we’ll just use the default and let Metal automatically select the GPU from our system.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;command-queue&quot;&gt;Command Queue&lt;&#x2F;h3&gt;
&lt;p&gt;In addition to the Device, another essential object to use in Metal is the Command Queue. This represents a basic queue that receives commands, such as packages for execution on the GPU. It’s called a queue because it has a specific order in which things are executed. The command queue not only receives our inputs and functions for execution, but also a lot of other things that are necessary for Metal to work.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;command-buffers&quot;&gt;Command Buffers&lt;&#x2F;h3&gt;
&lt;p&gt;When we talked about “packages” while explaining the Command Queue, we were actually referring to Command Buffers. These buffers work as storage for the functions and computations that we want to execute on the GPU. They don’t run the computations when they are created, but when they are pushed to the Command Queue. There are a few Command Buffers for different types of actions, but the ones that we are interested in are the compute commands.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pipeline-state&quot;&gt;Pipeline State&lt;&#x2F;h3&gt;
&lt;p&gt;This structure represents the GPU state that needs to be set for a specific command. It is initialized with a specific library, which is basically all the code written in MSL that we want to run, and provides all the necessary steps for the GPU to execute it.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;encoders&quot;&gt;Encoders&lt;&#x2F;h3&gt;
&lt;p&gt;For each type of command that we want to run on the GPU using Metal, we use a dedicated type of encoder. However, all encoders serve the same purpose of creating a package that will be our command buffer. The encoder takes all the arguments of the function that we want to run, as well as its arguments and the pipeline state, and creates a package that will be executed on the GPU. One encoder can be used to create multiple commands, which will be packaged in the same command buffer.&lt;&#x2F;p&gt;
&lt;p&gt;It is important to inform Metal when we have finished encoding all the commands, so that it can push all the created buffers to the queue. We can summarize all these new structures and how they communicate with the following diagram:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;YOBNdIJ.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;To better understand how all these structures work together, it is helpful to see some basic examples.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;programming-in-msl-and-rust&quot;&gt;Programming in MSL and Rust&lt;&#x2F;h2&gt;
&lt;p&gt;For the first example we will compute a basic product between arrays.&lt;&#x2F;p&gt;
&lt;p&gt;First let see how our function looks in MSL:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;&lt;code&gt;dotprod.metal&lt;&#x2F;code&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[[kernel]]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;void dot_product(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  constant uint *inA [[buffer(0)]],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  constant uint *inB [[buffer(1)]],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  device uint *result [[buffer(2)]],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  uint index [[thread_position_in_grid]])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  result[index] = inA[index] * inB[index];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;GPU programs are typically referred to as shaders which contain functions of different types. The &lt;code&gt;kernel&lt;&#x2F;code&gt; keyword in this context means that this is a &lt;strong&gt;compute function&lt;&#x2F;strong&gt; (made for running parallel computations) and makes it accessible from our Rust code. Since we are working with a kernel, we can specify which kind of thread grid it will run on.&lt;&#x2F;p&gt;
&lt;p&gt;Some arguments can be in different address spaces, &lt;code&gt;constant&lt;&#x2F;code&gt; and &lt;code&gt;device&lt;&#x2F;code&gt; in our case. Data in the &lt;code&gt;device&lt;&#x2F;code&gt; space is available for the device’s (another way to call the GPU) to read and write into. Data in the &lt;code&gt;constant&lt;&#x2F;code&gt; space is read-only.&lt;&#x2F;p&gt;
&lt;p&gt;You may notice that the function does not contain a &lt;code&gt;for&lt;&#x2F;code&gt; loop or any similar iteration to execute the product on the array. This is because multiple threads will work in parallel, executing this operation on different positions of the arrays. When we define the dimensions of our grid and the number of threads to use, each thread is assigned a specific position (the &lt;code&gt;index&lt;&#x2F;code&gt; parameter) to execute the task simultaneously. We use this for indexing, mapping one thread to one element in both arrays.&lt;&#x2F;p&gt;
&lt;p&gt;Lastly, the &lt;code&gt;[[buffer(id)]]&lt;&#x2F;code&gt; is an attribute which identifies that a kernel argument points to a specific &lt;code&gt;buffer&lt;&#x2F;code&gt;, which is a collection of data in memory that can be shared between the CPU and the GPU. When we define these buffers (on our main app), we set an index for the GPU to create a pointer to the buffer and use it accordingly. The 0, 1, 2 refer to the indexes of the different buffers that we want the kernel to access. To simplify this further, we create the arrays in the Rust code and then copy them to the buffers. The GPU uses these indexes to know where to read and write. Although the attributes are not necessary (buffers will be maped to arguments in order), it’s a best practice to use them.&lt;&#x2F;p&gt;
&lt;p&gt;Okay, that’s it for the MSL part, so let’s switch to Rust.&lt;&#x2F;p&gt;
&lt;p&gt;First we have to declare our Device, that is our abstraction of the GPU in the code.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let device: &amp;amp;DeviceRef = &amp;amp;Device::system_default().expect(&amp;quot;No device found&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this case we let Metal assign a default GPU to use.&lt;&#x2F;p&gt;
&lt;p&gt;Next, we need to reference the function written in MSL. For that, we need to compile our &lt;code&gt;.metal&lt;&#x2F;code&gt; code to generate a &lt;code&gt;.metallib&lt;&#x2F;code&gt; file that will be the library that our Rust code will use. To compile our metal file, we need to run the following command:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;xcrun -sdk macosx metal -c dotprod.metal -o dotprod.air&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;xcrun -sdk macosx metallib dotprod.air -o dotprod.metallib&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;You’ll need Xcode tools for this, you can see how to install it &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.freecodecamp.org&#x2F;news&#x2F;how-to-download-and-install-xcode&#x2F;&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Actually, this command will create two new files:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * One with `.air` extension which is an intermidiate language that apple recommends to compile first.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The `.metallib` file that will contain our compiled MSL library.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now, we can include the new lib in our Rust code&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;const LIB_DATA: &amp;amp;[u8] = include_bytes!(&amp;quot;dotprod.metallib&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And get a reference to the lib and our function&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let lib = device.new_library_with_data(LIB_DATA).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let function = lib.get_function(&amp;quot;dot_product&amp;quot;, None).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now that we have our metal lib and the function that we want to execute, we can create the Pipeline&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let pipeline = device&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .new_compute_pipeline_state_with_function(&amp;amp;function)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next, we declare all the buffers. These buffers are copies of the structures created in Rust (arrays &lt;code&gt;v&lt;&#x2F;code&gt; and &lt;code&gt;w&lt;&#x2F;code&gt;) of the portion of memory that is shared between the CPU and the GPU.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let length = v.len() as u64;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let size = length * core::mem::size_of::&amp;lt;u32&amp;gt;() as u64;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let buffer_a = device.new_buffer_with_data(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    unsafe { mem::transmute(v.as_ptr()) }, &#x2F;&#x2F; bytes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    size, &#x2F;&#x2F; length&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MTLResourceOptions::StorageModeShared, &#x2F;&#x2F; Storage mode&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let buffer_b = device.new_buffer_with_data(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    unsafe { mem::transmute(w.as_ptr()) },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    size,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MTLResourceOptions::StorageModeShared,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let buffer_result = device.new_buffer(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    size, &#x2F;&#x2F; length&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    MTLResourceOptions::StorageModeShared, &#x2F;&#x2F; Storage mode&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We’re dealing with two arrays of &lt;code&gt;u32&lt;&#x2F;code&gt; data type, so the first thing to do is get the size in bytes of both arrays. When using the &lt;code&gt;new_buffer_with_data()&lt;&#x2F;code&gt; method, we’re essentially creating a buffer that copies the data we’re pointing to (the &lt;code&gt;transmute()&lt;&#x2F;code&gt; function reinterprets a &lt;code&gt;*u32&lt;&#x2F;code&gt; raw pointer into a &lt;code&gt;*c_void&lt;&#x2F;code&gt;). Finally, we define the storage mode. There are a few modes available for different purposes, but for this case, we use the Shared mode, which simply creates a buffer in the system memory that is accessible from both GPU and CPU. We want &lt;code&gt;buffer_result&lt;&#x2F;code&gt; to be an empty buffer, so we only need to specify its size.&lt;&#x2F;p&gt;
&lt;p&gt;Now, we create the rest of our structures&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let command_queue = device.new_command_queue();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let command_buffer = command_queue.new_command_buffer();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let compute_encoder = command_buffer.new_compute_command_encoder();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;compute_encoder.set_compute_pipeline_state(&amp;amp;pipeline);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;compute_encoder.set_buffers(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    0, &#x2F;&#x2F; start index&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;amp;[Some(&amp;amp;buffer_a), Some(&amp;amp;buffer_b), Some(&amp;amp;buffer_result)], &#x2F;&#x2F;buffers&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;amp;[0; 3], &#x2F;&#x2F;offset&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note that we define the index of our buffers in the offset parameter when we call &lt;code&gt;set_buffers&lt;&#x2F;code&gt;. That indexing is what the GPU uses to know where the resource is that it has to use. This is exactly the same as&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;compute_encoder.set_buffer(0, Some(&amp;amp;buffer_a), 0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;compute_encoder.set_buffer(0, Some(&amp;amp;buffer_b), 1);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;compute_encoder.set_buffer(0, Some(&amp;amp;buffer_result), 2);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now is the time to set up the grid and threads that will be used in our function:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let grid_size = metal::MTLSize::new(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    length, &#x2F;&#x2F;width&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1, &#x2F;&#x2F; height&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1); &#x2F;&#x2F;depth&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let threadgroup_size = metal::MTLSize::new(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    length, &#x2F;&#x2F;width&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1, &#x2F;&#x2F; height&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1); &#x2F;&#x2F;depth;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;compute_encoder.dispatch_threads(grid_size, threadgroup_size);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As shown in the snippet above, the grid has a width, height and depth, just like the threadgroup. For this example, we can think of having a one dimensional grid that is our array, with the width being the length of the array. With this sizes we will have one thread per element in our array, which is exactly what we need, considering that each thread will execute a product between two elements. After all that, we simply dispatch the threads to the encoder.&lt;&#x2F;p&gt;
&lt;p&gt;That concludes the encoding and all the resources we need to be able to execute the task on the GPU, so now we can commit.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;compute_encoder.end_encoding();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;command_buffer.commit();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;command_buffer.wait_until_completed();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The function &lt;code&gt;wait_until_completed()&lt;&#x2F;code&gt; is needed to get the results of the program but consider that the CPU will stop executing things until the GPU is finished with the task. This may not be the best solution in some cases and you may prefer to run another function after the buffer work is done via &lt;code&gt;command_buffer.add_completed_handler()&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;If we want to check that the multiplication was done right in the GPU, we need access to the content of our &lt;code&gt;buffer_result&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let ptr = buffer_result.contents() as *const u32;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let len = buffer_result.length() as usize &#x2F; mem::size_of::&amp;lt;u32&amp;gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let slice = unsafe { slice::from_raw_parts(ptr, len) };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We get the pointer to the memory location of the result buffer and the exact length of the buffer to get all the elements of our array. Using that pointer with the calculated length, we can get a &lt;code&gt;slice&lt;&#x2F;code&gt; with the multiplied elements.&lt;&#x2F;p&gt;
&lt;p&gt;All the code for this example can be found in this &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;metal_playground&#x2F;tree&#x2F;main&#x2F;examples&#x2F;dotprod&quot;&gt;Metal Playground repository&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;learning-fft&quot;&gt;Learning FFT&lt;&#x2F;h2&gt;
&lt;p&gt;We learned how all the communication with the GPU works, so now we want to see what exactly the FFT algorithm is, and why it is a great candidate to be executed on the GPU.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;dft-and-how-fft-speed-things-up&quot;&gt;DFT and how FFT speed things up&lt;&#x2F;h3&gt;
&lt;p&gt;To begin, let’s discuss another widely used algorithm in the field of physics that is closely related to FFT - the Discrete Fourier Transform (DFT).&lt;&#x2F;p&gt;
&lt;p&gt;In brief, the DFT algorithm is a mathematical operation that converts a sequence of complex numbers into another sequence of complex numbers. For our specific use case, we are interested in how we can perform faster polynomial multiplication. As multiplying two polynomials involves computing the product of each pair of coefficients and adding the resulting terms with the same degree, it requires $O(N^2)$ operations for two polynomials of degree $N$. We can do better than that.&lt;&#x2F;p&gt;
&lt;p&gt;Our polynomials are typically represented using their coefficients, which we call a coefficient representation. However, we can also represent a polynomial with a series of points - precisely $n + 1$ points. It turns out that the product of two polynomials in the coefficient representation is equal to the pointwise multiplication of their point value representation, followed by a transformation of that result back to coefficients. Therefore, all we need is a way to transform the polynomial coefficient representation to a point value representation and then back to the coefficient representation, and that’s exactly what DFT and its inverse (IDFT) do.&lt;&#x2F;p&gt;
&lt;p&gt;The transformation from coefficient form to point value form is known as the evaluation process of the polynomial, while the other way around is known as the interpolation process. However, the problem with DFT is that it does not improve the complexity of the overall computation because it performs all this magic in $O(N^2)$ operations too. This is where FFT comes in handy.&lt;&#x2F;p&gt;
&lt;p&gt;The Fast Fourier Transform (FFT) algorithm is a computational technique used to efficiently compute the DFT by exploiting its symmetry and periodicity properties. The FFT algorithm uses a divide-and-conquer approach, where the coefficients are recursively divided into smaller sub-polynomials, and the DFT of each sub-polynomial is computed separately.&lt;&#x2F;p&gt;
&lt;p&gt;The key idea behind the FFT algorithm is to decompose the DFT computation into a series of smaller, atomic DFTs, called &lt;em&gt;butterflies&lt;&#x2F;em&gt; , that can be computed efficiently using multiplication and addition operations. The FFT algorithm significantly reduces the number of operations required to compute the DFT from $O(N^2)$ to $O(N*log(N))$, making it a practical solution for large polynomials.&lt;&#x2F;p&gt;
&lt;p&gt;A FFT algorithm can have different characteristics, such as if it uses a &lt;em&gt;Decimation in Time&lt;&#x2F;em&gt; or &lt;em&gt;Decimation in Frequency&lt;&#x2F;em&gt; approach (changes the &lt;em&gt;butterfly&lt;&#x2F;em&gt; operation), if it’s &lt;em&gt;n-radix&lt;&#x2F;em&gt; (meaning that it divides the problem in &lt;em&gt;n&lt;&#x2F;em&gt; every time) or &lt;em&gt;mixed-radix&lt;&#x2F;em&gt; (divides the problem in multiple sizes), if its &lt;em&gt;ordered&lt;&#x2F;em&gt; or not and which order does it handles, and a big etcetera.&lt;&#x2F;p&gt;
&lt;p&gt;Since the entire algorithm is based on dividing the problem into two, it’s essential to ensure that the polynomials have an order that is a power of 2.&lt;&#x2F;p&gt;
&lt;p&gt;That is a lot of information so let’s see a basic overview of these ideas:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;AZqXeDk.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;working-with-finite-fields&quot;&gt;Working with finite fields&lt;&#x2F;h3&gt;
&lt;p&gt;As mentioned earlier, we explained that the DFT works with complex numbers, but in our case, that won’t be necessary because all of the polynomials and calculations are done in finite fields. A finite field is a mathematical set with a finite number of elements satisfying certain algebraic properties, namely that you can sum, multiply and divide just like you can with regular numbers.&lt;&#x2F;p&gt;
&lt;p&gt;The most common finite fields have a prime number of elements (called the &lt;em&gt;order&lt;&#x2F;em&gt; of the field), so they are also called &lt;strong&gt;prime fields&lt;&#x2F;strong&gt;. Essentially, these are just the integers with the sum and multiplication done modulo the prime order, that is, operations “wrap around” when they go over it. If you’re interested in learning more about modular arithmetic and how it works, you can check out &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Modular_arithmetic&quot;&gt;this resource&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;twiddle-factors&quot;&gt;Twiddle factors&lt;&#x2F;h3&gt;
&lt;p&gt;One key aspect to understanding how the FFT algorithm works is the concept of &lt;strong&gt;twiddle factors&lt;&#x2F;strong&gt;. These factors are essential to exploiting the symmetry and periodicity properties of polynomials and enable the evaluation process to be completed with fewer operations. Typically, these factors are referred to as roots of unity - complex numbers that equal 1 when raised to some integer power $n$. As we previously mentioned, since we are working with finite fields, the twiddle factors used in our calculations are not complex numbers, but rather elements within the field.&lt;&#x2F;p&gt;
&lt;p&gt;For example, in the field with elements ${0,1,2,3,4,5,6}$ with order $p = 7$, the number $6$ will be a $2nd$ root of unity since $6^2 mod 7 = 1$&lt;&#x2F;p&gt;
&lt;p&gt;During the process of implementing FFT, it is crucial to calculate a specific number of roots of unity. However, in order to ensure that these calculations are both accurate and feasible, we require a specific characteristic for the prime fields we use. Specifically, the prime order of the fields must follow the form of $2^n k + 1$, where the $n$ is referred to as the “two-adicity” of the field. This condition guarantees that we can compute all necessary roots of unity to successfully carry out the FFT algorithm.&lt;&#x2F;p&gt;
&lt;p&gt;Furthermore, when calculating the twiddle factors, we will determine a “primitive root of unity”, which enables us to easily obtain other primitive roots by raising it to the required $n_{th}$ power.&lt;&#x2F;p&gt;
&lt;p&gt;This is just an introduction to the FFT algorithm, so don’t worry if everything isn’t clear yet. There are many intricacies involved in making this algorithm work, and additional calculations are required. To learn more about the FFT algorithm and how it operates, we highly recommend watching this &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=h7apO7q16V0&quot;&gt;excellent video&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;Metal serves as a great alternative to CUDA on Mac systems, allowing us to perform expensive computations much faster. However, using Metal requires an understanding of its structures and new concepts in addition to the algorithm and code we want to run. We hope this post helped provide some clarity on those concepts.&lt;&#x2F;p&gt;
&lt;p&gt;On another note, we’ve been exploring FFT, one of the greatest and most commonly used algorithms in the ZK world. Some of the mathematical concepts behind FFT are more complex and we want to explain those topics more in depth with more examples. Stay tuned for future posts on this exciting topic to learn how to bring it to code.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Better sane defaults in Zero Knowledge Proofs libraries or how to get the prover&#x27;s private key</title>
          <pubDate>Thu, 09 Mar 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/better-sane-defaults-in-zero-knowledge-proofs-libraries-or-how-to-get-the-prover-private-key/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/better-sane-defaults-in-zero-knowledge-proofs-libraries-or-how-to-get-the-prover-private-key/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/better-sane-defaults-in-zero-knowledge-proofs-libraries-or-how-to-get-the-prover-private-key/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;Many ZK libraries allow the creation of pair of points $(x,y)$ which do not belong to the elliptic curve they are working with when building circuits. Some also do not check that the points belong to the appropriate subgroup, which can lead to vulnerabilities.&lt;&#x2F;p&gt;
&lt;p&gt;The argument being made is that invalid points should not reach a prover. What is more surprising is that we would expect the example code or applications to tackle this issue, but they do not. They are not even giving thought to whether these additional checks are needed or not. Of course, many are worried about benchmarks since adding the constraints would make things slower, but removing the safety net and ignoring some attacks published many years ago is not a good long-term strategy. Even if these checks aren’t part of the prover, they must be somewhere and in many cases they aren’t! If builders take points, like Public Keys, from untrusted users, their system may be compromised, and secret keys may get stolen.&lt;&#x2F;p&gt;
&lt;p&gt;Secret keys may reveal encrypted data or hold access to funds the server may need to operate.&lt;&#x2F;p&gt;
&lt;p&gt;Going back to the checks, as we said before, they may not be needed if the application validates inputs before they reach the prover or if there is a thoughtful analysis of the protocol.&lt;&#x2F;p&gt;
&lt;p&gt;But the first solution, while easy, may lead to censorship. Why should a prover reject a proof generation, saying the input is invalid, without proof that it is invalid?&lt;&#x2F;p&gt;
&lt;p&gt;If there’s another bug in the code, there may be even more issues since a malicious user may have even more ways to scramble the program.&lt;&#x2F;p&gt;
&lt;p&gt;In a practical example, some weeks ago, we found a bug that allows us to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dusk-network&#x2F;plonk&#x2F;pull&#x2F;721&#x2F;files&quot;&gt;make the prover believe two points are equal when they are not&lt;&#x2F;a&gt;. Basically, they did not check that, given $A=(x_A,y_A)$ and $B=(x_B,y_B)$, $y_A=y_B$. If they check the points are in the elliptic curve, then necessarily, for the same $x=x_A=x_B$, there are only two possibilities, either $y_A=y_B$ or $y_A=-y_B$, since they have to satisfy the curve’s equation. If there is no such check (because the developer did not deem it necessary), then there are as many values as the order of the prime field for the $y$ coordinate.&lt;&#x2F;p&gt;
&lt;p&gt;So, even if the protocol is not vulnerable, it is a good idea and engineering practice to keep some extra checks as a &lt;em&gt;“defense in depth”&lt;&#x2F;em&gt; , to make the program more robust in case there are any other bugs that may be used in tandem with the lack of verifications to create exploits.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-history-of-attacks-and-vulnerabilities&quot;&gt;A history of attacks and vulnerabilities.&lt;&#x2F;h2&gt;
&lt;p&gt;The issue of not checking that a point belongs to a subgroup was first reported in 1997 by Chae Hoon Lira and Pil Joong Lee in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.iacr.org&#x2F;archive&#x2F;crypto2000&#x2F;18800131&#x2F;18800131.pdf&quot;&gt; “A Key Recovery Attack on Discrete Log-based Schemes Using a Prime Order Subgroup”&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Meanwhile, the issue with not checking bad curves was first reported in the year 2000 by Bhiel in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.iacr.org&#x2F;archive&#x2F;crypto2000&#x2F;18800131&#x2F;18800131.pdf&quot;&gt; “Differential fault attacks on elliptic curve cryptosystems “&lt;&#x2F;a&gt;. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2017&#x2F;554.pdf&quot;&gt;This article&lt;&#x2F;a&gt; also shows some problems when the code does not verify belonging to the elliptic curve.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s see how this exploit works with an example. We can write elliptic curves in Weierstrass form,&lt;br &#x2F;&gt;
$$ y^2 = x^3 +a x + b $$&lt;br &#x2F;&gt;
One crucial fact is that addition and doubling formulas do not depend on the value $b$. This means that two curves $E$ and $E^\prime$ have the same operations if they only differ in $b$. The curve $E^\prime$ is called an invalid curve relative to $E$, and an attacker may choose an $E^\prime$ with much weaker security.&lt;&#x2F;p&gt;
&lt;p&gt;Suppose an attacker sends some point $Q$ of low order $k$ (the simplest case is $k=2$, which means that $2Q=\mathcal{O}$). If the attacker performs a key exchange with the user $A$ to derive a shared key $K=KDF(sk_A Q)$ and $A$ sends some message $m$ to the attacker, then he can learn $sk \equiv sk_k \pmod{k}$&lt;&#x2F;p&gt;
&lt;p&gt;If the attacker repeats this process several times (using points of different order, all coprime), possibly using different invalid curves, he gets a system of congruences.&lt;&#x2F;p&gt;
&lt;p&gt;$sk\equiv sk_1 \pmod{k_1}$&lt;br &#x2F;&gt;
$sk\equiv sk_2 \pmod{k_2}$&lt;br &#x2F;&gt;
$sk\equiv sk_3 \pmod{k_3}$&lt;br &#x2F;&gt;
$sk\equiv sk_4 \pmod{k_4}$&lt;&#x2F;p&gt;
&lt;p&gt;Then, he can use the Chinese Remainder Theorem to reconstruct $sk$ or at least a list of candidates and solve the remaining problem with brute force search. This leads to the attacker learning the secret key and impersonating the server or user, and even signing transactions on behalf of the user (leading to fund stealing, for example)&lt;&#x2F;p&gt;
&lt;p&gt;We can extend this attack for protocols with a key exchange that starts diverging from the straightforward original example. For another example, see &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;link.springer.com&#x2F;chapter&#x2F;10.1007&#x2F;978-3-319-24174-6_21#Sec12&quot;&gt;Practical Invalid Curve Attacks on TLS-ECDH&lt;br &#x2F;&gt;
&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;Many cryptographic libraries for zero-knowledge-proof applications remove or ignore some basic checks on elliptic curves, which can lead to vulnerabilities. We’re talking with the contributors of the libraries to fix these issues and disclose them.&lt;&#x2F;p&gt;
&lt;p&gt;Even if they have been known for over 20 years, eagerness for performance has led to ignoring these issues, creating potential problems for developers building on top of these libraries. The question remains then, how far are our applications from these kinds of exploits, and how careful will the programmers be when handling data that can be poisoned.&lt;&#x2F;p&gt;
&lt;p&gt;Good defaults are important. From our point of view, all the checks should be done by default in libraries and if they aren’t this should be made mor explicit. Good examples with sane defaults should be part of the libraries. Leaving the optimizing of code by removing checks for highly audited code where skipping those checks gives a real improvement to real users.&lt;&#x2F;p&gt;
&lt;p&gt;Thanks to Diego Kingston and Mauro Toscano from LambdaClass for helping write this.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>How we are shaping the future of modular blockchains with  Zero Knowledge Proof, Starknet and Ethereum</title>
          <pubDate>Tue, 07 Mar 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/how-we-are-shaping-the-future-of-modular-blockchains-with-zero-knowledge-proof-verifications-in-ethereum/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/how-we-are-shaping-the-future-of-modular-blockchains-with-zero-knowledge-proof-verifications-in-ethereum/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/how-we-are-shaping-the-future-of-modular-blockchains-with-zero-knowledge-proof-verifications-in-ethereum/">&lt;p&gt;We believe in a permissionless future where individuals can cooperate and coordinate in scalable blockchain environments. With ten years of experience in distributed systems and a new obsession with cryptography, we can help builders achieve their goals.&lt;&#x2F;p&gt;
&lt;p&gt;To realize this future, we believe that developers don’t have all the tooling necessary to create products that compete with the UI&#x2F;UX of Web2. For the past year, we have been collaborating with StarkWare because the technology they have brought to the world will allow us to fulfill this objective. Specifically, STARKs and Cairo have not only been a major breakthrough in Computer Science but have also been battle-tested in StarkEx and, more recently it’s starting to be tested in Starknet.&lt;&#x2F;p&gt;
&lt;p&gt;Unlike most other solutions, StarkEx has been in production for years, already serving millions of users and facilitating over 850B USD in trades since its inception. It’s not a permisionless system. That what Starknet brings to the table. It’s ecosystem already has more than 900 experienced and talented developers bringing new products to the world. We are confident that while Starknet may encounter problems but we know that we will be able to overcome them. We trust that the quality of engineers at StarkWare, in our own team and the Starknet community is between the bests of the world.&lt;&#x2F;p&gt;
&lt;p&gt;We do recognize that there is still much work to be done. Specifically, it’s really important to be able to launch sequencers and provers. We also want to have light clients and support interoperable protocols such as IBC. A great example of this is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;polymerlabs.medium.com&#x2F;zkmint-the-first-zk-friendly-tendermint-consensus-engine-116000b9d4f9&quot;&gt;zkMint&lt;&#x2F;a&gt;. These are some examples of the things that are missing to build the future of modular blockchains:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Sovereign rollups where the data availability is stored in another chain like Bitcoin, Celestia or other systems&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Hybrid rollups using both optimistic and zero-knowledge techniques to get the best of both worlds&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * ZK Storage proofs to be able to move assets between chains in a safer manner&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Safer wrapped assets&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Multichain orderbooks that uses the liquidity of multiple chains&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We’re working to create internally and with other companies to build these tools and products.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;our-work-in-the-starknet-ecosystem&quot;&gt;Our work in the Starknet ecosystem:&lt;&#x2F;h3&gt;
&lt;p&gt;We developed &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;cairo-rs&quot;&gt;cairo-rs&lt;&#x2F;a&gt;, which is now 150 times faster than the initial implementation. Over the last three months we worked over in our implementation of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;starknet_in_rust&quot;&gt;starknet_in_rust&lt;&#x2F;a&gt;. With starknet in rust and the cairo-rs vm we can now receive and execute transactions.&lt;&#x2F;p&gt;
&lt;p&gt;We have been also making great progress on a Cairo STARK prover in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&quot;&gt;LambdaWorks&lt;&#x2F;a&gt;. LambdaWorks is a library designed for building provers and verifiers for SNARKs in general but the first thing we built is the Cairo STARK prover. We still have to implement the proving of builtins. Hopefully with the help of Starkware we will have this done in the upcoming weeks.&lt;&#x2F;p&gt;
&lt;p&gt;We’re also working on a Proof of Concept for a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;starknet_tendermint_sequencer&quot;&gt;Starknet sequencer built with Tendermint Core&lt;&#x2F;a&gt; that can be used as learning path to decentralize L2 such as Starknet. Yesterday we were happy to learn that the community took this effort and added support for Sovereign Rollups on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;celestia.space&#x2F;&quot;&gt;Celestia&lt;&#x2F;a&gt; using &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rollkit&#x2F;&quot;&gt;Rollkit&lt;&#x2F;a&gt;. We’re also working in a Sovereign Rollup to Bitcoin with Cairo and Starknet.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;broke: starknet as rollup with enshrined settlement layer&lt;br &#x2F;&gt;
woke: starknet as sovereign rollup on celestia&lt;&#x2F;p&gt;
&lt;p&gt;starknet &amp;lt;&amp;gt; rollkit &amp;lt;&amp;gt; celestia &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;t.co&#x2F;h77HajcL2j&quot;&gt;pic.twitter.com&#x2F;h77HajcL2j&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;— kari (@ammarif_) &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;ammarif_&#x2F;status&#x2F;1632680324290453506?ref_src=twsrc%5Etfw&quot;&gt;March 6, 2023&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The Starknet sequencer will be &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;starkware&#x2F;starknet-on-to-the-next-challenge-96a39de7717&quot;&gt;decentralized&lt;&#x2F;a&gt;. With multiple sequencers it would be unnecessary to generate a execution trace since the sequencers can compare their results and let the prover generate the trace and the proof that is then checked in Ethereum L1.&lt;br &#x2F;&gt;
This allows us to compile Cairo 1.0 into &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mlir.llvm.org&#x2F;&quot;&gt;MLIR&lt;&#x2F;a&gt; so that they can be executed in a much faster manner from the sequencer. Therefore we are currently working on a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;cairo_sierra_2_MLIR&quot;&gt;Cairo to MLIR compiler&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It’s very unlikely that Starknet will implement an hybrid approach with Optimistic and at the same time ZK rollup but it would be possible to do it. In addition to this as we have mentioned before data availabilty could be done in a different chain.&lt;&#x2F;p&gt;
&lt;p&gt;We’re also working on other projects in Starknet that will be made public in the upcoming weeks.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;how-we-think-that-zk-can-empower-builders-to-create-a-future-with-modular-blockchains-and-more-powerful-applications&quot;&gt;How we think that ZK can empower builders to create a future with modular blockchains and more powerful applications&lt;&#x2F;h3&gt;
&lt;p&gt;We are also trying to help projects that will help create a modular ecosystem but that have Ethereum and ZK as the main building blocks.&lt;&#x2F;p&gt;
&lt;p&gt;Some of these projects are:&lt;br &#x2F;&gt;
&lt;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.herodotus.dev&#x2F;&quot;&gt;Herodotus&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
The Herodotus team is trying to bring interoperability and synchronism back to the Ethereum ecosystem. To do so, they leverage a cryptographic protocol called Storage Proofs that allows developers to read, access, and process on-chain data. Developers will utilize Storage Proofs to process data from Chain A to execute certain logic on Chain B. This is incredibly useful for build multichain (L2 to L2 for now only) applications like secure bridges and multichain lending.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.gizatech.xyz&#x2F;&quot;&gt;Giza&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
On the other hand, Giza is utilizing Cairo to make on-chain Machine Learning a reality. This will be incredibly useful for on-chain gaming, advanced DeFi protocols, and zkML. That said we think that once the proving part is done in a faster way it will be possible to prove the training and inference of ML models. This will be crucial to run complex ML models off chain and verify them on chain.&lt;&#x2F;p&gt;
&lt;p&gt;We understand that this will not be a simple road, but we are excited to embark on this journey with our partners and test our abilities. In the last few years, here at LambdaClass, we have become a software powerhouse that specializes in developing critical infrastructure and our own products. We have had incredible growth, but we also believe we must empower other developer teams and communities, so stay tuned for further updates on our progress.&lt;&#x2F;p&gt;
&lt;p&gt;If you want to hack with us, send us an email at &lt;a href=&quot;mailto:federico@lambdaclass.com&quot;&gt;federico@lambdaclass.com&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Diving DEEP FRI in the STARK world: learning your daily moon math with a concrete example</title>
          <pubDate>Mon, 06 Mar 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/diving-deep-fri/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/diving-deep-fri/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/diving-deep-fri/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;At LambdaClass, we are building &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&quot;&gt;Lambdaworks&lt;&#x2F;a&gt;, a library for developing zero-knowledge stuff. One important proof system is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2018&#x2F;046.pdf&quot;&gt;STARKs&lt;&#x2F;a&gt; (Scalable, transparent arguments of knowledge). STARKs are a powerful tool that allows us to prove the integrity of a given computation. For an overview of STARKs, you can look at our &lt;a href=&quot;&#x2F;lambdaworks-or-how-we-decided-to-created-our-zksnarks-library-and-a-stark-prover&#x2F;t&quot;&gt;previous post&lt;&#x2F;a&gt; or the excellent tutorials by Starkware, such as &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;starkware.co&#x2F;stark-101&#x2F;&quot;&gt;STARK-101&lt;&#x2F;a&gt; (for the rust version, you can follow &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;STARK101-rs&#x2F;&quot;&gt;this link&lt;&#x2F;a&gt;) and the posts on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;starkware&#x2F;arithmetization-i-15c046390862&quot;&gt;arithmetization I&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;starkware&#x2F;arithmetization-ii-403c3b3f4355&quot;&gt;II&lt;&#x2F;a&gt;, and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;aszepieniec.github.io&#x2F;stark-anatomy&#x2F;overview&quot;&gt;Anatomy of a STARK&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;In this post, we will do a pen-and-paper example of STARKs, so we can follow all the steps needed to generate and validate a proof (we will skip the hashing part, though). One important aspect to point out is that, in this case, we are not interested in the security properties of what we do (but it should really matter in real life). Let’s jump into the problem…&lt;&#x2F;p&gt;
&lt;h2 id=&quot;problem-statement&quot;&gt;Problem statement&lt;&#x2F;h2&gt;
&lt;p&gt;Suppose we want to compute a sequence given by the following relations:&lt;br &#x2F;&gt;
$a_0=3$&lt;br &#x2F;&gt;
$a_{n+1}={a_n}^2$&lt;br &#x2F;&gt;
The sequence gives the square of the previous number, starting with the value 3. We will use as modulus the prime 17 (a Fermat prime, $2^4+1$), and we will understand all operations done modulo 17. The advantage of 17 is that it contains a multiplicative group of 16 elements, which is helpful for STARKs (in general, we want $p-1$ to be $2^m\times q$, where $m$ should be sufficiently large and $q$ is an odd prime). The first four elements of the sequence are:&lt;br &#x2F;&gt;
$a_0 = 3$&lt;br &#x2F;&gt;
$a_1 = {a_0}^2 = 9$&lt;br &#x2F;&gt;
$a_2 = {a_1}^2 = 9^2 = 81 \equiv 13 \pmod{17}$&lt;br &#x2F;&gt;
$a_3 = {a_2}^2 = 13^2 = 169 \equiv 16 \pmod{17}$&lt;br &#x2F;&gt;
The first step is to interpret these values as evaluations of a polynomial over a suitable domain. We are working with $p=17$, whose multiplicative group has 16 elements: $\{ 1 , 2 , 3 , 4 , \dots , 15 , 16 \}$. We will choose the following subgroup $D_t = {1 , 13 , 16, 4 }$, which is none other than the group formed by all powers of $13$ modulo $17$:&lt;br &#x2F;&gt;
$13^0 = 1$&lt;br &#x2F;&gt;
$13^1 = 13$&lt;br &#x2F;&gt;
$13^2 = 169 \equiv 16 \pmod{17}$&lt;br &#x2F;&gt;
$13^3 \equiv 4 \pmod{17}$&lt;br &#x2F;&gt;
$13^4 \equiv 1 \pmod{17}$&lt;br &#x2F;&gt;
From now on, we will drop the $\pmod{17}$ as understood from the context. We see that the powers of $13$ repeat every 4, which is the order of the element in the multiplicative group. Using this and calling the polynomial interpolating the trace as $t(x)$, we have:&lt;br &#x2F;&gt;
$t(1) = 3$&lt;br &#x2F;&gt;
$t(13) = 9$&lt;br &#x2F;&gt;
$t(16) = 13$&lt;br &#x2F;&gt;
$t(4) = 16$&lt;&#x2F;p&gt;
&lt;h2 id=&quot;interpolation&quot;&gt;Interpolation&lt;&#x2F;h2&gt;
&lt;p&gt;We can use Lagrange interpolation to find the polynomial (for larger problems, it is best to use the Fast-Fourier Transform):&lt;br &#x2F;&gt;
$t(x) = L_1(x)t(1) + L_2(x)t(13) + L_3(x)t(16) + L_4(x)t(4)$&lt;br &#x2F;&gt;
The Lagrange polynomial $L_1(x)$ is given by&lt;br &#x2F;&gt;
$$L_1(x) = \frac{(x-13)(x-16)(x-4)}{(1-13)(1-16)(1-4)}$$&lt;br &#x2F;&gt;
Doing the operations, we get&lt;br &#x2F;&gt;
$L_1 (x)t(1) = 5(x^3 + x^2 + x + 1)$&lt;br &#x2F;&gt;
Th other polynomials are&lt;br &#x2F;&gt;
$L_2 (x)t(13) = 8x^3 + 2x^2 + 9x + 15$&lt;br &#x2F;&gt;
$L_3 (x)t(16) = x^3 + 16x^2 + x + 16$&lt;br &#x2F;&gt;
$L_4 (x)t(4) = 16x^3 + 13x^2 + x + 4$&lt;br &#x2F;&gt;
The trace interpolating polynomial is thus&lt;br &#x2F;&gt;
$t(x) = 13x^3 + 2x^2 + 16x + 6$&lt;br &#x2F;&gt;
If we evaluate the polynomial at $D_t$, you can check that we get the same values as in the trace execution table.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;committing-to-the-trace-polynomial&quot;&gt;Committing to the trace polynomial&lt;&#x2F;h2&gt;
&lt;p&gt;We have to commit to the trace interpolating polynomial. To do so, we perform a low-degree extension by choosing a larger domain, different from the original domain. If we choose $h = 9$ and its powers, we get a cyclic subgroup with $8$ elements, $\{ h^0 , h^1 , h^2 , \dots , h^7 \}$. This group contains elements from $D_t$, so we shift it to another domain by introducing an element from the coset, $w$, and forming the following domain,&lt;br &#x2F;&gt;
$$ D_0 = \{ wh^0 , wh^1 , wh^2, \dots , wh^7 \}$$&lt;br &#x2F;&gt;
We can choose $w = 3$, and so the domain becomes&lt;br &#x2F;&gt;
$$ D_0 = \{ 3, 10, 5, 11, 14 , 7 , 12 , 6 \}$$&lt;br &#x2F;&gt;
To commit, we evaluate $t(x)$ over all values in $D_0$ and form a Merkle tree whose leaves are those values.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;$x$&lt;&#x2F;th&gt;&lt;th&gt;$t(x)$&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;15&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;5&lt;&#x2F;td&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;11&lt;&#x2F;td&gt;&lt;td&gt;13&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;td&gt;16&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;6&lt;&#x2F;td&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;enter-the-constraints&quot;&gt;Enter the constraints&lt;&#x2F;h2&gt;
&lt;p&gt;We now need to focus on the constraints over the trace elements the calculation gives. In this problem, we have two constraints:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Boundary condition. This applies to the first row, where $t(1)=3$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Transition constraint. These are given by the multivariate polynomial $P(x,y) = y - x^2$, where if $x = a_n$, then $y = a_{n+1}$.  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;What we need to do at this point is compose the trace polynomial with these constraints to enforce them over the whole trace.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;boundary-constraint&quot;&gt;Boundary constraint&lt;&#x2F;h3&gt;
&lt;p&gt;The first constraint is&lt;br &#x2F;&gt;
$p_1 (x) = t(x)-3$&lt;br &#x2F;&gt;
To ensure that it is enforced on the first step, the polynomial $p_1 (x)$ must be divisible by $x-1$ (a property of polynomials says that $p(a)=b$ if and only if $r(x) = p(x)-b$ is divisible by $x-a$).&lt;br &#x2F;&gt;
We have&lt;br &#x2F;&gt;
$p_1 (x) = 13x^3 + 2x^2 + 16x + 3$&lt;br &#x2F;&gt;
If we factorize this polynomial, we get&lt;br &#x2F;&gt;
$p_1 (x) = 13(x-1)(x^2 + 9x + 5)$&lt;br &#x2F;&gt;
which has the factor $(x-1)$. If we divide, we get&lt;br &#x2F;&gt;
$C_1 (x) = 13 (x^2 + 9x + 5)$&lt;br &#x2F;&gt;
You can check that if we want $t (x) - a$ to be divisible by $x-1$, the necessarily $a=3$.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;transition-verification-constraint&quot;&gt;Transition verification constraint&lt;&#x2F;h3&gt;
&lt;p&gt;To evaluate the second constraint, we need to be able to choose an element of the trace and the next. We can do it by noting that the elements of $D_t$ are generated by $g = 13$, so if we select $x=x_0$, then $y=g x_0$ is the next. So, $y=t(gx)=t(13x)$ and&lt;br &#x2F;&gt;
$t(gx) = x^3 + 15x^2 + 4x + 6$&lt;br &#x2F;&gt;
We now replace these polynomials into the transition verification polynomial, $P(x,y)$, to get $p_2(x)$&lt;br &#x2F;&gt;
$p_2 (x) = P(t(x) , t(gx)) = x^6 + 16 x^5 + 5x^4 + 2x^3 + 7x^2 + 16x + 4$&lt;br &#x2F;&gt;
You can check that if we choose $x \in {1, 13, 16 }$ the polynomial evaluates to $0$. This is expected, since the elements $a_n$ and $a_{n+1}$ are linked by the formula $a_{n+1}= {a_n}^2$. This is no longer the case for $4$ since there is no next element. As before, if the constraints are valid, then $p_2 (x)$ should be divisible by $Z_2 (x)$, which is the vanishing polynomial over the domain where the constraints are enforced. In our case,&lt;br &#x2F;&gt;
$Z_2 (x) = (x-1)(x-13)(x-16)$&lt;br &#x2F;&gt;
We can also write it as&lt;br &#x2F;&gt;
$$Z_2 = \frac{x^4 - 1}{x-4}$$&lt;br &#x2F;&gt;
where we just remove the elements in which the constraints are not enforced. We verified that $p_2 (x)=0$ for $x \in {1, 13, 16 }$, so $p_2 (x)$ has factors $(x-1)(x-13)(x-16)$. Its complete factorization is&lt;br &#x2F;&gt;
$p_2 (x) = (x-1)(x-13)(x-16)(x^3 + 12 x^2 + 9x + 16)$&lt;br &#x2F;&gt;
Thus,&lt;br &#x2F;&gt;
$$C_2 (x) = \frac{p_2 (x)}{Z_2 (x)} = x^3 + 12 x^2 + 9x + 16$$&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-constraint-composition-polynomial&quot;&gt;The (constraint) composition polynomial&lt;&#x2F;h2&gt;
&lt;p&gt;We are now in a condition to build the composition polynomial&lt;br &#x2F;&gt;
$$H(x) = C_1 (x) (\alpha_1 x^{ D - D_1 } + \beta_1 ) + C_2 (x) (\alpha_2 x^{ D - D_2 } + \beta_2 )$$&lt;br &#x2F;&gt;
where the $\alpha_k$ and $\beta_k$ are values provided by the verifier. The terms $D - D_k$ are added so that all the polynomials in the linear combination have the same degree. We want the total degree to be a power of $2$, so $D=4$.&lt;&#x2F;p&gt;
&lt;p&gt;Suppose the verifier samples as random coefficients the following: $\alpha_1 = 1$, $\beta_1 = 3$, $\alpha_2 = 2$, $\beta_2 = 4$. Then,&lt;br &#x2F;&gt;
$C_1 (x) (1 x^{ 4 - 2 } + 3 ) = 13x^4 + 15 x^3 + 2 x^2 + 11x + 8$&lt;br &#x2F;&gt;
$C_2 (x) (2 x^{ 4 - 3 } + 4 ) = 2x^4 + 11 x^3 + 15 x^2 + 13$&lt;br &#x2F;&gt;
Then,&lt;br &#x2F;&gt;
$H (x) = 15 x^4 + 9 x^3 + 11 x + 4$&lt;br &#x2F;&gt;
Splitting the polynomial into odd and even terms,&lt;br &#x2F;&gt;
$H_1 (x^2) = 15 x^4 + 4$&lt;br &#x2F;&gt;
$H_2 (x^2) = 9x^2 + 11$&lt;br &#x2F;&gt;
so that&lt;br &#x2F;&gt;
$H(x) = H_1 ( x^2 ) + x H_2 (x^2)$&lt;br &#x2F;&gt;
We can commit to the polynomial $H(x)$ or its parts, $H_1(x)$ and $H_2(x)$ by evaluating over $D_0$ and forming a Merkle tree.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;$x$&lt;&#x2F;th&gt;&lt;th&gt;$H_1(x)$&lt;&#x2F;th&gt;&lt;th&gt;$H_2(x)$&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;td&gt;13&lt;&#x2F;td&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;5&lt;&#x2F;td&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;td&gt;15&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;11&lt;&#x2F;td&gt;&lt;td&gt;13&lt;&#x2F;td&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;sampling-outside-the-original-domain&quot;&gt;Sampling outside the original domain&lt;&#x2F;h2&gt;
&lt;p&gt;The verifier now chooses a random point, $z$, outside the trace interpolation and evaluation domains. In our example, the points outside those are $\{ 2, 8, 9 , 15 \}$. Suppose the verifier selected $z = 8$. Then,&lt;br &#x2F;&gt;
$H ( 8 ) = 10$&lt;br &#x2F;&gt;
with each part being&lt;br &#x2F;&gt;
$H_1 (8^2) = 6$&lt;br &#x2F;&gt;
$H_2 (8^2) = 9$&lt;br &#x2F;&gt;
We need to check that the composition polynomial and trace elements are related. To be able to evaluate the constraints numerically, we need both $t(z)$ and $t(gz)$ (remember, $g$ is the generator of the trace interpolating domain) since we have to calculate $P(x,y)$. The necessary values are:&lt;br &#x2F;&gt;
$t(8) = 16$&lt;br &#x2F;&gt;
$t(13 \times 8) = t(2) = 14$&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-does-the-verifier-need-this&quot;&gt;Why does the verifier need this?&lt;&#x2F;h2&gt;
&lt;p&gt;The verifier can now check that the trace and composition polynomial are related:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. $p_1 (8) = t(8) - 3 = 13$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. $Z_1 (8) = 8 - 1 = 7$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. $C_1 (8) = p_1 (8) &#x2F; Z_1 (8) = 13 \times 7^{-1} = 14$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. $C_1 (8) (1\times 8^2 +3) = 3$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. $p_2 (8) = t(2) - t(8)^2 = 13$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    6. $Z_2 (8) = 8$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    7. $C_2 (8) = p_2 (8)&#x2F; Z_2 (8) = 13 \times 8^{-1} = 8$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    8. $C_2 (8) (2\times 8 +4) = 7$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    9. $H (8) = C_1 (8) + C_2 (8) = 3 + 7 = 10$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We see that the evaluation of $H_1 (z^2)$ and $H_2 (z^2)$ matches the calculation of $H(z)$ from the trace elements.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ensuring-the-prover-does-not-cheat&quot;&gt;Ensuring the prover does not cheat&lt;&#x2F;h2&gt;
&lt;p&gt;How does the verifier check that the values we passed are indeed the trace and composition polynomial evaluations at $z$ and $gz$? We can use the same trick: if the polynomial $y(x)$ evaluates to $b$ in $x=a$, then $y(x) - b$ is divisible by $x - a$. We form the DEEP composition polynomial,&lt;br &#x2F;&gt;
$$ P_0 (x) = \gamma_1\frac{t(x)-t(z)}{x-z} + \gamma_2 \frac{t(x)- t(gz)}{x-gz}+\gamma_3 \frac{H_1 (x^2) - H_1 (z^2) }{x-z^2 } + \gamma_4 \frac{H_2 (x^2) - H_2 (z^2) }{x - z^2}$$&lt;br &#x2F;&gt;
Let’s calculate each term&lt;br &#x2F;&gt;
$$\frac{t(x)-t(8)}{x-8} = 13(x+13)(x+3) = 13 (x^2 + 16 x + 5)$$&lt;br &#x2F;&gt;
$$\frac{t(x)-t(2)}{x-2} = 13(x+8)(x+2) = 13 (x^2 + 10 x + 16)$$&lt;br &#x2F;&gt;
$$\frac{H_1 (x^2) - H_1 (8^2) }{x-8^2 } = 15(x+15)(x+8)(x+2) $$&lt;br &#x2F;&gt;
$$\frac{H_2 (x^2) - H_1 (8^2) }{x-8^2 } = 9(x+8) $$&lt;&#x2F;p&gt;
&lt;p&gt;Each term is a polynomial, so the linear combination is also a polynomial. By applying the FRI protocol, we must prove to the verifier that this is close to a low-degree polynomial. The polynomial is (using $\gamma_i = 1$),&lt;br &#x2F;&gt;
$P_0 ( x ) = 15 x^3 + 15 x + 1$&lt;br &#x2F;&gt;
We can commit to this polynomial using $D_0$ and forming a Merkle tree,&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;$x$&lt;&#x2F;th&gt;&lt;th&gt;$P_0(x)$&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;9&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;5&lt;&#x2F;td&gt;&lt;td&gt;13&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;11&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;td&gt;15&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;td&gt;6&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;6&lt;&#x2F;td&gt;&lt;td&gt;16&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Splitting into odd and even terms,&lt;br &#x2F;&gt;
$xP_{0,odd} (x) = 15 x^3 + 15 x$&lt;br &#x2F;&gt;
$P_{0,even} (x) = 1$&lt;br &#x2F;&gt;
The verifier samples $\beta_0 = 4$. Then,&lt;br &#x2F;&gt;
$P_1 (y=x^2) = 9y +10$&lt;br &#x2F;&gt;
The domain is given by points of the form $y=x^2$, so $D_1 = \{ 9, 15, 8, 2\}$. The leaves of the Merkle tree are&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;$y$&lt;&#x2F;th&gt;&lt;th&gt;$P_1(y)$&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;9&lt;&#x2F;td&gt;&lt;td&gt;6&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;15&lt;&#x2F;td&gt;&lt;td&gt;9&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;td&gt;11&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;We repeat the process,&lt;br &#x2F;&gt;
$yP_{0,odd} (y) = 9y$&lt;br &#x2F;&gt;
$P_{0,even} (y) = 10$&lt;br &#x2F;&gt;
The verifier samples $\beta_1 = 3$&lt;br &#x2F;&gt;
$P_2 (z=y^2) = 3$.&lt;br &#x2F;&gt;
And we ended with a constant polynomial. This second domain is $D_2 = \{13, 4\}$&lt;&#x2F;p&gt;
&lt;h2 id=&quot;checking-fri-layers&quot;&gt;Checking FRI layers&lt;&#x2F;h2&gt;
&lt;p&gt;To generate the proof, the verifier chooses an element from $D_0$. We have to send him all the elements needed to reconstruct the evaluations of the composition polynomial and the FRI steps. Say he chooses $x=10$, which corresponds to the index equal to $1$. To evaluate everything, we must pass the evaluation at $x$ and $-x$ for each layer and the trace polynomial evaluated at $x$ and $gx$.&lt;&#x2F;p&gt;
&lt;p&gt;From $P_0(x)$ we pass the values $P_0(x=10)=4$ and $P_0(x=7)=15$, together with their authentication paths.&lt;br &#x2F;&gt;
From $P_1(x)$ we pass the values $P_1(x=15)=9$ and $P_1(x=2)=11$ and their authentication paths.&lt;br &#x2F;&gt;
From $P_2(x)$, we only need the constant value of $3$.&lt;&#x2F;p&gt;
&lt;p&gt;Checking the correctness of FRI requires verifying that each value corresponds to its Merkle tree and the colinearity test,&lt;br &#x2F;&gt;
$$P_{i+1}(x^2)=\frac{P_i(x) + P_i(-x)}{2}+\beta_i \frac{P_i (x) - P_i (-x)}{2x}$$&lt;br &#x2F;&gt;
Let’s check the jump from each layer:&lt;br &#x2F;&gt;
$$P_1(15) = 16 = \frac{P_0(10) + P_0(7)}{2} + 4 \frac{P_0 (10) - P_0 (7)}{2\times 10}$$&lt;br &#x2F;&gt;
We can see that&lt;br &#x2F;&gt;
$$\frac{P_0(10) + P_0(7)}{2} = 1$$&lt;br &#x2F;&gt;
and&lt;br &#x2F;&gt;
$$ 4 \frac{P_0 (10) - P_0 (7)}{2\times 10} = 8$$&lt;&#x2F;p&gt;
&lt;p&gt;Let’s jump onto the next layer,&lt;br &#x2F;&gt;
$$P_{2}(y^2)=\frac{P_1(y) + P_1(-y)}{2}+\beta_1 \frac{P_1 (y) - P_1 (-y)}{2y}$$&lt;br &#x2F;&gt;
Replacing the values,&lt;br &#x2F;&gt;
$$P_{2}(y^2) = 3$$&lt;br &#x2F;&gt;
and&lt;br &#x2F;&gt;
$$ \frac{P_1(15) + P_1(2)}{2} = 10$$&lt;br &#x2F;&gt;
$$ 3\frac{P_1 (15) - P_1 (2)}{2\times 15} = 10$$&lt;br &#x2F;&gt;
But&lt;br &#x2F;&gt;
$$ 10 + 10 = 3 = P_2(4)$$&lt;br &#x2F;&gt;
which completes the check. You can try selecting other indices and verifying the proof.&lt;&#x2F;p&gt;
&lt;p&gt;The only remaining check shows that the trace and composition polynomial are related. We leave it as a challenge (the answer will appear shortly)&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;This post covered a pen-and-paper example of computational integrity using STARKs. We chose a sequence where each element is the square of the previous one, starting from 3. We stated the problem, interpreted the computation as evaluating a polynomial over a suitable domain, and performed Lagrange interpolation. After that, we enforced the constraints over the execution trace and obtained the composition polynomial. To improve soundness, we forced the prover to evaluate at a point $z$ outside the domain and showed that the trace and composition polynomial are related. Then, we created a rational function that ensured the prover did not cheat and sent the correct values. If the prover is honest, then the resulting function is a polynomial, and we proved by showing that it is close to a low-degree polynomial using FRI. If you want to try more complicated examples, follow the updates at Lambdaworks.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Our small contribution to Paradigm’s Reth to diversify Ethereum clients</title>
          <pubDate>Mon, 06 Mar 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/our-small-contribution-to-paradigms-reth-to-diversify-ethereum-clients/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/our-small-contribution-to-paradigms-reth-to-diversify-ethereum-clients/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/our-small-contribution-to-paradigms-reth-to-diversify-ethereum-clients/">&lt;p&gt;In December, last year, we heard about &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;paradigmxyz&#x2F;reth&quot;&gt;Reth&lt;&#x2F;a&gt;, and it immediately piqued our interest. A greenfield new implementation of an Ethereum full node? Where do we sign up!?&lt;&#x2F;p&gt;
&lt;p&gt;The project, started and driven by &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.twitter.com&#x2F;gakonst&quot;&gt;@gakonst&lt;&#x2F;a&gt; from Paradigm (if you haven’t heard about it yet, we encourage you to read gakonst’s &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.paradigm.xyz&#x2F;2022&#x2F;12&#x2F;reth&quot;&gt;introductory post&lt;&#x2F;a&gt; ), aims to not just experiment improvements to performance, safety, software reuse through modularity, and node architecture, but also to contribute to Ethereum’s stability by improving implementation diversity.&lt;&#x2F;p&gt;
&lt;p&gt;These goals strongly resonated with our values and interests, the intersection of deep technical problems, good engineering, and building in the open and jointly. “Diversity” is not just a buzzword: time and time again we’ve seen how monocultures stagnate, how team composition and output benefits from integrating differing viewpoints and experiences, how the state of the art advances by integrating engineering and research, and how software projects grow stronger, instead of weaker, by having several implementations of the same thing. It’s not &lt;em&gt;just&lt;&#x2F;em&gt; “more eyeballs”, or “competition breeds excellence”. It’s an emergent property.&lt;&#x2F;p&gt;
&lt;p&gt;All this made us commit to contributing, but when we started we had to first go out on a learning path: the evolution and design tradeoffs of blockchain node architectures and protocols, the nitty gritty of implementing data structures and patterns used in crypto projects, and so on. For ourselves, we expected to just learn and hone our skills in this process of giving back, but were very satisfied to see other benefits: other projects we were working on required something we learned working on reth, or viceversa. Our seniors had interesting problems to work on, and our juniors had excellent guidance in their maturation process.&lt;&#x2F;p&gt;
&lt;p&gt;Among the many fascinating things one learns when working on cryptocurrency infrastructure project internals is just how to structure such a beast. Blockchain nodes are a kind of distributed database, so they need to handle incoming requests, both to read from the node storage and to write to the transaction mempool, handle connections to peers and the protocol used to communicate with them, and manage the actual storage of the data and cryptographic data structures used to provide the features and guarantees blockchains are known for.&lt;&#x2F;p&gt;
&lt;p&gt;As mentioned elsewhere, Reth takes some cues from Akula and Erigon, which propose a different &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ledgerwatch&#x2F;erigon-book&#x2F;blob&#x2F;main&#x2F;architecture.md&quot;&gt;architecture&lt;&#x2F;a&gt; than Geth, again, more modular and built up out of commmunicating components which can be separated out into other processes or projects as needed. A key component is the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ledgerwatch&#x2F;erigon&#x2F;blob&#x2F;devel&#x2F;eth&#x2F;stagedsync&#x2F;README.md&quot;&gt;staged&lt;&#x2F;a&gt; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;erigon.substack.com&#x2F;p&#x2F;erigon-stage-sync-and-control-flows&quot;&gt;sync&lt;&#x2F;a&gt;, a version of Go-Ethereum’s Full Sync designed with performance in mind.&lt;&#x2F;p&gt;
&lt;p&gt;This staged sync is in essence a state machine consisting of series of stages, each one of which is a segmented part of the syncing process of the node. Each stage takes care of one well-defined task, such as downloading headers or executing transactions, persist their results to a database, and roll forwards and backwards according to required changes. Each stage is thus executed once, unless an interruption or a network reorg&#x2F;unwind requires restarting or rolling back.&lt;&#x2F;p&gt;
&lt;p&gt;In Reth, the staged sync pipeline executes queued stages serially. An external component determines the tip of the chain and the pipeline then executes each stage in order from the current local chain tip and the external chain tip. When a stage is executed, it will run until it reaches the chain tip.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;paradigmxyz&#x2F;reth&#x2F;blob&#x2F;main&#x2F;crates&#x2F;stages&#x2F;src&#x2F;pipeline&#x2F;mod.rs#L28&quot;&gt;reth docs&lt;&#x2F;a&gt; for the pipeline have an excellent diagram detailing how the stages work.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;yMGxizE.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Of course, nothing is written in stone, and may change as possible improvements are detected and implemented, and as the project takes on it’s own direction.&lt;&#x2F;p&gt;
&lt;p&gt;What is relevant here is how things one takes for granted need in other contexts to be re-thought and implemented, such as maintaining data consistency, being able to provide efficient rollbacks and cryptographic hash state computations, etc.&lt;&#x2F;p&gt;
&lt;p&gt;But at the end of the day, code rules. Here are some of the more interesting PRs we were able to contribute:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Adding a stage to the sync pipeline for calculating the chain’s state root in an incremental fashion](https:&#x2F;&#x2F;github.com&#x2F;paradigmxyz&#x2F;reth&#x2F;pull&#x2F;994)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Adaptable request timeouts](https:&#x2F;&#x2F;github.com&#x2F;paradigmxyz&#x2F;reth&#x2F;pull&#x2F;789)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Prioritizing requesting peers with low latency](https:&#x2F;&#x2F;github.com&#x2F;paradigmxyz&#x2F;reth&#x2F;pull&#x2F;835)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Adding support for prometheus metrics](https:&#x2F;&#x2F;github.com&#x2F;paradigmxyz&#x2F;reth&#x2F;pull&#x2F;474) to the [headers sync stage](https:&#x2F;&#x2F;github.com&#x2F;paradigmxyz&#x2F;reth&#x2F;pull&#x2F;498) and [txpool](https:&#x2F;&#x2F;github.com&#x2F;paradigmxyz&#x2F;reth&#x2F;pull&#x2F;584).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As well as general tests and documentation.&lt;&#x2F;p&gt;
&lt;p&gt;We are thankful to Paradigm for spearheading and allowing us to collaborate with them and the community. Managing a project takes time and effort.&lt;&#x2F;p&gt;
&lt;p&gt;EOF.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>LambdaWorks or how we decided to create our zkSNARKs library and a STARK prover</title>
          <pubDate>Wed, 01 Mar 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/lambdaworks-or-how-we-decided-to-created-our-zksnarks-library-and-a-stark-prover/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/lambdaworks-or-how-we-decided-to-created-our-zksnarks-library-and-a-stark-prover/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/lambdaworks-or-how-we-decided-to-created-our-zksnarks-library-and-a-stark-prover/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;We think that most ZK libraries are not yet easy-to-use. Most of them assume that the user had a significant cryptography background, making it hard for a newcomer to learn from them, even if he had all the code in front of him. We also found that some commonly used libraries had poor documentation or hard-to-follow examples for beginners. In addition to this some libraries don’t follow state of the art engineering practices that are crucial to build reliable systems that go to production. There are many efforts like Cairo, Noir that don’t have these issues but they are full blown programming languages. We wanted a tool to build languages like those, new proving systems or anything that we need.&lt;&#x2F;p&gt;
&lt;p&gt;So, we decided to start building our &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;lambdaworks&quot;&gt;LambdaWorks&lt;&#x2F;a&gt; library with the following goals in mind:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Implemented in Rust with WASM support and an FFI API in other mainstream languages&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Easy to use API&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Contains most famous proving systems (Groth16, Plonk, STARKs, Plonky2 and maybe Halo2) and recursion&#x2F;IVC (Nova, Supernova)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Allow for hardware acceleration, such as GPU and FPGA integration&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. Clear documentation with different kinds of tutorials, from starters to advanced users&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Given their importance and applications, we decided to begin our library by implementing the STARKs’ prover. We had to implement finite field arithmetic and basic cryptographic stuff, such as Merkle trees and hash functions. We will continue with elliptic curves and SNARKs.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;starks&quot;&gt;STARKs&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2018&#x2F;046.pdf&quot;&gt;STARKs&lt;&#x2F;a&gt; (scalable, transparent arguments of knowledge) are cryptographic primitives, which are a convenient means to an end. The goal we are after is computational integrity, that is, showing that a computation was performed correctly (according to a set of instructions). For example, we want to prove that we computed the first 5000 values of a sequence correctly, or we ran a given machine learning algorithm, or we processed 4000 transactions in a blockchain. STARKs provide us with short proof of the integrity of the computation. The advantage STARKs gives us is that checking the proof is much faster than performing the naïve verification (re-executing the program by the verifier).&lt;&#x2F;p&gt;
&lt;p&gt;There are many interesting resources to learn the basics of STARKs, such as &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;starkware.co&#x2F;stark-101&#x2F;&quot;&gt;Starkware’s STARK 101&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;aszepieniec.github.io&#x2F;stark-anatomy&#x2F;overview&quot;&gt;Anatomy of a STARK&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;andrewmilson&#x2F;ministark&quot;&gt;Ministark&lt;&#x2F;a&gt;, as well as Starkware’s blog on arithmetization (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;starkware&#x2F;arithmetization-i-15c046390862&quot;&gt;parts I&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;starkware&#x2F;arithmetization-ii-403c3b3f4355&quot;&gt;II&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;The STARK protocol contains the following steps:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Arithmetization&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Transformation to polynomial equations.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * FRI, which has two steps: commitment and decommitment.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;arithmetization&quot;&gt;Arithmetization&lt;&#x2F;h2&gt;
&lt;p&gt;An execution trace is a table containing $w$ columns (the registers) and $T$ rows representing each state of the system. A trace looks like this:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Register 1&lt;&#x2F;th&gt;&lt;th&gt;Register 2&lt;&#x2F;th&gt;&lt;th&gt;$\dots$&lt;&#x2F;th&gt;&lt;th&gt;Register w&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;$x_{1,0}$&lt;&#x2F;td&gt;&lt;td&gt;$x_{2,0}$&lt;&#x2F;td&gt;&lt;td&gt;$\dots$&lt;&#x2F;td&gt;&lt;td&gt;$x_{w,0}$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$x_{1,1}$&lt;&#x2F;td&gt;&lt;td&gt;$x_{2,1}$&lt;&#x2F;td&gt;&lt;td&gt;$\dots$&lt;&#x2F;td&gt;&lt;td&gt;$x_{w,1}$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$\vdots$&lt;&#x2F;td&gt;&lt;td&gt;$\vdots$&lt;&#x2F;td&gt;&lt;td&gt;$\ddots$&lt;&#x2F;td&gt;&lt;td&gt;$\vdots$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;$x_{1,T}$&lt;&#x2F;td&gt;&lt;td&gt;$x_{2,T}$&lt;&#x2F;td&gt;&lt;td&gt;$\dots$&lt;&#x2F;td&gt;&lt;td&gt;$x_{w,T}$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;We will interpret each column (register) as the evaluation of a polynomial over a domain (we will call it the trace evaluation domain). For example, we can say that $f_1(x)$ is the polynomial representing column 1 and thus:&lt;br &#x2F;&gt;
$f_1(0)=x_{1,0}$&lt;br &#x2F;&gt;
$f_1(1)=x_{1,1}$&lt;br &#x2F;&gt;
$\vdots$&lt;br &#x2F;&gt;
$f_1(T)=x_{1,T}$&lt;&#x2F;p&gt;
&lt;p&gt;To make things easier and faster, we will use as trace evaluation domain a multiplicative subgroup, $\mathbb{Z_p}^\star$ of size $2^n$, such that $2^n \geq T$. That group has a generator, $\omega$, which spans all elements in the subgroup. The subgroup can be represented by the powers of $\omega$, $\{ 1, \omega , \omega^2 , \omega^3 ,…, \omega^N \}$. Our trace polynomial satisfies then&lt;br &#x2F;&gt;
$f_1(1)=x_{1,0}$&lt;br &#x2F;&gt;
$f_1(\omega)=x_{1,1}$&lt;br &#x2F;&gt;
$\vdots$&lt;br &#x2F;&gt;
$f_1(\omega^{T-1})=x_{1,T}$&lt;&#x2F;p&gt;
&lt;p&gt;The elements in the execution trace satisfy certain relations given by the computation and boundary conditions. We call these relations constraints. They can be broadly classified into two groups:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Boundary constraints.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Transition constraints.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Boundary constraints are rather straightforward: they specify the value of a register at a given time. For example, when we initialize the computations, each register has a given value. In the case of the Fibonacci sequence,&lt;br &#x2F;&gt;
$a_0=a_1=1$&lt;br &#x2F;&gt;
If our trace consists of a single column representing the sequence, the first two elements are equal to one:&lt;br &#x2F;&gt;
$x_{1,0}=1$&lt;br &#x2F;&gt;
$x_{1,1}=1$&lt;&#x2F;p&gt;
&lt;p&gt;We can translate the constraints into polynomial relations. We know that $x_{1,0}=f_1(1)$ and $x_{1,1}=f_1(\omega)$. If the constraint holds, say at $x=\omega$, then the monomial $x-\omega$ divides $f_1(x)-1$. This means that the result of the division of $f(x)-1$ by $x-\omega$ is a polynomial,&lt;br &#x2F;&gt;
$$ Q_{BC,1}(x)=\frac{f_1(x)-1}{x-\omega} $$&lt;br &#x2F;&gt;
Analogously,&lt;br &#x2F;&gt;
$$ Q_{BC,0}(x)=\frac{f_1(x)-1}{x-1} $$&lt;&#x2F;p&gt;
&lt;p&gt;One drawback in this approach is that if we have $n$ boundary constraints, we get $n$ polynomials. One optimization is to interpolate boundary constraints and obtain a new polynomial. In this case,&lt;br &#x2F;&gt;
$f_{BC}(1)=1$&lt;br &#x2F;&gt;
$f_{BC}(\omega)=1$&lt;br &#x2F;&gt;
Combining everything, we get&lt;br &#x2F;&gt;
$$ Q_{BC}(x)=\frac{f(x)-f_{BC}(x)}{Z_{BC}(x)}$$&lt;br &#x2F;&gt;
where $Z_{BC}(x)$ is the polynomial vanishing on the points where the boundary conditions are enforced:&lt;br &#x2F;&gt;
$Z_{BC}(x)=(x-1)(x-\omega)$&lt;&#x2F;p&gt;
&lt;p&gt;Transition constraints are relations between different rows that can be applied at various calculation points. In the case of the Fibonacci sequence, we have $a_{n+2}=a_{n+1}+a_n$ for every $n={0,1,…T-2 }$. In terms of the trace polynomial,&lt;br &#x2F;&gt;
$f_1(\omega^2 x)-f_1(\omega x)-f_1(x)=0$&lt;br &#x2F;&gt;
If the constraint is satisfied, the following function should be a polynomial,&lt;br &#x2F;&gt;
$$Q_T(x)=\frac{f_1(\omega^2 x)-f_1(\omega x)-f_1(x)}{Z_T(x)} $$&lt;br &#x2F;&gt;
where $Z_T(x)$ is the vanishing polynomial where the transition constraints are enforced,&lt;br &#x2F;&gt;
$Z_T(x)=\prod_{k=0}^{T-2} (x-\omega^k)$&lt;&#x2F;p&gt;
&lt;p&gt;Transition constraints are commonly expressed as multivariate polynomials linking two consecutive rows of the execution trace. For example, if we denote by $x$ a given row and $y$ is the next, a constraint could be something like&lt;br &#x2F;&gt;
$P(x,y)=y-x^2=0$&lt;br &#x2F;&gt;
If we compose the constraint polynomial with the trace polynomial, we have $x=t(x)$, $y=t(\omega x)$, so&lt;br &#x2F;&gt;
$t(\omega x) - t(x)^2=0$&lt;&#x2F;p&gt;
&lt;p&gt;If we did the calculations properly, then $Q_{BC}(x)$ and $Q_T(x)$ should be polynomials; if not, they are rational functions (quotients of two polynomials). We can reduce proving that each of them is a polynomial by taking a random linear combination&lt;br &#x2F;&gt;
$$ CP(x)=\alpha_{BC} Q_{BC}(x)+\alpha_{T} Q_T(x) $$&lt;br &#x2F;&gt;
If $Q_{BC}(x)$ and $Q_T(x)$ are both polynomials, so is $CP(x)$. But if at least one of them is a rational function, then $CP(x)$ is unlikely to be a polynomial.&lt;&#x2F;p&gt;
&lt;p&gt;Given that proving that $CP(x)$ is a polynomial is difficult, we will show that it is close to a low-degree polynomial. To do so, we will project $CP(x)$ to a new function with a smaller degree. We will continue taking projections until we reach a constant polynomial. The critical ingredient is that the projection operation respects the distance. If the original function is far from a low-degree polynomial, then the projections will also be far from it. Before jumping to the procedure (called FRI), we must commit to the trace polynomials.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;committing-to-the-trace&quot;&gt;Committing to the trace&lt;&#x2F;h2&gt;
&lt;p&gt;We need to evaluate the trace polynomials over a much larger domain; the domain size is $\beta 2^n$, where $\beta$ is the blowup factor. To avoid problems, we shift the domain by multiplying the elements by $h$, which belongs to the coset. The low-degree extension domain (simply domain) is given by&lt;br &#x2F;&gt;
$$D = \{ h, h \eta , h \eta^2 , … , h \eta^{ 2^n -1} \} $$&lt;br &#x2F;&gt;
Here $\eta$ is the generator of the subgroup of order $\beta 2^n$ so that it does not get confused with $\omega$ (though we could relate them by taking $\omega=\eta^\beta$).&lt;br &#x2F;&gt;
We evaluate the trace polynomials over this large domain and obtain vectors representing each evaluation:&lt;br &#x2F;&gt;
$$[ f_1 (h) , f_1 (h \eta) ,… , f_1 (h \eta^{ 2^n -1} )]$$&lt;br &#x2F;&gt;
$$[f_2 (h) , f_2 (h \eta) , … , f_2 (h \eta^{ 2^n -1} )]$$&lt;br &#x2F;&gt;
$$[f_w (h) , f_w (h \eta ) , … , f_w ( h \eta^{ 2^n -1} )]$$&lt;&#x2F;p&gt;
&lt;p&gt;To commit to these evaluations, we build Merkle trees, and the prover sends the root of the Merkle trees to the verifier. To make things easier, the elements of each row of the low-degree extension of the trace are grouped into a single leaf.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;committing-to-the-composition-polynomial&quot;&gt;Committing to the composition polynomial&lt;&#x2F;h2&gt;
&lt;p&gt;We use the same domain $$D = \{ h, h \eta , h \eta^2 , … , h \eta^{ 2^n -1} \} $$ to evaluate the composition polynomial. We can then create a Merkle tree from these evaluations and send the root to the verifier.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;relating-the-lde-of-execution-trace-and-the-composition-polynomial&quot;&gt;Relating the LDE of execution trace and the composition polynomial&lt;&#x2F;h2&gt;
&lt;p&gt;At some point, the verifier will ask the prover for the value of the composition polynomial at one point, $z$, that is, $CP(z)$. The verifier needs to be sure that the composition polynomial results from applying the polynomial constraints onto the trace polynomials. Given the value $z \in D$ (in DEEP, the value of $z$ is sampled outside the domain), the prover needs to send the values of the trace polynomials at given points so that the verifier can check the calculation. For example, in the case of Fibonacci (we will ignore all other constraints just for simplicity),&lt;br &#x2F;&gt;
$P(u,v,w)=w-v-u=0$&lt;br &#x2F;&gt;
$P(t(x),t(\omega x),t(\omega^2 x))=t(\omega^2x)-t(\omega x)-t(x)=0$&lt;br &#x2F;&gt;
To create the composition polynomial, we must divide the previous polynomial by the corresponding vanishing polynomial. So, if we pick $x=z$, we have&lt;&#x2F;p&gt;
&lt;p&gt;$$Q(z)=\frac{t(\omega^2z)-t(\omega z)-t(z)}{Z_D(z)}$$&lt;&#x2F;p&gt;
&lt;p&gt;The prover needs to send those three values. Note that $z=h \eta^k$, so the prover needs to send the values of $t(\omega^2 h \eta^k)$, $t(\omega h \eta^k)$, $t( h \eta^k)$, which are separated by $\beta$ elements in the Merkle tree. The verifier takes the three values, evaluates the vanishing polynomials, and checks that&lt;br &#x2F;&gt;
$Q(z)=CP(z)$&lt;&#x2F;p&gt;
&lt;p&gt;This way, the verifier is convinced that the composition polynomial is related to the execution trace via the constraint polynomials.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;fri-protocol&quot;&gt;FRI protocol&lt;&#x2F;h2&gt;
&lt;p&gt;The prover must show that $CP(x)$ is close to a low-degree polynomial. To do so, he will randomly fold the polynomial, reducing the degree, until he gets a constant polynomial (in optimizations, obtaining a constant polynomial is unnecessary, as the prover could send all the coefficients of a polynomial and have the verifier check it). The FRI protocol has two steps: commit and decommit.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;commitment&quot;&gt;Commitment&lt;&#x2F;h3&gt;
&lt;p&gt;The prover takes $CP(x)$ and splits it in the following way:&lt;br &#x2F;&gt;
$$g(x^2)=\frac{CP(x)+CP(-x)}{2}$$&lt;br &#x2F;&gt;
$$x h(x^2)=\frac{CP(x)-CP(-x)}{2}$$&lt;br &#x2F;&gt;
so that&lt;br &#x2F;&gt;
$$CP(x)=g(x^2)+x h(x^2)$$&lt;br &#x2F;&gt;
The verifier chooses a random value $\alpha_0$, and the prover forms the polynomial,&lt;br &#x2F;&gt;
$P_1(x)=g(x^2)+\alpha_0 h(x^2)$&lt;br &#x2F;&gt;
with the new domain $D_1 = \{ h^2 , h^2 \eta^2 , … , h^2 \eta^m \}$ having half the size of $D$.&lt;&#x2F;p&gt;
&lt;p&gt;The prover can perform the low-degree extension by evaluating $P_1(x)$ over $D_1$ and then commit to it by creating a Merkle tree and sending the root. He can continue with the procedure by halving the degree at each step. For step $k$, we have&lt;br &#x2F;&gt;
$$P_k(y^2)=\frac{P_{k-1}(y)+P_{k-1}(-y)}{2}+\alpha_{k-1}\left(\frac{P_{k-1}(y)-P_{k-1}(-y)}{2}\right)$$&lt;br &#x2F;&gt;
and&lt;br &#x2F;&gt;
$$D_k = \{ h^{ 2^{k-1} } , (h \eta)^{ 2^{k-1} } , … ,( \eta^l h)^{ 2^{k-1} } \}$$&lt;br &#x2F;&gt;
The prover evaluates $P_k(x)$ over $D_k$ and commits to it, sending the Merkle root.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;decommitment&quot;&gt;Decommitment&lt;&#x2F;h3&gt;
&lt;p&gt;The verifier chooses at random a point $q$ belonging to $D$. The prover needs to convince him that the trace polynomials and composition polynomial are related (we covered that previously) and that the elements of consecutive FRI layers are also related. For each layer, the prover needs to send two elements to the verifier, $P_k(z)$ and $P_k(-z)$. He also needs to show that these elements belong to the corresponding Merkle tree, so the authentication paths for each element are also required.&lt;&#x2F;p&gt;
&lt;p&gt;The verifier can check the correctness of the FRI layers by performing a colinearity check. Given $P_k(z)$, $P_k(-z)$ and $P_{k+1}(z^2)$, the verifier can compute&lt;br &#x2F;&gt;
$$g_{k+1}(z^2)=\frac{P_k(z)+P_k(-z)}{2}$$&lt;br &#x2F;&gt;
$$h_{k+1}(z^2)=\frac{P_k(z)-P_k(-z)}{2z}$$&lt;br &#x2F;&gt;
and get the value for the next layer&lt;br &#x2F;&gt;
$$u_{k+1}=g_{k+1}(z^2)+\alpha_k h_{k+1}(z^2)$$&lt;br &#x2F;&gt;
If the prover performed the calculations correctly, then&lt;br &#x2F;&gt;
$$u_{k+1}=P_{k+1}(z^2)$$&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-toy-example-for-fri&quot;&gt;A toy example for FRI&lt;&#x2F;h2&gt;
&lt;p&gt;We will use a simple example to understand how everything works on FRI. We choose $p=17$, whose multiplicative group has order $16=2^4$ and set $\eta=3$, which is a primitive root of unity (that is, $3^{16}=1$ and $3^k \neq 1$ for $0 &amp;lt;k&amp;lt;16$). Our composition polynomial is $P_0 (x) = x^3 + x^2 + 1$. The domain for the LDE is simply $ D_0 = \mathbb{Z_{17}}^\star = \{1 , 2 , 3 , 4 , 5 , 6 , … , 16 \}$. The following table contains the LDE of $P_0(x)$:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Index&lt;&#x2F;th&gt;&lt;th&gt;$x$&lt;&#x2F;th&gt;&lt;th&gt;$P_0(x)$&lt;&#x2F;th&gt;&lt;th&gt;Index&lt;&#x2F;th&gt;&lt;th&gt;$x$&lt;&#x2F;th&gt;&lt;th&gt;$P_0(x)$&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;td&gt;16&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;9&lt;&#x2F;td&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;9&lt;&#x2F;td&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;td&gt;16&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;td&gt;13&lt;&#x2F;td&gt;&lt;td&gt;11&lt;&#x2F;td&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;13&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;13&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;5&lt;&#x2F;td&gt;&lt;td&gt;5&lt;&#x2F;td&gt;&lt;td&gt;15&lt;&#x2F;td&gt;&lt;td&gt;13&lt;&#x2F;td&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;6&lt;&#x2F;td&gt;&lt;td&gt;15&lt;&#x2F;td&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;13&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;td&gt;11&lt;&#x2F;td&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;td&gt;15&lt;&#x2F;td&gt;&lt;td&gt;6&lt;&#x2F;td&gt;&lt;td&gt;15&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Suppose the verifier samples $\beta_0=3$. The prover performs the random folding over $P_0(x)$,&lt;br &#x2F;&gt;
$g_1( x^2 ) = 1 + x^2$&lt;br &#x2F;&gt;
$xh_1 ( x^2 ) = x^3 $&lt;br &#x2F;&gt;
so&lt;br &#x2F;&gt;
$P_1 ( x^2 ) = 1 + ( 1 + \beta_0) x^2$&lt;br &#x2F;&gt;
To make things simpler,&lt;br &#x2F;&gt;
$P_1(y)=1+4y$&lt;br &#x2F;&gt;
with $y = x^2$. The new domain is obtained by squaring the elements of $D_0$. The LDE of $P_1(y)$ is&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Index&lt;&#x2F;th&gt;&lt;th&gt;$y$&lt;&#x2F;th&gt;&lt;th&gt;$P_1(y)$&lt;&#x2F;th&gt;&lt;th&gt;Index&lt;&#x2F;th&gt;&lt;th&gt;$y$&lt;&#x2F;th&gt;&lt;th&gt;$P_1(y)$&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;5&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;16&lt;&#x2F;td&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;9&lt;&#x2F;td&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;5&lt;&#x2F;td&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;td&gt;16&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;13&lt;&#x2F;td&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;6&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;15&lt;&#x2F;td&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;9&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;The verifier samples $\beta_1=2$ and the prover folds $P_1(y)$ to get $P_2(z)$,&lt;br &#x2F;&gt;
$P_2(z)=1+4\beta_1=9$&lt;br &#x2F;&gt;
which is a constant polynomial. The domain $D_2 = \{ 1 , 13 , 16 , 4 \}$. All the elements in the LDE evaluate to 9, so there is no need for a table.&lt;&#x2F;p&gt;
&lt;p&gt;The evaluations of the polynomials $P_0(x)$, $P_1(x)$, and $P_2(x)$ are each committed using a Merkle tree and sent to the verifier.&lt;&#x2F;p&gt;
&lt;p&gt;Suppose the verifier selects index 4 in the LDE to check the correctness of the FRI layers. The prover needs to send him the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $P_0(13)=4$ and $P_0(-13)=P_0(4)=13$ and their authentication paths.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $P_1(16)=14$ and $P_1(-16)=P_1(1)=5$ and their authentication paths.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $P_2(4)=9$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can see that, for the first layer, the prover passes the values at positions 4 and 12, then 4 and 1 (which is $index+|D_1|&#x2F;2$, where $|D_1|$ is the number of elements in $D_1$, but since 8 exceeds the maximum value, we wrap around).&lt;&#x2F;p&gt;
&lt;p&gt;The verifier does the following calculation,&lt;br &#x2F;&gt;
$$u=\frac{P_0(13)+P_0(4)}{2}+\beta_0\left(\frac{P_0(13)-P_0(4)}{2\times 13}\right)$$&lt;&#x2F;p&gt;
&lt;p&gt;Recall that division by $t$ is simply multiplication by $t^{-1}$. In the case of $2$, we have $2^{-1}=9$, since $2\times 9=18\equiv 1 \pmod{17}$. Thus,&lt;br &#x2F;&gt;
$$u=2^{-1}\left(4+13\right)+3\times 9^{-1}\left(4-13\right)$$&lt;br &#x2F;&gt;
The first term is $0$, while the second is $48\equiv 14 \pmod{17}$, so&lt;br &#x2F;&gt;
$u=14$.&lt;br &#x2F;&gt;
Next, he checks&lt;br &#x2F;&gt;
$u=P_1(16)$&lt;br &#x2F;&gt;
Both are $14$, so the first layer is correct.&lt;&#x2F;p&gt;
&lt;p&gt;The verifier moves on to the next layer. He needs to calculate&lt;br &#x2F;&gt;
$$u=\frac{P_1(16)+P_1(1)}{2}+\beta_1\left(\frac{P_1(16)-P_1(1)}{2\times 16}\right)$$&lt;&#x2F;p&gt;
&lt;p&gt;If we work the calculations,&lt;br &#x2F;&gt;
$$u=\frac{2}{2}+2\left(\frac{9}{2 \times 16}\right)$$&lt;br &#x2F;&gt;
But this is just&lt;br &#x2F;&gt;
$$u=1+(-9)=1+8=9$$&lt;br &#x2F;&gt;
Now,&lt;br &#x2F;&gt;
$$P_2(4)=9=u$$&lt;br &#x2F;&gt;
so all the layers have been checked. You should try selecting an index and showing that all the calculations match.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;STARKs are powerful cryptographic primitives allowing a party to prove the integrity of a computation. To generate the proof, we obtain the execution trace of the program and interpret each column of the trace as the evaluations of a polynomial over a “nice” domain. The rows of the execution trace are related by low-degree polynomials, which determine the constraints. When we compose the constraint polynomials with the trace polynomials, we enforce the constraints over the execution trace. We can then divide them by the vanishing polynomial over their validity domain (the places where each constraint is enforced); if the constraints hold, the division is exact and yields a polynomial. Instead of proving that the result is a polynomial, STARKs show that the result is close to a low-degree polynomial. FRI randomly folds the function, halving the degree at each step; the critical point is that this folding preserves distance from low-degree polynomials. The protocol contains two phases: commit, in which the prover binds himself to evaluations of the polynomials over their corresponding domain, and decommit, where he generates the proof that allows the verifier to check the calculations. In an upcoming post, we will cover some optimizations and examples.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Everything you wanted to know about periodic constraints in STARKs but nobody told you</title>
          <pubDate>Fri, 24 Feb 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/periodic-constraints-and-recursion-in-zk-starks/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/periodic-constraints-and-recursion-in-zk-starks/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/periodic-constraints-and-recursion-in-zk-starks/">&lt;p&gt;As you might have already guessed we are studying all the literature and code available to become one of big players in the industry. We want to thank &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;EliBenSasson&quot;&gt;Eli Ben-Sasson&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;StarkWareLtd&quot;&gt;Starkware&lt;&#x2F;a&gt; for the amazing work they’ve been doing in the space and for helping us to learn all this. We also want to thank &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;maxgillett&quot;&gt;Max Gillett&lt;&#x2F;a&gt; for the time he has invested in talking with us about all these things. They have been amazing with us and we hope we can continue learning a lot from them.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Introduction&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2018&#x2F;046.pdf&quot;&gt;ZK-STARKs&lt;&#x2F;a&gt; (zero-knowledge scalable, transparent, post-quantum arguments of knowledge) are cryptographic tools that allow one party to prove the integrity of a computation. For example, a party can show that he computed the first 1000 elements of a Fibonacci sequence correctly, ran a given machine learning algorithm, or correctly processed 5000 Ethereum transactions. Moreover, checking the resulting proof is much faster than performing the naïve re-execution of the computation by a verifier (the verification time scales logarithmically in the calculation size). Given their properties, they have attracted interest in many areas; among them, they can solve the scalability problems that decentralized ledgers suffer from.&lt;&#x2F;p&gt;
&lt;p&gt;There are many interesting resources to learn the basics of STARKs, such as Starkware’s &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;starkware.co&#x2F;stark-101&#x2F;&quot;&gt;STARK 101&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;aszepieniec.github.io&#x2F;stark-anatomy&#x2F;overview&quot;&gt;Anatomy of a STARK&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;andrewmilson&#x2F;ministark&quot;&gt;Ministark&lt;&#x2F;a&gt;, as well as Starkware’s blog on arithmetization (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;starkware&#x2F;arithmetization-i-15c046390862&quot;&gt;parts I&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;starkware&#x2F;arithmetization-ii-403c3b3f4355&quot;&gt;II&lt;&#x2F;a&gt;). In this post, we will focus on how constraints are enforced and how to deal with them when applied periodically. Soon we will be posting a more in-depth version of STARKs.&lt;&#x2F;p&gt;
&lt;p&gt;The starting point for STARKs is arithmetization. We generate the execution trace of the program, obtaining a table showing how each register evolves according to the instructions being executed. The values of the execution table are related by constraints (usually low-degree polynomials). We will focus, in particular, on transition constraints and how to check that the values of the trace satisfy them.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Transition constraints&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;A transition constraint dictates the relations between different states of a computation. Suppose we have one register, which contains the elements of a Fibonacci sequence,&lt;&#x2F;p&gt;
&lt;p&gt;$a_0=a_1=1$&lt;&#x2F;p&gt;
&lt;p&gt;$a_{n+2}=a_{n+1}+a_n$&lt;&#x2F;p&gt;
&lt;p&gt;The last equation gives the transition constraint for the Fibonacci sequence; the others handle the boundary constraints for the problem, and it is easier to deal with them. To make our discussion easier, suppose that we performed $2^m$ steps of the Fibonacci sequence for some $m \geq 1$. We get, by rewriting the constraints and analyzing each index,&lt;&#x2F;p&gt;
&lt;p&gt;$a_2-a_1-a_0=0$&lt;&#x2F;p&gt;
&lt;p&gt;$a_3-a_2-a_1=0$&lt;&#x2F;p&gt;
&lt;p&gt;$a_4-a_3-a_2=0$&lt;&#x2F;p&gt;
&lt;p&gt;and so on. We can convert the trace elements into polynomials by interpolating over a suitable domain. To make things easier, we choose the $n$-th roots of unity, which enables us to perform interpolation via the fast Fourier transform. The roots are spanned by one element (a generator, $g$): by taking its powers, we get all the $n$-th roots of unity, $\left\{1,g,g^2,g^3,…,g^{n-1}\right\}$.Let us call $t(x)$ the polynomial interpolating the trace, that is, the polynomial taking the following values:&lt;&#x2F;p&gt;
&lt;p&gt;$t(1)=a_0$&lt;&#x2F;p&gt;
&lt;p&gt;$t(g)=a_1$&lt;&#x2F;p&gt;
&lt;p&gt;$t(g^2)=a_2$&lt;&#x2F;p&gt;
&lt;p&gt;$\vdots$&lt;&#x2F;p&gt;
&lt;p&gt;$t(g^{n-1})=a_{n-1}$&lt;&#x2F;p&gt;
&lt;p&gt;We can express the constraints as&lt;&#x2F;p&gt;
&lt;p&gt;$t(g^2)-t(g)-t(1)=0$&lt;&#x2F;p&gt;
&lt;p&gt;$t(g^3)-t(g^2)-t(g)=0$&lt;&#x2F;p&gt;
&lt;p&gt;$t(g^4)-t(g^3)-t(g^2)=0$&lt;&#x2F;p&gt;
&lt;p&gt;In a generic way,&lt;&#x2F;p&gt;
&lt;p&gt;$t(g^2x)-t(gx)-t(x)=0$&lt;&#x2F;p&gt;
&lt;p&gt;The way we can check that the constraints are enforced is by verifying that the polynomial $p(x)=t(g^2x)-t(gx)-t(x)$ is divisible by $(x-x_0)$, where $x_0$ is the point where we enforce the constraint. Another way to see this is that the resulting function&lt;&#x2F;p&gt;
&lt;p&gt;$$Q(x)=\frac{p(x)}{x-x_0} $$&lt;&#x2F;p&gt;
&lt;p&gt;is a polynomial. Instead of showing that $Q(x)$ is a polynomial, the STARK IOP proves that it is close to a low-degree polynomial.&lt;&#x2F;p&gt;
&lt;p&gt;In the case of the Fibonacci sequence, the constraint is valid for $x_0 \in \left\{1,g,g^2,…g^{n-3} \right\}$. Given that it is divisible by each factor, it is divisible by the product of all of them,&lt;&#x2F;p&gt;
&lt;p&gt;$Z_D(x)=\prod_{0}^{n-3} (x-g^k)$&lt;&#x2F;p&gt;
&lt;p&gt;The problem we face with this polynomial is that, to compute it, we need to perform a linear amount of multiplications, that is, as many multiplications as factors there are. Fortunately, the roots of unity have the following property:&lt;&#x2F;p&gt;
&lt;p&gt;$s(x)=\prod_{i=0}^{n-1} (x-g^k)=x^n-1$&lt;&#x2F;p&gt;
&lt;p&gt;So, instead of performing a linear amount of operations, we can calculate $Z_D(x)$ from $s(x)$ by taking out the missing factors:&lt;&#x2F;p&gt;
&lt;p&gt;$$Z_D(x)=\frac{ s(x)}{\prod_j (x-g^j)}=\frac{x^n-1}{(x-g^{n-1})(x-g^{n-2})} $$&lt;&#x2F;p&gt;
&lt;p&gt;The advantage of STARKs is that if a constraint is repeated many times, we can express that concisely. The only change goes in the vanishing polynomial $Z_D(x)$, which adds factors.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Constraints repeating after $m$ steps&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In a case such as Fibonacci’s, the constraint involves almost all points in the domain, so calculating the vanishing polynomial, $Z_D(x)$, is straightforward. But what happens when a constraint is applied only at certain points? For example, in EthStark, some transition constraints are applied only after $m$ steps.&lt;&#x2F;p&gt;
&lt;p&gt;To fix ideas, suppose that we have a transition constraint of the form&lt;&#x2F;p&gt;
&lt;p&gt;$f(x,gx,…g^d x)=0$&lt;&#x2F;p&gt;
&lt;p&gt;Our Fibonacci sequence fits this form. We will now consider that it applies every four steps; that is, the constraint is enforced at $x_0 \in \left\{1, g^4, g^8, g^{12},…\right\}$&lt;&#x2F;p&gt;
&lt;p&gt;The vanishing polynomial looks like&lt;&#x2F;p&gt;
&lt;p&gt;$Z_D(x)=\prod_k (x-g^{4k})$&lt;&#x2F;p&gt;
&lt;p&gt;If $g$ is a generator of the $n$-th roots of unity, $g^4$ is a generator of the $n&#x2F;4$-th roots of unity, $\omega=g^4$. So, we can rewrite the former as&lt;&#x2F;p&gt;
&lt;p&gt;$Z_D(x)=\prod_k (x-\omega^k)$&lt;&#x2F;p&gt;
&lt;p&gt;But since the product is over all $n&#x2F;4$-th roots of unity,$Z_D(x)=x^{n&#x2F;4}-1$. If the constraint is applied every 32 steps, as in EthStark, the vanishing polynomial is simply$Z_D(x)=x^{n&#x2F;32}-1$. If we skip some steps, we need to take those out. For example, suppose we have two constraints&lt;&#x2F;p&gt;
&lt;p&gt;$f_1(x,g x)=0$&lt;&#x2F;p&gt;
&lt;p&gt;$f_2(x, g x)=0$.&lt;&#x2F;p&gt;
&lt;p&gt;Constraint 2 is enforced every four steps, and constraint 1 is enforced every two (but not where constraint 2 is valid). To make it clear, constraint 2 is valid at $x_0 \in \left\{1,g^4,g^8,g^{12},…\right\}$ and constraint 1 is valid at $\left\{g^2, g^6, g^{10},… \right\}$. The vanishing polynomial for constraint 2 is&lt;&#x2F;p&gt;
&lt;p&gt;$Z_{D,2}(x)=\prod (x-g^{4k})$&lt;&#x2F;p&gt;
&lt;p&gt;and we have already found the solution, $Z_{D,2}(x)=(x^{n&#x2F;4}-1)$. For constraint 1, we have&lt;&#x2F;p&gt;
&lt;p&gt;$Z_{D,1} =\prod_{i \neq 0 \pmod{2} } (x-g^{2i})$&lt;&#x2F;p&gt;
&lt;p&gt;The $i \neq 0 \pmod{2}$ is just a way to say that the product only considers odd values of $i$ (so multiples of 4 are ruled out). We can apply the same trick as before:&lt;&#x2F;p&gt;
&lt;p&gt;$$Z_{D,1}=\frac{ \prod (x-g^{2i})}{\prod (x-g^{4k})}$$&lt;&#x2F;p&gt;
&lt;p&gt;This may seem weird, but we know precisely how to calculate each of them:&lt;&#x2F;p&gt;
&lt;p&gt;$$Z_{D,1}(x)=\frac{x^{n&#x2F;2}-1}{x^{n&#x2F;4}-1} $$&lt;&#x2F;p&gt;
&lt;p&gt;From here, we can remove some points where the constraint is not enforced. For example, if it is not valid at $x_0=6$,&lt;&#x2F;p&gt;
&lt;p&gt;$$Z_{D,1}(x)=\frac{x^{n&#x2F;2}-1}{(x^{n&#x2F;4}-1)(x-g^6)} $$&lt;&#x2F;p&gt;
&lt;p&gt;If we added a constraint $f_3(x,gx)$ that is enforced on steps $\left\{32,64,92,… \right\}$, we would have 3 vanishing polynomials,&lt;&#x2F;p&gt;
&lt;p&gt;$$Z_{D,3}=\frac{x^{n&#x2F;32}-1}{x-1} $$&lt;&#x2F;p&gt;
&lt;p&gt;$$Z_{D,2}=\frac{(x^{n&#x2F;4}-1)(x-1)}{x^{n&#x2F;32}-1} $$&lt;&#x2F;p&gt;
&lt;p&gt;$$Z_{D,1}(x)=\frac{x^{n&#x2F;2}-1}{x^{n&#x2F;4}-1} $$&lt;&#x2F;p&gt;
&lt;p&gt;So, by taking advantage of the properties of the roots of unity, we can enforce constraints that are applied periodically.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Summary&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;STARKs are a powerful tool that allows us to prove the integrity of a computation. To that end, STARKs start with the execution trace of a program and interpolate each column using polynomials. To see that the trace is valid, we need to check that all the constraints given by the computation are enforced. These constraints can be composed with the trace polynomials; if the constraints hold at step $T$, the resulting polynomial $P(x)$ should be divisible by $(x-g^{T-1})$ or, equivalently, there is a polynomial $Q(x)$ such that $P(x)=Q(x)(x-g^{T-1})$. If a constraint is applied multiple times, we can use the following facts to express them concisely:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The polynomial $P(x)$ is divisible by the product of factors of the form $x-x_0$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * We can easily shift the constraints thanks to the structure of the multiplicative subgroups.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The product of all elements in the multiplicative subgroups yield $x^n-1$, where $n$ is the subgroup&amp;#39;s order (number of elements).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This results in advantages in terms of performance and ease of understanding.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, we will post a beginner’s version of STARKs soon, so stay tuned!&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>A walkthrough on the open source Aleo VM implemented with Arkworks and blockchain implemented with Tendermint</title>
          <pubDate>Fri, 03 Feb 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/open-source-aleo-vm-implemented-with-arkworks-and-blockchain-implemented-with-tendermint/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/open-source-aleo-vm-implemented-with-arkworks-and-blockchain-implemented-with-tendermint/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/open-source-aleo-vm-implemented-with-arkworks-and-blockchain-implemented-with-tendermint/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;For the last 12 weeks, at LambdaClass, we have been developing an alternative implementation of the Aleo Blockchain. We want to thank Alex Pruden and Howard Wu from Aleo for their support throughout the process.&lt;&#x2F;p&gt;
&lt;p&gt;At a high level, the project consists of a Consensus Layer using Tendermint and a Zero-Knowledge Virtual Machine targeting Aleo instructions implemented with the arkworks framework.&lt;&#x2F;p&gt;
&lt;p&gt;You can check out the code:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Tendermint Blockchain implementation](https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;aleo_lambda_blockchain)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Virtual Machine implemented with Arkworks](https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;aleo_lambda_vm)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The key features of this blockchain revolve around the fact that it is designed to be a fully-private platform for users to develop applications that can then be built and executed off-chain, generating a proof of execution which is then sent to the blockchain nodes for verification and storage.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;If you’re in need of a team of engineers and researchers who’ve been working together for a decade in areas like distributed systems, machine learning, compilers, and cryptography, we’re your guys. Wanna chat more about it? Book a meeting with us by sending us an &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;calendly.com&#x2F;federicocarrone&quot;&gt;email&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;consensus-layer&quot;&gt;Consensus Layer&lt;&#x2F;h2&gt;
&lt;p&gt;The consensus layer is in charge of validating incoming transactions which perform state changes and replicating these transactions (and the order in which they were performed) on an arbitrary number of nodes.&lt;&#x2F;p&gt;
&lt;p&gt;To achieve this, we decided to utilize &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tendermint&#x2F;tendermint&quot;&gt;Tendermint Core&lt;&#x2F;a&gt;, an implementation of a consensus mechanism written in Go. Alongside the Tendermint Core binaries, you need to run your implementation of an &lt;em&gt;Application Blockchain Interface&lt;&#x2F;em&gt; (or &lt;em&gt;ABCI&lt;&#x2F;em&gt; for short). This ABCI needs to implement specific hooks that Tendermint Core calls through a socket whenever required. For example, when receiving a transaction, it will call &lt;code&gt;CheckTx&lt;&#x2F;code&gt;, which is supposed to validate the transaction before entering it into the mempool and relaying it to other nodes. This flexible approach allows for the ABCI to be written in any language as long as it responds to the calls appropriately. We decided to write our implementation in Rust.&lt;&#x2F;p&gt;
&lt;p&gt;You can see the code for this implementation &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;AleoHQ&#x2F;aleo_lambda_blockchain&quot;&gt;here&lt;&#x2F;a&gt;. The repository also contains a CLI application to compile, deploy and execute programs and send these transactions to the blockchain easily. It also has several other features related to accounts, such as retrieving a user’s balance or seeing which &lt;em&gt;records&lt;&#x2F;em&gt; the account possesses. We will explain the motivation behind records in the integration section of this post, but they are essentially a way to encapsulate state and ownership functionality in the blockchain.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;design-considerations&quot;&gt;Design considerations&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;architecture.png?raw=true&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Considering the VM implementation and the requirements from the blockchain, we had to make several design decisions on the consensus layer. Here’s a general overview of how Tendermint Core was implemented:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The Tendermint Core and the ABCI need to run side by side in the same node and are coupled by the interface defined by the protocol&amp;#39;s hooks.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * All code executed on the ABCI needs to be deterministic and isolated from external services since we want to ensure all transactions perform deterministic state changes on every node in the network.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The ABCI implements two databases to maintain the current state of the blockchain: The program store and the record store. &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      * The program store keeps track of every deployed program&amp;#39;s verifying keys and uses. The store contains the `credits` program&amp;#39;s keys as a built-in default. This program defines credit records. It is essentially a native Aleo program that has functions for managing credit records.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      * The record store encapsulates functionality related to validating whether the records utilized in incoming transactions have already been spent. &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        * The privacy requirements imply that we cannot disclose what records have been spent and which have not. Due to this, any record in the blockchain (i.e., it was output from the execution of a program) is stored separately from records that have been spent, of which we only store serial numbers.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The genesis block needs to be provided to Tendermint on startup and is done through a JSON file. We have written a particular binary to generate it for any number of nodes and give each of them a fixed amount of starting credits.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * To make testing simple, we have created several `make` targets to initialize and start multiple validators that can run locally or on a remote network.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Both the CLI and the consensus layer support Aleo&amp;#39;s SnarkVM and our own LambdaVM and are currently interchangeable through a compiler flag&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;staking&quot;&gt;Staking&lt;&#x2F;h3&gt;
&lt;p&gt;Tendermint supports adding new nodes to the network. In general, nodes in the network can work in two different modes:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Non-validator: The node catches up with the blockchain by performing every transaction but does not have voting power to validate and commit blocks.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Validator: The node is part of the network and can vote and sign blocks.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To add a non-validator, the node needs to have the same Genesis block and point to persistent peers (IP addresses acting as fixed nodes in the network). To transform a node into a validator, the ABCI needs to implement functionality to update the voting power of a Tendermint node.&lt;&#x2F;p&gt;
&lt;p&gt;For this, we implemented a &lt;code&gt;stake&lt;&#x2F;code&gt; command to “freeze” credits by exchanging them for staking records (and increase the voting power of a validator), which you can, in turn, &lt;code&gt;unstake&lt;&#x2F;code&gt; whenever you desire (decreasing the voting power accordingly).&lt;&#x2F;p&gt;
&lt;p&gt;When a node is a validator, it gets rewards on each block commit where it was involved.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;virtual-machine&quot;&gt;Virtual Machine&lt;&#x2F;h2&gt;
&lt;p&gt;At a high level, our VM provides an API to take an Aleo program that looks like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;program main.aleo;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;function add:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    input r0 as u16.public;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    input r1 as u16.private;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    add r0 r1 into r2;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    output r2 as u16.public;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And generate a pair of proving and verifying keys for it (this is usually called &lt;em&gt;building&lt;&#x2F;em&gt; or &lt;em&gt;synthesizing&lt;&#x2F;em&gt; the program), allowing anyone to execute the program and provide proof of it or verify said proof. The consensus layer uses this to deploy programs (i.e., upload their verifying key along with the code), execute them, and verify them.&lt;&#x2F;p&gt;
&lt;p&gt;Internally, this VM uses &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;arkworks-rs&quot;&gt;Arkworks&lt;&#x2F;a&gt; as a backend. Programs are turned into a Rank One Constraint System (&lt;code&gt;R1CS&lt;&#x2F;code&gt;), which is then passed on to the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;arkworks-rs&#x2F;marlin&quot;&gt;Marlin&lt;&#x2F;a&gt; prover for execution. As we started using Arkworks, we noticed some aspects of the API and its genericity were becoming a burden for developers, so we created a thin wrapper around it called &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;simpleworks&quot;&gt;Simpleworks&lt;&#x2F;a&gt;, along with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;lambdaclass.github.io&#x2F;simpleworks&#x2F;overview.html&quot;&gt;some basic documentation&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;example&quot;&gt;Example&lt;&#x2F;h3&gt;
&lt;p&gt;Given the following Aleo program&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;program foo.aleo;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;function main:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    input r0 as u64.public;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    input r1 as u64.public;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    add r0 r1 into r2;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    output r2 as u64.public;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Executing the function &lt;code&gt;main&lt;&#x2F;code&gt; would look like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;use lambdavm::jaleo::UserInputValueType::U16;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn main() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    use lambdavm::{build_program, execute_function};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Parse the program&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let program_string = std::fs::read_to_string(&amp;quot;.&#x2F;programs&#x2F;add&#x2F;main.aleo&amp;quot;).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let (program, build) = build_program(&amp;amp;program_string).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let function = String::from(&amp;quot;main&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Declare the inputs (it is the same for public or private)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let user_inputs = vec![U16(1), U16(1)];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Execute the function&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let (_execution_trace, proof) = execute_function(&amp;amp;program, &amp;amp;function, &amp;amp;user_inputs).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let (_proving_key, verifying_key) = build.get(&amp;amp;function).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    assert!(lambdavm::verify_proof(verifying_key.clone(), &amp;amp;user_inputs, &amp;amp;proof).unwrap())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;internals&quot;&gt;Internals&lt;&#x2F;h3&gt;
&lt;p&gt;The most significant task our VM has to perform is turning the program into an arithmetic circuit, as the rest of the work, namely generating the proof and verifying it, is pretty straightforward with the Arkworks API.&lt;&#x2F;p&gt;
&lt;p&gt;Before continuing, you should have at least a basic understanding of arithmetic circuits and how Arkworks lets you work with them. You can read about it &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;lambdaclass.github.io&#x2F;simpleworks&#x2F;overview.html&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;To generate the circuit, we go through the following steps:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Take the program&amp;#39;s source code and parse it into a `Program` containing all the relevant information about it (a list of all input and output instructions, whether they are public or private, a list of all regular instructions like add and its operands, etc.). We currently rely on SnarkVM&amp;#39;s parser but plan to write our own.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Instantiate an Arkworks `ConstraintSystem`, which will hold all our circuit&amp;#39;s constraints by the end.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * For every input instruction, instantiate its corresponding `Gadget`. You can think of a gadget as the equivalent of a native type (like `u8`) inside an arithmetic circuit. If the input is public, the gadget is made public; otherwise, it&amp;#39;s made a `witness`, i.e., private. In our example, the first instruction `input r0 as u16.public` becomes a call to `UInt16Gadget.new_input(...)` and the second instruction becomes `UInt16Gadget.new_witness(...)`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * For every regular instruction, we use the gadget&amp;#39;s associated function to perform the operation and generate its constraints inside our `ConstraintSystem`. In our example, when we encounter the `add r0 r1 into r2;` instruction, we call `UInt16Gadget.addmany(...)`. This is an arkworks provided function that will take a list of `UInt16&amp;#39;s, add them, implicitly mutate the `ConstraintSystem` with all the associated constraints, then return the value of the sum. Not all instructions have a corresponding arkworks function implemented, so for those, we had to roll our own.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * For every output instruction, assign to the register the computed value.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Because a program can have multiple registers interacting with each other, to do the above, we have to keep track of each register and its value as we go. For this, we keep an internal hash table throughout execution.&lt;&#x2F;p&gt;
&lt;p&gt;Additionally, we ran some benchmarks comparing our VM with Aleo’s &lt;code&gt;SnarkVM&lt;&#x2F;code&gt;, and our results show we are a few times faster than it; details will be published in a separate post. The code for benchmarks is in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;aleo_lambda_vm&quot;&gt;our VM Repo&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;vm-consensus-integration-layer&quot;&gt;VM-Consensus Integration Layer&lt;&#x2F;h2&gt;
&lt;p&gt;Above, we discussed how the VM allows running arbitrary Aleo programs that can be deployed, executed locally, and then verified on the Aleo blockchain. Each Aleo transaction is either the deployment or the proof of execution of a program (this is technically inaccurate, as there can be multiple of these per transaction, but we’ll ignore that for simplicity). In the case of executions, nodes use the program’s verifying key to verify the correct execution before committing transactions to a block.&lt;&#x2F;p&gt;
&lt;p&gt;After we got a basic VM version working, we realized that getting a fully functional Aleo blockchain required more work than just the above. Transactions would be of very little use if they proved that some computation was done correctly. To be useful, they also need to &lt;em&gt;modify the state&lt;&#x2F;em&gt;. In Aleo, the state is managed through &lt;em&gt;records&lt;&#x2F;em&gt; in what is essentially a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Unspent_transaction_output&quot;&gt;UTXO&lt;&#x2F;a&gt; model similar to Bitcoin. Typically, when a user sends a transaction, they will spend some records they own to create new ones in their place.&lt;&#x2F;p&gt;
&lt;p&gt;Because Aleo is entirely private, a transaction can’t just publish the records it wants to spend along with a signature; it has to &lt;em&gt;prove&lt;&#x2F;em&gt; ownership and existence of records in zero knowledge, then &lt;em&gt;encrypt&lt;&#x2F;em&gt; the records so only its owner can decrypt on-chain.&lt;&#x2F;p&gt;
&lt;p&gt;This means that, to integrate with the consensus layer and get a fully functional blockchain, we need a bit more. The VM can prove the correct execution of programs, but the Zero-Knowledge proof that comes with a transaction also needs to include the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * A signature in Zero-Knowledge, proof that the signature provided is the correct one. Remember, we can&amp;#39;t just show the user&amp;#39;s address sending the transaction.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * A proof that the caller of the transaction actually _owns_ the record they&amp;#39;re spending.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * A proof that the records being spent are on-chain. This is essentially verifying a Merkle path in Zero-Knowledge.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * A proof that the input records have not been spent. This is a bit involved as it requires deriving a record&amp;#39;s `serial number` (think of it as the `nullifier` if you know ZCash) in Zero-Knowledge.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We also talked about how records should be stored encrypted on-chain so that only someone possessing the record owner’s view key can decrypt them (in Aleo, the &lt;code&gt;view key&lt;&#x2F;code&gt; is just another key tied to an account that allows record decryption).&lt;&#x2F;p&gt;
&lt;p&gt;There’s a catch here, though. When, for instance, user A wants to send money to user B, they have to create a record owned by B and encrypt it so that only B can decrypt it. But &lt;code&gt;A&lt;&#x2F;code&gt; does not necessarily have &lt;code&gt;B&lt;&#x2F;code&gt;’s view key, only their address. This means the encryption scheme used by Aleo cannot be symmetric, as that would require user &lt;code&gt;A&lt;&#x2F;code&gt; to have &lt;code&gt;B&lt;&#x2F;code&gt;’s view key to send them money, not just their address.&lt;&#x2F;p&gt;
&lt;p&gt;To accomplish this, records are encrypted using a scheme called &lt;code&gt;ECIES&lt;&#x2F;code&gt; (Elliptic Curve Integrated Encryption Scheme). We’re not going to go into detail about how it works, but it’s a combination of a Diffie-Hellman key exchange with a symmetric encryption scheme.&lt;&#x2F;p&gt;
&lt;p&gt;We introduced a middle layer between our VM and the Consensus Layer to solve all the problems discussed above. This middle layer handles everything related to records, their encryption, and the snarks required for the state transition proofs.&lt;&#x2F;p&gt;
&lt;p&gt;In the original SnarkVM implementation, this middle layer does not really exist, as it’s part of the VM itself, but we found it more beneficial to separate these two concerns.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;work-in-progress&quot;&gt;Work in Progress&lt;&#x2F;h2&gt;
&lt;p&gt;This project is still in active development, and a few things are being worked on. They include:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Support for some data types and instructions on the VM, including the `group` data type (elliptic curve elements) and things like `BHP` commitments. You can check out a complete list on [the README](https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;aleo_lambda_vm).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Some of the circuits mentioned above prove the correctness of state transitions.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The generation of the proof that input records exist on-chain.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Due to how we store record information on the blockchain and considering the privacy requirements of the blockchain, asking for a user balance or unspent records from the CLI is currently not trivial: We need to ask for all records that have ever existed in addition to all serial numbers from records that have been spent and attempt to decrypt them on the user&amp;#39;s side. Some strategies to optimize this process include keeping track of records locally and only adding newly-created ones as the blockchain grows.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We plan to finish these tasks in the next four weeks. While many things could be improved, the project is already production ready.&lt;&#x2F;p&gt;
&lt;p&gt;We have many ideas and comments about improving the SnarkVM and Aleo in general, but we will leave that for another series of posts.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>What is property-based testing?  Two examples in Rust</title>
          <pubDate>Fri, 03 Feb 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/what-is-property-based-testing/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/what-is-property-based-testing/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/what-is-property-based-testing/">&lt;p&gt;This article will explore property-based tests and demonstrate their use in two of our open-source projects.&lt;br &#x2F;&gt;
First, let’s explain what a property-based test (PBT) is: If a picture is worth a thousand words, a PBT is worth a thousand unit tests (although this is tunable, as we will see later).&lt;br &#x2F;&gt;
It was born in the functional programming community and is very different from conventional methods. It’s a great tool to consider when testing the correctness of our programs.&lt;&#x2F;p&gt;
&lt;p&gt;As its name suggests, it is based on testing the properties of our code. In other words, invariants or behavior that we expect to be consistent across inputs. When we write a unit test, we test a function&#x2F;method for a specific set of parameters. So, we usually test with a representative (but small) number of inputs where we think the code may hide bugs. In contrast, a property-based test generates many random inputs and checks that the property is met for all of them. If it finds an unsatisfied value, it proceeds with a shrinking process to find the smallest input that breaks the property. That way, it is easier to reproduce the issue.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-first-example&quot;&gt;A First Example&lt;&#x2F;h2&gt;
&lt;p&gt;Enough talk; let us use a simple example to show how it works in practice. We’ll work with Rust to illustrate the benefits of this way of testing.&lt;&#x2F;p&gt;
&lt;p&gt;There are several libraries for doing property-based tests in Rust, but we chose &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;proptest-rs&#x2F;proptest&quot;&gt;proptest&lt;&#x2F;a&gt; because it’s straightforward to use and is being actively maintained.&lt;&#x2F;p&gt;
&lt;p&gt;In this example, we create a test for a function that adds two positive numbers. The test checks a property of positive number addition: the result is greater than each of the individual parts. We use the &lt;code&gt;prop_assert!&lt;&#x2F;code&gt; macro to verify that the property holds.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;use proptest::prelude::*;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn add(a: i32, b: i32) -&amp;gt; i32 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	a + b&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;proptest! {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	&#x2F;&#x2F; Generate 1000 tests.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	#![proptest_config(ProptestConfig::with_cases(1000))]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	#[test]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	fn test_add(a in 0..1000i32, b in 0..1000i32) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		let sum = add(a, b);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		prop_assert!(sum &amp;gt;= a);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		prop_assert!(sum &amp;gt;= b);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		prop_assert_eq!(a + b, sum);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let us see what happens if we change the first property to an incorrect one:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; prop_assert!(sum &amp;gt;= a); previous line&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;prop_assert!(sum &amp;lt;= a)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We will receive a report with the smallest instance that breaks the property.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;---- test_add stdout ----&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;thread &amp;#39;test_add&amp;#39; panicked at &amp;#39;Test failed: assertion failed: sum &amp;lt;= a at src&#x2F;lib.rs:13; minimal failing input: a = 0, b = 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        successes: 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        local rejects: 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        global rejects: 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;#39;, src&#x2F;lib.rs:7:1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To build tests for more complex structures, we can use regular expressions (if we have a way of building our data type from a string) or use &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;proptest&#x2F;latest&#x2F;proptest&#x2F;strategy&#x2F;trait.Strategy.html&quot;&gt;Strategies&lt;&#x2F;a&gt;, which are used to control how values are generated and how the shrinking process is done.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;case-studies&quot;&gt;Case studies&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;case-study-1-cairo-rs&quot;&gt;Case study 1: cairo-rs&lt;&#x2F;h3&gt;
&lt;p&gt;Let’s start with a more practical example. At LambdaClass, we developed a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;cairo-rs&quot;&gt;Rust implementation of the Cairo virtual machine&lt;&#x2F;a&gt;. Cairo stands for CPU Algebraic Intermediate Representation. It’s a programming language for writing provable programs, where one party can prove to another that a computation was executed correctly by producing a zero-knowledge proof.&lt;&#x2F;p&gt;
&lt;p&gt;Executing a program made in Cairo involves operating with a lot of field elements (i.e., numbers between 0 and a huge prime number). So every operation (addition, subtraction, multiplication, and division) needs to evaluate to a felt (field element) in the range [0; PRIME -1].&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;proptest! {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  #[test]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &#x2F;&#x2F; Property-based test that ensures, for 100 felt values that are randomly generated each time tests are run, that a new felt doesn&amp;#39;t fall outside the range  [0, PRIME-1].&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &#x2F;&#x2F; In this and some of the following tests, The value of {x} can be either [0]  or a huge number to try to overflow the value of {p} and thus ensure the modular arithmetic is working correctly.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  fn new_in_range(ref x in &amp;quot;(0|[1-9][0-9]*)&amp;quot;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let x = &amp;amp;Felt::parse_bytes(x.as_bytes(), 10).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let p = &amp;amp;BigUint::parse_bytes(PRIME_STR[2..].as_bytes(), 16).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    prop_assert!(&amp;amp;x.to_biguint() &amp;lt; p);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  #[test]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &#x2F;&#x2F; Property-based test that ensures, for 100 felt values that are randomly generated each time tests are run, that the negative of a felt doesn&amp;#39;t fall outside the range [0, PRIME-1].&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  fn neg_in_range(ref x in &amp;quot;(0|[1-9][0-9]*)&amp;quot;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let x = &amp;amp;Felt::parse_bytes(x.as_bytes(), 10).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let neg = -x;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let as_uint = &amp;amp;neg.to_biguint();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let p = &amp;amp;BigUint::parse_bytes(PRIME_STR[2..].as_bytes(), 16).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    prop_assert!(as_uint &amp;lt; p);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  #[test]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &#x2F;&#x2F; Property-based test that ensures, for 100 {x} and {y} values that are randomly generated each time tests are run, that multiplication between two felts {x} and {y} and doesn&amp;#39;t fall outside the range [0, PRIME-1]. The values of {x} and {y} can be either [0] or a very large number.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  fn mul_in_range(ref x in &amp;quot;(0|[1-9][0-9]*)&amp;quot;, ref y in &amp;quot;(0|[1-9][0-9]*)&amp;quot;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let x = &amp;amp;Felt::parse_bytes(x.as_bytes(), 10).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let y = &amp;amp;Felt::parse_bytes(y.as_bytes(), 10).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let p = &amp;amp;BigUint::parse_bytes(PRIME_STR[2..].as_bytes(), 16).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let prod = x * y;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let as_uint = &amp;amp;prod.to_biguint();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    prop_assert!(as_uint &amp;lt; p, &amp;quot;{}&amp;quot;, as_uint);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We already found two hard-to-find bugs by using a suite of property-based tests for each arithmetical operation. Also, it helped us easily change our field elements’ internal implementation to a more performant one and be confident that we didn’t break anything.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;case-study-2-patricia-merkle-tree&quot;&gt;Case study 2: Patricia Merkle Tree&lt;&#x2F;h3&gt;
&lt;p&gt;At LambdaClass, we are also developing a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;merkle_patricia_tree&quot;&gt;Merkle Patricia tree library&lt;&#x2F;a&gt; (like those used in Ethereum and many other cryptography-related projects). To test the correctness of the implementation, we decided to make property-based tests by comparing the results of our library’s operations against the results of a reference implementation, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;citahub&#x2F;cita-trie&quot;&gt;cita-trie&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;For testing, let’s generate some inputs for creating two trees: one using the reference implementation and one using our library.&lt;br &#x2F;&gt;
This time the property that we want to test is that for every generated tree from our library, its root hash matches the root hash of the reference implementation.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn proptest_compare_root_hashes(path in vec(any::&amp;lt;u8&amp;gt;(), 1..32), value in vec(any::&amp;lt;u8&amp;gt;(), 1..100)) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  use cita_trie::MemoryDB;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  use cita_trie::{PatriciaTrie, Trie};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  use hasher::HasherKeccak;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &#x2F;&#x2F; Prepare the data for inserting it into the tree&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  let data: Vec&amp;lt;(Vec&amp;lt;u8&amp;gt;, Vec&amp;lt;u8&amp;gt;)&amp;gt; = vec![(path, value)];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &#x2F;&#x2F; Creates an empty patricia Merkle tree using our library and &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &#x2F;&#x2F; Keccak256 as the hashing algorithm.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  let mut tree = PatriciaMerkleTree::&amp;lt;_, _, Keccak256&amp;gt;::new();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &#x2F;&#x2F; insert the data into the tree.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  for (key, val) in data.clone().into_iter() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    tree.insert(key, val);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &#x2F;&#x2F; computes the root hash using our library&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  let root_hash = tree.compute_hash().as_slice().to_vec();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &#x2F;&#x2F; Creates a cita-trie implementation of the&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &#x2F;&#x2F; Patricia Merkle tree.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  let memdb = Arc::new(MemoryDB::new(true));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  let hasher = Arc::new(HasherKeccak::new());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  let mut trie = PatriciaTrie::new(Arc::clone(&amp;amp;memdb), Arc::clone(&amp;amp;hasher));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &#x2F;&#x2F; Insert the data into the cita-trie tree.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  for (key, value) in data {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    trie.insert(key.to_vec(), value.to_vec()).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &#x2F;&#x2F; Calculates the cita-tree&amp;#39;s root hash.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  let reference_root = trie.root().unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  prop_assert_eq!(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    reference_root,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    root_hash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Using this technique, we can ensure that our implementation behaves the same way as the reference one.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;closing-words&quot;&gt;Closing words&lt;&#x2F;h2&gt;
&lt;p&gt;In conclusion, property-based testing is a powerful and effective way to test the correctness of our programs. Testing properties helps find bugs and ensure that our program meets invariants across a wide range of inputs. In this article, we demonstrated property-based testing in two open-source projects. We hope you consider it in your testing practices.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;related-resources&quot;&gt;Related Resources&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. QuickCheck original paper &amp;lt;https:&#x2F;&#x2F;www.cs.tufts.edu&#x2F;~nr&#x2F;cs257&#x2F;archive&#x2F;john-hughes&#x2F;quick.pdf&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. _Property-Based Testing with PropEr, Erlang, and Elixir_ by Fred Hebert &amp;lt;https:&#x2F;&#x2F;propertesting.com&#x2F;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Rust port of QuickCheck &amp;lt;https:&#x2F;&#x2F;github.com&#x2F;BurntSushi&#x2F;quickcheck&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. proptest book &amp;lt;https:&#x2F;&#x2F;altsysrq.github.io&#x2F;proptest-book&#x2F;intro.html&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</description>
      </item>
      <item>
          <title>Champagne SuperNova, incrementally verifiable computation</title>
          <pubDate>Thu, 02 Feb 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/champagne-supernova-incrementally-verifiable-computation-2/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/champagne-supernova-incrementally-verifiable-computation-2/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/champagne-supernova-incrementally-verifiable-computation-2/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;In the lasts posts we’ve been writing about proving systems and incremental verifiable computation:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Pinocchio Virtual Machine: Nearly Practical Verifiable Computation](&#x2F;pinocchio-virtual-machine-nearly-practical-verifiable-computation&#x2F;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Decentralized private computation: ZEXE and VERI-ZEXE](&#x2F;decentralized-private-computations-zexe-and-veri-zexe&#x2F;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * [Incrementally verifiable computation: NOVA](&#x2F;incrementally-verifiable-computation-nova&#x2F;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Incremental proof systems offer some advantages over conventional proving systems:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * They do not require static bounds on loop iterations, making them better suited for programs with dynamic flow control.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * They require minimal memory overhead, as the prover only needs space proportional to the necessary space to perform the step instead of storing the whole computation trace.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * They are well suited for the distribution and parallelization of proof generation.  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The prover can run the program, keeping track of the input and output variables and state changes, and then generate the proofs in parallel using CPU or GPU for each step of the computation. Better still, the proofs can be conveniently aggregated into a single one, which the verifier can check.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;incrementally-verifiable-computation-nova&#x2F;&quot;&gt;Incrementally verifiable computation&lt;&#x2F;a&gt; (IVC) offers an approach to prove the integrity of machine executions. To use ICV, we need to design a universal circuit that can perform any machine-supported instruction. At each step, we have to call this circuit. This is inconvenient since the cost of proving a step is proportional to the size of the universal circuit, even if the program only executes one of the supported instructions at a much lower cost. One way to deal with this shortcoming is by constructing virtual machines with a minimal instruction set to bound the size of the universal circuit.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2022&#x2F;1758&quot;&gt;SuperNova&lt;&#x2F;a&gt; provides a cryptographic proof system (comprising a prover and a verifier) based on a virtual machine and a program designed to run over such a machine, satisfying the following properties:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Succinctness: the size of the proof and the time to verify said proof are at most polylogarithmic in the execution time of the program.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Zero-knowledge: The proof does not reveal anything other than the correct execution of the problem.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Convenient cost profile: The cost of proving a step of the program is proportional to the size of the circuit representing such instruction.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Incremental proof generation: the prover can generate a proof for each step of the program&amp;#39;s execution independently and later combine those proofs into a single one without increasing the size of the proofs.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;SuperNova leverages folding schemes (a cryptographic primitive used previously by &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;microsoft&#x2F;Nova&quot;&gt;Nova&lt;&#x2F;a&gt;), using relaxed-committed &lt;a href=&quot;&#x2F;incrementally-verifiable-computation-nova&#x2F;&quot;&gt;R1CS&lt;&#x2F;a&gt;, to realize a non-uniform IVC. SuperNova is a generalization of Nova, as it supports machines with a rich instruction set (Nova was limited to one instruction). In the following sections, we will break down the different components needed for SuperNova and how to achieve non-uniform IVC.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;commitment-scheme-for-vectors&quot;&gt;Commitment scheme for vectors&lt;&#x2F;h2&gt;
&lt;p&gt;A &lt;a href=&quot;&#x2F;the-hunting-of-the-zk-snark&#x2F;&quot;&gt;commitment scheme&lt;&#x2F;a&gt; for vectors is a collection of three efficient algorithms:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Parameter generation, $\mathrm{Gen}(1^\lambda)=pp$: given a security level parameter, $\lambda$, the algorithm outputs public parameters $pp$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Commit, $\mathrm{commit}(pp,x,r)=\mathrm{cm}$: given the public parameters, a vector, and some randomness, $r$, outputs a commitment $\mathrm{cm}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Open, $\mathrm{open}(pp,\mathrm{cm},x,r)={0,1}$: given a commitment, the vector, randomness, and public parameters, the algorithm verifies whether the commitment given corresponds to the vector $x$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The commitment scheme has to satisfy the following properties:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Binding: given a commitment $\mathrm{cm}$, it is impossible to find two $x_1$, $x_2$ such that $\mathrm{commit}(pp,x_1,r)=\mathrm{commit}(pp,x_2,r)$. Simply put, the commitment binds us to our original value $x$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Hiding: the commitment reveals nothing from $x$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The following two properties are useful in our context and satisfied by some commitment schemes, such as Pedersen’s:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Additively homomorphic: given $x_1$, $x_2$ a commitment is additively homomorphic if $\mathrm{commit}(pp,x_1+x_2,r_1+r_2)=\mathrm{commit}(pp,x_1,r_1)+\mathrm{commit}(pp,x_2,r_2)$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Succinct: the size of the commitment is much smaller than the corresponding vector (for example, $\mathrm{commit}(pp,x,r)=\mathcal{O}(\log(x))$).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;SuperNova can be instantiated with any commitment scheme satisfying the four properties above, such as Pedersen’s, KZG, or Dory.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;computational-model-of-non-uniform-ivc-nivc&quot;&gt;Computational model of non-uniform IVC (NIVC)&lt;&#x2F;h2&gt;
&lt;p&gt;We can think of the program as a collection of $n+1$ non-deterministic, polynomial time computable functions, ${f_1,f_2,…,f_n,\phi}$, where each function receives $k$ input and $k$ output variables; each $f_j$ can also take non-deterministic input. The function $\phi$ can take non-deterministic input variables and output an element $j=\phi(z=(x,w))$, choosing one of the $f_i$. Each function is represented as a quadratic rank-one constraint system (R1CS), an NP-complete problem. In IVC, the prover takes as input at step $k$ $(k,x_0,x)$ and a proof $\Pi_k$ that proves knowledge of witnesses $(w_0,w_1,…,w_{k-1})$ such that&lt;br &#x2F;&gt;
$$ x_{j+1}=F(x_j,w_j) $$&lt;br &#x2F;&gt;
for all $j=0,1,…,k$ we have $x=x_{k+1}$. In other words, given a proof that shows that the previous step has been computed correctly and the current state $x_k$, we get the next state $x_{k+1}$ and a proof $\Pi_{k+1}$ showing that we computed step $k$ correctly. In the NIVC setting, $\phi$ selects which function we are going to use,&lt;br &#x2F;&gt;
$$ x_{j+1}=F_{\phi(x_j,w_j)} (x_j,w_j) $$&lt;&#x2F;p&gt;
&lt;p&gt;At each step, SuperNova folds an R1CS instance and its witness, representing the last step of the program’s execution into a running instance (it takes two $N$-sized NP instances into a single $N$-sized NP instance). The prover uses an augmented circuit containing a verifier circuit and the circuit corresponding to the function $f_j$ being executed. The verifier circuit comprises the non-interactive folding scheme and a circuit for computing $\phi$. We will represent the augmented functions as $f^\prime_j$.&lt;&#x2F;p&gt;
&lt;p&gt;One problem with the folding scheme is that we have multiple instructions, each having its R1CS representation. We could take the path of universal circuits, but this would make us pay a high cost for many cheap instructions. In Nova, we avoided the problem since we only had one type of instruction. To deal with multiple instructions, SuperNova works with $n$ running instances $U_i$, where $U_i(j)$ attests to all previous executions of $f^\prime_j$, up to step $i-1$. Therefore, checking all $U_i$ is equivalent to checking all $i-1$ steps. Each $f^\prime_j$ takes as input $u_i$, corresponding to step $i$, and folds it to the corresponding $U_i$ instance. We can think of it as looking at the function we want to execute and performing the instance folding with the one related to the previous executions. By doing so, we pay the cost for each instruction only when it is used, at the expense of keeping more running instances and updating accordingly.&lt;&#x2F;p&gt;
&lt;p&gt;The verifier circuit corresponding to $f_j^\prime$ does the following steps:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Checks that $U_i$ and $pc_i=\phi(x_{i-1},w_{i-1})$ (the index of the function executed previously) are contained in the public output of the instance $u_i$. This enforces that the previous step produces both $U_i$ and $pc_i$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Runs the folding scheme&amp;#39;s verifier to fold an instance and updates the running instances, $U_{i+1}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Calls $\phi(x_i,w_i)=pc_{i+1}$ to obtain the index of the following function to invoke.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;IVC is a powerful cryptographic primitive which allows us to prove the integrity of computation in an incremental fashion. This strategy is well-suited for virtual machine executions and general programs with dynamic flow control. We could achieve this by using universal circuits, but at the expense of a considerable cost for each instruction, no matter how cheap it could be. Nova introduced folding schemes, allowing one to realize IVC for a single instruction. SuperNova generalizes Nova to multiple instructions by adding a selector function $\phi$, choosing the instruction to be executed at each step. To support several instructions, SuperNova needs to maintain separate bookkeeping for each function’s execution. This construction has many exciting applications since we could realize IVC without requiring expensive arbitrary circuits.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Proof aggregation schemes:  SnarkPack and aPlonk</title>
          <pubDate>Fri, 27 Jan 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/proof-aggregation-schemes/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/proof-aggregation-schemes/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/proof-aggregation-schemes/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;the-hunting-of-the-zk-snark&#x2F;&quot;&gt;zk-SNARKs&lt;&#x2F;a&gt; are powerful cryptographic primitives, allowing one party, known as the prover, to show to a second party, the verifier, that he knows a given secret, without revealing anything about it. This has applications, for example, in decentralized private computations, where we can delegate an expensive computation to an untrusted server and receive cryptographic proof attesting to the correctness of the computation, without leaking sensitive information. We can also leverage zk-SNARKs to solve the problems of privacy and scalability affecting most decentralized ledgers. There, each node must perform the computation independently to check its validity. This means that the less powerful devices can act as bottlenecks, especially when the computations are expensive, affecting scalability. However, instead of having each node re-execute each computation, we could have them verify a short proof that shows that the computation is correct. In that case, we can lessen the burden on the entire system.&lt;&#x2F;p&gt;
&lt;p&gt;One of the main problems with zk-SNARKs is the proof’s generation time. Typically, proof generation involves transforming computations into some NP-complete problem, where we can prove the correctness of the calculation. Among them are &lt;a href=&quot;&#x2F;how-to-transform-code-into-arithmetic-circuits&#x2F;&quot;&gt;arithmetic circuit satisfiability&lt;&#x2F;a&gt; or systems of quadratic constraints (rank one constraint system, R1CS). We then have to perform some expensive computations, such as multiscalar multiplications (&lt;a href=&quot;&#x2F;multiscalar-multiplication-strategies-and-challenges&#x2F;&quot;&gt;MSM&lt;&#x2F;a&gt;) and elliptic curve pairings to check the solution. Several strategies have been adopted to lessen the computational cost, such as proof composition, batching, recursion, dealing with an increased number of smaller proofs, and exploiting the advantages of polynomial commitment schemes.&lt;&#x2F;p&gt;
&lt;p&gt;In a &lt;a href=&quot;&#x2F;incrementally-verifiable-computation-nova&#x2F;&quot;&gt;previous post&lt;&#x2F;a&gt;, we covered incrementally verifiable computation (IVC) and folding schemes, which give us ways to realize IVC in practice. We covered the basics of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;microsoft&#x2F;Nova&quot;&gt;Nova&lt;&#x2F;a&gt; and how the folding scheme works. We will now turn our attention to proof aggregation schemes: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2021&#x2F;529.pdf&quot;&gt;SNARKPack&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2022&#x2F;1352.pdf&quot;&gt;aPlonK&lt;&#x2F;a&gt;. These allow us to reduce the total size of the proofs and their associated verification time: for \( n \) proofs, the size and verification time of the aggregated proof will be \( \mathcal{O}(n) \), which is a significant reduction, especially for a large number of proofs. SNARKPack is built on top of the Groth16 SNARK, while aPlonk works with the &lt;a href=&quot;&#x2F;the-hunting-of-the-zk-snark&#x2F;&quot;&gt;Plonk&lt;&#x2F;a&gt; proving system. Both are among the most widely used SNARKs and use trusted setups, resulting from setup ceremonies involving multi-party computations.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;snarkpack&quot;&gt;SNARKPack&lt;&#x2F;h2&gt;
&lt;p&gt;In the Groth16 scheme, a proof \( \pi \) consists of three &lt;a href=&quot;&#x2F;need-for-speed-elliptic-curves-chapter&#x2F;&quot;&gt;elliptic curve&lt;&#x2F;a&gt; group elements, \( A,B,C \). Both \( A,B \) belong to the group \( \mathbb{G_1} \) and \( C \) belongs to the group \( \mathbb{G_2} \). The groups have the same &lt;a href=&quot;&#x2F;need-for-speed-elliptic-curves-chapter&#x2F;&quot;&gt;order&lt;&#x2F;a&gt; (number of elements), \( p \) and are among the torsion groups of order \( p \) of the elliptic curve over an extension field. We can define a bilinear map (or pairing operation) by taking an element from each group and outputting an element on a third group \( \mathbb{G_t} \): \( e:\mathbb{G_1} \times \mathbb{G_2} \rightarrow \mathbb{G_t}\). The operation has to fulfill the property \( e( g^a , h^b ) = e( g , h )^{a b}\) to be bilinear. In the equation before, \( a,b \) are numbers, and \( g,h \) are the generators of the groups \( \mathbb{G_1} \) and \( \mathbb{G_2} \), respectively (we say an element of the group, \( g \), is a generator if any element in the group can be obtained by repeatedly adding it). We perform the proof verification in Groth16 via the pairing operation,&lt;br &#x2F;&gt;
\[ e(A,C) = Ye(B,D)\]&lt;br &#x2F;&gt;
where \( D \) is an element of \( \mathbb{G_2} \) and \( Y \) is an element of \( \mathbb{G_t} \). The main idea behind the aggregation of \( n \) Groth16 proofs is that we can verify all of them simultaneously by using a random linear combination (up to some tiny error). This way, we only need to perform one pairing operation instead of \( n \),&lt;br &#x2F;&gt;
\[ \prod e(A_k,C_k)^{ r^k } = \prod Y_k^{ r^k } \prod e(B_k^{ r^k },D)\]&lt;br &#x2F;&gt;
where \( r \) is a randomly sampled number, and \( \prod \) means that we take the product of all possible pairings.&lt;&#x2F;p&gt;
&lt;p&gt;The following terms are defined to ease notation:&lt;br &#x2F;&gt;
\( Z_{AC} = \prod e(A_k,C_k)^{ r^k } \)&lt;br &#x2F;&gt;
\( Y_{prod} = \prod Y_k \)&lt;br &#x2F;&gt;
\( Z_B = \prod e(B_k^{ r^{k} },D) \)&lt;br &#x2F;&gt;
\( Z_{AC} = Y_{prod} Z_B \)&lt;br &#x2F;&gt;
After checking that this last equation holds, we are left with the task of verifying that, for some initial committed vectors \( A=(A_1,A_2,…A_n) \), \( B=(B_1,B_2,…,B_n) \) and \( C=(C_1,C_2,…,C_n) \), \(Z_{AC},Z_B \) are consistent with those specifications. We check this using two inner pairing arguments:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. The target inner pairing product (TIPP) shows that \\( Z_{AC} = \prod e( A_k , C_k )^{ r^k } \\).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. The multi-exponentiation inner pairing product (MIPP) shows that \\( Z_B = \prod e( B_k^{ r^{k} }, D) \\).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We need efficient commitment schemes with homomorphic and collapsing properties to build these inner pairing products. We say that a commitment is additively homomorphic if, given two elements, \( a,b \), the commitment scheme satisfies that \( \mathrm{cm}(a+b)=\mathrm{cm}(a)+\mathrm{cm}(b) \). Pedersen and Kate-Zaverucha-Goldberg commitments have this property, for example. To achieve logarithmic proof size, the authors of SNARKPack use the same strategy as bulletproofs, which is based on an inner product argument. These commitments are also homomorphic in the key space: given two keys \( k_1,k_2 \) and for any message \( m \), we have that \( \mathrm{cm}(m,k_1+k_2)=\mathrm{cm}(m,k_1)+\mathrm{cm}(m,k_2)\).&lt;&#x2F;p&gt;
&lt;p&gt;The protocol uses the trusted setups of two large setup ceremonies: Filecoin and Zcash. In Groth16, the structured reference string (SRS), which is the outcome of the ceremony, consists of the powers of a random element \( \tau \), hidden inside the groups \( \mathbb{G_1}, \mathbb{G_2} \). Given the generators \( g,h \), the SRS is given by \( {g, g^\tau , g^{ \tau^2 },…g^{ \tau^d }}={g,g_1,g_2,…} \) and \( {h, h^\tau , h^{ \tau^2 },…,h^{ \tau^d }}={h,h_1,h_2,…} \). These will allow us to commit to polynomials and verify claims over them.&lt;&#x2F;p&gt;
&lt;p&gt;We can now create pair group commitments by using the two SRS. To ease notation, we will call&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. \\( w_1 = (g,g_{11}, h_{12},...) \\) and \\( v_1 = (h,h_{11},h_{12},...) \\) are the SRS for ceremony 1.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. \\( w_2 = (g,g_{21}, h_{22},...) \\) and \\( v_2 = (h,h_{21},h_{22},...) \\) are the SRS for ceremony 2.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There are two versions of these commitments: single group and double group. The former takes as commitment key \( k_s=(v_1,v_2) \), while the latter uses \( k_d=(v_1,w_1,v_2,w_2) \).&lt;&#x2F;p&gt;
&lt;p&gt;The single group commitment takes a vector \( A \) and the key \( k_s \) and outputs two group elements:&lt;br &#x2F;&gt;
\[ \mathrm{cm_S}(A,k_s)=(t_A,u_A)\]&lt;br &#x2F;&gt;
where&lt;br &#x2F;&gt;
\( t_A=e(A_1,h)\times e(A_2,h_{11})\times e(A_3,h_{12})\times…. = A\cdot v_1 \)&lt;br &#x2F;&gt;
\( t_A=e(A_1,h)\times e(A_2,h_{21})\times e(A_3,h_{22})\times…. = A\cdot v_2 \)&lt;&#x2F;p&gt;
&lt;p&gt;The double commitment takes vectors \( A \) and \( C \) formed of elements in \( \mathbb{G_1} \) and \( \mathbb{G_2} \), respectively and \( k_d \) and outputs two elements:&lt;br &#x2F;&gt;
\[ \mathrm{cm_d}(A,C)=(t_{AC},u_{AC}) \]&lt;br &#x2F;&gt;
with&lt;br &#x2F;&gt;
\( t_{AC} = (A\cdot v_1)(C\cdot w_1) = (\prod e(A_k,h_{1,{k-1}})(\prod e(g_{1,k-1},C_k)) \)&lt;br &#x2F;&gt;
\( u_{AC}=(A\cdot v_2)(C\cdot w_2) = (\prod e(A_k,h_{2,{k-1}})(\prod e(g_{2,{k-1}},C_k)) \)&lt;&#x2F;p&gt;
&lt;p&gt;We will use the double commitment in conjunction with TIPP to show that \( Z_{AC} = \prod e(A , C)^{ r^k } \), while the MIPP will be used with the single commitment to see that \( Z_B = \prod e(B_k^{ r^k },D) \). There are two relations to be checked:&lt;br &#x2F;&gt;
\[ \mathcal{R_{MIPP}}={ (t_B,u_B,r,Z_B,B,r_v ): Z_B=B_k^{ r^k } \wedge (u_B,t_B) = \mathrm{cm_s}(B) \wedge (r_v)_{i} = r^{i-1} }\]&lt;&#x2F;p&gt;
&lt;p&gt;\[ \mathcal{R_{TIPP}} = (t_{AC},u_{AC},r,Z_{AC},A,C,r_v ): Z_{AC} = \prod e(A_k,C_k)^{ r^k } \wedge \]&lt;&#x2F;p&gt;
&lt;p&gt;\[ (u_{AC},t_{AC}) = \mathrm{cm_d}(A,C) \wedge (r_v)_{i} = r^{i-1} \]&lt;&#x2F;p&gt;
&lt;p&gt;In simple words, in each relation, we check that the value is correct and that the commitments are valid.&lt;&#x2F;p&gt;
&lt;p&gt;For the exact details of the proving and verification algorithms, we refer the reader to the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2021&#x2F;529.pdf&quot;&gt;source&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;In the case studies shown, the aggregation scheme outperforms batch verification in size and time at slightly more than 100 proofs.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aplonk&quot;&gt;aPlonk&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2022&#x2F;1352.pdf&quot;&gt;aPlonk&lt;&#x2F;a&gt; builds on the ideas of SNARKPack, using a different proving system (Plonk) and introducing multi-polynomial commitments to achieve sublinear size in the number of polynomials. The key idea is to verify several proofs by performing a random linear combination of commitments and checking it. The notation is slightly different since the authors of aPlonk use additive notation when working with groups, whereas the authors of SNARKPack use multiplicative notation. If \( \mathrm{cm}(p_k) \) is a commitment to a polynomial \( p_k \) (which, if we use KZG commitments, is an elliptic curve element), then we can verify all of them by doing&lt;br &#x2F;&gt;
\[ \sum r^k \mathrm{cm}(p_k)=\beta \]&lt;br &#x2F;&gt;
and checking that \( \beta \), at point \( z \), opens (evaluates) to&lt;br &#x2F;&gt;
\( v=\sum r^k v_k \)&lt;br &#x2F;&gt;
where \( v_k \) is the value of \( p_k(z) \). Had we used multiplicative notation, the previous equation would have read&lt;br &#x2F;&gt;
\[ \prod (\mathrm{cm}(p_k))^{ r^k }=\beta \]&lt;br &#x2F;&gt;
To achieve the sublinear size, the prover will commit to the commitments of the polynomials, that is \( \beta=\mathrm{cm}(\mathrm{cm}(p_1),\mathrm{cm}(p_2)…)\).&lt;br &#x2F;&gt;
Since we are calculating a linear combination using the powers of \( r \), it is natural to use a polynomial commitment scheme, such as KZG or inner product arguments (IPA).&lt;&#x2F;p&gt;
&lt;p&gt;Plonk’s constraint system has the following expression&lt;br &#x2F;&gt;
\[ q_{L_i}x_{a_i}+q_{R_i}x_{b_i}+q_{O_i}x_{C_i}+q_{M_i}x_{a_i}x_{b_i}+q_{C_i}=0\]&lt;br &#x2F;&gt;
and can be extended to include higher-order terms or custom gates. For each \( q_k \) we can define an univariate polynomial, \( q_L(x),q_R(x),q_O(x),q_M(x),q_C(x) \) by having each polynomial evaluate to their corresponding \( q_{k_i} \) at the n primitive roots of unity \( \omega_i \) (We say that \( \omega_i) \) is a primitive n-th root of unity if \( \omega_i^n=1 \) and \( \omega_i^k \neq 1 \) if \( k &amp;lt; n \). In addition, the prover has to show that the relations between the indices \( a_i,b_i,c_i \) are related by permutations. These permutations are also expressed in terms of polynomials. Therefore, we have to commit to a total of 8 polynomials.&lt;&#x2F;p&gt;
&lt;p&gt;One key building block is the multi-polynomial commitment scheme. This comprises of 5 efficient algorithms, \( \mathrm{setup},\mathrm{commit- polynomial},\mathrm{commit-evaluation},\mathrm{open},\mathrm{check}\); the main difference is the addition of the \( \mathrm{commit-evaluation} \) algorithm. The multi-polynomial commitment is built upon two polynomial commitment schemes: KZG and IPA.&lt;&#x2F;p&gt;
&lt;p&gt;One important optimization is that all polynomials are evaluated at the same random challenge \( r \), given by the Fiat-Shamir heuristic. Therefore, provers must obtain \( r \) from the partial transcript of all proofs, requiring that the proofs of each statement run coordinately. Even if this prevents the construction of incrementally-verifiable computation (IVC), since in that case, the proofs are generated one after the other, the construction works well for validity rollups.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;Proof aggregation schemes are an alternative to reduce the size and verifying time of many zk-SNARKs. In particular, we can obtain proof sizes and verification times of order \( \mathcal{O}(\log(n)) \) for \( n \) proofs. Proof aggregation outperforms batching techniques for slightly more than 100 proofs and has a clear advantage when we add together more than 1000 proofs. The main building blocks to achieve these properties are homomorphic polynomial commitments (such as KZG), two trusted setups, and the fact that we can verify many proofs by taking a random linear combination, using as coefficients the powers of some number \( r \).&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Climbing the tower: field extensions</title>
          <pubDate>Wed, 25 Jan 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/climbing-the-tower-field-extensions/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/climbing-the-tower-field-extensions/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/climbing-the-tower-field-extensions/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;Finite fields are a central piece in every cryptography and &lt;a href=&quot;&#x2F;the-hunting-of-the-zk-snark&#x2F;&quot;&gt;zk-SNARKs&lt;&#x2F;a&gt;. The most common finite fields appearing in practice are the fields with prime order $\mathbb F_p$. There are multiple ways of defining them. A usual one is seeing $\mathbb F_p$ as the set&lt;br &#x2F;&gt;
$$ \{0, 1, \cdots, p-1\}$$&lt;br &#x2F;&gt;
together with the rule of addition and the rule of multiplication modulo $p$. But other finite fields play important roles, too. For example, when dealing with pairing-friendly elliptic curves. You may have seen them denoted by things like $\mathbb F_{p^n}$.&lt;br &#x2F;&gt;
The usual way of defining and introducing them is through the theory of field extensions that involve quotients of &lt;a href=&quot;&#x2F;math-survival-kit-for-developers&#x2F;&quot;&gt;polynomial rings&lt;&#x2F;a&gt;. It is the most natural and correct way from a mathematical standpoint, mainly to prove things about them. But going down that road can be obscure and confusing if you are unfamiliar with the mathematical tools involved.&lt;&#x2F;p&gt;
&lt;p&gt;The idea is straightforward, and those fields are very concrete mathematical objects. This post aims to give a non-standard but more down-to-earth way of understanding extensions of finite fields.&lt;&#x2F;p&gt;
&lt;p&gt;If you want to see examples of finite field extensions in zk-SNARKs, you can look at the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;arkworks-rs&#x2F;algebra&#x2F;tree&#x2F;master&#x2F;ff&quot;&gt;arkworks&lt;&#x2F;a&gt; finite field arithmetic library, where they build field extensions to work with elliptic curve pairings.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-a-field&quot;&gt;What is a field?&lt;&#x2F;h2&gt;
&lt;p&gt;To kick this off, let’s revisit what a field is. The actual definition is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Field_(mathematics)#Classic_definition&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Loosely speaking, a field is a set $F$ with addition and multiplication rules that behave, for example, like real numbers. There has to be an element in $x_0 \in F$ that behaves like $0$. That means that $x_0 + x = x$ for all $x$ in $F$. We even denote this element just by $0$. Similarly, there has to be an element $1$ in $F$ such that $1\cdot x = x$ for all $x$ in $F$. They are called the &lt;em&gt;neutral elements&lt;&#x2F;em&gt; of multiplication and addition, respectively. In $\mathbb F_p$, these are already denoted by $0$ and $1$, so no surprises there.&lt;&#x2F;p&gt;
&lt;p&gt;A field also has to have a &lt;em&gt;multiplicative inverse&lt;&#x2F;em&gt; for all elements different from $0$. This means that if $x$ is any element of $F$ different from $0$, there has to be another element $y$ such that $x\cdot y = 1$. This element $y$ is unique and is denoted by $x^{-1}$. For example, in $\mathbb F_3$ we have $2^{-1} = 2$.&lt;&#x2F;p&gt;
&lt;p&gt;We can deduce lots of things from the defining properties of a field. We will need this one later: if $x\cdot x = 0$, then $x=0$.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-case-of-complex-numbers&quot;&gt;The case of complex numbers&lt;&#x2F;h2&gt;
&lt;p&gt;Computer scientists are very good at naming things, like &lt;em&gt;neural networks&lt;&#x2F;em&gt; and &lt;em&gt;artificial intelligence&lt;&#x2F;em&gt;. Mathematicians, on the other hand, are very often terrible at it. Early in our lives, we encounter one of the worst examples: &lt;em&gt;complex numbers&lt;&#x2F;em&gt;. There are at least three problems with them. First of all, the name. It biases everyone to think it’s a complex concept. Second, the obscure notation $a + bi$, and finally, the fact that the new symbol is called an &lt;em&gt;imaginary number&lt;&#x2F;em&gt;. This makes an explosive combination and hides its simplicity. Complex numbers are just pairs of real numbers, also called the &lt;em&gt;cartesian plane&lt;&#x2F;em&gt;. And the interesting thing is that there is a way to define addition and multiplication rules on this set of pairs that extends the ones of the real numbers. These even have geometric interpretations!&lt;&#x2F;p&gt;
&lt;p&gt;We introduce this because we will take a similar approach to finite fields. The approach is: we start from a field, in this case, $\mathbb R$, with the usual addition and multiplication rules. We then add a new coordinate to obtain the pairs of real numbers $(a, b)$. This set is usually denoted $\mathbb R^2$. On this set we define the addition component-wise $(a,b) + (c, d) := (a+c, b+d)$. We then try to define a multiplication rule on it. That is, we want to come up with a rule for the expression $(a, b)\cdot(c, d)$ such that:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. It forms a field together with the component-wise addition.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. It extends the operations of the real numbers in the following way. For all real numbers $a$ and ${b,}$ the equality $(a,0)\cdot(b,0) = (ab, 0)$ should hold. This means we can think of the real numbers as sitting inside $\mathbb R^2$. They are those elements with a null second coordinate. And the new operation boils down to the usual one on this restricted set.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If we try to define the multiplication component-wise, we will need something else. That is, if we define $(a, b)\cdot(c, d) = (ac, bd)$, then the whole thing won’t be a field. For example, there won’t be a neutral element for multiplication (think about it!). It is not evident, but it turns out that a formula that works is the following:&lt;&#x2F;p&gt;
&lt;p&gt;$$ (a, b) \cdot (c, d) := (ac - bd, ad + bc).$$&lt;&#x2F;p&gt;
&lt;p&gt;Here the neutral element of the multiplication is $(1, 0)$. The set of pairs of real numbers $\mathbb R^2$ together with this multiplication and the component-wise addition is the field of complex numbers $\mathbb C$.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;notation-a-bi&quot;&gt;Notation $a + bi$&lt;&#x2F;h3&gt;
&lt;p&gt;Let’s play around with this to arrive at the more familiar form $a + bi$. This will also be key to understanding the usual constructions of finite fields out of the rings of polynomials.&lt;&#x2F;p&gt;
&lt;p&gt;Since we can identify the real numbers inside $\mathbb R^2$ as the elements with a null second coordinate, we can abuse notation and write $a$ instead of $(a, 0)$. If we try to do the same with second coordinates, we need a way to distinguish them from the previous ones. So we write the elements of the form $(0, b)$ as $bi$. The $i$ means that it is not a real number. Now, the point $(a, b)$ is equal to $(a, 0) + (0, b)$. And with the new notation, it is written as $a + bi$. Notice that the notation $bi$ is consistent with our identification of $\mathbb R$ inside $\mathbb R^2$ and the multiplication rule. What we mean is that $bi$ is equal to $b\cdot i$ when we think $b$ as being $(b, 0)$ and $i$ as being the element $(0, 1)$. That is, $(b,0)\cdot(0, 1)=(0, b)$.&lt;&#x2F;p&gt;
&lt;p&gt;Last but not least, note that $(0, 1) \cdot (0, 1) = (-1, 0)$. So under this notation, this is $i^2 = -1$.&lt;&#x2F;p&gt;
&lt;p&gt;So why do we prefer the $a + bi$ notation over the $(a, b)$ one? I can think of a few reasons. It is more explicit that we want to think of the real numbers as sitting inside the complex numbers. It is also handier since it does not involve all the parenthesis. But it is just a notation.&lt;&#x2F;p&gt;
&lt;p&gt;The takeaway is that complex numbers are a field constructed from real numbers by adding more coordinates. The same process creates all the finite fields. The difference is that we start from the fields $\mathbb F_p$ instead of $\mathbb R$.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;wait-what-about-other-extensions-of-the-real-numbers&quot;&gt;Wait, what about other extensions of the real numbers?&lt;&#x2F;h4&gt;
&lt;p&gt;Now that we have the complex numbers $\mathbb C:= \mathbb R^2$ constructed as before, we could try to perform the same process and define a multiplication on the pairs of complex numbers $\mathbb C^2$ that together with addition component-wise is again a field.&lt;&#x2F;p&gt;
&lt;p&gt;Another thing we could do is start from the real numbers again, but this time add three or more copies of it. That is, try to define a multiplication on triplets of real numbers $(a,b,c)$ to form a field.&lt;&#x2F;p&gt;
&lt;p&gt;Both of these will need to be changed. This is called the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Frobenius_theorem_(real_division_algebras)&quot;&gt;Frobenius theorem&lt;&#x2F;a&gt;. It states that the best we can do is to define a non-commutative multiplication on $\mathbb C^2$ so that it won’t be a field. It is called the &lt;em&gt;quaternions&lt;&#x2F;em&gt;. It is a fascinating object with many applications, for example, in computer graphics, to deal with rotations.&lt;&#x2F;p&gt;
&lt;p&gt;The good news is that both constructions will work in the land of finite fields!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;binary-strings-of-length-2&quot;&gt;Binary strings of length $2$&lt;&#x2F;h2&gt;
&lt;p&gt;Let’s start simple. Consider $\mathbb F_2$. It has only two elements&lt;&#x2F;p&gt;
&lt;p&gt;$$\mathbb F_2 = \{0, 1\}$$&lt;&#x2F;p&gt;
&lt;p&gt;The addition and multiplication rules have $0$ as the neutral element for addition, $1$ as the neutral element for multiplication, and $1+1$ equals $0$. The addition is the usual XOR on the set of bits. This will be our building block. The field $\mathbb F_2$ will play the role of the real numbers in the previous section.&lt;&#x2F;p&gt;
&lt;p&gt;Let us now add one more coordinate and consider the set of all binary strings of length $2$. So our set now is ${ (0,0), (0,1), (1,0), (1,1)}$. We will call this set $\mathbb F_2^2$ for now. We want to find a multiplication rule on $\mathbb F_2^2$ just like in the case of complex numbers. The addition on is the component-wise addition of $\mathbb F_2$&lt;&#x2F;p&gt;
&lt;p&gt;$$(a,b) + (c, d) = (a+b, c+d).$$&lt;&#x2F;p&gt;
&lt;p&gt;So for example $(1,1) + (0,1) = (1, 0)$. This is again the XOR but now on strings of length $2$. The challenge is again to come up with a multiplication rule.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s try to reverse-engineer it. Assume it is somehow defined and has all the properties we want. Essential to what follows is that we also require the multiplicative neutral element to be $(1, 0)$. This is the $1$ in $\mathbb F_2$ under its usual identification as the elements with null second coordinate.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s find out what would be $(0,1)\cdot(0,1)$. It surely is one of the elements of $\mathbb{F}_2^2$. So there are only four possible choices. It cannot be $(0,1)\cdot(0,1)=(0,0)$, otherwise we would get $(0, 1) = (0,0)$. This is the property we mentioned in the first section of this post: in a field, if $x\cdot x$ equals the neutral element of the addition $0$, then $x = 0$. Here the neutral element is $(0,0)$ because we are in $\mathbb F_2^2$ with the component-wise addition.&lt;&#x2F;p&gt;
&lt;p&gt;Another possibility is that $(0,1)\cdot(0,1) = (1,0)$, then we could do the following reasoning.&lt;br &#x2F;&gt;
\[ \begin{align} (1,1)\cdot(1,1) &amp;amp;= ((1,0) + (0,1))\cdot((1,0) + (0,1)) \newline&lt;br &#x2F;&gt;
&amp;amp;= (1,0)\cdot(1,0) + 2(1,0)\cdot(0,1) + (0,1)\cdot(0,1) \newline&lt;br &#x2F;&gt;
&amp;amp;= (1,0)\cdot(1,0) + (0,1)\cdot(0,1) \newline&lt;br &#x2F;&gt;
&amp;amp;= (1,0) + (1,0) \newline&lt;br &#x2F;&gt;
&amp;amp;= (0,0) \end{align} \]&lt;br &#x2F;&gt;
This is bad for the same reason, we got $(1,1)\cdot(1,1) = (0,0)$ but $(1,1)$ is different from $(0,0)$.&lt;br &#x2F;&gt;
So we are left with only two options for the result of $(0, 1)\cdot(0, 1)$. Either $(0,1)\cdot(0,1)$ is equal to $(1,1)$ or it is equal to $(0, 1)$. But a similar argument to the ones we gave rules out $(0, 1)$. And so, the only possible candidate is&lt;br &#x2F;&gt;
$$(0, 1)\cdot(0, 1) = (1, 1)$$&lt;&#x2F;p&gt;
&lt;p&gt;With this fact, we can construct the rest of the multiplication table. For example&lt;br &#x2F;&gt;
$$(1,1)\cdot(1,1) = (1,0)\cdot(1,0) + (0,1)\cdot(0,1) = (1,0) + (1,1) = (0,1).$$&lt;&#x2F;p&gt;
&lt;p&gt;And this works fine. Although not evident at first sight, it satisfies all the properties we want. The proof is easy but tedious now that there’s a candidate for the multiplication rule. We would have to go through all the properties and verify that they are satisfied (this is a finite amount of checks).&lt;&#x2F;p&gt;
&lt;h4 id=&quot;notation&quot;&gt;Notation&lt;&#x2F;h4&gt;
&lt;p&gt;Let’s introduce a notation with the same spirit as the complex numbers’ $a + bi$ notation. Similar to that case, let’s use the identification of $\mathbb F_2$ inside $\mathbb F_2^2$ and write $0$ and $1$ to mean $(0, 0)$ and $(1, 0)$. Now instead of the symbol $i$ as with the complex numbers let’s use $x$ to mean $(0, 1)$. There’s no real reason for it. Just that $i$ is highly associated with complex numbers, we want to emphasize that this is not that field. So now we have&lt;&#x2F;p&gt;
&lt;p&gt;$$(0,0) = 0 + 0x = 0$$&lt;br &#x2F;&gt;
$$(1, 0) = 1 + 0x = 1$$&lt;br &#x2F;&gt;
$$(0, 1) = 0 + 1x = x$$&lt;br &#x2F;&gt;
$$(1,1) = 1+1x = 1 + x$$&lt;&#x2F;p&gt;
&lt;p&gt;And using the multiplication rule we just discovered, we obtain $x^2 = 1 + x$.&lt;br &#x2F;&gt;
This equation is all we need to be able to multiply any two elements by repeatedly applying it whenever a power larger than $1$ appears. For example:&lt;br &#x2F;&gt;
$$(1+x)x = x + x^2 = x + 1 + x = 1.$$&lt;&#x2F;p&gt;
&lt;p&gt;The set $\mathbb F_2^2$ with this addition and multiplication has its symbol: it is denoted $\mathbb F_4$ and is called &lt;em&gt;the field with four elements&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;binary-strings-of-length-3&quot;&gt;Binary strings of length $3$&lt;&#x2F;h2&gt;
&lt;p&gt;The same process can be done with triplets $(a,b,c)$ of elements of $\mathbb F_2$. The elements of this set are $(0,0,0), (1,0,0), (0,1,0),(1,1,0)$, etc. It has $8$ elements, and we will denote it by $\mathbb F_2^3$. We have the component-wise addition&lt;br &#x2F;&gt;
$$(a,b,c) + (a’,b’,c’) = (a+a’, b+b’, c+c’)$$&lt;br &#x2F;&gt;
We can play the same game as before and discover a multiplication rule on $\mathbb F_2^3$ such that it forms a field together with the component-wise addition. In this case, we can even find one such that $(0,1,0)\cdot(0,1,0) = (0,0,1)$. We are not going to show the whole process. You can try it out for yourself!&lt;&#x2F;p&gt;
&lt;p&gt;Similar to the previous case, this field is denoted $\mathbb F_8$, and it’s the unique field with $8$ elements.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;notation-1&quot;&gt;Notation&lt;&#x2F;h4&gt;
&lt;p&gt;We identify $\mathbb F_2$ in $\mathbb F_8$ as the elements with null second and third coordinates. That is, $\mathbb F_2$ is ${(0,0,0), (1,0,0)}$.&lt;&#x2F;p&gt;
&lt;p&gt;Now that we have three coordinates, we need two new symbols, $x$ and $y$, to write an element $(a,b,c)$ as $a + bx + cy$. But, since $(0,1,0)\cdot(0,1,0)$ equals $(0,0,1)$, we have $x^2 = y$. So we need only one symbol and can write $(a,b,c)$ as $a + bx+ cx^2$.&lt;&#x2F;p&gt;
&lt;p&gt;If you construct the multiplication rule as in the case of binary strings of length $2$ you’ll find that $(0,1,0)\cdot(0,0,1) = (1,1,0)$. With this notation, this is $x^3 = 1 + x$. Similar to the previous case. This equation is all we need to multiply elements. For example&lt;&#x2F;p&gt;
&lt;p&gt;$$(1 + x^2)(1 + x) = 1 + x + x^2 + x^3 = 1 + x + x^2 + 1 + x = x^2.$$&lt;&#x2F;p&gt;
&lt;h2 id=&quot;general-case&quot;&gt;General case!&lt;&#x2F;h2&gt;
&lt;p&gt;Suppose we start with $\mathbb F_p$, where $p$ is some prime number. We can consider the set of tuples $(a_0, a_1, \dots, a_{n-1})$, all of the same length $n$, and call that set $\mathbb F_{p^n}$. In there, we have the component-wise addition. A theorem states that there always exists a multiplication rule on $\mathbb F_{p^n}$ such that it forms a field! Moreover, all multiplication rules are essentially the same. And so this means that there is a unique field of $p^n$ elements.&lt;&#x2F;p&gt;
&lt;p&gt;Everything we showed for the binary strings of length $2$ and $3$ works here. We can write every element $(a_0, a_1, \dots, a_{n-1})$ as&lt;br &#x2F;&gt;
$$a_0 + a_1x + a_2x^2 + \cdots + a_{n-1}x^{n-1}$$&lt;&#x2F;p&gt;
&lt;p&gt;This notation is consistent with the multiplication rule, just like before. Also, there will be an equality of the form $x^n = b_0 + b_1x + \cdots + b_{n-1}x^{n-1}$ for some elements $b_i$ in $\mathbb F_p$.&lt;&#x2F;p&gt;
&lt;p&gt;And every finite field is of this form!&lt;&#x2F;p&gt;
&lt;h3 id=&quot;towers-of-fields&quot;&gt;Towers of fields&lt;&#x2F;h3&gt;
&lt;p&gt;The same works if we use any finite field $F$ as a building block. For example, we could start from $F = \mathbb F_8$. We can consider tuples $(a_0, \cdots, a_{n-1})$ of elements of $F$, and everything follows the same. There will always be a multiplication rule on $F^n$, making it a field. This is useful for constructing large extensions in small steps.&lt;&#x2F;p&gt;
&lt;p&gt;Say for example we need to work with $\mathbb F_{p^{12}}$, the field with $p^{12}$ elements (for some prime number $p$). We could construct it from scratch by finding a multiplication rule on $\mathbb F_p^{12}$, the set of tuples of length $12$ elements of $\mathbb F_p$.&lt;br &#x2F;&gt;
Another approach is as follows. Construct first the field $\mathbb F_{p^6}$ of $p^6$ elements. Then consider tuples $(a,b)$ with $a,b \in \mathbb F_{p^6}$. There is a multiplicative rule on that set of tuples, making it a field. That will be $\mathbb F_{p^{12}}$. These are called field towers and are a common way of constructing finite fields.&lt;&#x2F;p&gt;
&lt;p&gt;The case of $\mathbb F_{p^{12}}$ is particularly interesting when working with the BLS12-377 or BLS12-381 curves. It is the field where all the points relevant to the pairings are defined.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-set-of-bytes&quot;&gt;The set of bytes&lt;&#x2F;h2&gt;
&lt;p&gt;Note that $\mathbb F_{256}$ is the set of all possible bytes. Its elements are tuples $(a_0, a_1,\dots, a_7)$ of elements of $\mathbb F_2$. We denote them by $a_0 + a_1x + a_2x^2 + \cdots + a_7x^7$. Here the equation is $x^8 = x^4 + x^3 + x + 1$.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Advanced_Encryption_Standard&quot;&gt;Advanced Encryption Standard&lt;&#x2F;a&gt; (AES) uses this field as part of the block cipher!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;In the same way that complex numbers are just pairs of real numbers, field extensions of finite fields are just tuples of elements of some $\mathbb F_p$. It is not evident how to come up with the multiplication rule, but mathematicians have proved that it always exists, and the resulting field is essentially unique in a rigorous way we are not mentioning here. Field extensions are essential in many proving systems, especially those relying on Kate-Zaverucha-Goldberg (KZG) commitments.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>CUDA&#x27;ve been faster: learning CUDA from scratch</title>
          <pubDate>Mon, 23 Jan 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/cuda-from-scratch/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/cuda-from-scratch/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/cuda-from-scratch/">&lt;h1 id=&quot;practical-cuda&quot;&gt;Practical CUDA&lt;&#x2F;h1&gt;
&lt;p&gt;CUDA is a parallel computing platform and programming model developed by NVIDIA for general computing on graphical processing units. We can use it to accelerate expensive computations, distributing the load over several processors. For example, in some &lt;a href=&quot;&#x2F;the-hunting-of-the-zk-snark&#x2F;&quot;&gt;zk-SNARKs&lt;&#x2F;a&gt;, we have to calculate a &lt;a href=&quot;&#x2F;multiscalar-multiplication-strategies-and-challenges&#x2F;&quot;&gt;multiscalar multiplication&lt;&#x2F;a&gt;, which involves summing lots of points on an &lt;a href=&quot;&#x2F;what-every-developer-needs-to-know-about-elliptic-curves&#x2F;&quot;&gt;elliptic curve&lt;&#x2F;a&gt; (for example, 100,000,000), \( \sum a_k P_k\), where \( P_k \) are points on the curve and \( a_k \) are positive integers. We can also use CUDA for other problems where the task is highly parallelizable, such as solving differential equations, performing fast Fourier transforms, sorting elements, etc.&lt;&#x2F;p&gt;
&lt;p&gt;CUDA is also widely used in Machine Learning algorithms, especially in those involving Deep Learning. It is also commonly found in game engines, image processing, and simulations for scientific purposes.&lt;&#x2F;p&gt;
&lt;p&gt;In GPU-accelerated applications, the sequential part of the workload runs on the CPU, while processing large blocks of data runs on thousands of GPU cores in parallel. GPUs are optimized to run that kind of work! The overall philosophy is that the different cores run independently the same set of instructions in parallel (The SIMT or &lt;strong&gt;S&lt;&#x2F;strong&gt; ingle &lt;strong&gt;I&lt;&#x2F;strong&gt; nstruction, &lt;strong&gt;M&lt;&#x2F;strong&gt; ultiple &lt;strong&gt;T&lt;&#x2F;strong&gt; hread model).&lt;&#x2F;p&gt;
&lt;p&gt;An excellent introduction to the CUDA programming model can be found &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=4APkMJdiudU&amp;amp;list=PLC6u37oFvF40BAm7gwVP7uDdzmW83yHPe&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;In this post, we will focus on CUDA code, using google colab to show and run examples. But before we start with the code, we need to have an overview of some building blocks.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;building-blocks&quot;&gt;Building blocks&lt;&#x2F;h2&gt;
&lt;p&gt;With CUDA, we can run multiple threads in parallel to process data. These threads are grouped in different processing units with their data-sharing and synchronization primitives.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;logical-processing-units&quot;&gt;Logical processing units&lt;&#x2F;h3&gt;
&lt;p&gt;The most fundamental building block of our application is the thread. Threads are then grouped into &lt;strong&gt;Warps&lt;&#x2F;strong&gt; , which are grouped into &lt;strong&gt;Blocks&lt;&#x2F;strong&gt; which are finally contained in a &lt;strong&gt;Grid&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Depending on our algorithms, warps can be ignored, or be used to further optimize our application, as we will see later.&lt;&#x2F;p&gt;
&lt;p&gt;At the moment of this post, each warp has 32 threads, and each block has 1024 threads or 32 warps.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;1dc0TeK.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;physical-processing-units-and-memory&quot;&gt;Physical processing units and memory&lt;&#x2F;h3&gt;
&lt;p&gt;Blocks are run in &lt;strong&gt;Streaming Multiprocessors&lt;&#x2F;strong&gt;. Each streaming multi-processor has 8 &lt;strong&gt;CUDA Cores&lt;&#x2F;strong&gt; *. These cores can also be called Shaders or Streaming Processors.&lt;&#x2F;p&gt;
&lt;p&gt;A busy multi-processor executes a warp, with their instructions running in parallel. Since warp threads are running in the same multi-processor, they can exchange information via &lt;strong&gt;Registers&lt;&#x2F;strong&gt; in a speedy way. This is useful since, after having our application running in as many threads as possible, the method to improve our performance is reducing memory access.&lt;&#x2F;p&gt;
&lt;p&gt;Now that we have introduced registers, the next question we can ask is how do we share information between warps and between blocks? Let’s go upwards through the memory hierarchy.&lt;&#x2F;p&gt;
&lt;p&gt;Each Streaming Multiprocessor has an &lt;strong&gt;SRAM&lt;&#x2F;strong&gt;. Its size depends on the graphic card. For example, in a V100, it is 128 KiB, and 192 KiB in an A100.&lt;&#x2F;p&gt;
&lt;p&gt;This SRAM has a double purpose. First, it is used as an &lt;strong&gt;L1 cache&lt;&#x2F;strong&gt; in a way that is transparent to the programmer. A secondary use is as &lt;strong&gt;Shared Memory&lt;&#x2F;strong&gt;. This shared memory enables the programmer to share data inside a block in a fast manner.&lt;&#x2F;p&gt;
&lt;p&gt;Since the SRAM has two functionalities, CUDA allows the programmer to define how much of the SRAM can be used as an L1 cache and how much as Shared Memory.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, we have &lt;strong&gt;Global Memory&lt;&#x2F;strong&gt;. This memory is the one we see in the specifications of graphic cards as GPU Memory and the one allocated with cudaAlloc(). Global Memory allows us to share data between thread blocks seamlessly.&lt;&#x2F;p&gt;
&lt;p&gt;As tends to happen with hardware, operations become more expensive as we move to larger memories.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;gr4u7ru.png&quot; alt=&quot; &quot; &#x2F;&gt;&lt;br &#x2F;&gt;
&lt;em&gt;image from&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;developer.nvidia.com&#x2F;blog&#x2F;cuda-refresher-cuda-programming-model&#x2F;&quot;&gt;Cuda Refresher - Nvidia blog&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;*&lt;em&gt;Nvidia has also released a new kind of cores, called Tensor Cores, for their Tensor Cores GPUs. These cores can run a small matrix multiplication of floating points in mixed precision as a native operation to further optimize machine learning algorithms&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;programming-in-cuda&quot;&gt;Programming in CUDA&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;starting-simple-array-addition&quot;&gt;Starting - Simple array addition&lt;&#x2F;h3&gt;
&lt;p&gt;We will start by parallelizing some elementary operations and using only global memory. Let’s start making a program that adds two arrays.&lt;&#x2F;p&gt;
&lt;p&gt;Before we start, there are some standard procedures we need to do:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * For each function or kernel to use in the device, we need to define the following: &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      * How many blocks do we use?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      * How many threads do we include per block?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      * How are the blocks indexed?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * We need to allocate and copy data to the device&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Picking the best parameters for the kernel is a topic of its own, but it’s good to keep in mind that the number of threads per block should be a multiple of the number of threads per warp, 32.&lt;&#x2F;p&gt;
&lt;p&gt;Lastly, we need to decide how the blocks are indexed. We can set them to be accessed as a 1, 2, or 3-dimensional array. We are then picking between a typical array, a matrix, or a cube.&lt;&#x2F;p&gt;
&lt;p&gt;It is just an index for the device, and it does not matter. But it is helpful for the programmer to pick something related to the problem being solved. If we add arrays, one dimension is suitable; if we are processing images, 2 is the best pick; and, if we are working with 3d models, it makes sense to use 3-dimensional matrices.&lt;&#x2F;p&gt;
&lt;p&gt;In our case, we will define the following dimensions:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dim3 threadsPerBlock(128);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dim3 numBlocks(1024*1024);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If we wanted a 2d array, we could do&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dim3 threadsPerBlock(128);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dim3 numBlocks(1024,1024);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now, we also need to allocate some memory in our device and copy the arrays we want to add.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s assume we want to add two arrays of bytes, array1, and array2, with a size of AMOUNT_OF_ELEMENTS. Then we can reserve bytes for the two arrays and a result with:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;char* array1_in_device;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;char* array2_in_device;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;char* result_in_device;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cudaMalloc(&amp;amp;array1_in_device, AMOUNT_OF_ELEMENTS);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cudaMalloc(&amp;amp;array2_in_device, AMOUNT_OF_ELEMENTS);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cudaMalloc(&amp;amp;result_in_device, AMOUNT_OF_ELEMENTS);    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cudaMemcpy(array1_in_device, array1, AMOUNT_OF_ELEMENTS, cudaMemcpyHostToDevice);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cudaMemcpy(array2_in_device, array2, AMOUNT_OF_ELEMENTS, cudaMemcpyHostToDevice);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Notice we do not need to store the result in a different place if we do not need the original arrays after the addition inside CUDA. And it is common for only one malloc to be used, and then the pointer is indexed with the data’s location. But since this is the first program, we will make it as simple as possible.&lt;&#x2F;p&gt;
&lt;p&gt;Now, let’s focus on the algorithm.&lt;&#x2F;p&gt;
&lt;p&gt;A simple non-CUDA code to solve this problem would look like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;for(int i = 0; i &amp;lt; MAX_ELEMENTS; i++)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    solution_array[i] = a[i] + b[i]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If we assume we have one core for each index, we may delete the for and let each thread compute one addition. This is not always the case and makes for solutions that aren’t flexible enough. Then, we will need to use strides.&lt;&#x2F;p&gt;
&lt;p&gt;Strides are nothing more than steps in a for loop to distribute the load between threads. For example, if we had a stride of 4, Thread 0 would process elements 0 3 7 11 …, Thread 1 would process elements 1 4 8 12 …, and so on.&lt;&#x2F;p&gt;
&lt;p&gt;Instead of fixing the stride to one number, we can use CUDA primitives to make our algorithm flexible enough to work with different sizes of arrays and blocks. Our algorithm, using CUDA, would then become:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;__global__ void sum_arrays(char* array1, char* array2, char* result){&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    uint globalThreadID = blockIdx.x*blockDim.x+threadIdx.x;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    uint stride = gridDim.x*blockDim.x;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for (int i = globalThreadID; i &amp;lt; AMOUNT_OF_ELEMENTS; i += stride){&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        result[i] = array1[i] + array2[i];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here &lt;strong&gt;global&lt;&#x2F;strong&gt; indicates it’s a function that runs on the device that can be called from the host.&lt;&#x2F;p&gt;
&lt;p&gt;blockIdx is the block’s id, and blockDim is the number of elements in the block. ThreadIdx is the id of the thread inside the block. Notice then, by doing&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;uint globalThreadID = blockIdx.x*blockDim.x+threadIdx.x;&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;we obtain a unique ThreadID, independent of the block, that’s useful to split the work.&lt;&#x2F;p&gt;
&lt;p&gt;The stride is defined as the number of threads we have to split the work evenly.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, to call this function from the host, we use the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sum_arrays&amp;lt;&amp;lt;&amp;lt;numBlocks, threadsPerBlock&amp;gt;&amp;gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    array1_in_device, array2_in_device, result_in_device&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The complete code can be read and run by copying the following &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;colab.research.google.com&#x2F;drive&#x2F;1SXZjOpb7t352VctCQ6xLhYZJCi2zCB_A?usp=sharing&quot;&gt;google colab&lt;&#x2F;a&gt;. We have also added some examples of a matrix addition to show how the indexing works with more dimensions.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;host-device-parallelism&quot;&gt;Host - Device parallelism&lt;&#x2F;h3&gt;
&lt;p&gt;Let’s keep using the same sum_arrays() functions differently and check another scenario.&lt;&#x2F;p&gt;
&lt;p&gt;Suppose we call our function in the device from the host; after that, we write operations for the CPU. What happens in this scenario? Is the code run, or does it wait for the device?&lt;&#x2F;p&gt;
&lt;p&gt;To answer the first question, let’s take some measures.&lt;&#x2F;p&gt;
&lt;p&gt;We will make a program that does a lot of work over a small array and then retrieve the data in two chunks. And we will also measure the time it takes to call the function to retrieve both pieces.&lt;&#x2F;p&gt;
&lt;p&gt;Since the code is a bit long, we will leave it in the same &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;colab.research.google.com&#x2F;drive&#x2F;1SXZjOpb7t352VctCQ6xLhYZJCi2zCB_A?authuser=3#scrollTo=3jyEZO03whXD&amp;amp;line=26&amp;amp;uniqifier=1&quot;&gt;google colab&lt;&#x2F;a&gt; we used before, so feel free to copy and run it by yourself.&lt;&#x2F;p&gt;
&lt;p&gt;What happens, then?&lt;&#x2F;p&gt;
&lt;p&gt;We can see the function call takes almost no time, and the memcpy of the second chunk goes fast too. In the middle of both functions, the first memcpy takes most of the time, almost 1000 times more than the second one! Yet, the operation is the same. What’s going on?&lt;&#x2F;p&gt;
&lt;p&gt;The answer is kernels run concurrently with the host, and the program is only blocked when it needs the data. The memcpy is not taking that much time, but it’s the first function call that requires the result, so it has to wait for the device to finish.&lt;&#x2F;p&gt;
&lt;p&gt;To make it more evident, we will make use of another primitive:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cudaDeviceSynchronize();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With this function, all the time is spent waiting for the device, and both memcpy takes the same amount of time.&lt;&#x2F;p&gt;
&lt;p&gt;And knowing we can run code both in the GPU and the CPU simultaneously, we can further optimize our intensive application.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;multi-stream-code&quot;&gt;Multi-stream code&lt;&#x2F;h3&gt;
&lt;p&gt;Knowing what happens when we launch a kernel and try to run code locally, we could ask the following question: What happens if we launch multiple kernels simultaneously? Can they run in parallel too? What about memory transfers?&lt;&#x2F;p&gt;
&lt;p&gt;Let’s try to answer these questions.&lt;&#x2F;p&gt;
&lt;p&gt;Kernels and memcpy functions run sequentially in their stream. In the case we have seen before, there wasn’t an explicit mention of the stream, so the default stream is used.&lt;&#x2F;p&gt;
&lt;p&gt;But, we can create more streams that we can use, using &lt;code&gt;cudaStreamCreate&lt;&#x2F;code&gt; and then assigning the kernels to the new streams.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s see an example with two kernels:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cudaStream_t stream1, stream2;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cudaStreamCreate(&amp;amp;stream1);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cudaStreamCreate(&amp;amp;stream2);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;foo&amp;lt;&amp;lt;&amp;lt;blocks,threads,0,stream1&amp;gt;&amp;gt;&amp;gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;foo&amp;lt;&amp;lt;&amp;lt;blocks,threads,0,stream2&amp;gt;&amp;gt;&amp;gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cudaStreamDestroy(stream1);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cudaStreamDestroy(stream2);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With this, if one kernel is not enough to fully use the device, we can fill it up with many other tasks that we can run in parallel. If both kernels of the last example used 50% of the device, we would have full occupancy.&lt;&#x2F;p&gt;
&lt;p&gt;Since we have many kernels running, it’s a good idea to use the async version of memcpy to start moving data as soon as it comes.&lt;&#x2F;p&gt;
&lt;p&gt;For example:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cudaMemcpyAsync(&amp;amp;results, &amp;amp;results_in_kernel1, AMOUNT_OF_ELEMENTS, cudaMemcpyDeviceToHost, stream1);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cudaMemcpyAsync(&amp;amp;results, &amp;amp;results_in_kernel2, AMOUNT_OF_ELEMENTS, cudaMemcpyDeviceToHost, stream2);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Suppose the computation spends a lot of time transferring data between the device and the host. Async memory transfers can be done in parallel with kernel execution since the GPU supports transferring and computing at the same time.&lt;&#x2F;p&gt;
&lt;p&gt;If you want more examples of this, we have written a complete example in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;colab.research.google.com&#x2F;drive&#x2F;1SXZjOpb7t352VctCQ6xLhYZJCi2zCB_A?authuser=3#scrollTo=CA0_yYSxNB7p&amp;amp;line=5&amp;amp;uniqifier=1&quot;&gt;colab&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;synchronization-and-events&quot;&gt;Synchronization and Events&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;how-do-we-synchronize-work&quot;&gt;How do we synchronize work?&lt;&#x2F;h4&gt;
&lt;p&gt;Within the host code, we can use different levels of synchronization. From more to less synchronization, some API calls we can use are:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * We can synchronize everything using `cudaDeviceSynchronize()`, which blocks the host until all issued CUDA calls are complete;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * we can synchronize concerning a specific stream using `cudaStreamSynchronize(stream)`, which blocks the host until all issued CUDA calls in `stream` are complete;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Or we can synchronize hosts or devices more selectively using **events**.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;events&quot;&gt;Events&lt;&#x2F;h4&gt;
&lt;p&gt;CUDA events provide a mechanism to signal when operations have occurred in a stream. They are helpful for profiling and synchronization.&lt;&#x2F;p&gt;
&lt;p&gt;Events have a boolean state: “Occurred” (which is the default state) or “Not Occurred”.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;managing-events-and-synchronizing-streams&quot;&gt;Managing events and synchronizing streams&lt;&#x2F;h4&gt;
&lt;p&gt;The most common way to create, delete and enqueue events are:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `cudaEventCreate(&amp;amp;event)` creates an `event`;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `cudaEventDestroy(&amp;amp;event)` destroys an `event`;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `cudaEventRecord(&amp;amp;event, stream)`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      * sets the `event` state to &amp;quot;Not Occurred&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      * enqueues the `event` into a `stream` and&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      * `event` state is set to occur when it reaches the front of the `stream`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;How can we make sure that certain events have occurred before continuing execution?&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `cudaEventQuery(event)` returns `CUDA_SUCCESS` if `event` has occurred.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `cudaEventSynchronize(event)` blocks the host until `event` has occurred.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `cudaStreamWaitEvent(stream, event)`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      * blocks all launches on `stream` after this call until `event` occurs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      * does not block the host.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;CUDA allows us to speed up expensive calculations by distributing the load among GPUs. To make the best use of these capabilities, we need to rethink how we carry out our calculations, looking for algorithms that can be easily parallelized (such as the fast Fourier transform). In this post, we reviewed the basics of CUDA, what are the threads, and warps and how to manage and synchronize events. GPUs can offer tools to improve proving and verification times in zk-SNARKs, opening the door to many exciting applications. In future posts, we will cover more advanced topics of CUDA.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>ZPrize: eyes on the prize</title>
          <pubDate>Mon, 23 Jan 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/eyes-on-the-prize/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/eyes-on-the-prize/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/eyes-on-the-prize/">&lt;h1 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h1&gt;
&lt;p&gt;This post contains a summary of different approaches to optimize multiscalar multiplication with CUDA, as presented for &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.zprize.io&#x2F;blog&#x2F;announcing-zprize-results&quot;&gt;ZPrize&lt;&#x2F;a&gt;. This is an important calculation in certain &lt;a href=&quot;&#x2F;the-hunting-of-the-zk-snark&#x2F;&quot;&gt;proving systems&lt;&#x2F;a&gt; (zk-SNARKs), where it is necessary to add lots of points over an &lt;a href=&quot;&#x2F;multiscalar-multiplication-strategies-and-challenges&#x2F;&quot;&gt;elliptic curve&lt;&#x2F;a&gt;. These large sums can be broken down into smaller ones, each of which can be calculated in parallel by a processor, making the use of CUDA ideal to speed it up considerably. A short introduction to CUDA can be found &lt;a href=&quot;&#x2F;cuda-from-scratch&#x2F;&quot;&gt;here&lt;&#x2F;a&gt;. The results of the ZPrize are promising, leading to more than 2x speed up; and the good news does not stop there, since each solution introduces different tricks and strategies. Below you will find an overview of some solutions and the links to each repo.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;table-of-contents&quot;&gt;Table of Contents&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Goal&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Pippenger&amp;#39;s algorithm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Base algorithm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Speakspeak&amp;#39;s submission&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * 6block&amp;#39;s submission&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Mike Voronov and Alex Kolganov&amp;#39;s submission&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * MatterLabs&amp;#39;s submission&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Yrrid&amp;#39;s submission&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;goal&quot;&gt;Goal&lt;&#x2F;h2&gt;
&lt;p&gt;Given $n\in\mathbb{N}$, elliptic curve points $P_1, \dots, P_n$ and scalars $k_1, \dots, k_n$ in a finite field, compute $$P=\sum_{i=1}^nk_iP_i$$&lt;&#x2F;p&gt;
&lt;p&gt;where the summation is understood in terms of ordinary &lt;a href=&quot;&#x2F;what-every-developer-needs-to-know-about-elliptic-curves&#x2F;&quot;&gt;elliptic curve addition&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The number of points is related to the number of constraints needed to represent the computation (which can be larger than 100,000,000). This calculation appears, for example, when we want to compute the commitment of a polynomial \( a_0+a_1x+a_2x^2+…a_dx^d \) using the Kate-Zaverucha-Goldberg (KZG) commitment scheme.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pippenger-algorithm&quot;&gt;Pippenger algorithm&lt;&#x2F;h2&gt;
&lt;p&gt;Let $\lambda$ be the number of bits needed to store the scalars, and let $s$ be an integer between $1$ and $\lambda$. Denote by $\lceil \lambda&#x2F;s \rceil$ the ceiling of $\lambda&#x2F;s$, that is the least integer number greater than or equal to $\lambda&#x2F;s$.&lt;&#x2F;p&gt;
&lt;p&gt;Write each scalar $k_i$ in base $2^s$&lt;br &#x2F;&gt;
$$k_i = \sum_{j=0}^{\lceil \lambda&#x2F;s \rceil-1}m_{i,j}(2^{s})^j,$$&lt;br &#x2F;&gt;
where $0 \leq m_{i,j} &amp;lt; 2^s$. Then&lt;&#x2F;p&gt;
&lt;p&gt;$$\sum_{i=1}^n k_iP_i = \sum_{i=1}^n\sum_{j}m_{i,j}2^{sj}P_i = \sum_{j=0}^{\lceil \lambda&#x2F;s \rceil-1}2^{sj}(\sum_{i=1}^n m_{i,j}P_i).$$&lt;&#x2F;p&gt;
&lt;p&gt;Let us rewrite the inner sum differently. For each $1 \leq m &amp;lt; 2^s$ we can group all the terms of the inner sum that have $m_{i,j}=m$ and write&lt;&#x2F;p&gt;
&lt;p&gt;$$\sum_{i=1}^nm_{i,j}P_i = \sum_{m=1}^{2^s-1}m(\sum_{i:,m_{i,j}=m}P_i)$$&lt;&#x2F;p&gt;
&lt;p&gt;For the elements $m$ such that there is no $i$ with $m_{i,j}=m$ we interpret the sum $\sum_{i:, m_{i,j}=m}P_i$ as $0.$ This last step is called &lt;em&gt;bucketing&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Putting it all together we obtain:&lt;br &#x2F;&gt;
$$\sum_{i=1}^nk_iP_i = \sum_{j=0}^{\lceil \lambda&#x2F;s \rceil - 1}2^{sj}\sum_{m=1}^{2^s-1}m\sum_{i:, m_{i,j}=m}P_i \tag{1}$$&lt;br &#x2F;&gt;
Pippenger’s algorithm consists of computing the sums above starting from the innermost sum:&lt;&#x2F;p&gt;
&lt;p&gt;(1) For each $j$ and $m$ compute $B_{j,m} := \sum_{i:,m_{i,j}=m}P_i$.&lt;&#x2F;p&gt;
&lt;p&gt;(2) For each $j$ compute $G_j := \sum mB_{j,m}$ as follows. For all $1 \leq m &amp;lt; 2^s$ compute all the partial sums in descending order of the indices&lt;br &#x2F;&gt;
$$S_{j,m} = B_{j,2^{s-1}} + \cdots + B_{j,m}.$$&lt;br &#x2F;&gt;
Then compute the sum of the partial sums $S_{j,1} + \cdots + S_{j,2^s-1}$. This is equal to the sum $G_j$ we want.&lt;&#x2F;p&gt;
&lt;p&gt;(3) Compute&lt;&#x2F;p&gt;
&lt;p&gt;$$\sum_{j=0}^{\lceil \lambda&#x2F;s \rceil-1}2^{sj}G_j.$$&lt;&#x2F;p&gt;
&lt;p&gt;In pseudocode (extracted from &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2022&#x2F;1321.pdf&quot;&gt;this paper&lt;&#x2F;a&gt;):&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;vXGaugg.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;base-algorithm&quot;&gt;Base algorithm&lt;&#x2F;h2&gt;
&lt;p&gt;The implementation is in &lt;code&gt;algorithms&#x2F;src&#x2F;msm&#x2F;variable_base&#x2F;&lt;&#x2F;code&gt;. It is specific to the BLS12-377 curve. For this curve, we have $\lambda=253$.&lt;&#x2F;p&gt;
&lt;p&gt;Aleo uses Pippenger’s algorithm with $s=1$. Equation $(1)$ reduces to&lt;br &#x2F;&gt;
$$\sum_{i=1}^nk_iP_i = \sum_{j=0}^{\lambda - 1}2^{j}\sum_{i:, 1=m_{i,j}}P_i,$$&lt;br &#x2F;&gt;
where $m_{i,j}$ are defined as before, but in this particular case $m_{i,j}$ coincides with the $j$-th bit of $k_i$.&lt;br &#x2F;&gt;
Step 1 of Pippenger’s algorithm is trivial for this particular choice of $s$ and we get $G_j = B_{j,1}.$&lt;&#x2F;p&gt;
&lt;h4 id=&quot;parallelization-strategy&quot;&gt;Parallelization strategy&lt;&#x2F;h4&gt;
&lt;p&gt;CUDA parallelization is only used to modify step 2 as follows.&lt;&#x2F;p&gt;
&lt;p&gt;(2) The goal is to compute $G_{j} = \sum_{i:, 1=m_{i,j}}P_i$ for all $j$. For that, the following steps are performed.&lt;&#x2F;p&gt;
&lt;p&gt;(2.a) First, compute&lt;&#x2F;p&gt;
&lt;p&gt;$$G_{j, a} = \sum_{\substack{i:, 1=m_{i,j},\ 128a\leq i &amp;lt; 128(a+1)}}P_i$$&lt;&#x2F;p&gt;
&lt;p&gt;for all $0 \leq a &amp;lt; \lceil n&#x2F;128 \rceil$ and all $j$ in parallel. That is done using $\lambda * \lceil n&#x2F;128 \rceil$ threads.&lt;&#x2F;p&gt;
&lt;p&gt;(2.b) Then for each $j$ compute $G_{j}$ by adding $G_{j,a}$ for all $a$. Each $j$ gets its thread and so this step requires $\lambda$ steps. Each thread adds $\lceil n&#x2F;128\rceil$ elliptic curve points.&lt;&#x2F;p&gt;
&lt;p&gt;Once all the $G_j$ are computed the rest of the Pippenger algorithm is executed in the CPU as in the previous section.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;speakspeak&quot;&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;z-prize&#x2F;2022-entries&#x2F;tree&#x2F;main&#x2F;open-division&#x2F;prize1-msm&#x2F;prize1a-msm-gpu&#x2F;speakspeak&quot;&gt;Speakspeak&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The article is “cuZK: Accelerating Zero-Knowledge Proof with A Faster Parallel Multi-Scalar Multiplication Algorithm on GPUs” and can be found &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2022&#x2F;1321.pdf&quot;&gt;here&lt;&#x2F;a&gt;. There are differences between what the paper describes and the actual implementation in the ZPrize submission.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;parallelization-strategy-described-in-the-paper&quot;&gt;Parallelization strategy described in the paper&lt;&#x2F;h4&gt;
&lt;p&gt;The strategy here is to change steps 1 and 2 of Pippenger’s algorithm to leverage GPU parallelization.&lt;&#x2F;p&gt;
&lt;p&gt;We use the notation introduced in the &lt;strong&gt;Pippenger’s algorithm&lt;&#x2F;strong&gt; section. Let $t$ be the number of threads to be used.&lt;&#x2F;p&gt;
&lt;p&gt;(1) compute $B_{j,m}$ as follows. For each $1 \leq j &amp;lt; \lceil \lambda &#x2F; s \rceil$:&lt;&#x2F;p&gt;
&lt;p&gt;(1.a) compute $m_{i,j}$ in parallel for all $i$ using all $t$ threads.&lt;&#x2F;p&gt;
&lt;p&gt;(1.b) For each $0\leq l &amp;lt; t$ compute&lt;&#x2F;p&gt;
&lt;p&gt;$$B_{j,m,l} := \sum_{\substack{i \text{ such that} \ ,m_{i,j}=m \ i \equiv l \text{ mod } t}}P_i$$&lt;&#x2F;p&gt;
&lt;p&gt;Use all $t$ threads for it.&lt;&#x2F;p&gt;
&lt;p&gt;(1.c) Let $M^{(j)}$ be the matrix with elliptic curve point entries such that $M_{m, l}^{(j)} = B_{j,m,l}$. This is a sparse matrix. Compute $B_{j,m} = M^{(j)}\cdot 1_t$, where $1_t$ is the vector of length $t$ with all entries equal to $1$. This can be done using existing parallel algorithms for sparse matrix-vector multiplications. Use all $t$ threads for it.&lt;&#x2F;p&gt;
&lt;p&gt;(2) Compute all $G_j$ as follows. For all $0\leq j &amp;lt; \lceil \lambda &#x2F; s \rceil$ do the following in parallel using $t’ := t&#x2F;\lceil \lambda &#x2F; s \rceil$ threads for each one.&lt;&#x2F;p&gt;
&lt;p&gt;(2.a) For a given $j$, to compute $G_j = \sum mB_{j,m}$, split the sum in $t’$ even chunks and compute each one separately in its thread. That is, if we denote $\sigma=(2^s-1)&#x2F;t’$, for each $0 \leq \xi &amp;lt; \sigma$ compute&lt;&#x2F;p&gt;
&lt;p&gt;$$\sum_{m=\xi\sigma}^{(\xi+1)\sigma-1}mB_{j,m}.$$&lt;&#x2F;p&gt;
&lt;p&gt;This can be done in the same way with the partial sum trick as in step 2 of Pippenger. There is an additional step needed in this case because the sequence of coefficient in the sum above is $\xi\sigma, \xi\sigma+1, \dots,$ instead of $1, 2, 3,\dots$. But that is easily fixed by adding $(\xi\sigma-1)$ times the largest partial sum.&lt;&#x2F;p&gt;
&lt;p&gt;(2.b) Add all the chunks of the previous step. The result is $G_j$.&lt;&#x2F;p&gt;
&lt;p&gt;Finally compute step 3 as in Pippenger.&lt;&#x2F;p&gt;
&lt;p&gt;In pseudocode:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;meWCE2d.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;TdZi4gO.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;parallelization-strategy-from-the-implementation&quot;&gt;Parallelization strategy from the implementation&lt;&#x2F;h3&gt;
&lt;p&gt;The parallelization strategy in the actual code of the submission is quite simpler. There is no optimization with sparse matrix multiplications. However, there are several interesting things to note.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Only the curve BLS12-377 is supported.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The window size $s$ is chosen to be $21$. Since $\lambda = 253 = 12 * 21 + 1$, there are 13 windows, one of which has only binary scalars. This last window is treated differently from the other 12 windows. This is an odd choice given that $253 = 11 * 23$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * All the memory to store the inputs, the results, and all the partial results in between is allocated at the beginning. This needs quite a lot of memory. About 3.2GB of GPU RAM is only needed to store the scalars of all windows in the case of $2^{26}$ base points.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * For the most part (first 12 windows) kernels are launched with grids of blocks of $12$ columns and $M$ rows, where $M$ varies according to the task. Blocks on the other hand are one dimensional of size 32 and therefore warps and blocks coincide. Each column then handles computations relative to a specific window.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * There is intensive use of the `cub` [library](https:&#x2F;&#x2F;nvlabs.github.io&#x2F;cub&#x2F;index.html#sec1) for [sorting](https:&#x2F;&#x2F;nvlabs.github.io&#x2F;cub&#x2F;structcub_1_1_device_radix_sort.html), computing [run lengths](https:&#x2F;&#x2F;nvlabs.github.io&#x2F;cub&#x2F;structcub_1_1_device_run_length_encode.html), computing [cumulative sums](https:&#x2F;&#x2F;nvlabs.github.io&#x2F;cub&#x2F;structcub_1_1_device_scan.html) and [filtering](https:&#x2F;&#x2F;nvlabs.github.io&#x2F;cub&#x2F;structcub_1_1_device_select.html) lists.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Most of the code is actually inside the `sppark&#x2F;msm` directory. The original `sppark&#x2F;msm` code has been modified.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The repository includes a walkthrough of the main parts of the code. Here is a summary.&lt;&#x2F;p&gt;
&lt;p&gt;Let $n=2^{26}$ be the number of base points and let $N$ be $2 * Cores &#x2F; (12 * 32)$, where $Cores$ is the number of cores of the GPU. Kernels will be usually launched with grids of 12 x $N$ blocks of 32 threads. The factor $2$ in $N$ makes sense at least at a step where a binary reduction algorithm is used to add up all points of an array of size $12 * N *32$.&lt;&#x2F;p&gt;
&lt;p&gt;For step (1) of Pippenger.&lt;&#x2F;p&gt;
&lt;p&gt;(1.a) To compute $m_{i,j}$ for all $i,j$, a kernel with $N$ x $12$ blocks of $32$ threads are launched. All the scalars are partitioned and each thread is in charge of computing the $m_{i, j}$ for all $j$ for the coefficients $k_i$ in its partition. Partitions are of size ~ $n&#x2F;(32*N)$.&lt;&#x2F;p&gt;
&lt;p&gt;(1.b) Sequentially for each window $j$, the set of scalars $m_{i,j}$ is sorted using &lt;code&gt;cub::DeviceRadixSort::SortPairs&lt;&#x2F;code&gt;. Let us denote $m_{i, j}’$ the $i$-th scalar of window $j$ after sorting.&lt;&#x2F;p&gt;
&lt;p&gt;(1.c) Sequentially for each window $j$, the number of occurrences of each scalar $1 \leq m &amp;lt; 2^s$ in the window is computed using &lt;code&gt;cub::DeviceRunLengthEncode::Encode&lt;&#x2F;code&gt; on the previously sorted scalars $m_{i,j}’$.&lt;&#x2F;p&gt;
&lt;p&gt;(1.d) For technical reasons needed in the next step, the cumulative sum of the number of occurrences is computed using &lt;code&gt;cub::DeviceScan::InclusiveSum&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;(1.e) A kernel is launched to compute the buckets. The kernel gets a grid of size $N$ x $12$ blocks of $32$ threads. Column $j$ of the total $12$ columns handles the buckets of a window $j$. The range of indexes $1$ to $n$ is divided evenly into subranges and each thread handles the buckets corresponding to the unique scalars $m_{i,j}’$ with $i$ in its range. Ranges are slightly expanded and contracted for threads to get non-overlapping sets of scalars.&lt;&#x2F;p&gt;
&lt;p&gt;This concludes the computation of the buckets $B_{j, m}$ for all $0\leq j &amp;lt; 12$ and $1 \leq m &amp;lt; 2^s$&lt;&#x2F;p&gt;
&lt;p&gt;For step (2) of Pippenger.&lt;&#x2F;p&gt;
&lt;p&gt;(2.a) A kernel is launched on a grid of $N$ x $12$ blocks of $32$ threads. Each thread computes an even chunk of the sum $G_j = \sum mB_{j,m}$ just as described in the paper. As before, each column of the grid handles a different window.&lt;&#x2F;p&gt;
&lt;p&gt;(2.b) For each window $j$, its chunks are added up using a binary reduction algorithm. This effectively computes all $G_j$ for $0 \leq j &amp;lt;12$.&lt;&#x2F;p&gt;
&lt;p&gt;Then step (3) of Pippenger is performed in the CPU.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;6block-submission&quot;&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;z-prize&#x2F;2022-entries&#x2F;tree&#x2F;main&#x2F;open-division&#x2F;prize1-msm&#x2F;prize1a-msm-gpu&#x2F;6block&quot;&gt;6block submission&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The main contribution of this solution is a different approach to steps (1) and (2). If we forget about GPU parallelization for a moment, both steps are performed in a single step as follows.&lt;&#x2F;p&gt;
&lt;p&gt;(1’) For each window $j$, first sort all scalars $m_{i, j}$. Denote by $m_{i ,j}‘$ and $P_{i}’$ the sorted list of scalars and points respectively. For each $i$ from $n$ to $1$, where $n$ is the number of base points, compute&lt;&#x2F;p&gt;
&lt;p&gt;$$\begin{aligned} t_{i-1} &amp;amp;:= t_{i} + P_{i}’ \\ s_{i-1} &amp;amp;:= (m_{i, j}’ - m_{i-1, j}’)t_i + s_i\end{aligned}$$&lt;&#x2F;p&gt;
&lt;p&gt;with $t_n = P_n’$ and $s_n = \mathcal O$. Then $G_j$ is equal to $m_{0,j}’t_0 + s_0$. The rest of the approach is the same as in Pippenger.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;parallelization-strategy-1&quot;&gt;Parallelization strategy.&lt;&#x2F;h3&gt;
&lt;p&gt;Let $n$ be the number of base points $2^{26}$. The window size used is $21$. The $253$ bits are grouped in $11$ windows of size $21$ and an additional window of size $22$.&lt;&#x2F;p&gt;
&lt;p&gt;(1’.a) A kernel is launched on a one-dimensional grid of one-dimensional blocks of at most 128 threads. The exact size of the blocks is computed using the CUDA occupancy calculation function &lt;code&gt;cudaOccupancyMaxPotentialBlockSize&lt;&#x2F;code&gt;. The total number of threads equals the number of points. Each thread is then in charge of computing all the $m_{i, j}$ for a single scalar $k_i$.&lt;&#x2F;p&gt;
&lt;p&gt;The following steps are performed sequentially for each window $j$.&lt;&#x2F;p&gt;
&lt;p&gt;(1’.b) Having fixed $j$, the list $(m_{i, j})&lt;em&gt;{i=1}^n$ is sorted &lt;em&gt;.&lt;&#x2F;em&gt; The &lt;code&gt;cub&lt;&#x2F;code&gt; function &lt;code&gt;cub::DeviceRadixSort::SortPairs&lt;&#x2F;code&gt; is used for this. This function sorts key-value pairs. In this case, the pairs sorted are $(m&lt;&#x2F;em&gt;{i,j}, i)$, to keep track of which base point corresponds to which scalar in the sorted list. Let us denote by $m_{i, j}^\prime$ and $P_i^\prime$ the sorted list of scalars and points respectively.&lt;&#x2F;p&gt;
&lt;p&gt;(1’.c) Then a kernel is launched on a one-dimensional grid of one-dimensional blocks of at most 128 threads. Again the exact size of the blocks is computed using &lt;code&gt;cudaOccupancyMaxPotentialBlockSize&lt;&#x2F;code&gt;. The range $1$ to $n$ is split evenly and each thread is in charge of computing the sum $\sum m_{i, j}‘P_i’$ for $i$ in its range. This is done by computing $s_0$ and $t_0$ as described above. This produces a certain number of partial results (one for each thread) that we denote here by $B_{k, j}$. The sum of all these elements for all $k$ equals $G_j$.&lt;&#x2F;p&gt;
&lt;p&gt;(1’.d) The results $B_{k, j}$ for all $k$ are copied to the CPU and added sequentially to get $G_j$. Then, this is doubled $21$ times to get $2^{21}G_j$ (except for the last window where $2^{22}G_{12}$ is computed). While this happens in the CPU, steps (1’.b) and (1’.c) are handled in the GPU for the subsequent window.&lt;&#x2F;p&gt;
&lt;p&gt;Once all windows have been handled, the final sum is performed in the CPU.&lt;&#x2F;p&gt;
&lt;p&gt;A few interesting things to note about this solution.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The code is very clear. It uses OOP and many c++11 features and standard libraries.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * A naive implementation of the kernel launched in step (1&amp;#39;c) could severely suffer from warp divergence. This is because there is a lot of branching in the construction of $t_i$ and $s_i$. For example, if one $m_{i, j}&amp;#39;$ is equal to $m_{i-1,j}&amp;#39;$ then nothing has to be done to compute $s_i$. To overcome this issue, each thread fills up a buffer of max size $10$ with the non-zero differences $m_{i, j} - $m_{i-1, j}$ it encounters. All the elliptic curve operations are postponed until one of the threads in the warp fills out its buffer. At this point, all the threads in the warp flush their pending elliptic curve operations. To do this the warp vote function `__any_sync` is used (see [here](https:&#x2F;&#x2F;docs.nvidia.com&#x2F;cuda&#x2F;cuda-c-programming-guide&#x2F;index.html#warp-vote-functions)).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;mike-voronov-and-alex-kolganov&quot;&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;z-prize&#x2F;2022-entries&#x2F;tree&#x2F;main&#x2F;open-division&#x2F;prize1-msm&#x2F;prize1a-msm-gpu&#x2F;mikevoronov&quot;&gt;Mike Voronov and Alex Kolganov&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Mainly, this submission improves over the baseline using signed scalars to reduce the number of buckets in step (1) of Pippenger (more details below). Although it also claims to use a careful tiling of threads to compute the partial sums in step (2) in Pippenger’s algorithm in parallel, there is little documentation about it.&lt;&#x2F;p&gt;
&lt;p&gt;The main contribution is in step (1). This solution uses a window size $s=23$.&lt;&#x2F;p&gt;
&lt;p&gt;(1.a) To compute $m_{i, j}$ a one-dimensional grid of one-dimensional blocks of size $256$ is launched. The total number of threads equals the number of base points, which is $2^{26}$. Each thread is in charge of computing the subscalars $m_{i, j}$ for a single $k_i$. Since the window size is $2^{23}$, all the subscalars $m_{i, j}$ satisfy $0 \leq m_{i, j} &amp;lt; 2^{23}$. If a subscalar is $m_{i, j}$ turns out to be bigger than $2^{22}$, then $2^{23}$ is substracted from it reducing it to the range $-2^{22} \leq m_{i, j} &amp;lt; 0$ and $2^{23}$ is carried over to the next window. The sign of the negative subscalar is transferred to the base point, given that it is cheap to negate elliptic curve points. As a consequence, they end up with subscalars in the range $0 \leq m_{i, j} &amp;lt; 2^{22}$ and possibly an additional window in case the last window needs to carry scalars.&lt;&#x2F;p&gt;
&lt;p&gt;Windows are then separated into two groups: The windows with odd and even indexes. Windows are handled in an asynchronous way and it is possible to handle more than two, the &lt;code&gt;config.numAsync&lt;&#x2F;code&gt; variable manages stream count. But for A40, two streams are enough to utilize all compute resources. The only exception is the last window which is treated separately in the CPU since it is the overflow window of the previous step and it is therefore much smaller. Each group gets its stream of threads and traverses its windows sequentially to compute the buckets and the final window sum $G_j$ as follows.&lt;&#x2F;p&gt;
&lt;p&gt;(1.b) For each window $j$, it sorts the subscalars $m_{i, j}$ and precomputes the starting and ending indexes of the occurrences of each subscalar in the sorted list, along with the number of occurrences of each one. This is done using the &lt;code&gt;thrust::sort_by_key&lt;&#x2F;code&gt; and &lt;code&gt;thrust::inclusive_scan&lt;&#x2F;code&gt; functions from the &lt;code&gt;thrust&lt;&#x2F;code&gt; library. It then launches a kernel with a one-dimensional grid of one-dimensional blocks of size $32$ to compute the buckets using the above pre-computed information.&lt;&#x2F;p&gt;
&lt;p&gt;(2.a) All windows are computed in parallel in different streams (two streams were used, but it is possible to use more, depending on GPU memory).&lt;br &#x2F;&gt;
(2.b) The buckets are then sorted, such that the buckets with the most points are run first. This allows the GPU warps to run convergent workloads and minimizes the tail effect. This solution writes custom algorithms to achieve this.&lt;&#x2F;p&gt;
&lt;p&gt;Then step (3) of Pippenger is performed in the CPU.&lt;&#x2F;p&gt;
&lt;p&gt;Other things to note from this solution.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The use of the `thrust` library.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * It always uses one-dimensional grids of one-dimensional blocks of sizes either $256$ or $32$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Two streams are used to even and odd windows in step (1.b) in parallel. This is because two streams are enough to utilize all computational resources.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * It looks like it was developed and run on a memory-constrained GPU card. In step (1.b) each group reuses the allocated arrays to store the buckets. It also reuses allocated arrays for different unrelated intermediate steps in the computation of the sorted lists of subscalars and the indexes associated with the first and last occurrences of each one.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Tested ideas that didn’t work. From the README of the submission:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * NAF - signed scalars are better because NAF reduces the number of buckets 2&#x2F;3 times, but signed scalars in 2 times&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * NAF + signed scalars - the main drawback of this variant is that a count of sums on the 2nd step twice more&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Karatsuba multiplication + Barrett reduction - turned out that the CIOS baseline Montgomery is better&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Affine summation + the Montgomery trick - turned out to be slower than the baseline summation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;matterlabs&quot;&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;z-prize&#x2F;2022-entries&#x2F;tree&#x2F;main&#x2F;open-division&#x2F;prize1-msm&#x2F;prize1a-msm-gpu&#x2F;matter-labs&quot;&gt;MatterLabs&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;This solution precomputes $2^{69j}P_i$ for each input point (this is different from what is stated in the documentation), $P_i$, and $j=0, 1, 2, 3$. These are all points in the EC. We can rewrite the first sum in this way:&lt;&#x2F;p&gt;
&lt;p&gt;$$ \sum_{i=1}^n \sum_{j=0}^3 k_{ij}2^{69j} P_i$$&lt;&#x2F;p&gt;
&lt;p&gt;where each $k_{ij}&amp;lt;2^{69}$.&lt;&#x2F;p&gt;
&lt;p&gt;Since each $2^{69j}P_i$ belongs to the EC and is already computed we can rewrite the sum as $\sum_{m=1}^{3n}k_m P_m$ (for other $k$s and other $P$s) where each $k_{m}&amp;lt;2^{69}$. This allows us to split each $k_m$ into three 23-bit windows for Pippenger’s algorithm.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;Arkworks&lt;&#x2F;code&gt; library is used to represent finite fields, elliptic curves, and big integers in the tests. However, for the MSM algorithm itself, these structures are implemented by the authors. They used optimized versions of the operations to run them on the GPU when running device code.&lt;&#x2F;p&gt;
&lt;p&gt;A new library is developed called &lt;code&gt;Bellman-CUDA&lt;&#x2F;code&gt;. It’s used to make operations on finite fields, sort (using &lt;code&gt;CUB&lt;&#x2F;code&gt; utilities), run length-encoding (using &lt;code&gt;CUB&lt;&#x2F;code&gt; as well), etc. taking advantage of the GPU. The goal of this is probably to replace in the future the calls to &lt;code&gt;CUB&lt;&#x2F;code&gt; with more efficient algorithms.&lt;&#x2F;p&gt;
&lt;p&gt;The windows are processed in smaller parts. The first chunk of all the windows is processed first, then the second chunk of all windows, etc. This allows processing while other scalar parts are still in asynchronous transfer from the host to the device memory.&lt;&#x2F;p&gt;
&lt;p&gt;For each window chunk, a tuple index for each bucket is generated in parallel: $(i, j)$ where $i$ is the coefficient for the bucket and $j$ is the EC point in that bucket. These are sorted (in parallel) according to the first component so that we have the EC points that are to be summed up in each bucket. They are then length-encoded and sorted (in parallel as well) according to the number of points that the bucket has. In this way, the buckets that have more points will be processed first to enable efficient usage of the GPU hardware. After that, a list of offsets is generated (using the parallel algorithm to compute exclusive sums implemented by &lt;code&gt;CUB&lt;&#x2F;code&gt;) to know where each bucket starts and ends. For example:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\begin{align}&lt;br &#x2F;&gt;
2P_1+5P_2+4P_3+1P_4+2P_5 \rightarrow (2,1), (5,2), (4,3), (1,4), (2,5) \\&lt;br &#x2F;&gt;
\rightarrow [(1, 4), (2, 1), (2, 5), (4, 3), (5, 2)], [1, 2, 4, 5], [1, 2, 1, 1] \\&lt;br &#x2F;&gt;
\rightarrow [4, 1, 5, 3, 2], [0, 1, 3, 4, 5], [1, 2, 4, 5], [1, 2, 1, 1]&lt;br &#x2F;&gt;
\end{align}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;The buckets are then aggregated in parallel.&lt;&#x2F;p&gt;
&lt;p&gt;The FF and EC routines have been optimized:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Based on Montgomery&amp;#39;s multiplication&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Minimized correction steps in the FF operations&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Use of XYZZ representation for the EC point accumulators&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Use of fast squaring&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;streams-and-memory-management&quot;&gt;Streams and memory management&lt;&#x2F;h3&gt;
&lt;p&gt;The following streams are created:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `stream`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `stream_copy_scalars`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `stream_copy_bases`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `stream_copy_finished`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `stream_sort_a`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * `stream_sort_b`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The first one is the mainstream. Kernels such as &lt;code&gt;initialize_buckets&lt;&#x2F;code&gt;, &lt;code&gt;compute_bucket_indexes&lt;&#x2F;code&gt;, &lt;code&gt;run_length_encode&lt;&#x2F;code&gt;, &lt;code&gt;exclusive_sum&lt;&#x2F;code&gt;, and &lt;code&gt;sort_pairs&lt;&#x2F;code&gt; are run in that stream.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;stream_copy_scalars&lt;&#x2F;code&gt; waits for &lt;code&gt;event_scalars_free&lt;&#x2F;code&gt;.&lt;br &#x2F;&gt;
&lt;code&gt;stream_copy_scalars&lt;&#x2F;code&gt; handles the async copying of scalars and enqueues &lt;code&gt;event_scalars_loaded&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;stream_copy_bases&lt;&#x2F;code&gt; waits for &lt;code&gt;event_scalars_loaded&lt;&#x2F;code&gt; and &lt;code&gt;event_bases_free&lt;&#x2F;code&gt;. This stream also handles the async copying of bases and queues &lt;code&gt;event_bases_loaded&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;stream&lt;&#x2F;code&gt; waits for &lt;code&gt;event_scalars_loaded&lt;&#x2F;code&gt;, handles the kernel &lt;code&gt;compute_bucket_indexes&lt;&#x2F;code&gt;, and queues &lt;code&gt;event_scalars_free&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;stream&lt;&#x2F;code&gt; handles the sorting of the indexes and the asynchronous allocation of memory for the indexes and run lengths, as well as the &lt;code&gt;exclusive_sum&lt;&#x2F;code&gt; kernel and the allocation of memory for the offsets.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;stream&lt;&#x2F;code&gt; enqueues &lt;code&gt;event_sort_inputs_ready&lt;&#x2F;code&gt;. &lt;code&gt;stream_sort_a&lt;&#x2F;code&gt; and &lt;code&gt;stream_sort_b&lt;&#x2F;code&gt; wait on that event to handle the sorting of the pairs on the GPU.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;stream_sort_a&lt;&#x2F;code&gt; enqueues &lt;code&gt;event_sort_a&lt;&#x2F;code&gt; and &lt;code&gt;stream_sort_b&lt;&#x2F;code&gt; enqueues &lt;code&gt;event_sort_b&lt;&#x2F;code&gt;. &lt;code&gt;stream&lt;&#x2F;code&gt; waits on that event and also on &lt;code&gt;event_bases_loaded&lt;&#x2F;code&gt; before handling the kernel that aggregates the buckets. &lt;code&gt;stream&lt;&#x2F;code&gt; enqueues the (async) freeing of memory for the bases.&lt;&#x2F;p&gt;
&lt;p&gt;On the last loop of window chunk processing, &lt;code&gt;stream_copy_finished&lt;&#x2F;code&gt; waits for &lt;code&gt;event_scalars_loaded&lt;&#x2F;code&gt; and &lt;code&gt;event_bases_loaded&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Memory es freed and the streams (except &lt;code&gt;stream&lt;&#x2F;code&gt; that handles the bucket reduction and window splitting kernels) are destroyed.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;bucket-aggregation-algorithm&quot;&gt;Bucket aggregation algorithm&lt;&#x2F;h3&gt;
&lt;p&gt;This algorithm is used after having every bucket computed, and is the basis for a parallelization strategy to aggregate buckets. It is an alternative to the classic sum of partial sums trick in Pippenger’s. In what follows we assume every bucket has already been computed and the remaining problem is to add up all the points in every window.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;notation&quot;&gt;Notation&lt;&#x2F;h3&gt;
&lt;p&gt;Let us fix some notation. Let $W=(B_0, \dots, B_{2^{b}-1})$ be a tuple of $2^b$ elliptic curve points. Let us call such a tuple a &lt;strong&gt;$b$-bit window&lt;&#x2F;strong&gt;. To every window $W$ we associate an elliptic curve point $P_W$ defined as&lt;&#x2F;p&gt;
&lt;p&gt;$$P_W := B_1 + 2B_2 + \cdots + (2^{b}-1)B_{2^{b}-1}$$&lt;&#x2F;p&gt;
&lt;p&gt;We call a tuple of $m$ such windows $C = (W_0, \dots, W_{m-1})$ of the same length $2^{b}$ a &lt;strong&gt;window configuration&lt;&#x2F;strong&gt;. We say that the window configuration has shape $(m, b)$. Every window configuration has an associated elliptic curve point defined by&lt;&#x2F;p&gt;
&lt;p&gt;$$P_C := P_{W_0} + 2^{b}P_{W_1} + 2^{2b}P_{W_2} + \cdots + 2^{(m-1)b}P_{W_{m-1}}$$&lt;&#x2F;p&gt;
&lt;p&gt;In the context of MSM, each $B_i$ is a bucket and $P_C$ is the desired final result.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;reduction-process&quot;&gt;Reduction process&lt;&#x2F;h3&gt;
&lt;p&gt;Let us assume every bucket has already been computed and let $C$ be the corresponding window configuration. MatterLabs’ solution implements an algorithm to obtain $P_C$ by iteratively reducing a window configuration $C_i$ of shape $(m, b)$ to another window configuration $C_{i+1}$ of shape $(2m, \lceil b&#x2F;2 \rceil)$. At every step, the point $P_{C_{i}}$ is not necessarily equal to $P_{C_{i+1}}$, but it can be obtained from $C_{i+1}$ by shifting some scalars. See below for the details. The process starts with a configuration $C$ of shape $(3, 23)$ and ends with a configuration $D$ of shape $(96, 1)$. At this point, $P_C$ is computed from $D$.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;window-splitting&quot;&gt;Window splitting&lt;&#x2F;h3&gt;
&lt;p&gt;The reduction consists of splitting every window of a configuration. Let us describe this splitting process for a single $b$-bit window $W$. We construct from it two new $\lceil b&#x2F;2\rceil$-bit windows $\hat W_0$ and $\hat W_1$ such that&lt;&#x2F;p&gt;
&lt;p&gt;$$P_W = P_{\hat W_0} + 2^{\lceil b&#x2F;2 \rceil}P_{\hat W_1}.$$&lt;&#x2F;p&gt;
&lt;p&gt;The idea behind this construction is the following. Every component of $W$ is of the form $B_r$, where $0\leq r &amp;lt; 2^b$. We can write $r = a + b2^{k}$ where $0\leq a,b &amp;lt; 2^k$. Then $B_r$ is put into two new buckets, namely the $a$-th component of window $\hat W_0$ and the $b$-th component of window $\hat W_1$.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;case-b-even&quot;&gt;Case $b$ even:&lt;&#x2F;h4&gt;
&lt;p&gt;Write $b=2k$. Let $W$ be a $b$-bit window. Define the new $k$-bit windows $\hat W_0$ and $\hat W_{1}$ as follows.&lt;&#x2F;p&gt;
&lt;p&gt;Denote the components of $W$ by $(B_{0}, \dots, B_{2^b-1})$. Then&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\begin{aligned}&lt;br &#x2F;&gt;
\hat W_{0} &amp;amp;:= (\sum_{i=0}^{2^{k}-1}B_{i2^k}, \sum_{i=0}^{2^{k}-1}B_{i2^k+1},\dots,\sum_{i=0}^{2^{k}-1}B_{i2^k+2^{k}-1}), \\&lt;br &#x2F;&gt;
\hat W_{1} &amp;amp;:= (\sum_{i=0}^{2^{k}-1}B_{i}, \sum_{i=0}^{2^{k}-1}B_{i + 2^k},\dots,\sum_{i=0}^{2^{k}-1}B_{i + (2^{k}-1)2^{k}})&lt;br &#x2F;&gt;
\end{aligned}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;h4 id=&quot;case-b-odd&quot;&gt;Case $b$ odd:&lt;&#x2F;h4&gt;
&lt;p&gt;Let us write $b = 2k-1$. This case is similar to the above. As before, let $W$ be a $b$-bit window. The definition of $\hat W_0$ and $\hat W_1$ follows the same logic as before.&lt;br &#x2F;&gt;
But there is a catch. If $r$ is such that $0\leq r &amp;lt; 2^b$ and we write $r= a + b2^k$ with $0\leq a,b &amp;lt; 2^k$, then $b$ is necessarily at most $2^{k-1}$. And so the second half of the coordinates of $\hat W_{1}$ will be empty. This is because none of the buckets $B_r$ of $W_n$ will be assigned to those coordinates. And so we obtain&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\begin{aligned}&lt;br &#x2F;&gt;
\hat W_{0} &amp;amp;:= (\sum_{i=0}^{2^{k-1}-1}B_{i2^k}, \sum_{i=0}^{2^{k-1}-1}B_{i2^k+1},\dots,\sum_{i=0}^{2^{k-1}-1}B_{i2^k+2^{k}-1}), \\&lt;br &#x2F;&gt;
\hat W_{1} &amp;amp;:= (\sum_{i=0}^{2^{k}-1}B_{i}, \sum_{i=0}^{2^{k}-1}B_{i + 2^k},\dots,\sum_{i=0}^{2^{k}-1}B_{i + (2^{k-1}-1)2^{k}}, \mathcal O,\dots, \mathcal O).&lt;br &#x2F;&gt;
\end{aligned}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;In the above definition, there are $2^{k-1}$ coordinates with entry $\mathcal O$, the point at infinity.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;reduction-of-window-configurations-and-coefficient-shifts&quot;&gt;Reduction of window configurations and coefficient shifts&lt;&#x2F;h3&gt;
&lt;p&gt;Performing the above process on every window of a configuration $C$ we obtain a new configuration $D$ of the desired shape. We will not always have $P_C = P_D$.&lt;&#x2F;p&gt;
&lt;p&gt;Let $C=(W_0, W_1, \dots, W_n)$ be a window configuration of shape $(m, b)$. For every window $W_n$, let $\hat W_{2n}$ and $\hat W_{2n+1}$ the two $\lceil b&#x2F;2 \rceil$-bit windows obtained from splitting $W_n$. Let $D=(\hat W_0, \hat W_1, \dots, \hat W_{2m-1})$. This is a window configuration of shape $(2m, \lceil b&#x2F;2 \rceil)$.&lt;&#x2F;p&gt;
&lt;p&gt;If $b$ is even, then it is easy to see that $P_C = P_D$.&lt;&#x2F;p&gt;
&lt;p&gt;If $b$ is odd, then $P_C$ is, in general, different from $P_D$. For example, the first 2 terms of $P_C$ are $W_0 + 2^bW_1$. On the other hand, the first four terms of $P_D$ are $\hat W_0 + 2^k\hat W_1 + 2^{2k}\hat W_2 + 2^{3k}\hat W_3$. This is equal to $W_0 + 2^{2k} W_1 = W_0 + 2^{b+1}W_1$. And so the coefficient of $W_1$ in $P_D$ has an extra factor of $2$.&lt;&#x2F;p&gt;
&lt;p&gt;Nevertheless, $P_C$ is equal to&lt;&#x2F;p&gt;
&lt;p&gt;$$P_{\hat W_0} + 2^{k-f_1}P_{\hat W_1} + 2^{2k-f_2}P_{\hat W_2} + \cdots + 2^{(2m-1)k-f_{2m-1}}P_{\hat W_{2m-1}},$$&lt;br &#x2F;&gt;
where $f_i = \lfloor i&#x2F;2\rfloor$. We call these the coefficient shifts.&lt;&#x2F;p&gt;
&lt;p&gt;In general, we can define $f_i$ to be $0$ for all $i$ if $b$ is even and $f_i = \lfloor i&#x2F;2 \rfloor$ for all $i$ if $b$ is odd.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;algorithm&quot;&gt;Algorithm&lt;&#x2F;h3&gt;
&lt;p&gt;We start with a window configuration $C_0$ of shape $(m, b) = (3, 23)$. Inductively for every $i$ perform the reduction step on $C_i$ to obtain a new window configuration $C_{i+1}$ and also accumulate the coefficient shifts. After $4$ steps we obtain $C_5$ of shape $(96, 1)$ and the accumulated coefficient shifts $f_i$.&lt;&#x2F;p&gt;
&lt;p&gt;From $C_5$ and and the $f_i$ we can compute $P_{C_0}$.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;parallelization-strategy-2&quot;&gt;Parallelization strategy&lt;&#x2F;h3&gt;
&lt;p&gt;When splitting a window configuration of shape $(m, b)$ into one of shape $(2m, k)$, where $k=\lceil b&#x2F;2\rceil$, each new bucket is a sum of $2^k$ elements (or $2^{k-1}$ in some cases when $b$ is odd). To compute these, the following kernels are launched.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. First a kernel with $2m2^{k+l}$ threads for some $l \leq \lfloor b&#x2F;2 \rfloor$ is launched. The $2^k$ terms of the sum of each new bucket are split into $2^{l}$ even groups. Each thread then computes the sum of the terms in a group. These partial sums are computed sequentially.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. A second kernel with $2m2^{k}$ threads is launched. Each thread is in charge of a bucket. It uses a binary reduction algorithm to compute it by adding the $2^l$ partial sums obtained by the previous kernel.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;yrrid&quot;&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;z-prize&#x2F;2022-entries&#x2F;tree&#x2F;main&#x2F;open-division&#x2F;prize1-msm&#x2F;prize1a-msm-gpu&#x2F;yrrid&quot;&gt;Yrrid&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;This solution precomputes $2^{2\cdot23j}P_i$ for each input point, $P_i$ and $j=1,…,6$. These are all points in the EC. We can rewrite the first sum in this way:&lt;&#x2F;p&gt;
&lt;p&gt;$$ \sum_{i=1}^n \sum_{j=0}^5 k_{ij}2^{2\cdot23j} P_i$$&lt;&#x2F;p&gt;
&lt;p&gt;where each $k_{ij}&amp;lt;2^{2\cdot23}$.&lt;&#x2F;p&gt;
&lt;p&gt;Since each $2^{46j}P_i$ belongs to the EC and is already computed we can rewrite the sum as $\sum_{m=1}^{6n}k_m P_m$ (for other $k$s and other $P$s) where each $k_{m}&amp;lt;2^{46}$. This allows us to&lt;br &#x2F;&gt;
split each $k_m$ into two 23-bit windows for Pippenger’s algorithm.&lt;&#x2F;p&gt;
&lt;p&gt;Another optimization the algorithm uses is the following: the window value has a sign bit and a 22-bit scalar value. If the scalar is large, we can negate the point and change the scalar to $s’=m - s$ where $m$ is the order of the field. The new scalar, $s’$, will have a high bit clear. This works since $s’ (-P_i) = (m - s) (-P_i) = -s -P_i = s P_i$.&lt;&#x2F;p&gt;
&lt;p&gt;The buckets are then sorted, such that the buckets with the most points are run first. This allows the GPU warps to run convergent workloads and minimizes the tail effect. This solution writes custom algorithms to achieve bucket sorting instead of using the CUB libraries.&lt;&#x2F;p&gt;
&lt;p&gt;The bucket sums are computed in parallel (assigning a thread to each bucket) using the XYZZ EC representation. The operations for this curve representation can be found &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;hyperelliptic.org&#x2F;EFD&#x2F;g1p&#x2F;auto-shortw-xyzz.html#addition-add-2008-s&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The FF and EC routines have been optimized:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Based on Montgomery&amp;#39;s multiplication&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Minimize correction steps in the FF operations&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Use an XYZZ representation for the EC point accumulators&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Use fast squaring&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;Multiscalar multiplication (MSM) is one of the key operations in many proving systems, such as Marlin or Plonk with Kate polynomial commitment schemes. Owing to the nature of the operation, we can leverage GPUs to reduce its calculation time. The ZPrize competition sought to improve the current baseline of 5.86 seconds for an MSM with \( 2^{26} \) points for the BLS12-377 curve. There were 6 different proposals, each with its unique features, based on Pippenger’s algorithm: optimizing window size, precomputation of some points (trading memory for speed), different coordinate systems for elliptic curve addition, endomorphisms, parallel reduction algorithms, point negation, non-adjacent form for integers, better finite field arithmetic. The best solutions achieved 2.52 seconds (2.3x speedup), but we think there is still more room for further optimization. Will we get below 1 second? Maybe you have the answer…&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Incrementally verifiable computation: NOVA</title>
          <pubDate>Fri, 20 Jan 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/incrementally-verifiable-computation-nova/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/incrementally-verifiable-computation-nova/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/incrementally-verifiable-computation-nova/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;One of the current goals is to realize, in an efficient way, incrementally verifiable computation (IVC). This cryptographic primitive allows a given party to show the integrity of a given computer program’s execution by providing proof that the result of each step is correct and that all previous ones have been appropriately executed at every step. More precisely, given step \( N \), we apply a function \( F_N \) which updates the state, taking as inputs the current state \( x_N \) and a proof that asserts the correct execution of all steps \( 1,2,…N-1 \), \( \pi_{N-1} \), and outputting the new state \( x_{N+1} \) and a proof of its correct execution \( \pi_{N+1} \). IVC has many applications, such as allowing decentralized private computation (DPC), where you can delegate the execution of your programs to untrusted third parties, succinct blockchains, and verifiable delay functions.&lt;&#x2F;p&gt;
&lt;p&gt;In a previous post, we discussed the problem of DPC and two protocols related to it, &lt;a href=&quot;&#x2F;decentralized-private-computations-zexe-and-veri-zexe&#x2F;&quot;&gt;ZEXE and VERI-ZEXE&lt;&#x2F;a&gt;. ZEXE discussed the possibility of using proof-carrying data (PCD) to be able to verify arbitrary computations, but this can be pretty expensive computationally since, at each step, we need to verify the proof of the previous step, for which we need to:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Compute expensive bilinear pairing operations.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Include the arithmetic circuit of the verifier into our program, which is not a lightweight construction.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;VERI-ZEXE leveraged accumulation schemes (AS) to provide IVC. The key idea is to delay the final proof to the ledger’s validators (where we will need to compute the expensive pairing operation). At each step of the computation, the proof \( \pi_{N-1} \) is “added” to an accumulator, which is then partially verified: the prover checks that the result of the accumulation is correct, but does not compute pairing operations. We mask the group elements in the accumulator using a randomizer to ensure zero knowledge.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2021&#x2F;370.pdf&quot;&gt;Nova&lt;&#x2F;a&gt; is a new protocol proposing an alternative to realizing IVC with lightweight construction. Instead of using &lt;a href=&quot;&#x2F;the-hunting-of-the-zk-snark&#x2F;&quot;&gt;zk-SNARKs&lt;&#x2F;a&gt;, they take advantage of folding schemes, accumulating NP instances instead of SNARKs. The authors claim it results in a weaker, simpler, and more efficient scheme than those relying on succinct arguments of knowledge:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The verifier circuit is constant in size and dominated by two group scalar multiplications.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The prover&amp;#39;s work is dominated by two multiexponentiations.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The key point is that the folding acts as a deferral of proof verification until the last point: to check the correct application of \( N \) times a given function, we only need to check the folded proof for the \( N \) steps.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;folding-schemes&quot;&gt;Folding schemes&lt;&#x2F;h2&gt;
&lt;p&gt;A folding scheme is a protocol between an untrusted prover and a verifier. Each of them has an \( N- \)sized NP instance of equal size, and the prover has, in addition, witnesses for both instances (recall, in the context of zk-SNARKs that we call witness the secret inputs&#x2F;information). The protocol enables them to output a single \( N- \) sized NP instance, known as the folded instance. The folding scheme guarantees that the folded instance is satisfiable only if the original instances are valid. We call the scheme non-trivial if the verifier’s work and communication are less than those he would have if he did not participate in the folding scheme. The folding scheme reduces the satisfiability of two NP instances to just one NP instance. Some techniques exhibiting this two-to-one reduction (or some reduction) are sum check protocols, batch proving, and bulletproofs. To realize such a construction, we have to introduce relaxed (quadratic) rank-one constraint systems (relaxed R1CS).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;r1cs-and-relaxed-r1cs&quot;&gt;R1CS and relaxed R1CS&lt;&#x2F;h2&gt;
&lt;p&gt;We saw that the correct execution of a given code could be expressed as a &lt;a href=&quot;&#x2F;how-to-transform-code-into-arithmetic-circuits&#x2F;&quot;&gt;circuit satisfiability problem&lt;&#x2F;a&gt;. Circuits are equivalent to R1CS, which are systems of equations of the form:&lt;br &#x2F;&gt;
\[ Az \times Bz = Cz \]&lt;br &#x2F;&gt;
where \( A,B,C \) are sparse matrices and \( \times \) denotes component-wise product. It is quadratic because each variable in each equation has at most degree two (we can have \( z_1^2 \) but not \( z_1^4 \)). Even though R1CS are a convenient way to express circuits, they are not fully compatible with folding schemes; in other words, it is not easy to build a folding scheme on top of R1CS.&lt;&#x2F;p&gt;
&lt;p&gt;Nova works by taking incremental computations, where each step is expressed as an R1CS; the constraint system is augmented with the verification circuit, which has to assert the correctness of the execution of the previous step. However, instead of verifying the proof \( \pi_{N-1} \), Nova treats it as an instance of R1CS and folds it into a running relaxed R1CS.&lt;&#x2F;p&gt;
&lt;p&gt;A relaxed R1CS introduces an error, \( E \), and a scalar, \( u \), such that&lt;br &#x2F;&gt;
\[ Az \times Bz = uCz+E \]&lt;br &#x2F;&gt;
Note that any R1CS is also a relaxed R1CS, where \( E \) is the zero vector and \( u=1\). Relaxed R1CS retains the property that it is NP-complete, which means that we can reduce any NP problem to it.&lt;&#x2F;p&gt;
&lt;p&gt;We want the folding scheme to merge two instances of R1CS with the same matrices \( A, B, C \) into a single one. Each R1CS has its corresponding instance-witness pairs (that is, public and private data), \( z_i=(w_i,x_i) \), and we want to create a new \( z=(w,x) \) satisfying the R1CS system of equations with \( A, B, C \), such that this also implies that each \( z_i=(w_i,x_i) \) does so. One way to do this is by having the verifier select a random \( r \) and perform the following transformation:&lt;br &#x2F;&gt;
\[ z=z_1+rz_2 \]&lt;br &#x2F;&gt;
This transformation would suffice for linear systems of equations, but since the R1CS is nonlinear, we cannot apply this simple strategy. If we replace this into the R1CS&lt;br &#x2F;&gt;
\[ Az_1\times Bz_1+r(Az_1 \times Bz_2 +Az_2\times Bz_1)+r^2(A_2z_2\times B_2z_2) = Cz_1+rCz_2 \]&lt;&#x2F;p&gt;
&lt;p&gt;In the relaxed R1CS, the error term \( E \) will absorb all the cross-terms generated by introducing the linear combination, and \( u \) will take the extra \( r \) term on the right-hand side. To do so,&lt;br &#x2F;&gt;
\[ u=u_1+ru_2 \]&lt;br &#x2F;&gt;
\[ E=E_1+r(Az_1\times Bz_2+Az_2\times Bz_1-u_1Cz_2-u_2Cz_1)+r^2E_2\]&lt;br &#x2F;&gt;
and both \( u,E \) are added to the instance-witness pair. The main problem is that the prover has to send the witnesses \( w_1,w_2 \) to the verifier so that he can compute \( E \). To do this, we treat both \( E \) and \( w \) as witnesses and hide them using polynomial commitment schemes.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;polynomial-commitment-scheme&quot;&gt;Polynomial commitment scheme&lt;&#x2F;h2&gt;
&lt;p&gt;Nova uses an inner product argument (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;dankradfeist.de&#x2F;ethereum&#x2F;2021&#x2F;07&#x2F;27&#x2F;inner-product-arguments.html&quot;&gt;IPA&lt;&#x2F;a&gt;), which relies on Pedersen commitments. These are based on the assumption that the discrete log is hard to solve and do not require a trusted setup. IPA differs from other popular commitment schemes, such as KZG, which relies on elliptic curve pairings and needs a trusted setup. Regarding proof sizes and verification times, KZG is better since IPA with Pedersen commitments requires linear work from the verifier, with proof size depending on the input (KZG’s proof and verification time are constant). However, we can work these weaknesses around in systems such as Halo.&lt;&#x2F;p&gt;
&lt;p&gt;The lightweight construction of the verifier is tied to the polynomial commitment scheme. In this case, the highest cost is two &lt;a href=&quot;&#x2F;need-for-speed-elliptic-curves-chapter&#x2F;&quot;&gt;group scalar multiplications &lt;&#x2F;a&gt;. Nova’s verifier circuit is around 20,000 constraints.&lt;&#x2F;p&gt;
&lt;p&gt;The fundamental property that the polynomial commitment scheme must satisfy is that it is additively homomorphic: given two variables \( a, b \), we say that the commitment is additively-homomorphic if \( \mathrm{cm}(a+b)=\mathrm{cm}(a)+\mathrm{cm}(b) \), where \( \mathrm{cm}(x) \) is the commitment of \( x \). Both KZG and Pedersen’s commitments fulfill this property. Using this, both the verifier’s communication and work are constant.&lt;&#x2F;p&gt;
&lt;p&gt;The other necessary property is succinctness: the commitment size must be logarithmic in the opening size. For example, if we have a degree \( n \) polynomial, its commitment should take at most \( \log(n) \) elements.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;folding-scheme-for-committed-relaxed-r1cs&quot;&gt;Folding scheme for committed relaxed R1CS&lt;&#x2F;h2&gt;
&lt;p&gt;An instance (that is, the public variables) for a committed relaxed R1CS is given by \( x \), the public input and output variables, \( u \) and the commitments to \( E \), \( \mathrm{cm}(E) \) and \( \mathrm{cm}(w) \). We can group these in the tuple \( (x,\mathrm{cm}(w),\mathrm{cm}(E),u)\). The instance is satisfied by a witness (secret variables) \( (E,r_E,w,r_w)\) if \( \mathrm{cm}(E)=\mathrm{Commit}(E,r_E)\), \( \mathrm{cm}(w)=\mathrm{Commit}(w,r_w)\) and \( Az\times Bz = uCz+E \), where \( z=(w,x,u) \). In simple words, the witness satisfies the instance if the public variables \( \mathrm{cm}(E) \) and \( \mathrm{cm}(w) \) are indeed the commitments to the private variables \( E,w \) using randomness \( r_E,r_w \), respectively and they fulfill the relaxed R1CS equations.&lt;&#x2F;p&gt;
&lt;p&gt;The prover and verifier have access to two instances of relaxed R1CS, \( (x_1,\mathrm{cm}(w_1),\mathrm{cm}(E_1),u_1)\) and \( (x_2,\mathrm{cm}(w_2),\mathrm{cm}(E_2),u_2)\). In addition, the prover has \( (E_1,r_{E1},w_1,r_{w1})\) and \( (E_2,r_{E2},w_2,r_{w2})\). The protocol proceeds as follows:&lt;&#x2F;p&gt;
&lt;p&gt;1.The prover computes \( T=Az_1\times Bz_2+Az_2\times Bz_1-u_1Cz_2-u_2Cz_1\) and sends the commitment to it, \( \mathrm{cm}(T)=\mathrm{Commit}(T,r_T) \).&lt;br &#x2F;&gt;
2. The verifier samples the random challenge, \( r \).&lt;br &#x2F;&gt;
3. The prover and verifier output the folded instance,&lt;br &#x2F;&gt;
\( \mathrm{cm}(E)=\mathrm{cm}(E_1)+r^2\mathrm{cm}(E_2)+r\mathrm{cm}(T) \)&lt;br &#x2F;&gt;
\( u=u_1+ru_2 \)&lt;br &#x2F;&gt;
\( \mathrm{cm}(w)=\mathrm{cm}(w_1)+r\mathrm{cm}(w_2) \)&lt;br &#x2F;&gt;
\( x=x_1+rx_2 \)&lt;br &#x2F;&gt;
4. The prover updates the witness&lt;br &#x2F;&gt;
\( E=E_1+rT+r^2E_2 \)&lt;br &#x2F;&gt;
\( r_E=r_{E1}+rr_T+r^2r_{E2} \)&lt;br &#x2F;&gt;
\( w=w_1+r w_2 \)&lt;br &#x2F;&gt;
\( r_w=r_{w1}+rr_{w2} \)&lt;&#x2F;p&gt;
&lt;p&gt;The protocol can be made non-interactive by using the Fiat-Shamir transformation.&lt;&#x2F;p&gt;
&lt;p&gt;Using this strategy, we can realize IVC by successively updating the parameters after folding. The prover can then use a zk-SNARK showing that he knows the valid witness \( (E,r_E,w,r_w) \) for the committed relaxed R1CS in zero knowledge, that is, without revealing its value.&lt;&#x2F;p&gt;
&lt;p&gt;The problem with using some common SNARKs is that the prover must show that he knows valid vectors whose commitments equal given values. This implies encoding a linear number of group scalar multiplications in the SNARK’s model. Therefore, we need a new construction to deal with this problem.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;polynomial-interactive-oracle-proof-piop&quot;&gt;Polynomial interactive oracle proof (PIOP)&lt;&#x2F;h2&gt;
&lt;p&gt;The PIOP is a modified version of Spartan. It is based on the sum-check protocol and multilinear polynomials. For a given function mapping bitstrings to field elements, \( f:{0,1}^n \rightarrow \mathbb{F}\), we say that \( p:{0,1}^n \rightarrow \mathbb{F} \) is a polynomial extension of \( f \) if it is a low degree polynomial satisfying \( f(x)=p(x) \) for all \( x \) in \( {0,1}^n \). We call the extension multilinear if \( p \) is a multilinear polynomial such that \( f(x)=p(x) \). Multilinear polynomials are polynomials in several variables, such that the degree of each variable is at most 1 in every term. For example, \( p(x_1,x_2,x_3)=x_1+x_1x_2x_3+x_2x_3 \) is multilinear (in each term, we have at most \( x_i \)), but \( p(x_1,x_2)=x_1^2x_2 \) is not.&lt;&#x2F;p&gt;
&lt;p&gt;The R1CS matrices, \( A,B,C \) can be thought as functions from \( {0,1}^m \times {0,1}^m\) to some finite field \( \mathbb{F_p} \) in a natural way. Therefore, we can also make multilinear extensions of them \( A_{ML}, B_{ML}, C_{ML} \), that is, \( 2\log(m) \) multilinear polynomials. Since the R1CS matrices are sparse, the corresponding multilinear polynomials are sparse (in simple words, they have few non-zero coefficients). The vectors \( E \) and \( w \) can also be interpreted as polynomials, \( E_{ML} \) and \( w_{ML} \). The vector \( z=(w,x,u) \) and \( y=(x,u) \) have also their multilinear extensions \(z_{ML},y_{ML} \). We have the following function,&lt;br &#x2F;&gt;
\[ F(t)=(\sum_y A_{ML}(t,y)z_{ML}(y))\times (\sum_y B_{ML}(t,y)z_{ML}(y))-\ (u\sum_y C_{ML}(t,y)z(y)+E_{ML}(t)) \]&lt;br &#x2F;&gt;
where we sum over all values of \( y \) in \( {0,1}^s \). We only need to check whether the following identity holds for a randomly sampled \( \tau \)&lt;br &#x2F;&gt;
\[ \sum_x g(\tau,x)F(x)=0 \]&lt;br &#x2F;&gt;
for \( x \) in \( {0,1}^s \), with \( g(x,y)=1 \) for \( x=y \) and zero otherwise. We can check that equality by applying the sum-check protocol to the polynomial \( p(t)=g(\tau,t)F(t) \)&lt;&#x2F;p&gt;
&lt;h2 id=&quot;advantages&quot;&gt;Advantages&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The verifier circuit is lightweight, with little more than 20,000 constraints.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * It does not need to perform FFT, so no special elliptic curves are required. The only condition is that it is sufficiently secure (that is, the discrete log problem must be hard).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The verification is not based on elliptic curve pairings, so expensive operations and pairing-friendly curves are unnecessary.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;Nova is a new protocol for realizing incrementally verifiable computation based on a new cryptographic primitive called a folding scheme. The key idea is to merge two instances of a given NP statement into a single one. To be able to do so, we have to make changes to the R1CS to include an error term \( E \) and a scalar \( u \) to obtain a relaxed R1CS, over which we can build an efficient folding scheme. We also need additively-homomorphic polynomial commitment schemes, such as Pedersen commitments. The resulting construction has a small verifier circuit (around 20,000 constraints in R1CS), obtaining fast proof generation and verification. This has many applications to public ledgers, verifiable delay functions, and proof aggregation.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Message Authentication Codes</title>
          <pubDate>Wed, 18 Jan 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/message-authentication-codes/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/message-authentication-codes/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/message-authentication-codes/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;We &lt;a href=&quot;&#x2F;symmetric-encryption&#x2F;&quot;&gt;discussed previously&lt;&#x2F;a&gt; how to ensure message confidentiality between two parties, Alice and Bob. We saw that we could use a symmetric key cipher, such as AES or ChaCha20, to encrypt messages between Alice and Bob so that only they can read them. However, when Bob gets a message from Alice, how does he know that it is truly from Alice, nor that a malicious party has not changed it? Here is where authenticity comes into play. For example, a man-in-the-middle (MIM) can try to impersonate Alice and Bob during a key exchange in a Diffie-Hellman protocol. The scheme works as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Alice chooses a random number \\( a \\) and computes \\( g^a \\) and sends it.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. The MIM gets \\( g^a \\), chooses \\( a^\prime \\) and sends Bob \\( g^{ a^\prime } \\).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Bob chooses a random number \\( b \\) and computes \\( g^b \\) and sends it.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. The MIM gets \\( g^b \\), chooses \\( b^\prime \\) and sends Bob \\( g^{ b^\prime } \\).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. Alice gets the shared secret \\( g^{ ab^\prime } \\), and Bob gets \\( g^{ a^\prime b } \\); their messages get decrypted by the MIM, who can read them and then re-encrypt them to Alice or Bob with the corresponding secret key.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Authenticity is also crucial in contexts where confidentiality is not needed. For example, we could have an authentication tag that gives proof of the integrity of files on our hard drive. If an attacker gets access to our hard drive, he may try to change files in our operating system. The authentication tags would tell us if there has been a modification in our files or not.&lt;&#x2F;p&gt;
&lt;p&gt;A message authentication code (MAC) is a primitive which allows us to ensure the integrity of a given message. Several constructions can be used, depending on the context. Two commonly used constructions are CBC-MAC and HMAC. MACs play an essential role in internet protocol security (IPsec), secure shell (ssh), and transport layer security (TLS), generating authentication codes for each packet that is transmitted.&lt;&#x2F;p&gt;
&lt;p&gt;We will discuss later how to combine authentication codes with encryption to obtain authenticated encryption, which can guarantee semantic security (that is, the attacker cannot learn anything from a given ciphertext) and ciphertext integrity, leading to secure encryption against tampering.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-a-mac&quot;&gt;What is a MAC?&lt;&#x2F;h2&gt;
&lt;p&gt;A message authentication code is a pair of efficient algorithms, signing, and verification, \( S, V \), which work over a set of messages and tags and take keys. The key space is given by an n-bit string \( {0,1 }^n \). If we know the key, we can add authentication tags and verify them. The signing algorithm takes a message \( m \) and the key \( k \) and outputs a tag \( t \):&lt;br &#x2F;&gt;
\[ S(k,m)=t \]&lt;br &#x2F;&gt;
The verification algorithm gets a tag, \( t \), the key \( k \), and the message \( m \) and outputs a boolean variable \( b \), which tells us whether the tag corresponds to the given message:&lt;br &#x2F;&gt;
\[ V(k,t,m)=b \]&lt;br &#x2F;&gt;
The MAC construction has to be secure to be helpful; otherwise, an attacker could forge messages. We say that an attacker has produced a forgery if he can find a valid pair \( m,t \) without knowing the key.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;attacks-against-mac&quot;&gt;Attacks against MAC&lt;&#x2F;h2&gt;
&lt;p&gt;To see whether a MAC is secure, we need to establish the powers of the attacker and what would be a successful attack.&lt;&#x2F;p&gt;
&lt;p&gt;We suppose the attacker can perform a chosen message attack (CMA). In simple words, the attacker is free to choose any messages \( m_i \) and can get access to the corresponding tag \( t_i=S(k,m_i) \) by having Alice or Bob calculate the tag. He does not have access to the key, though. While this may be seen as an awkward power (because he can get the tag of any message), this is something that could take place in the real world. The goal of the attacker is, given pairs \( (t_i,m_i) \) for \( i=1,2,…j \), to find a new valid pair \( t,m \), where \( m\neq m_i \). This pair is called an existential forgery. We will say the MAC is secure if it is existentially unforgeable under CMA.&lt;&#x2F;p&gt;
&lt;p&gt;MACs could also be rendered insecure by replay attacks. In this situation, an adversary may capture a message and its tag from Alice to Bob and then use it to impersonate Alice by sending the same message To Bob sometime later. To avoid this, MACs include a message number (increased with each new message) or a time stamp, which is authenticated with the original message in the MAC.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;construction-of-mac-by-pseudo-random-functions-prf&quot;&gt;Construction of MAC by pseudo-random functions (PRF)&lt;&#x2F;h2&gt;
&lt;p&gt;We saw examples of pseudo-random functions when we talked about block ciphers. We mentioned that these behave as pseudo-random permutations, where we take a message \( m \) and map it over one of all the possible output messages. For example, the AES block cipher is a function \( f:K\times \{0,1 \}^{128} \rightarrow \{0,1 \}^{128} \), taking a message of 16 bytes and outputting a random string of 16-bytes.&lt;&#x2F;p&gt;
&lt;p&gt;We can construct a MAC from a given PRF, taking messages in a space \( X \) (for example, messages up to GB long), and outputting a tag in \( Y \) (for example, a 128-bit string), \( g: K\times X \rightarrow Y \) by doing&lt;br &#x2F;&gt;
\[ t=g(k,m) \]&lt;br &#x2F;&gt;
This MAC is secure provided that the PFR g is secure and that the output set is large enough; that is, the number of elements \( \vert Y \vert \) is greater than \( 2^{80} \).&lt;&#x2F;p&gt;
&lt;p&gt;If the tag space is small, the attacker has a high probability of outputting the correct tag.&lt;&#x2F;p&gt;
&lt;p&gt;Block ciphers and cryptographic hash functions behave as pseudo-random functions; therefore, their use in constructing MAC is reasonable. In the first case, we get CBC-MAC, while in the second, HMAC.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;cbc-mac&quot;&gt;CBC-MAC&lt;&#x2F;h2&gt;
&lt;p&gt;We need a pseudo-random permutation (PRP) to build CBC-MAC, such as a block cipher. We can picture the MAC function as \( f:K^2\times M \rightarrow {0,1}^n\). It takes two different keys, \(k_1,k_2 \), a message and outputs a tag. In the case of using AES as PRP, \( n=128 \). Given that AES works with 16-byte words, the message is split into equal blocks of 16 bytes. We can always pad the message conveniently if it is not a multiple of 16. Let’s call \( m_0,m_1,…m_N \) the blocks composing the message and \( E(k,m)=C \) the AES encryption function, where the first argument is the key and the second is the message block. The algorithm proceeds as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Compute \\( t_1 = E( k_1 , m_0 )\\).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. For \\( j = 2, ... ,N \\) do  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;\( t_{ j-1 }^\prime = t_{ j-1 }\oplus m_j \)&lt;br &#x2F;&gt;
\( t_j = E(k_1 , t_{ j-1 }^\prime)\)
3. Compute \( t = E(k_2 , t_N) \)&lt;&#x2F;p&gt;
&lt;p&gt;This last step is critical to make the MAC secure against existential forgery. If step 3 were omitted, then we can perform the following chosen message attack:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Choose \\( m \\)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Request \\( t = E(k,m) \\)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Obtain the tag for the forged message \\( m,t\oplus m \\).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can see that we have obtained a valid pair by performing the calculations:&lt;br &#x2F;&gt;
\( f(k,m\vert \vert t\oplus m)=E(k,E(k,m)\oplus t\oplus m)=E(k,t\oplus t\oplus m)=E(k,m)=t \)&lt;br &#x2F;&gt;
where we have used the fact that \( a\oplus a\oplus b=b\) (XORing \(b \) twice with the same bitstring returns \( b \)).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;nmac&quot;&gt;NMAC&lt;&#x2F;h2&gt;
&lt;p&gt;The NMAC construction is based on the cascade diagram. In this case, the NMAC function is \( g:K^2\times M\rightarrow K \). As in CBC-MAC, we split the message in \( N+1 \) equal blocks, \( m_0 , m_1 , … m_N \). To obtain the tag,&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Set \\( t_0 = k_1 \\).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. For \\(i = 1,...N \\) perform \\( F(t_{i-1} , m_{i-1}) = t_i\\)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Pad \\( t_N \\) with a fix pad element \\( \mathrm{fpad} \\) so that its length corresponds to the size of the elements in \\( M \\), \\( t_{N+1} \\).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Compute \\( t=F(k_2 , t_{N+1}) \\)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Step 2 corresponds to the cascade. Step 4 is necessary once again to prevent a length extension attack. We can see that if we know the result of the cascade \( \mathrm{cascade}(k,m)\), then we can append any string \( w \) and obtain the exit of the cascade \( \mathrm{cascade}(k,m\vert \vert w)\).&lt;&#x2F;p&gt;
&lt;p&gt;Even though we could use NMAC with AES, this proves inconvenient in practice since there is a rapid change in the key scheduling. The strategy works best with cryptographic hash functions.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pmac&quot;&gt;PMAC&lt;&#x2F;h2&gt;
&lt;p&gt;The problem with the NMAC and CBC-MAC is that they are carried out sequentially. This can be inconvenient in the case of very long messages since we cannot leverage multiple processors to accelerate the calculation. Parallel MAC solves this problem by adopting a different scheme. To build PMAC, we need two functions: a pseudo-random function \( F:K\times M\rightarrow M \) and a function taking a key and a counter \( P:K\times \mathbb{Z_0 }^+ \rightarrow K \). To compute the tag:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. For \\( i = 0, 1 ,...N \\) compute \\( {m_i}^\prime = m_i \oplus P(k_1 ,i)\\) and \\( t_i = F(k_2 , {m_i}^\prime) \\).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Compute \\( m^\prime = m_0^\prime \oplus m_1^\prime\oplus ...\oplus m_N^\prime \\).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Obtain \\( t = F(k_2 , m^\prime) \\).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;universal-hashing-and-one-time-mac&quot;&gt;Universal hashing and One-time MAC&lt;&#x2F;h2&gt;
&lt;p&gt;A faster version than PFR function-based MACs is the one-time MAC; this can be secure against all adversaries. They are based on universal hash functions, which are weaker than cryptographic hash functions (they do not need to be collision-resistant) but operate much faster. A universal hash function (UHF) takes a key, \( k \), and a message, \( m \), and gives the hash \( h_m = UHF(k,m) \). The only security requirement is that for any two messages \( m_1 , m_2 \), the probability that they hash to the same value for a random key is negligible:&lt;br &#x2F;&gt;
\[Pr(UHF(k,m_1) = UHF(k,m_2), k\leftarrow K) = \mathrm{neg}\ \forall m_1,m_2 \]&lt;&#x2F;p&gt;
&lt;p&gt;First, we break the message into \( N \) blocks as before. Then, we interpret each of these blocks as a number over a large finite field (that is, every block is an element from \( {0,1,2,..,q-1} \)). We can take each of them as the coefficient of a polynomial. To build the MAC, we fix a large prime \( q \) and take two random integers \( a,b \) in \( {1,2,…q-1}\). The signing algorithm is&lt;br &#x2F;&gt;
\[ S(a,b,m) = a^{N+1} + m_{N} a^N + m_{N-1} a^{N-1} + … a_1 m_1 + b \mod{q} \]&lt;br &#x2F;&gt;
The algorithm evaluates the polynomial with coefficients given by \( m_i \) at point \( a \), adds \( b \), and reduces the result modulo \( q \) so that the tag is also an element in the finite field \( \mathbb{F}_q \).&lt;&#x2F;p&gt;
&lt;p&gt;Poly1305 is an example of such a construction and is used in combination with AES or ChaCha20 (we will soon see why we need to combine them) to provide a fast MAC, used, for example, by Google, to secure HTTPS connections. In particular, Poly1305 breaks the messages into blocks of 16 bytes, interpreting each as a 129-bit number in little-endian form by appending an additional bit to each block. The modulus is \(q = 2^{130}-5 \), and the final result is reduced by taking the remainder by \( 2^{128} \).&lt;&#x2F;p&gt;
&lt;p&gt;The problem with one-time MACs is that we can authenticate only one message. An attacker can easily break the scheme to obtain both \( a \) and \( b \). Note that if the attacker submits a message where each \( m_i=0 \), then \( S(a,b,m)=b \). Then, he can send the message \( m_1=1,m_i=0\ \forall \ i&amp;gt;1 \) and get \( S(a,b,m)=b+a \mod{q} \) and recover \( a \). We can solve this problem by improving the construction and incorporating a pseudo-random function.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;carter-wegman-mac&quot;&gt;Carter-Wegman MAC&lt;&#x2F;h2&gt;
&lt;p&gt;The Carter-Wegman MAC combines a PRF with a one-time MAC. If \( F:K_F\times {0,1}^n \rightarrow {0,1}^n\) is the pseudo-random function and \( S(k_S,m) \) is a secure one-time MAC, the Carter-Wegman MAC is calculated as follows: Pick at random \( r \) in \( {0,1}^n \) and calculate&lt;br &#x2F;&gt;
\[ CW(k_F,k_S,m)=(r,F(k_F,r)\oplus S(k_S,m)) \]&lt;br &#x2F;&gt;
The input to the pseudo-random function is small, and even though \( F \) can be slower than \( S \), it will be computed very fast. We leave the message to the one-time MAC, which can deal efficiently even with large messages.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;hmac&quot;&gt;HMAC&lt;&#x2F;h2&gt;
&lt;p&gt;To construct HMAC we need a key, \( k \), inner and outer paddings, \( \mathrm{ipad,opad} \) and a secure cryptographic hash function \( H:{0,1}^\star\rightarrow {0,1}^n \). The signing algorithm is&lt;br &#x2F;&gt;
\[ S(k,m)=H(k\oplus \mathrm{opad},H(k\oplus \mathrm{ipad},m)) \]&lt;br &#x2F;&gt;
The pseudo-random function masks the only weakness of the UHF by XORing the result of the UHF with a strongly random output from the PFR.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;timing-attacks-on-tag-verification&quot;&gt;Timing attacks on tag verification&lt;&#x2F;h2&gt;
&lt;p&gt;MAC verification can be subject to bugs or attacks if not done correctly. One standard attack against poorly implemented MAC verification schemes is timing attacks. In the verification, the verifier takes the key, \( k \), and the message \( m \), computes the authentication tag \( t^\prime \), and compares the received tag \( t \). One naïve way to do this is by performing a byte by byte comparison,&lt;br &#x2F;&gt;
\[ t^\prime[i] == t[i]\]&lt;br &#x2F;&gt;
The problem with checking this way is that, as soon as two bytes differ, for example, byte number 3, an attacker can be sure that the first two bytes are correct. The attacker can try different values for the third byte and measure the time it takes to verify. If it increases, he knows he got right at least another byte. The process can continue until he exhausts the number of bytes in the tag, getting the valid tag \( t \) for a message \( m \), being able to produce an existential forgery. Therefore, the lesson is to ensure the verification is performed in constant time so that no information is leaked from the tag.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;need-to-change-the-key&quot;&gt;Need to change the key&lt;&#x2F;h2&gt;
&lt;p&gt;To be secure, the MAC needs to be long enough. If not, they could be subjected to brute force attacks. We can find bounds for the number of messages we can MAC before changing keys. For example, in CBC-MAC, which outputs tags in \( \{0,1 \}^n \), if the adversary can query \( q \) messages of length \( \ell \), then we need that&lt;br &#x2F;&gt;
\[ \frac{q^2 \ell^2 }{ 2^n } \ll 1\]&lt;br &#x2F;&gt;
This means that \( q\ell \ll 2^n \). If we use AES where \( n=128 \) and we consider that \( 2^{-32}\approx 2\times 10^{-10}\) to be sufficiently small, then \( q\ell \leq 2^{48} \). Given that 1 GB of data is \( 2^{30} \) bytes, we can encrypt several messages containing up to several GB before changing the key.&lt;&#x2F;p&gt;
&lt;p&gt;In the case of HMAC with SHA-256, we have \( n=256 \), and the amount of messages we can tag before reaching the limit is \( q \ll 2^{256&#x2F;2} \), which, for our case, could be something like \( 2^{100}\approx 10^{30} \)&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;Encryption schemes, such as AES or ChaCha20, offer confidentiality but cannot ensure the authenticity of messages nor that an attacker has not modified them. The lack of authenticity can lead to devastating attacks and break cryptographic schemes. Message authentication codes (MAC) provide ways to ensure the integrity of the message, which we can combine with encryption schemes to provide authenticated encryption. To be secure, MACs need to satisfy existential unforgeability under chosen message attacks; given a new message \( m \), an attacker should not be able to generate a valid authentication tag \( t \), even if he has access to other valid pairs \( m_i,t_i \). MAC can be obtained from pseudo-random functions (such as hash functions or block ciphers, like AES) or universal hash functions, each offering advantages and disadvantages in terms of speed, size, processing in parallel, etc.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Symmetric encryption</title>
          <pubDate>Tue, 17 Jan 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/symmetric-encryption/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/symmetric-encryption/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/symmetric-encryption/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;Encryption has been the main application of cryptography for a very long time. Its goal is to transform a message into another one and send it through an insecure channel, such that only the intended parties (who know all the elements necessary to reverse the transformation) can read it while looking like absolute nonsense to everybody else. For example, suppose that you are a general during a war, and you need to communicate the battle plan to your reinforcement battalions (which are still far from you) and launch a surprise attack at the precise moment. If you sent some messenger with an unencrypted letter containing the plans, then anyone reading the letter would know your strategy and act in consequence. Besides, the messenger could betray you, exchange that information with your enemies, and thwart your masterminded tactic.&lt;&#x2F;p&gt;
&lt;p&gt;Encryption uses an algorithm called cipher and some key to change the message into a random-looking text. More precisely, it takes a plaintext and outputs a ciphertext through some mathematical computations. The cyphertext can only be decrypted if the key is known. In modern encryption, only the key is secret; the details of the encryption algorithm are publicly known. This construction is in accordance with Kerkhoff’s principle, which states that, in a cryptographic system, only the key should be secret. In older times, people tried to hide the message by using unknown algorithms or strategies, hoping that the enemy would not be able to figure out the secret; we call this security through obscurity. Needless to point out, this strategy has failed numerous times with catastrophic consequences.&lt;&#x2F;p&gt;
&lt;p&gt;Symmetric encryption is widely used today, and there are efficient algorithms, some even implemented on hardware. Examples of symmetric encryption algorithms are AES (Advanced Encryption Standard), 3DES, ChaCha, Salsa, Twofish, Blowfish, and Serpent. In this type of encryption, we use the same key to encrypt and decrypt messages (therefore, if someone can send encrypted messages, he can decrypt them as well). We will see in a later chapter that there is asymmetric encryption (or public key cryptography), where we have two different keys: a public key (used to encrypt messages) and a private key (used to decrypt).&lt;&#x2F;p&gt;
&lt;p&gt;Once we have the key, we can send secure messages between the parties. It is unlikely that unwanted parties will decrypt them, thanks to the math and heuristics behind it and the appropriate security levels. However, we find ourselves with the problem of agreeing on the key between the involved parties. If we tried sending it in plaintext over an insecure channel, it could be compromised, and the symmetric encryption would be pointless since adversaries could have obtained it. We will focus in a later post on how to perform key exchanges.&lt;&#x2F;p&gt;
&lt;p&gt;There are two main ciphers types for symmetric encryption: block and stream ciphers. We will analyze their characteristics in the following sections.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;formalization&quot;&gt;Formalization&lt;&#x2F;h2&gt;
&lt;p&gt;We have two parties wanting to communicate securely, which we will call Alice and Bob (for A and B, respectively). Alice wants to send Bob a plaintext, \( P \), so that only Bob can read it and learn its contents. They have previously agreed on a common secret key, \( k \), and they will use some algorithm, such as AES. The encryption algorithm is some function, $E$, taking they plaintext and the key and outputting the ciphertext \( C \):&lt;br &#x2F;&gt;
\[ E(P,k)=C \]&lt;br &#x2F;&gt;
The decryption algorithm, \( D \), on the other hand, takes the ciphertext and the key and returns the plaintext&lt;br &#x2F;&gt;
\[ D(C,k)=P \]&lt;&#x2F;p&gt;
&lt;p&gt;We want some things from our encryption algorithm and the output ciphertext. First, the ciphertext should appear as a random text with no clear patterns. We would also like that if we change even a single bit from the message, the resulting ciphertext is utterly different from the original one: We call this the avalanche effect.&lt;&#x2F;p&gt;
&lt;p&gt;These are related to two properties that a secure cipher should have: confusion and diffusion. Confusion serves to hide the relationship between the key and the ciphertext. Diffusion is related to the fact that the value in the ciphertext of one bit depends on others; equivalently, if we changed one bit from the plaintext, we could expect that many bits would also change their values, which is related to the avalanche effect.&lt;&#x2F;p&gt;
&lt;p&gt;A cipher’s permutation should satisfy the following three conditions to be secure:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The key should determine the permutation.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Different keys should give rise to different permutations.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The permutations should look random.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The first condition guarantees that we need the key to be able to decrypt. If the key does not determine the permutations, it plays no role in the process, and anyone could decrypt things without it. The second one means that no two keys yield the same permutation. If it were so, then we could decrypt the messages encrypted with one key with another, and that would make it easier to break the cryptosystem. The third one implies that we should not be able to learn anything about the plaintext from the ciphertext (an example where this fails is on some bitmaps with ECB mode encryption).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;information-versus-computational-security&quot;&gt;Information versus Computational security.&lt;&#x2F;h2&gt;
&lt;p&gt;One important key is related to the security proofs of our cryptographic schemes. In some cases, one can prove that specific methods are mathematically secure, even if the attacker has unbounded computational power. These schemes are known as information-theoretically secure. However, we need to introduce some assumptions to build practical cryptographical schemes. Modern cryptographic algorithms can be proven computationally secure, where the adversary has bounded computing power and can break the system only after spending a lot of time or resources, even with the fastest and most powerful devices available nowadays.&lt;&#x2F;p&gt;
&lt;p&gt;Instead of perfect security, computational security relies on the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Security is preserved only against efficient adversaries.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Adversaries can succeed, but only with negligible probability.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can consider our schemes secure for practical purposes if we have sufficiently reasonable bounds for computational power and the probability of success is small enough.&lt;&#x2F;p&gt;
&lt;p&gt;There are two common approaches to analyzing the security of our cryptographic protocols:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Concrete.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Asymptotic.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In the concrete case, we bound the probability of success, \( \epsilon \), after the attacker has spent time \(t \). We say that the scheme is \( (t,\epsilon) \)-secure if an adversary spending time \(t \) has a probability of success of at most \( \epsilon \).&lt;&#x2F;p&gt;
&lt;p&gt;The asymptotic approach is related to complexity theory. It views the running time of the attacker and his success probability as functions of a security parameter, \( \lambda \) (for example, the secret key size). It only guarantees security provided \( \lambda \) is sufficiently large.&lt;&#x2F;p&gt;
&lt;p&gt;We say an algorithm is efficient if its running time is polynomial in \( \lambda \), that is \( c_1 \lambda^{c_2} \) for some numbers \( c_1 \) and \( c_2\). We can also write this in big O notation, \( \lambda^{c_2}\).&lt;&#x2F;p&gt;
&lt;p&gt;As for the probability of success, we consider them to be small if it is smaller than any inverse polynomial in \( \lambda \). More precisely, for every constant \( c \), the attacker’s success probability is smaller than the inverse polynomial in \( \lambda \), \( \lambda^{-c}\). A function growing slower than any inverse polynomial is called negligible.&lt;&#x2F;p&gt;
&lt;p&gt;A scheme is secure if every probabilistic, polynomial-time attacker succeeds in breaking it with only negligible probability.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bit-operations-exclusive-or-xor&quot;&gt;Bit operations: exclusive OR (XOR)&lt;&#x2F;h2&gt;
&lt;p&gt;One operation frequently used in cryptography is the exclusive OR operator (XOR). It is a binary operation, taking two bits and outputting another; we will represent the operation with the \( \oplus \) symbol. Its truth table is:&lt;br &#x2F;&gt;
\( 0\oplus 0=0\)&lt;br &#x2F;&gt;
\( 0\oplus 1=1\)&lt;br &#x2F;&gt;
\( 1\oplus 0=1\)&lt;br &#x2F;&gt;
\( 1\oplus 1=0\)&lt;&#x2F;p&gt;
&lt;p&gt;We can also view the XOR operation as an addition modulo \( 2 \):&lt;br &#x2F;&gt;
\( 0+0\equiv 0 \pmod{2}\)&lt;br &#x2F;&gt;
\( 1+0\equiv 1 \pmod{2}\)&lt;br &#x2F;&gt;
\( 1+1\equiv 0 \pmod{2}\)&lt;br &#x2F;&gt;
These results are expected: adding two odd or two even numbers is always even, whereas adding one odd and one even number is always odd.&lt;&#x2F;p&gt;
&lt;p&gt;Why is this operation helpful? Suppose we want to encrypt a message given as a sequence of bits. One way to encrypt it is to generate a sequence of (pseudo) random bits and XOR each bit to get the ciphertext. An attacker can try to decipher the text, but he finds the following problem:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * If he sees \\( 0 \\) in the ciphertext, it could be because the plaintext had \\( 1 \\) and the random bit was also \\( 1 \\), or both were zero. So, he has a \\( 50 % \\) chance of guessing correctly!&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * If he sees \\( 1 \\) in the ciphertext, either the plaintext is \\(1 \\) and the random bit is \\( 0 \\) or the other way round. Again, he has a \\( 50 % \\) chance of guessing correctly.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If the message is composed of several bytes (for example, 16 bytes - 128 bits), the probability of guessing the correct message is \( 3\times 10^{-39} \)!&lt;&#x2F;p&gt;
&lt;p&gt;We see that the XOR operation is hard to reverse unless we know one of the original inputs. In that case, if \( c=m\oplus r\), then&lt;br &#x2F;&gt;
\[ m=c\oplus r\]&lt;&#x2F;p&gt;
&lt;h2 id=&quot;stream-and-block-ciphers&quot;&gt;Stream and Block ciphers&lt;&#x2F;h2&gt;
&lt;p&gt;A block cipher takes a message of fixed length (128 bits, for example) and encrypts it by performing some random permutation of its elements. Two values characterize the block cipher: the block size (for example, 16 bytes -128 bits-) and the key size. Both determine the level of security of the cipher. This cipher does not operate with individual bits but with fixed-sized blocks.&lt;&#x2F;p&gt;
&lt;p&gt;Block sizes must be neither very large nor very small. In the first case, it can impact the cost and performance of the encryption since the memory footprint and ciphertext length will be significant. However, if the block size is small, it is susceptible to a codebook attack.&lt;&#x2F;p&gt;
&lt;p&gt;In practice, a block cipher is the repetitive application of permutation and substitution steps; these take place in rounds. The main building blocks are:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Substitution boxes (S-boxes).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Mixing permutations.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Key schedule.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If we call \(f_k \) the function corresponding to round \( k \), the ciphertext is&lt;br &#x2F;&gt;
\[ C= f_n(f_{n-1}(…f_2(f_1(P))))\]&lt;&#x2F;p&gt;
&lt;p&gt;The round functions have the same operations but are parametrized by a different key (which leads to other substitutions and permutations). We should not use the same key for all steps; otherwise, our cryptosystem can be vulnerable to slide attacks.&lt;&#x2F;p&gt;
&lt;p&gt;Decryption is the successive application of the inverse functions \( g_k=f_k^{-1}\),&lt;br &#x2F;&gt;
\[ P=g_1(g_2(…g_{n-1}(g_n(C))))\]&lt;&#x2F;p&gt;
&lt;p&gt;Stream ciphers work very differently; instead of combining blocks of text and the key, they deterministically generate a sequence of “random” bits (called the keystream) from the key and perform XOR operations with the text.&lt;&#x2F;p&gt;
&lt;p&gt;The keystream, \( KS \), is derived from the secret key \( k \) and a public nonce \( \mathrm{nonce} \). If we have our message, \( \mathrm{m} \) to encrypt we perform \( C=KS \oplus \mathrm{m} \). To decrypt, we simply XOR again, \( \mathrm{m}=KS\oplus C\). We can easily see that the encrypt and decrypt operations are essentially the same; we only need the keystream to be able to do it. It is important that \( \mathrm{nonce} \), which need not be secret, is never reused. To see why, suppose we have two messages \( \mathrm{m}_1 \) and \( \mathrm{m}_2\), and their corresponding ciphertexts, which have been encrypted using the same key \( k \) and \( \mathrm{nonce} \). We can recover the message \( \mathrm{m}_1 \) using the following operation:&lt;br &#x2F;&gt;
\[ \mathrm{m}_1=C_2\oplus C_1 \oplus \mathrm{m}_2 \]&lt;&#x2F;p&gt;
&lt;p&gt;The above was an implementation error that Microsoft Excel and Word had: they reused the same nonce, which meant that decryption could be done if two versions of the same file were available.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;encryption-algorithms&quot;&gt;Encryption algorithms&lt;&#x2F;h2&gt;
&lt;p&gt;In the following sections, we will cover the basics of each type of cipher, analyzing two commonly used ones. We will start with AES (a block cipher), the most widely used cipher nowadays, and ChaCha (a stream cipher), commonly used in android systems in the form of ChaCha20-Poly1305.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;aes&quot;&gt;AES&lt;&#x2F;h2&gt;
&lt;p&gt;The Advanced Encryption Standard (AES) resulted from an open competition organized by NIST in 1997 that lasted for three years. The proposal by Rijmen and Daemen was nominated as the winner and was standardized in 2001 by NIST. We implemented AES and its arithmetization for use in zero-knowledge proofs &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;AES_zero_knowledge_proof_circuit&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;AES offers three levels of security: AES-128, AES-192, and AES-256, with key sizes of 16, 24, and 32 bytes, respectively. As the key’s size increases, so does security. However, for most applications, AES-128 provides sufficient security levels (the best-known attacks against AES are only slightly better than brute-force attacks, which would require \( 2^{128} \) operations).&lt;&#x2F;p&gt;
&lt;p&gt;AES is a block cipher: it takes a 16-byte block (128 bits) and the variable length key and outputs a 16-byte ciphertext. If the text has less than 16 bytes, it is conveniently padded. After performing decryption, it should be possible to eliminate the padding to recover the message; therefore, we cannot use random padding because we cannot distinguish the original message from the random bits.&lt;&#x2F;p&gt;
&lt;p&gt;Remember that block ciphers are permutations: they map all the possible plaintexts into all possible ciphertexts.&lt;&#x2F;p&gt;
&lt;p&gt;The cipher sees the plaintext as a \( 4\times 4 \) matrix of bytes. AES has a round function, which is applied several times to the plaintext, scrambling and mixing everything well until we obtain the ciphertext. Each round uses a different key (which is generated in a deterministic way from the secret key), making the slightest changes in the bits of the secret key result in an entirely different encryption. The steps in each round function (except in the last one) are:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * SubBytes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * ShiftRows&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * MixColumns&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * AddRoundKey&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The first three are easily reversible, but the last one is not: it performs an XOR operation between the text and the round key. However, all the steps are necessary to achieve the desired security levels.&lt;&#x2F;p&gt;
&lt;p&gt;AES uses ten rounds to perform encryption. All steps contain the four operations, except for the first (only the round key is added) and the 10th (MixColumns is omitted).&lt;&#x2F;p&gt;
&lt;p&gt;SubBytes (also called substitution boxes) provide the substitution step and is a nonlinear function. Given that we encrypt blocks of 16 bytes, we can do the substitution with the aid of lookup tables.&lt;&#x2F;p&gt;
&lt;p&gt;In ShiftRows and MixColumns, the bytes of the columns&#x2F;rows are moved.&lt;&#x2F;p&gt;
&lt;p&gt;The key schedule function is called to generate the keys for each round: all the keys are derived from the secret key, using the substitution boxes and XOR operations. One drawback of this key scheduling is that if an attacker learns one of the keys, he can reverse the algorithm and discover all other keys, including the secret key.&lt;&#x2F;p&gt;
&lt;p&gt;Why do we need all these operations to have a secure cipher?&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The MixColumns and ShiftRows guarantee that all the elements are &amp;quot;well mixed&amp;quot;. If one of them is missing, then we could break the cipher into smaller blocks and perform a codebook search over \\( 2^{32} \\) possibilities, which is far better than \\( 2^{128} \\).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * SubBytes gives the nonlinear part to the cipher. Without it, all the operations are linear and easier to reverse.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * AddRoundKey makes the ciphertext depend on the key. If we skip this step, we don&amp;#39;t need any key to decipher.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The key schedule prevents us from reusing the same key all the time, making the cipher vulnerable to slide attacks.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When we want to encrypt a message bigger than the block size, we can divide it into blocks of 16 bytes and pad the last one, if necessary. This simple approach is known as the electronic codebook mode (ECB) and should not be used. As encryption is deterministic, we will get the same ciphertext every time we encrypt a given plaintext. This is problematic when we have, for example, an image with repetitive patterns or large areas of one color since the ciphertext will exhibit those patterns too. There are several modes that we can use to avoid this problem:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Cipher block chaining (CBC)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Propagating cipher block chaining (PCBC)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Cipher Feedback (CFB)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Output feedback (OFB)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Counter (CTR)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For example, in the CBC mode:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Initialize a 16-byte random vector (IV),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Perform \\( \tilde{B}_1=IV \oplus B_1 \\), where \\( B_1 \\) is the first block and set \\( k=1 \\).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Use AES to encrypt \\( E_1= \tilde{B}_1 \\).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Perform \\( \tilde{B_{k+1}}=E_k \oplus B_{k+1} \\)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. Use AES to encrypt \\( E_{k+1}= \tilde{B_{k+1}} \\) and do \\( k=k+1 \\)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    6. If \\( k \neq k_{max} \\), go to step 4. Otherwise, it is the end of the encryption.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The IV guarantees that the resulting ciphertext will be different even if the same plaintext is encrypted.&lt;&#x2F;p&gt;
&lt;p&gt;Another problem we face is that, even though the message has been encrypted, we cannot know whether an attacker has modified it. To prevent modification of the ciphertext, we can add message authentication codes (MAC), which we will cover in another post.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;chacha20&quot;&gt;ChaCha20&lt;&#x2F;h2&gt;
&lt;p&gt;ChaCha20 is a modification of the Salsa20 cipher, invented by Daniel J. Bernstein in 2005. Its working principle is the same as all stream ciphers: it generates a keystream from the secret key and encrypts by performing an XOR operation between the plaintext and the keystream.&lt;&#x2F;p&gt;
&lt;p&gt;ChaCha20 generates the keystream by repeatedly calling a block function that outputs 64 bytes of keystream. It takes as input:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * 256-bit key.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * 96-bit nonce.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * 32-bit counter.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Every time the function outputs 64 bytes of the keystream, the counter is increased by one, and the process continues until the keystream is larger than the plaintext; then, we truncate it to the plaintext length, and we perform an XOR operation. The maximum size we can encrypt is given by the total value of the counter, \( 2^{32} \), and the output of each round, 64 bytes, yielding a maximum of \( 2^{32}\times 64=256 \) GB.&lt;&#x2F;p&gt;
&lt;p&gt;The core operation is the Quarter Round. It takes 4 32-bit unsigned integers, denoted \( a,b,c \) and \(d \) and performs the following operations:&lt;br &#x2F;&gt;
\( a=a+b;\space d=d\oplus a;\space d&amp;lt;&amp;lt;&amp;lt;16\)&lt;br &#x2F;&gt;
\( c=c+d;\space b=b\oplus c;\space b&amp;lt;&amp;lt;&amp;lt;12\)&lt;br &#x2F;&gt;
\( a=a+b;\space d=d\oplus a;\space d&amp;lt;&amp;lt;&amp;lt;8\)&lt;br &#x2F;&gt;
\( c=c+b;\space b=b\oplus c;\space b&amp;lt;&amp;lt;&amp;lt;7\)&lt;br &#x2F;&gt;
where \( &amp;lt;&amp;lt;&amp;lt;n \) denotes an \( n \)-bit rotation towards the left.&lt;&#x2F;p&gt;
&lt;p&gt;The ChaCha state comprises 16 32-bit words: the first four are constants; the next eight correspond to the key, followed by the counter and the nonce.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;Symmetric encryption is one of the most widely used encryption schemes nowadays; it also provides tools upon which we can build hash functions. We can classify symmetric ciphers into two big groups: block (like AES) and stream ciphers (like Chacha20). Both provide confidentiality by scrambling and substituting the message. In a subsequent post, we will deal with how parties can agree on a key over an insecure channel.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Arithmetization schemes for ZK-SNARKs</title>
          <pubDate>Sat, 14 Jan 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/arithmetization-schemes-for-zk-snarks/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/arithmetization-schemes-for-zk-snarks/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/arithmetization-schemes-for-zk-snarks/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;Zero-knowledge proofs (ZKP) are gaining ground thanks to their many applications in delegating computations to untrusted servers and solving the scalability issues that decentralized ledgers suffer from. ZKP allow us to prove a given computation’s validity without revealing sensitive data. One of the key advantages is that the proof is short (succinct), and its verification time is much faster than the naïve re-execution of the computation. We can exploit this in decentralized ledgers, where each node must check the correctness of the transactions. Here, the weakest devices act as bottlenecks. If we can now verify the validity of a transaction by checking a small proof (taking a few milliseconds), then the scalability problems begin to fade away. We can also make proofs showing that we executed thousands of transactions or operations by using recursive proof composition, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.entropy1729.com&#x2F;proof-aggregation-schemes-snarkpack-and-aplonk&#x2F;&quot;&gt;proof aggregation&lt;&#x2F;a&gt;, or &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.entropy1729.com&#x2F;incrementally-verifiable-computation-nova&#x2F;&quot;&gt;folding schemes&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;To prove the validity of the computation and avoid revealing sensitive information, ZKP rely on polynomials and their properties. Polynomials are expressions of the form \( a_0+a_1x+a_2x2+a_3x3+…a_n x^n \), where the coefficients \( a_k \) are elements of some &lt;a href=&quot;&#x2F;math-survival-kit-for-developers&#x2F;&quot;&gt;ring or field&lt;&#x2F;a&gt; (for example, integers, real numbers or members of a finite field, like \( \mathbb{Z}&#x2F;7\mathbb{Z}\), the integers modulo 7). Now, to be able to use polynomials, we have to be able to express our computations in terms of them by a process known as arithmetization.&lt;&#x2F;p&gt;
&lt;p&gt;Arithmetization reduces computed statements to algebraic statements involving polynomials of a bounded degree. Arithmetization can be divided into two categories:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Circuit computations. Most SNARKs use this.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Machines computations. STARKs use this approach.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Circuit computations are better for unstructured computations and support composability with relative ease. On the other hand, machine computations are better for uniform computations and support unbounded computations.&lt;&#x2F;p&gt;
&lt;p&gt;Some operations can be easily transformed into arithmetic operations, either because they are algebraic operations over a finite field or because we can translate them with some slight changes into those. This leads to a shift in thought about what is an expensive or straightforward computation. For example, stream ciphers are efficient encryption schemes, performing XOR operations between the plaintext (the message we want to encrypt) and a keystream (a pseudorandom string of bits), which the processor can calculate very fast. However, in terms of their arithmetization and the number of equations we need to describe them (that is, the number of constraints), they are expensive operations for SNARKs. Examples of costly operations for SNARKs are bitwise operations (AND, XOR, OR), bound checks, and comparisons (because these require breaking the variable into bits).&lt;&#x2F;p&gt;
&lt;p&gt;The arithmetization adds significant overhead to the computation time. There can be nearly two orders of magnitude increase in computation time using SNARK-friendly operations and more for non-friendly operations.&lt;&#x2F;p&gt;
&lt;p&gt;Recently, many different optimizations have been presented to reduce the overhead, such as:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Lookup tables.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * SNARK-friendly cryptographic primitives (such as [Rescue](https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2020&#x2F;1143.pdf), [SAVER](https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2019&#x2F;1270.pdf) or [Poseidon](https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2019&#x2F;458)).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Concurrent proof generation.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Hardware acceleration (such as using GPU or FPGA).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In general, arithmetization cannot be done manually except for elementary programs. Besides, the use of naïve arithmetization can lead to significant overhead. To deal with this, dedicated compilers accepting high-level programming languages have been developed, as well as zero-knowledge virtual machines, such as CAIRO. We will examine the most popular schemes, R1CS, AIR, and plonkish arithmetization.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;r1cs&quot;&gt;R1CS&lt;&#x2F;h2&gt;
&lt;p&gt;Arithmetic circuits can be expressed as (quadratic) rank one constraint systems (R1CS). These are systems of equations, each at most quadratic in each variable, of the form&lt;br &#x2F;&gt;
\[ (\sum_k A_{ik} z_k)(\sum_k B_{ik}z_k)-(\sum_k C_{ik}z_k)=0 \]&lt;br &#x2F;&gt;
where \( A_{ik}, B_{ik}, C_{ik} \) are elements in some finite field \( \mathbb{F} \), with many of them zero. We can write down any complex computation in this way. For example, if we want to calculate \( w=x^4 \) we can express this as&lt;br &#x2F;&gt;
\( x\times x= w_1 \)&lt;br &#x2F;&gt;
\( w_1 \times w_1=w \)&lt;br &#x2F;&gt;
where we have introduced an additional variable, \( w_1 \), which we have to decide whether it will be a public or private variable. It is important to see that R1CS for describing a given computation are not unique. For example, we could have expressed the previous computation as&lt;br &#x2F;&gt;
\( x\times x= w_1 \)&lt;br &#x2F;&gt;
\( x\times w_1= w_2 \)&lt;br &#x2F;&gt;
\( x\times w_2= w \)&lt;br &#x2F;&gt;
This system is equivalent to the previous one but has one more constraint.&lt;&#x2F;p&gt;
&lt;p&gt;To implement R1CS, programs have gadgets, allowing one to construct arithmetic circuits modularly. For example, if we want to work with a boolean variable, we can have a gadget implementing the constraints, such that the variable only takes the values 0 or 1. If we call the variable \( b \), then&lt;br &#x2F;&gt;
\( b(1-b)= 0 \)&lt;br &#x2F;&gt;
If we want to perform an OR operation between \( a \) and \( b \), then the boolean gadget implements also&lt;br &#x2F;&gt;
\( a(1-a)=0 \)&lt;br &#x2F;&gt;
while the OR gadget adds&lt;br &#x2F;&gt;
\( a+b-ab=c \)&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;arkworks-rs&#x2F;snark&#x2F;tree&#x2F;master&#x2F;relations&#x2F;src&quot;&gt;Arkworks&lt;&#x2F;a&gt; library contains gadgets for basic data types and operations. Common expressions for operators and range checks can be found in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;zips.z.cash&#x2F;protocol&#x2F;protocol.pdf&quot;&gt;Zcash protocol specification&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;algebraic-intermediate-representation-air&quot;&gt;Algebraic intermediate representation (AIR)&lt;&#x2F;h2&gt;
&lt;p&gt;Algebraic Intermediate Representation (AIR) is the arithmetization procedure used by StarkWare in their virtual machine, CAIRO (CPU AIR). The AIR consists of the three following elements:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. The execution trace of the computation. This is expressed as a trace execution matrix, \\( T \\), whose rows represent the computation state at a given time point and whose columns correspond to an algebraic register tracked over all the computation steps.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Transition constraints enforce the relations between two or more rows of the trace matrix \\( T \\).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Boundary constraints enforce equalities between some cells of the execution and constant values.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The arithmetization takes place in two stages:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Generating the execution trace and the low-degree polynomial constraints.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Transforming the previous two into a single univariate polynomial.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The set of polynomial constraints is constructed so that they are all verified if and only if the execution trace is valid (that is if the trace represents a valid computation). The constraints are low-degree polynomials but are not necessarily restricted to degree \( 2 \), as in the case of R1CS.&lt;&#x2F;p&gt;
&lt;p&gt;To see how AIR works, let us look at a few examples. Suppose that we want to add all the elements in a given vector of size \( n \), \( a=(a_1,a_2,a_3,…,a_n) \). We could introduce a variable \( t \) starting at \( 0 \) and which at each step adds the value of one of the components of \( a \). The trace matrix contains two columns; the first one is given by the elements of \( a \) and the partial sums in \( t \)&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Row&lt;&#x2F;th&gt;&lt;th&gt;\( a \)&lt;&#x2F;th&gt;&lt;th&gt;\( t \)&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;\( a_1 \)&lt;&#x2F;td&gt;&lt;td&gt;\( 0 \)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;\( a_2 \)&lt;&#x2F;td&gt;&lt;td&gt;\( a_1 \)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;\( a_3 \)&lt;&#x2F;td&gt;&lt;td&gt;\( a_1+a_2 \)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;\( a_4 \)&lt;&#x2F;td&gt;&lt;td&gt;\( a_1+a_2+a_3 \)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;\( \vdots \)&lt;&#x2F;td&gt;&lt;td&gt;\( \vdots \)&lt;&#x2F;td&gt;&lt;td&gt;\( \vdots \)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;n&lt;&#x2F;td&gt;&lt;td&gt;\( a_n \)&lt;&#x2F;td&gt;&lt;td&gt;\( \sum_k^{n-1} a_k \)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;n+1&lt;&#x2F;td&gt;&lt;td&gt;\( \sum_k a_k \)&lt;&#x2F;td&gt;&lt;td&gt;\( \sum_k a_k \)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;The following polynomial constraints can summarize the correctness of the computation:&lt;br &#x2F;&gt;
\( t_1=0 \)&lt;br &#x2F;&gt;
\( t_{j+1}-t_j-a_j=0 \) for \( j=1,2,…n \)&lt;br &#x2F;&gt;
\( a_{n+1}-t_{n+1}=0 \)&lt;&#x2F;p&gt;
&lt;p&gt;The advantage, in this case, is that the polynomial equations are not constrained to degree two or less. Multiplicative inverses, \( x^{-1} \), such that \( x \times x^{-1}=1 \) can be written down in two equivalent forms:&lt;br &#x2F;&gt;
\( x^{p-2}=y \)&lt;br &#x2F;&gt;
\( x\times y -1 =0 \)&lt;br &#x2F;&gt;
The first expression uses Fermat’s little theorem and involves a gate of degree \( p-2 \), while the second has degree 2.&lt;&#x2F;p&gt;
&lt;p&gt;The procedure for AIR as used in STARKs follows these steps:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Get the execution trace.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Perform low-degree extension.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Evaluate constraints.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Compose constraints into the compositional polynomial.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The low-degree extension works as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Take each register (each column of the execution trace matrix) as evaluations of some polynomial, \\( f \\).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Interpolate the \\( f \\) over the trace domain to find its coefficients.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Evaluate \\( f \\) over a larger domain.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The easiest way to work our way around is by using the number theoretic transform (this is the finite field version of the fast Fourier transform). We need to select a finite field such that it contains the n-th roots of unity, \( w_k \), such that \( w_k^n=1 \) and \( n \) is a power of 2 (\( n=2^m \)) larger than the number of rows. To obtain all the n-th roots, we can take powers of a generator, \( \omega \), \( \omega^0=1, \omega=w_1, \omega^2=w_2,…\), etc. To perform a low-degree extension, we can increase the domain by adding the 2n-th roots of unity and take advantage of our previous evaluations (or 4n-th roots of unity, leading to a 4x blowup).&lt;&#x2F;p&gt;
&lt;p&gt;To evaluate the constraints,&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Define the algebraic relations between rows.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Reinterpret these relations as polynomials with roots at the points where the conditions hold.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Divide out roots from constraint polynomials to convert them into rational constraints.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For example, if we have some relation between the rows, such as&lt;br &#x2F;&gt;
\( r_{k+2} = r_{k+1}^2+2r_{k} \)&lt;br &#x2F;&gt;
we can interpret this as some polynomial \( f \) and associate each step with \( x_k=\omega^k \), so&lt;br &#x2F;&gt;
\( f(x \omega^2)=(f(x \omega)^2+2 f(x)) \)&lt;br &#x2F;&gt;
The polynomial&lt;br &#x2F;&gt;
\( p(x)=f(x \omega^2)-(f(x \omega)^2+2 f(x)) \)&lt;br &#x2F;&gt;
has roots at the points \( x \) where the relation \( f \) holds.&lt;br &#x2F;&gt;
We can then take out the roots by dividing them by&lt;br &#x2F;&gt;
\( d(x)=\prod_k (x-\omega_k) \)&lt;br &#x2F;&gt;
where the product is carried out only over the values of \( k \) where the constraint holds. We get the required polynomial,&lt;br &#x2F;&gt;
\[ g(x)=\frac{p(x)}{d(x)} \]&lt;br &#x2F;&gt;
The following identity gives a practical result,&lt;br &#x2F;&gt;
\[ \prod_{k=0}^{n-1} (x-\omega^k) = x^n-1 \]&lt;br &#x2F;&gt;
So, if we know that the constraint holds on most \( \omega^k \), \( d(x) \) can be computed efficiently using that identity. For example, if \(n=256 \) and it holds for all rows, except \( k=128, 194 \), then&lt;br &#x2F;&gt;
\[ d(x) = \frac{x^n-1 }{(x-\omega^{128}) (x-\omega^{194}) }\]&lt;&#x2F;p&gt;
&lt;p&gt;For our previous relationship&lt;br &#x2F;&gt;
\( r_{k+2} = r_{k+1}^2+2r_{k} \)&lt;br &#x2F;&gt;
say that \( r_1=1, r_2=5 \) and we want to calculate until \( r=1000 \). We will use \( n=1024 \) because this is the smallest power of \( 2 \) larger than \( 1000 \). In addition to the constraints being valid for all points from \( 3 \) to \( 1000 \), we also have constraints for the two initial values:&lt;br &#x2F;&gt;
\( f(\omega^0)=1=f(1) \)&lt;br &#x2F;&gt;
\( f(\omega)=5 \)&lt;br &#x2F;&gt;
Therefore, we get some additional polynomials (if the conditions do hold):&lt;br &#x2F;&gt;
\[ p_1(x)=\frac{f(x)-1}{x-1} \]&lt;br &#x2F;&gt;
\[ p_2(x)=\frac{f(x)-5}{x-\omega} \]&lt;br &#x2F;&gt;
\[ p_3(x)=\frac{f(x \omega^2)-(f(x \omega)^2+2 f(x))}{d_3(x)} \]&lt;br &#x2F;&gt;
where&lt;br &#x2F;&gt;
\[ d_3(x) = \frac{x^{1024}-1 }{(x-1 )(x-\omega) \prod_{k = 1001}{1023}(x-\omegak) } \]&lt;br &#x2F;&gt;
We can finally obtain the compositional polynomial by taking a random linear combination of \( p_1,p_2,p_3 \):&lt;br &#x2F;&gt;
\[ P(x)=\alpha_1 p_1+\alpha_2 p_2+\alpha_3 p_3\]&lt;&#x2F;p&gt;
&lt;h2 id=&quot;plonkish-arithmetization&quot;&gt;Plonkish arithmetization&lt;&#x2F;h2&gt;
&lt;p&gt;The arithmetization used by Plonk is known as randomized algebraic intermediate representation with preprocessing (RAP, for short). TurboPlonk and UltraPlonk are restricted cases of RAP. As before, our starting point is the execution trace matrix, \( T \), consisting of \( n \) rows and \( w \) columns.&lt;&#x2F;p&gt;
&lt;p&gt;Plonk’s constraint system is written (considering two fan-in gates) as&lt;br &#x2F;&gt;
\[ q_L x_a+q_R x_b+q_O x_C+q_M x_a x_b +q_C=0 \]&lt;&#x2F;p&gt;
&lt;p&gt;This can represent the operations found in R1CS and allows for the implementation of custom gates. Plonk’s original arithmetization scheme consisted in encoding the computation trace into polynomials, for which we had to check the correctness of the wiring, that the polynomial encodes the inputs correctly, that every gate is evaluated correctly, and the output of the last gate.&lt;&#x2F;p&gt;
&lt;p&gt;A preprocessed AIR (PAIR) extends the execution trace by adding new columns, \( c_1,c_2,…c_m \) so that the new columns will participate in the constraints. These variables allow us to change the relationship between different rows in the trace matrix. For example, we could alternate the relationship between even and odd rows, performing different operations. For example, we might want to have the following:&lt;br &#x2F;&gt;
\( x_{2n} = x_{2n-1}^2 \)&lt;br &#x2F;&gt;
\( x_{2n+1} = 2\times x_{2n} \)&lt;br &#x2F;&gt;
We can encode this relationship by doing&lt;br &#x2F;&gt;
\( c_1(x_n-x_{n-1}^2)+(1-c_1)(x_n-2x_{n-1}) \)&lt;br &#x2F;&gt;
where \( c_1=1 \) in even rows and \( c_1=0 \) in odd rows. Because we can use them to choose the operation we want to perform, they are called selectors. We can use more selectors to describe complex operations, such as elliptic curve addition.&lt;&#x2F;p&gt;
&lt;p&gt;We can use the grand product check to check that two vectors \( a,b \) are permutations of each other. Given a random \( \gamma \) in the finite field \( \mathbb{F} \), the following equality should hold:&lt;br &#x2F;&gt;
\[ \prod (a_i+\gamma) = \prod (b_i+\gamma)\]&lt;br &#x2F;&gt;
Due to the Schartz-Zippel lemma, we know that the probability that two polynomials are equal at a randomly sampled value is less than \( 1-d&#x2F;\vert \mathbb{F} \vert \), where \( d \) is the degree of the polynomial and \( \vert \mathbb{F} \vert \) is the number of elements of the finite field.&lt;&#x2F;p&gt;
&lt;p&gt;To check that this operation has been carried out correctly, we can introduce one additional variable, \( v \), such that&lt;br &#x2F;&gt;
\( v_1=1 \)&lt;br &#x2F;&gt;
\( v_k=v_{k-1}\times (a_{k-1}+\gamma)&#x2F;(b_{k-1}+\gamma) \) for \( k={2,n+1} \)&lt;br &#x2F;&gt;
If the last value, \( v_{n+1} \), is equal to one, then we know, with very high probability, that the columns \( a,b \) are permutations of each other.&lt;&#x2F;p&gt;
&lt;p&gt;Plonk allows one to include lookup arguments. These help us check that a given operation between two variables \( a,b \) yielding output \( c \) is correct by looking inside a table with precomputed valid \( (a,b,c) \). To do so, we need to incorporate a table \( t \) where the rows give all possible input&#x2F;output combinations. For example, we can take \( a,b \) be 8-bit strings and provide the results of the XOR operation, \( c=a\oplus b \). This gives a total of \( 2^{16} \) combinations. To check that the result is correct, we can use a random variable, \( \beta \), and compute \( f_k=a_k+\beta b_k+\beta^2 c_k \) and \( g_k=t_{k1}+\beta t_{k2}+\beta^2 t_{k3} \), where \( t_{ki} \) are the elements of the table. We will cover these kinds of arguments in an upcoming post.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;One of the critical steps in the generation of zk-SNARKs for verifiable computation is transforming a given computer program into polynomials. This process is known as arithmetization, and we have some schemes to do it efficiently, such as R1CS, AIR, and Plonkish arithmetization. In the first one, we need gadgets to implement the data types (such as boolean, u8, and i64 variables) and their associated operations. In the case of AIR and Plonkish, we need to get the execution trace of the program, establish the relationship between the rows and interpolate polynomials. Both approaches need to be carefully implemented, as naïve ways to do so can lead to a greater number of constraints and significant overhead. Fortunately, the development of new SNARK-friendly primitives, lookup arguments, custom gates, and hardware acceleration (such as the use of GPU and FPGA) can reduce either the arithmetic complexity or increase the speed at which calculations are performed and enable shorter proving and verifying times, open the doors for many new and exciting applications in the real world.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>How to transform code into arithmetic circuits</title>
          <pubDate>Sat, 14 Jan 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/how-to-transform-code-into-arithmetic-circuits/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/how-to-transform-code-into-arithmetic-circuits/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/how-to-transform-code-into-arithmetic-circuits/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;The use of efficient &lt;a href=&quot;&#x2F;the-hunting-of-the-zk-snark&#x2F;&quot;&gt;zk-SNARKs&lt;&#x2F;a&gt; (zero-knowledge succinct non-interactive arguments of knowledge) has given rise to many new and vital applications. For example, we can &lt;a href=&quot;&#x2F;decentralized-private-computations-zexe-and-veri-zexe&#x2F;&quot;&gt;delegate expensive computations&lt;&#x2F;a&gt; to untrusted servers and receive proof showing the integrity of the computations. This proof is short and can be verified much faster than the naïve approach of re-executing the whole calculation. How can this be possible? The key idea is that the integrity of the computation can be expressed as the solution or satisfiability of a non-deterministic polynomial (NP)-complete problem. Before we explain what NP-complete means, let’s look at an example. When you write down code in a high-level language, the compiler transforms it into machine code. It is then executed in the processor, which has dedicated circuits for performing the necessary operations. We can express any complex computation in the form of some circuit. The idea with SNARKs is that we can transform the code into an arithmetic circuit made of operations such as the addition and multiplication of integers and prove the correctness of the execution by checking that the values involved in the calculation satisfy the circuit.&lt;&#x2F;p&gt;
&lt;p&gt;An NP-complete problem is such that:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * We can verify its solution in polynomial time. We can always find the answer by executing a brute-force search over all possibilities. These conditions correspond to the class NP.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * We can use the problem to simulate any other in the NP class.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Examples of NP-complete problems are circuit satisfiability, the graph coloring problem, and the traveling salesman problem.&lt;&#x2F;p&gt;
&lt;p&gt;We don’t want to write down the circuit corresponding to a program every time we want to code something. Doing this would be like writing code in assembly language or machine code instead of using a higher-level language. To do so, we need to construct a dedicated compiler, which reads our code and transforms it into an arithmetic circuit. We will see that some operations lead to a straightforward representation as arithmetic circuits (such as the addition or multiplication of integers). In contrast, other simple functions, such as XOR, AND, or equality checks, have a more complex structure.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;arithmetic-circuits&quot;&gt;Arithmetic circuits&lt;&#x2F;h2&gt;
&lt;p&gt;An arithmetic circuit is a directed acyclic graph involving the multiplication and addition of numbers. We can think of it as evaluating some polynomial over those numbers. For example, the following circuit expresses the calculation of the following polynomial, \( p(x) = x^3 + x^2 + 1 \)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;ruVa3AS.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;br &#x2F;&gt;
We can also have circuits taking different values and representing a multivariate polynomial, such as \( p(x_1,x_2) = x_1 x_2 + x_1 + x_2^2\).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;Ky9wLuo.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Arithmetic circuits can also be expressed as rank one constraint system, such that there is a one-to-one correspondence between them.&lt;&#x2F;p&gt;
&lt;p&gt;As we mentioned, the only operations we have are addition and multiplication; operations such as division have to be simulated. For example, if we want to perform&lt;br &#x2F;&gt;
\[ a&#x2F;b=c\]&lt;br &#x2F;&gt;
we can introduce an additional variable (the multiplicative inverse of \( b \), that is, \( b^{-1}\)),&lt;br &#x2F;&gt;
\(x\times b=1 \)&lt;br &#x2F;&gt;
\(a\times x=c \)&lt;br &#x2F;&gt;
The first condition ensures that \( x \) is \( b^{-1} \), and the second performs the calculation we wanted. The arithmetic circuit would look like&lt;br &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;TrjZGXD.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;br &#x2F;&gt;
We could have also worked this by remembering that the multiplicative inverse of an integer (using modular arithmetic) is \( b^{-1 } = b^{p-2} \) . However, this leads to a more complex circuit since we would have to evaluate, in general, a large power, which needs many multiplication gates, even if done efficiently (of the order of \( \log(p) \)). Therefore, when trying to express a non-native operation over arithmetic circuits, we must think about the most efficient way.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;r1cs&quot;&gt;R1CS&lt;&#x2F;h2&gt;
&lt;p&gt;A (quadratic) rank-one constrain system is a system of equations of the form:&lt;br &#x2F;&gt;
\( \left(a_{01}+\sum a_{k1} x_k\right)\left(b_{01}+\sum b_{k1} x_k\right)=\left(c_{01}+\sum c_{k1} x_k\right) \)&lt;br &#x2F;&gt;
\( \left(a_{02}+\sum a_{k2} x_k\right)\left(b_{02}+\sum b_{k2} x_k\right)=\left(c_{02}+\sum c_{k2} x_k\right) \)&lt;br &#x2F;&gt;
\( \left(a_{0n}+\sum a_{kn} x_k\right)\left(b_{0n}+\sum b_{kn} x_k\right)=\left(c_{0n}+\sum c_{kn} x_k\right) \)&lt;&#x2F;p&gt;
&lt;p&gt;The number \( n \) gives the total number of constraints in the system. We can show that any bounded computation can be expressed as an R1CS. What happens if we want to perform computations involving something like \( y^5 \)? We can use a simple approach known as flattening. We introduce new variables for the intermediate computations:&lt;br &#x2F;&gt;
\( y\times y=y_1=y^2\)&lt;br &#x2F;&gt;
\( y\times y_1=y_2=y^3 \)&lt;br &#x2F;&gt;
\( y_1 \times y_2= y_3=y^5 \)&lt;br &#x2F;&gt;
For this simple calculation, the vector \( x \) is simply \( x=(y,y_1,y_2,y_3) \). Most of the elements \( a_{ij},b_{ij},c_{ij} \) are zero. The non-zero elements are \( a_{11},b_{11},c_{11},a_{12},b_{22},c_{32},a_{23},b_{33},c_{34}\), which are all equal to one. We could also express the R1CS as&lt;br &#x2F;&gt;
\(y\times y=y_1 \)&lt;br &#x2F;&gt;
\(y_1\times y_1=y_2 \)&lt;br &#x2F;&gt;
\(y\times y_2=y_3 \)&lt;br &#x2F;&gt;
Both represent the same calculation, but the constraints look a bit different. Therefore, there can be multiple representations for a given problem.&lt;&#x2F;p&gt;
&lt;p&gt;R1CS keeps track of the values involved in the calculation and the relationships between the variables. We have a deciding function to check whether or not a given assignment of the variables \( x \) satisfies the R1CS. We have to replace the values of \( x \) into the system of equations and see that the right and left-hand sides are equal. Equivalently,&lt;br &#x2F;&gt;
\( \left(a_{01}+\sum a_{k1} x_k\right)\left(b_{01}+\sum b_{k1} x_k\right)-\left(c_{01}+\sum c_{k1} x_k\right)=0 \)&lt;br &#x2F;&gt;
\( \left(a_{02}+\sum a_{k2} x_k\right)\left(b_{02}+\sum b_{k2} x_k\right)-\left(c_{02}+\sum c_{k2} x_k\right)=0 \)&lt;br &#x2F;&gt;
\( \left(a_{0n}+\sum a_{kn} x_k\right)\left(b_{0n}+\sum b_{kn} x_k\right)-\left(c_{0n}+\sum c_{kn} x_k\right)=0 \)&lt;&#x2F;p&gt;
&lt;p&gt;One advantage of R1CS stems from its modularity. If we have two systems of constraints, \( CS_1, CS_2 \), we can obtain a new one \( CS_3 \) which has to satisfy both systems.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;compilers&quot;&gt;Compilers&lt;&#x2F;h2&gt;
&lt;p&gt;We have seen that circuits and R1CS have a modularity property, allowing us to derive more complex circuits or systems of equations by combining simpler ones. We can leverage this by developing a compiler that generates the circuits&#x2F;constraints associated with each data type and associated operations.&lt;&#x2F;p&gt;
&lt;p&gt;The native elements for arithmetic circuits are the &lt;a href=&quot;&#x2F;math-survival-kit-for-developers&#x2F;&quot;&gt;field elements&lt;&#x2F;a&gt;, that is, \( 0,1,2,3,…p \), which we can also interpret as \( -p&#x2F;2+1,-p&#x2F;2+2,…,0,1,2,…p&#x2F;2 \) and the operations \( + \) and \( \times \). Data types such as &lt;code&gt;u8&lt;&#x2F;code&gt;, &lt;code&gt;u16&lt;&#x2F;code&gt;, &lt;code&gt;u64&lt;&#x2F;code&gt;, and &lt;code&gt;i128&lt;&#x2F;code&gt; are not and have to satisfy specific properties. Likewise, we have to express their operations in terms of arithmetic circuits. For example, &lt;code&gt;u16&lt;&#x2F;code&gt; is an integer value between 0 and 65535, much smaller than the field elements’ range. If we want such a data type, we must perform a range check to ensure that the value is between 0 and 65535. This condition adds overhead since we have to add constraints to the circuit associated with the range check.&lt;&#x2F;p&gt;
&lt;p&gt;Boolean variables also face similar problems. In ordinary circuits, a boolean is directly associated with one bit, and operations between bits have been optimized for performance. If we want to represent a boolean variable, which takes as values only 0 and 1, we have to add constraints to enforce these values. One simple way to ensure this is by having the variable \( b \) satisfy the following equation&lt;br &#x2F;&gt;
\( b(1-b)=0\)&lt;br &#x2F;&gt;
The arithmetic circuit associated with this equation is shown below and displays three gates: two multiplications and one addition.&lt;br &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;qGxf87H.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If we want to calculate \( c= \neg b \), we need to know how to represent NOT in circuit form first. The following equation can represent this&lt;br &#x2F;&gt;
\[ c=1-b \]&lt;br &#x2F;&gt;
The circuit representation is,&lt;br &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;CeoYeMi.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;br &#x2F;&gt;
If we do a naïve pasting of both circuits, we get&lt;br &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;4z3zqbU.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;br &#x2F;&gt;
We see that there are a lot of repeated elements (such as \(1, -1, -b\). In a later stage, we could optimize the circuit not to introduce redundant elements or computations, as these only increase the proving time.&lt;&#x2F;p&gt;
&lt;p&gt;Suppose we want to represent an integer \( k \) in its bit representation (say &lt;code&gt;u16&lt;&#x2F;code&gt;). In that case, we have 16 bits, \( b_k \), each of which has the same circuit (meaning we have 32 multiplication and 16 addition gates), plus additional checks showing the following:&lt;br &#x2F;&gt;
\[ k=\sum_{j=0}^{15} 2^jb_j \]&lt;br &#x2F;&gt;
A simple gate does not represent bitwise operations, such as AND, XOR, and NOT. If we want to perform in a naïve way \(a \oplus b \) (performing an XOR operation between two bitstrings, which is something you would typically do in a &lt;a href=&quot;&#x2F;symmetric-encryption&#x2F;&quot;&gt;stream cipher&lt;&#x2F;a&gt; such as ChaCha20), we need to represent the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Each bitstring.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The check that those bits represent \\( a,b \\)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The circuits for each XOR operation.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can use two solutions to avoid this shortcoming. First, instead of trying to represent each non-arithmetic operation by a combination of field operations, we can create tables that show the relations between input and outputs and check the validity of the computation by looking that the combination is in the table. For example, we could store the results of XORing all 8-bit strings in a table and then use a lookup argument to check. This way, we can reduce the number of constraints, reducing the degree of the resulting polynomials and leading to faster proof generation times.&lt;&#x2F;p&gt;
&lt;p&gt;The second solution is to use new cryptographic functions which are SNARK-friendly. We can say that SNARK-friendly primitives have a simple representation as arithmetic circuits (few constraints can represent them); they usually try to use the native operations in the field. Examples of SNARK-friendly hash functions are Poseidon and Rescue.&lt;&#x2F;p&gt;
&lt;p&gt;Circuit compilers work in phases. In the first phase, the compiler starts with the main function. It begins by replacing functions with their corresponding circuits and adding the necessary variables and the circuits associated with their data types. In the second phase, the input variables are replaced by their actual values and all the intermediate results, getting a solution to the system of constraints.&lt;&#x2F;p&gt;
&lt;p&gt;To translate code into arithmetic circuits, we can implement gadgets. These are simply elements that give the behavior of one of the building blocks of a computational problem. For example, we can implement a gadget to test the equality of two integers or one which performs the concatenation of two strings. Given the modularity property, we can glue everything together and obtain the large circuit. For example, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;arkworks-rs&quot;&gt;Arkworks&lt;&#x2F;a&gt; gives tools to transform code into R1CS using gadgets.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;The integrity of a given computation can be expressed as the satisfiability or solution of an NP-complete problem, such as arithmetic circuit satisfiability. To that end, we transform the entire computation into an arithmetic circuit, where the native elements are field elements (instead of bits), and the addition and multiplication of field elements are the natural operations in the circuit. We can equivalently express circuits as constraint systems, such as R1CS. Given the modularity property of circuits and R1CS, we can leave the transformation of code into circuits to a dedicated compiler, which takes every data type and its operations and transforms it into circuit form. All non-native data types and their operations have to be defined in terms of the native elements and operations, which makes certain operations, such as bitwise AND, XOR, NOT expensive. This translation, in turn, makes well-established cryptographic primitives expensive for zk-SNARKs, as each function adds many constraints. The development of new, SNARK-friendly primitives and lookup tables can help reduce the complexity of the circuit representation and speed up proof generation.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Decentralized private computation: ZEXE and VERI-ZEXE</title>
          <pubDate>Fri, 13 Jan 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/decentralized-private-computations-zexe-and-veri-zexe/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/decentralized-private-computations-zexe-and-veri-zexe/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/decentralized-private-computations-zexe-and-veri-zexe/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;The &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2018&#x2F;962.pdf&quot;&gt;ZEXE&lt;&#x2F;a&gt; (Zero-knowledge EXEcution) protocol appeared in 2018, introducing the cryptographic primitive of decentralized private computation (DPC). It aims to solve two main drawbacks that decentralized ledgers suffer: privacy and scalability.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s take the examples of Bitcoin and Ethereum. We see that the history of all transactions is public (which could leak sensitive information on your company’s suppliers, acquaintances, or the services you hire). Ethereum offers programmability but requires each node to execute every operation, where the least powerful device acts as a bottleneck. ZCash tackles the privacy problem but does not offer programmability, just private transactions. ZEXE tries to get the best of both worlds:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Privately running arbitrary programs.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Being able to run computations offline.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Providing proof of the integrity of the computations, which nodes can verify quickly.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For an overview of the protocol, we recommend our previous post on &lt;a href=&quot;&#x2F;fully-private-applications-a-zexe-protocol&#x2F;&quot;&gt;ZEXE&lt;&#x2F;a&gt;. As a quick reminder, the protocol offers the following features:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Programmability: we can run arbitrary programs.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Fast verification: we can prove the validity of our computations by using zk-SNARKs (zero-knowledge Succinct Non-interactive ARguments of Knowledge), which offer short (succinct) proofs that verifiers can check on-chain in a few milliseconds.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Data and function privacy: the protocol hides relevant input information and functions when we execute transitions in the ledger.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The ZEXE protocol has seen several improvements since its introduction to enhance its performance. This post will analyze the differences between the original protocol and a recent proposal, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2022&#x2F;802.pdf&quot;&gt;VERI-ZEXE&lt;&#x2F;a&gt;. The authors of VERI-ZEXE compared their protocol’s performance with the original proposal of ZEXE and its early modifications. There are no comparisons between the current improved versions of the ZEXE protocol and VERI-ZEXE.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;building-blocks&quot;&gt;Building blocks&lt;&#x2F;h2&gt;
&lt;p&gt;We mentioned that the ZEXE protocol uses zk-SNARKs, which allow us to provide proofs of integrity for given computations, which anyone can verify much faster than the naïve approach of re-execution. The highest cost of the system is related to the generation of the proof, which relies on elliptic curve operations. You can look at the basics of some SNARK systems in &lt;a href=&quot;&#x2F;the-hunting-of-the-zk-snark&#x2F;&quot;&gt;our previous post&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Modern proof systems have two main building blocks: a polynomial interactive oracle proof -PIOP- (which transforms a given computation into polynomial equations) and a polynomial commitment scheme -PCS-. We get different proving systems depending on our choices, each of which has advantages and disadvantages. Some examples of PIOPs are Marlin, PLONK (Permutations over Lagrange-bases for Oecumenical Noninteractive arguments of Knowledge) -and all its derivates- and Spartan. Among the PCS, we have KZG (Kate-Zarevucha-Goldberg), FRI (Fast Reed-Solomon Interactive Oracle Proofs of Proximity), Bulletproofs, and DARK (Diophantine ARgument of Knowledge), to name a few.&lt;&#x2F;p&gt;
&lt;p&gt;To be able to perform proofs in a fast and efficient way, we need “SNARK-friendly” cryptographic primitives and operations. A function is “SNARK-friendly” if its representation as an arithmetic circuit is small. For example, intuitive and straightforward bitwise operations such as AND and XOR have a complex circuit representation. Therefore, the cost of functions in the context of SNARKs must consider the complexity of the arithmetic circuit used to represent the operation and its variables.&lt;&#x2F;p&gt;
&lt;p&gt;A great deal of the cost in SNARK systems comes from:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Multiscalar multiplication ([MSM](&#x2F;multiscalar-multiplication-strategies-and-challenges&#x2F;)). These are operations of the form \\( Q= \sum_k a_k P_k \\), where \\( a_k \\) are numbers and \\( P_k \\) are points belonging to an elliptic curve.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Elliptic curve pairings. These are used in the verification of some systems. They involve field extensions and operations between different groups of elliptic curves.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Polynomial evaluations over non-native fields.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Fiat-Shamir transform: a hash function is needed to generate the challenges. Many well-established cryptographic primitives have complicated representations as arithmetic circuits, which makes their evaluation costly.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Research efforts are attempting to solve all of these problems. GPUs or FPGA can &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.zprize.io&#x2F;prizes&#x2F;accelerating-msm-operations-on-gpu-fpga&quot;&gt;speed up the calculation of MSM&lt;&#x2F;a&gt;. New hash functions and encryption schemes with nicer arithmetic circuits can further reduce the complexity of frequently used cryptographic primitives (for example, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2019&#x2F;458.pdf&quot;&gt;Poseidon&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;tosc.iacr.org&#x2F;index.php&#x2F;ToSC&#x2F;article&#x2F;view&#x2F;8695&#x2F;8287&quot;&gt;Vision and Rescue&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;veri-zexe-s-choices&quot;&gt;VERI-ZEXE’s choices&lt;&#x2F;h2&gt;
&lt;p&gt;To tackle these problems, VERI-ZEXE changes the proving system and cryptographic primitives. Here are some of the main modifications:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * PLONK as PIOP. Over the last years, PLONK has seen several significant improvements, such as high-degree custom gates, the use of lookup tables, and the use of multilinear polynomials (which avoids using fast Fourier transform) (such as turboPLONK, ultraPLONK, and [hyperPLONK](https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2022&#x2F;1355.pdf)).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Lightweight verifier circuit via [accumulation scheme](https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2020&#x2F;499.pdf). The protocol moves out the pairing check from the SNARK circuit and delays the verification to the ledger&amp;#39;s validators.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Instance merging. When performing transactions, birth and death predicates of records have to be checked. Instead of verifying each predicate separately, the protocol leverages that the predicates can be taken in birth&#x2F;death pairs, resulting in a larger predicate. However, since the verification of the combined predicate has a simpler circuit representation (this means that the number of operations does not scale linearly), the overall cost is reduced.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Proof batching. We can generate and verify proofs in batches by exploiting the properties of some PCS, such as KZG. These allow the opening of \\( N \\) different commitments simultaneously, with a cost that does not scale linearly in the number of commitments (that is, you can open \\( N \\) commitments for less than the cost of \\( N \\) separate openings).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Variable base MSM via a lookup table. The MSM is carried out by combining Pippenger&amp;#39;s algorithm (which splits the scalars into blocks) with a [lookup table](https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2020&#x2F;315.pdf), reducing the cost of elliptic curve additions.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Polynomial evaluation over non-native fields. The circuits of the prover and the verifier lie in different finite fields. One way to deal with this was using two pairs of elliptic curves. VERI-ZEXE uses modular addition and multiplication with range check with lookup, resulting in a slightly more complicated circuit.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * SNARK-friendly symmetric primitives. Using collision-resistant hash functions, pseudorandom generators, and commitment schemes with a smaller circuit representation (which reduces the number of operations), resulting in less memory and time use. For example, the Fiat-Shamir transformation uses the sponge construction of the Rescue permutation.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The use of PLONK and its additions, together with simpler constructions for cryptographic primitives, results in a reduction of more than one order of magnitude in the total number of constraints, which in turn decreases the scale of the MSM multiplications and overall proving time.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;accumulation-schemes-as-and-incrementally-verifiable-computation-ivc&quot;&gt;Accumulation schemes (AS) and Incrementally verifiable computation (IVC)&lt;&#x2F;h2&gt;
&lt;p&gt;The verification of proofs requires the calculation of costly pairing operations. The original ZEXE protocol used incrementally verifiable computation to prove the satisfiability of user-defined predicates using SNARK recursion: given a computation at step \( N \), the prover would receive the state \( z_{N} \) and a proof \( \pi_{N-1} \) attesting to the correct execution of the previous step. The prover would then execute step \( N \) and generate a proof \( \pi_N \) which certifies that “the new state \( z^\prime \) is the result of the correct execution and that \( \pi_{N-1} \) is true (in other words, that the prover did the \( N-1 \) previous steps correctly)”. In this last step, the computational burden comes in: to check the proof, the verifier’s computation is embedded inside the prover’s circuit, which slows down the proof’s generation.&lt;&#x2F;p&gt;
&lt;p&gt;An accumulation scheme proceeds differently by delaying the verification of the final proof to the ledger’s validators. At each step of the calculation, the prover receives the current state and an accumulator, which is partially verified (the prover checks that the accumulation results are correct but does not calculate the elliptic curve pairing operation). The group elements in the accumulator must be masked using a randomizer, which acts as an additional witness (secret input) for the accumulator’s verifier. This masking ensures that the accumulator does not leak information on the computations being carried out,&lt;&#x2F;p&gt;
&lt;h2 id=&quot;lookup-tables-and-efficient-modular-operations&quot;&gt;Lookup tables and efficient modular operations&lt;&#x2F;h2&gt;
&lt;p&gt;Using lookup tables for elliptic curve addition in the Pippenger algorithm and efficient operations for modular arithmetic reduces the number of PLONK constraints by a factor of 6.&lt;&#x2F;p&gt;
&lt;p&gt;The idea behind lookup tables for MSM is as follows:&lt;br &#x2F;&gt;
\[ Q= \sum_i a_i P_i \]&lt;br &#x2F;&gt;
The Pippenger algorithm splits the scalars \( a_i \) into \( m \) windows of length \( c \) (For example, a scalar is a 256-bit number, and we choose a window of 8-bits). We can write each scalar as&lt;br &#x2F;&gt;
\[ a_i= \sum_j a_{ij}2^{mj}\]&lt;br &#x2F;&gt;
where each \( a_{ij} \) is in the range \( {0,1,…,2^c-1} \). We can compute, for each point \( P_i \) all possible combinations of scalars values \( 2P_i,3P_i,4P_i,…,(2^c-1)P_i\).&lt;&#x2F;p&gt;
&lt;p&gt;We can now calculate the result \( Q_{ij}=a_{ij}P_i\) by looking at the table (which has a more straightforward description than pure elliptic curve operations) and get the results of the j-th bucket,&lt;br &#x2F;&gt;
\[ B_j = \sum_i Q_{ij} \]&lt;br &#x2F;&gt;
We can get the final result by finally adding over the \( m \) buckets,&lt;br &#x2F;&gt;
\[ Q=\sum_j B_j 2^{cj}\]&lt;&#x2F;p&gt;
&lt;h2 id=&quot;further-improvements-from-hyperplonk&quot;&gt;Further improvements from HyperPlonk?&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;xymqID7.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;VERI-ZEXE uses PLONK with lookup tables, resulting in fewer constraints and shorter proving times. Two weeks ago, HyperPLONK came out, providing linear time prover and high-degree custom gates. One of the key changes is the shift from univariate polynomials (polynomials in one variable, \(x \), such as \(a_0+a_1x+a_2x2+…a_dxd \)) to multivariate linear polynomials (polynomials in several variables, where the degree of each \( x_k \) is at most one, such as \( a_0 +a_1x_1+a_2x_2+a_{12}x_1x_2+a_{145}x_1x_4x_5 \)). This change avoids using the fast Fourier transform (FFT) for very large systems (with over \(2^{20} \) constraints), which has a superlinear cost (roughly speaking, the FFT for \( n \) points needs \( n\log(n) \) operations). Preliminary studies have shown that this new PLONK version performs better for circuits with more than 16000 constraints compared to optimized versions of the original proposal. We will cover this topic in an upcoming post.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;ZK proofs are the key to many new applications, such as decentralized finances, governance, etc. The ZEXE protocol introduced the concept of decentralized private computation, allowing users to run private applications over public ledgers. The original proposal was based on non-universal proving systems, which have efficient performance but require a new trusted setup for each program we want to run. Since then, several significant improvements in proving systems (such as Marlin and PLONK) and new “SNARK-friendly” cryptographic primitives (such as symmetric ciphers and hash functions) have been introduced, resulting in increased performance and lower computational costs. These changes allow less powerful devices to act as provers and run more complex programs.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Pinocchio Virtual Machine: Nearly Practical Verifiable Computation</title>
          <pubDate>Fri, 13 Jan 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/pinocchio-virtual-machine-nearly-practical-verifiable-computation/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/pinocchio-virtual-machine-nearly-practical-verifiable-computation/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/pinocchio-virtual-machine-nearly-practical-verifiable-computation/">&lt;p&gt;At &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;lambdaclass.com&#x2F;&quot;&gt;LambdaClass&lt;&#x2F;a&gt; we set up a small research team to work on Zero Knowledge Proofs and Fully Homomorphic Encryption, who in the past few weeks implemented a virtual machine implementing the Pinocchio protocol in Rust.&lt;&#x2F;p&gt;
&lt;p&gt;You can check out the repository at &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;pinocchio_lambda_vm&quot;&gt;lambdaclass&#x2F;pinocchio_lambda_vm&lt;&#x2F;a&gt;. It was built by Mauro Toscano, Sergio Chouhy, Agustin Garassino and Diego Kingston.&lt;&#x2F;p&gt;
&lt;p&gt;If you’re in need of a team of engineers and researchers who’ve been working together for a decade in areas like distributed systems, machine learning, compilers, and cryptography, we’re your guys. Wanna chat more about it? Book a meeting with us through &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;calendly.com&#x2F;federicocarrone&quot;&gt;calendly&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;zk-SNARKs protocols can be hard to understand for newcomers. One of the first practical implementations is called Pinocchio and it’s a very good starting point for anyone trying to get their head around them. Pinocchio’s paper can be found &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2013&#x2F;279.pdf&quot;&gt;here&lt;&#x2F;a&gt;. Having a thorough understanding of its main ideas is of great value to be able to get through the newer and more sofisticated protocols.&lt;&#x2F;p&gt;
&lt;p&gt;In this post we discuss the intuition behind its inner workings and the way it is able to provide succint proofs of circuit executions.&lt;&#x2F;p&gt;
&lt;p&gt;We know that sometimes math seems more complicated and scary than it actually is. And, very often, being able to take a look at some actual code sheds light on what’s happening. So we created a companion for this blogpost: a zero-dependency rust implementation of Pinocchio for learning purposes. You can find it at &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;pinocchio_lambda_vm&quot;&gt;lambdaclass&#x2F;pinocchio_lambda_vm&lt;&#x2F;a&gt;. We encourage you to go there if you are searching for details not covered here.&lt;&#x2F;p&gt;
&lt;p&gt;So, let’s get started!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-problem-to-solve&quot;&gt;The problem to solve&lt;&#x2F;h2&gt;
&lt;p&gt;The problem that this is trying to solve is the following: someone runs some code with a number of input values. She gets the final result of the program and wants to convince others that this value is actually the output of the execution of that program for the given inputs.&lt;&#x2F;p&gt;
&lt;p&gt;The starting point of this is a process where the program of interest is translated to “arithmetic circuits”. In the context of Pinocchio these are directed graphs where the nodes represent arithmetic operations. We’ll see now with an example.&lt;&#x2F;p&gt;
&lt;p&gt;By the way, we are not discussing here how to convert the programs to circuits. Our context is the following: someone called a “prover” wants to convince others, the “verifiers”, that she executed an arithmetic circuit and got some output values out of it. Let’s see what this all means.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;circuit-execution&quot;&gt;Circuit execution&lt;&#x2F;h2&gt;
&lt;p&gt;Throughout this post, let’s consider a variant of the example circuit from the paper as a running example. The circuit is the following:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2023&#x2F;01&#x2F;imagen.png&quot; alt=&quot;imagen&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The little squares on the top represent the input values. Choosing input values determines the output values of all the other gates. Executing the circuit means choosing some values for the input gates and filling out the rest of the values corresponding to the output of the multiplication gates. If you are wondering why we are only labeling the output of the multiplication gates, that’s normal. The answer is: it’s enough to do it this way. We’ll come back to this in a moment.&lt;&#x2F;p&gt;
&lt;p&gt;For example, suppose we are working in $\mathbb F_{p}$, for some large prime $p$. The following are two evaluations of the circuit.&lt;&#x2F;p&gt;
&lt;p&gt;Here the input values are $2$ and $3$. The output is $30$. The unique intermediate value is $6$.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2023&#x2F;01&#x2F;imagen-2.png&quot; alt=&quot;imagen-2&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Another evaluation is the following: the input values are $6$ and $4$, the output value is $240$, and the intermediate value is $24$.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2023&#x2F;01&#x2F;imagen-3.png&quot; alt=&quot;imagen-3&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;equations-that-satisfy-circuit-execution-instances&quot;&gt;Equations that satisfy circuit execution instances&lt;&#x2F;h4&gt;
&lt;p&gt;Let’s name the input values  $c_1, c_2$, the ouput value $c_3$ and the intermediate one $c_4$.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2023&#x2F;01&#x2F;imagen-5.png&quot; alt=&quot;imagen-5&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Here is a simple but important observation. It doesn’t matter which input values we choose, the resulting values will satisfy the following system of equations:&lt;br &#x2F;&gt;
$c_1c_2 = c_4$&lt;br &#x2F;&gt;
$(c_1+c_2)c_4 = c_3$&lt;br &#x2F;&gt;
Here we have one equation for every multiplication gate. Since we are not labeling the output of the addition gates, we expand them in the left and right operands of the multiplication gate. In this example, that happens only in the left operand of the second equation.&lt;br &#x2F;&gt;
Every set of values $c_1,c_2,c_3,c_4$ that satisfy those two equalities are the values corresponding to an execution instance of the program. They are the unique values corresponding to the execution of the program with input values $c_1$ and $c_2$.&lt;br &#x2F;&gt;
These equations test whether a set of values $c_1,c_2,c_3,c_4$ correspond to an execution instance.&lt;&#x2F;p&gt;
&lt;p&gt;We could have named $c_5$ the output of the addition gate and have the following larger system of equations.&lt;br &#x2F;&gt;
$c_1c_2 = c_4$&lt;br &#x2F;&gt;
$c_1+c_2 = c_5$&lt;br &#x2F;&gt;
$c_5c_4 = c_3$&lt;br &#x2F;&gt;
But it is unnecessary. And not doing so has the advantage that every equation in the resulting system of equations has the form&lt;br &#x2F;&gt;
$$(c_{i_1} + \cdots + c_{i_\alpha})(c_{j_1} + \cdots + c_{j_\beta}) = c_k$$&lt;br &#x2F;&gt;
Note that the second equation in the last system is not of this form. Having all equations of the same shape will be very convenient for the protocol. Moreover, having all the equations of that specific form will be very important, as we’ll later see. And we achieve this simply by giving variable names to the input and output values of the multiplication gates, but not addition gates. A system of equations of this form is called a Rank-1 Constraint System (R1CS).&lt;&#x2F;p&gt;
&lt;h4 id=&quot;recap&quot;&gt;Recap&lt;&#x2F;h4&gt;
&lt;p&gt;So, we started from a circuit. By choosing some input values and tracking the output values of every multiplication gate, we obtain a tuple of values $(c_1,\dots,c_N)$ that satisfy a system of equations of a specific form, called R1CS. Moreover, any solution to that system of equations corresponds to some execution of the circuit.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;naive-proof-of-execution&quot;&gt;Naive proof of execution&lt;&#x2F;h2&gt;
&lt;p&gt;In our example, if we would like to prove that we executed the circuit, we could show the values we got $c_1,c_2,c_3,c_4$. A verifier could then check that the equations hold and be sure that we executed the circuit with input values $c_1$ and $c_2$, and we got $c_3$ as a result. The problem with this is evident: the verification work is the same as executing the circuit. This is useless since we want to delegate heavy computations to untrusted servers and then have concise proof of the execution. So redoing all the work is off the table.&lt;&#x2F;p&gt;
&lt;p&gt;The idea of QAP and Pinocchio is expressing the system of equations in a more compact form as a single polynomial identity. This, together with some fundamental algebra results, will allow us to give a succinct proof of the execution. The amount of work that the verifier will have to do is always the same, regardless of the complexity of the circuit.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pinocchio-s-idea-of-proof-of-execution&quot;&gt;Pinocchio’s idea of proof of execution&lt;&#x2F;h2&gt;
&lt;p&gt;As we will see shortly, there is a very particular and circuit dependant way of constructing a polynomial $p$ out of the values $c_1, c_2, c_3, c_4$ that encodes correct executions. Meaning that $c_1,c_2,c_3,c_4$ are valid execution instance values if and only if their associated polynomial $p$ satisfies a special property. For the circuit of the example, this property is $p$ being equal to $X(X-1)h$ for some polynomial $h$. We’ll see shortly where this property comes from. So, the protocol’s idea is that the prover constructs the polynomial $p$ and convinces the verifier that there exists $h$ such that $p=X(X-1)h$.&lt;&#x2F;p&gt;
&lt;p&gt;The protocol will be something like this.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. In a setup phase a random point $s$ in $\mathbb F_p$ is chosen and the value $s(s-1)$ is precomputed.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. The prover executes the circuit with public input values $c_1$ and $c_2$ and obtains $c_3,c_4$. She constructs the polynomial $p$ out of these values and computes $h$ such that $p = X(X-1)h$. She evaluates $a = p(s)$ and $b = h(s)$ and sends $a$ and $b$ to the verifier.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. The verifier checks that $a = s(s-1)b$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We will have to address many disturbing things for this to work. For example:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. How is $p$ constructed?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Why is it enough to check that $a = s(s-1)b$ to be convinced that $p = X(X-1)h$?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. How does the verifier know that the prover followed the correct recipe to construct $p$ from the values of the circuit&amp;#39;s execution?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. How does the verifier know that $a$ and $b$ are values that come from evaluating polynomials $p$ and $h$ at $s$?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. How does the verifier know which public input values were used to execute the circuit?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    6. What&amp;#39;s stopping the prover from simply choosing $b=1$ and $a = s(s-1)$?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    7. How is this ever going to work?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To address all these questions, the protocol gets more convoluted. But the essence of it is the steps above. The rest comes into play to guarantee that no one is cheating. We’ll cover all of these questions, and in the end, we’ll obtain the actual Pinocchio protocol.&lt;&#x2F;p&gt;
&lt;p&gt;For more complex circuits, more complex polynomials $p$ are involved, and the condition $p = X(X-1)h$ is replaced with $p = X(X-1)(X-2)\cdots(X-k)h$ for a number $k$ that depends on the number of multiplication gates of the circuit. The idea is still the same. More importantly, the number of checks the verifier has to perform is independent of the circuit!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1-polynomials-to-express-correct-circuit-executions&quot;&gt;1. Polynomials to express correct circuit executions&lt;&#x2F;h2&gt;
&lt;p&gt;Let’s start by showing how we construct the polynomial $p$.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;from-families-of-polynomials-to-systems-of-equations&quot;&gt;From families of polynomials to systems of equations&lt;&#x2F;h3&gt;
&lt;p&gt;Let’s forget about our examples and circuits and start by playing around with random polynomials. Let’s take $v_1$ as&lt;br &#x2F;&gt;
$$v_1 = X, v_2 = X + 1, v_3 = X + 2$$&lt;&#x2F;p&gt;
&lt;p&gt;$w_1$ as&lt;br &#x2F;&gt;
$$w_1 = 2X + 1, w_2 = 2X + 2, w_3 = 2X + 3$$&lt;&#x2F;p&gt;
&lt;p&gt;and $y_1$ as&lt;br &#x2F;&gt;
$$y_1 = X, y_2 = -X + 1, y_3 = 0$$&lt;&#x2F;p&gt;
&lt;p&gt;Let $c_1,c_2,c_3$ be three elements of $\mathbb F_p$. Out of them, construct the following polynomial&lt;br &#x2F;&gt;
$$p = (c_1v_1 + c_2v_2 + c_3v_3)(c_1w_1 + c_2w_2 + c_3w_3) - (c_1y_1 + c_2y_2 + c_3y_3)$$&lt;br &#x2F;&gt;
We could ask ourselves the following (seemingly unrelated to anything) question: which values $c_1, c_2, c_3$ are such that $p$ has roots at $0$ and $1$? To figure it out, we can evaluate at $0$ and $1$. Precisely, $p(0) = 0$ and $p(1) = 0$ mean&lt;&#x2F;p&gt;
&lt;p&gt;$0 = p(0) = (c_2+2c_3)(c_1 + 2c_2 + 3c_3) - c_2$&lt;br &#x2F;&gt;
$0 = p(1) = (c_1 + 2c_2 + 3c_3)(3c_1 + 4c_2 + 5c_3) - c_3$&lt;&#x2F;p&gt;
&lt;p&gt;$c_1,c_2$, and $c_3$ are such that the polynomial $p$ satisfies $p(0) = 0$ and $p(1) = 0$ if and only if they solve the following system of equations&lt;&#x2F;p&gt;
&lt;p&gt;$(c_2+2c_3)(c_1 + 2c_2 + 3c_3) = c_2$&lt;br &#x2F;&gt;
$(c_1 + 2c_2 + 3c_3)(3c_1 + 4c_2 + 5c_3) = c_3$&lt;&#x2F;p&gt;
&lt;p&gt;On the other hand, the basic theory of polynomials says that $0$ and $1$ are roots of a polynomial $p$ if and only if $X(X-1)$ divides $p$. That is, if and only if there exists a polynomial $h$ such that&lt;br &#x2F;&gt;
$$p = X(X-1)h$$&lt;&#x2F;p&gt;
&lt;h4 id=&quot;takeaway&quot;&gt;Takeaway&lt;&#x2F;h4&gt;
&lt;p&gt;Wrapping up, we started from sets of polynomials $v_i, w_i, y_i$. These give a way to construct a polynomial $p$ out of any tuple $c_1,c_2,c_3$. The polynomial $p$ is divisible by $X(X-1)$ if and only if the values $c_1,c_2,c_3$ satisfy a system of equations.&lt;&#x2F;p&gt;
&lt;p&gt;This way of encoding systems of equations in a single polynomial identity is the fundamental trick to constructing succinct proofs.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;going-back-to-our-circuit&quot;&gt;Going back to our circuit&lt;&#x2F;h3&gt;
&lt;p&gt;In the previous section, we chose random polynomials. Therefore we got associated with them a system of equations that has nothing to do with our circuit. What we are going to do now is to carefully choose polynomials $v_i, w_i, y_i$, such that the system of equations associated with them is the R1CS of our circuit:&lt;&#x2F;p&gt;
&lt;p&gt;$c_1c_2 = c_4$&lt;br &#x2F;&gt;
$(c_1+c_2)c_4 = c_3$&lt;&#x2F;p&gt;
&lt;p&gt;Since we have four variables $c_1,c_2,c_3$, and $c_4$, we need four polynomials in each family. In other blogposts we will explain how to construct them using polynomial interpolation, but for now, here are the polynomials we want:&lt;&#x2F;p&gt;
&lt;p&gt;$v_1 = 1, v_2 = X, v_3 = 0, v_4 = 0$&lt;br &#x2F;&gt;
$w_1 = 0, w_2 = -X + 1, w_3 = 0, w_4 = X$&lt;br &#x2F;&gt;
$y_1 = 0, y_2 = 0, y_3 = X y_4 = -X + 1$&lt;&#x2F;p&gt;
&lt;p&gt;And for every $(c_1,c_2,c_3,c_4)$ we construct $p$ following this recipe:&lt;&#x2F;p&gt;
&lt;p&gt;$p = (c_1v_1 + c_2v_2 + c_3v_3 + c_4v_4)(c_1w_1 + c_2w_2 + c_3w_3 + c_4w_4) - (c_1y_1 + c_2y_2 + c_3y_3 + c_4y_4)$&lt;br &#x2F;&gt;
$= (c_1 + c_2X)(c_2(-X+1) + c_4X) - (c_3X + c_4(-X + 1))$&lt;&#x2F;p&gt;
&lt;p&gt;We have $p(0) = c_1c_2 - c4$ and $p(1) = (c_1+c_2)c4 - c3$. So $p$ is divisible by $X(X-1)$ if and only if&lt;&#x2F;p&gt;
&lt;p&gt;$c_1c_2 = c_4$&lt;br &#x2F;&gt;
$(c_1+c_2)c_4 = c_3$&lt;&#x2F;p&gt;
&lt;p&gt;Let’s plug in some actual values and see what $p$ looks like. Let’s start with the tuples of our execution examples. For our first example, we have $(c_1,c_2,c_3,c_4) = (2, 3, 30, 6)$. We get&lt;&#x2F;p&gt;
&lt;p&gt;$p = (2 + 3X)(3(-X+1) + 6X) - (30X + 6(-X+1))$&lt;br &#x2F;&gt;
$ = (2 + 3X)(3X + 3) - (24X + 6)$&lt;br &#x2F;&gt;
$ = 6X + 6 + 9X^2 + 9X - 24X - 6$&lt;br &#x2F;&gt;
$ = 9X^2 -9X$&lt;br &#x2F;&gt;
$ = 9X(X-1)$&lt;&#x2F;p&gt;
&lt;p&gt;For our second example, $(c_1,c_2,c_3,c_4) = (6, 4, 240, 24)$. We obtain&lt;&#x2F;p&gt;
&lt;p&gt;$p = (6 + 4X)(4(-X+1) + 24X) - (240X + 24(-X+1))$&lt;br &#x2F;&gt;
$ = (6 + 4X)(20X + 4) - (216X + 24)$&lt;br &#x2F;&gt;
$ = 120X + 24 + 80X^2 + 16X - 216X - 24$&lt;br &#x2F;&gt;
$ = 80X^2-80X$&lt;br &#x2F;&gt;
$ = 80X(X-1)$&lt;&#x2F;p&gt;
&lt;p&gt;So in both cases $p(0)=0, p(1)=0$, and consequently $p$ is divisible by $X(X-1)$.&lt;&#x2F;p&gt;
&lt;p&gt;Let us see what happens when we choose $(c_1, c_2, c_3, c_4)$ that do not correspond to an execution instance. For example, consider the polynomial $p$ associated with $c_1=1, c_2=1, c_3=0, c_4=0$. These values do not conform to an execution instance of the circuit. We get&lt;&#x2F;p&gt;
&lt;p&gt;$p = (1 + X)((-X+1) + 0X) - (0X + 0(-X+1))$&lt;br &#x2F;&gt;
$= (1 + X)(-X + 1)$&lt;&#x2F;p&gt;
&lt;p&gt;and this polynomial satisfies $p(0) = 1$, so it’s not divisible by $X(X-1)$.&lt;&#x2F;p&gt;
&lt;p&gt;Families of polynomials $v_i, w_i, y_i$ that encode circuit execution instances like this exist for any circuit.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;recap-1&quot;&gt;Recap&lt;&#x2F;h3&gt;
&lt;p&gt;The main goal is to prove the correct execution of a circuit. Showing the values we got $c_1,\dots,c_N$ is not great because the verifier has to do a lot of work to validate them. Polynomials enter here to give an alternative way of showing that information. Out of the values $c_1,\dots,c_N$ we can construct a polynomial $p$. That polynomial has a special property when the values $c_i$ correspond to a valid execution of the circuit. In our example that property is $p$ being divisible by $X(X-1)$. So this gives another way to prove correct executions:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Show that we properly constructed $p$ following the recipe for the circuit in question.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Show that $p = X(X-1)h$ for some polynomial $h$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;2-schwartz-zippel-lemma&quot;&gt;2. Schwartz-Zippel lemma&lt;&#x2F;h2&gt;
&lt;p&gt;A naive way of showing that $p = X(X-1)h$ would be to give the coefficients of $p$ to the verifier and let him divide it by $X(X-1)$ to find that such a polynomial $h$ exists. This isn’t good since the amount of work required to do that division scales with the complexity of the circuit. There is a very cheap alternative that appears in every SNARK: show that the equality $p(s) = s(s-1)h(s)$ holds for some random element $s$ in $\mathbb F_p$. The Schwarz-Zippel lemma states that this is enough to be convinced that $p = X(X-1)h$ with high probability. Let’s see why.&lt;&#x2F;p&gt;
&lt;p&gt;The key concept here is that of a &lt;em&gt;root&lt;&#x2F;em&gt; of a polynomial. A root of a polynomial $f$ is an element $r \in \mathbb F_p$ such that $f(r)=0$. A fundamental algebra theorem states that a non-zero polynomial of degree $d$ can have, at most, $d$ roots. For example, the polynomial $f = X^5 -3X + 8$ has at most $5$ roots. So if $\mathbb F_p$ has a vast number of elements and we choose a random $s$ in it, the chance of it being one of the $5$ roots of that polynomial is meager. On the other hand, the polynomial $f=0$ is the only one that satisfies $f(s)=0$ for all $s$.&lt;&#x2F;p&gt;
&lt;p&gt;Putting this all together, if $f$ is a polynomial and $f(s)=0$ for a random $s$, then with high probability, we can be sure that $f=0$.&lt;&#x2F;p&gt;
&lt;p&gt;In our case, we have $p$ and $h$ and want to convince a verifier that $p = X(X-1)h$. In other words, we have the polynomial $f = p - X(X-1)h$ and we want to convince the verifier that $f=0$. So using this approach, it’s enough to show that $0 = f(s) = p(s) - s(s-1)h(s)$ for a random $s$. This is the same as showing that $p(s) = s(s-1)h(s)$ for a random $s$.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;3-hidings&quot;&gt;3. Hidings&lt;&#x2F;h2&gt;
&lt;p&gt;So far things look a bit silly because we are working with raw elements in $\mathbb F_p$. If the prover sends the verifier $p(s)$ and $h(s)$, she sends two elements of $\mathbb F_p$. So the verifier receives two elements $a, b$ in $\mathbb F_p$ and has no idea how they were produced. Are they random? Are they actually $p(s)$ and $h(s)$? There’s no way to tell.&lt;&#x2F;p&gt;
&lt;p&gt;The solution is to work with obfuscated data that allows parties to do a minimal set of operations. The way to obfuscate is pretty simple. We will have a group $G$ and a way to associate to every element of $\mathbb F_p$ its element in $G$ in a way that’s hard to invert.&lt;&#x2F;p&gt;
&lt;p&gt;$$\mathbb F_p \longrightarrow G$$&lt;&#x2F;p&gt;
&lt;h4 id=&quot;example&quot;&gt;Example&lt;&#x2F;h4&gt;
&lt;p&gt;Let’s give an example. The number $113$ is prime, and here is a fact we’ll use: in $\mathbb Z_{454}$ the element $3$ has the property that $3^{x} \equiv 1$ modulo $454$ if and only if $n \equiv 0$ modulo $113$. This implies that $3^i \equiv 3^j$ modulo $454$ if and only if $i \equiv j$ modulo $113$.&lt;&#x2F;p&gt;
&lt;p&gt;So, we have a field $\mathbb F_{113}$, a group $G=\mathbb Z_{454}$ and the element $3\in\mathbb Z_{454}$. We can use all of this to &lt;strong&gt;hide&lt;&#x2F;strong&gt; elements of $\mathbb F_{113}$ in $\mathbb Z_{454}$ as follows: the hiding of an element $x\in\mathbb F_{113}$ is $3^x$ modulo $454$.&lt;&#x2F;p&gt;
&lt;p&gt;$\mathbb F_{113} \longrightarrow \mathbb Z_{454}$&lt;br &#x2F;&gt;
$x \mapsto 3^x$&lt;&#x2F;p&gt;
&lt;p&gt;Here are some examples:&lt;&#x2F;p&gt;
&lt;p&gt;$1 \mapsto 3$&lt;br &#x2F;&gt;
$9 \mapsto 161$&lt;br &#x2F;&gt;
$10 \mapsto 29$&lt;br &#x2F;&gt;
$90 \mapsto 65$&lt;&#x2F;p&gt;
&lt;p&gt;Suppose someone chooses a random $s \in \mathbb F_{113}$, computes $3^s$ modulo $454$, and publishes the result. Say the result is $225$. So we know that $3^s \equiv 225$ modulo $454$. It’s tough to find out what $s$ is without going through all the possibilities. The brute force attack works here because numbers are small. For larger fields and groups, this becomes infeasible. Assume that’s the case for this toy example too. Say there’s no way for us to obtain the value of $s$.&lt;&#x2F;p&gt;
&lt;p&gt;Now, even though we don’t know $s$, we can compute other hidings off the hiding $3^s$. For example, we know that $3^s = 225$, so&lt;&#x2F;p&gt;
&lt;p&gt;$3^{10s} = 225^{10} = 343$&lt;&#x2F;p&gt;
&lt;p&gt;So, even if we only know the hiding of $s$, we can compute the hiding of $10s$. Moreover we can compute the hiding of $as + b$ for any $a,b$ in $\mathbb F_{113}$: $3^{as+b} = 3^{s a \cdot3^b} = 225^{a \cdot3^b}$. For example&lt;&#x2F;p&gt;
&lt;p&gt;$s \mapsto 225$&lt;br &#x2F;&gt;
$10s \mapsto 343$&lt;br &#x2F;&gt;
$3s+2 \mapsto 155$&lt;&#x2F;p&gt;
&lt;h4 id=&quot;in-general&quot;&gt;In general&lt;&#x2F;h4&gt;
&lt;p&gt;The actual group $G$ where hidings live is not that important now. The example above should give a feel of what they look like. But, from now on, we’ll assume we have a way to compute hidings. And we’ll denote the hiding of an element $x\in\mathbb F_p$ by $E(x)$. In the examples $E(s) = 225$, $E(10s) = 343$.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;checking-equations-on-hidings&quot;&gt;Checking equations on hidings&lt;&#x2F;h3&gt;
&lt;p&gt;We just saw that if we have the hiding $E(s)$ of an unknown element $s$, we can compute the hiding of $as+b$ for any $a$ and $b$. More generally if we have hidings $E(s)$ and $E(t)$, we can compute the hiding of $as + bt$ as&lt;br &#x2F;&gt;
$$E(as+bt) = E(s)^a E(t)^b.$$&lt;br &#x2F;&gt;
This is because we have $E(s)$, $E(t)$, and the rest involves group operations with those two elements. What we can’t do is compute $E(st)$, the hiding of $st$, without knowing the raw values $s$ and $t$.&lt;&#x2F;p&gt;
&lt;p&gt;That’s sad, but it’s not the end of the world. We can get away with it without that. We will need an algorithm that helps us check relations on the original values when we have only their hidings. Precisely, we’ll need an algorithm $\mathcal A$ that takes $5$ hidings $E(a), E(b), E(c), E(t), E(d)$ and outputs $1$ if $ab - c = td$, and outputs $0$ otherwise. And the beauty of it is that it won’t reveal what the raw values $a,b,c,t,d$ are.&lt;&#x2F;p&gt;
&lt;p&gt;The actual algorithm $\mathcal A$ is something we need to sweep under the rug. The important thing is that such algorithms exist for some groups $G$, especially for elliptic curves. We suggest leaving this as a black box for now.&lt;&#x2F;p&gt;
&lt;p&gt;Note that $\mathcal A(E(a), E(b), E(c), E(0), E(0))$ outputs $1$ if and only if $ab=c$. This will also be useful! Since we’ll use this version a lot, we’ll call it the algorithm $\mathcal B$. So $\mathcal B$ takes $3$ hidings $E(a)$, $E(b)$ and $E(c)$ and outputs 1 if and only if $c = ab$.&lt;&#x2F;p&gt;
&lt;p&gt;For example, using the hidings from the previous section,&lt;br &#x2F;&gt;
$$\mathcal B(161, 29, 65) = 1.$$&lt;&#x2F;p&gt;
&lt;h4 id=&quot;ok-but-why&quot;&gt;Ok, but why?&lt;&#x2F;h4&gt;
&lt;p&gt;Recall that the formula to construct $p$ from values $c_1,c_2,c_3,c_4$ is&lt;&#x2F;p&gt;
&lt;p&gt;$$p = vw - y,$$&lt;&#x2F;p&gt;
&lt;p&gt;where $v = c_1v_1 + c_2v_2 + c_3v_3 + c_4v_4$, $w = c_1w_1 + c_2w_2 + c_3w_3 + c_4w_4$ and $y=c_1y_1 + c_2y_2 + c_3y_3 + c_4y_4$. And if the prover did everything right, she’ll be able to find a polynomial $h$ such that $p = X(X-1)h$.&lt;&#x2F;p&gt;
&lt;p&gt;So the idea is that the prover sends $E(v(s))$, $E(w(s))$, $E(y(s))$ and $E(h(s))$ for some unknown value $s$. Then the verifier, who is going to have $E(s(s-1))$, can use algorithm $\mathcal A$ to check that $v(s)w(s) - y(s) = s(s-1)h(s)$. This is exactly $p(s) = s(s-1)h(s)$, the thing we wanted.&lt;&#x2F;p&gt;
&lt;p&gt;Sending the hidings of $v(s)$, $w(s)$, and $y(s)$ instead of the hiding of $p(s)$ has the advantage that recipes for constructing $v, w$ and $y$ are way much easier than the recipe to build $p$. They are linear combinations of the base polynomials $v_i, w_i, y_i$. And, as we’ll see now, there’s a way to prove we correctly constructed those polynomials in the land of hidings.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;recap-2&quot;&gt;Recap&lt;&#x2F;h4&gt;
&lt;p&gt;Instead of raw values, the prover and verifier will have to work with hidings. The setup phase will produce enough hidings so the prover can compute the values it needs to show to the verifier. And that will be enough for him to be convinced that the prover properly executed the circuit. And with some tricks, we can guarantee that the prover can’t cheat.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;4-intuition-on-how-to-prove-correct-constructions-of-polynomials&quot;&gt;4. Intuition on how to prove correct constructions of polynomials&lt;&#x2F;h2&gt;
&lt;p&gt;Let’s start addressing the third question: how does the verifier know that the prover followed the correct recipe to construct a polynomial?&lt;&#x2F;p&gt;
&lt;p&gt;What follows is an intuition on how the protocol solves this issue. Why do we say it is an intuition? Well, it has gaps. We’ll discuss the actual security proofs in other blogposts.&lt;&#x2F;p&gt;
&lt;p&gt;See for yourself if you can spot the gaps!&lt;&#x2F;p&gt;
&lt;h4 id=&quot;proving-correct-construction-of-v&quot;&gt;Proving correct construction of $v$&lt;&#x2F;h4&gt;
&lt;p&gt;Let’s start with $v$. What we want is to somehow send $E(v(s))$ to the verifier along with some redundant information that proves that $v(s) = c_1v_1(s) + c_2v_2(s) + c_3v_3(s) + c_4v_4(s)$. But without giving away the values $c_1,c_2,c_3,c_4$.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s go back to our example. We have $v_1,v_2,v_3,v_4$. And assume there was a setup phase in which random $s$ and $\alpha$ were sampled from $\mathbb F_p$, and the following evaluation and verification keys were publicly published&lt;br &#x2F;&gt;
Evaluation key:&lt;&#x2F;p&gt;
&lt;p&gt;$E(v_1(s)), E(v_2(s)), E(v_3(s)), E(v_4(s)),$&lt;br &#x2F;&gt;
$E(\alpha v_1(s)), E(\alpha v_2(s)), E(\alpha v_3(s)), E(\alpha v_4(s)).$&lt;&#x2F;p&gt;
&lt;p&gt;Verification Key:&lt;&#x2F;p&gt;
&lt;p&gt;$$E(\alpha)$$&lt;&#x2F;p&gt;
&lt;p&gt;The values $s$ and $\alpha$ are not known to anyone and were discarded. Suppose the prover has already executed the circuit, obtained $c_1,c_2,c_3,c_4$, and constructed $v$. She wants to send the verifier $v(s)$, but she doesn’t know $s$. She can then use the evaluation key to send its hiding: $E(v(s))$. So the prover constructs the following elements and sends them to the verifier:&lt;&#x2F;p&gt;
&lt;p&gt;$E(v(s)) = E(v_1(s))^{c_1} E(v_2(s))^{c_2} E(v_3(s))^{c_3} E(v_4(s))^{c_4} ,$&lt;&#x2F;p&gt;
&lt;p&gt;$E(\alpha v(s)) = E(\alpha v_1(s))^{c_1}E(\alpha v_2(s))^{c_2}E(\alpha v_3(s))^{c_3}E(\alpha v_4(s))^{c_4}.$&lt;&#x2F;p&gt;
&lt;p&gt;Note that the right-hand sides depend on elements known to the prover.&lt;&#x2F;p&gt;
&lt;p&gt;The verifier receives these two elements. Let’s call them $V=E(v(s))$ and $V’=E(\alpha v(s))$. But the verifier doesn’t trust the prover, so for the moment, he knows that he received two hidings $V=E(x)$ and $V’=E(y)$ of some elements $x$ and $y$. And he wants to be convinced that $x = c_1v_1(s) + c_2v_2(s) + c_3v_3(s) + c_4v_4(s)$ for some $c_1,c_2,c_3,c_4$. If those values correspond to a correct evaluation of the circuit is something we are not worrying about right now, and another check will cover that. What we are doing right now is just checking that $x$ is an evaluation at $s$ of a polynomial constructed in a very particular way.&lt;br &#x2F;&gt;
The verifier performs the following check using the verification key&lt;br &#x2F;&gt;
$$\text{Check that }\mathcal B(V, E(\alpha), V’)\text{ equals }1$$&lt;br &#x2F;&gt;
If the prover did everything right, the check would pass. From the verifier’s end, if the check passes, let’s see what he can be sure about. If the check passes, since $V=E(x)$ and $V’=E(y)$, he knows that $y=\alpha x$. Looking at the evaluation key, he sees that the prover doesn’t know the raw value of $\alpha$. The only thing the prover knows related to $\alpha$ is the hidings $E(\alpha v_i(s))$ in the evaluation key. So the only way the prover could have ever constructed the hiding of a multiple of $\alpha$ is from the values $E(\alpha v_i(s))$. And the only thing that can be constructed using them and the group operation is&lt;&#x2F;p&gt;
&lt;p&gt;$E(\alpha v_1(s))^{c_1}E(\alpha v_2(s))^{c_2}E(\alpha v_3(s))^{c_3}E(\alpha v_4(s))^{c_4} = E(c_1\alpha v_1(s) + c_2\alpha v_2(s) + c_3\alpha v_3(s) + c_4\alpha v_4(s)))$&lt;br &#x2F;&gt;
$= E(\alpha(c_1v_1(s) + c_2v_2(s) + c_3v_3(s) + c_4v_4(s)))$&lt;&#x2F;p&gt;
&lt;p&gt;for some $c_1,c_2,c_3,c_4$. So $V’=E(\alpha x)$ has to be of the form above. This implies that $\alpha x = \alpha(c_1v_1(s) + c_2v_2(s) + c_3v_3(s) + c_4v_4(s))$, and therefore the verifier is in possession of&lt;br &#x2F;&gt;
$$V = E(x) = E(c_1v_1(s) + c_2v_2(s) + c_3v_3(s) + c_4v_4(s)).$$&lt;br &#x2F;&gt;
And that’s how the verifier gets convinced that the prover sent him $V=E(v(s))$ where $v$ is a polynomial constructed using the correct recipe!&lt;&#x2F;p&gt;
&lt;h4 id=&quot;a-gap&quot;&gt;A gap&lt;&#x2F;h4&gt;
&lt;p&gt;Did you spot it? The problem lies in the phrase, “The only thing the prover knows related to $\alpha$ are the hidings $E(\alpha v_i(s))$ in the evaluation key.” That’s false because the verification key is also public and potentially known to the prover. The prover also has $E(\alpha)$. She could use it. For example, she could choose any $z$ and send the verifier $V=E(z)$ and $V’=E(\alpha)^z = E(\alpha z)$. And that would pass the verifier’s check without being $z = v(s)$ for any linear combination $v$ of the polynomials $v_i$.&lt;br &#x2F;&gt;
To this point, this is what we have and the prover could sneak in that $z$ if she wants. It’s unclear how the prover could use that flexibility to construct fake proofs. And she actually can’t without breaking some cryptographic assumptions first. But that proof takes another path. For now, let’s continue with our intuition ignoring this fact.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;intuition-continues&quot;&gt;Intuition continues&lt;&#x2F;h4&gt;
&lt;p&gt;Even though there’s this glitch we just discussed, this idea gives an obvious use case of hidings to convince a verifier that a value was produced in a very particular way.&lt;&#x2F;p&gt;
&lt;p&gt;Since the prover needs to send also $E(w(s))$ and $E(y(s))$, there must be a trusted setup publishing enough hidings to construct them. This is what it would look like.&lt;&#x2F;p&gt;
&lt;p&gt;So to send all $E(v(s))$, $E(w(s))$ and $E(y(s))$ we need a trusted setup that samples random $s$, $\alpha_v$, $\alpha_w$, $\alpha_y$ and publishes&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Evaluation key: for all $i$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$E(v_i(s)), E(\alpha_v v_i(s)),$&lt;br &#x2F;&gt;
$E(w_i(s)), E(\alpha_w w_i(s)),$&lt;br &#x2F;&gt;
$E(y_i(s)), E(\alpha_y y_i(s)),$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Verification Key: $E(\alpha_v), E(\alpha_w), E(\alpha_y)$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With all this, the prover can construct all the hidings and send them to the verifier. He follows all the checks and gets convinced that he received $E(v(s)))$, $E(w(s))$ and $E(y(s))$, where $v, w$ and $y$ are linear combinations of the respective $v_i, w_i$ and $y_i$.&lt;&#x2F;p&gt;
&lt;p&gt;But there’s a problem with that. Let’s repeat what we just said in more detail to see it.&lt;br &#x2F;&gt;
The verifier gets convinced that he received $E(v(s))$, where $v(s)$ is &lt;strong&gt;some&lt;&#x2F;strong&gt; linear combination of the $v_i(s)$, say $v(s) = av_1(s) + bv_2(s) + cv_3(s) + dv_4(s)$ for some values $a,b,c,d$.&lt;br &#x2F;&gt;
On the other hand he also received $E(w(s))$, where $w(s)$ is &lt;strong&gt;some&lt;&#x2F;strong&gt; linear combination of the elements $w_i(s)$, say $w(s) = a’v_1(s) + b’v_2(s) + c’v_3(s) + d’v_4(s)$ for some values $a’,b’,c’,d’$. And that’s the problem. The verifier has no guarantee that $a=a’$, $b=b’$, $c=c’$, and $d=d’$. And that’s important! Because $v, w$ and $y$ need to be constructed using the same values $c_1,c_2,c_3,c_4$. That’s part of the recipe to construct $p$.&lt;&#x2F;p&gt;
&lt;p&gt;So we need something that connects the three hidings sent by the prover. Because so far, they are independent, and so are the three checks of the verifier.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;proving-construction-of-all-v-w-y&quot;&gt;Proving construction of all $v,w,y$&lt;&#x2F;h4&gt;
&lt;p&gt;The solution is to use the same trick cleverly yet again. And things start to get weird.&lt;br &#x2F;&gt;
The setup phase will now sample random $s, \alpha_v, \alpha_w, \alpha_y, \beta$ and publishes the following keys&lt;&#x2F;p&gt;
&lt;p&gt;Evaluation key:&lt;&#x2F;p&gt;
&lt;p&gt;$E(v_i(s)), E(\alpha_v v_i(s)),$&lt;br &#x2F;&gt;
$E(w_i(s)), E(\alpha_w w_i(s)),$&lt;br &#x2F;&gt;
$E(y_i(s)), E(\alpha_y y_i(s)),$&lt;br &#x2F;&gt;
$E(\beta(v_i(s) + w_i(s) + y_i(s))).$&lt;&#x2F;p&gt;
&lt;p&gt;Verification Key:&lt;&#x2F;p&gt;
&lt;p&gt;$$E(\alpha_v), E(\alpha_w), E(\alpha_y), E(\beta)$$&lt;&#x2F;p&gt;
&lt;p&gt;As before the prover obtains $c_1,c_2,c_3,c_4$ and uses the evaluation key to compute $E(v(s))$, $E(\alpha_v v(s))$, $E(w(s))$, $E(\alpha_w w(s))$, $E(y(s))$, $E(\alpha_y y(s))$. But now she can also use the new elements of the evaluation key to compute $E(\beta (v(s) + w(s) + y(s)))$. She sends these seven elements to the verifier. The verifier receives seven hidings. Let’s denote them $V,V’, W, W’, Y, Y’, Z$ in the order the prover sent them.&lt;br &#x2F;&gt;
The verifier performs the following checks:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Check that $\mathcal B(V, E(\alpha_v), V&amp;#39;)$, $\mathcal B(W, E(\alpha_w), W&amp;#39;)$, and $\mathcal B(Y, E(\alpha_y), Y&amp;#39;)$ all equal $1$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. He computes $VWY$ using the group operation and checks that $\mathcal B(VWY, E(\beta), Z)$ equals $1$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If all these tests pass, the prover will convince the verifier that&lt;&#x2F;p&gt;
&lt;p&gt;$V = E(av_1(s) + bv_1(s) + cv_3(s) + dv_4(s)),$&lt;br &#x2F;&gt;
$W = E(aw_1(s) + bw_2(s) + cw_3(s) + dw_4(s))$&lt;br &#x2F;&gt;
$Y = E(ay_1(s) + by_2(s) + cy_3(s) + dy_4(s))$&lt;&#x2F;p&gt;
&lt;p&gt;for some elements $a,b,c,d$. And the reason is very similar to the previous case. The second check guarantees that $Z$ is the hiding of some multiple of $\beta$. The only way that it could have been produced is using the new hidings $E(\beta(v_i(s) + w_i(s) + y_i(s)))$. With such hidings the prover can only compute $E(\beta(v(s) + w(s) + y(s)))$ where $v,w$ and $y$ are linear combinations of the $v_i$, $y_i$ and $w_i$, respectively, with the &lt;strong&gt;same&lt;&#x2F;strong&gt; coefficients. That, and again using the second check passed, implies that the coefficients in the raw values of $V, W$, and $Y$ are the same.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-about-h&quot;&gt;What about $h$?&lt;&#x2F;h4&gt;
&lt;p&gt;As we said previously, the prover is sending $E(v(s))$, $E(w(s))$ and $E(y(s))$ because the verifier can use them to check that $\mathcal A(E(v), E(w), E(y), E(s(s-1)), E(h(s)))$ equals $1$. For that the verifier needs both $E(s(s-1))$ and $E(h(s))$. The value $E(s(s-1))$ is independent of the particular execution of the circuit and can be added to the verifying key. Concerning $E(h(s))$, the prover needs to provide that. So she needs to be able to construct it. The hidings on the evaluation key are insufficient now since $h$ won’t be, in general, any linear combination of the polynomials $v_i, w_i, y_i$. The solution is to add $E(s^i)$ to the evaluation key for as many values $i$ as are needed to construct $h$ in the worst case.&lt;&#x2F;p&gt;
&lt;p&gt;To keep this short, we will wait to add this to the protocol. We’ll cover the remaining issue and then write down the final protocol.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;recap-3&quot;&gt;Recap&lt;&#x2F;h4&gt;
&lt;p&gt;With all this, the prover can construct hidings of $v(s)$, $w(s)$,$y(s), h(s)$ and convince the verifier that she followed the correct recipe to build the polynomials $v,w,y$. And moreover that $p = vw-y=X(X-1)h$. This answers the third and fourth questions of the beginning!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;5-inputs-and-outputs&quot;&gt;5. Inputs and outputs&lt;&#x2F;h2&gt;
&lt;p&gt;Let’s answer question 5. How does the verifier know that the prover used the input values $c_1$ and $c_2$? This is very simple. Recall that the verifier expects a proof of execution of the circuit on inputs $c_1,c_2$. So the prover executes the circuit, obtains the output $c_3$, and communicates $c_3$ to the verifier. So the verifier knows $c_1,c_2$, and $c_3$. In general, the verifier knows all public input and output values. Therefore we can modify the protocol slightly to allow the verifier to check inputs and outputs.&lt;&#x2F;p&gt;
&lt;p&gt;The polynomial $p$ is equal to $vw - y$ where $v = c_1v_1 + c_2v_2 + c_3v_3 + c_4v_4$ and similarly for $w$ and $y$. And the verifier is expecting to receive, for instance, the hiding $E(v(s))$ as part of the proof. But the input&#x2F;output part of $E(v(s))$ is something the verifier can compute by himself. More precisely, he knows $c_1,c_2,c_3$ and $E(v_1(s))$, $E(v_2(s))$ and $E(v_3(s))$ since they are part of the public evaluation key so far. So he can compute&lt;&#x2F;p&gt;
&lt;p&gt;$$E(c_1v_1(s) + c_1v_2(s) + c_3v_3(s)) = E(v_1(s))^{c_1} E(v_2(s))^{c_2} E(v_3(s))^{c_3}$$&lt;&#x2F;p&gt;
&lt;p&gt;This means that if the prover only sends him $V = E(c_4v_4(s))$, then the verifier can complete it with the above to obtain $E(v(s))$:&lt;br &#x2F;&gt;
$$E(v(s)) = E(c_1v_1(s) + c_1v_2(s) + c_3v_3(s))V$$&lt;br &#x2F;&gt;
And doing so, he gets the guarantee that the terms in $v(s)$ corresponding to the input&#x2F;output are the ones he expects.&lt;&#x2F;p&gt;
&lt;p&gt;Note that if we do this, the prover won’t need the hidings $E(v_1(s))$, $E(v_2)$, and $E(v_3(s))$ anymore. So we are moving them to the verifying key.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s write down what we have so far!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;6-final-protocol&quot;&gt;6. Final protocol&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;almost-the-final-protocol-for-the-example&quot;&gt;Almost the final protocol for the example&lt;&#x2F;h3&gt;
&lt;p&gt;Recall that we assume there is a hiding function $E: \mathbb F_p \to G$ for some group $G$ and that there exists an algorithm $\mathcal A$ such that $\mathcal A(E(a), E(b), E(c), E(t), E(h)) = 1$ if and only if $ab-c=th$. We define $\mathcal B(E(a), E(b), E(c)) := \mathcal A(E(a), E(b), E(c), E(0), E(0))$ which outputs $1$ if and only if $ab=c$. Also recall that $E(a)E(b) = E(a+b)$.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;1-setup&quot;&gt;1. Setup&lt;&#x2F;h4&gt;
&lt;p&gt;Five random elements $s, \alpha_v, \alpha_w, \alpha_y, \beta$ are sampled from $\mathbb F_p$. Two public &lt;em&gt;keys&lt;&#x2F;em&gt; are generated from them: the evaluation key and the verification key&lt;br &#x2F;&gt;
3.1 Evaluation Key:&lt;&#x2F;p&gt;
&lt;p&gt;$E(v_4(s)), E(w_4(s)), E(y_4(s)),$&lt;br &#x2F;&gt;
$E(\alpha_vv_4(s)), E(\alpha_ww_4(s)), E(\alpha_yy_4(s)),$&lt;br &#x2F;&gt;
$E(\beta(v_4(s) + w_4(s) + y_4(s))),$&lt;br &#x2F;&gt;
$E(1)$&lt;&#x2F;p&gt;
&lt;p&gt;3.2 Evaluation Key:&lt;&#x2F;p&gt;
&lt;p&gt;$E(\alpha_v), E(\alpha_w), E(\alpha_y), E(\beta),$&lt;br &#x2F;&gt;
$E(v_1(s)), E(v_2(s)), E(v_3(s)),$&lt;br &#x2F;&gt;
$E(w_1(s)), E(w_2(s)), E(w_3(s)),$&lt;br &#x2F;&gt;
$E(y_1(s)), E(y_2(s)), E(y_3(s)),$&lt;br &#x2F;&gt;
$E(s(s-1))$&lt;&#x2F;p&gt;
&lt;h4 id=&quot;2-proof-generation&quot;&gt;2. Proof generation&lt;&#x2F;h4&gt;
&lt;p&gt;The prover executes the circuit with public input values $c_1, c_2$, obtains the output value $c_3$, and the intermediate value $c_4$. She computes&lt;&#x2F;p&gt;
&lt;p&gt;$v = c_1v_1 + c_2v_2 + c_3v_3 + c_4v_4$&lt;br &#x2F;&gt;
$w = c_1w_1 + c_2w_2 + c_3w_3 + c_4w_4$&lt;br &#x2F;&gt;
$y = c_1y_1 + c_2y_2 + c_3y_3 + c_4y_4$&lt;br &#x2F;&gt;
$p = vw - y$&lt;&#x2F;p&gt;
&lt;p&gt;She also computes $h$ such that $p = X(X-1)h$. The polynomial $h$ must be of degree $0$ for this particular circuit, so it is a constant value in $\mathbb F_p$.&lt;br &#x2F;&gt;
The prover computes the following hidings from the evaluation key.&lt;&#x2F;p&gt;
&lt;p&gt;$\pi = (E(c_4v_4(s)), E(\alpha_vc_4v_4(s)),$&lt;br &#x2F;&gt;
$E(c_4w_4(s)), E(\alpha_wc_4w_4(s)),$&lt;br &#x2F;&gt;
$E(c_4y_4(s)), E(\alpha_yc_4y_4(s)),$&lt;br &#x2F;&gt;
$E(\beta c_4(v_4(s) + w_4(s) + y_4(s)),$&lt;br &#x2F;&gt;
$E(h))$&lt;&#x2F;p&gt;
&lt;p&gt;The prover sends the output value $c_3$ to the verifier and the proof $\pi$.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;3-verification&quot;&gt;3. Verification&lt;&#x2F;h4&gt;
&lt;p&gt;The verifier receives the output value $c_3$ and the proof $\pi = (V, V’, W, W’, Y, Y’, Z, H)$. He computes the input&#x2F;output parts from the verification key.&lt;&#x2F;p&gt;
&lt;p&gt;$V_{IO} = E(c_1v_1(s) + c_2v_2(s) + c_3v_3(s))$&lt;br &#x2F;&gt;
$W_{IO} = E(c_1w_1(s) + c_2w_2(s) + c_3w_3(s))$&lt;br &#x2F;&gt;
$Y_{IO} = E(c_1y_1(s) + c_2y_2(s) + c_3y_3(s))$&lt;&#x2F;p&gt;
&lt;p&gt;He performs the following checks&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. $\mathcal B(V&amp;#39;, V, E(\alpha_v)) = 1$, $\mathcal B(W&amp;#39;, W, E(\alpha_w)) = 1$, $\mathcal B(Y&amp;#39;, Y, E(\alpha_y)) = 1$,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. $\mathcal B(VWY, E(\beta), Z)=1$,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. $\mathcal A(V_{IO}V, W_{IO}W, Y_{IO}Y, E(s(s-1)), H) = 1$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If all checks pass, the verifier gets convinced that the prover executed the circuit with input values $c_1,c_2$ and obtained the output value $c_3$.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pinocchio-s-protocol&quot;&gt;Pinocchio’s protocol&lt;&#x2F;h3&gt;
&lt;p&gt;Now we give the actual protocol for a general circuit. Suppose the circuit has $n_I$ input values and $n_O$ output values.&lt;&#x2F;p&gt;
&lt;p&gt;As before, let $E$ be the hiding function and $\mathcal A$ and $\mathcal B$ the algorithms to check equations on hidings.&lt;&#x2F;p&gt;
&lt;p&gt;Let $N=n_I + n_O$. Executing the circuit with input values $(c_1,\dots,c_{n_I})$ outputs the values $(c_{n_I+1},\dots, c_{N})$ and all the intermediate values $(c_{N+1}, \dots, c_m)$. Putting these tuples together, we say that $(c_1,\dots,c_m)$ are the values of the execution of the circuit.&lt;&#x2F;p&gt;
&lt;p&gt;In the example, we had $n_I=2, n_O=1$, $N=3$ and therefore executing the circuit with input values $(c_1,c_2)$ produces the output value $c_3$ and the intermediate value $c_4$.&lt;&#x2F;p&gt;
&lt;p&gt;Let $d$ be the number of multiplication gates in the circuit. Let $t = X(X-1)(X-2)\cdots (X-d)$. There exist families of polynomials $v_i,w_i,y_i$, with $i=1,\dots, m$, such that $(c_1,\dots,c_m)$ are the values of the execution of the circuit if and only if $p = vw-y$ is divisible by $t$, where $v=\sum_i c_iv_i$, $w=\sum_ic_iw_i$ and $y=\sum_ic_iy_i$.&lt;&#x2F;p&gt;
&lt;p&gt;In our example $t = X(X-1)$.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;1-setup-1&quot;&gt;1. Setup&lt;&#x2F;h4&gt;
&lt;p&gt;Eight random elements $s, r_v, r_w, \alpha_v, \alpha_w, \alpha_y, \beta, \gamma$ are sampled from $\mathbb F_p$. Let $r_y=r_vr_w$. Two public &lt;em&gt;keys&lt;&#x2F;em&gt; are generated from them: the evaluation key and the verification key&lt;br &#x2F;&gt;
3.1 Evaluation Key: For all $i=N+1,\dots,m$, and for all $j=1,\dots,d-2$&lt;&#x2F;p&gt;
&lt;p&gt;$E(r_vv_i(s)), E(r_ww_i(s)), E(r_yy_i(s)),$&lt;br &#x2F;&gt;
$E(\alpha_vr_vv_i(s)), E(\alpha_wr_ww_i(s)), E(\alpha_yr_yy_i(s)),$&lt;br &#x2F;&gt;
$E(\beta(r_vv_i(s) + r_ww_i(s) + r_yy_i(s))),$&lt;br &#x2F;&gt;
$E(s^j)$&lt;&#x2F;p&gt;
&lt;p&gt;3.2 Evaluation Key: For all $i=1,\dots, N$&lt;&#x2F;p&gt;
&lt;p&gt;$E(\alpha_v), E(\alpha_w), E(\alpha_y), E(\beta\gamma), E(\gamma)$&lt;br &#x2F;&gt;
$E(r_vv_i(s)),$&lt;br &#x2F;&gt;
$E(r_ww_i(s)),$&lt;br &#x2F;&gt;
$E(r_yy_i(s)),$&lt;br &#x2F;&gt;
$E(t(s))$&lt;&#x2F;p&gt;
&lt;h4 id=&quot;2-proof-generation-1&quot;&gt;2. Proof generation&lt;&#x2F;h4&gt;
&lt;p&gt;The prover executes the circuit with input values $(c_1,\dots,c_{n_I})$ and obtains the values $(c_1,\dots,c_m)$. She computes:&lt;&#x2F;p&gt;
&lt;p&gt;$v = \sum_{i=1}^m c_iv_i$&lt;br &#x2F;&gt;
$w = \sum_{i=1}^m c_iw_i$&lt;br &#x2F;&gt;
$y = \sum_{i=1}^m c_iy_i$&lt;br &#x2F;&gt;
$p = vw - y$&lt;&#x2F;p&gt;
&lt;p&gt;She also computes $h$ such that $p = th$. The polynomial $h$ is of degree at most $d$.&lt;br &#x2F;&gt;
The prover computes the following hidings from the evaluation key. Note that all the sums here have $i$ ranging from $N+1$ to $m$. That corresponds to the indices of the intermediate values.&lt;&#x2F;p&gt;
&lt;p&gt;$\pi = (E(\sum_{i=N+1}^mc_ir_vv_i(s)), E(\alpha_v\sum_{i=N+1}^mr_vc_iv_i(s)),$&lt;br &#x2F;&gt;
$E(\sum_{i=N+1}^mc_ir_ww_i(s)), E(\alpha_w\sum_{i=N+1}^mr_wc_iw_i(s)),$&lt;br &#x2F;&gt;
$E(\sum_{i=N+1}^mc_ir_yy_i(s)), E(\alpha_y\sum_{i=N+1}^mr_yc_iy_i(s)),$&lt;br &#x2F;&gt;
$E(\beta \sum_{i=N+1}^mr_vc_iv_i(s) + r_wc_iw_i(s) + r_ic_iy_i(s)),$&lt;br &#x2F;&gt;
$E(h))$&lt;&#x2F;p&gt;
&lt;p&gt;The prover sends the output values $(c_{n_O+1},\dots,c_N)$ to the verifier and the proof $\pi$.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;3-verification-1&quot;&gt;3. Verification&lt;&#x2F;h4&gt;
&lt;p&gt;The verifier receives the output values $(c_{n_O},\dots, c_N)$ and the proof $\pi = (V, V’, W, W’, Y, Y’, Z, H)$. He computes the input&#x2F;output parts from the verification key. Note that all sums here have $i$ ranging from $1$ to $N$. That corresponds to the input&#x2F;output indices.&lt;&#x2F;p&gt;
&lt;p&gt;$V_{IO} = E(\sum_{i=1}^Nc_ir_vv_i(s))$&lt;br &#x2F;&gt;
$W_{IO} = E(\sum_{i=1}^Nc_ir_ww_i(s))$&lt;br &#x2F;&gt;
$Y_{IO} = E(\sum_{i=1}^Nc_ir_yy_i(s))$&lt;&#x2F;p&gt;
&lt;p&gt;He performs the following checks&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. $\mathcal B(V&amp;#39;, V, E(\alpha_v)) = 1$, $\mathcal B(W&amp;#39;, W, E(\alpha_w)) = 1$, $\mathcal B(Y&amp;#39;, Y, E(\alpha_y)) = 1$,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. $\mathcal A(Z, E(\gamma), E(0), VWY, E(\beta\gamma))=1$,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. $\mathcal A(V_{IO}V, W_{IO}W, Y_{IO}Y, E(t(s)), H) = 1$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * If all checks pass, the verifier gets convinced that the prover executed the circuit with input values $(c_1,\dots,c_{n_I})$ and obtained the output values $(c_{n_O+1}, \dots, c_N)$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</description>
      </item>
      <item>
          <title>The hunting of the (zk)-SNARK</title>
          <pubDate>Wed, 11 Jan 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/the-hunting-of-the-zk-snark/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/the-hunting-of-the-zk-snark/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/the-hunting-of-the-zk-snark/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;Succinct Non-Interactive Arguments of Knowledge (SNARKs) are powerful cryptographic primitives with decentralized finances, governance, and computation applications. There are many different SNARKs, such as Marlin (the one Aleo uses), Plonk, STARKs, Groth16, etc., depending on the tools they are built on and with differences in performance, proof sizes, verification times, etc. However, they are all based on some common principles and properties. Among SNARKs, the most important ones for private applications are zero-knowledge SNARKs (zk-SNARKs, for short). They allow us to prove that we know certain variables, called witness, $w$, such that the output of a function $F$, evaluated at the witness and instance (public variables), $x$, is $F(x,w)=y$, without revealing anything about $w$.&lt;&#x2F;p&gt;
&lt;p&gt;We can convert computer programs to functions receiving input (some of which we may want to conceal) and prove their correct execution with SNARKs. For example, we can transform the program into an arithmetic circuit, $C$, and, given the public input and output, $x$, and confidential data, $w$, we can prove that the program was correctly executed by showing the satisfiability of the circuit, $C(x,w)=0$. Since arithmetic circuit satisfiability is an NP-complete problem, we can reduce any NP problem to an arithmetic circuit (this is not the only alternative, though, and several constructions rely on different techniques).&lt;&#x2F;p&gt;
&lt;p&gt;Before jumping into the details, let us first explain the main properties of a SNARK and the precise meaning of each term in the name. A zk-SNARK involves two parties, the prover and the verifier, where the first one tries to convince the latter of a given statement, such as the prover knows $w$ such that $C(w,x)=0$. The SNARK must fulfill the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Completeness: If the prover knows $w$, he will always be able to convince an honest verifier of the statement&amp;#39;s validity.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Soundness: if the statement is false, then no cheating prover could convince the verifier to accept, except with very low probability.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Zero-knowledge: the proof does not reveal anything about the witness.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As for the name, we have the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Succinctness: the proofs must be short and quick to verify. This property would enable us to delegate expensive computations to untrusted parties and check their validity without running the program ourselves.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Non-interactive: does not require interaction between prover and verifier, nor to generate the proof or verify it. We will see that the construction will rely first on interactive proofs, but we can turn it into non-interactive by employing the [Fiat-Shamir](https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Fiat%E2%80%93Shamir_heuristic) transform.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Argument of knowledge: we can prove with a high probability that we know the witness.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;setup&quot;&gt;Setup&lt;&#x2F;h2&gt;
&lt;p&gt;SNARKs require trusted setups. Among them, we can distinguish:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Uniform reference string or transparent setups (URS).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Structured reference string or private setup (SRS).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In the case of SRS, we can find two instances:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Universal (for example, MARLIN)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Specific (Groth 16)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In practice, the trusted setup is carried out as a multiparty computation; the construction will be secure if there is at least one honest party. The problem with specific SRS is that the string depends on the program, and we must carry out a new setup for each one (this is an undesirable property).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;probabilistic-proofs-and-capabilities-of-the-verifier&quot;&gt;Probabilistic proofs and capabilities of the verifier&lt;&#x2F;h2&gt;
&lt;p&gt;The conciseness of the argument relies on probabilistic proofs. To do that, we first have to establish the things that the “powers” or capabilities of the verifier. We have:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Interaction: the verifier can interact with the prover, sending challenges and receiving responses.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Multiprover: there are several provers, but they are isolated.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Randomness: the verifier can select random elements or queries.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Ability to perform queries to an oracle: the verifier may query the prover&amp;#39;s messages.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When the verifier has access to more than one of these powers, we get different types of proofs:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Interactivity + Randomness: Interactive proofs (IP).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Randomness + Oracle: Probabilistically checkable proofs (PCP).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Interactivity + Randomness + Oracle: Interactive Oracle Proofs (IOP)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There are other possibilities, such as MIOP, but we will focus on the previous 3. IOPs give the most efficient constructions for SNARKs: quasilinear time verification, linear size proof lengths, linear time prover, and efficient implementations. PCP are interesting from an educational point of view but are inefficient in practice (it does not result in succinct proofs, except with linear queries). Finally, IP give some powerful building blocks in the form of subroutines.&lt;&#x2F;p&gt;
&lt;p&gt;In an IOP, the prover and verifier exchange messages. The prover sends arbitrary messages (in a polynomial IOP, the prover sends commitments - see next section- to polynomials), and the verifier sends random challenges. After some rounds, the verifier queries some values and decides whether to accept or reject the proof.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;commitment-schemes&quot;&gt;Commitment schemes&lt;&#x2F;h2&gt;
&lt;p&gt;The performance of SNARKs depends on the type of commitment used; there have been many advances over the last years to improve them.&lt;&#x2F;p&gt;
&lt;p&gt;We can think of a commitment as a safe box. We make some choice for a bet, store it in a secure container, and hand it to someone else. Once the result is known, we can reveal our selection by opening the safe box.&lt;&#x2F;p&gt;
&lt;p&gt;A commitment has to verify two properties:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Binding: we cannot produce two valid openings for the same commitment. In other words, if we committed to some value $a$, it should be impossible to find $b$ such that the $cm(a)=cm(b)$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Hiding: the commitment reveals nothing about the committed data.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;One way to commit to a message is by using a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Cryptographic_hash_function&quot;&gt;collision-resistant hash function&lt;&#x2F;a&gt;. If we have a message $m$ and some random value $r$,&lt;br &#x2F;&gt;
$\mathrm{cm}(m,r)=hash(m\mid r)$&lt;br &#x2F;&gt;
Given that it is collision-resistant, we have the binding property.&lt;br &#x2F;&gt;
We can afterward open the commitment and verify the following:&lt;br &#x2F;&gt;
$\mathrm{Verify}(m,r,\mathrm{cm})\rightarrow$ accept or reject&lt;br &#x2F;&gt;
One advantage of commitments is that they tend to be short. For example, if we use SHA-256, the digest length will be 32 bytes.&lt;&#x2F;p&gt;
&lt;p&gt;One relevant group of commitments is the polynomial schemes. Here are some constructions and the math that they rely on:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Basic elliptic curves: bulletproofs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Bilinear groups: Kate-Zaverucha-Goldberg (KZG) polynomial commitments (pairings, trusted setup) DORY (no trusted setup)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Groups of unknown order: DARK&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Hash functions only: FRI&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;anatomy-of-a-snark&quot;&gt;Anatomy of a SNARK&lt;&#x2F;h2&gt;
&lt;p&gt;A SNARK can be constructed by selecting the following two elements:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. A type of probabilistic proof: for example, probabilistically checkable proof (PCP) or interactive oracle proof (IOP). A particular kind of IOP is polynomial IOP (PIOP).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. A commitment scheme (cryptography). For example, polynomial&#x2F;functional commitments, vector commitments, and linear encoding.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The probabilistic proof determines the type of computation. It can be either a machine computation (such as vmTinyRam) or a circuit.&lt;&#x2F;p&gt;
&lt;p&gt;The cryptographic element determines the cost to generate the proofs, whether it will be postquantum secure, and the type of setup (transparent or structured). The math tools we need to work with each of them are:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Linear encoding: Elliptic curve pairings (ECP) + Lattices&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Vector commitment: Collision resistant hash (CRH) functions + ECP.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Polynomial commitment: CRH, ECP, PO groups, UO groups&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Some SNARK recipes are:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Linear PCP + Linear encoding: Groth16, Groth-Maller 17&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. PCP&#x2F;IOP + vector commitment: STARKs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Polynomial PCP&#x2F;IOP + polynomial commitment: MARLIN, SONIC, Plonk, Spartan.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Bulletproofs take different combinations of the elements above and are based on cryptographic sum checks.&lt;&#x2F;p&gt;
&lt;p&gt;The proof’s size depends strongly on the type of construction. For example, for PIOP with KZG polynomial commitments, proofs take less than one kB (two elliptic curve elements). In contrast, IOP with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;vitalik.ca&#x2F;general&#x2F;2017&#x2F;11&#x2F;22&#x2F;starks_part_2.html&quot;&gt;FRI&lt;&#x2F;a&gt; (Fast Reed-Solomon Interactive Oracle Proofs of Proximity) needs around 100 kB, more than two orders of magnitude more! This difference is because FRI uses Merkle trees; the verification requires an authentication path, needing several hashes.&lt;&#x2F;p&gt;
&lt;p&gt;One problem we face with circuits is that the verifier should read it, resulting in a linear verification time that depends linearly on the size (which would make it non-succinct). To avoid this, we can preprocess it and attain sublinear verification times.&lt;&#x2F;p&gt;
&lt;p&gt;We will now focus on the KZG polynomial commitment, which is the basis of Marlin and Plonk.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;kzg-commitment-scheme&quot;&gt;KZG commitment scheme&lt;&#x2F;h2&gt;
&lt;p&gt;The polynomial commitment scheme has the following algorithms:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Setup.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Commit.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Open.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To commit to a polynomial, we will evaluate the polynomial at a given but unknown point $\alpha$.&lt;&#x2F;p&gt;
&lt;p&gt;The setup takes the maximum degree of the polynomial (which depends on the number of gates of the arithmetic circuit) and outputs the public parameters: proving key and verifying key. To be able to evaluate polynomials, we will use an elliptic curve (we will need it to be &lt;a href=&quot;&#x2F;multiscalar-multiplication-strategies-and-challenges&#x2F;&quot;&gt;pairing friendly&lt;&#x2F;a&gt;, such as BLS 12-377) to hide $\alpha$ and its powers ($\alpha$ is chosen during the setup ceremony and discarded as toxic waste!). To do that, we pick a generator of a group of large prime order $d+1$, $g$ and calculate&lt;br &#x2F;&gt;
$H={g,\alpha g, \alpha^2 g, \alpha^3 g,…, \alpha^{d} g}={h_0,h_1,h_2,…h_{d}}$&lt;br &#x2F;&gt;
This calculation will give us a vast collection of elliptic curve points (we will save them as a string), which will work as the proving key. In the case of a universal setup, the number of elements will coincide with the maximum size of the circuit. Since elliptic curve points take in the order of $100$ B, if we want to deal with $10^{8}$ gates, we will need more than 1 GB to store it. For a given circuit, which could be much smaller than the maximum, MARLIN trims the key so that it is much simpler and faster to work. The setup also depends on a security parameter $\lambda$, but we will consider it to be fixed in our analysis.&lt;br &#x2F;&gt;
We therefore have $\mathrm{setup}(\lambda,N)\rightarrow \mathrm{pp(pk,vk)}$.&lt;&#x2F;p&gt;
&lt;p&gt;The prover generates the polynomial $P(x)=p_0+p_1x+…p_dx^d$ and commits to it by evaluating it at $\alpha$. Since we do not know $\alpha$, only the scalar multiples of group elements of powers of $\alpha$,&lt;br &#x2F;&gt;
$\mathrm{cm}(P)=p_0g+p_1\alpha g+…+p_d\alpha^d g=p_0h_0+p_1h_1+…p_dh_d$&lt;br &#x2F;&gt;
This calculation is the problem of multiscalar multiplication (&lt;a href=&quot;&#x2F;multiscalar-multiplication-strategies-and-challenges&#x2F;&quot;&gt;MSM&lt;&#x2F;a&gt;). We see that the polynomial commitment corresponds to one group element of the elliptic curve.&lt;&#x2F;p&gt;
&lt;p&gt;We could also use a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Merkle_tree&quot;&gt;Merkle tree&lt;&#x2F;a&gt; to commit to a polynomial. The problem with Merkle trees is that the size of the tree would be dependent on the degree of the polynomial. In the case of KZG, the commitment is just one group element independent of the size. Besides, when we want to evaluate the polynomial in a proof, we need to send all the coefficients in the clear (revealing the polynomial), with the verifier having to do linear work on the size of the polynomial. On the other hand, we will see that KZG mostly hides the polynomial (unless there are lots of queries), and the verification is independent of the degree of the polynomial. Additionally, KZG allows for batch proofs: if we have several commitments $\mathrm{cm}_1$, $\mathrm{cm}_2$, …, $\mathrm{cm}_k$, we can generate a single proof showing that all commitments are valid.&lt;&#x2F;p&gt;
&lt;p&gt;Once the prover commits to the polynomial, the verifier (in an interactive scheme) can send random points $r_k$ to the prover, and the latter gives the polynomial evaluated at $r_k$, $P(r_k)$. To make it non-interactive, we use the Fiat-Shamir transform to generate random challenges from a cryptographic hash function.&lt;&#x2F;p&gt;
&lt;p&gt;Suppose the prover wants to convince the verifier that $P(u)=v$. He can transform that equation into a polynomial, $g(x)=P(x)-v$, which has a root at $x=u$. This fact means that $g(x)$ is divisible by $x-u$, which we can write as $g(x)=P(x)-v=Q(x)(x-u)$, where $Q$ is the quotient polynomial. The prover can commit to $Q(x)$ doing the same as before, that is&lt;br &#x2F;&gt;
$\mathrm{cm}(Q)=q_0g+q_1\alpha d+…+q_{d-1}\alpha^{d-1} g=q_0h_0+q_1h_1+…q_{d-1}h_{d-1}$&lt;br &#x2F;&gt;
which is another MSM. The proof $\pi$ contains this group element: constant size! The proof will show that $P(u)=v$ and $P$ is indeed a polynomial of at most degree $d$ and that the commitment of $P$ is $\mathrm{cm}(P)$.&lt;&#x2F;p&gt;
&lt;p&gt;The verifier accepts the proof if $(\alpha-u)\mathrm{cm}(Q)=\mathrm{cm}(P)-vg$. The problem is that we do not know $\alpha$. This is where &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;vitalik.ca&#x2F;general&#x2F;2017&#x2F;01&#x2F;14&#x2F;exploring_ecp.html&quot;&gt;pairings&lt;&#x2F;a&gt; come to our aid, and we only need the elements $h_0$ and $h_1$ to be able to compute. Roughly speaking, an elliptic curve pairing is a function&lt;br &#x2F;&gt;
$f: \mathcal{G}_1 \times \mathcal{G}_2\rightarrow \mathcal{G}_t$&lt;br &#x2F;&gt;
which takes two elements, $P$ from $\mathcal{G}_1$ and $Q$ from $\mathcal{G}_2$ and outputs an element $R$ from $\mathcal{G}_t$. All the groups have the same order $r$ and correspond to groups in pairing-friendly elliptic curves. In the case of MARLIN, we use the &lt;a href=&quot;&#x2F;multiscalar-multiplication-strategies-and-challenges&#x2F;&quot;&gt;curve BLS 12-377&lt;&#x2F;a&gt;. The pairing satisfies the following:&lt;br &#x2F;&gt;
$f(P,Q)=f(g,g_2)^{pq}$&lt;br &#x2F;&gt;
where $g$ and $g_2$ are generators for the groups $\mathcal{G}_1$ and $\mathcal{G}_2$ (and $P=pg$ and $Q=qg_2$). The form of the verification equation in terms of pairings is&lt;br &#x2F;&gt;
$f(\mathrm{cm}(Q),(\alpha-u)g_2)=f(\mathrm{cm}(P)-vg,g_2)$&lt;br &#x2F;&gt;
We do the check over $\mathcal{G}_t$. We only need to know $\alpha g_2$ from the trusted setup.&lt;&#x2F;p&gt;
&lt;p&gt;How can we be convinced that if we evaluated the polynomials at a single point and they coincide, then it is likely that the argument is true? The answer lies with the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Schwartz%E2%80%93Zippel_lemma&quot;&gt;Schwartz-Zippel lemma&lt;&#x2F;a&gt; (we will state it for finite fields): for a polynomial $P$ of degree $d$ over a finite field of order $p$, the probability that the polynomial is zero at a point sampled at random $r$ is&lt;br &#x2F;&gt;
$\mathrm{Pr}(P(r)=0)=d&#x2F;p$&lt;br &#x2F;&gt;
Given that the maximum size of circuits (which gives the maximum degree of a polynomial) is around $2^{26}\approx 10^8$ and the size of the field is larger than $2^{256}$, the probability is around $2^{-230}\approx 10^{-70}$. If we say $P_1$ and $P_2$ coincide at one point $r$, we can construct the polynomial $P(x)=P_1(x)-P_2(x)$ (since polynomial addition is closed) and $P(r)=0$. Given how unlikely it is to hit a zero at random, we are confident that $P(x)$ is the zero polynomial.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;Zk-SNARKs have started gaining attention due to their use in developing fully private applications. They provide succinct proofs that a specific computation was carried out correctly without revealing sensitive information. There are many possible constructions, most based on probabilistic proofs and a commitment scheme. Depending on the different choices, more efficient versions are possible and determine the type of computation (machine or circuit computation). We explored the KZG commitment scheme, which shows the idea behind systems such as MARLIN and Plonk and the calculations we need to generate and verify the proofs.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Multiscalar Multiplication: Strategies and Challenges</title>
          <pubDate>Mon, 09 Jan 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/multiscalar-multiplication-strategies-and-challenges/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/multiscalar-multiplication-strategies-and-challenges/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/multiscalar-multiplication-strategies-and-challenges/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;Generating a zk-SNARK (zero-knowledge succinct non-interactive argument of knowledge), as the one Aleo uses, involves a lot of cryptographic calculations, almost all of which happen inside an elliptic curve over a finite field.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;elliptic-curves&quot;&gt;Elliptic Curves&lt;&#x2F;h2&gt;
&lt;p&gt;The following is a short version of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;cryptographyinrustforhackers.com&#x2F;chapter_2.html#elliptic-curves&quot;&gt;this&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;An elliptic curve point is a pair of numbers $(x,y)$ in a finite field (you can think of a finite field as $Z_p$, the integers modulo some huge prime number, though sometimes they’re more than that), which satisfy an equation of the form:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
y^2 = x^3 + ax + b&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;for some $a$ and $b$ in the finite field.&lt;&#x2F;p&gt;
&lt;p&gt;You can sum elliptic curve points, but not in the traditional way. Instead of doing&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
(x_1, y_1) + (x_2, y_2) = (x_1 + x_2, y_1 + y_2)&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;We do this:&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
(x_1, y_1) + (x_2, y_2) = (x_3, -y_3)&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;where&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
x_3 = s^2 - x_1 - x_2 \&lt;br &#x2F;&gt;
y_3 = s(x_1 - x_3) - y_1 \&lt;br &#x2F;&gt;
s = \frac{y_2 - y_1}{x_2 - x_1} x_3&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;There are two exceptions to this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. When $(x_1, y_1) = (x_2, y_2)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. When $x_1 = x_2$ but $y_1 \neq y_2$. In this case, as no other solution exists, $y_1 = - y_2$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In both 1. and 2. the calculation above is not defined (we would be dividing by zero), so what we do instead is:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. The sum of a point with itself is, as before, a point $(x_3, y_3)$, only in this case  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
x_3 = s^2 - 2 x_1 \&lt;br &#x2F;&gt;
y_3 = (x_1 - x_3) - y_1 \&lt;br &#x2F;&gt;
s = \dfrac{3 x_1^2 + a}{2 y_1}&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
(Here, $a$ is the coefficient defining the curve equation above).
2. In this case, the result of the sum is a unique point we arbitrarily add to the curve, called the &lt;em&gt;point at infinity&lt;&#x2F;em&gt; and noted $\mathcal{O}$. This point works as the zero for our sum, i.e.,&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
\mathcal{O} + (x, y) = (x, y)&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
for every $(x,y)$.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;primitive-operations&quot;&gt;Primitive operations&lt;&#x2F;h2&gt;
&lt;p&gt;Elliptic curve cryptography ultimately relies on two primitive operations, point addition (adding two different points) and point doubling (adding a point to itself), which we call &lt;code&gt;ECADD&lt;&#x2F;code&gt; and &lt;code&gt;ECDBL&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;We can apply the double-and-add algorithm if we try to add a point many times to itself. As already explained &lt;a href=&quot;&#x2F;what-every-developer-needs-to-know-about-elliptic-curves&#x2F;&quot;&gt;in one of our posts&lt;&#x2F;a&gt;, the idea is simple: if we want to calculate, say, $9P$ for some curve point $P$, instead of performing nine additions we can do&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
P + P = 2P \&lt;br &#x2F;&gt;
2P + 2P = 4P \&lt;br &#x2F;&gt;
4P + 4P = 8P \&lt;br &#x2F;&gt;
4P + P = 9P&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;which is only four addition operations.&lt;&#x2F;p&gt;
&lt;p&gt;When we have to add many different points $k_1P_1+k_2P_2+…+k_nP_n$, most techniques assume these primitives are given and focus on how to perform the scalar multiplications $k_i P_i$ and the additions, minimizing the amount of &lt;code&gt;ECADD&lt;&#x2F;code&gt;s and &lt;code&gt;ECDBL&lt;&#x2F;code&gt;s.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;msm&quot;&gt;MSM&lt;&#x2F;h2&gt;
&lt;p&gt;The &lt;em&gt;Multi-Scalar Multiplication&lt;&#x2F;em&gt; problem consists of, given an elliptic curve, calculating&lt;&#x2F;p&gt;
&lt;p&gt;$$&lt;br &#x2F;&gt;
\sum_{i=1}^{n} k_i P_i&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;for some scalars (a.k.a. integers modulo a certain prime) $k_i$, some elliptic curve points $P_i = (x_i, y_i)$ and some $n$ (in Aleo’s challenge it is $2^{26}$).&lt;&#x2F;p&gt;
&lt;p&gt;The sum operation here is the one discussed in the previous section. Similarly, $k_i P_i$ means “$P_i$ summed to itself $k_i$ times,” the sum once again being the one defined above.&lt;&#x2F;p&gt;
&lt;p&gt;Around 80% of the time to produce a zk-SNARK proof is spent doing MSM, so optimizing it is crucial for performance.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;bucketing-method&quot;&gt;Bucketing method&lt;&#x2F;h3&gt;
&lt;p&gt;We can break the MSM into smaller sums and reduce the number of operations by repeatedly using the windowing technique. If we want to compute each $k_iP_i$, we can break it into windows of size $c$&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
k_iP_i=k_{i0}P_i+k_{i1}2^{c} P_i+k_{i2}2^{2c} P_i+…+k_{i,m-1}2^{c(m-1)} P_i&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
Using this, we can rewrite the MSM problem as&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
P=\sum_{i} k_iP_i=\sum_{i}\sum_{j} k_{ij}2^{cj}P_i&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
We can now change the order of the summations,&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
P=\sum_{i} k_iP_i=\sum_{j}2^{cj}\left(\sum_{i} k_{ij}P_i\right)=\sum_j 2^{cj} B_j&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
In other words, we first divide the scalars into windows and then combine all the points in each window. Now we can focus on how to calculate each $B_j$ efficiently:&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
B_j=\sum_{i} k_{ij}P_i=\sum_{\lambda=0}{2c-1} \lambda \sum_{u(\lambda)} P_u&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
where the summation over $u(\lambda)$ is done only over points whose coefficient is $\lambda$. For example, if $c=3$ and we have $15$ points,&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
B_1=4P_1+3P_2+5P_3+1P_4+4P_5+6P_7+6P_8+3P_{14}+5P_{15}&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
We can split the summation by the coefficients $\lambda$, taking values from $1$ to $7$. For $\lambda=1$, $\sum_u P_u=P_4$ (because $P_4$ is the only one with coefficient $1$), for $\lambda=4$, $\sum_u P_u=P_1+P_5$, etc. We place all points with a common coefficient $\lambda$ into the $\ lambda$ bucket. Thus,&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
B_j=\sum_\lambda \lambda S_{j\lambda}=S_{j1}+2S_{j2}+3S_{j3}+4S_{4j}+5S_{5j}+6S_{j6}+7S_{j7}&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
We can calculate this with a minimum number of point additions using partial sums.&lt;br &#x2F;&gt;
$T_{j1}=S_{j7}$&lt;br &#x2F;&gt;
$T_{j2}=T_{j1}+S_{j6}$&lt;br &#x2F;&gt;
$T_{j3}=T_{j2}+S_{j5}$&lt;br &#x2F;&gt;
$T_{j4}=T_{j3}+S_{j4}$&lt;br &#x2F;&gt;
$T_{j5}=T_{j4}+S_{j3}$&lt;br &#x2F;&gt;
$T_{j6}=T_{j5}+S_{j2}$&lt;br &#x2F;&gt;
$T_{j7}=T_{j6}+S_{j1}$&lt;br &#x2F;&gt;
Each of these operations involves doing just one elliptic point addition. We can obtain the final result by summing these partial sums:&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
B_j=\sum T_{jk}&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;We can improve the calculations by changing the expansion of the coefficients $k_i$. In binary representation, the Hamming weight is the number of non-zero bits. Ideally, we would like this weight to be as small as possible to reduce the number of additions (For example, 65537, which is $2^{16}+1$, is used as the public key for the RSA cryptosystem in many implementations. The square and multiply algorithm requires only two multiplications). The average Hamming weight in a binary representation is $1&#x2F;2$; if we introduce a signed binary representation ($-1,0,1$), the average weight is reduced to $1&#x2F;3$, with the consequent decrease in the number of operations (on average).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bls-12-377&quot;&gt;BLS 12-377&lt;&#x2F;h2&gt;
&lt;p&gt;The curve which Aleo uses is called BLS 12-377. The base field (finite field) has order $q$ (a 377-bit prime) and has an embedding degree of 12. Both the order of the elliptic curve group $G_1$, $r$, and finite field are highly 2-adic (that is, both $q$ and $r$ can be written as $2^\alpha r+1$, where $r$ is an odd number and $\alpha$ is greater than $40$). The orders $q$ and $r$ are related by the embedding degree: $r \mid q^{12}-1$. The equation for the elliptic curve is&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
y2=x3+1&lt;br &#x2F;&gt;
$$&lt;&#x2F;p&gt;
&lt;p&gt;Additionally, we can build a second group $G_2$ over a quadratic field extension of $\mathbb{F}_q$; the equation of the curve is&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
y2=x3+B&lt;br &#x2F;&gt;
$$&lt;br &#x2F;&gt;
where $B$ is a parameter. For more information on the curve’s parameters, see &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;ark-bls12-377&#x2F;latest&#x2F;ark_bls12_377&#x2F;&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;BLS 12-377 is birrationally equivalent to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;draft-irtf-cfrg-hash-to-curve-05#appendix-B&quot;&gt;Montgomery and twisted Edwards’s curves&lt;&#x2F;a&gt;. This allows us to perform point addition and scalar multiplication faster by avoiding costly field inversions. In the case of Montgomery curves, it is possible to perform scalar multiplication in constant time, making the operation resistant to timing attacks.&lt;&#x2F;p&gt;
&lt;p&gt;Implementations of the BLS 12-377 curve and the (birrationally equivalent) twisted Edwards curve are given in this &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;arkworks-rs&#x2F;curves&quot;&gt;repository&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;BLS 12-377 is one of the pairing-friendly elliptic curves; these have applications such as short digital signatures that are efficiently aggregatable, polynomial commitment schemes, and single-round multi-key exchanges.&lt;br &#x2F;&gt;
The reason why we have two equations for the BLS curve and two groups is related to pairings. A pairing is a bilinear map: it takes two points, each from a group of prime order $r$. For technical reasons, these groups need to be different. As the original curve has only one group of order $r$, we need to extend the field to find other groups of order $r$. The embedding degree gives how much we have to extend the field to find those other groups. As a bonus, the extended field contains all the $r$-th roots of unity.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;a-note-on-field-extensions&quot;&gt;A note on Field Extensions&lt;&#x2F;h3&gt;
&lt;p&gt;The embedding degree is also the degree of the field extension we need to use. Familiar examples of field extensions are the real numbers, $\mathbb{R}$, (extending the field of rational numbers $\mathbb{Q}$, which is a transcendental extension) and the complex numbers, \( \mathbb{C} \) (extending \( \mathbb{R} \)). The latter cannot be further extended since there are no irreducible polynomials in \( \mathbb{C} \) (we say that the complex numbers are algebraically closed).&lt;&#x2F;p&gt;
&lt;p&gt;If we want to build a quadratic extension of \( \mathbb{F_{q}} \), \( \mathbb{F_{q^2}}\) we can think of it as a polynomial \( a_0+a_1x \), where \( a_0\) and \( a_1 \) are elements in \( \mathbb{F_q} \). The addition is straightforward since we add the independent and linear terms separately. For multiplication, given elements $a$ and $b$&lt;br &#x2F;&gt;
\[ a\times b = a_0b_0 +(a_0b_1+a_1b_0)x+a_1b_1 x^2\]&lt;&#x2F;p&gt;
&lt;p&gt;To avoid the problem of going outside linear polynomials, we can reduce the degree by using an irreducible polynomial, such as \( x^2+1 \) and setting \( x^2+1=0 \). If we replace the above equation,&lt;br &#x2F;&gt;
\[ a\times b = a_0b_0 - a_1b_1 +(a_0b_1+a_1b_0)x\]&lt;br &#x2F;&gt;
which resembles multiplication in complex numbers.&lt;&#x2F;p&gt;
&lt;p&gt;The conditions for choosing the polynomial are:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. It must have the same degree as the extension field (quadratic in our case).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. It must be irreducible in the field we are extending, meaning that we cannot factor it into smaller degree polynomials.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Arithmetic in \( \mathbb{F_{q^{12}}} \) is complicated and expensive. Luckily, we can perform a sextic twist so that the group \( G_2 \) is defined over \( \mathbb{F_{q^{2}}} \).&lt;&#x2F;p&gt;
&lt;p&gt;In practice, when we want to build a field extension such as \( \mathbb{F_{q^{12}}} \), we can proceed by extending smaller fields in a sequential form: a tower of extensions (such as \( \mathbb{Q}\rightarrow \mathbb{R}\rightarrow \mathbb{C} \)).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;faster-with-fft&quot;&gt;Faster with FFT&lt;&#x2F;h2&gt;
&lt;p&gt;The potential use for FFTs comes when implementing the primitives &lt;code&gt;ECADD&lt;&#x2F;code&gt; and &lt;code&gt;ECDBL&lt;&#x2F;code&gt;. We can do these operations in different coordinate systems. As stated &lt;a href=&quot;&#x2F;need-for-speed-elliptic-curves-chapter&#x2F;&quot;&gt;here&lt;&#x2F;a&gt;, projective coordinates are typically much faster because they avoid doing a finite field inversion, which is much more expensive than multiplications and additions.&lt;&#x2F;p&gt;
&lt;p&gt;When using projective coordinates, the calculations are faster because we trade divisions for multiplications. This means there are a lot of multiplications to be done, which is why we need efficient methods to multiply integers, where Karatsuba’s, Toom’s, or FFT algorithms might become appealing since we are dealing with &lt;a href=&quot;&#x2F;weird-ways-to-multiply-really-fast-with-karatsuba-toom-cook-and-fourier&#x2F;&quot;&gt;multiplication of large integers&lt;&#x2F;a&gt;. The optimal algorithm will depend on the size of the integers.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Verifiable AES: encryption using zero-knowledge proofs</title>
          <pubDate>Sat, 07 Jan 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/verifiable-encryption-using-zero-knowledge-proofs/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/verifiable-encryption-using-zero-knowledge-proofs/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/verifiable-encryption-using-zero-knowledge-proofs/">&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2023&#x2F;01&#x2F;download-1.jpeg&quot; alt=&quot;download-1&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;scope&quot;&gt;Scope&lt;&#x2F;h2&gt;
&lt;p&gt;At Lambdaclass, we want to try and test different cryptographic primitives that we can use to develop new products and applications to empower individuals and organizations, with an increased focus on security and requiring minimal trust between parties. In a series of posts, we will cover powerful primitives such as zero-knowledge proofs and fully homomorphic encryption, their applications, and use cases.&lt;&#x2F;p&gt;
&lt;p&gt;Encryption is transforming messages into random-looking texts to ensure confidentiality between two parties.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is our objective here?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
We want to generate proof allowing us to verify an encryption algorithm, ensuring it does what it was designed for.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why do we need this?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
We need this so that the user does not need to trust that the other party performed the encryption correctly; we replace trust with cryptographic proofs. There a few use cases where the receiver doesn’t want to decrypt the message unless it’s an emergency. But at the same time the receiver needs to make sure the encryption was correctly done so that the message is there waiting for him to open it.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;When is this useful?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Whenever we want to receive unknown data from untrusted parties in a secure way and be sure that we are not being cheated.&lt;&#x2F;p&gt;
&lt;p&gt;The repository of the project can be found &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;AES_zero_knowledge_proof_circuit&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;general-introduction&quot;&gt;General Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;Two parties (we will call them Alice and Bob) can communicate securely by using encryption schemes. We can broadly classify encryption schemes into the following categories:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Private (symmetric) key encryption. Commonly used methods are AES and ChaCha20.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Public (asymmetric) key encryption. Commonly used methods are RSA and ElGamal.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In symmetric encryption, Alice and Bob must agree on a shared key before sending messages. The problem is how they can agree on something if they can’t send messages to each other securely? Luckily, key agreement schemes, such as Diffie-Hellman, allow them to choose a secret key. We will focus here on the Elliptic Curve Diffie-Hellman protocol. The key ingredients are a finite field $\mathbb{F_p}$ (where $p$ is a large prime) and an elliptic curve $\mathcal{C}$ defined over $\mathbb{F_p}$ (which contains a subgroup of prime order $r$ with a generator $g$). It consists of the following steps:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Alice chooses an element $s_A$ in $\mathbb{F_p}$ and computes her public key, $g_A=s_A g$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Alice sends her public key $g_A$ to Bob.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Bob chooses an ephemeral key, $s_B$ in $\mathbb{F_p}$, and computes his public key $g_B=s_B g$ and the shared secret $g_{AB}=s_B g_A=s_As_B g$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Bob sends $g_B$ to Alice; Alice can also derive the shared secret by doing $g_{AB}=s_A g_B$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. They can calculate the symmetric key, $sk$, from the same key derivation function, $sk=KDF(g_{AB})$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Given a message $m$, Bob can encrypt it and send it to Alice by using a scheme such as AES and the key,&lt;br &#x2F;&gt;
$$c=E(m,sk)$$&lt;br &#x2F;&gt;
Any encryption scheme must satisfy the following consistency check:&lt;br &#x2F;&gt;
$$ m=D(E(m,sk),sk)=D(c,sk)$$&lt;&#x2F;p&gt;
&lt;h3 id=&quot;goal&quot;&gt;Goal&lt;&#x2F;h3&gt;
&lt;p&gt;Alice needs Bob to send her some secret, $sc$, which she does not know directly (otherwise, she would not need to communicate with Bob). She only knows a hash of $sc$ (for example, a Pedersen commitment). To send the secret, they need to agree on the key first. Then, Bob has to use that key to encrypt $sc$ and send it to Alice. The biggest problem is that Alice does not fully trust Bob. He could encrypt another message or use a different key. We want to develop a scheme where Bob can prove to Alice that he encrypted the message $sc$ using the key $sk$ without obviously leaking information about the key or the message.&lt;&#x2F;p&gt;
&lt;p&gt;Concisely, we can say that the goal is the following: Bob has to prove that the ciphertext $c$ is the result of the encryption of $m$ (whose commitment is $cm_m$) under a scheme (AES) using the symmetric key $sk$.&lt;&#x2F;p&gt;
&lt;p&gt;The following list shows all the input variables, indicating whether they are sensitive (should be secret) or not:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Secret: Bob&amp;#39;s ephemeral key, $s_B$, the message, $sc$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Public&#x2F;Not secret: ciphertext, $c$, Alice and Bob&amp;#39;s public keys, $g_A$ and $g_B$, the commitment to the message $cm_{sc}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;All other elements, such as the curve and finite field, have been previously agreed on and are publicly known.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;steps&quot;&gt;Steps&lt;&#x2F;h3&gt;
&lt;p&gt;The following calculations would allow Bob to achieve his goal:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Using his ephemeral key, show that $g_B==s_B g$. If he succeeds, he gets a boolean variable, $b_1=1$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Using $s_B$ and $g_A$, he derives $sk$, encrypts $m$ and shows that $c==E(sc,sk)$. If this passes, he gets $b_2=1$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Using $sc$, he computes $cm_m$ and compares whether $cm_{sc}=\mathrm{commit}(sc)$. If this is correct, he gets $b_3=1$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. If $b_1 \wedge b_2 \wedge b_3=1$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The big question is how can he prove all these conditions without revealing sensitive information? Here is where zero-knowledge proofs come into play.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-are-zero-knowledge-proofs&quot;&gt;What are zero-knowledge proofs?&lt;&#x2F;h2&gt;
&lt;p&gt;Zero-knowledge proofs (ZKP) are powerful cryptographic primitives which allow us to prove the validity of a statement or computation without revealing information other than the truth of the statement. We can represent any bounded computation as an arithmetic circuit, $C$. ZKP allow us to prove that we know some secret $w$ and public known values, $x$, such that $C(z=(x,w))=0$. In our case, the circuit is given by the computation performing checks 1-4. The variable $w$ contains $s_B$ and $sc$, $w=(s_B,sc)$. The public instance $x$ contains $g_A,g_B,c,cm_{sc}$ and the intended output, $1$, $x=(g_A,g_B,c,cm_{sc},1)$.&lt;&#x2F;p&gt;
&lt;p&gt;ZKP use polynomials and their properties to prove statements. Zk-SNARKs are ZKP with the following additional properties: succinctness (proofs are brief and faster to verify than naïve re-execution of the calculation) and non-interactive (prover and verifier do not need to exchange messages). There are two building blocks to most SNARKs: an information-theoretic device (most commonly, polynomial interactive oracle proofs, PIOP) and a cryptographic commitment scheme (in particular, polynomial commitment schemes, PCS). In this case, we will work with Marlin (PIOP) and the Kate-Zaverucha-Goldberg (KZG) commitment scheme.&lt;&#x2F;p&gt;
&lt;p&gt;The first step is to transform our code into arithmetic circuits or, equivalently, as a (quadratic) rank-one constraint system (R1CS). The latter is a system of equations of the form:&lt;br &#x2F;&gt;
$$ Az\cdot Bz=Cz$$&lt;br &#x2F;&gt;
where $A,B,C$ are matrices of the same size and $\cdot$ indicates the componentwise product.&lt;&#x2F;p&gt;
&lt;p&gt;Then, we will express these constraints as polynomials and generate the proof. Polynomial commitments come into play to ensure the prover does not cheat and make the protocol zero-knowledge. We will now focus on the proof generation and verification of step 2 (AES encryption).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;encryption-using-the-advanced-encryption-standard-aes&quot;&gt;Encryption using the Advanced Encryption Standard (AES)&lt;&#x2F;h2&gt;
&lt;p&gt;AES is a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Block_cipher&quot;&gt;block cipher&lt;&#x2F;a&gt;: it takes a 128-bit message (interpreted as a $4\times 4$ matrix of bytes) and a secret key, $sk$, and performs a pseudorandom permutation. AES has a round function, which is applied a fixed number of times, each using a different key, to encrypt the message. We use the key scheduling function to derive all the round keys from the master key, $sk$. The round function consists of the following operations:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Add a round key.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Substitute bytes (S-boxes).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Shift rows.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Mix columns.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Each of these operations is necessary to guarantee that AES is secure. Repeating the operations in multiple rounds guarantees that elements are sufficiently shuffled and mixed, leading to semantic security (that is, we cannot learn anything about the plaintext just by looking at the ciphertext).&lt;&#x2F;p&gt;
&lt;p&gt;AES is described in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;nvlpubs.nist.gov&#x2F;nistpubs&#x2F;FIPS&#x2F;NIST.FIPS.197.pdf&quot;&gt;NIST standard&lt;&#x2F;a&gt;. AES needs to use a mode to deal with messages of size greater than 128 bits. Some standard modes are AES-CBC (cipher block chaining) and AES-GCM (Galois counter mode, which provides authenticated encryption).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;add-round-key&quot;&gt;Add round key&lt;&#x2F;h3&gt;
&lt;p&gt;This is the step that makes the encryption depend on the key. For each round, a round key is derived from the master key ($sk$). The function is straightforward: it consists of an XOR operation between the round key and the state (the message or its transformations). To make it consistent with the code,&lt;br &#x2F;&gt;
$$ \mathrm{ret}=\mathrm{input_text}\oplus \mathrm{key} $$&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn add_round_key(input_text: &amp;amp;[u8], key: &amp;amp;[u8; 16]) -&amp;gt; [u8; 16] {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut ret = [0_u8; 16];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let _ = zip(input_text, key)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .map(|(cell_i, key_i)| cell_i ^ key_i)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .collect_slice(&amp;amp;mut ret[..]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ret&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The XOR operation appears frequently in cryptography. Unless we know the key, we have a 50 % chance of guessing the correct value for each bit, which is as good as flipping a fair coin and guessing.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;substitute-bytes-s-boxes&quot;&gt;Substitute bytes &#x2F; S-boxes&lt;&#x2F;h3&gt;
&lt;p&gt;The S-boxes add the non-linear component to the block cipher. Here, each byte of the matrix is one-to-one mapped onto another byte. Here we present the complete code for the S-boxes, but this is done via a lookup table in practice. This will prove helpful in generating the proof since looking at the table requires fewer constraints than the whole operation.&lt;&#x2F;p&gt;
&lt;p&gt;In AES, we interpret bytes as polynomials of degree at most $7$, with coefficients in ${0,1}$. For example, the byte $10010110$ is interpreted as the polynomial $x7+x4+x^2+x$, and $00100001$ is $x^5+1$. We can multiply polynomials, but if the degree is larger than 7, we have to take the remainder of the product and the irreducible polynomial $m(x)=x8+x4+x^3+x+1$.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn rotate_left(byte: u8, n: u8) -&amp;gt; u8 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    (byte &amp;lt;&amp;lt; n) | (byte &amp;gt;&amp;gt; (8 - n))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn substitute_byte(byte: u8) -&amp;gt; Result&amp;lt;u8&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if byte == 0x00 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return Ok(0x63);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut p = 1_u8;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut q = 1_u8;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut sbox = [0_u8; 256];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;* loop invariant: p * q == 1 in the Galois field *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    loop {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;* multiply p by 3 *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        p = p ^ (p &amp;lt;&amp;lt; 1_u8) ^ (((p &amp;gt;&amp;gt; 7_u8) &amp;amp; 1) * 0x1B);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;* divide q by 3 (equals multiplication by 0xf6) *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        q ^= q &amp;lt;&amp;lt; 1_u8;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        q ^= q &amp;lt;&amp;lt; 2_u8;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        q ^= q &amp;lt;&amp;lt; 4_u8;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        q ^= ((q &amp;gt;&amp;gt; 7_u8) &amp;amp; 1) * 0x09;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;* compute the affine transformation *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let xformed =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            q ^ rotate_left(q, 1) ^ rotate_left(q, 2) ^ rotate_left(q, 3) ^ rotate_left(q, 4);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let p_as_usize: usize = p.try_into()?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        *sbox&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .get_mut(p_as_usize)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .to_anyhow(&amp;quot;Error saving substitution box value&amp;quot;)? = xformed ^ 0x63;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        if p == 1 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            break;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let byte_index: usize = byte.try_into()?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Ok(*sbox&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .get(byte_index)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .to_anyhow(&amp;quot;Error getting substitution box value&amp;quot;)?)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In the first step, each byte is mapped to its multiplicative inverse. If $p(x)$ is the polynomial associated with the byte, there exists another polynomial $q(x)$ such that $p(x)q(x)\equiv 1 \pmod{m(x)}$ (there is $q(x)$ such that $m(x)$ divides $p(x)q(x)-1$). The only edge case is the 0 byte, which has no inverse and is mapped onto itself (this is the if at the beginning of the function).&lt;&#x2F;p&gt;
&lt;p&gt;The following steps give the calculation of the inverse:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let mut p = 1_u8;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let mut q = 1_u8;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;p = p ^ (p &amp;lt;&amp;lt; 1_u8) ^ (((p &amp;gt;&amp;gt; 7_u8) &amp;amp; 1) * 0x1B);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;q ^= q &amp;lt;&amp;lt; 1_u8;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;q ^= q &amp;lt;&amp;lt; 2_u8;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;q ^= q &amp;lt;&amp;lt; 4_u8;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;q ^= ((q &amp;gt;&amp;gt; 7_u8) &amp;amp; 1) * 0x09;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next, we perform an affine transformation on the inverse, which combines the bits at different positions:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let xformed =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            q ^ rotate_left(q, 1) ^ rotate_left(q, 2) ^ rotate_left(q, 3) ^ rotate_left(q, 4);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This last operation consists of four left rotations and four XOR operations.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;shiftrows&quot;&gt;ShiftRows&lt;&#x2F;h3&gt;
&lt;p&gt;This function changes the order of the elements in each row by performing a cyclic shift. The second row shifts each element one place to the left, the third one two places, and the fourth three. This transformation is linear; the constraints associated with it will also be linear.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn shift_rows(bytes: &amp;amp;[u8; 16], cs: &amp;amp;ConstraintSystemRef&amp;lt;ConstraintF&amp;gt;) -&amp;gt; Result&amp;lt;[u8; 16]&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Add each number to the constraint system.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for byte in bytes {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        UInt8::new_witness(ark_relations::ns!(cs, &amp;quot;shift_rows_witness&amp;quot;), || Ok(byte))?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Turn the bytes into the 4x4 AES state matrix.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; The matrix is represented by a 2D array,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; where each array is a row.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; That is, let&amp;#39;s suppose that the flattened_bytes variable&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; is formed by the bytes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; [b0, ..., b15]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Then the AES state matrix will look like this:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; b0, b4, b8, b12,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; b1, b5, b9, b13,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; b2, b6, b10, b14,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; b3, b7, b11, b15&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; And our array will look like this:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;[&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;  [b0, b4, b8, b12],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;  [b1, b5, b9, b13],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;  [b2, b6, b10,b14],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;  [b3, b7, b11,b15]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut state_matrix = [[0_u8; 4]; 4];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for (i, state) in state_matrix.iter_mut().enumerate() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        *state = [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            *(bytes.get(i).context(&amp;quot;Out of bounds&amp;quot;))?,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            *(bytes.get(i + 4).context(&amp;quot;Out of bounds&amp;quot;)?),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            *(bytes.get(i + 8).context(&amp;quot;Out of bounds&amp;quot;)?),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            *(bytes.get(i + 12).context(&amp;quot;Out ouf bounds&amp;quot;)?),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Rotate every state matrix row (u8 array) as specified by&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; the AES cipher algorithm.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for (rotations, bytes) in state_matrix.iter_mut().enumerate() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F; For the moment, this operation does not generate constraints in the&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F; circuit, but it should in the future.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        bytes.rotate_left(rotations);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Turn the rotated arrays into a flattened&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F;16-byte array, ordered by column.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut flattened_matrix = [0_u8; 16];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for i in 0..4 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        for j in 0..4 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            *flattened_matrix&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                .get_mut((i * 4) + j)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                .to_anyhow(&amp;quot;Error getting element of flattened_matrix slice&amp;quot;)? = *state_matrix&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                .get(j)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                .to_anyhow(&amp;quot;Error getting element of state_matrix&amp;quot;)?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                .get(i)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                .to_anyhow(&amp;quot;Error getting element of state_matrix&amp;quot;)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Ok(flattened_matrix)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;mixcolumns&quot;&gt;MixColumns&lt;&#x2F;h3&gt;
&lt;p&gt;The MixColumn function operates over each column of the state matrix. Every four-byte column is interpreted as a polynomial degree four polynomial, modulo $x^4+1$. We can view each column as the result of a linear combination. Each byte can be multiplied by 1, 2 or 3. If the result exceeds the modulus, we have to reduce the result, similar to what we did in substitute bytes.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn gmix_column(input: [u8; 4]) -&amp;gt; Option&amp;lt;[u8; 4]&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut b: [u8; 4] = [0; 4];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;* The array &amp;#39;a&amp;#39; is simply a copy of the input array &amp;#39;r&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     * The array &amp;#39;b&amp;#39; is each element of the array &amp;#39;a&amp;#39; multiplied by 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     * in Rijndael&amp;#39;s Galois field&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     * a[n] ^ b[n] is element n multiplied by 3 in Rijndael&amp;#39;s Galois field *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for (i, c) in input.iter().enumerate() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let h = (c &amp;gt;&amp;gt; 7_usize) &amp;amp; 1; &#x2F;* arithmetic right shift, thus shifting in either zeros or ones *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        *b.get_mut(i)? = (c &amp;lt;&amp;lt; 1_usize) ^ (h * 0x1B); &#x2F;* implicitly removes high bit because b[c] is an 8-bit char, so we xor by 0x1b and not 0x11b in the next line *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;* Rijndael&amp;#39;s Galois field *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Some([&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        b.first()? ^ input.get(3)? ^ input.get(2)? ^ b.get(1)? ^ input.get(1)?,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        b.get(1)? ^ input.first()? ^ input.get(3)? ^ b.get(2)? ^ input.get(2)?,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        b.get(2)? ^ input.get(1)? ^ input.first()? ^ b.get(3)? ^ input.get(3)?,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        b.get(3)? ^ input.get(2)? ^ input.get(1)? ^ b.first()? ^ input.first()?,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn mix_columns(input: &amp;amp;[u8; 16]) -&amp;gt; Option&amp;lt;[u8; 16]&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut ret = [0_u8; 16];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for (pos, column) in input.chunks(4).enumerate() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let column_aux = [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            *column.first()?,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            *column.get(1)?,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            *column.get(2)?,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            *column.get(3)?,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let column_ret = gmix_column(column_aux)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;&#x2F; put column_ret in ret:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        *ret.get_mut(pos * 4)? = *column_ret.first()?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        *ret.get_mut(pos * 4 + 1)? = *column_ret.get(1)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        *ret.get_mut(pos * 4 + 2)? = *column_ret.get(2)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        *ret.get_mut(pos * 4 + 3)? = *column_ret.get(3)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Some(ret)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;key-scheduling&quot;&gt;Key scheduling&lt;&#x2F;h3&gt;
&lt;p&gt;This function derives the round keys from the master key.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn derive_keys(secret_key: &amp;amp;[u8; 16]) -&amp;gt; Result&amp;lt;[[u8; 16]; 11]&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    const ROUND_CONSTANTS: [u32; 10] = [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        u32::from_be_bytes([0x01, 0x00, 0x00, 0x00]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        u32::from_be_bytes([0x02, 0x00, 0x00, 0x00]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        u32::from_be_bytes([0x04, 0x00, 0x00, 0x00]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        u32::from_be_bytes([0x08, 0x00, 0x00, 0x00]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        u32::from_be_bytes([0x10, 0x00, 0x00, 0x00]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        u32::from_be_bytes([0x20, 0x00, 0x00, 0x00]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        u32::from_be_bytes([0x40, 0x00, 0x00, 0x00]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        u32::from_be_bytes([0x80, 0x00, 0x00, 0x00]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        u32::from_be_bytes([0x1B, 0x00, 0x00, 0x00]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        u32::from_be_bytes([0x36, 0x00, 0x00, 0x00]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut result = [0_u32; 44];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    result[0] = to_u32(&amp;amp;secret_key[..4]).to_anyhow(&amp;quot;Error converting to u32&amp;quot;)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    result[1] = to_u32(&amp;amp;secret_key[4..8]).to_anyhow(&amp;quot;Error converting to u32&amp;quot;)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    result[2] = to_u32(&amp;amp;secret_key[8..12]).to_anyhow(&amp;quot;Error converting to u32&amp;quot;)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    result[3] = to_u32(&amp;amp;secret_key[12..16]).to_anyhow(&amp;quot;Error converting to u32&amp;quot;)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for i in 4..44 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        if i % 4 == 0 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let substituted_and_rotated = to_u32(&amp;amp;substitute_word(rotate_word(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                *result.get(i - 1).to_anyhow(&amp;quot;Error converting to u32&amp;quot;)?,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ))?)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .to_anyhow(&amp;quot;Error converting to u32&amp;quot;)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            *result.get_mut(i).to_anyhow(&amp;quot;Error getting elem&amp;quot;)? =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                (result.get(i - 4).to_anyhow(&amp;quot;Error getting elem&amp;quot;)? ^ (substituted_and_rotated))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    ^ ROUND_CONSTANTS&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                        .get(i &#x2F; 4 - 1)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                        .to_anyhow(&amp;quot;Error getting elem&amp;quot;)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        } else {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            *result.get_mut(i).to_anyhow(&amp;quot;Error getting elem&amp;quot;)? =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                result.get(i - 4).to_anyhow(&amp;quot;Error getting elem&amp;quot;)?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    ^ result.get(i - 1).to_anyhow(&amp;quot;Error getting elem&amp;quot;)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut ret = [[0_u8; 16]; 11];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for (i, elem) in result.chunks(4).enumerate() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        elem.iter()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .flat_map(|e| e.to_be_bytes())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .collect_slice(&amp;amp;mut ret.get_mut(i).to_anyhow(&amp;quot;Error getting elem&amp;quot;)?[..]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Ok(ret)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn to_u32(value: &amp;amp;[u8]) -&amp;gt; Option&amp;lt;u32&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let array_aux: [u8; 4] = [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        *value.first()?,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        *value.get(1)?,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        *value.get(2)?,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        *value.get(3)?,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Some(u32::from_be_bytes(array_aux))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn rotate_word(input: u32) -&amp;gt; [u8; 4] {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let bytes: [u8; 4] = input.to_be_bytes();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        *bytes.get(1).unwrap_or(&amp;amp;0),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        *bytes.get(2).unwrap_or(&amp;amp;0),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        *bytes.get(3).unwrap_or(&amp;amp;0),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        *bytes.first().unwrap_or(&amp;amp;0),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;circuits-and-gadgets&quot;&gt;Circuits and gadgets&lt;&#x2F;h2&gt;
&lt;p&gt;If we tried hardcoding the circuit of AES, this would be an impossible task, given the kind and number of operations we have to perform. For example, suppose we want to perform the XOR operation between one byte of the message and the round key, $st[i] \oplus rk[i]=st^\prime [i]$. First, we need to decompose each byte into its constituent bits and check that each of them is indeed either $0$ or $1$:&lt;br &#x2F;&gt;
$st[i,j]\times st[i,j]=st[i,j]$&lt;br &#x2F;&gt;
$rk[i,j]\times rk[i,j]=rk[i,j]$&lt;br &#x2F;&gt;
$st^\prime[i,j]\times st\prime[i,j]=st\prime[i,j]$&lt;br &#x2F;&gt;
Next, we need to compute the XOR operation between bits,&lt;br &#x2F;&gt;
$2st[i,j]\times rk[i,j]=st[i,j]+rk[i,j]-st^\prime[i,j]$&lt;br &#x2F;&gt;
We have eight equations per byte, so there are 32 constraints for every byte XOR (we could remove the checks for $st^\prime$ since the XOR guarantees that they are 0 or 1, reducing the count to 24). Every add round key function takes 16 bytes, so we take 512 (or 384) constraints per round!&lt;&#x2F;p&gt;
&lt;p&gt;We can implement a gadget that adds the constraints corresponding to its binary decomposition whenever we define a new byte variable. We can also implement an XOR gadget between bytes, adding the constraints for the operation. The following code makes use of gadgets for &lt;code&gt;u8&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;use ark_r1cs_std::bits::uint8::UInt8;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let a = UInt8::new_input(cs, || Ok(1))?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let result = a.xor(&amp;amp;a)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let zero = UInt8::constant(0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;result.enforce_equal(&amp;amp;zero)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;What happens with the substitution boxes? We could implement a gadget for the whole operation. The problem is that the number of constraints scales super fast! There are more than 10 XOR operations per step, which is time-consuming. The s-boxes are generally obtained from a lookup table, which has all the possible output values precomputed.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn substitute_byte(byte: &amp;amp;UInt8Gadget, lookup_table: &amp;amp;[UInt8Gadget]) -&amp;gt; Result&amp;lt;UInt8Gadget&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Ok(UInt8Gadget::conditionally_select_power_of_two_vector(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;byte.to_bits_be()?,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        lookup_table,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    )?)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn substitute_bytes(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    bytes: &amp;amp;[UInt8Gadget],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    lookup_table: &amp;amp;[UInt8Gadget],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; Result&amp;lt;Vec&amp;lt;UInt8Gadget&amp;gt;&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ensure!(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        bytes.len() == 16,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;quot;Input must be 16 bytes length when substituting bytes&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut substituted_bytes = vec![];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for byte in bytes {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        substituted_bytes.push(substitute_byte(byte, lookup_table)?);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ensure!(substituted_bytes.len() == 16, &amp;quot;Error substituting bytes&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Ok(substituted_bytes)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;proof-generation&quot;&gt;Proof generation&lt;&#x2F;h2&gt;
&lt;p&gt;The first step to generating the proof is to obtain the proving and verification keys. These are derived from the structured reference string (SRS) obtained from a secure multiparty computation.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let (proving_key, verifying_key) = synthesize_keys(message_length)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here is the definition of the synthesize keys function:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn synthesize_keys(plaintext_length: usize) -&amp;gt; Result&amp;lt;(ProvingKey, VerifyingKey)&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let rng = &amp;amp;mut simpleworks::marlin::generate_rand();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let universal_srs =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        simpleworks::marlin::generate_universal_srs(1_000_000, 250_000, 3_000_000, rng)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let constraint_system = ConstraintSystem::&amp;lt;ConstraintF&amp;gt;::new_ref();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let default_message_input = vec![0_u8; plaintext_length];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let default_secret_key_input = [0_u8; 16];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let default_ciphertext_input = vec![0_u8; plaintext_length];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut message_circuit: Vec&amp;lt;UInt8Gadget&amp;gt; = Vec::with_capacity(default_message_input.len());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for byte in default_message_input {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        message_circuit.push(UInt8Gadget::new_witness(constraint_system.clone(), || {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            Ok(byte)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        })?);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut secret_key_circuit: Vec&amp;lt;UInt8Gadget&amp;gt; =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Vec::with_capacity(default_secret_key_input.len());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for byte in default_secret_key_input {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        secret_key_circuit.push(UInt8Gadget::new_witness(constraint_system.clone(), || {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            Ok(byte)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        })?);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut ciphertext_circuit: Vec&amp;lt;UInt8Gadget&amp;gt; =&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Vec::with_capacity(default_ciphertext_input.len());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for byte in default_ciphertext_input {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ciphertext_circuit.push(UInt8Gadget::new_input(constraint_system.clone(), || {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            Ok(byte)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        })?);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let _ciphertext = encrypt_and_generate_constraints(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;message_circuit,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;secret_key_circuit,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;ciphertext_circuit,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        constraint_system.clone(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    );&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    simpleworks::marlin::generate_proving_and_verifying_keys(&amp;amp;universal_srs, constraint_system)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Since this is only a test, we generate the SRS from a function instead of reading it from the result of the multiparty computation.&lt;&#x2F;p&gt;
&lt;p&gt;We now define a function that contains all the steps to generate the proof:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn encrypt(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    message: &amp;amp;[u8],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    secret_key: &amp;amp;[u8; 16],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ciphertext: &amp;amp;[u8],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    proving_key: ProvingKey,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; Result&amp;lt;MarlinProof&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let rng = &amp;amp;mut simpleworks::marlin::generate_rand();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let constraint_system = ConstraintSystem::&amp;lt;ConstraintF&amp;gt;::new_ref();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut message_circuit: Vec&amp;lt;UInt8Gadget&amp;gt; = Vec::with_capacity(message.len());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for byte in message {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        message_circuit.push(UInt8Gadget::new_witness(constraint_system.clone(), || {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            Ok(byte)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        })?);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut secret_key_circuit: Vec&amp;lt;UInt8Gadget&amp;gt; = Vec::with_capacity(secret_key.len());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for byte in secret_key {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        secret_key_circuit.push(UInt8Gadget::new_witness(constraint_system.clone(), || {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            Ok(byte)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        })?);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut ciphertext_circuit: Vec&amp;lt;UInt8Gadget&amp;gt; = Vec::with_capacity(ciphertext.len());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for byte in ciphertext {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        ciphertext_circuit.push(UInt8Gadget::new_input(constraint_system.clone(), || {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            Ok(byte)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        })?);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    encrypt_and_generate_constraints(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;message_circuit,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;secret_key_circuit,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;ciphertext_circuit,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        constraint_system.clone(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    )?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; Here we clone the constraint system because deep down when generating&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; the proof the constraint system is consumed and it has to have one&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; reference for it to be consumed.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let cs_clone = (*constraint_system&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .borrow()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .ok_or(&amp;quot;Error borrowing&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .map_err(|e| anyhow!(&amp;quot;{}&amp;quot;, e))?)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    .clone();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let cs_ref_clone = ConstraintSystemRef::CS(Rc::new(RefCell::new(cs_clone)));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let proof = simpleworks::marlin::generate_proof(cs_ref_clone, proving_key, rng)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Ok(proof)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally, we run the following lines to get the proof:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let message = [1_u8; 16]; \\Example message&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let secret_key = [0_u8; 16]; \\Example key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let proof = encrypt(&amp;amp;message, &amp;amp;secret_key, &amp;amp;primitive_ciphertext, proving_key)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;verification&quot;&gt;Verification&lt;&#x2F;h2&gt;
&lt;p&gt;To verify the proof, we first encapsulate all the steps in this function, reading the verifying key, the proof and the ciphertext:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn verify_encryption(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    verifying_key: VerifyingKey,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    proof: &amp;amp;MarlinProof,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ciphertext: &amp;amp;[u8],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;) -&amp;gt; Result&amp;lt;bool&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut ciphertext_as_field_array = vec![];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    for byte in ciphertext {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let field_array = byte_to_field_array(*byte);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        for field_element in field_array {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            ciphertext_as_field_array.push(field_element);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    simpleworks::marlin::verify_proof(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        verifying_key,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;ciphertext_as_field_array,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        proof,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;amp;mut simpleworks::marlin::generate_rand(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then, we run and check the result&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let result = verify_encryption(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    verifying_key,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;amp;proof,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;amp;primitive_ciphertext&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)?;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;assert!(result);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;AES is the most widely used encryption method. In this post, we addressed the problem of offering cryptographic proof for the correct execution of the AES encryption function for a given plaintext-key pair. Using the Arkworks library, we implemented AES and obtained its representation as an R1CS. Afterward, using Marlin and the Kate-Zaverucha-Goldberg polynomial commitment scheme, we generated a cryptographic proof. The verifier, using the ciphertext as input, can verify the proof to assert the correct execution of the function.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Fully private applications: A ZEXE protocol</title>
          <pubDate>Thu, 05 Jan 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/fully-private-applications-a-zexe-protocol/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/fully-private-applications-a-zexe-protocol/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/fully-private-applications-a-zexe-protocol/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;One of the key issues in the current world is how to achieve consensus between trustless parties. Distributed ledgers have become popular since the advent of cryptocurrencies, built over a technology known as blockchain. One of the main problems is that these ledgers offer limited privacy and are quite constrained on the kind of programs they can run. Aleo provides a full-stack approach for writing private applications. One of its core components is the ZEXE protocol, which is the first ledger system in which applications can be run privately, trustlessly, and can be easily scaled.&lt;&#x2F;p&gt;
&lt;p&gt;As we mentioned before, ledger-based systems can support rich applications, but often suffer from two main drawbacks:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Validating a transaction requires re-executing the state transition it refers to.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Transactions are not private; they reveal information about users and the state of the system.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The latter creates a large number of issues where privacy is critical, since it may leak relevant information regarding one’s medical history, payment records, acquaintances and trading partners, etc, which can be used to the advantage of malicious parties.&lt;&#x2F;p&gt;
&lt;p&gt;The first drawback, on the other side, creates scalability issues, since every transition has to be recomputed by every device forming the network (which can have very different computational power), with the weakest one acting as a bottleneck. This has led to the introduction of mechanisms such as gas to make users pay more for expensive computations and discourage denial-of-service attacks.&lt;&#x2F;p&gt;
&lt;p&gt;Some protocols, such as Zerocash, provide privacy-preserving payments and Hawk allows for state transitions where private data remains hidden from third parties. We can say that they achieve data-privacy, but not function privacy, because the transition function being executed is not hidden (even though the input and output parameters may be secret). Function privacy means that an observer is unable to distinguish between different computations performed offline from one another.&lt;&#x2F;p&gt;
&lt;p&gt;ZEXE’s aim is to provide a scalable solution to these problems, where both data and function privacy are achieved. This can act as a solid foundation for new forms of data sharing, financial systems, and governance. The main ideas are based on the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. We can run programs offline (or delegate their execution to a powerful but trustless server) and obtain a proof attesting to the validity of the computation.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. We can quickly verify the validity of a computation or transition by checking the proof; this operation will be less computationally expensive than performing the whole computation.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Transitions can be accepted into the layer by checking the proofs.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The proofs will have to satisfy two properties for this system to work:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Privacy: The proofs should not reveal anything, other than the validity of the statement.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Succinctness: the proof can be validated in a time that is independent of the cost of the computation to whose correctness it attests.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ZEXE will offer users rich functionality, with offline computations used to realize state transitions of multiple applications, running atop the same ledger. The shared execution environment provides the following properties:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Extensibility: users can run arbitrary functions, without seeking anyone&amp;#39;s permission.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Isolation: functions of malicious users cannot interfere with the computations and data of honest users.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Interprocess communication: functions may exchange data with one another.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In the next section, we will cover the main ingredients and how the protocol works: terms such as zk-SNARKs, elliptic curve cryptography, pairings, etc, will be demystified.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ingredients&quot;&gt;Ingredients&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;decentralized-private-computation&quot;&gt;Decentralized private computation&lt;&#x2F;h3&gt;
&lt;p&gt;The core of ZEXE relies on a new cryptographic primitive to perform computations on a ledger, known as decentralized private computation (DPC), by extending the ideas on how Zerocash works. We can perform the computations offline and present a proof asserting that it is a valid transition on the ledger; the proof can be quickly verified by the nodes of the ledger (much faster than it would take each of them to repeat our original calculation) and be accepted. One disadvantage is that, even though proofs are fast to verify, their generation can be quite expensive (remember that we want to allow the user to run arbitrary programs; thus, the proof system should be able to cope with many different kinds of statements and instructions). We can leverage the construction and create a delegable DPC: we can make trustless servers or devices carry out computations and provide us with proofs that the computations were performed as they should and without leaking relevant information.&lt;&#x2F;p&gt;
&lt;p&gt;The building blocks of the DPC schemes are:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Collision-resistant hash function.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Pseudorandom function family.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Commitments.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * NIZK: non-interactive arguments of knowledge (the proofs).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To enable delegatable DPC we need a further ingredient: randomized signatures.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;records&quot;&gt;Records&lt;&#x2F;h3&gt;
&lt;p&gt;In Zerocash, when coins are created, their &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Commitment_scheme&quot;&gt;commitments&lt;&#x2F;a&gt; (1) are published on the ledger; when they are consumed, their serial number is published. Every transaction tells that some “old” coins were consumed to create “new” coins: it has the serial number of the spent coins, the commitments of the “new” coins, and a proof that the values of the “old” and “new” coins add up (the proof shows that it was a valid transaction and that no extra money was created or destroyed during the exchange). The transaction is private because we don’t know the values or addresses of the coins exchanged. Since the serial number is published, no coin can be spent more than once.&lt;&#x2F;p&gt;
&lt;p&gt;The units of data, called records (the coins in ZEXE), are bound to arbitrary programs and specify the conditions under which a record can be created and consumed. We can think of them as having tokens or coins that we can spend to run programs and get proofs that what we have done is valid (like in arcade games). To extend the idea to arbitrary functions, we can think of a record as storing some arbitrary data payload. The commitment of a record is published whenever a record is created and its serial number is revealed when it is consumed. A transaction on the ledger contains information on the records spent and created during the operation and a proof that invoking a function on the data payload of the old record produces the data payload of the new records.&lt;&#x2F;p&gt;
&lt;p&gt;A record structure contains:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The address public key.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The data payload.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Birth and death predicates.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * A serial number nonce.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The record&amp;#39;s commitment.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The record’s commitment is a commitment to all the aforementioned attributes (public key, payload, birth and death predicates, and the serial nonce).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-record-nano-kernel-rnk&quot;&gt;The Record Nano Kernel (RNK)&lt;&#x2F;h3&gt;
&lt;p&gt;This is an execution environment operating over the records. We can think of it as a kind of operating system for the ledger. It provides process isolation, data ownership, handling of interprocess communications, etc. The RNK ensures that birth and death predicates are met so that during the record’s lifetime certain constraints are enforced. In other words, depending on the input data, predicates can decide whether certain interactions with that record are allowed or not.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;transitions-and-transactions&quot;&gt;Transitions and transactions&lt;&#x2F;h3&gt;
&lt;p&gt;On the ledger, transactions contain the following information:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. The serial number of all consumed records during the transaction.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. The commitments of all the records created in the transaction.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. A memorandum. This is a string associated with the transaction.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Other construction-specific information.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Recently, transactions have been updated and are made up of transitions. In other words, a transaction is composed of several transitions.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;zk-snarks&quot;&gt;zk-SNARKs&lt;&#x2F;h3&gt;
&lt;p&gt;zero-knowledge succinct non-interactive arguments of knowledge (zk-SNARKs for friends) are cryptographic primitives which allow one party (the prover) to convince another one (the verifier) of the validity of a certain statement&#x2F;calculation. It has the following properties:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Completeness: Given a statement and a witness (for example, I know $x$ such that $g^x=b$), the prover can convince an honest verifier.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Soundness: A malicious prover cannot convince the verifier of a false statement.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Zero-knowledge: the proof reveals nothing else other than the validity of the statement; it does not reveal the witness.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Succinctness: the proof is small and &amp;quot;easy&amp;quot; to verify.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Given that we want to let users perform arbitrary computations, we need the proof system to be able to handle lots of different statements in a rather general way; this will represent the largest cost in the ZEXE protocol. These statements fall in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;NP_(complexity)&quot;&gt;class NP&lt;&#x2F;a&gt; (non-deterministic polynomial time), which are problems that can be efficiently verified in polynomial time. The NP statements that we need to prove contain predicates defined by the user, which would force us to build everything on zk-SNARKs for universal computations, which depend on very expensive tools. An advantage of zk-SNARKs, verification is done in constant-time; in other words, the amount of time needed to verify is independent of the size of the computation. This is a desirable property from the point of view of privacy because different verification times could give hints on what kind of operations are being performed.&lt;&#x2F;p&gt;
&lt;p&gt;To tackle this problem, the protocol relies on recursive proof composition: instead of checking the arbitrary NP statement, we can check succinct proofs attesting to the validity of the statement. This way, we can avoid zk-SNARKs for universal computations and can instead focus on succinct proofs, which can be hardcoded in the statement. We can achieve the goal by making use of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2012&#x2F;095.pdf&quot;&gt;proof carrying data&lt;&#x2F;a&gt;: we append to a message a succinct proof that asserts that the result is consistent. For example, instead of checking directly the birth and death predicates (which can be quite general), we can verify succinct proofs $\pi_b$ and $\pi_d$ attesting to the satisfaction of these predicates. Since the inner proofs are succinct, it is (relatively) inexpensive to verify them. Moreover, since the outer proofs are zero knowledge (therefore, not revealing anything that is used to generate the proof), the inner proofs need not be zero-knowledge, further simplifying the calculations.&lt;&#x2F;p&gt;
&lt;p&gt;We can reduce any NP statement to an equivalent NP-complete problem, such as graph-coloring or boolean circuit satisfiability. ZEXE proves the correctness of computations by transforming our arbitrary program into an arithmetic circuit satisfiability problem, defined over a &lt;a href=&quot;&#x2F;math-survival-kit-for-developers&#x2F;&quot;&gt;finite field&lt;&#x2F;a&gt; $\mathbb{F}_r$. The problem that arises is that proof verifications involve operations over field $\mathbb{F}_q$, where $r \neq q$. It is, in principle, possible to simulate operations in $\mathbb{F}_q$ over $\mathbb{F}_r$, but this is quite expensive and would make the whole system burdensome. An alternative to this is working with a pair of &lt;a href=&quot;&#x2F;what-every-developer-needs-to-know-about-elliptic-curves&#x2F;&quot;&gt;elliptic curves&lt;&#x2F;a&gt;, with some desired properties; we call them pairing-friendly elliptic curves.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pairing-friendly-elliptic-curves&quot;&gt;Pairing-friendly Elliptic Curves.&lt;&#x2F;h3&gt;
&lt;p&gt;Given an elliptic curve $E$ defined over some finite field $\mathbb{F}_q$, we can define an operation over the points of the curve such that they form a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.entropy1729.com&#x2F;math-survival-kit-for-developers&#x2F;&quot;&gt;group&lt;&#x2F;a&gt; under that operation. The order of the subgroup $\mathbb{G}$ (that is, the number of elements) is $r$, with $r \neq q$. Two prime order curves $E_1$ and $E_2$ over fields $\mathbb{F}_q$ and $\mathbb{F}_r$ are said to be pairing friendly if the size of one’s base field $\mathbb{F}$ equals the other’s subgroup order and vice versa.&lt;&#x2F;p&gt;
&lt;p&gt;An elliptic curve pairing is a function $e:\mathbb{G}_1\times \mathbb{G}_2 \rightarrow \mathbb{G}_T$ that is bilinear. Here, $\mathbb{G}_1$ and $\mathbb{G}_2$ are the groups over elliptic curves. Bilinear means that, given two points $\mathcal{P_1}$ and $\mathcal{Q}_1$ in $\mathbb{G}_1$ and $\mathcal{P_2}$ and $\mathcal{Q}_2$ in $\mathbb{G}_2$ the following properties hold (we will write all the group operations as additions):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. $e(\mathcal{P_1}+\mathcal{Q}_1,\mathcal{P}_2)=e(\mathcal{P_1},\mathcal{P}_2)+e(\mathcal{Q}_1,\mathcal{P}_2)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. $e(\mathcal{P_1},\mathcal{P}_2+\mathcal{Q}_2)=e(\mathcal{P_1},\mathcal{P}_2)+e(\mathcal{P}_1,\mathcal{Q}_2)$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For efficiency reasons, we need both fields to have subgroups whose orders are large powers of $2$. ZEXE uses a curve from the Barreto-Scott-Lynn family, $E_{BLS}$ (with embedding degree(2) 12), which conservatively achieves 128 bits of security. The pairing friendly curve is generated via the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2006&#x2F;372.pdf&quot;&gt;Cocks-Pinch method&lt;&#x2F;a&gt;, $E_{CP}$. This is a very time consuming step since it involves exploring many different curves until we find one with the desired properties.&lt;&#x2F;p&gt;
&lt;p&gt;Given that the base field of $E_{CP}$ is larger than that of $E_{BLS}$, operations over the former are more expensive. To avoid this shortcoming, the relation $R_e$ is split into two: $R_{BLS}$ and $R_{CP}$. The last one is responsible for verifying proofs of predicates’ satisfaction, while all other checks depend on the $E_{BLS}$ curve.&lt;&#x2F;p&gt;
&lt;p&gt;Commitments and collision-resistant hash functions can be expressed as efficient arithmetic circuits for Pedersen-type constructions over Edwards curves. Therefore, two additional curves, $E_{Ed,BLS}$ and $E_{Ed,CP}$ over the fields $\mathbb{F}_r$ and $\mathbb{F}_q$ are selected, so as to implement important cryptographic primitives, such as hashing, commitments, and randomizable signatures. This allows us to reduce the difficulty of the multiple checks for NP relations.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;ZEXE is a protocol that was designed to allow users to execute arbitrary programs over public ledgers, without compromising privacy. It solves two of the main drawbacks of distributed ledgers so far: First, computations can be performed offline and a proof of the correct computation is submitted to the ledger. Since the proof is fast to verify, this avoids the problem of naïve re-execution and gives scalable solutions. Second, it achieves both data and function privacy: observers cannot get information over the data involved in the computations, not even on which specific functions are being called.&lt;&#x2F;p&gt;
&lt;p&gt;The protocol introduces new cryptographic primitives, such as DPC and delegatable DPC; the latter allows users with less powerful devices (such as smartphones) to hand their computations to untrusted parties and get proofs that show that the results obtained correspond to the correct execution of the program. These are supported by zk-SNARKs, relying on elliptic curve pairings and tools for converting arbitrary programs to an arithmetic circuit, where we can check the validity of the calculations.&lt;&#x2F;p&gt;
&lt;p&gt;It gives the basis for fully private applications, becoming an ideal platform for decentralized applications, such as finance, gaming, authentication, governance, and more.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;notes&quot;&gt;Notes&lt;&#x2F;h2&gt;
&lt;p&gt;(1) A commitment allows a user to commit to one value, with the ability to later reveal it. For example, in a roulette bet, I could choose “25” (I really feel very confident) and with the commitment, I am bound to my choice of “25” (though nobody could know, a priori, that I chose 25 since it is hidden). A way to achieve this is by using a collision resistant hash function and publishing the resulting hash (to make it work, we need to add something else, otherwise we can hash all the possibilities and see which one has the corresponding hash). If I then try to change my bet, the hash will not match with that of my original bet.&lt;br &#x2F;&gt;
(2) The embedding degree of an elliptic curve over the field $\mathbb{F}_q$ is the smallest positive integer $k$ such that $q^k-1$ is divisible by $r$, the order of the group. The embedding degree should be high so that the discrete logarithm problem is hard to solve. However, if $k$ is too large, then the arithmetic over the curves becomes much slower.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>LambdaClass and FuzzingLabs Partner to Create 4G and 5G Telecommunication security solution</title>
          <pubDate>Wed, 04 Jan 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/lambdaclass-and-fuzzinglabs-partnership/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/lambdaclass-and-fuzzinglabs-partnership/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/lambdaclass-and-fuzzinglabs-partnership/">&lt;p&gt;We’re excited to announce a new partnership between LambdaClass and FuzzingLabs. This collaboration brings together two leaders in the tech industry, combining Lambda’s expertise in distributed systems and cryptography with FuzzingLabs’s advanced fuzzing tools, to help ensure the reliability and security of 4G and 5G networks.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-lambdaclass-and-fuzzinglabs-are-a-perfect-match&quot;&gt;Why LambdaClass and FuzzingLabs are a perfect match:&lt;&#x2F;h2&gt;
&lt;p&gt;LambdaClass is a venture studio that specializes in building and scaling companies that leverage distributed systems, data engineering and cryptography. We have a track record of success in creating innovative solutions for a wide range of industries, including telecommunications. Our team of experts is uniquely qualified to help businesses and organizations navigate the complex world of highly scalable systems, cryptography and cutting edge technologies.&lt;&#x2F;p&gt;
&lt;p&gt;FuzzingLabs, on the other hand, is a leader in the field of fuzzing, a powerful technique for identifying vulnerabilities in software. The security tools we build will allow projects and companies to identify and fix any issues before they become a problem.&lt;&#x2F;p&gt;
&lt;p&gt;Together, LambdaClass and FuzzingLabs will offer a comprehensive solution for businesses and organizations looking to deploy reliable and secure 4G and 5G networks. By combining our proficiency in distributed systems, cryptography, and fuzzing, we’re able to help our customers take full advantage of the benefits of 4G and 5G while minimizing risks.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-this-partnership-means&quot;&gt;What this partnership means&lt;&#x2F;h2&gt;
&lt;p&gt;For LambdaClass, this partnership means access to FuzzingLabs’s advanced fuzzing tools. This will help ensure that our customers’ networks are robust and secure, and can handle the demands of the modern digital economy. LambdaClass will identify vulnerabilities and demonstrate potential methods of exploitation to highlight potential security risks.&lt;&#x2F;p&gt;
&lt;p&gt;For FuzzingLabs customers, this partnership means access to Lambda’s expertise in distributed systems and cryptography. Whether you’re looking to deploy a 4G and 5G network or optimize your existing infrastructure, Lambda has the knowledge and experience to help you succeed.&lt;&#x2F;p&gt;
&lt;p&gt;In addition to this, we will focus on research and development in order to build exploits to show and educate our customers and the community about the precautions to take when building complex systems.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;We’re thrilled to be partnering with FuzzingLabs to bring the power of fuzzing to the world of 5G and telecommunications. By combining our experience and resources, we’re confident that we can help businesses and organizations deploy reliable and secure networks that are ready for the future.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Weird ways to multiply really fast with Karatsuba, Toom–Cook and Fourier</title>
          <pubDate>Mon, 02 Jan 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/weird-ways-to-multiply-really-fast-with-karatsuba-toom-cook-and-fourier/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/weird-ways-to-multiply-really-fast-with-karatsuba-toom-cook-and-fourier/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/weird-ways-to-multiply-really-fast-with-karatsuba-toom-cook-and-fourier/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;The applicability and performance of algorithms depend on how fast certain routine computations can be done. For example, in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Elliptic-curve_cryptography&quot;&gt;elliptic curve cryptography&lt;&#x2F;a&gt;, one needs to calculate the public key as $k\times g=g+g+g+….+g$, where $k$ is a very large integer (typically a number with a hundred digits or so) and $g$ is a point of the elliptic curve $(x,y)$, known as the generator. If done naïvely, that is, adding repeatedly $g$ to itself, it would take about $10^{100}$ operations (we say that the algorithm runs in $\mathcal{O}(n)$, indicating that the number of operations -up to some constant factor- increases with $k$ in a linear fashion). The fastest supercomputer can perform less than $10^{18}$ &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;FLOPS&quot;&gt;floating point operations per second&lt;&#x2F;a&gt;; it would take you forever to do just one calculation. Nevertheless, we perform such calculations or related ones everyday, thanks to developing faster algorithms (for example, we can reduce the computation time by repeatedly adding $g+g=2g$, $2g+2g=4g$, etc, reducing the number of calculations to $\mathcal{O}(\log(n))$ -compare $10^{100}$ to something like $100\times \log_2{10}$).&lt;&#x2F;p&gt;
&lt;p&gt;zk-SNARKs (zero-knowledge succinct non-interactive arguments of knowledge) are important cryptographic primitives that allow one party (the prover) to convince another (the verifier) that a certain statement is true, without revealing anything else other than the validity of that statement. The applications of zk-SNARKs are far-ranging, given their potential as a foundation for new forms of governance, data sharing, and financial systems. For example, you could delegate a hard computation to an untrusted party and get a proof that allows you to verify the integrity of the computation, without the need to re-run everything. The key is that proofs are succinct, so they can be verified in the order of hundreds of milliseconds, as opposed to performing the whole computation. The construction relies on transforming the computation to polynomials and checking conditions over the polynomials. Polynomial multiplication can be done in a very efficient way via the fast Fourier transform -one of the most important algorithms ever devised by mankind-. Moreover, this calculation can be parallelized: several processors can run parts of the algorithm to make it even faster.&lt;&#x2F;p&gt;
&lt;p&gt;Even simple calculations such as integer multiplications (which take place almost everywhere) can be done faster than the school rule, provided the numbers we are trying to multiply are large enough.&lt;&#x2F;p&gt;
&lt;p&gt;If you want to learn how to speed up some ordinary calculations and make your algorithms run faster, then the next sections are for you.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;divide-and-conquer-karatsuba&quot;&gt;Divide and conquer: Karatsuba&lt;&#x2F;h2&gt;
&lt;p&gt;We all learned at elementary school how to multiply two numbers: we write one below the other and proceed to multiply each of the numbers above by each digit of the number below and then we add all the numbers:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1234 &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;×          152&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;———————————————&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      2468 ( =  1234 ×     2)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     6170  ( =  1234 ×    50)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1234   ( =  1234 ×   100)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;———————————————&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    187568 ( = 187568)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This algorithm has $\mathcal{O}(n^2)$. In 1960, Kolmogorov speculated that this represented the asymptotic bound for multiplication (that is, multiplication of two numbers could not take less than $\mathcal{O}(n^2)$ operations). He gave a lecture on the topic and one of the students, Karatsuba, then 23 years old, came up with a solution that runs with $\mathcal{O}(n^{\log_2(3)})$, thus disproving Kolmogorov’s conjecture. The basic idea of Karatsuba’s algorithm is the following: say we want to multiply $x$ and $y$; we can break them into smaller numbers:&lt;br &#x2F;&gt;
$x=x_1\times 10^m +x_0$&lt;br &#x2F;&gt;
$y=y_1\times 10^m +y_0$&lt;br &#x2F;&gt;
where both $x_0$ and $y_0$ are numbers less than $10^m$. The product $x\times y$ is simply:&lt;br &#x2F;&gt;
$x\times y=x_1\times y_1\times 10^{2m}+(x_1\times y_0+y_1\times x_0)\times 10^m+x_0y_0$&lt;br &#x2F;&gt;
Karatsuba found that $x_1y_0+y_1x_0$ can be calculated efficiently at the expense of some additions:&lt;br &#x2F;&gt;
$x_1\times y_0+y_1\times x_0=(x_1+x_0)\times (y_1+y_0)-x_1\times y_1-x_0\times y_0$.&lt;br &#x2F;&gt;
Even if there are some extra calculations, these operate over smaller numbers, resulting in an overall smaller cost for large numbers.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;toom-cook-algorithm&quot;&gt;Toom-Cook algorithm&lt;&#x2F;h2&gt;
&lt;p&gt;The divide and conquer strategy can be taken further, leading to a reduction in the complexity of the multiplication algorithm. Toom and Cook developed several methods (known as Toom-X, X being a number), which consist of the following stages:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Splitting&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Evaluation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Pointwise multiplication&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Interpolation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. Recomposition&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Several variants of the algorithms are implemented in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gmplib.org&#x2F;&quot;&gt;GNU Multiple Precision Arithmetic Library&lt;&#x2F;a&gt;. Toom-2 is the same as Karatsuba’s algorithm. Toom-X begins by splitting the numbers $x$ and $y$ in X parts of equal length(1) and these are treated as the coefficients of some polynomial (we focus on Toom-3, but you can see more details &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gmplib.org&#x2F;manual&#x2F;Toom-4_002dWay-Multiplication&quot;&gt;here&lt;&#x2F;a&gt;)(2):&lt;br &#x2F;&gt;
$x(t)=x_2 t^2+x_1 t+x_0$&lt;br &#x2F;&gt;
$y(t)=y_2 t^2+y_1 t+y_0$&lt;br &#x2F;&gt;
If we evaluate $x$, $y$ at $t=b$, we get the numbers back. The multiplication of both numbers is equal to a polynomial of degree $2(X-1)$,&lt;br &#x2F;&gt;
$w(t)=w_4t4+w_3t3+w_2t^2+w_1t+w_0$&lt;br &#x2F;&gt;
We can evaluate the polynomials at 5 different points, which will suffice to determine uniquely the polynomial $w$ due to the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Polynomial_interpolation#Interpolation_theorem&quot;&gt;interpolation theorem&lt;&#x2F;a&gt;. We can choose 5 convenient points which make the evaluation and reconstruction of the polynomial easy. Common points are $0, 1, -1, 2$ and $\infty$ (this last one is just the product of the main coefficients). Let’s see the form of each value:&lt;br &#x2F;&gt;
$w(0)=x(0)y(0)=x_0y_0$&lt;br &#x2F;&gt;
$w(1)=x(1)y(1)=(x_0+x_1+x_2)(y_0+y_1+y_2)$&lt;br &#x2F;&gt;
$w(-1)=x(-1)y(-1)=(x_0-x_1+x_2)(y_0-y_1+y_2)$&lt;br &#x2F;&gt;
$w(2)=x(2)y(2)=(x_0+2x_1+4x_2)(y_0+2y_1+4y_2)$&lt;br &#x2F;&gt;
$w(\infty)=x(\infty)y(\infty)=x_2y_2$&lt;&#x2F;p&gt;
&lt;p&gt;If we look at things from $w$ and its coefficients, we get:&lt;br &#x2F;&gt;
$w(0)=w_0$&lt;br &#x2F;&gt;
$w(1)=w_4+w_3+w_2+w_1+w_0$&lt;br &#x2F;&gt;
$w(-1)=w_4-w_3+w_2-w_1+w_0$&lt;br &#x2F;&gt;
$w(2)=16w_4+8w_3+4w_2+2w_1+w_0$&lt;br &#x2F;&gt;
$w(\infty)=w_4$&lt;&#x2F;p&gt;
&lt;p&gt;This is just solving one linear system (where 2 coefficients are straightforward). Once the coefficients are known, all that remains is to evaluate $w$ at $t=b$ and add. Toom-3 has a lower order ($\mathcal{O}(n{\log(5)&#x2F;\log(3)})=\mathcal{O}(n{1.46}$)) than Karatsuba’s method ($\mathcal{O}(n^{1.58})$, so it runs faster for sufficiently large integers.&lt;&#x2F;p&gt;
&lt;p&gt;For larger integers (in the order of 10,000 to 40,000 digits), we can go faster by means of the Schönhage-Strassen algorithm, which uses the fast-Fourier transform (FFT) to achieve a complexity $\mathcal{O}(n\log(n)\log\log(n))$. Before we can explain the algorithm, we need to introduce the FFT. The order can be further reduced to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;hal.archives-ouvertes.fr&#x2F;hal-02070778&#x2F;document&quot;&gt;$\mathcal{O}(n\log(n))$&lt;&#x2F;a&gt;, but this algorithm is only practical for (super-ultra) incredibly large numbers and is an example of a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Galactic_algorithm&quot;&gt;galactic algorithm&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-fast-fourier-transform&quot;&gt;The Fast-Fourier Transform&lt;&#x2F;h2&gt;
&lt;p&gt;The FFT is one of the key building blocks of many important algorithms, such as fast multiplication of very large numbers, polynomial multiplication, solving finite difference equations, error correcting codes (Reed-Solomon codes), and digital signal processing. It was used by Gauss early in the 19th century when he was trying to interpolate the orbits of asteroids Pallas and Juno. A simple implementation requires $\mathcal{O}(n^2)$ operations. In 1965, Cooley and Tukey realized that the algorithm could be implemented more efficiently, reducing it to $\mathcal{O}(n\log(n))$, which led to its widespread use. Almost every language and numerical computation library have it implemented. In Rust, you can check this &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;GSL&#x2F;latest&#x2F;rgsl&#x2F;fft&#x2F;index.html&quot;&gt;link&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;To get an idea of the huge improvement over the naïve algorithm, let’s look at the number of calculations for different samples:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Number of samples&lt;&#x2F;th&gt;&lt;th&gt;$10^3$&lt;&#x2F;th&gt;&lt;th&gt;$10^6$&lt;&#x2F;th&gt;&lt;th&gt;$10^{12}$&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;DFT operations&lt;&#x2F;td&gt;&lt;td&gt;$10^6$&lt;&#x2F;td&gt;&lt;td&gt;$10^{12}$&lt;&#x2F;td&gt;&lt;td&gt;$10^{24}$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;FFT operations&lt;&#x2F;td&gt;&lt;td&gt;$10^4$&lt;&#x2F;td&gt;&lt;td&gt;$2\times10^{7}$&lt;&#x2F;td&gt;&lt;td&gt;$4\times10^{13}$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;We see that the amount of computations is reduced by more than two orders of magnitude for samples with $1000$ or more elements!&lt;&#x2F;p&gt;
&lt;h3 id=&quot;fft-over-complex-numbers&quot;&gt;FFT over complex numbers&lt;&#x2F;h3&gt;
&lt;p&gt;The Fourier transform maps a function from its original domain (space or time) to another function depending on the (space or time) frequency. Stated another way, it decomposes a function into a collection of sine waves with different frequencies and amplitudes, which are useful to analyze the behavior of a given system. We can also perform the inversion, adding all those waves to recover the original function. Even though (continuous) Fourier transforms have many applications, we will be interested in discrete Fourier transforms (DFT), where we have a finite collection of data. Given data $x_0$, $x_1$,…$x_{N-1}$, the DFT gives a sequence $X_0, X_1,…X_{N-1}$, where&lt;br &#x2F;&gt;
$X=\sum_{k=0}^{N-1} x_k\exp(-2\pi i k&#x2F;N)$&lt;br &#x2F;&gt;
where $i^2=-1$ is the imaginary unit. Inversion of the DFT is given by&lt;br &#x2F;&gt;
$x=\frac{1}{N}\sum_{k=0}^{N-1} X_k\exp(2\pi i k&#x2F;N)$.&lt;&#x2F;p&gt;
&lt;p&gt;The DFT can be cast in the form of a matrix-vector product, $X=Mx$, where $M$ is the $N\times N$ DFT matrix:&lt;br &#x2F;&gt;
$M_{ij}=\omega^{(i-1)\times (j-1)}$&lt;br &#x2F;&gt;
where $\omega=\exp(2\pi i&#x2F;N)$ and $i$ and $j$ take the values $1,2,3,…N$&lt;&#x2F;p&gt;
&lt;p&gt;Implemented this way, the DFT requires $N^2$ operations, resulting from vector-matrix multiplication. The FFT will make this calculation more efficient, by taking advantage of the structure and using a divide and conquer strategy.&lt;&#x2F;p&gt;
&lt;p&gt;We can also see the DFT as evaluating a polynomial with coefficients $x_k$ over the roots of unity. This will be useful when discussing fast polynomial multiplication.&lt;&#x2F;p&gt;
&lt;p&gt;The key point is that computing the DFT with $N$ points can be reduced to calculating two DFTs with $N&#x2F;2$ points. We can apply this recursively to break down a very large problem into a collection of smaller and easier-to-solve subproblems and then recombine those results to get the DFT.&lt;&#x2F;p&gt;
&lt;p&gt;The algorithm also takes advantage of the properties of the $n$-th roots of unity in the complex plane. A number $z$ is known as an $n$-root of unity if $z^n=1$. These are of the form&lt;br &#x2F;&gt;
$z_k=\exp(2\pi i k&#x2F;n)$ for $k=0,1,2,…,n-1$. An interesting point is that these roots come in conjugate pairs: for each root $r$ we have the corresponding $\bar{r}$ (as a matter of fact, they form a finite group of order $n$ under multiplication). For example, the fourth roots of unity are: $1, i, -1, -i$. It is easy to see which are the pairs.&lt;&#x2F;p&gt;
&lt;p&gt;To see how all works, suppose we have a vector $x=(x_0,x_1,x_2,…x_{n-1})$ and we want to compute the FFT. We can split between even and odd numbered terms:&lt;br &#x2F;&gt;
$X=\sum_{k=0}^{n&#x2F;2-1} x_{2k}\exp(2\pi i 2k&#x2F;n)+\sum_{k=0}^{n&#x2F;2-1} x_{2k+1}\exp(2\pi i (2k+1)&#x2F;n)$&lt;br &#x2F;&gt;
We can express the odd terms in a different way, by taking out a factor of $\exp(2\pi i&#x2F;n)$,&lt;br &#x2F;&gt;
$X=\sum_{k=0}^{n&#x2F;2-1} x_{2k}\exp(2\pi i 2k&#x2F;n)+\exp(2\pi i&#x2F;n)\sum_{k=0}^{n&#x2F;2-1} x_{2k+1}\exp(2\pi i (2k)&#x2F;n)$&lt;br &#x2F;&gt;
We can now see that the factors corresponding to the $n$-roots of unity repeat themselves whenever $k$ is larger than $n&#x2F;2$. Another way to see this is to rearrange the terms by taking $2$ from the numerator of the exponential and sending it to the denominator:&lt;br &#x2F;&gt;
$X=\sum_{k=0}^{n&#x2F;2-1} x_{2k}\exp(2\pi i k&#x2F;(n&#x2F;2))+\exp(2\pi i&#x2F;n)\sum_{k=0}^{n&#x2F;2-1} x_{2k+1}\exp(2\pi i (k)&#x2F;(n&#x2F;2))$&lt;br &#x2F;&gt;
We now find that $\sum_{k=0}^{n&#x2F;2-1} x_{2k}\exp(2\pi i k&#x2F;(n&#x2F;2))=DFT(x_{2k})$ is just the DFT of the even terms, which contains $n&#x2F;2$ points. Similarly, $\sum_{k=0}^{n&#x2F;2-1} x_{2k+1}\exp(2\pi i (k)&#x2F;(n&#x2F;2))$ is the DFT of the odd terms, containing $n&#x2F;2$ points. This way, we broke the $n$ point DFT into two smaller $n&#x2F;2$ point DFTs, which can be combined to yield the original one. Now, each of those $n&#x2F;2$ DFTs can be broken into two smaller ones, so we can recursively reduce the number of computations by working with smaller samples (this way, we save ourselves of the large vector-matrix product).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;extending-the-fft-to-arbitrary-rings&quot;&gt;Extending the FFT to arbitrary rings&lt;&#x2F;h3&gt;
&lt;p&gt;FFT can be extended from complex or real numbers to arbitrary rings, such as integers or polynomials (check our &lt;a href=&quot;&#x2F;math-survival-kit-for-developers&#x2F;&quot;&gt;math survival kit&lt;&#x2F;a&gt;). In particular, we can use the number theoric transform which specializes the FFT to $\mathbb{Z}&#x2F;p\mathbb{Z}$, that is, the integers modulo $p$ (a prime number). Here we also have the $n$-roots of unity, given by&lt;br &#x2F;&gt;
$\alpha^n\equiv 1 \pmod{p}$&lt;br &#x2F;&gt;
It is important that we restrict ourselves to prime numbers: in this case, we have that the square root of $1$ are just $1$ and $-1$. For example, if we take $p=5$, $1^2\equiv 1 \pmod{5}$ and $-1\equiv 4$, $4^2 =16 \equiv 1 \pmod{5}$. This is not true for $8$ since $1^2\equiv 3^2\equiv 5^2\equiv 7^2\equiv 1 \pmod{8}$ and we would have $4$ square roots!&lt;&#x2F;p&gt;
&lt;p&gt;The problem with using FFT in finite fields is that we are not free to choose the domain and the field just as we please. We need to select a multiplicative subgroup of order $2^n$ (in other words, we need to select a group that is generated by an element $g$ and which contains its powers up to $2^n$). For example, if we take $p=5$, we have a group of order $4=2^2$ which is generated by $2$: ${21=2,22=4,2^3\equiv 3, 2^4\equiv 1}$; it does not need to span all the elements of the field, though.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;fft-multiplication-algorithm&quot;&gt;FFT multiplication algorithm&lt;&#x2F;h2&gt;
&lt;p&gt;The algorithm follows the same line as Karatsuba’s and Toom’s:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Split&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Evaluation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Pointwise multiplication&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Interpolation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. Combination&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The key difference lies in the use of the FFT to speed up calculations.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;polynomial-multiplication&quot;&gt;Polynomial multiplication&lt;&#x2F;h3&gt;
&lt;p&gt;Let’s start with polynomial multiplication. Given two polynomials, $p(x)=p_d xd+p_{d-1}x{d-1}+…+p_0$ and $q(x)=q_d xd+q_{d-1}x{d-1}+…+q_0$, we want to find their product, $w(x)=p(x)q(x)$. The simplest algorithm would be to apply repeatedly the distributive property, perform the multiplications and rearrange everything. The product of two polynomials of degree $d$ is a polynomial of degree $2d$. We can see that this strategy involves operations of the order $\mathcal{O}(d^2)$, that is, operations grow quadratically with the degree of the polynomials involved. We can take advantage of the structure of the polynomials and the interpolation theorem. We have at least two forms to describe the same polynomial:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Giving the $d+1$ coefficients.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Specifying the value of the polynomial at exactly $d+1$ points(3).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;What are the advantages of the second option? That we get to choose the points freely and reduce the number of calculations. For example, if we have an even function, $f(x)=f(-x)$ we can evaluate fewer points. Similarly, if the function is odd, $f(-x)=-f(x)$ and we have to change the sign to get the value of $-x$. So, choosing pairs $x$ and $-x$ we reduce the number of evaluations by half (except if we choose $0$, for example). We can split our polynomial between two polynomials: one has odd number terms, and the other even:&lt;br &#x2F;&gt;
$p(x)=p_e(x)+xp_o(x)$.&lt;br &#x2F;&gt;
For example, if $p=x5+3x4+5x3+2x2+6x+3$, we split it:&lt;br &#x2F;&gt;
$p(x)=(3x4+2x2+3)+x(x4+5x2+6)$&lt;br &#x2F;&gt;
We have then:&lt;br &#x2F;&gt;
$p_e=(3x4+2x2+3)$ and $p_o=(x4+5x2+6)$, where both polynomials are even functions! This way, we easily see that:&lt;br &#x2F;&gt;
$p(-x)=p_e(x)-xp_o(x)$&lt;br &#x2F;&gt;
If we have pairs $(x_k,p(x_k))$ and $(x_k,q(x_k))$, the product polynomial evaluated at $x_k$ is $(x_k,p(x_k)q(x_k))$.&lt;&#x2F;p&gt;
&lt;p&gt;To determine the product polynomial, we need $2d+1$ points; taking advantage of the above strategy, we need fewer point evaluations. If we could convert easily from the coefficient form to point evaluations, perform the multiplications in that form, and then transform back to coefficient form, we can achieve a lower complexity. We can recursively break the polynomials $p_e(x^2)$ and $p_o(x^2)$ into smaller polynomials.&lt;&#x2F;p&gt;
&lt;p&gt;We can choose as evaluation points the $n$ roots of unity, which come in pairs: $exp(2\pi i k&#x2F;n)$ with $k=0,1,2…n-1$. In other words, we can quickly calculate the DFT of the polynomials, multiply the coefficients and reverse the DFT once the product has been found. This leads to operations in the order $\mathcal{O}(d\log(d))$.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;integer-multiplication&quot;&gt;Integer multiplication&lt;&#x2F;h3&gt;
&lt;p&gt;To apply the FFT to integer multiplication, we need to transform our numbers to the coefficients of polynomials, perform the FFT multiplication and finally reconstruct the result. Overall this will take $\mathcal{O}(n\log(n)\log(\log(n))$. There is a large overhead, which will make this algorithm practical only for very large integers. For example, if we want to multiply $3578$ and $2457$, we can define vectors $(8,7,5,3,0,0,0,0)$ and $(7,5,4,2,0,0,0,0)$, where we conveniently pad the numbers with zeros.&lt;&#x2F;p&gt;
&lt;p&gt;Typically, operations are performed modulo $2^N+1$, where $N$ is larger than the combined number of bits of the integers $x$ and $y$, to make sure that results never wrap around.&lt;&#x2F;p&gt;
&lt;p&gt;The Fourier transform has the advantage that an operation such as the convolution of $x$ and $y$ can be calculated from the product of the transforms $X$ and $Y$ and transforming back:&lt;br &#x2F;&gt;
$\sum_{k=0}^{N} x_k y_{N-k}=IFFT(FFT(y)\times FFT(x))$&lt;&#x2F;p&gt;
&lt;p&gt;The Schönhage-Strassen algorithm makes use of the negacyclic convolution. Given vectors $x$ and $y$ of length $n$ and $r$ a $2n$-th (primitive) root of unity (that is, $r^{2n}\equiv 1 \pmod{p}$ and $r^k\not\equiv 1$ if $0&amp;lt;k&amp;lt;2n$), we can define the following weight vectors:&lt;br &#x2F;&gt;
$W_j=r^j$ for $0\leq j&amp;lt;n$&lt;br &#x2F;&gt;
$W_j{-1}=r{-j}$ for $0\leq j&amp;lt;n$&lt;br &#x2F;&gt;
The negacyclic convolution (NCC) of $x$ and $y$ can be computed as:&lt;br &#x2F;&gt;
$NCC(x,y)=W^{-1}IFFT(FFT(Wx)\times FFT(Wy))$&lt;&#x2F;p&gt;
&lt;p&gt;A comparison of the different methods implemented in GNU Multiple Precision Arithmetic Library is shown in this &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gmplib.org&#x2F;devel&#x2F;&quot;&gt;link&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;Choosing the right algorithms to carry out routine calculations, such as integer or polynomial multiplications, can have a dramatic effect on the performance of software. Depending on the size of the integers, it is possible to speed up (reducing the number of calculations) by adopting a divide and conquer approach: we break the calculation into smaller ones, which can be easily tackled, or continue breaking them down until they are manageable. All the fast algorithms we presented make use of this approach, leading to significant savings in computations. The FFT, thanks to its complexity $\mathcal{O}(n\log(n))$ can be a valuable tool to accelerate computations, even though it may at first seem weird or farfetched!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;notes&quot;&gt;Notes&lt;&#x2F;h2&gt;
&lt;p&gt;(1) If this is not possible, the most significant part can be shorter than the rest.&lt;br &#x2F;&gt;
(2) We will drop the multiplication symbol just for convenience.&lt;br &#x2F;&gt;
(3) We mentioned this earlier with the Toom-Cook method. For example, we know from geometry that we need to give two points to determine a straight line, which is a one-degree polynomial.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>An introduction to Fully Homomorphic Encryption (FHE)</title>
          <pubDate>Fri, 23 Dec 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/fully-homomorphic-encryption/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/fully-homomorphic-encryption/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/fully-homomorphic-encryption/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;Recently, cloud computing and storage have changed the way businesses and individuals use, store and manage their data. To be secure, data is encrypted using a secure cryptographic scheme, such as AES, where a secret key is needed to decrypt and read the data. Before 2009, if we wanted to perform data analytics on an untrusted server, we needed to provide access to the data in the clear or hand the key encrypting the data to the server. Either option had its risks, as the server could learn valuable or sensitive information, without being able to fully control what it does with it later on. Or, even if the other party were honest, some attacker could breach its security and gain access to our private information in the clear (or the key). Fully homomorphic encryption (FHE) is a powerful cryptographic primitive which allows parties to compute with encrypted data, without the need of decrypting it first. It has applications in finance, health care systems, image and text classification, machine learning, electronic voting, and multiparty computation. An easy example would be wanting to calculate the sum of two numbers, \( a \) and \( b \). Instead of summing them directly, we could encrypt them, \( E(a) \) and \( E(b) \), perform some operation \( E(a)\oplus E(b) \) and get \( E(c)=E(a)\oplus E(b) \), where \( c=a+b \).&lt;&#x2F;p&gt;
&lt;p&gt;More formally, the idea is we have our data as plaintext and we want to compute some function over that plaintext space (for example, we could work with integers, \( \mathbb{Z} \), representing the salaries of individuals and want to compute the average function). To do so, we transform our plaintexts to ciphertexts and perform operations over the ciphertext space, such that the resulting ciphertext is the encryption of the function applied to the plaintexts: \( E(f(x))=\hat{f}(E(x)) \). In a &lt;a href=&quot;&#x2F;arithmetization-schemes-for-zk-snarks&#x2F;&quot;&gt;previous post&lt;&#x2F;a&gt;, we covered that computations could be expressed as arithmetic circuits, where we have two operations: addition and multiplication. If we could get those operations to work on ciphertexts, then, in principle, we could build more complex functions.&lt;&#x2F;p&gt;
&lt;p&gt;A homomorphism is a function between two &lt;a href=&quot;&#x2F;math-survival-kit-for-developers&#x2F;&quot;&gt;algebraic structures&lt;&#x2F;a&gt; of the same kind (such as two groups, rings, fields, or vector spaces, to name a few), which preserves their structure. In particular, we are interested in ring homomorphisms, where we have a set with two operations. Given rings \( (\mathcal{R_1},+,\times) \) and \( (\mathcal{R_2},\oplus,\cdot) \), a function \( f:\mathcal{R_1}\rightarrow \mathcal{R_2} \) is a (ring) homomorphism if, given any \( x,y \) in \( \mathcal{R_1} \),&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * \\( f(x+y)=f(x)\oplus f(y) \\).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * \\( f(x\times y)= f(x)\cdot f(y) \\).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Two common examples of homomorphisms are between integers with ordinary operations \( (\mathbb{Z},+,\times) \) and the integers modulo \(p \) with their operations \( (\mathbb{Z}&#x2F;p\mathbb{Z},+,\times) \). Another example is between polynomials, \( (\mathbb{Z}[X],+,\times) \) and integers \( (\mathbb{Z},+,\times) \) when we use the evaluation of the polynomial at a point as morphism. We can see that it is the same if we first sum or multiply two polynomials and then evaluate them at point \( x_0 \), or we first evaluate the polynomials at \( x_0 \) and then add or multiply the results. Given \( p(x), q(x) \) polynomials and \( \circ \) an operation (addition or multiplication), \( (p\circ q)(x_0)=p(x_0)\circ q(x_0) \).&lt;&#x2F;p&gt;
&lt;p&gt;The first FHE scheme was presented in 2009 by &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;crypto.stanford.edu&#x2F;craig&#x2F;craig-thesis.pdf&quot;&gt;Craig Gentry&lt;&#x2F;a&gt;. To get an idea of how the scheme works, we can imagine the ciphertext to contain an error or noise attached to it. As long as the error is not large, we can decrypt the ciphertext and recover the plaintext. If we add or multiply ciphertexts, the error increases; if it is above a certain threshold, then decryption will not work. The key point introduced in Gentry’s work is bootstrapping, by which we can take a ciphertext and a public evaluation key and re-encrypt the message, reducing the error. This enables the computation of circuits of higher depth (performing more operations).&lt;&#x2F;p&gt;
&lt;p&gt;Even though Gentry’s construction proved that FHE is possible, it was extremely slow to be practical, taking as much as half an hour to perform the bootstrapping of 1 bit. Since then, there have been numerous advances and we reached a point where bootstrapping can be done on the scale of microseconds per bit (nearly 10 orders of magnitude). There are 4 generations of FHE as of today. Some constructions are Brakerski&#x2F;Fan-Vercauteren (BFV) and Brakerski-Gentry-Vaikuntanathan (BGV) for integer arithmetic, Cheon-Kim-Kim-Song (CKKS) for real number arithmetic and Ducas-Micciancio (DM) and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2018&#x2F;421.pdf&quot;&gt;Chillotti-Gama-Georgieva-Izabachene&lt;&#x2F;a&gt; (CGGI&#x2F;TFHE) for boolean circuits and arbitrary functions. In this post, we will focus on fully homomorphic encryption over the torus (TFHE).&lt;&#x2F;p&gt;
&lt;p&gt;Currently, schemes can be divided in:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Bootstrapping approach. This has no depth limitations and bootstrapping is done whenever needed to reduce the noise. It works better when the circuit is very deep or its depth is unknown. TFHE is an example of this approach.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Levelled approach. This needs the circuit to be known in advance and works better when the depth of the circuit is small and known in advance. CKKS is an example of this strategy.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The security of many FHE schemes is based on the hardness of the ring learning with errors (RLWE) problem. This is closely related to a famous hard lattice problem, which is thought to be secure against quantum computers. Quantum computers are efficient at breaking homomorphic encryption schemes based on Abelian groups.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;encryption-using-tfhe&quot;&gt;Encryption using TFHE&lt;&#x2F;h2&gt;
&lt;p&gt;TFHE supports various schemes to encrypt different variables or to perform certain operations.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;lwe-scheme&quot;&gt;LWE scheme&lt;&#x2F;h3&gt;
&lt;p&gt;Suppose that we want to encrypt a message \( m \), which can be a bit or a modular integer. To encrypt, we need two numbers, \( p \), and \( q \), a secret key, \( s \), of \( n \) bits (depending on the security level), and an error distribution, from which we will obtain the error, \( e \). To encrypt, we need to sample a random vector \( a \) with \( n \) elements in \( \mathbb{Z}&#x2F;q\mathbb{Z} \). \( q=2^{n_b} \), where \( n_b \) is the number of bits in the ciphertext and \( p=2^{m_b} \), with \( m_b \) the number of bits of the plaintext. Typically, \( q \) is in the order of \( 2^{32} \) to \( 2^{64} \). The error, \( e \) should be less than \( p&#x2F;2q \), otherwise, it could affect the message’s bits when adding or multiplying.&lt;&#x2F;p&gt;
&lt;p&gt;The ciphertext, \( c \), resulting from the encryption of \( m \) is given by&lt;br &#x2F;&gt;
\[ E(m,s)=c=(a,b) \]&lt;br &#x2F;&gt;
where \( b=\sum_{k=1}^n a_ks_k+e+\Delta m \). Here, \( \Delta \) is the ratio of \( p \) and \( q \), so that the message is encoded in the most significant bits of the ciphertext.&lt;&#x2F;p&gt;
&lt;p&gt;To decrypt, we have to use the key to eliminate \( \sum_{k=1}^n a_ks_k \) and round the result (take the most significant bits),&lt;br &#x2F;&gt;
\[ D(c,s)=\mathrm{round}(b-\sum_{k=1}^n a_ks_k) \]&lt;&#x2F;p&gt;
&lt;p&gt;This scheme supports ciphertext addition and multiplication by a constant factor. The addition, \( \oplus \), of two ciphertexts is&lt;br &#x2F;&gt;
\[ E(m_1,s)\oplus E(m_2,s)=(a_1+a_2,b_1+b_2) \]&lt;br &#x2F;&gt;
The multiplication by a constant factor \( \alpha \) is&lt;br &#x2F;&gt;
\[ \alpha E(m,s)=(\alpha a,\alpha b)\]&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ring-learning-with-errors-rlwe&quot;&gt;Ring Learning with Errors (RLWE)&lt;&#x2F;h3&gt;
&lt;p&gt;In this case, the message is a polynomial \( M \) modulo \( x^N-1 \), which contains \( N \) coefficients. The key \( S(x) \) is a polynomial with coefficients in \( {0,1} \). The encryption function is&lt;br &#x2F;&gt;
\[ E(M(x),S(x))=(A(x),B(x))\]&lt;br &#x2F;&gt;
with \( B(x)=A(x)\cdot S(x)+E(x)+\Delta M(x) \). The error is now a polynomial of degree \( N-1 \), too.&lt;&#x2F;p&gt;
&lt;p&gt;The scheme supports the addition of ciphertexts and multiplication by a constant polynomial.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ring-gsw-rgsw&quot;&gt;Ring GSW (RGSW)&lt;&#x2F;h3&gt;
&lt;p&gt;This scheme supports the addition and multiplication of ciphertexts. The message, key, and error are the same as in RLWE, but the ciphertext is different. We can think of it as a three-dimensional matrix, containing \( \ell \) layers of&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;$A_j(x)$&lt;&#x2F;th&gt;&lt;th&gt;$B_j(x)$&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;$A_j^\star(x)$&lt;&#x2F;td&gt;&lt;td&gt;$B_j^\star(x)$&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;The resulting polynomials are given by the following relations:&lt;br &#x2F;&gt;
\[ B_j(x)=A_j(x)S(x)+E_j(x)-M(x)S(x)\frac{q}{\beta^j} \]&lt;&#x2F;p&gt;
&lt;p&gt;\[ B_j\star(x)=A_j\star(x)S(x)+E_j\star(x)+M(x)S(x)\frac{q}{\betaj} \]&lt;&#x2F;p&gt;
&lt;p&gt;Addition and multiplication by a constant polynomial follow the same rules as the cases before. To multiply two messages, we need to decompose each layer of the first term into \( \ell \) smaller polynomials and perform a multiplication between this decomposition and the corresponding layer of the other ciphertext.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;summary-of-ciphertexts&quot;&gt;Summary of ciphertexts&lt;&#x2F;h3&gt;
&lt;p&gt;The following table summarizes the different types of ciphertexts and the supported operations.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Case&lt;&#x2F;th&gt;&lt;th&gt;Addition&lt;&#x2F;th&gt;&lt;th&gt;Constant Mult&lt;&#x2F;th&gt;&lt;th&gt;Multiplication&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;LWE&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;td&gt;No&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;RLWE&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;td&gt;No&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;RGSW&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;turning-private-key-into-public-key-schemes&quot;&gt;Turning private key into public key schemes&lt;&#x2F;h2&gt;
&lt;p&gt;Rothblum’s theorem states that a semantically secure private key homomorphic encryption scheme, which can perform addition modulo 2, can be turned into a public key semantically secure homomorphic scheme.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;external-product-and-controlled-multiplexer-cmux-gates&quot;&gt;External product and controlled multiplexer (CMux) gates&lt;&#x2F;h2&gt;
&lt;p&gt;The external product, \( \times \), is an operation involving an RLWE ciphertext and an RGSW ciphertext, outputting, and RLWE ciphertext. To perform the outer product, we have to decompose the \( A(x) \) and \( B(x) \) polynomials in the RLWE ciphertext and perform a matrix-vector product between the decomposition and the layers of the RSGW ciphertext.&lt;&#x2F;p&gt;
&lt;p&gt;One interesting application of the external product is related to the controlled mux gate, where we assign values according to an if condition. Given two values, \( y_1, y_2 \) and a boolean variable \( b \), we can construct the following operation&lt;br &#x2F;&gt;
\[ (y_2-y_1)b+y_1=y \]&lt;&#x2F;p&gt;
&lt;p&gt;If \( b \) is \( 0 \), we get \( y_1 \) and if \( b=1 \) we get \( y_2 \).&lt;&#x2F;p&gt;
&lt;p&gt;This is an important building block for the bootstrapping operation.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;key-switching&quot;&gt;Key switching&lt;&#x2F;h2&gt;
&lt;p&gt;The key-switching operation can be used to change encryption keys in different parameter sets. To implement it, we need key switching keys. The procedure has some parallelism with bootstrapping, with the subtle difference that it increases the noise in the ciphertext. The key switching can be applied to change the keys in LWE and RLWE ciphertexts, but it can also be used to transform LWE ciphertexts (one or many) into one RLWE.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;FHE is an important cryptographic primitive which allows us to compute with encrypted data, without the need of decrypting it first, opening the doors for many interesting and new applications. Since 2009, four generations of FHE schemes have been proposed, adding new functionalities and improving performance by several orders of magnitude. There are two types of approaches: bootstrapped and leveled. The first one works for circuits that are deep or their depth is unknown, while the second works for circuits of small depth. The security of many FHE schemes relies on post-quantum hard problems, such as ring learning with errors (RLWE). One powerful scheme is TFHE, a bootstrapped construction that operates on different types of ciphertext to attain rich functionality. In upcoming posts, we will be covering other schemes and we will go deeper into the fundamentals of FHE.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Fully-homomorphic encryption, zero-knowledge proofs, and multiparty computation</title>
          <pubDate>Fri, 16 Dec 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/fully-homomorphic-encryption-zero-knowledge-proofs-and-multiparty-computation/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/fully-homomorphic-encryption-zero-knowledge-proofs-and-multiparty-computation/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/fully-homomorphic-encryption-zero-knowledge-proofs-and-multiparty-computation/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;Cloud computing and storage have changed the way businesses and people use, store and manage their data. Data is securely stored in an encrypted form, typically using a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.entropy1729.com&#x2F;symmetric-encryption&#x2F;&quot;&gt;symmetric key encryption scheme&lt;&#x2F;a&gt;, such as AES or ChaCha20. However, to perform data analytics, we have to either give the key to the server so that it can decrypt it or we have to download it, decrypt it, and run the calculations on our own, which can be costly, requiring lots of time or memory. Fully homomorphic encryption (FHE) allows us to delegate computations involving encrypted data to untrusted third parties, without any need to decrypt them first.&lt;&#x2F;p&gt;
&lt;p&gt;Even if this is a very powerful cryptographic primitive, we still face a big challenge: how do we know that the third party performed the calculation it was supposed to do? This is where zero-knowledge proofs (ZKP) come into play. ZKP allow us to prove the integrity of a given computation, without the need to re-execute it. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.entropy1729.com&#x2F;the-hunting-of-the-zk-snark&#x2F;&quot;&gt;zk-SNARKs&lt;&#x2F;a&gt; (succinct non-interactive arguments of knowledge) yield short proofs which can be verified very fast and have applications in decentralized ledgers (solving both privacy and scalability issues) and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.entropy1729.com&#x2F;decentralized-private-computation-zexe-and-veri-zexe&#x2F;&quot;&gt;decentralized private computations&lt;&#x2F;a&gt;. They also face some challenges: generating proofs for arbitrary computations can be expensive and users with less powerful devices may not be able to generate them. Many zk-SNARKs require trusted setups, which should be generated by an honest party to ensure that nobody can cheat and generate fake proofs.&lt;&#x2F;p&gt;
&lt;p&gt;Both of them can be solved by multiparty computation (MPC). In this scheme, the generation of the proof or the establishment of the trusted setup is entrusted to various parties, which could have partial access to the data. In the case of setup ceremonies, as long as one of the parties involved is honest, the setup is secure. MPC can also be used, with decentralized ledgers, to ensure that anyone can participate in setup ceremonies and prevent malicious parties from blocking honest participants, using proofs with transparent setups (such as STARKs - scalable, transparent argument of knowledge).&lt;&#x2F;p&gt;
&lt;p&gt;Proof generation can be carried out by multiple servers, each of them having partial information on the secret inputs. Each party can submit proof attesting to the correctness of the proof generation protocol. Multiparty computation can also be used to perform calculations among different parties, each of them having different pieces of information relevant to the problem, such as financial information between banks or health-related information for health service providers. FHE helps parties share information and make calculations without revealing it or train machine learning models without compromising sensitive data.&lt;&#x2F;p&gt;
&lt;p&gt;It is clear from all the above that FHE, ZKP, and MPC have many points in common and each has something to offer to the other. ZKP can provide integrity of computations, FHE allows data sharing and calculation without compromising it and MPC gives us the power to delegate expensive computations to other parties. These open the doors for many new and exciting applications in finance, health, and medical sectors, with an emphasis on data privacy and decentralization.&lt;&#x2F;p&gt;
&lt;p&gt;We will now explain the basic idea behind each of these primitives.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;fully-homomorphic-encryption&quot;&gt;Fully Homomorphic encryption&lt;&#x2F;h2&gt;
&lt;p&gt;Fully homomorphic encryption is a form of encryption where we can perform operations with encrypted data and the result of those operations is the encrypted form of an operation involving the ciphertext. For example, in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.entropy1729.com&#x2F;how-to-create-your-own-crappy-rsa-as-a-software-developer&#x2F;&quot;&gt;RSA cryptosystem&lt;&#x2F;a&gt;, we encrypt a message &lt;em&gt;m&lt;&#x2F;em&gt; using the public key by taking&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;E(m)=m e(&lt;&#x2F;em&gt; mod _ &lt;em&gt;n&lt;&#x2F;em&gt;)_&lt;&#x2F;p&gt;
&lt;p&gt;Now suppose that we have &lt;em&gt;m 1&lt;&#x2F;em&gt;,&lt;em&gt;m 2&lt;&#x2F;em&gt; numbers and we want to compute their product &lt;em&gt;m 1&lt;&#x2F;em&gt;× &lt;em&gt;m 2&lt;&#x2F;em&gt;. We can see that if we perform the product and then encrypt it, we get&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;E(m 1&lt;&#x2F;em&gt;× &lt;em&gt;m 2&lt;&#x2F;em&gt;)=(&lt;em&gt;m 1&lt;&#x2F;em&gt;× &lt;em&gt;m 2&lt;&#x2F;em&gt;)e  (mod   &lt;em&gt;n&lt;&#x2F;em&gt;)&lt;&#x2F;p&gt;
&lt;p&gt;If we take the product of the encrypted forms of m1,m2, then&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;E(m 1)&lt;&#x2F;em&gt;× &lt;em&gt;E(m 2&lt;&#x2F;em&gt;)=&lt;em&gt;m e1&lt;&#x2F;em&gt;× &lt;em&gt;m e2&lt;&#x2F;em&gt;=(&lt;em&gt;m 1&lt;&#x2F;em&gt;× &lt;em&gt;m 2&lt;&#x2F;em&gt;)e   (mod &lt;em&gt;n&lt;&#x2F;em&gt;)&lt;&#x2F;p&gt;
&lt;p&gt;which is the same as calculating first the product and then encrypting. The operation in the encrypted space need not be the same as the one in the original. Given this property of the RSA cryptosystem, many researchers started wondering whether it could be possible to build a fully homomorphic encryption scheme. The first FHE scheme was presented in 2009 by &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;crypto.stanford.edu&#x2F;craig&#x2F;craig-thesis.pdf&quot;&gt;Craig Gentry&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;math-interlude-homomorphisms&quot;&gt;Math interlude: Homomorphisms&lt;&#x2F;h3&gt;
&lt;p&gt;To be more precise, a homomorphism is a function between two &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.entropy1729.com&#x2F;math-survival-kit-for-developers&#x2F;&quot;&gt; algebraic structures&lt;&#x2F;a&gt; (such as two groups, two rings, two vector spaces) and preserves their structure. If you had a course on linear algebra, linear transformations are examples of homomorphisms. In the context of groups, suppose we have two groups (𝔾1,⋅) and (𝔾2,⊕), each with their binary operation (it could be multiplication, addition, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.entropy1729.com&#x2F;what-every-dev-needs-to-know-about-elliptic-curves&#x2F;&quot;&gt; elliptic curve addition&lt;&#x2F;a&gt;, function composition, etc). A function &lt;em&gt;f&lt;&#x2F;em&gt; :𝔾1→𝔾2 is an homomorphism if, given &lt;em&gt;x&lt;&#x2F;em&gt; ,&lt;em&gt;y&lt;&#x2F;em&gt; in 𝔾1 we have&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;f(x⋅y)  = f(x)&lt;&#x2F;em&gt; ⊕ &lt;em&gt;f(y)&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Note that the operation between the images &lt;em&gt;f(x),f(y)&lt;&#x2F;em&gt; is the operation over 𝔾2. We also saw examples of homomorphisms between rings, when we defined modular arithmetic: we have a function preserving addition and multiplication from the set of integers with the usual operations, (ℤ,+,×) and the ring of integers modulo &lt;em&gt;p&lt;&#x2F;em&gt; , (ℤ&#x2F;&lt;em&gt;p&lt;&#x2F;em&gt; ℤ,⊕,⋅) (we use different symbols for addition and multiplication to remember that these are modulo &lt;em&gt;p&lt;&#x2F;em&gt;). For example, if we take &lt;em&gt;p&lt;&#x2F;em&gt;  = 7, we have ℤ&#x2F;&lt;em&gt;p&lt;&#x2F;em&gt; ℤ={0,1,2,3,4,5,6}. We can see that: −5+3=−2. This is related to 2 ⊕ 3 ≡ 5 (mod7), where 2 is the element corresponding to −5 in ℤ&#x2F;&lt;em&gt;p&lt;&#x2F;em&gt; ℤ, 3 corresponds to itself and 5 is congruent to −2.−3×4=−12 which relates to 4⋅4≡2(mod7) in the same way as before.&lt;&#x2F;p&gt;
&lt;p&gt;It is important to see that homomorphisms are not necessarily one-to-one functions (the last ring homomorphism shows a clear example). If the homomorphism is a bijective function, it is called an isomorphism. The following is an example of an isomorphism from the real numbers ℝ with addition to the positive real numbers equipped with multiplication, ℝ +,  &lt;em&gt;f&lt;&#x2F;em&gt;  : ℝ→ℝ+ , &lt;em&gt;f  (x)&lt;&#x2F;em&gt; = exp &lt;em&gt;(x)&lt;&#x2F;em&gt;  , with its inverse, &lt;em&gt;f −1&lt;&#x2F;em&gt; : ℝ+→  ℝ,  &lt;em&gt;f&lt;&#x2F;em&gt; −1 (&lt;em&gt;z&lt;&#x2F;em&gt;) = ln(&lt;em&gt;z&lt;&#x2F;em&gt;). You can easily check that &lt;em&gt;f   (x + y )=f (x) ⋅ f (y)&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In the context of cryptography, we would like to have encryption or commitment schemes preserving some operations. For example, the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.entropy1729.com&#x2F;the-hunting-of-the-zk-snark&#x2F;&quot;&gt; Kate-Zaverucha-Goldberg &lt;&#x2F;a&gt; (KZG) commitment scheme is additively homomorphic. The commitment takes polynomials (which we can think of as a group with ordinary polynomial addition, (ℙ,+)) and maps them into elliptic curve points (which also have a group structure, with elliptic curve addition, (𝔾,⊕)). We can verify that&lt;&#x2F;p&gt;
&lt;p&gt;cm(&lt;em&gt;p&lt;&#x2F;em&gt; 1 (&lt;em&gt;x&lt;&#x2F;em&gt;)  +  &lt;em&gt;p 2&lt;&#x2F;em&gt;(x))  =  cm(&lt;em&gt;p &lt;em&gt;1   (&lt;em&gt;x&lt;&#x2F;em&gt;))  ⊕  cm(&lt;em&gt;p 2&lt;&#x2F;em&gt;(x))&lt;&#x2F;em&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This property is useful for &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.entropy1729.com&#x2F;proof-aggregation-schemes-snarkpack-and-aplonk&#x2F;&quot;&gt;proof aggregation&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.entropy1729.com&#x2F;incrementally-verifiable-computation-nova&#x2F;&quot;&gt;folding schemes&lt;&#x2F;a&gt;. Elliptic curve pairings also provide some way to compute multiplications between polynomials in committed form (using KZG).&lt;&#x2F;p&gt;
&lt;p&gt;To be able to construct an FHE scheme we need not only preserve operations but also have a way to decipher the result.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;fhe-fundamentals&quot;&gt;FHE fundamentals&lt;&#x2F;h2&gt;
&lt;p&gt;There are many libraries for FHE nowadays, such as &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.openfhe.org&#x2F;&quot;&gt;OpenFHE&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.microsoft.com&#x2F;en-us&#x2F;research&#x2F;project&#x2F;microsoft-seal&#x2F;&quot;&gt;Microsoft SEAL&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cpeikert&#x2F;Lol&quot;&gt;Λ∘λ&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;homomorphicencryption.org&#x2F;introduction&#x2F;&quot;&gt;many more&lt;&#x2F;a&gt;. With FHE you can make private queries to search engines or pages, such as Wikipedia; see &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;spiralwiki.com&#x2F;&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;FHE schemes are based on lattice cryptography. A lattice is given by linear combinations with integer coefficients of some base vectors. To fix ideas, imagine we have two vectors &lt;em&gt;e x&lt;&#x2F;em&gt; = (1,0) and &lt;em&gt;e y&lt;&#x2F;em&gt; = (0,1) and we consider all possible combinations &lt;em&gt;p  = xex + yey&lt;&#x2F;em&gt; with &lt;em&gt;x&lt;&#x2F;em&gt; ,&lt;em&gt;y&lt;&#x2F;em&gt; in ℤ, yielding points in space (0,0),(1,0),(1,1),(−1,−2),…. A lattice looks like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Lattice_problem#&#x2F;media&#x2F;File:SVP.svg&quot;&gt; this&lt;&#x2F;a&gt;. Ideal lattices correspond to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Ideal_(ring_theory)&quot;&gt;ideals in polynomial rings&lt;&#x2F;a&gt;, inheriting the natural addition and multiplication operations of the ring (Ideals generalize the idea behind certain subsets of the integers, such as even numbers. The addition of any two even numbers is always even and, whenever we multiply any integer by an even, the result is also even -an absorption property-).&lt;&#x2F;p&gt;
&lt;p&gt;To build an FHE scheme we could picture having a ciphertext with some small attached to it, such that the decryption works as long as the noise is below a certain threshold. If we have ways to homomorphically multiply and add ciphertexts, but at the expense of increasing the noise parameters accordingly, that is, _E(a  + b) =E (a) &lt;em&gt;⊕ _  E (b)&lt;&#x2F;em&gt; and &lt;em&gt;E(a×b)=E(a)⋅E(b)&lt;&#x2F;em&gt;. We call this a somewhat homomorphic encryption scheme (SHE). If we could add a “recrypt” algorithm, which can take a given ciphertext &lt;em&gt;E(m)&lt;&#x2F;em&gt; and reduce its noise, obtaining a new ciphertext &lt;em&gt;E′(m)&lt;&#x2F;em&gt; that also encrypts &lt;em&gt;m&lt;&#x2F;em&gt; , then we can obtain an FHE scheme.&lt;&#x2F;p&gt;
&lt;p&gt;The SHE scheme can handle circuits of a certain depth (imagine this as the number of times you can multiply or add before the noise becomes too large). The SHE can be modified to have its decryption circuit have a lower multiplicative depth, making it “bootstrappable” and thus transforming it into an FHE scheme.&lt;&#x2F;p&gt;
&lt;p&gt;Some common schemes for FHE are:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Brakerski-Fan-Vercauteren (BFV) and Brakerski-Gentry-Vaikuntanathan (BGV) for integer arithmetic.&lt;&#x2F;li&gt;
&lt;li&gt;Cheon-Kim-Kim-Song (CKKS) for real number arithmetic.&lt;&#x2F;li&gt;
&lt;li&gt;Ducas-Micciancio (DM) and Chillotti-Gama-Georgieva-Izabachene (CGGI) for boolean circuits and arbitrary functions using lookup tables.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Many cryptographic primitives, such as public key cryptography, are based on the hardness or intractability of mathematical problems, such as &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Integer_factorization&quot;&gt;integer factorization&lt;&#x2F;a&gt; (RSA) or the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Discrete_logarithm&quot;&gt;discrete logarithm problem&lt;&#x2F;a&gt; (elliptic curve cryptography). These problems cannot be solved efficiently with current computers (at least, provided that the integers involved are big enough or the groups have a large number of elements). However, quantum computers could easily handle these problems if certain conditions are met, via &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Shor%27s_algorithm&quot;&gt;Shor’s algorithm&lt;&#x2F;a&gt;. FHE is based on the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Lattice_problem&quot;&gt;shortest vector problem&lt;&#x2F;a&gt; or &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;homomorphicencryption.org&#x2F;wp-content&#x2F;uploads&#x2F;2018&#x2F;11&#x2F;HomomorphicEncryptionStandardv1.1.pdf&quot;&gt;ring learning-with-error&lt;&#x2F;a&gt; (RLWE) problem, which is an NP-hard problem that cannot be tackled with Shor’s algorithm (FHE is considered to be quantum resistant).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;zero-knowledge-proofs&quot;&gt;Zero-knowledge proofs&lt;&#x2F;h2&gt;
&lt;p&gt;Zero-knowledge proofs (ZKP) have been gaining a lot of attention during the last decade, especially after the first efficient SNARK constructions. ZKP play an important role in the solution of two of the main challenges in decentralized ledgers: scalability and privacy. To validate transactions, nodes have to re-execute them, leading to bottlenecks. Besides, all the information in the ledger is public, which can leak sensitive information about individuals and organizations.&lt;&#x2F;p&gt;
&lt;p&gt;zk-SNARKs allow one party to prove a statement, without revealing anything other than the validity of the statement. For example, we can prove that we have a given secret key, without revealing it. We can also prove that we have executed some transaction or computation, without exposing secret or sensitive information. An important property of SNARKs is their succinctness, which means that proofs:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Are short (occupy little memory, about 1 kB for some SNARKs).&lt;&#x2F;li&gt;
&lt;li&gt;Are fast to verify (typically, in the order of milliseconds).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Ethereum has been adding zero-knowledge proof technologies recently to solve scalability issues. Zcash implemented ZKP to provide private transactions, while Aleo uses them to enable running private computations in a decentralized way.&lt;&#x2F;p&gt;
&lt;p&gt;How do SNARKs work under the hood? Even if there are many different constructions (such as Marlin, Plonk, Halo, and STARKs), they have a common recipe. The building blocks of SNARKs are polynomial interactive oracle proofs (PIOP) and polynomial commitment schemes (PCS). Depending on the choices made, the resulting SNARK has different properties and requirements. For example, it may be transparent (does not need a trusted setup), post-quantum secure, need special (pairing-friendly) elliptic curves, take longer times to generate proofs, have shorter proofs (less than 1 kB), allow for easy recursion, etc. A comparison between different polynomial commitment schemes is shown &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;hackernoon.com&#x2F;kzg10-ipa-fri-and-darks-analysis-of-polynomial-commitment-schemes&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;To be able to construct the proof, we first need to transform our computation into some SNARK-friendly format. We can prove the correctness of our execution by reducing it to some kind of NP-complete problem, such as graph coloring or circuit satisfiability. We will work with arithmetic circuits and the transformation of a program into a circuit is known as arithmetization. There are different forms or strategies for doing this transformation; an overview of the most commonly used is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.entropy1729.com&#x2F;arithmetization-schemes-for-zk-snarks&#x2F;&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;multiparty-computation&quot;&gt;Multiparty computation&lt;&#x2F;h2&gt;
&lt;p&gt;In a secure multiparty computation, a group of participants, &lt;em&gt;p 1,p2,…,pm&lt;&#x2F;em&gt;, each having some secret information &lt;em&gt;s 1,s2,…sm&lt;&#x2F;em&gt;, want to compute a certain function that requires the knowledge of that secret information. For example, we could have m employees wanting to know their average salary without revealing their income. One easy way to do so would be that all of them trust another party and each sends their secret information and the “trusted” party computes the average. The drawback: the “trusted” party learns all the information and could leverage it. Or perhaps he is honest, but he gets hacked and an attacker obtains everything.&lt;&#x2F;p&gt;
&lt;p&gt;Luckily, there is a useful cryptographic primitive to deal with cases like these: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.geeksforgeeks.org&#x2F;additive-secret-sharing-and-share-proactivization-using-python&#x2F;&quot;&gt; additive secret sharing&lt;&#x2F;a&gt;. Each of the participants can break their secret &lt;em&gt;s k&lt;&#x2F;em&gt; into &lt;em&gt;m&lt;&#x2F;em&gt; shares in such a way that no shareholder can, on his own, learn the secret. To be able to reconstruct the secret, all of the other parties have to collude and share their part. In the example above, each employee can break his salary, &lt;em&gt;s k&lt;&#x2F;em&gt; into &lt;em&gt;m&lt;&#x2F;em&gt; different, random shares. For example, if we have 4 employees and employee A earns 4500, he can have 4 shares, &lt;em&gt;s Ai&lt;&#x2F;em&gt;: -1200, 1500, 3600, 600, such that ∑i sAi_ = 4500. He keeps one share and distributes the rest to B, C, and D. In turn, the rest break their secret and divide it. Afterward, each participant sums all the shares he has, obtaining a partial sum, &lt;em&gt;s p,A&lt;&#x2F;em&gt; = ∑k sk,A, and then shares these partial sums to compute the final average.&lt;&#x2F;p&gt;
&lt;p&gt;Secret sharing is secure whenever parties knowing at most &lt;em&gt;m&lt;&#x2F;em&gt;  − 1 have no more information than anyone with no shares at all.&lt;&#x2F;p&gt;
&lt;p&gt;Now, how can we ensure that each party does what it is supposed to do? ZKP give us a way to guarantee that each participant does the computation as expected, by submitting proof that attests to the correct execution. If he cheats, the proof should fail and he could be penalized. Early MPC protocols had significant overhead; the last decade has seen many advances, making it efficient and leading to many applications.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;Fully homomorphic encryption, zero-knowledge proofs, and multiparty computations are important cryptographic primitives that have been gaining more and more attention in recent years, with the introduction of decentralized ledgers and increasing concern over data privacy. Each has its unique features and applications and has something to offer to the other primitives. FHE allows us to make cloud computations on encrypted data without needing to hand our key to the server, which prevents third parties from gaining access to the specific contents of the data. ZKP allow us to prove the correctness of a given computation by submitting a short proof, which can be quickly verified. This is seen as one of the greatest tools to solve the privacy and scalability issues of decentralized ledgers. Multiparty computation helps us distribute a complex computation or calculate something when all the inputs are distributed among several parties in a secure way; it has applications for voting, private auctions, bidding, etc. FHE can help us improve existing ZKP, which in turn can make multiparty computation much simpler and more secure. In turn, MPC is needed for the setup ceremonies of zk-SNARKs and can also help provers reduce their proof generation time by delegating them to untrusted powerful servers. ZKP can also help us ensure that the computations involving encrypted data are carried out correctly. All these fields have seen great advances over the last decade and each will help the others advance, leading to new interesting applications, with a greater focus on decentralization and privacy. In upcoming posts, we will cover in more depth the mathematical foundations of FHE and further applications of MPC and ZKP.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>How to create your own crappy RSA as a software developer</title>
          <pubDate>Fri, 26 Aug 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/how-to-create-your-own-crappy-rsa-as-a-software-developer/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/how-to-create-your-own-crappy-rsa-as-a-software-developer/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/how-to-create-your-own-crappy-rsa-as-a-software-developer/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;One of the key developments in cryptography was the introduction of public key (or asymmetric) cryptosystems. These rely on pairs of keys: one of them is the public key (known to everybody) and the other is the private key (known only to the specific user). The public key is used to encrypt messages (anybody can do this since it is public), while the private key is used to decrypt the messages. This contrasts with symmetric encryption, where there is one key that can perform both operations (and was the only method available before the 1970s). This meant that a secure channel was needed to exchange&#x2F;decide on the key, so that only certain priviledged parties were able to do cryptography. The real-time cryptography and the internet as we know it was enabled by public key cryptography. Depending on the method used, the keys could be numbers -for example, (RSA) or, in the case of elliptic curve cryptography (ECC), a number and a point of an elliptic curve. The algorithm of encryption and decryption is also publicly known, so the security of the whole system depends on never revealing the private key (this is known as &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Kerckhoffs%27s_principle&quot;&gt;Kerckhoff’s principle&lt;&#x2F;a&gt;). Asymmetric cryptography plays a fundamental role in many applications and protocols, offering confidentiality, authenticity, and non-repudiability of data and electronic communications. Internet standards, such as TLS, SSH, and PGP rely on this cryptographic primitive.&lt;&#x2F;p&gt;
&lt;p&gt;RSA (named after Rivest, Shamir, and Adleman) is one of the first public key cryptosystems, the most widely used, and one of the simplest to understand and implement (1). We will discuss today how RSA works, how to implement its basic structure, and what are some of the pitfalls and weaknesses of this system (which have led to its losing ground against ECC).&lt;&#x2F;p&gt;
&lt;p&gt;We will be using some math and cryptography concepts below; you may want to review our math &lt;a href=&quot;&#x2F;math-survival-kit-for-developers&#x2F;&quot;&gt;survival kit&lt;&#x2F;a&gt; first.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-rsa-works&quot;&gt;How RSA works&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;non-rigorous-mathematical-idea&quot;&gt;Non-rigorous mathematical idea&lt;&#x2F;h3&gt;
&lt;p&gt;RSA relies on four key steps: key generation, key distribution, encryption, and decryption. Instead of describing each of them in sequence, we will give an overview of the whole process and then go into the details. The basic idea is the following: given a number $n$ (public), there are two numbers $e$ (public key, used for encryption) and $d$ (private key, used for decryption), which are multiplicative inverses (that is, $d\times e=1$, so $e=d^{-1}$). Given a message $M$, expressed as a number between $0$ and $n-1$, the encryption $E(M)$ is done by taking the $e$-th power of $M$,&lt;br &#x2F;&gt;
$E(M)=M^e$&lt;br &#x2F;&gt;
Decryption is done similarly by taking the $d$-th power of the encrypted message,&lt;br &#x2F;&gt;
${E(M)}d=(M{e})d=M{d\times e}=M$&lt;br &#x2F;&gt;
Of course, if you think in terms of high-school math, there are several problems, starting with the obvious fact that knowing $e$ allows you to calculate $d$ and that the encrypted message can grow into a very large number (and take a lot of space). This is where number theory and modular arithmetic come to our rescue.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;steps&quot;&gt;Steps&lt;&#x2F;h3&gt;
&lt;p&gt;Let’s now look in more detail at each of the steps and how we can get something that is very difficult to crack unless you know the secret key.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Key generation:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Pick large random prime numbers $p$ and $q$ and keep them secret (2).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Calculate $n=p\times q$. $n$ is released as part of the public key parameters.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Compute the value of [Euler&amp;#39;s totient function](https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Euler%27s_totient_function) $\phi(n)=(p-1)\times (q-1)$ and keep it secret (3).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Choose an integer $1&amp;lt;e&amp;lt;\phi(n)$ which is coprime to $\phi (n)$ (that is, their only common divisor is 1). $65537=2^{16}+1$ is a typical choice since it offers rather fast encryption and security. Another popular choice is $3$, but it is known that this leads to insecure encryption in many settings.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Calculate $d=e^{-1} \mod{\phi(n)}$, that is, $d$ is the multiplicative inverse of $e$ modulo $\phi(n)$ (4). This can be done via taking powers of $e$ or in a faster way using the [extended Euclidean algorithm](https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Extended_Euclidean_algorithm).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Key distribution: If two people Alice and Bob want to communicate, each sends the other their public parameters $(e_A,n_A)$ and $(e_B,n_B)$. Of course, an obvious question arises, how do Bob and Alice know that they got each other&amp;#39;s public parameters and not someone else&amp;#39;s (the infamous man-in-the-middle)?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Encryption:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Convert the message $P$ into an integer $1&amp;lt;m&amp;lt;n$ by using an agreed padding scheme.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $E(m)$ is calculated $E(m)\equiv m^e \pmod{n}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Decryption:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Compute the message $m$ by doing ${E(m)}^d\equiv m \pmod{n}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * Reverse the first step of encryption to convert $m$ to $P$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;example-of-the-calculations&quot;&gt;Example of the calculations&lt;&#x2F;h3&gt;
&lt;p&gt;Let’s pick a toy model to illustrate how the calculations are done (of course, no real model uses these simple numbers, because it is rather easy to break, even by brute force attempts).&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. We choose two random primes 17 and 19.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. $n=17\times 19=323$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. We evaluate $\phi(323)=288$ or $\lambda(323)=144=lcm(16,18)$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. We pick $e=5$ (remember, a small $e$ is not a good choice). We cannot pick $3$ because $3$ is not coprime to $\phi(n)=288=2^5 \times 3^2$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. $d=5^{11}\equiv 29 \pmod{144}$. (We use Carmichael&amp;#39;s totient function since it is faster). Let&amp;#39;s check we did right: $5\times 29=145\equiv 1 \pmod{144}$, since $145=1\times 144+1$. An even faster alternative would be using the extended Euclidean algorithm.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    6. Our message is $11$. Therefore $E(11)=11^5\equiv 197\pmod{323}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    7. We now attempt to decrypt $197^{29}\equiv 11 \pmod{323}$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;the-math-behind-the-scenes&quot;&gt;The math behind the scenes&lt;&#x2F;h3&gt;
&lt;p&gt;The trick works because we have two numbers $d$ and $e$, such that $d\times e \equiv 1 \pmod{\phi(n)}$. In other words, $d\times e=k\phi(n)+1$. If we perform encryption, followed by decryption, we get&lt;br &#x2F;&gt;
${(me)}d=m^{e\times d}=m^{1+k\phi(n)}=m\times (m{\phi(n)})k \equiv m \pmod{n}$&lt;br &#x2F;&gt;
The last step is a consequence of Euler’s theorem, since&lt;br &#x2F;&gt;
$a^{\phi(n)}\equiv 1 \pmod{n}$, given $a$ and $n$ are coprime.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;security-issues&quot;&gt;Security issues&lt;&#x2F;h3&gt;
&lt;p&gt;There are several issues with RSA, especially when it is not implemented properly. When generating random prime numbers, these must be truly random (therefore, always use a pseudorandom generator that works for cryptographic applications). Many attacks depend on getting to the factorization of the public parameter $n$. If we can find $p$ or $q$, then we get the other and we can calculate $\lambda (n)$ or $\phi(n)$, the multiplicative inverse of $e$, which is none other than the private key. For example, if $p$ and $q$ are very similar in length, we know $p \approx q \approx \sqrt{n}$ and Fermat’s factorization as two squares $n=a2-b2$ is possible. It is easy to see that $a2-b2=(a+b)\times (a-b)$ and so we have both numbers. If we know many different $n$, we can try breaking the factorization by finding the least common divisor. For example, say we know for two people $n_1$ and $n_2$ and that they share a common factor $p$. Then we have $p=gcd(n_1,n_2)$ and the gcd can be found extremely fast (in polynomial time) thanks to Euclid’s algorithm. This way, we break the security of both accounts.&lt;&#x2F;p&gt;
&lt;p&gt;Other methods work even if the factorization is not known. In the case of low exponents $e$ (such as $3$), it may happen that $M^3$ does not exceed the modulus $n$ and so it may be easily broken by taking the cubic root. On the other hand, if the private key is small, you can use &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Wiener%27s_attack&quot;&gt;Wiener’s&lt;&#x2F;a&gt; or &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;eprint.iacr.org&#x2F;2020&#x2F;1214.pdf&quot;&gt;Boneh-Durfree’s attacks&lt;&#x2F;a&gt; and get the key. A collection of several strategies is on the following &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;RsaCtfTool&#x2F;RsaCtfTool&quot;&gt;link&lt;&#x2F;a&gt;. You can build your own factorization methods or try using open source tools such as &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.sagemath.org&#x2F;&quot;&gt;SageMath&lt;&#x2F;a&gt; to try and see how easy is to perform the factorization of a composite number.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;implementing-some-of-the-key-functions&quot;&gt;Implementing some of the key functions&lt;&#x2F;h2&gt;
&lt;p&gt;To be able to perform operations with RSA, we need to implement first some of the arithmetic operations and define field elements. We will show how to implement some of these in Rust.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;use::std::ops::{Add, Sub, Mul, Div};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub struct FieldPoint {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    num: u128,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    prime: u128,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The first line imports the standard library (in particular, the operations of addition, subtraction, multiplication, and division) which will allow us to override these operators with the expressions we need to use in modular arithmetic.&lt;&#x2F;p&gt;
&lt;p&gt;In the second line, we define a public structure named &lt;code&gt;FieldPoint&lt;&#x2F;code&gt;, which has two fields: &lt;code&gt;num&lt;&#x2F;code&gt; (a number in the range 0 to prime) and &lt;code&gt;prime&lt;&#x2F;code&gt; (this will give us the size and we will perform all operations modulo prime). For practical applications, we need to replace the unsigned integers &lt;code&gt;u128&lt;&#x2F;code&gt; with appropriate variables that allow us to store large integers.&lt;&#x2F;p&gt;
&lt;p&gt;We can now instantiate some methods over &lt;code&gt;FieldPoint&lt;&#x2F;code&gt;, such as how to create one or how to multiply or divide field elements.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;impl FieldPoint {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    pub fn new(num: u128, prime: u128) -&amp;gt; FieldPoint {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        if num &amp;gt; prime {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            panic!(&amp;quot;Not a valid input for a field point, num should be nonnegative and less than prime, obtained {}&amp;quot;, num);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        } else {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            FieldPoint {num:num, prime:prime}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Methods are defined following the keyword &lt;code&gt;impl&lt;&#x2F;code&gt; and the name of the &lt;code&gt;struct&lt;&#x2F;code&gt;. We have a constructor for the &lt;code&gt;FieldPoint&lt;&#x2F;code&gt;, which takes two unsigned &lt;code&gt;u128&lt;&#x2F;code&gt; integers.&lt;&#x2F;p&gt;
&lt;p&gt;To define addition, we can implement the trait &lt;code&gt;Add&lt;&#x2F;code&gt; for &lt;code&gt;FieldPoint&lt;&#x2F;code&gt; in this way&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;impl Add for FieldPoint {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    type Output = Self;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    fn add(self, other: Self) -&amp;gt; Self {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        if self.prime == other.prime {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            FieldPoint {num: (self.num + other.num).rem_euclid(self.prime), prime: self.prime}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        } else {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            panic!(&amp;quot;Cannot add these field points, different prime values {},{}&amp;quot;,self.prime,other.prime);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The addition is simply adding the &lt;code&gt;num&lt;&#x2F;code&gt; fields and if the result exceeds the modulus &lt;code&gt;prime&lt;&#x2F;code&gt;, we take the remainder of the Euclidean division between the sum and the modulus.&lt;&#x2F;p&gt;
&lt;p&gt;Multiplication works in a similar way&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;impl Mul for FieldPoint {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    type Output = Self;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    fn mul(self, other: Self) -&amp;gt; Self {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        if self.prime == other.prime {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            FieldPoint {num: (self.num*other.num).rem_euclid(self.prime), prime: self.prime}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        } else {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            panic!(&amp;quot;Cannot multiply these field points, different prime values, {},{}&amp;quot;,self.prime,other.prime);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We need to define the powers of &lt;code&gt;FieldElement&lt;&#x2F;code&gt;. We can do this in a rather efficient way by squaring and taking the remainder:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn power(&amp;amp;self,index: u128) -&amp;gt; Self {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        if index == 0 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            FieldPoint {num: 1u128, prime: self.prime}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        } else {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let mut aux=index.rem_euclid(self.prime-1u128);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let mut acc: u128 = 1;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            let mut base: u128 =self.num;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            while aux &amp;gt;0{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                if aux%2 == 0 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    base = (base*base).rem_euclid(self.prime);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    aux=aux&#x2F;2u128;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                } else {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    acc = (acc*base).rem_euclid(self.prime);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    aux=aux-1u128; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            FieldPoint {num: acc, prime: self.prime}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The power function takes a &lt;code&gt;FieldElement&lt;&#x2F;code&gt; and &lt;code&gt;index&lt;&#x2F;code&gt;, a &lt;code&gt;u128&lt;&#x2F;code&gt;. If the index is $0$, the result is trivial and we output a &lt;code&gt;FieldElement&lt;&#x2F;code&gt; with &lt;code&gt;num&lt;&#x2F;code&gt; equal to $1$. In any other case, we first reduce &lt;code&gt;index&lt;&#x2F;code&gt; (if &lt;code&gt;index&lt;&#x2F;code&gt; exceeds &lt;code&gt;prime&lt;&#x2F;code&gt;, we can take the remainder of &lt;code&gt;index&lt;&#x2F;code&gt; by &lt;code&gt;prime-1&lt;&#x2F;code&gt; -this works when the modulus is prime since Euler’s theorem says that $a^{p-1}\equiv 1 \pmod{p}$-. A better version would reduce &lt;code&gt;index&lt;&#x2F;code&gt; by $\phi(n)$) and store it in &lt;code&gt;aux&lt;&#x2F;code&gt;. We also define a variable to calculate the result &lt;code&gt;acc&lt;&#x2F;code&gt; and &lt;code&gt;base&lt;&#x2F;code&gt;, where we will repeatedly square and take the remainder of the &lt;code&gt;num&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;We now focus on the squaring and the updating of the result:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;while aux &amp;gt;0{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if aux%2 == 0 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        base = (base*base).rem_euclid(self.prime);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        aux=aux&#x2F;2u128;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    } else {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        acc = (acc*base).rem_euclid(self.prime);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        aux=aux-1u128; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We will go decreasing the index stored in &lt;code&gt;aux&lt;&#x2F;code&gt;: if it is even (the first condition -this could be checked much faster, by inspecting the last bit of &lt;code&gt;aux&lt;&#x2F;code&gt;-), we divide &lt;code&gt;aux&lt;&#x2F;code&gt; by two and update &lt;code&gt;base&lt;&#x2F;code&gt; to the remainder of its square. If it is odd, then we proceed to update the result in &lt;code&gt;acc&lt;&#x2F;code&gt; and decrease &lt;code&gt;aux&lt;&#x2F;code&gt; by one (which means that in the next step it will be even).&lt;&#x2F;p&gt;
&lt;p&gt;To convince ourselves, let’s take a short numerical example, while we follow the instructions. Let’s take &lt;code&gt;prime&lt;&#x2F;code&gt; as 11, &lt;code&gt;num&lt;&#x2F;code&gt; as 4, and &lt;code&gt;index&lt;&#x2F;code&gt; as 39.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. We set `aux` equal to the remainder of 39 and 10 (which is also $\phi(11)$). We get `aux=9`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Since $9&amp;gt;0$, we go inside the while loop. $9$ is odd, so `acc=9` and `aux=8`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. `aux` is even, so `base=4*4=16`; we have to reduce the number by taking the remainder by $11$, so `base=5` and `aux=4`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. `aux` is even, so `base=5*5=25` and we get `base=3` and `aux=2`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. `aux` is once again even, `base=9` and `aux=1`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    6. `aux` is odd, we get `acc=9*4=36-&amp;gt;3` and `aux=0`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    7. Since `aux=0`, we jump outside the while loop and the function returns the `FieldPoint` (`num`=3,`prime`=11).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Another function that we need is the greatest common divisor. A very simple form of the algorithm looks like this&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn gcd(a: u128,b: u128) -&amp;gt; u128 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut r0: u128=b;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut r1: u128=a;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if a&amp;gt;b {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        r0 = b;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        r1 = a;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    } &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut r2: u128 = 1;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    while r2 &amp;gt;0 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        r2=r1.rem_euclid(r0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        r1=r0;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        r0=r2;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    r1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We take two numbers $a$ and $b$ and we output their greatest common divisor. If $a$ is smaller than $b$ we initialize the dividend as $b$ and the divisor as $a$ (this makes us chop the larger number by the smaller one); otherwise we invert the selection. Next, we begin by reducing $r_1$ by $r_0$ and we change the roles (since $r_2$ is smaller then $r_0$). A numerical example helps illustrate the points:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Take a=12, b=8 (we can immediately see that the right answer is 4, but this helps us see how the algorithm finds it).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. $r_0=8$, $r_1=12$, $r_2=1$ so we immediately enter the while loop.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. $r_2=4$ since the remainder of $12$ divided by $8$ is 4.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. $r_1=8$ and $r_0=4$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. Since $r_2$ is not zero, we keep it inside the loop.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    6. $r_2=0$ (since $8$ is divisible by $4$), $r_1=4$ and $r_0=0$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    7. Now $r_2=0$ so we exit the loop and the function outputs $gcd=4$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Carmichael’s totient function can be easily calculated with the help from the previous function:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn lambda(p: u128,q: u128) -&amp;gt; u128 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let greatest_div: u128=gcd(p-1,q-1);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    (p-1)*(q-1)&#x2F;greatest_div&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Inverses can be easily calculated with help from the extended Euclidean algorithm:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn inversion(a:i128,b:i128) -&amp;gt; i128 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut t=0i128;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut r=b;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut t1=1i128;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut r1=a;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    while r1 != 0i128 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let q=r.div_euclid(r1);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        (t,t1)=(t1,t-q*t1);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        (r,r1)=(r1,r-q*r1);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if r != 1i128 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return 0i128;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    if t&amp;lt;0{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        t=t+b;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    t&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let’s see how it works for a simple case: $a=3$, $b=5$; the inverse of $3$ (modulo 5) is $2$. The algorithm begins:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. $t=0$, $t_1=1$, $r=5$, $r_1=3$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Since $r_1=3 \neq 0$ we loop: $q=1$, $t=1$, $t_1=0-1\times 1=-1$, $r=3$, $r_1=2$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. $r_1 \neq 0$, $q=1$, $t=-1$, $t_1=1-1\times (-1)=2$, $r=2$, $r_1=1$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. $r_1 \neq 0$, $q=2$, $t=2$, $t_1=-1-2\times 2=-5$, $r=1$ and $r_1=0$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. $r_1 = 0$, so the function outputs $t=2$, which is the correct answer.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can test primality using the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Miller%E2%80%93Rabin_primality_test&quot;&gt;Miller-Rabin test&lt;&#x2F;a&gt;. Given an odd number $n$, we can write it as $n=2^r\times d +1$, for some $r&amp;gt; 0$ and $d$ an odd number. If $d$ is prime, then:&lt;br &#x2F;&gt;
$a^d \equiv 1 \pmod{n}$&lt;br &#x2F;&gt;
$a{2r \times d}\equiv -1 \pmod{n}$&lt;br &#x2F;&gt;
If $n$ is prime, then it satisfies Fermat’s little theorem and the only square roots of $1$ are $-1$ and $1$. If any of these conditions is not fulfilled, $n$ is not prime (if it passes, it could be composite, depending on the choice of $a$, known as the witness). Checking several $a$ allows us to make sure that the test passed for a composite number. The decomposition is easy to do:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub fn decompose(n: u128) -&amp;gt; (u128,u128) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let mut d: u128=n-1;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let mut r: u128=0;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        while d%2 == 0 {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            d &#x2F;= 2;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            r += 1;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        (d,r)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Since $n-1$ is even, we can take factors of $2$ repeatedly, until $d$ is no longer divisible by $2$. The condition can be checked faster by looking at the last bit of $n-1$.&lt;&#x2F;p&gt;
&lt;p&gt;The core of the Miller-Rabin test is (it yields true if it is probably prime):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn miller_rabin(a: u128, n: u128, d: u128, r: u128) -&amp;gt; bool {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let n_minus_one: u128 = n - 1u128;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let field=FieldPoint::new(a,n);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let mut x = field.power(d);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        let mut count: u128 =1;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        if x.num == 1 || x.num == n_minus_one {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            return true;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        while count &amp;lt; r {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            x = x.power(2u128);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            if x.num == n_minus_one {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                return true;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            count += 1u128;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you have a composite number and try several witnesses, it is very likely it will fail at least one (and stop at the first one) and so we can discard the number.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;We covered the basics of RSA and discussed its mathematical foundations. We also gave some of the attacks it may subjected to, especially when the implementation is not done properly. Finally, we gave some of the basic functions to build RSA (such as modular powers, calculating inverses and checking for primality via the Rabin-Miller test). Even if you could build your own RSA from scratch, it is not advisable, since it could be vulnerable to several attacks (unless it is very well implemented, of course).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;notes&quot;&gt;Notes&lt;&#x2F;h2&gt;
&lt;p&gt;(1) Even if you can code it very fast, there is no guarantee that your implementation is useful for real-life. There are several things to check and one should try to follow the standards. Besides, you should know cryptography and understand some of the underlying math).&lt;br &#x2F;&gt;
(2) For security reasons, $p$ and $q$ should have different number of digits (unless you want your system to be vulnerable to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Fermat%27s_factorization_method&quot;&gt;Fermat’s factorization&lt;&#x2F;a&gt;) and the selection should be truly random (careful with pseudorandom generators which are not meant for cryptographic applications, they are part of the recipe for disaster).&lt;br &#x2F;&gt;
(3) If you want something better, compute &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Carmichael_function&quot;&gt;Carmichael’s totient function&lt;&#x2F;a&gt; $\lambda (n)=lcm(q-1,p-1)$, where $lcm$ stands for least common multiple of $q-1$ and $p-1$. Whenever $\phi$ shows up, you can replace it with $\lambda$.&lt;br &#x2F;&gt;
(4) This is the same as saying that $d\times e-1$ is divisible by $\phi(n)$ or $d\times e=k\phi(n)+1$ for some integer $k$. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Euler%27s_theorem&quot;&gt;Euler’s theorem&lt;&#x2F;a&gt; states that $a^{\phi(m)}\equiv 1 \pmod{m}$ if $a$ and $n$ are coprime.&lt;br &#x2F;&gt;
If we take $m=\phi(n)$ and $a=e$ we see that $e\times e^{\phi(\phi(n))-1}\equiv 1 \pmod{\phi(n)}$, $d=e^{\phi(\phi(n))-1}$, which means that $d$ can be calculated by performing powers of $e$.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Math Survival Kit for Developers</title>
          <pubDate>Fri, 19 Aug 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/math-survival-kit-for-developers/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/math-survival-kit-for-developers/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/math-survival-kit-for-developers/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;When working with cryptographic applications you need to understand some of the underlying math (at least, if you want to do things properly). For example, the RSA cryptographic system (which was one of the earliest methods and most widely adopted, until it lost ground to better methods, such as those based on elliptic curves) works by encrypting a message $M$ (expressed as a number in the range 1,2,3,…$n-1$, with $n$ a large composite number) with a public key $e$ doing the following calculation:&lt;br &#x2F;&gt;
$E(M)=M^e \pmod{n}$&lt;br &#x2F;&gt;
If you want to decrypt the message, you need the private key, $d$ and perform:&lt;br &#x2F;&gt;
$M=E(M)^d \pmod{n}$.&lt;br &#x2F;&gt;
Now, what do all these calculations mean and why does RSA work? The trick relies on Euler’s theorem and the fact that $d$ and $e$ are related by $d\times e \equiv 1 \pmod{\phi(n)}$, so that when we apply $e$ and afterward $d$, “it is the same as” elevating the message to 1. Of course, there are quite many symbols you might not understand, but some key concepts are, in fact, quite straightforward. They are just shrouded in the mist by all the math jargon, which makes things very easy to state for those knowing the meaning, but it can be quite challenging for someone who is not acquainted with them.&lt;&#x2F;p&gt;
&lt;p&gt;Another problem frequently showing up is finding prime numbers (in general, very large numbers, with 100 or more digits) or determining whether a certain number is prime or composite. For example, in zk-SNARKs (zero-knowledge succinct non-interactive arguments of knowledge), one of the key ingredients is the ability to perform (something similar to) homomorphic encryption. This is achieved in practice by pairing two elliptic curves over two sets of numbers, where the total number of elements is the prime $m$, satisfying $m=k\times 2^N+1$, with $k$ an odd number and $N$ a large number. We say that $m$ has large 2-adicity and is expressed in compact form as $m-1\equiv 0 \pmod{2^N}$ or $2^N \mid m-1$ (this is read as $2^N$ divides $m-1$). In RSA, the number $n$ is the product of two large prime numbers, $p$ and $q$, that is, $n=p\times q$. If you choose two primes that are very close to each other, your cryptographic system could be easily broken using &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Fermat%27s_factorization_method&quot;&gt;Fermat’s method to factorize numbers&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;We see, therefore, that we need to understand the math behind it to know which tricks we can apply to solve a problem easily, how to break a cryptographic system or what are the limitations or weaknesses of our own systems. We will be explaining many key ideas of number theory and abstract algebra to help you build the foundations you need to deal with cryptography.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;natural-numbers-integers-rational-real-and-complex-numbers&quot;&gt;Natural numbers, Integers, Rational, Real and Complex numbers.&lt;&#x2F;h2&gt;
&lt;p&gt;Natural numbers are those we use to count objects and were the first things we learned at school: $1,2,3,4…$ are natural numbers. The set (collection) of these numbers is frequently represented by $\mathbb{N}$. Numbers like $-1$, $-2$, $0$, etc, are part of the integers; the set is represented by $\mathbb{Z}$ (from German, &lt;em&gt;zahlen&lt;&#x2F;em&gt; , numbers). Numbers that can be expressed as the ratio of two integers $a$ and $b$ (with $b\neq 0$) are called rational, $r=a&#x2F;b$ and the set is denoted by $\mathbb{Q}$. Rational numbers can be extended with the addition of irrational numbers (such as $\pi$ and $e$) to form the set of real numbers $\mathbb{R}$. You might have also heard of the complex numbers $\mathbb{C}$, which contain numbers such as $i$, where $i^2=-1$.&lt;&#x2F;p&gt;
&lt;p&gt;In the integers, we have the four basic operations: addition, subtraction, multiplication and division. Let’s focus first on addition and subtraction:&lt;br &#x2F;&gt;
If we take $a$ and $b$ in $\mathbb{Z}$, then $c=a+b$ and $d=a-b$ are also in $\mathbb{Z}$. We say the sum and subtraction are closed operations on the set.&lt;br &#x2F;&gt;
2. If we add $0$ to any number $a$, we get $a$, that is, $a+0=0+a=a$. $0$ is the additive identity of $\mathbb{Z}$.&lt;br &#x2F;&gt;
3. We know that if we sum $a$ and $-a$ we get $0$. That is, $a+(-a)=a-a=0$, so subtracting is the same as adding $-a$. $-a$ is the additive inverse of $a$.&lt;br &#x2F;&gt;
4. Given $a$, $b$ and $c$, $a+(b+c)=(a+b)+c$. This is the associative property.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;groups&quot;&gt;Groups&lt;&#x2F;h2&gt;
&lt;p&gt;The above properties show that the set of integers $\mathbb{Z}$ with the $.+.$ operation form an algebraic group. Other sets, combined with different operations, have the same mathematical structure. For example, positive rational numbers with multiplication have a group structure. $n\times n$ invertible matrices form a group under the matrix multiplication. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Vector_space&quot;&gt;Vector spaces&lt;&#x2F;a&gt; form a group under the addition (if you take any two vectors $u$ and $v$, their sum is always in the vector space). Elliptic curve cryptography uses the fact that adding two points over an elliptic curve always results in a third point over the curve. Groups appear in many applications in Mathematics, Physics and Chemistry. We can define a group as a (non-empty) set $G$ together with a binary operation (that is, an operation that takes two input elements from the set $G$) $\times$ satisfying:&lt;br &#x2F;&gt;
G1. If $a$ and $b$ are in the set, then $a\times b=c$ is also in the set.&lt;br &#x2F;&gt;
G2. There is an identity element, $e$, such that $e\times a=a\times e=a$.&lt;br &#x2F;&gt;
G3. If $a$ is in the set, there is some $b$ in the set such that $a\times b=e$. We say that $b$ is the inverse of $a$ and denote it $b=a^{-1}$.&lt;br &#x2F;&gt;
G4. For $a,b,c$, $a\times (b\times c)=(a\times b)\times c$.&lt;&#x2F;p&gt;
&lt;p&gt;The notation in groups is sometimes confusing and people can freely use additive (+) or multiplicative ($\times$) notation, and call their identities either $0$ or $1$. This doesn’t matter much, since the binary operation can be quite weird (such as “addition” on elliptic curves). If you can start by looking at things a little bit more abstractly, it will pay off very quickly.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Exercise: Take the space of $n\times n$ matrices, such that their determinant is non-zero (that is, the set of invertible matrices). Show that this is a group.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We also learned at school that addition in the integers is commutative (that is, the order of the factors does not change the result $a+b=b+a$). Not all groups satisfy this condition, though. For those privileged groups, we have the name Abelian (or commutative) group. An Abelian group has an additional condition:&lt;br &#x2F;&gt;
G5. If $a$, $b$ are in $G$, $a\times b = b\times a$.&lt;&#x2F;p&gt;
&lt;p&gt;When we look at multiplication and division in the integers, we see that there are some problems.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. If $a$ and $b$ are integers, $a\times b=c$ is also an integer. The operation is closed under multiplication.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. If we multiply any number by $1$, we get the same number. $1$ is the multiplicative identity.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Given $a,b,c$, we have $a\times (b\times c)=(a\times b)\times c$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Given $a$, $b$ and $c$, $a\times (b+c)=a\times b+a\times c$ and $(b+c)\times a=b\times a+c\times a$. This is the distributive property.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. If $a$ and $b\neq 0$ are integers, their division $a&#x2F;b$ is not necessarily an integer. For example, $a=3$ and $b=2$ results in $c=3&#x2F;2$, which is a rational (not integer) number. In other words, the operation is not closed.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;rings-and-fields&quot;&gt;Rings and fields&lt;&#x2F;h2&gt;
&lt;p&gt;The set $\mathbb{Z}$ together with addition and multiplication forms a ring. The polynomials with ordinary addition and multiplication also form a ring. $n\times n$ matrices also form a ring under addition and multiplication. Formally, a ring is a set $R$ with two operations $+$ and $\times$ such that:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. R is an abelian group under $+$ (that is, R fulfills all the conditions for a group G1 to G4, plus commutativity, G5).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. There is a multiplicative identity $e$, such that $a\times e=e\times a=a$. Frequently, we use $e=1$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Multiplication is associative.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. We have the distributive property of multiplication concerning addition.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;em&gt;Exercise: Check that the $n\times n$ matrices form a ring with ordinary matrix addition and multiplication.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If we look at the rational numbers, for any non-zero element, we have a multiplicative inverse. For example, $1&#x2F;5$ is the multiplicative inverse of $5$, since $5\times 1&#x2F;5=1$. The division is now a closed operation. Besides, multiplication is also commutative. $\mathbb{Q}$ with the ordinary addition and multiplication is a field. Other examples of fields are $\mathbb{R}$ and $\mathbb{C}$. When the number of elements in the set is finite (such as $4$, $2^{255}-19$, etc), the field is known as a finite field. These will be very important for cryptography.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;some-concepts-from-number-theory&quot;&gt;Some concepts from number theory&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;divisibility&quot;&gt;Divisibility&lt;&#x2F;h3&gt;
&lt;p&gt;We will start by talking about divisibility. Given two natural numbers, $a$ and $b$, we say that $a$ divides $b$ (and write it $a\mid b$) if there is another number $c$ such that $a\times c=b$. $a$ is called a divisor of $b$. If $a$ does not divide $b$, we write $a\nmid b$ and we can write $b=q\times a+r$, where $r&amp;lt;a$, with $q$ the quotient and $r$ the remainder of the division. If $a$ divides $b\times c$, then $a\mid b$ or $a\mid c$. Another fact is that if $a\mid b$ and $a\mid c$, then $a\mid (x\times b+y\times c)$ for any numbers $x,y$.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;prime-numbers&quot;&gt;Prime Numbers&lt;&#x2F;h3&gt;
&lt;p&gt;A number $p&amp;gt;1$ is called prime if its only divisors are $1$ and itself. Otherwise, the number is composite. Examples of prime numbers are $2,3,5,7,11,13,17,19,23,29,31,…$. The &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Fundamental_theorem_of_arithmetic&quot;&gt;fundamental theorem of arithmetic&lt;&#x2F;a&gt; tells us that any number can be expressed in a unique way (up to ordering) as a product of powers of prime numbers. For example, $20=2^2\times 5$, $186=2\times 3\times 31$, $5=5$, etc. Finding prime numbers is crucial for cryptography. One easy way (but by no means practical for large numbers) to see whether a number $p$ is prime or not consists in checking whether it is divisible by all primer numbers smaller than $p$. The problem is that, if $p$ is very large, this can be pretty inefficient. There are some better and faster algorithms, but we will cover them some other time.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Exercise: Find all prime numbers that are smaller than 100.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;greatest-common-divisor-and-euclid-s-algorithm&quot;&gt;Greatest common divisor and Euclid’s algorithm&lt;&#x2F;h3&gt;
&lt;p&gt;An important concept is that of the greatest common divisor: given two numbers $a$ and $b$ we want to find the largest number $c$ such that $c\mid a$ and $c\mid b$. We denote this by $c=gcd(a,b)$ or simply $c=(a,b)$. For example, $20=2^2\times 5$ and $50=2\times 5^2$. Both numbers are divisible by $1,2,5,10$. $10$ is the greatest number dividing both and so $gcd(20,50)=10$. Two numbers $a,b$ are called relatively prime (or coprime) if $gcd(a,b)=1$. If $a$ and $b$ are both prime (and different), $1$ is the only common divisor. However, $8$ and $9$ are not prime themselves ($8=2^3$ and $9=3^2$), but their only common divisor is $1$ and are coprime.&lt;&#x2F;p&gt;
&lt;p&gt;The greatest common divisor satisfies the following equation, for some $x$ and $y$:&lt;br &#x2F;&gt;
$x\times a+y\times b=gcd(a,b)$&lt;br &#x2F;&gt;
The greatest common divisor can be found very efficiently using the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Euclidean_algorithm&quot;&gt;Euclidean algorithm&lt;&#x2F;a&gt; and the numbers $x$ and $y$ can also be found with little extra cost using the extended Euclidean algorithm.&lt;&#x2F;p&gt;
&lt;p&gt;To understand the algorithm, let’s look at an example: say we want to calculate the gcd(2502,864). The algorithm takes advantage that the remainder is always less than the divisor, so we can “chop down” the larger number; this chopping does not affect the largest common divisor.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Let&amp;#39;s find the remainder of $2502&#x2F;864$, $r_0=774$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Let&amp;#39;s find the remainder of $864&#x2F;774$, $r_1=90$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. The remainder of $774&#x2F;90$ is $r_2=54$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. $r_3=36$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. $r_4=18$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    6. $r_5=0$, since $36$ is divisible by $18$. So, the greatest common divisor is $18$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can see, from the factorization of $864=2^5\times 3^3$ and $2502=2\times 3^2\times 139$, that the $gcd$ is equal to $2\times 3^2=18$. The advantage is that we found it in a few steps (6) and we didn’t have to know the factorization (which, for large numbers can be really hard to find. As a matter of fact, that is the key to the RSA cryptosystem).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;congruences-and-modular-arithmetic&quot;&gt;Congruences and modular arithmetic&lt;&#x2F;h3&gt;
&lt;p&gt;One problem we face with computers is that the numbers we can work with are limited. Besides, in some cases, we are not interested in a number itself, but rather in its belonging to a certain class or group. For example, when we bet on a roulette, we can choose whether the result will be even or odd. If it is even, then $r=2\times k$, for some $k \in {0,1,2,3…18}$. If it is odd, then $r=2\times k+1$. We notice that if we want to check parity, we only need to look at the remainder, which can take two values in this case: $0$ or $1$. In fact, when we want to check whether a number is even in the computer, we look at the leftmost bit and check whether it is zero or not. For the case of $2$, we see that any number $a$ satisfies either:&lt;br &#x2F;&gt;
$a\equiv 0 \pmod{2}$&lt;br &#x2F;&gt;
$a\equiv 1 \pmod{2}$&lt;br &#x2F;&gt;
We say that $a$ is congruent to $0$ (or $1$) modulo $2$. This way, we split all the numbers into two categories: even and odd. We can do the same for any number $p&amp;gt;1$, remembering that the remainder is $0 \leq r \leq p-1$. This can also be seen as $a\equiv r \pmod{p}$ as $p\mid a-r$ or $a=k\times p+r$. This notation was invented by Gauss and is really powerful to study a lot of complex problems. We can perform usual operations such as addition and multiplication, but we have to be careful of how things work, given that results will always have to be in the range $0 \leq r \leq p-1$ (As a side note, you could choose a different range, such as ${-2,-1,0,1,2,p-3}$, but it can be confusing and we should better stick to our first choice).&lt;&#x2F;p&gt;
&lt;p&gt;In the case of the sum, we can add them just as regular numbers and, if the result exceeds $p$, take the remainder. For example, let’s take $p=7$, so the elements we have are ${0,1,2,3,4,5,6}$. First, we see that $0$ is an element of the set and that adding it to any number does not change the result. If we add $2$ and $3$ the result is $5$. If we add $5$ and $4$, we get $9$, but&lt;br &#x2F;&gt;
$4+5=9\equiv 2 \pmod{7}$&lt;br &#x2F;&gt;
$2$ is just the remainder of the division of $9$ by $7$. We see that the result stays in the original set. What happens when we add $4$ and $3$?&lt;br &#x2F;&gt;
$4+3=7\equiv 0 \pmod{7}$&lt;br &#x2F;&gt;
We get $0$! That is because $7$ is divisible by itself and the remainder is $0$. We see that $4$ is the additive inverse of $3$ under this arithmetic. Similarly, $1$ and $6$ are each other’s inverse, $2$ and $5$. We can recognize that the set ${0,1,2,3,4,5,6}$ with the sum done modulo $7$ is an abelian group. Subtraction can be easily defined as adding the inverse of the number or just performing ordinary subtraction and then taking the result modulo $p$.&lt;&#x2F;p&gt;
&lt;p&gt;With multiplication we get something similar. For example,&lt;br &#x2F;&gt;
$4\times 5=20\equiv 6 \pmod{7}$.&lt;br &#x2F;&gt;
Taking the modulo operation ensures that we always stay inside the set. We also see that $1$ works as the multiplicative identity since any number multiplied by $1$ stays the same. Let’s look at what happens with $6\times 6$:&lt;br &#x2F;&gt;
$6\times 6=36\equiv 1 \pmod{7}$.&lt;br &#x2F;&gt;
We multiplied $6$ by itself and got $1$! We talked before that division $a&#x2F;b$ could be restated as $a\times b^{-1}$, where $b\times b^{-1} = 1 = b^{-1} \times b$. We see that $6$ is its own multiplicative inverse with the multiplication modulo $p$. We can also see that:&lt;br &#x2F;&gt;
$3\times 5 = 15\equiv 1 \pmod{7}$&lt;br &#x2F;&gt;
$2\times 4 = 8\equiv 1 \pmod{7}$&lt;br &#x2F;&gt;
So, $3 = 5^{-1}$ and $2 = 4^{-1}$! This can sound weird, but we have to remember that we are working with congruence. We can understand the precise meaning of this by rephrasing. Let’s take the case of $6$ and $6$. There are two numbers $a = q_1\times 7+6$ and $b = q_2\times 7+6$ (because that is what the congruence means). Let’s take the product $a\times b$:&lt;br &#x2F;&gt;
$a\times b = (q_1\times 7+6)\times (q_2\times 7+6)$&lt;br &#x2F;&gt;
Let’s apply the distributive law:&lt;br &#x2F;&gt;
$a\times b = q_1\times q_2 \times 7^2+6\times 7\times (q_1+q_2)+36$&lt;br &#x2F;&gt;
Let’s split this further $36=1+35=1+7\times 5$ and regroup, taking as a common factor $7$:&lt;br &#x2F;&gt;
$a\times b = 7\times (q_1\times q_2\times 7+6\times(q_1+q_2)+5)+1$&lt;br &#x2F;&gt;
The first term is divisible by $7$, so it is congruent to $0$. Or, if we subtract $1$ to $a\times b$, we see that it is divisible by $7$ (since it is the product of $7$ and an integer).&lt;&#x2F;p&gt;
&lt;p&gt;We can see that, if $p$ is prime, then the set ${0,1,2,…p-1}$ with addition and multiplication modulo $p$ is a finite field.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Exercise: Prove that this is indeed a finite field.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;mathbb-z-n-mathbb-z-as-a-group-cyclic-groups&quot;&gt;$\mathbb{Z}&#x2F;n\mathbb{Z}$ as a group. Cyclic groups.&lt;&#x2F;h3&gt;
&lt;p&gt;You will frequently see these sets are denoted as $\mathbb{Z}&#x2F;p\mathbb{Z}$. We have to be very careful if we want to work with $n$ not prime in $\mathbb{Z}&#x2F;n\mathbb{Z}$ (in this case, it is not a finite field either). For example, let’s try to solve this equation:&lt;br &#x2F;&gt;
$(x+2)\times(x+1)\equiv 0 \pmod{12}$&lt;br &#x2F;&gt;
We could use our knowledge of math and, when the product of two numbers is $0$, at least one of them is $0$ (spoiler’s alert: this will go wrong):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. $(x+2)\equiv 0 \pmod{12}$. If $x=10$, then $x+2=12\equiv 0$, since it is divisible by 12.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. $(x+1)\equiv 0 \pmod{12}$. If $x=11$, then $x+1=12\equiv 0$, since it is divisible by 12.  &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let’s pick now $2$ and see what happens:&lt;br &#x2F;&gt;
$(2+2)\times(2+1)=12\equiv 0 \pmod{12}$.&lt;br &#x2F;&gt;
So $2$ is a solution to the equation, but $2+2\equiv 4\not\equiv 0$ and $2+1\equiv 3\not\equiv 0$. This happens because $12$ is not a prime number.&lt;&#x2F;p&gt;
&lt;p&gt;As a matter of fact, given $a$ and $n$, we have that $a$ has an inverse (modulo $n$) if and only if $gcd(a,n)=1$, that is, $a$ and $n$ are coprime. In the previous example, $3$ is not coprime to $12$ (they have $3$ as a common divisor).&lt;&#x2F;p&gt;
&lt;p&gt;If the set is not too large, we can find inverses just by trial and error. However, it would be nice to have some results that help us compute inverses and how to calculate (integer) powers of numbers.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s focus on a prime number $p$ and take all the non-zero elements of the set, $(\mathbb{Z}&#x2F;p\mathbb{Z})^\star$. Let’s fix $p=7$, so $(\mathbb{Z}&#x2F;p\mathbb{Z})^\star = {1,2,3,4,5,6}$ and let’s focus on multiplication over the set. We can define the power $a^n=a\times a\times a\times …\times a$. Obviously, $1$ is not interesting, because $1^n=1$, so let’s take $5$:&lt;br &#x2F;&gt;
$5^1\equiv 5 \pmod{7}$&lt;br &#x2F;&gt;
$5^2\equiv 4 \pmod{7}$&lt;br &#x2F;&gt;
$5^3\equiv 6 \pmod{7}$&lt;br &#x2F;&gt;
$5^4\equiv 2 \pmod{7}$&lt;br &#x2F;&gt;
$5^5\equiv 3 \pmod{7}$&lt;br &#x2F;&gt;
$5^6\equiv 1 \pmod{7}$&lt;br &#x2F;&gt;
$5^7\equiv 5 \pmod{7}$&lt;br &#x2F;&gt;
$5^8\equiv 4 \pmod{7}$&lt;br &#x2F;&gt;
$5^{13}\equiv 5 \pmod{7}$&lt;br &#x2F;&gt;
We see that the powers of $5$ span all the elements of the group. We also see that numbers repeat themselves at an interval of $6$, that is $4 = 5^2 = 5^8 = 5^{14}…$. Let’s look at $3$:&lt;br &#x2F;&gt;
$3^1\equiv 3 \pmod{7}$&lt;br &#x2F;&gt;
$3^2\equiv 2 \pmod{7}$&lt;br &#x2F;&gt;
$3^3\equiv 6 \pmod{7}$&lt;br &#x2F;&gt;
$3^4\equiv 4 \pmod{7}$&lt;br &#x2F;&gt;
$3^5\equiv 5 \pmod{7}$&lt;br &#x2F;&gt;
$3^6\equiv 1 \pmod{7}$&lt;br &#x2F;&gt;
$3^7\equiv 3 \pmod{7}$&lt;br &#x2F;&gt;
We got all the elements (albeit in a different order). Finally, let’s look at $2$:&lt;br &#x2F;&gt;
$2^1\equiv 2 \pmod{7}$&lt;br &#x2F;&gt;
$2^2\equiv 4 \pmod{7}$&lt;br &#x2F;&gt;
$2^3\equiv 1 \pmod{7}$&lt;br &#x2F;&gt;
$2^4\equiv 2 \pmod{7}$&lt;br &#x2F;&gt;
This time we didn’t span all the elements of the group and we got to the same number after $3$. We will show that these results are valid in general (provided we’re working modulo a prime number).&lt;&#x2F;p&gt;
&lt;p&gt;First, we can prove that the set $(\mathbb{Z}&#x2F; p\mathbb{Z})^\star$ together with multiplication forms an abelian group (the product can never give 0 since all the numbers are not divisible by $p$). Second, the group is finite, since the number of elements is finite (6 in our example); its order is $6$. We also saw that by repeatedly multiplying $5$ by itself (that is, taking powers of $5$), we can generate all the elements of the group (note that everything repeats after $6$, which is the order of the group). Since the group can be generated by one of its elements, it is a (finite) cyclic group.&lt;&#x2F;p&gt;
&lt;p&gt;For an element $a$, the lowest positive integer $n$ such that $a^n\equiv 1 \pmod{p}$ is known as the order of $a$. The elements of the group with their respective order in parentheses are: $1 (1)$, $2 (3)$, $3 (6)$, $4 (2)$, $5(6)$, $6(2)$. We can see that the orders of each element divide the order of the group, $6$. We will present the following theorems, which show that this is not a coincidence.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;three-useful-theorems-and-the-magic-behind-rsa&quot;&gt;Three useful theorems and the magic behind RSA&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Fermat%27s_little_theorem&quot;&gt;Fermat’s Little Theorem&lt;&#x2F;a&gt;: If $p$ is prime, then, for any integer $a$ we have that $a^p-a$ is divisible by $p$:&lt;br &#x2F;&gt;
$a^p\equiv a \pmod{p}$.&lt;br &#x2F;&gt;
&lt;em&gt;Exercise: Check that this is indeed valid for all elements of $(\mathbb{Z}&#x2F;7\mathbb{Z})^\star$&lt;&#x2F;em&gt;&lt;br &#x2F;&gt;
If $a$ is coprime to $p$, we can write this equivalently:&lt;br &#x2F;&gt;
$a^{p-1}\equiv 1 \pmod{p}$&lt;br &#x2F;&gt;
An interesting consequence is that we can calculate inverses by doing $a^{-1} = a^{p-2}$, even though in some cases we are overestimating the power (for example, $6\times 6\equiv 1 \pmod{7}$).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Euler%27s_theorem&quot;&gt;Euler’s theorem&lt;&#x2F;a&gt;: If $a$ and $n$ are positive coprime integers, then $a^{\phi(n)}\equiv 1 \pmod{n}$, where $\phi(n)$ is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Euler%27s_totient_function&quot;&gt;Euler’s phi (or totient) function&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Euler’s $\phi(n)$ function counts the numbers $m &amp;lt; n$ that are coprime to $n$. For example, if we take $n = 5$, the numbers $1,2,3,4$ are all coprime to $5$ and $\phi(5) = 4$ (this is reasonable, since $5$ is prime). If we take $8$, we have ${ 1 , 2 , 3 , 4 , 5 , 6 , 7}$; however, only $1,3,5,7$ are coprime to $8$, so $\phi(8)=4$. For prime numbers, we have&lt;br &#x2F;&gt;
$\phi(p)=p-1$&lt;br &#x2F;&gt;
so, Euler’s theorem gives us Fermat’s theorem as a particular case. Another useful property is that if $m$ and $n$ are relatively prime, then&lt;br &#x2F;&gt;
$\phi(m\times n)=\phi(n)\times \phi(m)$&lt;br &#x2F;&gt;
This shows that $\phi$ is a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Multiplicative_function&quot;&gt;multiplicative function&lt;&#x2F;a&gt;. In particular, if $n$ is the product of two primes, $p$ and $q$, then&lt;br &#x2F;&gt;
$\phi(n) = (p-1)\times (q-1)$&lt;br &#x2F;&gt;
RSA’s working principle is here. The public key $e$ and private $d$ are multiplicative inverses, modulo $\phi(n)$,&lt;br &#x2F;&gt;
$d\times e \equiv 1 \pmod{\phi(n)}$&lt;br &#x2F;&gt;
This means that $d\times e = 1+k\phi(n)$ for some integer $k$, so when we compute&lt;br &#x2F;&gt;
$M^{ e \times d } = M^{ 1 + k \phi(n) } = M \times M^{ k \phi(n) } \equiv M \pmod{n}$&lt;br &#x2F;&gt;
since $M^{k \phi(n) } = {(M^{ \phi(n) })}^k \equiv 1^k \pmod{n}$. RSA is only as hard as it is factoring the number $n$ and over the years the length of the keys has increased significantly (it is around 2000 to 4000 bits); elliptic curves, on the other hand, give the same level of security for shorter keys.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;subgroups-lagrange-s-theorem&quot;&gt;Subgroups. Lagrange’s theorem&lt;&#x2F;h3&gt;
&lt;p&gt;We saw that the order of $(\mathbb{Z}&#x2F;7\mathbb{Z})^\star$ was 6 and that if we take any element $a$, doing $a^6\equiv 1 \pmod{7}$. However, for $2$ we can do $2^3\equiv 1 \pmod{7}$. A subgroup $H$ is a subset of $G$, that is itself a group, that is, satisfies G1-G4. For example, if we consider the subset $H={1}$, this is a subgroup of order $1$. Why? Because $1\times 1=1$, so the operation is closed and all other properties follow from the operations of the group $G$. $G$ is also a subgroup of itself. These two are called the trivial subgroups of $G$ (which are not very interesting). The set ${1,2,4}$ is a subgroup of $(\mathbb{Z}&#x2F;7\mathbb{Z})^\star$. To check this, we need to see that if an element is in the set, so is its inverse, the identity belongs to the set and the operation is closed. Let’s check this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * $1$ is in the set and $1$ is its own inverse.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    * The operation is closed, because $2\times 2\equiv 4 \pmod{7}$, because $4\times 4=16\equiv 2 \pmod{7}$ and because $2\times 4=8\equiv 1 \pmod{7}$ (we don&amp;#39;t need to check the products with $1$ since that is obvious). We also checked the inverses, since $4=2^{-1}$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The subset ${1,2,4}$ forms a subgroup of order $3$. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Lagrange%27s_theorem_(group_theory)&quot;&gt;Lagrange’s theorem&lt;&#x2F;a&gt; states that the order of a subgroup divides the order of the group. We have another subgroup ${1,6}$, which is of order $2$. These are non-trivial subgroups. If the order of a group is prime, then its only subgroups are the trivial subgroups (since $p$ is prime, the subgroups can only be of order $1$ and $p$). A group whose only subgroups are the trivial ones is known as a simple group. For example, $\mathbb{Z}&#x2F;7\mathbb{Z}$ with addition is the group ${0,1,2,3,4,5,6}$ of order $7$. There are no subgroups other than the whole group and ${0}$. Note that the order of each element (other than zero, which has order $1$) is $7$, since $7\times a=a+a+a+a+a+a+a$ is divisible by $7$ and, therefore, congruent to $0$ modulo $7$. The fact that some groups can be broken down into smaller subgroups is of concern when working with elliptic curves: if the group is not of prime order, it can be broken down into smaller groups and an attacker may break the system by performing searches on these subgroups.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-discrete-logarithm-problem&quot;&gt;The discrete logarithm problem&lt;&#x2F;h3&gt;
&lt;p&gt;Given a group, we can apply the operation repeatedly on a point $g$ to get to a point $P$, that is $g^k=g\times g\times g\times … \times g=P$. For example, in $(\mathbb{Z}&#x2F;7\mathbb{Z})^\star$, $5$ generates all the elements by successive multiplications with itself. We could then ask how many times $x$ should we multiply $5$ with itself to get to $3$, that is, $5^x\equiv 3 \pmod{7}$. Since we know that the order of the group is $6$, we should only concern ourselves with numbers $0-6$. If we look above or try all combinations, $5^5\equiv 3 \pmod{7}$ so $x=5$. Similarly, if we look for $y$ such that $5^y\equiv 4 \pmod{7}$, we get $y=2$. The problem of finding $x$ so that $g^k=P$ is known as the discrete logarithm problem (in number theory, $x$ and $y$ are known as indices). We quickly see that this logarithm works quite differently from the common logarithm on the real numbers (though the idea is the same, given $y$, find $x$ such that $e^x=y$). There is no obvious pattern, it is not increasing and if we had to search over a large set, it could be really daunting. Many cryptographic systems rely on the hardness of this problem over a finite cyclic group.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;We presented some basic terms and concepts from number theory and algebra that will be useful when reading cryptography, since many key concepts and strategies rely on math. The notions of groups, rings and fields and prime numbers show up almost all the time. Soon we will continue with other important tools and concepts that will help us understand how elliptic curve cryptography works, how to perform faster operations over groups and how to combine elliptic curves to build zk-SNARKs.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Need for speed: Elliptic curves chapter</title>
          <pubDate>Fri, 12 Aug 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/need-for-speed-elliptic-curves-chapter/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/need-for-speed-elliptic-curves-chapter/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/need-for-speed-elliptic-curves-chapter/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;Elliptic curves (EC) have gained widespread acceptance as tools for cryptography. They offer several advantages over other methods, such as RSA, providing equal levels of security with shorter keys (for example, 228-bit keys in EC cryptography are as good as 2300-bit RSA keys). This represents an advantage, since more and more cryptography is done on smart-phones, which are less powerful than computers. These are curves defined by the equation $y^2 = x^3 + ax + b$ over some &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Field_(mathematics)&quot;&gt;field&lt;&#x2F;a&gt; (for example, the real numbers). Their shape depends on $a$ and $b$, but they look more or less like the following picture:&lt;br &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;rk6M8y0.jpg&quot; alt=&quot;An elliptic curve over the real numbers&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In cryptography, we are not interested in curves defined over the real numbers. We work with them over some finite field $\mathcal{F_p}$ (that is, a set with a finite number of elements, such as $53$, $101$ o $2^{255}-19$), because that gives us a mathematical structure (a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Finite_group&quot;&gt;finite group&lt;&#x2F;a&gt;) which is very convenient. The curve looks like scattered points with no clear pattern over a finite field:&lt;br &#x2F;&gt;
&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;sQDajke.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Elliptic curves play a role in key exchange when connecting via SSH to a server or to prove ownership in bitcoin. They also appear when performing digital signatures, generating random numbers (though there have been some problems) and they are useful even to factor numbers (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Lenstra_elliptic-curve_factorization&quot;&gt;Lenstra’s algorithm&lt;&#x2F;a&gt;). For example, in the elliptic curve digital signature algorithm (ECDSA) you have these steps (don’t worry if you do not understand all the terms now, we will cover them one by one afterwards):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    1. Calculate E=hash(message), where hash is a secure [hash function](https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Hash_function).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    2. Take Z equal to the $n$ leftmost bits of E, where $n$ is the order of the group (that is, the number of elements making the group).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    3. Select a cryptographically secure random number $k$ (never use the same $k$ twice or you&amp;#39;ll be revealing your key).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    4. Evaluate $(x_1,y_1)=kg$, where $g$ is the generator of the group.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    5. Let $r=x_1$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    6. Evaluate $s=k^{-1}(Z+rs_k) \pmod{n}$, where $s_k$ is the secret key.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    7. The signature is the pair $(r,s)$.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this example, we have to evaluate in step 4 an addition on the curve to arrive at point $(x_1,y_1)$, which gives us $r$. In general, $k$ is a large number (having 256 bits, for example), so that operation can be quite expensive. Besides, if the implementation is not done properly, elliptic curve cryptography could be targeted by side-channel attacks, such as timing and cache attacks. Some elliptic curves have properties that allow for a constant-time implementation, which makes them resistant to these strategies.&lt;&#x2F;p&gt;
&lt;p&gt;Elliptic curves also appear in zk-SNARKs (zero-knowledge succint non-interactive arguments of knowledge; we’ll go hunting for the SNARK on another post) to provide homomorphic hiding. The word sounds important, but the idea behind is simple. Suppose that there are two variables, $x$ and $y$ and you want (or need) to know $x+y$. The problem is, you don’t know them directly, but you have their encrypted form $E(x)$ and $E(y)$. If you have homomorphic hiding, you can compute $E(x+y)=E(x)\times E(y)$, where $\times$ is the operation over the encrypted variables. So, even if you don’t know the variables themselves, you can perform mathematical operations on them (and luckily, that’s just what you need). This is achieved in practice by means of two elliptic curves (known as a pairing; not all elliptic curves are that sociable or get along quite well with others). To be a good match, we need that the operations can be performed as quickly as possible (among other things). A simple example is the exponential function, $f: \mathbb{R} \rightarrow \mathbb{R}^+&#x2F; f(x)=\exp(x)$. If you have $x=2.303$, $\exp(2.303)\approx 10$, $y=3$, $\exp(3)\approx 20.09$, then $\exp(x+y)=\exp(x)\exp(y)=10\times 20.09=200.9$, which is equal to $\exp(5.303)$ and $x+y=5.303$. Of course, in this case it is very easy to go back and know the exact numbers $x$, $y$ and $x+y$; in the case of elliptic curves, this is very hard, owing to the particular group structure.&lt;&#x2F;p&gt;
&lt;p&gt;To be able to work with elliptic curves, we need to define an operation involving the points on the curve. We can do this using the chord-and-tangent construction: given two points on the curve, we can draw a line connecting them; the line intersects the curve at a third point and we reflect it around the $x$-axis to obtain the sum (remember the picture of the curve defined over real numbers). The formulae are&lt;br &#x2F;&gt;
$s=\frac{y_2-y_1}{x_2-x_1}$&lt;br &#x2F;&gt;
$x_3=s^2-x_1-x_2$&lt;br &#x2F;&gt;
$y_3=s(x_1-x_3)-y_1$&lt;&#x2F;p&gt;
&lt;p&gt;There are some special cases, such as when we want to add a point to itself (we call that “doubling”). To make things work, we need to add a special point $\mathcal{O}$, the point at infinity. The curve, together with the operation, form a finite cyclic group. In simple words, every time we add two points we get a third one which belongs to the curve (it is closed under the operation). We also have an identity point (the point at infinity, $P+\mathcal{O}$) and each point $P$ has an inverse $P^\prime$, such that $P+P^\prime=\mathcal{O}$. Moreover, the elements of the group can be generared by repeteadly adding a point $g$ (the generator) to itself. In other words, for $P$ in the group, there is some $k$ such that $kg=P$. If we are given $k$, we can quickly calculate $P$, but doing the operation the other way around (that is, given $P$, find $k$) can be very difficult (this is known as the discrete logarithm problem) and we used this idea in a previous paragraph.&lt;&#x2F;p&gt;
&lt;p&gt;All these calculations are done with the operations of the finite field $\mathcal{F}_p$. We see that, at each addition step, we have to calculate the slope of the line, which involves a division on elements of the finite field. This can be rewritten as $s=(x_2-x_1)^{-1}(y_2-y_1)$, where $(x_2-x_1)^{-1}=b$ is the multiplicative inverse of $x_2-x_1$. In simpler form, $b(x_2-x_1)\equiv 1 \pmod{p}$ (When we write $a \equiv b \pmod{p}$, we say that there is some integer $q$ such that a=pq+b. It is read $a$ is congruent to $b$ modulo $p$). Computing inverses is possible, but quite more expensive than multiplications. There is a result from number theory called &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Fermat%27s_little_theorem&quot;&gt;Fermat’s little theorem&lt;&#x2F;a&gt;, which tells us that $a^{p-1}\equiv 1 \pmod{p}$ if $a$ and $p$ have no common divisors other than 1 (we say $a$ and $p$ are coprime). We can write this in a different fashion,&lt;&#x2F;p&gt;
&lt;p&gt;$a^{p-2}a\equiv 1 \pmod{p}$&lt;&#x2F;p&gt;
&lt;p&gt;and we see that $b=a^{p-2}$ (we can make things simple and then reduce $b$ to $a^{p-2} \pmod{p}$). So, to get the multiplicative inverse, we have to perform many multiplications. (Sometimes it is much easier. Let’s take $p=5$ and we try to find $4^{-1}$. We can see that if we do $4\times 4=16 \equiv 1 \pmod{5}$, so $4^{-1}=4$. This is rather strange, but we have to remember that operations on the finite field have a different behavior). As a matter of fact, $p-1$ gives an upper bound to the power $n$ we have to apply to a field element $a$ to get its inverse, that is $a^n \equiv 1 \pmod{p}$. We call the lowest (positive) exponent $n$ such that $a^n \equiv 1 \pmod{p}$ the order of the element. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Lagrange%27s_theorem_(group_theory)&quot;&gt;Lagrange’s Theorem&lt;&#x2F;a&gt; says that the order $n$ divides $p-1$. For example, take $p=7$, so $p-1=6$. We see that $4^3=64\equiv 1 \pmod{7}$, so $4^2\equiv 2 \pmod{7}$ is the inverse of $4$ ($2\times 4=8 \equiv 1 \pmod{7}$). In the same way, $2^3\equiv 1 \pmod{7}$. In the case of $3$, $3^6 \equiv 1 \pmod{7}$ and $3^5 \equiv 5 \pmod{7}$ and we also have $5^6 \equiv 1 \pmod{7}$. So, we see that the orders $n$ are among the divisors of $p-1=6$.&lt;&#x2F;p&gt;
&lt;p&gt;So, even if the equations for point addition over elliptic curves look really simple, they involve many calculations and these may be expensive. If every time we want to add two points, we have to find the multiplicative inverse modulo a large prime, we see that we are paying a high price. There are a couple of tricks we can perform, such as transforming the curve, to gain a lot of speed or avoid some other issues, such as side-channel attacks.&lt;&#x2F;p&gt;
&lt;p&gt;If you are one of those not willing to pay the cost of finding inverses and saving some time or just love speed for the sake of it, then the next section is for you.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;projective-coordinates&quot;&gt;Projective coordinates&lt;&#x2F;h2&gt;
&lt;p&gt;We can save ourselves from costly inversions if we move from our nice 2 dimensional space to a 3 dimensional space. This was introduced by Moebius and helps us also to represent the point at infinity properly. We can map our points from our elliptic curve $(x,y)$ to points in projective space $(X,Y,Z)$ as $(x,y) \rightarrow (X=x,Y=y,Z=1)$ and $\mathcal{O} \rightarrow (0,1,0)$. We can go back using the transformation $(X,Y,Z) \rightarrow (x=X&#x2F;Z,y=Y&#x2F;Z)$, except for the point at infinity, where it is ill-defined. We can visualize this process with the following picture, where we take three points from an elliptic curve and transform them to 3-d.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;zmlMAg9.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We can think of this as transforming our 2-d points to lines passing through the origin in 3-d space. For example, the point $(x_1,y_1)$ in 2-d transforms to the line $(\mu x_1,\mu y_1, \mu)$ with $\mu$ an element in the field. Thus, two points $P_1=(X_1,Y_1,Z_1)$ and $P_2=(X_2,Y_2,Z_2)$ are the same in 2-d (more precisely, are congruent) if we can find $\eta$ such that $(\eta X_1,\eta Y_1,\eta Z_1)=(X_2,Y_2,Z_2)$. These lines do not contain the origin $(0,0,0)$. It is usual to write points is projective space as $(X:Y:Z)$, instead of $(X,Y,Z)$. In our picture, the point A (yellow) gets mapped to the point D (red above it). All the points that lie on the same straight line passing through the origin and D (pink dashed) are considered equivalent to D. Similarly, point B (blue) is mapped to point F (light blue) and all the ponts over the light green dotted line (except the origin) are equivalent to F. When we add points in this space, the components $(X,Y,Z)$ will change, but we can go back to the point belonging to the curve by just retracing our steps to $Z=1$ along the line that passes through the origin. Why go all this length? We will shortly see that we avoid inversions at each addition step and do just one at the time of finding the point in 2-d (for example, when we need to find $r=x_1$ in ECDSA). Of course, if we have to do $P=2g$ we didn’t gain anything, but if we have to perform $P=kg$ with $k$ in the order of 256 bits, we saved many costly inversions.&lt;&#x2F;p&gt;
&lt;p&gt;Making the substitutions into the elliptic curve equation&lt;br &#x2F;&gt;
$$\left(\frac{Y}{Z}\right)^2 = \left(\frac{X}{Z}\right)^3 + a\left(\frac{X}{Z}\right) + b$$&lt;br &#x2F;&gt;
We can multiply by $Z^3$ and get the equation&lt;br &#x2F;&gt;
$$ZY^2 = X^3 + aZ^2 + bZ^3$$&lt;br &#x2F;&gt;
If we want to sum $P$ and $Q$ to yield $R = P + Q$ in projective space, we can use the formulae:&lt;&#x2F;p&gt;
&lt;p&gt;$Z_R = Z_PZ_Q(X_PZ_Q-X_QZ_P)^3$&lt;br &#x2F;&gt;
$X_R = (X_PZ_Q-X_QZ_P)(Z_QZ_P(Y_PZ_Q-Y_QZ_P)^2 - (X_PZ_Q-X_QZ_P)^2(X_PZ_Q+X_QZP))$&lt;br &#x2F;&gt;
$Y_R = Z_PZ_Q(X_QY_P-X_PY_Q)(X_PZ_Q-X_QZ_P)^2 - (Y_PZ_Q-Y_QZ_P)A$&lt;br &#x2F;&gt;
$A = Z_PZ_Q(Y_PZ_Q-Y_QZ_P)^2 - (X_PZ_Q+X_QZ_P)(X_PZ_Q-X_QZ_P)^2$.&lt;&#x2F;p&gt;
&lt;p&gt;This looks more complicated and difficult than the simple formulae for 2 dimensional (2-d) space. However, we do not have to calculate any inverses! To get the sum, we have to perform 12 multiplications and 2 squarings. In 2-d, we have 2 multiplications, one squaring and one inversion. Inversions can be 20 times or more expensive than multiplications, so we’ve saved at least 10 multiplications (some authors say inversions are about 80 times more expensive than multiplications).&lt;&#x2F;p&gt;
&lt;p&gt;Some curves can go even faster. If $x^3 + ax + b$ has a solution in $\mathcal{F_p}$, we can work with an equivalent Jacobi quartic $v^2 = a^\prime u^4 + du^2 + 1$, where $a^\prime$ and $d$ depend on the root. We can transform the curve $(u,v)$ to 3-d space $(U,V,W)$ using $u = U&#x2F;W$ and $v = V &#x2F; W^2$ and get the equation&lt;&#x2F;p&gt;
&lt;p&gt;$$V^2 = a^\prime U^4 + dU^2 W^2 + W^4$$&lt;&#x2F;p&gt;
&lt;p&gt;If we want to sum $P_3 = P_1+P_2$, in these coordinates we have:&lt;&#x2F;p&gt;
&lt;p&gt;$U_3 = U_1W_1V_2 + U_2W_2V_1$&lt;br &#x2F;&gt;
$V_3 = ((W_1 W_2)^2 + a^\prime (U_1 U_2)^2)(V_1 V_2 + dU_1 U_2 W_1 W_2) + 2a^\prime U_1 U_2 W_1 W_2 ({U_1}^2 {W_2}^2 + {U_2}^2 {W_1}^2)$&lt;br &#x2F;&gt;
$W_3 = (W_1 W_2)^2 - a^\prime (U_1 U_2)^2$&lt;&#x2F;p&gt;
&lt;p&gt;These allow us to further reduce the costs for adding to 6 multiplications and 4 squarings. Other models with fast implementations are Edwards curves and Montgomery curves, which have some of the fastest implementations.&lt;&#x2F;p&gt;
&lt;p&gt;Montgomery curves satisfy the following equation&lt;br &#x2F;&gt;
$$By^2 = x^3 + Ax^2 + x$$&lt;br &#x2F;&gt;
where $B(A^2-4)\neq 0$. This expression can be cast in the Weierstrass form by making some transformation. If we take $(x,y)$ and map it to $(x^\prime , y^\prime)$ given by $(x,y) \rightarrow (x&#x2F;B+A&#x2F;3B,y&#x2F;B)$, we get&lt;br &#x2F;&gt;
$$y^2 = x^3 + \left(\frac{3 - A^2}{ 3B^2 }\right)x + \frac{2A^3 - 9A}{27B^3}$$&lt;br &#x2F;&gt;
Transforming a Weierstrass curve into a Montgomery curve is not always possible, though. The order of the group must be divisible by $4$ and $x^3 + ax + b = 0$ must have a solution.&lt;&#x2F;p&gt;
&lt;p&gt;Montgomery curves can also be related to twisted Edwards curves, which obey the following equation&lt;br &#x2F;&gt;
$$ax^2 + y^2 = 1+dx^2 y^2$$&lt;br &#x2F;&gt;
The parameters are related via $A=2(a+d)&#x2F;(a-d)$ and $B=4&#x2F;(a-d)$. We say these two curves are birrationally equivalent. For example, the well-known Edwards curve 25519, with $p = 2^{255}-19$ is (birrationally) equivalent to the Montgomery curve $t^2 = u^3 + 486662u^2 + u$. The mappings are&lt;br &#x2F;&gt;
$(x,y) = (\sqrt{-486664}u&#x2F;t,(u-1)&#x2F;(u+1))$&lt;br &#x2F;&gt;
$(u,t) = ((1+y)&#x2F;(1-y),\sqrt{-486664}(1+y)&#x2F;(x(1-y)))$&lt;&#x2F;p&gt;
&lt;p&gt;Montgomery curves have some interesting properties that lend themselves to constant time implementation. We can work in projective coordinates just using the $x$ component, with the transformation $x=X&#x2F;Z$. Doubling a point takes the simple form:&lt;br &#x2F;&gt;
$4R = (X_1+Z_1)^2 - (X_1-Z_1)^2$&lt;br &#x2F;&gt;
$X_2 = (X_1+Z_1)^2 (X_1-Z_1)^2$&lt;br &#x2F;&gt;
$Z_2 = R((X_1-Z_1)^2 + ((A+2)&#x2F;4)R)$&lt;&#x2F;p&gt;
&lt;p&gt;Twisted Edwards curves have there advantages, too. The expressions for point addition and doubling are the same. Given $P_1 = (x_1 , y_1)$, $P_2 = (x_2,y_2)$ we get&lt;br &#x2F;&gt;
$x_3 = \frac{x_1y_2 + x_2y_1}{1 + dx_1x_2y_1y_2}$&lt;br &#x2F;&gt;
$y_3 = \frac{y_1y_2 - ax_1x_2}{1 - dx_1x_2y_1y_2}$&lt;br &#x2F;&gt;
If we let $x_1 = x_2$ and $y_1 = y_2$ we get the expressions for point doubling. There are several alternatives to speeding up the calculations, such as projective, inverted or extended coordinates.&lt;&#x2F;p&gt;
&lt;p&gt;There are some other tricks to add and multiply points over elliptic curves, such as the technique by Gallant, Lambert and Vanstone (GLV) and generalized by Galbraith, Lin and Scott (GLS).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;&#x2F;h2&gt;
&lt;p&gt;Elliptic curves have gained acceptance in cryptography because they offer good levels of security with short key lengths and allow for faster implementations than other methods such as RSA. This allows smartphones and other less powerful devices to perform cryptographic operations in a fast and reliable way.&lt;&#x2F;p&gt;
&lt;p&gt;Using the chord-and-tangent method, we can generate finite cyclic groups; in applications, we are generally interested in calculating $kg$, where $k$ is an integer and $g$ is a point in the elliptic curve. The main drawback is that we need to find multiplicative inverses of field elements, which involve many multiplications.&lt;&#x2F;p&gt;
&lt;p&gt;We can improve the speed of these computations by performing transformations between curves (for example, taking a Weierstrass curve to Montgomery form) and using projective coordinates. This way, we avoid calculating multiplicative inverses at each step, at the expense of a few extra multiplications (this extra cost is usually negligible to the overall cost of the inversion). There are also more advanced techniques allowing us to jump from one point to a very distant one, such as with GLS.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>What every developer needs to know about elliptic curves</title>
          <pubDate>Sat, 06 Aug 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/what-every-developer-needs-to-know-about-elliptic-curves/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/what-every-developer-needs-to-know-about-elliptic-curves/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/what-every-developer-needs-to-know-about-elliptic-curves/">&lt;p&gt;Elliptic curves (EC) have become one of the most useful tools for modern cryptography. They were proposed in the 1980s and became widespread used after 2004. Its main advantage is that it offers smaller key sizes to attain the same level of security of other methods, resulting in smaller storage and transmission requirements. For example, EC cryptography (ECC) needs 256-bit keys to attain the same level of security as a 3000-bit key using RSA (another public-key cryptographic system, born in the late 70s). ECC and RSA work by hiding things inside a certain mathematical structure known as a finite cyclic group (we will explain this soon). The hiding is done rather in plain sight: you could break the system if you could reverse the math trick (spoiler alert: if done properly, it would take you several lifetimes). It is as if you put $1.000.000 inside an unbreakable glass box and anyone could take it if they could break it.&lt;&#x2F;p&gt;
&lt;p&gt;In order to understand these objects and why they work, we need to go backstage and look at the math principles (we won’t enter into the hard details or proofs, but rather focus on the concepts or ideas). We will start by explaining finite fields and groups and then jump onto the elliptic curves (over finite fields) and see whether all curves were created equal for crypto purposes.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;finite-fields&quot;&gt;Finite fields&lt;&#x2F;h2&gt;
&lt;p&gt;We know examples of fields from elementary math. The rational, real and complex numbers with the usual notions of sum and multiplication are examples of fields (these are not finite though).&lt;&#x2F;p&gt;
&lt;p&gt;A finite field is a set equipped with two operations, which we will call + and ×. These operations need to have certain properties in order for this to be a field:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;If &lt;em&gt;a&lt;&#x2F;em&gt; and &lt;em&gt;b&lt;&#x2F;em&gt; are in the set, then &lt;em&gt;c=a+b&lt;&#x2F;em&gt; and &lt;em&gt;d=a×b&lt;&#x2F;em&gt; should also be in the set. This is what is mathematically called a closed set under the operations +, ×.&lt;&#x2F;li&gt;
&lt;li&gt;There is a zero element, 0, such that &lt;em&gt;a&lt;&#x2F;em&gt; +0=&lt;em&gt;a&lt;&#x2F;em&gt; for any a in the set. This element is called the additive identity.&lt;&#x2F;li&gt;
&lt;li&gt;There is an element, 1, such that 1× &lt;em&gt;a&lt;&#x2F;em&gt; =&lt;em&gt;a&lt;&#x2F;em&gt; for any a in the set. This element is the multiplicative identity.&lt;&#x2F;li&gt;
&lt;li&gt;If a is in the set, there is an element &lt;em&gt;b&lt;&#x2F;em&gt; , such that &lt;em&gt;a+b&lt;&#x2F;em&gt; =0. We call this element the additive inverse and we usually write it as &lt;em&gt;−a&lt;&#x2F;em&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;If &lt;em&gt;a&lt;&#x2F;em&gt; is in the set, there is an element &lt;em&gt;c&lt;&#x2F;em&gt; such that &lt;em&gt;a×c=1&lt;&#x2F;em&gt;. This element is called the multiplicative inverse and we write is as &lt;em&gt;a&lt;&#x2F;em&gt; −1.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Before we can talk about examples of finite fields, we need to introduce the modulo arithmetic.&lt;&#x2F;p&gt;
&lt;p&gt;We learned that given a natural number or zero, &lt;em&gt;a&lt;&#x2F;em&gt; and a non-zero number &lt;em&gt;b&lt;&#x2F;em&gt; , we could write out a in the following way &lt;em&gt;a=q×b+r&lt;&#x2F;em&gt; where &lt;em&gt;q&lt;&#x2F;em&gt; is the quotient and &lt;em&gt;r&lt;&#x2F;em&gt; is the remainder of the division of &lt;em&gt;a&#x2F;b&lt;&#x2F;em&gt;. This &lt;em&gt;r&lt;&#x2F;em&gt; can take values 0,1,2,…,b−1 We know that if &lt;em&gt;r&lt;&#x2F;em&gt; is zero, then a is a multiple of &lt;em&gt;b&lt;&#x2F;em&gt;. It may not seem new, but this gives us a very useful tool to work with numbers. For example, if &lt;em&gt;b&lt;&#x2F;em&gt; =2 then &lt;em&gt;r&lt;&#x2F;em&gt; =0,1. When it is 0, &lt;em&gt;a&lt;&#x2F;em&gt; is even (it is divisible by 2) and when it is 1, &lt;em&gt;a&lt;&#x2F;em&gt; is odd. A simple way to rephrase this (due to Gauss):&lt;&#x2F;p&gt;
&lt;p&gt;a≡1(mod2)&lt;&#x2F;p&gt;
&lt;p&gt;if &lt;em&gt;a&lt;&#x2F;em&gt; is odd and&lt;&#x2F;p&gt;
&lt;p&gt;a≡0(mod2)&lt;&#x2F;p&gt;
&lt;p&gt;if &lt;em&gt;a&lt;&#x2F;em&gt; is even. We can see that if we sum two odd numbers &lt;em&gt;a1&lt;&#x2F;em&gt; and &lt;em&gt;a2&lt;&#x2F;em&gt; ,&lt;&#x2F;p&gt;
&lt;p&gt;a1+a2≡1+1≡0(mod2)&lt;&#x2F;p&gt;
&lt;p&gt;This shows us that, if we want to know whether a sum is even or not, we can simply sum the remainders of their division by 2 (an application of this is that in order to check divisibility by two, we should only look at the last bit of the binary representation).&lt;&#x2F;p&gt;
&lt;p&gt;Another situation where this arises every day is with time. If we are on Monday at 10 am and we have 36 hours till the deadline of a project, we have to submit everything by Tuesday 10 pm. That is because 12 fits exactly 3 times in 36, leading to Mon-10 pm, Tue-10 am, Tue-10 pm. If we had 39 hours, we jump to Wed-1 am.&lt;&#x2F;p&gt;
&lt;p&gt;An easy way to look at this relation (formally known as congruence modulo p) is that if &lt;em&gt;a≡b&lt;&#x2F;em&gt;(mod &lt;em&gt;p&lt;&#x2F;em&gt;), then &lt;em&gt;p&lt;&#x2F;em&gt; divides &lt;em&gt;a−b&lt;&#x2F;em&gt; , or &lt;em&gt;a=k×p+b&lt;&#x2F;em&gt; for an integer &lt;em&gt;k&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;More informally, we see that operating (mod &lt;em&gt;p&lt;&#x2F;em&gt;) wraps around the results of certain calculations, giving always numbers in a bounded range by &lt;em&gt;p&lt;&#x2F;em&gt; −1.&lt;&#x2F;p&gt;
&lt;p&gt;We can see that if a1≡b1(modp) and a2≡b2(modp), then a1+a2≡b1+b2(mod &lt;em&gt;p&lt;&#x2F;em&gt;) (if b1+b2&amp;gt;p we can wrap around the result). Similar results apply when using subtraction and multiplication. Division presents some difficulties, but we can change things a little bit and make it work this way: instead of thinking of dividing &lt;em&gt;a÷b&lt;&#x2F;em&gt; we can calculate &lt;em&gt;a×b−1&lt;&#x2F;em&gt; , where &lt;em&gt;b&lt;&#x2F;em&gt; −1 is the multiplicative inverse of &lt;em&gt;b&lt;&#x2F;em&gt; (remember &lt;em&gt;b×b −1&lt;&#x2F;em&gt;=1). Consider &lt;em&gt;p&lt;&#x2F;em&gt; =5, so the elements of the group are 0,1,2,3,4.&lt;&#x2F;p&gt;
&lt;p&gt;We can see that 1 is its own multiplicative inverse, since 1×1=1≡1  (mod5). If we take 2 and 3, then 2×3=6≡1  (mod5) (so 3 is the multiplicative inverse of 2) and 4×4=16≡1 (mod5). The set and the operations defined satisfy the conditions for a field.&lt;&#x2F;p&gt;
&lt;p&gt;We can also define integer powers of field elements in a simple way. If we want to square a number &lt;em&gt;a&lt;&#x2F;em&gt; , it is just doing &lt;em&gt;a×a&lt;&#x2F;em&gt; and take mod &lt;em&gt;p&lt;&#x2F;em&gt;. If we want a cube, we do &lt;em&gt;a×a×a&lt;&#x2F;em&gt; and take mod &lt;em&gt;p&lt;&#x2F;em&gt;. RSA uses exponentiation to perform encryption. It is easy to see that if the exponent is rather large (or the base is very large, or both), numbers get really big. For example, we want to evalute 265536(mod &lt;em&gt;p&lt;&#x2F;em&gt;). When we reach a 1000, we get numbers with over 300 digits and we are still a long way to go. We can do this calculation much simpler realizing that 65536=216 and squaring the number and taking the remainder every time. We end up doing only 16 operations like this, instead of the original 65536! thus avoiding huge numbers. A similar strategy will be used when we work with ECs!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;groups&quot;&gt;Groups&lt;&#x2F;h2&gt;
&lt;p&gt;We saw that whenever we add two even integers, we get another one. Besides, as 0 is even and if we sum &lt;em&gt;a&lt;&#x2F;em&gt; and &lt;em&gt;−a&lt;&#x2F;em&gt; we get 0, which is the identity element for the sum. Many different objects have a similar behavior when equipped with a certain operation. For example, the multiplication of two invertible matrices results in an invertible matrix. If we consider the set of invertible matrices of &lt;em&gt;N&lt;&#x2F;em&gt; × &lt;em&gt;N&lt;&#x2F;em&gt; equipped with the multiplication, we can see that if &lt;em&gt;A&lt;&#x2F;em&gt; is in the set, &lt;em&gt;A −1&lt;&#x2F;em&gt; is in the set; the identity matrix is in the set (and it plays the role of identity element with respect to multiplication). In other words, some sets equipped with a certain operation share some properties and we can take advantage of the knowledge of this structure. The set, together with the operation, forms a group. Formally, a group is a set &lt;em&gt;G&lt;&#x2F;em&gt; equipped with a binary operation × such that:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 1. The operation is associative, that is, _(a×b)×c=a×(b×c)_.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 2. There is an identity element, _e: e×a=a_ and _a×e=a_. &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 3. For every element _a_ in the set, there is an element _b_ in the set such that _a×b=e_ and _b×a=e_. We denote _b=a−1_ for simplicity.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can easily see that any field is, in particular, a group with respect to each one of its two operations (conditions 1, 2 and 4 for the field indicate it is also a group with respect to the sum and 1, 3 and 5 for multiplication). If the operation is commutative (that is, &lt;em&gt;a×b=b×a&lt;&#x2F;em&gt;) the group is known as an abelian (or commutative) group. For example, the invertible matrices of &lt;em&gt;N×N&lt;&#x2F;em&gt; form a group, but it is not abelian, since &lt;em&gt;A×B≠B×A&lt;&#x2F;em&gt; for some matrices &lt;em&gt;A&lt;&#x2F;em&gt; and &lt;em&gt;B&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;We will be interested in finite groups (those where the set contains a finite number of elements) and, in particular, cyclic groups. These are groups which can be generated by repeatedly applying the operation over an element &lt;em&gt;g&lt;&#x2F;em&gt; , the generator of the group. The &lt;em&gt;n&lt;&#x2F;em&gt; -th roots of unity in the complex numbers form an example of a cyclic group under multiplication; this is the set of solutions of &lt;em&gt;x n&lt;&#x2F;em&gt;=1, which are of the form exp(2 &lt;em&gt;πik&#x2F;n&lt;&#x2F;em&gt;), with &lt;em&gt;k&lt;&#x2F;em&gt; =0,1,2…,&lt;em&gt;n&lt;&#x2F;em&gt; −1. This group can be generated by taking integer powers of exp(2 &lt;em&gt;πi&#x2F;n&lt;&#x2F;em&gt;). The roots of unity play an important role in the calculation of the fast Fourier transform (FFT), which has many applications.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;elliptic-curves-in-a-nutshell&quot;&gt;Elliptic curves in a nutshell&lt;&#x2F;h2&gt;
&lt;p&gt;Elliptic curves are very useful objects because they allow us to obtain a group structure with interesting properties. Given a field &lt;em&gt;F&lt;&#x2F;em&gt; , an elliptic curve is the set of points &lt;em&gt;(x,y)&lt;&#x2F;em&gt; which satisfy the following equation:&lt;&#x2F;p&gt;
&lt;p&gt;_y 2+a1xy+a3y=x3+a2x2+a4x+a6 _&lt;&#x2F;p&gt;
&lt;p&gt;This is known as the general Weierstrass equation. In many cases, this can be written in the simpler form&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;y 2=x3+ax+b&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;which is the (Weierstrass) short-form. Depending on the choice of the parameters a and b and the field, the curve can have some desired properties or not. If _4a 3+27b2≠0 _, the curve is non-singular.&lt;&#x2F;p&gt;
&lt;p&gt;We can define an operation which allows us to sum elements belonging to the elliptic curve and obtain a group. This is done using a geometric construction, the chord-and-tangent rule. Given two points on the curve &lt;em&gt;P1=(x 1,y1)&lt;&#x2F;em&gt; and &lt;em&gt;P 2=(x2,y2)&lt;&#x2F;em&gt;, we can draw a line connecting them. That line intersects the curve on a third point &lt;em&gt;P 3=(x3,y3)&lt;&#x2F;em&gt;. We set the sum of &lt;em&gt;P 1&lt;&#x2F;em&gt; and &lt;em&gt;P 2&lt;&#x2F;em&gt; as &lt;em&gt;(x 3,−y3)&lt;&#x2F;em&gt;, that is, point &lt;em&gt;P 3&lt;&#x2F;em&gt; flipped around the &lt;em&gt;x&lt;&#x2F;em&gt; -axis. The formulae are:  &lt;img src=&quot;&#x2F;images&#x2F;2022&#x2F;12&#x2F;imagen-1.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We can easily see that we have a problem if we try to sum &lt;em&gt;P 1=(x1,y1)&lt;&#x2F;em&gt; and &lt;em&gt;P 2=(x1,−y1)&lt;&#x2F;em&gt;. We need to add an additional point to the system, which we call the point at infinity &lt;em&gt;O&lt;&#x2F;em&gt;. This inclusion is necessary to be able to define the group structure and works as the identity element for the group operation.&lt;&#x2F;p&gt;
&lt;p&gt;Another problem appears when we want to sum &lt;em&gt;P 1&lt;&#x2F;em&gt; and &lt;em&gt;P 1&lt;&#x2F;em&gt; to get to &lt;em&gt;P 3=2P1&lt;&#x2F;em&gt;. But, if we draw the tangent line to the curve on P1, we see that it intersects the curve at another point. If we want to perform this operation, we need to find the slope of the tangent line and find the intersection:&lt;&#x2F;p&gt;
&lt;p&gt;$$s=\frac{3x21+a}{2y1}$$&lt;br &#x2F;&gt;
$$x3=s2−2x1$$&lt;br &#x2F;&gt;
$$y3=s(x1−x3)−y1$$&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2022&#x2F;12&#x2F;imagen-5.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It takes a little bit of work, but we can prove that the elliptic curve with this operation has the properties of a group. We will use finite fields to work with these curves and the groups that we will obtain are finite cyclic groups, that is, groups which can be generated by repeteadly using the operation on a generator, &lt;em&gt;g: g,2g,3g,4g,5g,….&lt;&#x2F;em&gt; &lt;img src=&quot;&#x2F;images&#x2F;2022&#x2F;12&#x2F;imagen-3.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If we plot the collection of points onto a graph, we see that the points are distributed in a rather “random” fashion. For example, &lt;em&gt;2 g&lt;&#x2F;em&gt; could be very far from &lt;em&gt;3 g&lt;&#x2F;em&gt; which in turn are very far from &lt;em&gt;4 g&lt;&#x2F;em&gt;. If we wanted to know how many times &lt;em&gt;k&lt;&#x2F;em&gt; we have to add the generator to arrive at a certain point &lt;em&gt;P&lt;&#x2F;em&gt; (that is solving the equation &lt;em&gt;kg=P&lt;&#x2F;em&gt;) we see that we don’t have an easy strategy and we are forced to perform a brute search over all possible &lt;em&gt;k&lt;&#x2F;em&gt;. This problem is known as the (elliptic curve) discrete logarithm (log for friends) problem (other friends prefer ECDLP).&lt;&#x2F;p&gt;
&lt;p&gt;On the other hand, if we know &lt;em&gt;k&lt;&#x2F;em&gt; , we can compute in a very fast way &lt;em&gt;P=kg&lt;&#x2F;em&gt;. This offers us a way to hide (in plain sight) things inside the group. Of course, if you could break the DLP, you could get k, but it is rather infeasible. If we want to calculate 65536 &lt;em&gt;g&lt;&#x2F;em&gt; , we can do it by realizing that &lt;em&gt;g+g=2 g, 2g+2g=4g, 4g+4g=8&lt;&#x2F;em&gt;…until &lt;em&gt;32768 g+32768g=65535g&lt;&#x2F;em&gt;, so we narrowed the operations 65536 to 16. There are many useful algorithms that allow us to speed up the operations over elliptic curves, allowing us to avoid expensive calculations such as inversions, which appear when we want to calculate the slope.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;are-all-elliptic-curves-useful-for-crypto&quot;&gt;Are all elliptic curves useful for crypto?&lt;&#x2F;h2&gt;
&lt;p&gt;The strength of elliptic curve cryptography lies on the hardness to solve the discrete logarithm problem. This is related to the number of elements (the order of the set) making the cyclic group. If the number is a very large prime, or it contains a very large prime in its factorization (that is, the number is a multiple of a large prime), then the problem becomes infeasible. However, if the order is made up of small primes, it is possible to search over the subgroups and reconstruct the answer with help from the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Chinese_remainder_theorem&quot;&gt;Chinese Remainder Theorem&lt;&#x2F;a&gt;. This is because the difficulty depends on the size of the largest prime involved.&lt;&#x2F;p&gt;
&lt;p&gt;Some curves have desired properties and have been given names. For example, Bitcoin uses secp256k1, which has the following parameters:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;a=0&lt;&#x2F;em&gt;&lt;br &#x2F;&gt;
&lt;em&gt;b&lt;&#x2F;em&gt; =7 &lt;em&gt;p&lt;&#x2F;em&gt; =2256−232−977 &lt;em&gt;g x&lt;&#x2F;em&gt;=&lt;em&gt;0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798&lt;&#x2F;em&gt; &lt;em&gt;g y=0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8&lt;&#x2F;em&gt; &lt;em&gt;r=0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;To get an idea on the number of elements of the group, they’re about &lt;em&gt;r&lt;&#x2F;em&gt; ≈1077. Even if we had 1012 supercomputers performing over 1017 search points per second for a hundred million years we wouldn’t even get close to inspecting all the possibilities.&lt;&#x2F;p&gt;
&lt;p&gt;To be able to guarantee 128-bits of security, ECs need group orders near 256-bits (that is, orders with prime factors around 1077). This is because there are algorithms which can solve the problem doing operations around √r. If the largest prime is less than 94-bits long, it can be broken with help from a desktop computer. Of course, even if your group is large enough, nothing can save you from a poor implementation.&lt;&#x2F;p&gt;
&lt;p&gt;The question arises: how can we know the number of elements of our EC? Luckily, math comes once again to our aid like the Hasse bound, Schoof’s algorithm and how to test whether a number is prime or not. Next time we will continue revealing the math principles behind useful tools in cryptography.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Ethereum development made easy with Foundry</title>
          <pubDate>Mon, 01 Aug 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/ethereum-development-made-easy-with-foundry/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/ethereum-development-made-easy-with-foundry/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/ethereum-development-made-easy-with-foundry/">&lt;p&gt;As part of our trip to Devcon Amsterdam back in April, we attended the War Room Games Amsterdam competition, an Ethereum CTF where you “hacked” smart contracts to win points. The event was loads of fun, but we realized while playing that our main obstacle was not Ethereum&#x2F;Solidity knowledge, but rather tooling. We knew how to hack most contracts, but struggled to do so because we lacked the right tools, relying a lot on manual Metamask or Remix interaction.&lt;&#x2F;p&gt;
&lt;p&gt;This prompted us to write some &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;ethereum_war_game_tooling&quot;&gt;basic REPL-style tool to develop, deploy and interact with smart contracts on chain&lt;&#x2F;a&gt; written in Elixir, a language we are very comfortable with. After writing its basic functionality in a weekend, we started looking for other existing tools not written in Javascript (the most well-known ones, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;trufflesuite.com&#x2F;&quot;&gt;Truffle&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;hardhat.org&#x2F;&quot;&gt;Hardhat&lt;&#x2F;a&gt;, expect you to do everything in JS).&lt;&#x2F;p&gt;
&lt;p&gt;Enter &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;foundry-rs&#x2F;foundry&quot;&gt;Foundry&lt;&#x2F;a&gt;, an Ethereum toolkit written in Rust. Inspired by &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dapphub&#x2F;dapptools&quot;&gt;Dapp Tools&lt;&#x2F;a&gt;, it lets you write, run, test and deploy smart contracts, all in Solidity.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;ethereum&quot;&gt;Ethereum&lt;&#x2F;h1&gt;
&lt;p&gt;Before diving into Foundry, a quick recap on Ethereum. As the leading example of blockchain’s second generation, Ethereum distinguishes itself most prominently from Bitcoin by running a full &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Virtual_machine&quot;&gt;Virtual Machine&lt;&#x2F;a&gt; capable of (at least in theory) running any computation. This means that it is not just a public ledger for a virtual currency where users can pay each other, but also a global public computer, capable of trustlessly executing any code.&lt;&#x2F;p&gt;
&lt;p&gt;Thus Ethereum transactions are not limited to &lt;code&gt;eth&lt;&#x2F;code&gt; exchanges, but can be any arbitrary logic, which allowed the creation of stablecoins, NFTs, DeFi or even &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;zkga.me&#x2F;&quot;&gt;actual games&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;For our purposes, you will need to setup an ethereum account, which you can do by downloading an Ethereum wallet like Metamask (the word “wallet” here is a bit of a misnomer, as it allows you to do more than just manage your money). Take note of your account’s private key (in Metamask, “Account details” -&amp;gt; “Export Private Key”), as it is will be needed to send transactions to the network.&lt;&#x2F;p&gt;
&lt;p&gt;NOTE: Treat this account you just created as a throwaway to play around. In a real scenario, you should never be copy pasting your private key around, as it is what makes your wallet yours.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;foundry&quot;&gt;Foundry&lt;&#x2F;h1&gt;
&lt;p&gt;Let’s now dive into Foundry by going through an example. First, install it with&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;curl -L https:&#x2F;&#x2F;foundry.paradigm.xyz | bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;foundryup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;forge-and-cast&quot;&gt;Forge and Cast&lt;&#x2F;h2&gt;
&lt;p&gt;Foundry’s first and most important tool is &lt;code&gt;Forge&lt;&#x2F;code&gt;, a complete testing framework. Let’s write a very simple smart contract (taken from &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.soliditylang.org&#x2F;en&#x2F;v0.8.13&#x2F;introduction-to-smart-contracts.html&quot;&gt;here&lt;&#x2F;a&gt;) to see it in action.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;creating-a-project&quot;&gt;Creating a project&lt;&#x2F;h2&gt;
&lt;p&gt;Create a new project with&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;forge init storage&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This will create a &lt;code&gt;storage&lt;&#x2F;code&gt; directory with a bunch of files, the only one we care about for now is in &lt;code&gt;src&#x2F;Contract.sol&lt;&#x2F;code&gt;. Rename that file &lt;code&gt;Storage.sol&lt;&#x2F;code&gt; and add the following code to it&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; SPDX-License-Identifier: UNLICENSED&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pragma solidity ^0.8.13;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;contract Storage {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    uint256 number;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    function store(uint256 num) public {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        number = num;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    function retrieve() public view returns (uint256){&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return number;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The contract is self-explanatory: it stores a certain number with the &lt;code&gt;store(num)&lt;&#x2F;code&gt; method and returns it with &lt;code&gt;retrieve()&lt;&#x2F;code&gt;. Running&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;forge build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;should tell you compilation was successful. We now have our contract compiled, but how do we run it? This is code that’s meant to be deployed on the ethereum blockchain, to be interacted with by users who send transactions. Ideally, the tests we perform should be as close as possible to this environment. One thing we can do is deploy it to a Testnet and call it from there.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;deploying&quot;&gt;Deploying&lt;&#x2F;h2&gt;
&lt;p&gt;To deploy a contract to an ethereum network, we can use the &lt;code&gt;forge create&lt;&#x2F;code&gt; command. In our case, the easiest way to to interact with a testnet is (unfortunately) to use a provider like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;infura.io&#x2F;&quot;&gt;Infura&lt;&#x2F;a&gt; or &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.alchemy.com&#x2F;&quot;&gt;Alchemy&lt;&#x2F;a&gt;. Just register with a free account and create a &lt;code&gt;Goerli&lt;&#x2F;code&gt; testnet application, which should give you an RPC URL to interact with said testnet that looks something like this&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;https:&#x2F;&#x2F;eth-goerli.g.alchemy.com&#x2F;v2&#x2F;&amp;lt;API_KEY&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Set the &lt;code&gt;ETH_RPC_URL&lt;&#x2F;code&gt; environment variable to this value to use it for all our interactions.&lt;&#x2F;p&gt;
&lt;p&gt;The last thing we need is to fund our account to pay for the transactions we send. For this, look for a faucet like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;goerlifaucet.com&#x2F;&quot;&gt;this one&lt;&#x2F;a&gt; and request funds by pasting your address (faucets are a bit annoying in that they’re usually either very sketchy or require authentication). Having done all that, let’s deploy our &lt;code&gt;Storage&lt;&#x2F;code&gt; contract:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;forge create Storage --private-key &amp;lt;your_private_key&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If everything goes well, you should see something like&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Deployer: &amp;lt;your_address&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Deployed to: &amp;lt;contract_address&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Transaction hash: &amp;lt;transaction_hash&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;calling-our-contract&quot;&gt;Calling our contract&lt;&#x2F;h2&gt;
&lt;p&gt;To interact with our deployed contract, Foundry has a tool called &lt;code&gt;Cast&lt;&#x2F;code&gt;; it is a more mature CLI version of the elixir code we wrote mentioned at the beginning.&lt;&#x2F;p&gt;
&lt;p&gt;We can call the &lt;code&gt;retrieve()&lt;&#x2F;code&gt; method by doing&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cast call &amp;lt;contract_address&amp;gt; &amp;quot;retrieve()&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;which should return&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x0000000000000000000000000000000000000000000000000000000000000000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Notice the result is in an awkward binary format; that’s because it’s &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.soliditylang.org&#x2F;en&#x2F;v0.8.13&#x2F;abi-spec.html&quot;&gt;ABI&lt;&#x2F;a&gt; encoded. If we also provide the return type of the method, &lt;code&gt;cast&lt;&#x2F;code&gt; will decode it for us:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cast call &amp;lt;contract_address&amp;gt; &amp;quot;retrieve()(uint256)&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To call the &lt;code&gt;store&lt;&#x2F;code&gt; method, we need to use &lt;code&gt;cast send&lt;&#x2F;code&gt; instead of &lt;code&gt;call&lt;&#x2F;code&gt;. This is because &lt;code&gt;retrieve&lt;&#x2F;code&gt; is a method that does not modify any blockchain state, it just reads it. On the other hand, &lt;code&gt;store&lt;&#x2F;code&gt; does modify state, which requires sending an actual &lt;code&gt;transaction&lt;&#x2F;code&gt; to our contract so that, when it gets included in a block, the &lt;code&gt;store&lt;&#x2F;code&gt; method is run and the state of our variable is updated and stored in the network.&lt;&#x2F;p&gt;
&lt;p&gt;All that said, to run &lt;code&gt;store&lt;&#x2F;code&gt; we do&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cast send &amp;lt;contract-address&amp;gt; --private-key &amp;lt;your_private_key&amp;gt; &amp;quot;store(uint256)&amp;quot; 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;which, after a while, should return a transacion receipt with all the info about the transaction, and the &lt;code&gt;number&lt;&#x2F;code&gt; variable should now be updated to be &lt;code&gt;5&lt;&#x2F;code&gt;. We can verify that by running again&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cast call &amp;lt;contract_address&amp;gt; &amp;quot;retrieve()(uint256)&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;writing-tests&quot;&gt;Writing tests&lt;&#x2F;h2&gt;
&lt;p&gt;We just verified that our contract worked as expected, though it was a bit cumbersome; the problem with trying out smart contracts, as opposed to more traditional development environments, is that most of the code that matters has to go through a transaction on the blockchain. This is a very slow process, so while the above works, it quickly becomes annoying as the code becomes more complex code and starts interacting with other contracts.&lt;&#x2F;p&gt;
&lt;p&gt;Forge allow us to write tests running in a simulated blockchain environment, with the ability to manipulate it to recreate any situation we want.&lt;&#x2F;p&gt;
&lt;p&gt;To keep things simple, we will add a test to the same file we were using before, though typically tests go on separate files. At the bottom of &lt;code&gt;Storage.sol&lt;&#x2F;code&gt;, add:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;import &amp;quot;forge-std&#x2F;Test.sol&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;contract StorageTest is Test {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Storage storageContract;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    function setUp() public {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        storageContract = new Storage();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    function testSetWorks() public {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        assertEq(storageContract.retrieve(), 0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        storageContract.store(5);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        assertEq(storageContract.retrieve(), 5);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Notice this is just another contract written in solidity, only we imported the &lt;code&gt;forge-std&#x2F;Test.sol&lt;&#x2F;code&gt;, which contains all the test code and utilities, like assertions and logging.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;setUp&lt;&#x2F;code&gt; function runs before every test, and in this case just deploys a &lt;code&gt;Storage&lt;&#x2F;code&gt; contract so that we can call it. The test itself is in the &lt;code&gt;testSetWorks()&lt;&#x2F;code&gt; (test methods must start with the word &lt;code&gt;test&lt;&#x2F;code&gt;), and it does the same thing we did above, only in the blockchain environment provided by Forge.&lt;&#x2F;p&gt;
&lt;p&gt;Running &lt;code&gt;forge test&lt;&#x2F;code&gt; should print the following&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Running 1 test for src&#x2F;Storage.sol:StorageTest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[PASS] testSetWorks() (gas: 32478)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Test result: ok. 1 passed; 0 failed; finished in 323.17µs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;printing-and-events&quot;&gt;Printing and events&lt;&#x2F;h2&gt;
&lt;p&gt;A very common problem developers new to Ethereum run into is printing variables for debugging. Again, because our code is meant to be run on the Ethereum virtual machine on-chain, printing to standard output isn’t something baked into the language. Some people get around it by manually emitting &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;ethereum.org&#x2F;es&#x2F;developers&#x2F;tutorials&#x2F;logging-events-smart-contracts&#x2F;&quot;&gt;Events&lt;&#x2F;a&gt;, but this is very cumbersome.&lt;&#x2F;p&gt;
&lt;p&gt;The Forge Test contract gives us &lt;code&gt;console.log&lt;&#x2F;code&gt; methods to print out values when running tests. If we add a log statement to our test, like so&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;function testSetWorks() public {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    assertEq(storageContract.retrieve(), 0);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    storageContract.store(5);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    uint256 result = storageContract.retrieve();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    assertEq(result, 5);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    console.log(result);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;and run the tests again with a verbosity of two (&lt;code&gt;forge test -vv&lt;&#x2F;code&gt;) we should see&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Running 1 test for src&#x2F;Storage.sol:StorageTest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[PASS] testSetWorks() (gas: 31774)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Logs:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;and our variable gets printed. Under the hood, what’s happening here is &lt;code&gt;console.log&lt;&#x2F;code&gt; emits actual ethereum events (the ones mentioned above) in Forge’s execution environment, which Forge are then captured and printed out.&lt;&#x2F;p&gt;
&lt;p&gt;Note that we could have added calls to &lt;code&gt;console.log&lt;&#x2F;code&gt; to our regular non-test code, and we would have seen those logs when running tests as well.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;traces-and-gas-estimation&quot;&gt;Traces and gas estimation&lt;&#x2F;h2&gt;
&lt;p&gt;In the last section we used the &lt;code&gt;-vv&lt;&#x2F;code&gt; flag when running tests to show logs, but the verbosity level can go up to five. Running &lt;code&gt;forge test -vvvvv&lt;&#x2F;code&gt; should return something like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Traces:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  [88926] StorageTest::setUp()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├─ [34487] → new Storage@&amp;quot;0xce71…c246&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    │   └─ ← 172 bytes of code&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    └─ ← ()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  [31774] StorageTest::testSetWorks()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├─ [2246] Storage::retrieve() [staticcall]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    │   └─ ← 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├─ [20212] Storage::store(5)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    │   └─ ← ()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├─ [246] Storage::retrieve() [staticcall]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    │   └─ ← 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ├─ [0] console::f5b1bba9(0000000000000000000000000000000000000000000000000000000000000005) [staticcall]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    │   └─ ← ()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    └─ ← ()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This shows the stack trace of every test, each function call also showing its associated &lt;code&gt;gas&lt;&#x2F;code&gt; cost. Recall &lt;code&gt;gas&lt;&#x2F;code&gt; in ethereum is a measure of the cost of execution of a certain operation; the higher it is the more computationally expensive a bunch of code is. Because &lt;code&gt;gas&lt;&#x2F;code&gt; is ultimately paid in real money, optimizing it becomes extremely important.&lt;&#x2F;p&gt;
&lt;p&gt;In this case we can see that a call to &lt;code&gt;store&lt;&#x2F;code&gt; is an order of magnitude more expensive than &lt;code&gt;retrieve&lt;&#x2F;code&gt;, i.e., storing data is much more expensive than just reading it. Additionally, the second call to &lt;code&gt;retrieve&lt;&#x2F;code&gt; was 10x cheaper than the first one. This is no bug, the EVM reduces the cost of a storage read if the variable in question has already been read from (i.e. if the variable is &lt;code&gt;hot&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;closing-thoughts&quot;&gt;Closing thoughts&lt;&#x2F;h2&gt;
&lt;p&gt;Foundry has a lot more features including fuzz testing, forking from live networks, an array of cheatcodes, and the list goes on. For a deeper dive we highly recommend going directly to the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;book.getfoundry.sh&#x2F;&quot;&gt;Foundry book&lt;&#x2F;a&gt;, it is very easy to follow and has some thorough tutorials.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Secure computation in Rust: Using Intel&#x27;s SGX instructions with Teaclave and Fortanix</title>
          <pubDate>Thu, 05 May 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/secure-computation-in-rust-using-intels-sgx-instructions-with-teaclave-and-fortanix/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/secure-computation-in-rust-using-intels-sgx-instructions-with-teaclave-and-fortanix/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/secure-computation-in-rust-using-intels-sgx-instructions-with-teaclave-and-fortanix/">&lt;p&gt;If you have been following this blog you should already know that I am a distributed system and Rust zealot.&lt;br &#x2F;&gt;
I started playing with Rust 2014 since it was implemented in OCaml, a language I love, and because it had green threads similar to the ones of Erlang. At the end of 2014, start of 2015 Rust’s runtime system and green-threading model was removed. I continued using Rust because of its great community and its C + ML roots. In addition to this it is a great complement to Erlang since it is has almost opposite semantics, specially in its error handling philosophy.&lt;&#x2F;p&gt;
&lt;p&gt;At the end of 2017 I started working on the crypto space, mostly because I needed the money. I’ve not been very public about it since I was skeptical of the whole movement. Even if I liked working on the technical problems that appeared on the space I thought that most crypto projects were ponzi-scheme or completely useless for users.&lt;&#x2F;p&gt;
&lt;p&gt;In these years I’ve met great engineers and technologies that made me believe more in the movement. That is one of the reasons why we started working on the zero knowledge proof space. One of this projects we are working with requires high standards of data security and privacy. For this we need to abstract ourselves from potential OS security vulnerabilities hosted in third party servers.&lt;br &#x2F;&gt;
The following blog post follows our journey discovering Intel SGX and it’s integration in the development of Rust applications.&lt;&#x2F;p&gt;
&lt;p&gt;As you can already guess this is a project full of challenges, from performance ones to potential security issues. So we would like to abstract ourselves from potential OS security vulnerabilities that the host devices might have, more so when you deploy your application in the cloud. So we’ve been tasked with deploying essential parts of the project in a specific Trusted Execution Environments (or TEEs for short), Intel’s SGX.&lt;&#x2F;p&gt;
&lt;p&gt;The following blog post follows our journey discovering Intel SGX and its integration in the development of Rust applications.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Subscribe to our&lt;&#x2F;em&gt;&lt;a href=&quot;&#x2F;#&#x2F;portal&#x2F;signup&quot;&gt; &lt;em&gt;newsletter&lt;&#x2F;em&gt;&lt;&#x2F;a&gt; &lt;em&gt;to receive news and updates from Not a Monad Tutorial delivered directly to your inbox.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;Imagine you are building a piece of software which handles sensitive information. And that you decided to deploy your application in the cloud.&lt;&#x2F;p&gt;
&lt;p&gt;Since our project handles private keys used to access transactions and e-wallets, we need to ensure enhanced confidentiality and integrity, even in the presence of privileged malware at the OS, BIOS, VMM, or SMM layers.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;tees&quot;&gt;TEEs&lt;&#x2F;h3&gt;
&lt;p&gt;TEEs can be thought of as processes that are running “isolated” from the OS and upper layers in a secure part of the CPU. The idea of this is to help to significantly reduce the attack surface. TEEs aim to ensure a subset of data integrity, code integrity and data privacy, which fits our sensitive data manipulation needs. Each CPU vendor has their own implementation, some of which are:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Intel SGX&lt;&#x2F;li&gt;
&lt;li&gt;ARM TrustZone&lt;&#x2F;li&gt;
&lt;li&gt;AMD Secure Encrypted Virtualization&lt;&#x2F;li&gt;
&lt;li&gt;ZAYA TEE for RiscV&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;From now on we’ll be focusing on Intel SGX.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;intel-sgx&quot;&gt;Intel SGX&lt;&#x2F;h3&gt;
&lt;p&gt;SGX is an Intel ISA extension with TEEs support. The environments are called &lt;strong&gt;enclaves&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Some important aspects:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;It’s not possible to read nor write the enclave’s memory space from outside the enclave&lt;&#x2F;strong&gt; , regardless of the privilege level and CPU mode.&lt;&#x2F;li&gt;
&lt;li&gt;In production, it’s not possible to debug enclaves by software nor hardware.&lt;&#x2F;li&gt;
&lt;li&gt;Entering the enclave via function calls, jumps or stack&#x2F;register manipulation is not possible. To do so you have to use a specific CPU instruction which also does some safety checks ([E]call, [O]call).&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Enclave’s memory is encrypted&lt;&#x2F;strong&gt; , and the key used changes on every power cycle. It’s stored within the CPU and is not accessible.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;Lb332Bp.png&quot; alt=&quot;&quot; &#x2F;&gt;Source: Microsoft Azure Confidential Computing &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.microsoft.com&#x2F;en-us&#x2F;azure&#x2F;confidential-computing&#x2F;confidential-computing-enclaves&quot;&gt;Documentation&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Warning&lt;&#x2F;strong&gt; : if you are considering developing an SGX application, we’d highly suggest &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ayeks&#x2F;SGX-hardware#desktop-cpus-affected-by-the-product-change-notification-from-2015&quot;&gt;checking your CPU&lt;&#x2F;a&gt; and whether it has SGX support. Intel’s C++ SDK has some simulation capabilities (as we’ll see later), but those aren’t fully fleshed out. We managed to run in a Macbook Pro some sample projects using Teclave’s simulation mode… but at what cost? So, only if you like stepping on Legos for fun try running SGX in your M1.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;hqeSchG.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sgx-rust-development&quot;&gt;SGX Rust Development&lt;&#x2F;h2&gt;
&lt;p&gt;The Intel SGX’s SDK is implemented on C++, so usually you’ll implement your application using C&#x2F;C++ and their &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.intel.com&#x2F;content&#x2F;www&#x2F;us&#x2F;en&#x2F;developer&#x2F;tools&#x2F;software-guard-extensions&#x2F;get-started.html&quot;&gt;toolkit&lt;&#x2F;a&gt;.&lt;br &#x2F;&gt;
As a starting point Intel gives a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;intel&#x2F;linux-sgx&#x2F;tree&#x2F;master&#x2F;SampleCode&quot;&gt;couple of code examples&lt;&#x2F;a&gt; for different implementations.&lt;br &#x2F;&gt;
But, are there any developers worth their salt that want to develop a solid blockchain project in those languages when you’ve got the hip and cool option that is Rust? (in fact, yes) &lt;em&gt;We don’t look forward to that.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;Whhj2XE.png&quot; alt=&quot;&quot; &#x2F;&gt; Recreation of what the Rust SDK developers may have thought&lt;&#x2F;p&gt;
&lt;p&gt;Since our source code is already written in Rust we looked for crates that allow us an easy and seamless integration of our code with the SGX enclaves.&lt;br &#x2F;&gt;
We found 2 alternatives for this, which use different approaches. Both are open source:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Teaclave SGX SDK&lt;&#x2F;li&gt;
&lt;li&gt;Fortanix Enclave Development Platform&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;teaclave&quot;&gt;Teaclave&lt;&#x2F;h2&gt;
&lt;p&gt;It wraps the Intel SGX’s SDK. You can check their &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;apache&#x2F;incubator-teaclave-sgx-sdk&quot;&gt;GitHub repo&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;Bd8I1r5.png&quot; alt=&quot;&quot; &#x2F;&gt;Source: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.trentonsystems.com&#x2F;blog&#x2F;what-is-intel-sgx&quot;&gt;https:&#x2F;&#x2F;www.trentonsystems.com&#x2F;blog&#x2F;what-is-intel-sgx&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;With Teaclave SDK you will split your application into two:&lt;br &#x2F;&gt;
- Trusted, also called the &lt;em&gt;enclave&lt;&#x2F;em&gt;.&lt;br &#x2F;&gt;
- Untrusted, called the &lt;em&gt;app&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Remember, under the hood you’re still using Intel SDK library.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;ixchGF6.png&quot; alt=&quot;&quot; &#x2F;&gt;Source: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.infoq.com&#x2F;presentations&#x2F;intel-sgx-enclave&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.infoq.com&#x2F;presentations&#x2F;intel-sgx-enclave&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The Untrusted code is in charge of initializing and shutting down the enclave, and you have to define an interface for the app and the enclave to communicate with each other. During compilation, those interfaces get transformed into [E]calls and [O]calls. In the end you would end up with something like this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;rzWrjSw.png&quot; alt=&quot;&quot; &#x2F;&gt;Source: Slide from Yu Ding’s &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.infoq.com&#x2F;presentations&#x2F;intel-sgx-enclave&#x2F;&quot;&gt;talk&lt;&#x2F;a&gt; at infoq about Intel SGX enclaves on Rust&lt;&#x2F;p&gt;
&lt;p&gt;But as the saying goes, not everything that shines is gold. The enclave will run under &lt;code&gt;#[no_std]&lt;&#x2F;code&gt;, so keep in mind that your favorite crates might not be supported. However, the maintainers have been porting and developing a bunch of useful crates to work with and of course you can also port the ones you want as well. Among them there’s the &lt;code&gt;libc&lt;&#x2F;code&gt;, the &lt;code&gt;std&lt;&#x2F;code&gt; (or part of it), synchronization primitives (e.g. &lt;code&gt;SgxMutex&lt;&#x2F;code&gt;, &lt;code&gt;SgxRWLock&lt;&#x2F;code&gt;) and more. However, there is not support for async Rust yet.&lt;&#x2F;p&gt;
&lt;p&gt;The repo is populated with some sample projects, which are great to start learning how to structure the project works and some conventions you need to follow and it’s also where you can take some as templates for your own application.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;simulation-mode&quot;&gt;Simulation Mode&lt;&#x2F;h3&gt;
&lt;p&gt;Since under the hood it uses Intel’s SDK, you still need to meet the necessary requirements. However, Intel also has simulation libraries (although those don’t have all the features implemented) which might come in handy to test your enclave locally despite not having an Intel processor.&lt;br &#x2F;&gt;
You also have available a docker image and you can check the details on how to run it &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;apache&#x2F;incubator-teaclave-sgx-sdk#running-without-intel-sgx-drivers&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;fortanix-edp&quot;&gt;Fortanix EDP&lt;&#x2F;h2&gt;
&lt;p&gt;Fortanix EDP is developed by a company named &lt;em&gt;Fortanix&lt;&#x2F;em&gt;. From their website we read:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Fortanix secures sensitive data across public, hybrid, multicloud and private cloud environments, enabling customers to operate even the most sensitive applications in any environment.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;They came up with a different solution to running Rust code on Intel enclaves.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;M5pt0Zd.png&quot; alt=&quot;&quot; &#x2F;&gt;Source: Fortanix EDP &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;edp.fortanix.com&#x2F;docs&#x2F;concepts&#x2F;architecture&#x2F;&quot;&gt;architecture documentation&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;First, instead of building an &lt;em&gt;app&lt;&#x2F;em&gt; and an &lt;em&gt;enclave&lt;&#x2F;em&gt; Fortanix EDP helps you build only the enclave and the way of communicating between the app and the enclave is up to you.&lt;&#x2F;p&gt;
&lt;p&gt;The enclave runner is responsible for initializing and shutting down enclaves and handling via a usercall interface the enclave’s needs.&lt;&#x2F;p&gt;
&lt;p&gt;Since it avoids this interfacing between app and enclave, it greatly reduces a lot of bureaucracy regarding project structure and setup. This was one of the benefits considered when &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;apache&#x2F;tvm&#x2F;issues&#x2F;2887&quot;&gt;TVM swapped Teaclave for Fortanix&lt;&#x2F;a&gt;. You can also see from this Fortanix &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;fortanix&#x2F;rust-sgx&#x2F;tree&#x2F;master&#x2F;examples&#x2F;mpsc-crypto-mining&quot;&gt;example crate&lt;&#x2F;a&gt; that only a few lines were added to the &lt;code&gt;Cargo.toml&lt;&#x2F;code&gt;, and the rest is a standard pure Rust project.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;supported-crates-and-std-caveats&quot;&gt;Supported crates and std Caveats&lt;&#x2F;h3&gt;
&lt;p&gt;Of course most of the time there’s going to be a catch. You might sometimes need to create an implementation of a crate for the SGX target. The process is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;edp.fortanix.com&#x2F;docs&#x2F;tasks&#x2F;dependencies&#x2F;&quot;&gt;documented&lt;&#x2F;a&gt; as well. Also some crates have been adding SGX support for the &lt;code&gt;x86_64-fortanix-unknown-sgx&lt;&#x2F;code&gt; target, such as the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-random&#x2F;rand&#x2F;pull&#x2F;680&#x2F;files&quot;&gt;rand&lt;&#x2F;a&gt; crate.&lt;&#x2F;p&gt;
&lt;p&gt;This project is already a tier 2 target for the Rust compiler (more on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;nightly&#x2F;rustc&#x2F;platform-support.html#tier-2&quot;&gt;Rust tiers&lt;&#x2F;a&gt;), and that’s great news! It’s based on &lt;code&gt;libstd&lt;&#x2F;code&gt;, practice which may have its drawbacks since it assumes &lt;code&gt;time&#x2F;net&#x2F;env&#x2F;thread&#x2F;process&#x2F;fs&lt;&#x2F;code&gt; are implemented. Some of those are still not implemented (&lt;code&gt;fs&lt;&#x2F;code&gt; for example) and will throw a runtime panic instead of a compile error, breaking the Rust’s philosophy of “if it compiles it works”. More info on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;edp.fortanix.com&#x2F;docs&#x2F;concepts&#x2F;rust-std&#x2F;&quot;&gt;Rust std support&lt;&#x2F;a&gt; on Fortanix’s documentation.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;i-o&quot;&gt;I&#x2F;O&lt;&#x2F;h3&gt;
&lt;p&gt;The recommended way of handling input&#x2F;output in the enclave is via byte streams, particularly using &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;edp.fortanix.com&#x2F;docs&#x2F;concepts&#x2F;rust-std&#x2F;#stream-networking&quot;&gt;&lt;code&gt;TcpStream&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; and using TLS (Transport Layer Security is a protocol used to provide secure communications to a network and mostly known for its use on &lt;em&gt;https&lt;&#x2F;em&gt;) on top of that is strongly suggested.&lt;br &#x2F;&gt;
There are primitives for dealing with pointers to user space as well. These primitives use Rust’s borrowing and ownership mechanism to avoid data races among other issues, and also prevent creating dangerous Rust references to user memory. Still, using &lt;code&gt;TcpStream&lt;&#x2F;code&gt; is preferred.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;an-example-using-both-fortanix-and-teaclave&quot;&gt;An example using both Fortanix and Teaclave&lt;&#x2F;h2&gt;
&lt;p&gt;We’re going to show a simplified of the hello-world &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;apache&#x2F;incubator-teaclave-sgx-sdk&#x2F;tree&#x2F;master&#x2F;samplecode&#x2F;hello-rust&quot;&gt;example&lt;&#x2F;a&gt; from the Teaclave repo and see how we would do a similar thing using Fortanix’s EDP.&lt;&#x2F;p&gt;
&lt;p&gt;We’ll be omitting some details, so if you’re interested in getting them we suggest that you check out Teaclave’s repo.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;teaclave-1&quot;&gt;Teaclave&lt;&#x2F;h3&gt;
&lt;p&gt;The project structure is:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;mm0n8rE.png&quot; alt=&quot;&quot; &#x2F;&gt;Example of project structure using Teaclave&lt;&#x2F;p&gt;
&lt;p&gt;Notice that we have the &lt;code&gt;app&#x2F;&lt;&#x2F;code&gt; and the &lt;code&gt;enclave&#x2F;&lt;&#x2F;code&gt; directories. First let’s see the app’s code:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;extern {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    fn say_something(eid: sgx_enclave_id_t, retval: *mut sgx_status_t,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                     some_string: *const u8, len: usize) -&amp;gt; sgx_status_t;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We define the function that we want to run in the enclave as an external function, notice that we are not using Rust’s &lt;code&gt;String&lt;&#x2F;code&gt; here, we need to pass the raw parts instead.&lt;&#x2F;p&gt;
&lt;p&gt;You need to initialize the enclave with a &lt;code&gt;SgxEnclave::create&lt;&#x2F;code&gt; call before running code on it. Remember to &lt;strong&gt;always initialize&lt;&#x2F;strong&gt; the enclave first.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Initialize the enclave - proceed on success&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let enclave = match init_enclave() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Ok(r) =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        println!(&amp;quot;[+] Init Enclave Successful {}!&amp;quot;, r.geteid());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        r&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Err(x) =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        println!(&amp;quot;[-] Init Enclave Failed {}!&amp;quot;, x.as_str());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let input_string = String::from(&amp;quot;This is a normal world string passed into Enclave!\n&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let mut retval = sgx_status_t::SGX_SUCCESS;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then we make the &lt;code&gt;[E]call&lt;&#x2F;code&gt; into the enclave. This needs to be wrapped with an unsafe block and we need to split the String into its pointer and length.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let result = unsafe {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    say_something(enclave.geteid(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                  &amp;amp;mut retval,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                  input_string.as_ptr() as * const u8,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                  input_string.len())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;[E]call&lt;&#x2F;code&gt; will return with a &lt;code&gt;sgx_status_t&lt;&#x2F;code&gt; we can check against to see if the enclave ran successfully.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;match result {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    sgx_status_t::SGX_SUCCESS =&amp;gt; {},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    _ =&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        println!(&amp;quot;[-] ECALL Enclave Failed {}!&amp;quot;, result.as_str());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;println!(&amp;quot;[+] say_something success...&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You have to destroy the enclave before exiting. From the documentation it reads:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is highly recommended that the sgx_destroy_enclave function be called after the application has finished using the enclave to avoid possible deadlocks.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;enclave.destroy();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now into the enclave’s code:&lt;&#x2F;p&gt;
&lt;p&gt;Each &lt;code&gt;[E]call&lt;&#x2F;code&gt; should follow the signature &lt;code&gt;#[no_mangle] pub extern &quot;C&quot; fn func_name(args) -&amp;gt; sgx_status_t&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#[no_mangle]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub extern &amp;quot;C&amp;quot; fn say_something(some_string: *const u8, some_len: usize) -&amp;gt; sgx_status_t &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Again, we need the unsafe block to call &lt;code&gt;from_raw_parts&lt;&#x2F;code&gt; and we get our string slice back.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let str_slice = unsafe { slice::from_raw_parts(some_string, some_len) };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; A sample &amp;amp;&amp;#39;static string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let rust_raw_string = &amp;quot;This is a in-Enclave &amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Construct a string from &amp;amp;&amp;#39;static string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let mut hello_string = String::from(rust_raw_string);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&#x2F; Ocall to normal world for output&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;println!(&amp;quot;{}&amp;quot;, &amp;amp;hello_string);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sgx_status_t::SGX_SUCCESS&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And there’s even more. You need to define the &lt;code&gt;[E]call&#x2F;[O]call&lt;&#x2F;code&gt; interface in the enclave subdirectory in an &lt;code&gt;Enclave.edl&lt;&#x2F;code&gt; file.&lt;&#x2F;p&gt;
&lt;p&gt;It would look something like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;enclave {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    from &amp;quot;sgx_tstd.edl&amp;quot; import *;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &#x2F;&#x2F; you would have other imports here&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    trusted {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;* define ECALLs here. *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        public sgx_status_t say_something([in, size=len] const uint8_t* some_string, size_t len);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    untrusted {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &#x2F;* define OCALLs here. *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There are even more files we haven’t touched yet. But this is enough to show that while Teaclave might give you a lot of control of what’s going on, it’s not easy and increases the overall complexity of your project.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;same-implementation-using-fortanix-edp&quot;&gt;Same implementation using Fortanix EDP&lt;&#x2F;h3&gt;
&lt;p&gt;As Fortanix’s documentation says:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;EDP applications should be thought of as providing a service to other parts of your system. An EDP application might interact with other services which themselves might be EDP applications. The service may be implemented as a gRPC server, an HTTPS server with REST APIs, or any other service protocol.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer&lt;&#x2F;strong&gt; : we haven’t been able to get our hands into an Intel SGX capable machine, hence we weren’t able to test this example. However, we think this serves as a good illustration example and gives some credit to Teaclave and Intel for the simulation capabilities.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s see how can we accomplish our hello world using Fortanix EDP. Our final project looks like this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;8Wh6Nk4.png&quot; alt=&quot;&quot; &#x2F;&gt;Example of a project structure using Fortanix&lt;&#x2F;p&gt;
&lt;p&gt;Let’s look at what the &lt;code&gt;main.rs&lt;&#x2F;code&gt; has to offer:&lt;&#x2F;p&gt;
&lt;p&gt;We needed to add this two lines to the &lt;code&gt;.cargo&#x2F;config&lt;&#x2F;code&gt; file:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[target.x86_64-fortanix-unknown-sgx]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;runner=&amp;#39;ftxsgx-runner-cargo&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And that’s the only setup we needed (besides the Rust code).&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;use std::net::{TcpListener, TcpStream};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;use std::io::Read;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn main() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let listener = TcpListener::bind(&amp;quot;127.0.0.1:7878&amp;quot;).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let (mut stream, _addr) = listener.accept().unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    let mut message = [0; 128];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    stream.read(&amp;amp;mut message).unwrap();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    println!(&amp;quot;new client: {:?}&amp;quot;, std::str::from_utf8(&amp;amp;message).unwrap());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Pretty much like good ol’ Rust code right? In fact, we’re able to compile it without the Fortanix runner and have it running.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;GPPD8IR.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This only constitutes the enclave, but an easy way to test it is by making the TCP request, so it should be enough to run the following command:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo &amp;quot;Hello World!&amp;quot; | nc 127.0.0.1 7878&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The way this is built means that you could call this from another language as long as you can make the TPC connection.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;sgx_with_rust_blog_post&quot;&gt;&lt;em&gt;Full code here&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;teaclave-vs-fortanix&quot;&gt;Teaclave vs. Fortanix&lt;&#x2F;h2&gt;
&lt;p&gt;One significant difference between the two is their size: Teaclave’s repo contains ~80K lines of Rust code while Fortanix’s one has ~18K lines of code, which is about 4 times less. Some of these could be atributed to the amount of examples Teaclave has in their repo but still that doesn’t make up for the whole difference.&lt;br &#x2F;&gt;
Also, Fortanix is mostly written using Rust code, while Teaclave has another 80K more lines of non Rust code… yikes!&lt;&#x2F;p&gt;
&lt;p&gt;In terms of community activity we ran a comparison of both thru &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;vesoft-inc.github.io&#x2F;github-statistics&#x2F;&quot;&gt;github-statistics&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;bejTcAq.png&quot; alt=&quot;&quot; &#x2F;&gt;Comparison between Fortanix and Teaclave repos stats&lt;&#x2F;p&gt;
&lt;p&gt;Teaclave seems to have more traction based on the amount of stars and forks. Nevertheless, during 2021 there is a clear increase of the activity in the Fortanix’s EDP repository. So it seems like Teaclave is more widely used but it’s development has stagnated somewhat while Fortanix is taking the lead, a dynamic that has been reinforced since attaining &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;users.rust-lang.org&#x2F;t&#x2F;sgx-target-is-now-a-rust-tier-2-platform&#x2F;24779&quot;&gt;Rust tier 2 in january on 2019&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;weighting-pros-and-cons&quot;&gt;Weighting pros and cons&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;teaclave-2&quot;&gt;Teaclave&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;✅ Uses Intel’s libs, and they’re supposed to be the experts on that.&lt;&#x2F;li&gt;
&lt;li&gt;✅ There are simulation libraries which expand the support a bit.&lt;&#x2F;li&gt;
&lt;li&gt;✅ Already solves connecting the app and the enclave.&lt;&#x2F;li&gt;
&lt;li&gt;✅ There are a few more examples available (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;apache&#x2F;incubator-teaclave-sgx-sdk&#x2F;tree&#x2F;master&#x2F;samplecode&quot;&gt;Teaclave SGX SDK repo&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;glassonion1&#x2F;rust-101&#x2F;tree&#x2F;main&#x2F;sgx-sdk&quot;&gt;Rust 101 repo&lt;&#x2F;a&gt;).&lt;&#x2F;li&gt;
&lt;li&gt;❌ Uses Intel’s libs, and they’re supposed to be the experts on that. This might not be a bad thing by itself, but you could think of this as adding an extra dependency with a centralized entity such as Intel. Which is why in a decentralized environment might not be ideal (debatable).&lt;&#x2F;li&gt;
&lt;li&gt;❌ Integrating SGX to an existing system using this SDK is a bit tedious, since you need to restructure your application, use some Makefiles to handle linking the enclave with the application, declaring the interface connecting your applications in a separate &lt;code&gt;.edl&lt;&#x2F;code&gt; file with its own syntax and more.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;vMOMK15.png&quot; alt=&quot;&quot; &#x2F;&gt;Enclave folder using Teaclave vs Fortanix&lt;&#x2F;p&gt;
&lt;h3 id=&quot;fortanix&quot;&gt;Fortanix&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;✅ You can write all Rust code.&lt;&#x2F;li&gt;
&lt;li&gt;✅ Officially target tier 2 of the Rust compiler.&lt;&#x2F;li&gt;
&lt;li&gt;✅ Add a few lines to your &lt;code&gt;Cargo.toml&lt;&#x2F;code&gt; and you are set.&lt;&#x2F;li&gt;
&lt;li&gt;✅ We trust the fact that it is open source and therefore audited by many users, and being included as a tier 2 target for the Rust compiler means that it has earned some respect from the Rust community as well.&lt;&#x2F;li&gt;
&lt;li&gt;❌ Well, sometimes it’s not that easy. Not all crates have support for SGX although you can add your own implementation for the Fortanix target.&lt;&#x2F;li&gt;
&lt;li&gt;❌ since it uses &lt;code&gt;libstd&lt;&#x2F;code&gt; it assumes that you have implementations for &lt;code&gt;time&#x2F;net&#x2F;env&#x2F;thread&#x2F;process&#x2F;fs&lt;&#x2F;code&gt;, which SGX does not entirely support. This will generate runtime panics when used and you won’t be getting compilation errors.&lt;&#x2F;li&gt;
&lt;li&gt;❌ It’s easier to develop on, but that is because it hides some of the complexity away and you may ask yourself if we can trust on its security when many things are hidden away from the developer.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;&#x2F;h2&gt;
&lt;p&gt;We don’t find a clear winner between Teaclave and Fortanix, as both have their pros and cons.&lt;&#x2F;p&gt;
&lt;p&gt;Having to make a choice we tend to go with Fortanix as its easier to develop in pure Rust. Also as Fortanix is endorsed as Tier 2 we can have a high confidence about its compatilibity with our software allowing for a seamless implementation. As an added bonus this level of trust from the Rust developers gives us a somewhat indirect clue that there aren’t blatant security issues hidden in the code that are meaningful enough to make us to doubt it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;further-readings&quot;&gt;Further readings&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.intel.com&#x2F;content&#x2F;dam&#x2F;develop&#x2F;public&#x2F;us&#x2F;en&#x2F;documents&#x2F;intel-sgx-product-brief-2019.pdf&quot;&gt;SGX product brief&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.intel.com&#x2F;content&#x2F;www&#x2F;us&#x2F;en&#x2F;developer&#x2F;library.html?s=Newest&amp;amp;f:@stm_10309_en=%5BIntel%C2%AE%20Software%20Guard%20Extensions%20(Intel%C2%AE%20SGX)%5D&quot;&gt;Intel technical library - Software Guard Extensions&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;fortanix.com&#x2F;intel-sgx&#x2F;&quot;&gt;Fortanix resources&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;teaclave.apache.org&#x2F;docs&#x2F;&quot;&gt;Teaclave documentation&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Benchmarking and analyzing Rust code performance with Criterion and Iai</title>
          <pubDate>Sat, 30 Apr 2022 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/benchmarking-and-analyzing-rust-performance-with-criterion-and-iai/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/benchmarking-and-analyzing-rust-performance-with-criterion-and-iai/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/benchmarking-and-analyzing-rust-performance-with-criterion-and-iai/">&lt;p&gt;At &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;ClassLambda&quot;&gt;LambdaClass&lt;&#x2F;a&gt; we are big fans of reading, discussing and implementing distributed systems, compilers, drivers. The last few years we also got our hands dirty with reverse engineering and embedded systems development. Based on our interests it shouldn’t be a surprise that we have been using Rust for quite some time. Rust is one of a kind.&lt;&#x2F;p&gt;
&lt;p&gt;Correctness and performance are the main reasons we choose Rust for developing many of our applications. Rust’s compiler is a great tool to find bugs. The compiler can help a lot on the performance front but at the end you need to measure your running code. You need to know the bottlenecks that your code has in order to solve them.&lt;&#x2F;p&gt;
&lt;p&gt;In this post, we’ll talk about our experience doing benchmarks in Rust, what tools we used and why it was important for us. Usually a fully optimized function is harder to read than a simpler and slower one. Optimization is something that you’ll have to balance with readability and maintenance costs: sadly we can’t have the cake and eat it too in this case.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-benchmarking&quot;&gt;Why Benchmarking?&lt;&#x2F;h2&gt;
&lt;p&gt;A lot of new developers are starting to use Rust and they have not been exposed to benchmarking before. Just because Rust is fast and memory-efficient doesn’t mean that your code will be fast as well. The features that make Rust what it is, comes with a great cost if we don’t know how to properly use them. With great power comes great responsibility. These are mostly performance costs.&lt;&#x2F;p&gt;
&lt;p&gt;In our specific case, we worked with a function that iterates over a range of numbers and use them to create some data structures that would be used in another process. Sometimes this number range could be pretty big, so we wanted this function to be very efficient.&lt;&#x2F;p&gt;
&lt;p&gt;But how to know if this function is fast enough or at least takes the expected amount of time for our process?&lt;&#x2F;p&gt;
&lt;p&gt;Well, that’s the reason why we started benchmarking. We needed to know how much time it was taking to iterate and create all the structures, so we started researching benchmarking and how we could do that in Rust.&lt;&#x2F;p&gt;
&lt;p&gt;Probably, if you search how to benchmark in Rust the first result that you’ll get is “Criterion”. Recently Rust published a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;blog.rust-lang.org&#x2F;inside-rust&#x2F;2022&#x2F;04&#x2F;04&#x2F;lang-roadmap-2024.html&quot;&gt;roadmap for 2024&lt;&#x2F;a&gt; where they mentioned the possibility to adopt Criterion officially.&lt;&#x2F;p&gt;
&lt;p&gt;It’s worth mentioning that Rust comes with a benchmarking feature but is currently unstable as it says in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;nightly&#x2F;cargo&#x2F;commands&#x2F;cargo-bench.html?highlight=feature&quot;&gt;Rust documentation&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-criterion&quot;&gt;What is Criterion?&lt;&#x2F;h2&gt;
&lt;p&gt;Criterion is an Open-Source library, ported from the original &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;haskell&#x2F;criterion&quot;&gt;Haskell’s Criterion library&lt;&#x2F;a&gt;, with some sophisticated tools to do micro-benchmarks in Rust. By micro-benchmarking, we refer to measuring the performance of small parts of our process, like one or two functions (more on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;a&#x2F;2842707&quot;&gt;micro-benchmarking&lt;&#x2F;a&gt;). Benchmarking with Criterion gives you a general overview of the time that is spent on a task. This is known as &lt;strong&gt;Wall-time&lt;&#x2F;strong&gt; and it’s the time interval between the moment when the task started and when it’s finished. We’ll get on this later.&lt;br &#x2F;&gt;
We started playing with Criterion and we discovered some awesome features for our analysis:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Criterion makes some graphics to help you visualize the time that your function takes and make generates a report with those graphics.&lt;&#x2F;li&gt;
&lt;li&gt;It gives automatic comparisons between the last run of the benchmark and a new run with your new changes to see if your function improves in performance or if has regressed.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Furthermore, Criterion is pretty programmer-friendly. So you don’t need any external tools or a hard setup to start.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;analyzing-criterion-results&quot;&gt;Analyzing Criterion results&lt;&#x2F;h2&gt;
&lt;p&gt;We’ve mentioned graphic tools, visualizations, and comparisons that Criterion makes to help us understand the results but, how does that look?&lt;&#x2F;p&gt;
&lt;p&gt;Well, you have two ways to read the results provided by Criterion, one is the Command-Line Output and the other one is the generated &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;bheisler.github.io&#x2F;criterion.rs&#x2F;book&#x2F;user_guide&#x2F;html_report.html&quot;&gt;HTML report&lt;&#x2F;a&gt; with distribution plots and other resources.&lt;&#x2F;p&gt;
&lt;p&gt;The CLI output looks like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Benchmarking Get Blocks Function&#x2F;benches&#x2F;samples&#x2F;.ledger-2-4: Warming up for 3.0000 s&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Get Blocks Function&#x2F;benches&#x2F;samples&#x2F;.ledger-2-4                                                                          &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                        time:   [55.239 s 55.443 s 55.653 s]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Found 1 outliers among 10 measurements (10.00%)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  1 (10.00%) high mild&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;slowpoke-slow.gif&quot; alt=&quot;&quot; &#x2F;&gt;Graphic depiction of our results&lt;&#x2F;p&gt;
&lt;p&gt;Here is what we first saw when we ran &lt;code&gt;cargo bench&lt;&#x2F;code&gt;. We have information about the mean time, some other measurements, and the outliers encountered among the runs.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;KTm8I6O.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;htmlpreview.github.io&#x2F;?https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;how_to_benchmark_blogpost&#x2F;blob&#x2F;main&#x2F;report&#x2F;first_report_example.html&quot;&gt;HTML report example of our function&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Here we have an example of the HTML report that we also obtained when we used &lt;code&gt;cargo bench&lt;&#x2F;code&gt;. You can find this report on &lt;code&gt;target&#x2F;criterion&#x2F;report&#x2F;index.html&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Surely you noticed that the first output says “10 measurements”, the reason for this is that Criterion executes the function that we want to benchmark several times and the final result is the mean time among all of that results. Criterion has a default sample size value of 100. We’ve changed it to 10 because our function takes a lot of time on its own, and doing 100 samples of it would take a lot of time.&lt;&#x2F;p&gt;
&lt;p&gt;This was the report for our function creating 400 of these structures, this was pretty bad from what we were expecting.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;well-what-s-next&quot;&gt;Well, what’s next?&lt;&#x2F;h2&gt;
&lt;p&gt;So far, Criterion helped us measure how much execution time that function takes (on average). Is this enough to improve our implementation? Criterion tells us how long a function takes to run but we still don’t know how to improve our function. This is when we started to think about Profiling.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;start-profilling-and-beyond-criterion&quot;&gt;Start Profilling and beyond Criterion&lt;&#x2F;h2&gt;
&lt;p&gt;Profiling tells us more about the actual implementation of the function that we want to improve. There are different ways and tools that help profile our code.&lt;&#x2F;p&gt;
&lt;p&gt;We wanted a graphical way to understand the performance issues of our code so we started researching &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.brendangregg.com&#x2F;flamegraphs.html&quot;&gt;FlameGraphs&lt;&#x2F;a&gt; that use the &lt;code&gt;perf&lt;&#x2F;code&gt; tool. &lt;code&gt;perf&lt;&#x2F;code&gt; is a Linux command tool to obtain performance analysis of our applications. It was written by the master of all masters in computing performance analysis: Brendan Gregg.&lt;&#x2F;p&gt;
&lt;p&gt;Thankfully Rust has a crate called &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;flamegraph-rs&#x2F;flamegraph&quot;&gt;&lt;code&gt;flamegraph&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; that works with &lt;code&gt;cargo&lt;&#x2F;code&gt; and it’s pretty easy to use.&lt;&#x2F;p&gt;
&lt;p&gt;In this flamegraph, you can see all the function calls and how much time consumes in the whole process, including calls from the Rust standard library.&lt;br &#x2F;&gt;
FlameGraph in specific looks a little bit like this:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;PvYguTf.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;a href=&quot;&#x2F;images&#x2F;external&#x2F;first_flamegraph_example.svg&quot;&gt;Flamegraph of our function&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I know, right?&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;calculating-meme-template-047hp.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;analyzing-flamegraph-results&quot;&gt;Analyzing flamegraph results&lt;&#x2F;h2&gt;
&lt;p&gt;Each box represents a function in the stack. The x-axis spans the sample population, &lt;strong&gt;it does not show the passing of time from left to right&lt;&#x2F;strong&gt;. The width of the box shows a proportion of the total of time it was on-CPU or part of ancestry that was on-CPU (wider rectangles mean more time spent). And if you are wondering if the colors have some meaning the answer is no, only to give the flame aspect to the graphic.&lt;&#x2F;p&gt;
&lt;p&gt;It’s worth mentioning that flamegraph orders the function calls in the x-axis in alphabetical order by default, you can change this if you want but it wasn’t so important for us to know when the function was called, we wanted to know how much time each one took. The flamegraph groups all the different calls to show you the final time that this function spent in that call stack.&lt;&#x2F;p&gt;
&lt;p&gt;Profiling it’s important because we didn’t want to do changes without knowing that something was a real performance issue. This helped us discover those specific things that were making our function slower.&lt;&#x2F;p&gt;
&lt;p&gt;So now we have information about the bottlenecks! We only have to look at the call stacks and try to reduce that time when it’s possible.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;gotta-go-fast&quot;&gt;Gotta go fast!&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;f64ca7d4beb9865d2ed5145d120f0c56.gif&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Now we have some information to speed up our function. The first thing that we thought of was to integrate &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rayon-rs&#x2F;rayon&quot;&gt;Rayon&lt;&#x2F;a&gt; into this part. Rayon is a Rust library to make sequential computations into parallel. We started with that.&lt;&#x2F;p&gt;
&lt;p&gt;When we do a change the first thing that we want to check is if the time it’s better, so we go back to Criterion again.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Benchmarking Get Blocks Function&#x2F;benches&#x2F;samples&#x2F;.ledger-2-4: Warming up for 3.0000 s&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Get Blocks Function&#x2F;benches&#x2F;samples&#x2F;.ledger-2-4                                                 &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            time:   [15.985 s 16.246 s 16.482 s]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            change: [-70.886% -70.401% -69.951%]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Performance has improved.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So here we have the Command-line output with a new line. That &lt;strong&gt;change&lt;&#x2F;strong&gt; line shows us the improvement or regression compared to the last benchmark and we see that is 70% better so we have the happy case. Let’s take a look at the new reports.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;external&#x2F;4pFWn55.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;htmlpreview.github.io&#x2F;?https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;how_to_benchmark_blogpost&#x2F;blob&#x2F;main&#x2F;report&#x2F;comparison_report_example.html&quot;&gt;HTML comparison report with our new implementation&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Here we have the new graph. Criterion automatically merged the last two plots and did one with the comparison. It’s easy for us to show these new results.&lt;&#x2F;p&gt;
&lt;p&gt;With a relatively small change, we made an important difference so this was enough for us at least for now. If you think that is not fast enough the good thing is that you can repeat these steps, do flamegraph again, see the slow part of the process, correct it and go with Criterion again.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;problems-with-rayon-and-criterion&quot;&gt;Problems with Rayon and Criterion&lt;&#x2F;h2&gt;
&lt;p&gt;One thing we encountered is that benchmarking with Rayon and parallel code comes with an extra step. Rayon works with an internal ThreadPool to run paralel code and it has a default number of threads to use.&lt;br &#x2F;&gt;
Sometimes for benchmarking this threadpool needs to be bigger so we had to include a custom global ThreadPool using&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;rayon::ThreadPoolBuilder::new()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .stack_size(size)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .num_threads(number_of_threads)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .build_global()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This solved our problem and hopefully will solve yours too.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;criterion-and-ci-integration&quot;&gt;Criterion and CI Integration&lt;&#x2F;h2&gt;
&lt;p&gt;At some point, we wanted to check regression or improvements with every PR done to our Repo to keep track and make sure that future changes won’t affect our performance. In summary, the idea was to integrate our Criterion benchmarks with CI tools. It turned out that Criterion is not a good option if we want to do continuous integration. This is because the virtualization used by all these CI tools &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;bheisler.github.io&#x2F;criterion.rs&#x2F;book&#x2F;faq.html&quot;&gt;introduces noise into the benchmarking process&lt;&#x2F;a&gt;. For Criterion the result may be affected by this and the results would show changes in performance without touching that part of our code.&lt;&#x2F;p&gt;
&lt;p&gt;We’ll dig next in how we can make this possible with another tool .&lt;&#x2F;p&gt;
&lt;h2 id=&quot;next-steps-and-how-to-improve-our-benchmarks&quot;&gt;Next steps and how to improve our benchmarks&lt;&#x2F;h2&gt;
&lt;p&gt;At this point, we already used Criterion to set our first-time baseline, and then we introduced flamegraph to identify bottlenecks in our code. Maybe this is enough but, what if we want to go a little further? It was at this point that we found &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;bheisler.github.io&#x2F;criterion.rs&#x2F;book&#x2F;iai&#x2F;iai.html&quot;&gt;&lt;strong&gt;Iai&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Iai&lt;&#x2F;strong&gt; is an experimental Framework designed for One-shot benchmarking. This framework provides a tool for making benchmarks. All these tools work on Valgrind and use &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.cs.cmu.edu&#x2F;afs&#x2F;cs.cmu.edu&#x2F;project&#x2F;cmt-40&#x2F;Nice&#x2F;RuleRefinement&#x2F;bin&#x2F;valgrind-3.2.0&#x2F;docs&#x2F;html&#x2F;cg-manual.html#:~:text=Cachegrind%20is%20a%20tool%20for,misses%2C%20writes%20and%20writes%20misses.&quot;&gt;Cachegrind&lt;&#x2F;a&gt; for profiling our code. The profiling gives us another kind of information like the number of instructions of our function, the access to the different Cache memories, access to RAM, and Estimated cycles.&lt;br &#x2F;&gt;
All of this comes with some pros and cons to consider:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;✅ High-precision measurements and better performance since Iai executes the benchmark only once.&lt;&#x2F;li&gt;
&lt;li&gt;✅ Making a benchmark in Iai works in a very similar way compared to Criterion, it’s easy to set up and the code structure is almost the same.&lt;&#x2F;li&gt;
&lt;li&gt;✅ Like flamegraph, Iai works as a complement of Criterion and not a competitor.&lt;&#x2F;li&gt;
&lt;li&gt;✅ Iai uses an abstraction to prevent optimizations to be made by the compiler.&lt;&#x2F;li&gt;
&lt;li&gt;❌ Needs Valgrind to work so it won’t be possible to use it on a platform that doesn’t support Valgrind. We can use it with docker but this definitely will slow things down.&lt;&#x2F;li&gt;
&lt;li&gt;❌ It’s not good for test change from sequential code to paralel code.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;One of the best things that we can solve with Iai is the possibility of integrating benchmarks with our CI tools. We mentioned that Criterion is not a good option for this. Iai runs all the benchmarks inside Valgrind&#x2F;Cachegrind so the virtual machine measurements won’t be affected by external noise.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;that-s-all-folks&quot;&gt;That’s all, folks!&lt;&#x2F;h2&gt;
&lt;p&gt;We introduced you to the benchmark world with Rust exploring some tools and showing you how to interpret all the results that this tool gave us. The world of benchmarking is expansive and exciting and Criterion is the biggest thing since the invention of sliced bread. Thanks to the Flamegraph profiling tool we learned a lot about the inner workings of the calls to the machine that Rust generates.&lt;&#x2F;p&gt;
&lt;p&gt;As a result of this journey our code improved a lot without losing code readability. Although we spent &lt;strong&gt;a lot of time&lt;&#x2F;strong&gt; in subsequent iterations of the function to achieve this. So you have to take into account that benchmarking and profiling should only be used when performance gains are crucial to your project. Don’t lose sleep over functions that don’t use too many resources, you should trust us on this one.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Simulations are about to get way, way faster with JuliaSim</title>
          <pubDate>Thu, 02 Sep 2021 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/simulations-are-about-to-get-way-way-faster-with-juliasim/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/simulations-are-about-to-get-way-way-faster-with-juliasim/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/simulations-are-about-to-get-way-way-faster-with-juliasim/">&lt;p&gt;Today we’re excited to bring you a first glance at the result of a major multi-year project by the Julia Computing team.&lt;&#x2F;p&gt;
&lt;p&gt;JuliaSim is a cloud-based simulation platform built on top of the Julia open source stack, including SciML and ModelingToolkit, which we explored in depth &lt;a href=&quot;&#x2F;scientific-machine-learning-with-julia-the-sciml-ecosystem&#x2F;&quot;&gt;here&lt;&#x2F;a&gt; and &lt;a href=&quot;&#x2F;modeling-complexity-with-symbolics-jl-and-modelingtoolkit-jl&#x2F;&quot;&gt;here&lt;&#x2F;a&gt;, respectively. These were just the base of JuliaSim, which aims to change the way the industry does modeling and simulation with powerful acceleration and integration within a complete ecosystem.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;juliacomputing.com&#x2F;products&#x2F;juliasim&#x2F;&quot;&gt;JuliaSim&lt;&#x2F;a&gt;’s first beta will be released in a few months. We interviewed Chris Rackauckas to learn more about the project.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h4 id=&quot;what-is-juliasim-how-does-it-compare-to-alternatives-like-modelica-dymola&quot;&gt;What is JuliaSim? How does it compare to alternatives like Modelica&#x2F;Dymola?&lt;&#x2F;h4&gt;
&lt;p&gt;JuliaSim is a cloud-based platform for accelerated modeling and simulation. Unlike tools like Dymola, it integrates with a large open source community, the Julia programming language and the SciML ecosystem, to enhance its environment with offerings like easy parallelism, automated generation of ML surrogate models, and much more. In &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=lNbU5jNp67s&quot;&gt;a recent talk at JuliaCon 2021&lt;&#x2F;a&gt; I highlight this community integration as one of its core aspects that gives JuliaSim a competitive advantage in terms of features and performance, since it allows us to contribute to and benefit from the work of many scientists and engineers from across the world.&lt;&#x2F;p&gt;
&lt;p&gt;While JuliaSim has acausal modeling as one of its core features, unlike Modelica-based tools that is just one of its domains. Accelerated simulation of PDEs with neural networks, integrating stochastic simulation into workflows, specific simulation environments for pharmacology and circuit modeling, and much more are all part of the JuliaSim product. We see the future as a place where composability will be necessary to achieve the next level of simulations.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;can-it-integrate-with-the-fmi-will-we-be-able-to-use-models-written-in-e-g-modelica-inside-juliasim&quot;&gt;Can it integrate with the FMI? Will we be able to use models written in, e.g. Modelica, inside JuliaSim?&lt;&#x2F;h4&gt;
&lt;p&gt;Yes, JuliaSim at its release will offer features for integrating with the FMI standard, allowing for FMI imports and FMI exports. This will allow for example the ability to build surrogates of models from Modelica or Simulink platforms, and allow for generating binaries that can integrate back into these platforms.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;a-key-aspect-of-modelica-is-its-standard-library-which-includes-many-of-the-most-common-components-for-modeling-will-there-be-a-similar-thing-in-juliasim&quot;&gt;A key aspect of Modelica is its standard library, which includes many of the most common components for modeling. Will there be a similar thing in JuliaSim?&lt;&#x2F;h4&gt;
&lt;p&gt;With JuliaSim we are building a standard library which includes similar domains to the Modelica Standard Library, but also includes many other domains related to the customers we have been working with. For example, with JuliaSim one will be able to easily search a database of hundreds of physiological and systems biological models for accelerating workflows in biomedical simulation and drug development. We plan to continually improve this model library and mold it to the needs of our customers.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-are-surrogate-models-what-makes-them-important-especially-beyond-academic-applications&quot;&gt;What are surrogate models? What makes them important, especially beyond academic applications?&lt;&#x2F;h4&gt;
&lt;p&gt;Surrogate models are an amortization of compute cost to improve simulation workflows. It gives you a way to say “do 100 simulations now, and all of my future simulations are 100x faster”. When you mix this with cloud resources you can get a major workflow update: pay for a bit of cloud compute to spawn a bunch of simulations in parallel, but now every time you click the simulate button you do not have to wait 30 minutes to check the result.&lt;&#x2F;p&gt;
&lt;p&gt;When I was in graduate school I noticed that there is a very nonlinear effect of code speed on productivity which I captured in a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.stochasticlifestyle.com&#x2F;the-nonlinear-effect-of-code-speed-on-productivity&quot;&gt;blog post&lt;&#x2F;a&gt;. If you have to wait 30 minutes for a result, that means that instead you’ll start it before lunch or before a 1 hour meeting, so the true “time to see simulation results” gets amplified further. 2 hour simulations are something you will start in the morning and check at night. Thus a surrogate changing a long simulation to something that you can analyze in real-time is invaluable to decreasing labor costs because of how simulation time effects the day-to-day life of an engineer.&lt;&#x2F;p&gt;
&lt;p&gt;While in an academic sense we focus on issues like “training the surrogate costs 100 simulations, but we needed 10,000 simulations for to optimize the building design and thus we saved in the end”, I do not think this calculus is really the major change that surrogates will bring. Even if it takes 100 simulations to train a surrogate that you use 10 times, if you integrate this will cloud compute to do those all in parallel, then to the user you only have to sit through what is effectively 2 simulations. If that’s a two hour simulation time, you’ve now changed a workflow that takes a full day to something that you set to train in the morning and then after lunch you can interactively fiddle with parameters until your controls are correct. And then any time you revisit in the future, it’s ready to be fiddled with again. When you view surrogates in this light, I think you can see why we believe this will be a gamechanger for the everyday engineer.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;one-of-the-main-innovations-brought-by-juliasim-is-the-generation-of-fast-and-accurate-surrogate-models-that-can-speedup-simulations-as-much-as-500x-even-in-the-presence-of-stiff-models-how-is-this-achieved-what-s-a-ctesn&quot;&gt;One of the main innovations brought by JuliaSim is the generation of fast and accurate surrogate models that can speedup simulations as much as 500x, even in the presence of stiff models. How is this achieved? What’s a CTESN?&lt;&#x2F;h4&gt;
&lt;p&gt;A continuous-time echo state network (CTESN) is an implicitly trained machine learning framework for capturing the dynamics of stiff models. These are models with phase transitions, fast transient behavior, and are well-known to be numerically difficult. Across many domains we have shown the CTESN training procedure to be robust due to how it incorporates implicit features of stable differential equation solvers. All that we need to generate it is a chunk of simulations done beforehand, and what results is this really fast object that will predict the simulation behavior at new parameters.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;how-easy-is-it-to-compose-surrogate-models-with-normal-ones-in-juliasim-what-are-the-advantages-of-this-approach&quot;&gt;How easy is it to compose surrogate models with normal ones in JuliaSim? What are the advantages of this approach?&lt;&#x2F;h4&gt;
&lt;p&gt;The CTESN represents the surrogate of a differential equation model as a differential equation model. Because of this representation, it’s not different from the other physical components. As long as you train it to cover the right states and observables, it will slot right into where you had the larger model before.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;paramount-to-surrogatization-is-the-ability-to-check-the-accuracy-of-the-surrogate-model-and-its-performance-against-the-original-one-how-does-juliasim-tackle-this-are-these-metrics-appropriately-exposed-to-the-user&quot;&gt;Paramount to surrogatization is the ability to check the accuracy of the surrogate model and its performance against the original one. How does JuliaSim tackle this? Are these metrics appropriately exposed to the user?&lt;&#x2F;h4&gt;
&lt;p&gt;JuliaSim generates diagnostics of the surrogate training process to signal to the user important features like the projected maximum error over the timeseries over the user-defined parameter space. A lot of this is done through quasi-random sampling right now, though we are investigating more complex techniques to more quickly achieve good estimates.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;does-juliasim-run-on-top-of-juliahub-or-are-they-separate-things-is-the-pricing-model-expected-to-be-the-same&quot;&gt;Does JuliaSim run on top of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;juliahub.com&#x2F;lp&#x2F;&quot;&gt;JuliaHub&lt;&#x2F;a&gt; or are they separate things? Is the pricing model expected to be the same?&lt;&#x2F;h4&gt;
&lt;p&gt;JuliaSim is JuliaHub-based platform. JuliaSim users receive a subscription to a set of proprietary packages, such as the standard library and the surrogatization tools, which grants access to their use on JuliaHub. The pricing model of JuliaSim is simply the subscription and pay-for-compute, so users only pay for what they use but have access to the full suite.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;will-there-be-a-gui-for-modeling-or-will-we-mostly-have-to-write-all-the-julia-code-explicitly&quot;&gt;Will there be a GUI for modeling or will we mostly have to write all the Julia code explicitly?&lt;&#x2F;h4&gt;
&lt;p&gt;There will be many GUIs! The first GUI that we are building is more pharmaceutical modeling focused given our early customer base and connections with Pumas-AI. This allows for quickly building chemical reaction network and systems pharmacology models, and representing models in a visual form for presentations and reporting. It also will serve as the basis for visual programming of compartmental models in pharmacokinetics. We also will have a GUI at launch which simplifies the FMU surrogatization process, allowing non-Julia users to quickly accelerate their FMUs by entering in parameter information and clicking “surrogatize”. We have other GUIs planned for the near future as well, such as GUIs for block diagrams and acausal modeling, along with 3D visualization tools.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;juliasim-is-launching-pretty-soon-what-can-we-expect-from-this-first-version-what-features-are-next&quot;&gt;JuliaSim is launching pretty soon; what can we expect from this first version? What features are next?&lt;&#x2F;h4&gt;
&lt;p&gt;JuliaSim’s first beta will be launching fairly soon. I wouldn’t call it the first version quite yet, though the beta will already be usable as we have been working with a group of customers to showcase the performance advantage for their specific applications. The first release will be a mix of GUIs, cloud parallel surrogatization, and standard libraries. And for the future we are aiming for a lot more. The full vision of JuliaSim is expressed in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=lNbU5jNp67s&quot;&gt;the JuliaCon 2021 video&lt;&#x2F;a&gt; so refer to that for more details.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>BEAM all the things! ClojErl, an implementation of Clojure on the Erlang Virtual Machine</title>
          <pubDate>Thu, 15 Jul 2021 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/clojerl-an-implementation-of-the-clojure-language-that-runs-on-the-beam/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/clojerl-an-implementation-of-the-clojure-language-that-runs-on-the-beam/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/clojerl-an-implementation-of-the-clojure-language-that-runs-on-the-beam/">&lt;h4 id=&quot;an-interview-with-its-creator-juan-facorro&quot;&gt;&lt;strong&gt;An interview with its creator, Juan Facorro.&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Our blog has had a long standing interest in novel uses of the BEAM, or Erlang virtual machine, as shown by the many articles we have published on that topic: we talked to Eric Merritt about &lt;a href=&quot;&#x2F;eric-merritt-erlang-and-distributed-systems-expert-gives-his-views-on-beam-languages-hindley&#x2F;&quot;&gt;languages that run on BEAM&lt;&#x2F;a&gt; from a high-level overview, and went deep on &lt;a href=&quot;&#x2F;an-interview-with-the-creator-of-gleam-an-ml-like-language-for-the-erlang-vm-with-a-compiler&#x2F;&quot;&gt;Gleam&lt;&#x2F;a&gt; (an ML-like language for the Erlang VM with a compiler written in Rust), &lt;a href=&quot;&#x2F;d-day-invasion-with-mlfe-ml-landing-in-the-erlang-world&#x2F;&quot;&gt;MLFE&lt;&#x2F;a&gt; (which is short for ML-Flavored Erlang), &lt;a href=&quot;&#x2F;efene-an-erlang-vm-language-that-embraces-the-python-zen&#x2F;&quot;&gt;Efene&lt;&#x2F;a&gt; (an alternative syntax for Erlang), &lt;a href=&quot;&#x2F;gaming-with-elixir-discovering-new-lands-in-the-beam-realm&#x2F;&quot;&gt;using Elixir for videogame backends&lt;&#x2F;a&gt;, and &lt;a href=&quot;&#x2F;lasp-a-little-further-down-the-erlang-rabbithole&#x2F;&quot;&gt;Lasp&lt;&#x2F;a&gt; (“a suite of libraries aimed at providing a comprehensive programming system for planetary scale Elixir and Erlang applications”).&lt;&#x2F;p&gt;
&lt;p&gt;We also published a guide to learn &lt;a href=&quot;&#x2F;how-to-earn-your-clojure-white-belt&#x2F;&quot;&gt;Clojure&lt;&#x2F;a&gt; and an &lt;a href=&quot;&#x2F;a-pythonist-finds-a-new-home-at-clojure-land&#x2F;&quot;&gt;interview&lt;&#x2F;a&gt; that might persuade you to get into it if you haven’t already.&lt;&#x2F;p&gt;
&lt;p&gt;So our readers will understand it was inevitable for us to be interested in Juan Facorro’s project, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;clojerl&#x2F;clojerl&quot;&gt;ClojErl&lt;&#x2F;a&gt;. And of course, we interviewed him about it. We hope you enjoy it as much as we did.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h4 id=&quot;tell-us-a-little-about-clojerl-what-is-it-how-did-it-come-about&quot;&gt;&lt;strong&gt;Tell us a little about ClojErl, what is it? How did it come about?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;ClojErl is an implementation of the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;clojure.org&#x2F;&quot;&gt;Clojure&lt;&#x2F;a&gt; language that runs on the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;BEAM_(Erlang_virtual_machine)&quot;&gt;BEAM&lt;&#x2F;a&gt; (the Erlang Virtual Machine).&lt;&#x2F;p&gt;
&lt;p&gt;The project started as a learning and exploratory exercise on language implementation. The idea was born out of the combination of my desire to use Clojure at work, and me starting a new job at &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;inaka.github.io&#x2F;&quot;&gt;Inaka&lt;&#x2F;a&gt; where I learned to use Erlang (and the BEAM) to build systems.&lt;&#x2F;p&gt;
&lt;p&gt;I found that the concurrency model of the BEAM made sense to me, because it provided a framework and some guarantees that made it simple for me to think about concurrency. This has not been the case for me with other concurrency models.&lt;&#x2F;p&gt;
&lt;p&gt;The BEAM was built to solve a practical problem (i.e. high availability communication switches) and solving for concurrency was a big part of the solution, which also included immutable data structures. These two concepts, concurrency and immutability, are also at the core of Clojure’s design principles, so it seemed like a good idea to try to bring this language to the BEAM.&lt;&#x2F;p&gt;
&lt;p&gt;I’m not sure if I thought about it at the time, but the abstractions on which Clojure is built make using the language a pleasure. The example that I always use is the fact that you can use the &lt;strong&gt;count&lt;&#x2F;strong&gt; core function with almost any data structure (it only needs to implement the &lt;strong&gt;ICounted&lt;&#x2F;strong&gt; protocol). Even though it is possible to define a function like this in Erlang, I think the resulting code would not be idiomatic Erlang and it would be hard both to maintain and to extend to new types. This is not the case with Clojure.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-advantages-does-the-actor-model-bring-over-clojure-s-concurrency-model&quot;&gt;&lt;strong&gt;What advantages does the actor model bring over clojure’s concurrency model?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;I don’t think there are absolute advantages of one model over the other.&lt;&#x2F;p&gt;
&lt;p&gt;Because of the way systems are built on the BEAM and the tools it provides (i.e. lightweight processes, monitors and links), it is very suitable for building resilient systems that (when designed right) can recover from failure. This can arguably be done with any language and platform (e.g. Akka on the JVM), but I think it is simpler and easier to do when using the BEAM.&lt;&#x2F;p&gt;
&lt;p&gt;Other things are harder and end up being more complex when using Erlang, but I have wondered if this is something that is more related to the size of the community and the problems it is solving, than the language itself. The amount of Elixir libraries that have been written to do almost anything would suggest that this is very likely the case.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;when-would-clojerl-be-a-better-choice-than-regular-jvm-clojure&quot;&gt;&lt;strong&gt;When would ClojErl be a better choice than regular JVM clojure?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;I would say that whenever you need to build a system that is resilient, degrades gracefully and can recover from failures, and you don’t want to spend time on building the mechanism to achieve this from scratch. Using ClojErl will provide a battle-tested platform where all these things are already included in the VM’s design and how systems are built on it.&lt;&#x2F;p&gt;
&lt;p&gt;This assumes that you don’t need a very purpose-specific library that exists only in Java, or a Clojure library that is a lot of work to port from Clojure(Script) into ClojErl.&lt;&#x2F;p&gt;
&lt;p&gt;It also assumes that there is a library (either in Erlang or maybe other BEAM language) for every one of your needs, which unfortunately is sometimes not the case.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;how-much-impact-does-losing-java-interop-have-on-the-language-in-everyday-use&quot;&gt;&lt;strong&gt;How much impact does losing Java interop have on the language in everyday use?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;There is no impact as far as I can tell, although I’m biased :).&lt;&#x2F;p&gt;
&lt;p&gt;Anything that would necessitate Java interop is either replaced with Erlang interop or an implementation of the set of protocols through which Clojure interacts with the platform (e.g. &lt;strong&gt;IWriter&lt;&#x2F;strong&gt; and &lt;strong&gt;IReader&lt;&#x2F;strong&gt; for I&#x2F;O).&lt;&#x2F;p&gt;
&lt;h4 id=&quot;there-are-certain-clojure-features-that-are-unsupported-why-is-that&quot;&gt;&lt;strong&gt;There are certain Clojure features that are unsupported. Why is that?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Clojure JVM is implemented on a platform that allows mutability, which is not the case on the BEAM.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;clojure.org&#x2F;reference&#x2F;transients&quot;&gt;Transient data structures&lt;&#x2F;a&gt; for example, rely on the fact that parts of the underlying representation can be updated in-place. The whole point of their existence is to allow for faster operations without the cost of creating new instances after each modification. This cannot be achieved on the BEAM if we want to use the native immutable data structures.&lt;&#x2F;p&gt;
&lt;p&gt;I have not explored the path of implementing a whole set of data structures through &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;erlang.org&#x2F;doc&#x2F;tutorial&#x2F;nif.html&quot;&gt;NIFs&lt;&#x2F;a&gt; that would maybe make this possible. I’m not convinced this is a good idea though, for a number of reasons. The first one is that it would be a lot of work and we would end up with an implementation that needs to be battle-tested before it can be relied upon. The second is that the cost of calling a NIF is not zero and the result might not even provide significant performance gains. And the third is that it would not be possible to use any of the built-in Erlang functions from the standard library or any of the optimizations for them added to the BEAM.&lt;&#x2F;p&gt;
&lt;p&gt;Another feature that is not implemented for Clojure on the BEAM is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;clojure.org&#x2F;reference&#x2F;refs&quot;&gt;Refs and Transactions&lt;&#x2F;a&gt;. This feature is heavily dependent on how the JVM works and it is also not something that is very widely used (as far as I know) in the wild.&lt;&#x2F;p&gt;
&lt;p&gt;ClojErl relies only on the numeric types provided by the platform. This means that things such as ratios, big decimals, and flags about unchecked math are not available. The BEAM is not designed to provide good performance around numerical operations, so if that is your use case you are better off using another set of tools for that purpose.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;how-good-is-the-interoperability-with-erlang-what-about-elixir&quot;&gt;&lt;strong&gt;How good is the interoperability with Erlang? What about Elixir?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;One of the design principles for ClojErl was to make interoperability with the platform as seamless as possible.&lt;&#x2F;p&gt;
&lt;p&gt;A function call to an Erlang function is equivalent to any other Clojure function call: &lt;strong&gt;(module&#x2F;function arg1 arg2 … argN)&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Data structures are not equivalent, Clojure’s are implemented on top of Erlang’s. All Clojure core functions related to data structures (e.g. count, first, map, etc.) work for all of Erlang’s though, since the necessary protocols are implemented for them to work. It is possible to write expressions for literal Erlang data structures by using the &lt;strong&gt;#erl&lt;&#x2F;strong&gt; reader macro before a Clojure literal (e.g. &lt;strong&gt;#erl{:a 1}&lt;&#x2F;strong&gt; would be compiled to a literal Erlang map).&lt;&#x2F;p&gt;
&lt;p&gt;As mentioned before ClojErl currently provides only the numerical data types available on the BEAM: integer (unbound) and float (64 bits).&lt;&#x2F;p&gt;
&lt;p&gt;ClojErl strings are Erlang UTF-8 binaries. It is possible to write literal Erlang strings (i.e. lists of integers) by using the #erl reader macro.&lt;&#x2F;p&gt;
&lt;p&gt;Pattern matching is also available in ClojErl when using any of the special forms where bindings are created (i.e. &lt;strong&gt;fn&lt;&#x2F;strong&gt;* , &lt;strong&gt;let&lt;&#x2F;strong&gt;* , &lt;strong&gt;loop&lt;&#x2F;strong&gt;* and &lt;strong&gt;case&lt;&#x2F;strong&gt;*).&lt;&#x2F;p&gt;
&lt;p&gt;A ClojErl anonymous function can be used as an argument to any of the Erlang BIFs that expect a function, as long as the ClojErl function doesn’t use variadic arity or multiple arities. These two features are specific to Clojure, which means that Erlang code wouldn’t know how to correctly call the function in that case.&lt;&#x2F;p&gt;
&lt;p&gt;The story for Elixir is similar to Erlang’s (or any other language on the BEAM). Any function from an Elixir module can be called from ClojErl. Elixir is a little particular in that all its modules have an implicit “&lt;strong&gt;Elixir.&lt;&#x2F;strong&gt; ” prefix added by the compiler to them. There have been some people recently trying this out with some success (see &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;marcio_lopes&#x2F;status&#x2F;1400256642478903299&quot;&gt;here&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-was-is-the-most-challenging-part-of-the-project&quot;&gt;&lt;strong&gt;What was&#x2F;is the most challenging part of the project?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;The most challenging part was and still is finding ways to reconcile what the BEAM offers with the semantics of the Clojure language. Sometimes the conclusion is that we can’t support a feature (e.g. transient collections), other times we need to provide something similar but a little more limited than the original (e.g. vars), and yet other times we add something completely new to the language because we want to have interoperability with platform features (e.g. pattern matching).&lt;&#x2F;p&gt;
&lt;p&gt;Another big challenge has been performance. Some features, when implemented on the JVM, do not translate very well to how the BEAM works (e.g. transducers) which results in a much worse performance (i.e. an order of magnitude slower) than what the JVM offers. The release of OTP 24 saw the inclusion of a JIT compiler, preliminary micro-benchmarking using this release showed a lot of improvement in the run time performance of some expressions. There is still quite a lot of work to be done performance wise (both with time and memory usage) on ClojErl.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;are-there-currently-any-interesting-use-cases-for-clojerl&quot;&gt;&lt;strong&gt;Are there currently any interesting use cases for ClojErl?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;If we talk about production environment use cases, the short answer is no. The project is still in beta and there hasn’t been (that I know of) any company or individual that has used ClojErl in a production environment.&lt;&#x2F;p&gt;
&lt;p&gt;But there are some use cases that I have found interesting and fun.&lt;&#x2F;p&gt;
&lt;p&gt;One of them is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;clojerl&#x2F;doodler&quot;&gt;doodler&lt;&#x2F;a&gt; which is an implementation of a canvas for creating animations inspired in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;quil.info&#x2F;?example=fireworks&quot;&gt;quil&lt;&#x2F;a&gt; Clojure(Script) project.&lt;&#x2F;p&gt;
&lt;p&gt;Another one is the application behind &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;try.clojerl.online&#x2F;&quot;&gt;try.clojerl.online&lt;&#x2F;a&gt; which is built in ClojErl. I think I spent more time on the JS client-side console than on the code necessary to have a remote running ClojErl REPL.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;is-the-project-open-for-contributions-if-so-how-should-people-get-started&quot;&gt;&lt;strong&gt;Is the project open for contributions? If so, how should people get started?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Yes, absolutely, 100%!&lt;&#x2F;p&gt;
&lt;p&gt;There are open issues to which I haven’t had time to dedicate myself and anyone that is interested in working on them and any other features or improvements, can reach out through the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;clojerl&#x2F;clojerl&quot;&gt;GitHub repository&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;jfacorro&quot;&gt;Twitter&lt;&#x2F;a&gt; ot the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;erlanger.slack.com&#x2F;archives&#x2F;C7KBUEAMC&quot;&gt;#ClojErl Slack channel&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The fastest way to have a working development environment is by using &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gitpod.io&#x2F;&quot;&gt;gitpod.io&lt;&#x2F;a&gt;, which provides an online IDE for any public project hosted in the major code repositories (e.g. GitHub). Firing up a new environment is as simple as following &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gitpod.io&#x2F;#github.com&#x2F;clojerl&#x2F;clojerl&quot;&gt;this link&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;How to navigate code is a little bit more complicated because the documentation around this is lacking. There is some documentation in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.clojerl.org&#x2F;&quot;&gt;ClojErl.org&lt;&#x2F;a&gt; page and there are also &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;hexdocs.pm&#x2F;clojerl&#x2F;clj_compiler.html&quot;&gt;API docs for the Erlang modules in hex.pm&lt;&#x2F;a&gt;. But they provide a limited view and there are some important things that are not included there, therefore until there is more documentation for developing ClojErl I am available for people to reach out with their questions.&lt;&#x2F;p&gt;
&lt;p&gt;Other areas that need some love are tools for developing. The &lt;strong&gt;rebar3_ClojErl&lt;&#x2F;strong&gt; plugin currently provides pretty good support for compiling, testing, building applications and script; and starting up a REPL. The area that is not so great is the editor support for ClojErl. Syntax highlighting is available and simple to get, but it would be an amazing developer experience if &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;erlang-ls&#x2F;erlang_ls&quot;&gt;&lt;strong&gt;Erlang-ls&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt; could also parse ClojErl files and help navigate the code both in Erlang and ClojErl.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;can-i-use-any-library-written-in-erlang-directly-in-clojerl&quot;&gt;Can I use any library written in Erlang directly in ClojErl?&lt;&#x2F;h4&gt;
&lt;p&gt;Yes! ClojErl is “just” an Erlang library, which means you can combine it with any other Erlang library and&#x2F;or application by using &lt;strong&gt;rebar3&lt;&#x2F;strong&gt; and the dedicated &lt;strong&gt;rebar3_ClojErl&lt;&#x2F;strong&gt; plugin.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>We wrote a book! “Data Science in Julia for Hackers” beta is now live and free to read</title>
          <pubDate>Fri, 19 Mar 2021 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/how-we-wrote-a-hands-on-bayesian-data-science-book-in-6-months/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/how-we-wrote-a-hands-on-bayesian-data-science-book-in-6-months/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/how-we-wrote-a-hands-on-bayesian-data-science-book-in-6-months/">&lt;h4 id=&quot;learn-about-data-science-and-julia-while-solving-real-life-problems&quot;&gt;Learn about data science and Julia while solving real-life problems&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;strong&gt;Read our book “Data Science in Julia for Hackers” at:&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;datasciencejuliahackers.com&#x2F;&quot;&gt;&lt;strong&gt;https:&#x2F;&#x2F;datasciencejuliahackers.com&#x2F;&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-t93INVDo-XNSm7iObeXODQ.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;We put together this post to share the release of our first book on data science methods, which focuses on solving real-life problems. This release is actually a beta version, as we are looking to receive constructive criticism and feedback, in order to improve the book until the first revised version is ready.&lt;&#x2F;p&gt;
&lt;p&gt;We come from different backgrounds. Federico Carrone is a developer with over 15 years of experience and founder of a startup that is running since 2014, who is currently studying towards a degree in Mathematics. Herman Obst is an Industrial Engineer who is just learning to program as is our Physicist, Mariano Nicolini. Martina Cantaro coordinated the writing process and our technical consultants, Manuel Puebla and Lucas Fernández Piana, are making sure our definitions are simple to understand yet accurate.&lt;&#x2F;p&gt;
&lt;p&gt;We do not come from academia, nor are we experts in statistics, which may make some people wonder whether we have enough authority to concern ourselves with such complex issues. But we have one thing in common: above all, we are doers. Collectively, we have experience in setting ourselves big goals and achieving them through, learning, hacking, tinkering and thinking. Data science is a toolkit that has enabled us to solve different real-life problems and we want to share what we have learned in the process.&lt;&#x2F;p&gt;
&lt;p&gt;Speaking of real-life problems, few disciplines have as much impact when it comes to solving them as data science. Currently, our society is constantly generating massive amounts of information encoding complex behaviors and relationships from a wide array of fields. And people are developing the tools to use that information to our benefit.&lt;&#x2F;p&gt;
&lt;p&gt;That was why we were so struck by the fact that almost all the books on data science and statistics had a very theoretical approach, focusing on understanding the mathematics of the algorithms and never talking about their applications to situations we might encounter in work or life in general.&lt;&#x2F;p&gt;
&lt;p&gt;Because of this (and because of our love for making and generating things) we decided to embark on the adventure of writing a book. A book whose first and foremost premise was to propose diverse and interesting problems, and solve them using the ingenuity and tools of data science. And theory does not play a minor role, not at all, but it is developed only to the extent that the resolution of the problem requires it. In this way, a real connection between theory and reality is achieved.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-we-want-you-to-learn&quot;&gt;What we want you to learn&lt;&#x2F;h3&gt;
&lt;p&gt;One of the ideas we are most interested in conveying is that of taking action. Nowadays there is a dominant way of thinking, widespread in the academic world, which maintains that before being able to carry any meaningful work we must first acquire a broad theoretical knowledge of the subject. We think this can be counterproductive, as it makes people afraid of taking risks and daring to immerse themselves in practice.&lt;&#x2F;p&gt;
&lt;p&gt;We decided to disprove this way of thinking by making a book about Bayesian statistics, machine learning and artificial intelligence, without (at first) knowing much about any of these fields.&lt;&#x2F;p&gt;
&lt;p&gt;That was our goal. We figured out the rest as we went along.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-we-learned&quot;&gt;What we learned&lt;&#x2F;h3&gt;
&lt;p&gt;With our goal always in mind, we started searching and solving a wide variety of problems that could be interesting to tackle using Bayesian inference, which at the beginning was the only topic we planned to talk about. That way we got used to the Bayesian mindset and the different probabilistic programming tools in Julia, our language of choice.&lt;&#x2F;p&gt;
&lt;p&gt;But as we profressed, we changed the focus of the book from something like “Bayesian methods from a practical perspective” to include data science topics in general, from time series prediction to the powerful Scientific Machine Learning ecosystem. Finally, although we wanted to focus on these -not so widespread- methods, we thought it pertinent to add a section on more classical methods, such as deep learning and machine learning — the latter currently in production.&lt;&#x2F;p&gt;
&lt;p&gt;As the dificulty of the scenarios we created began to increase (we often found that a problem was way more complicated than we initially thought), it became clear that we had to incorporate a little more solid knowledge about Bayesianism. That’s where reading &lt;em&gt;Bayesian Methods for Hacker&lt;&#x2F;em&gt; s and &lt;em&gt;Statistical Rethinking&lt;&#x2F;em&gt; gave us a much better understanding and tools to deal with the complexity.&lt;&#x2F;p&gt;
&lt;p&gt;Our writing process also got better over time. Although we already had some experience writing blog posts, writing a book was a brand new challenge for everyone, especially since we are not native English speakers.&lt;&#x2F;p&gt;
&lt;p&gt;At the beginning, our explanations of models and the theory behind them were somewhat lacking. Several pages were discarded, and the rest were re-written several times until we found them passable. It was a process that involved some deal of frustration, but as we iterated over them, the quality of the pages increased substantially. Finally, we found a comfort zone in terms of diagraming, coding and writing the chapters.&lt;&#x2F;p&gt;
&lt;p&gt;The road was winding and some keys to keep the progress up were to not let ourselves be overwhelmed by the enormous task, to divide the work, to go chapter by chapter and, above all, to always keep moving forward. One strategy we used was to complete the writing of the chapters until we felt they were 80% complete. That way, the progress curve always kept a good positive slope, since (by Pareto law) that last 20% would take 80% of the time to complete. Only when we had completed 80% of the book, we went back chapter by chapter to finish polishing it.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;where-you-can-read-it&quot;&gt;Where you can read it&lt;&#x2F;h3&gt;
&lt;p&gt;And that’s it! As of now, the book is up for everyone to read at:&lt;&#x2F;p&gt;
&lt;h4 id=&quot;https-datasciencejuliahackers-com&quot;&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;datasciencejuliahackers.com&#x2F;&quot;&gt;https:&#x2F;&#x2F;datasciencejuliahackers.com&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;We hope it will be useful to as many people as possible and we hope to receive lots of feedback and constructive criticism, so we can keep improving edition after edition.&lt;&#x2F;p&gt;
&lt;p&gt;Enjoy!&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Modeling complexity with Symbolics.jl and ModelingToolkit.jl</title>
          <pubDate>Thu, 18 Mar 2021 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/modeling-complexity-with-symbolics-jl-and-modelingtoolkit-jl/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/modeling-complexity-with-symbolics-jl-and-modelingtoolkit-jl/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/modeling-complexity-with-symbolics-jl-and-modelingtoolkit-jl/">&lt;h4 id=&quot;an-interview-with-chris-rackauckas&quot;&gt;An interview with Chris Rackauckas&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-sHzrVkhNvHxdiJ2IBmfVPA.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;As we often mentioned on Not a Monad Tutorial, the world is complex, and we increasingly understand where our tools fall short when trying to model this complexity.&lt;&#x2F;p&gt;
&lt;p&gt;We’ve previously interviewed Chris Rackauckas on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;notamonadtutorial.com&#x2F;scientific-machine-learning-with-julia-the-sciml-ecosystem-b22802951c8a&quot;&gt;SciML&lt;&#x2F;a&gt;; this time he joins us to answer questions regarding new developments in the area of symbolic computation with Julia, its relation to numerical computing, causal vs acausal approaches, how these matters are represented in Symbolics.jl and ModelingToolkit.jl, and how these packages relate to the existing simulation tooling landscape.&lt;&#x2F;p&gt;
&lt;p&gt;These packages compose easily and thus allow modelling larger, more complex systems by reusing parts, as well as helping community efforts. Having these interoperable packages is key to building a modern simulation software stack which can address the aforementioned needs of complex modelling.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h4 id=&quot;what-is-symbolics-jl-what-are-the-motivations-behind-the-creation-of-the-system&quot;&gt;What is Symbolics.jl? What are the motivations behind the creation of the system?&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;JuliaSymbolics&#x2F;Symbolics.jl&quot;&gt;Symbolics.jl&lt;&#x2F;a&gt; is a Computer Algebra System (CAS) in the Julia programming language developed by the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;juliasymbolics.org&#x2F;&quot;&gt;JuliaSymbolics Organization&lt;&#x2F;a&gt;. Think symbolic computation: write down equations and ask the computer to come up with symbolic solutions. It’s a modern CAS, meaning it’s built on a widely used modern programming language (Julia), making use of modern tooling like pervasive parallelism, new algorithms like E-Graphs, integration with machine learning, and more.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-is-modelingtoolkit-jl-what-are-the-needs-it-addresses&quot;&gt;What is ModelingToolkit.jl? What are the needs it addresses?&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;SciML&#x2F;ModelingToolkit.jl&quot;&gt;ModelingToolkit.jl&lt;&#x2F;a&gt; is an equation-based acausal modeling system. It’s similar to systems like Modelica which allow for composing models to quickly generate realistic simulations. This lets you take pre-built models created by other scientists and build complete systems. For example, you can take a high fidelity model of an air conditioning, then make a model of a building, and stick the air conditioning into the building and ask what kind of energy efficiency you get. Then change the building to start designing what’s most efficient.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;how-does-acausal-modeling-relate-to-tools-like-simulink&quot;&gt;How does acausal modeling relate to tools like Simulink?&lt;&#x2F;h4&gt;
&lt;p&gt;Simulink is a causal modeling tool. You have to know “what causes what” in order to develop the simulation. This can be difficult in our complex world: the heat of the building is read by the thermostat which turns the AC on which then changes the heat of the building. Feedbacks and “algebraic loops” cause issues in causal modeling systems: users have to break the loops or change the model. For this reason &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;abs&#x2F;1909.00484&quot;&gt;experts consider causal modeling as not suitable for complex simulations&lt;&#x2F;a&gt; as they do not compose well. This is the reason acausal tools like Modelica have seen a lot of adoption. Even MATLAB has an acausal tool now, SimScape. Given the advancements in these techniques, I see the next generation of engineers all using acausal tools, with ModelingToolkit.jl being one of the only fully-featured free and open-source acausal systems.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;why-is-symbolic-computation-needed-at-all-what-are-the-advantages-compared-to-numerical-computation-when-is-one-preferred-to-the-other&quot;&gt;Why is symbolic computation needed at all? What are the advantages compared to numerical computation? When is one preferred to the other?&lt;&#x2F;h4&gt;
&lt;p&gt;Are you sure you know enough mathematics to have written the mathematical model in the most numerically-stable form? Even if you know all of the tricks that you’re supposed to do, do you want to do it all by hand? I see the main use of symbolic computation in symbolic-numerics, i.e. using symbolic techniques to improve the models which are then used in numerical methods. For example, in a recent blog post titled &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.stochasticlifestyle.com&#x2F;generalizing-automatic-differentiation-to-automatic-sparsity-uncertainty-stability-and-parallelism&#x2F;&quot;&gt;Generalizing Automatic Differentiation to Automatic Sparsity, Uncertainty, Stability, and Parallelism&lt;&#x2F;a&gt;, I describe how a two-dimensional pendulum simulation without the small angle approximation requires a differential-algebraic equation. The intuitive model of “position moves by velocity, velocity moves by acceleration, and length is constant” is actually an unstable description of the full pendulum. You have to differentiate the “length is constant” equation twice, then substitute other relationships, and then you arrive at an “index-1” DAE which is easier to numerically solve. Even if you know enough of these details to do it, you don’t want to handle that! Symbolic-numeric computation is how we will get to a future where that is all automated.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;wolfram-mathematica-and-sympy-in-python-are-some-of-the-most-popular-choices-when-dealing-with-symbolic-manipulation-nowadays-what-are-the-advantages-symbolics-jl-offers-in-comparison-to-them&quot;&gt;Wolfram Mathematica and SymPy in Python are some of the most popular choices when dealing with symbolic manipulation nowadays. What are the advantages Symbolics.jl offers in comparison to them?&lt;&#x2F;h4&gt;
&lt;p&gt;Symbolics.jl is being built from the ground up for speed, being built from the ground up with parallelism, and last but not least, it’s being built up from a community of tools. There is so much good stuff out there that I think it would be unreasonable to silo one’s organization off and do everything from scratch. Julia has many great initiatives like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.computeralgebra.de&#x2F;sfb&#x2F;&quot;&gt;OSCAR.jl&lt;&#x2F;a&gt; which are building fast implementations of the mathematical guts. We are using the fact that Julia is a high performance language to both develop high level interfaces and ensure that all of these tools can be used with minimal overhead, mental and computational. So while you might know nothing about Galois fields, there might be a fancy algorithm underneath the hood when you call factorize(x² + 2x + 1) that does it efficiently and scales to large systems.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;how-is-modelingtoolkit-jl-related-to-symbolics-jl-what-role-does-julia-s-composability-play-in-the-relationship-between-the-two-packages&quot;&gt;How is ModelingToolkit.jl related to Symbolics.jl? What role does Julia’s composability play in the relationship between the two packages?&lt;&#x2F;h4&gt;
&lt;p&gt;Acausal modeling requires symbolic transformations of equations. In that pendulum example, “differentiate the equation twice and substitute”, what kind of tool provides features like differentiation and high performance equation rewriting (i.e. substitution)? A CAS! So ModelingToolkit.jl let’s someone say “this is an ODE”, where it’s equations are described by Symbolics.jl expressions. There are then functions that do things like “transform this to index-1 form” and “analytically discover which equations are redundant and delete them”, and those transformations are written using the tools of Symbolics.jl. This means that as the CAS grows more powerful, so will ModelingToolkit.jl and its environment.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;how-does-modelingtoolkit-jl-compare-to-other-modeling-frameworks-such-as-modelica-and-simulink-how-easily-would-a-person-with-some-background-on-these-frameworks-adapt-to-modelingtoolkit-jl&quot;&gt;How does ModelingToolkit.jl compare to other modeling frameworks such as Modelica and Simulink? How easily would a person with some background on these frameworks adapt to ModelingToolkit.jl?&lt;&#x2F;h4&gt;
&lt;p&gt;ModelingToolkit.jl’s focus at this point has mainly been on flexibility and speed. In terms of flexibility, ModelingToolkit.jl is the only one which has a hackable compiler that allows composing transformations. All of the symbolic enhancements that are allowed in the Modelica and Simulink compilers are those that are built-in. While it sounds like that’s all that most users need, what that really does is stifle innovation. There are people working in these fields that need a common framework to build off of. Many of these researchers are now in Julia. So for example, could we add an analysis pass that automatically tells you whether you can distinguish between parameters with the data you have? Yes, anyone could extend the ModelingToolkit.jl system with a pass that does that, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;alexeyovchinnikov&#x2F;SIAN-Julia&quot;&gt;and we’re already talking with authors of Julia libraries about doing this&lt;&#x2F;a&gt;. There is so much going on in this space that it’s hard to express, but expect tons of unique transformations to be allowed on your models. “Make a model that doesn’t solve in other systems solve here” is not just a dream.&lt;&#x2F;p&gt;
&lt;p&gt;And then there’s speed. We haven’t done complete and comprehensive benchmarking against all of the systems yet, but we have seen &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;abs&#x2F;2103.05244&quot;&gt;some good performance against some Modelica compilers&lt;&#x2F;a&gt;, indicating we’re doing really well. One NASA user of ModelingToolkit.jl said &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;tQpqsmwlfY0&quot;&gt;a 15 minute Simulink simulation took 50ms in ModelingToolkit.jl&lt;&#x2F;a&gt;. A user mentioned at the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;FMVOUvWNlLE&quot;&gt;AAS&#x2F;AIAA Space Flight Mechanics meeting that every case against a Fortran package with a MATLAB interface, they saw at least an order of magnitude acceleration by moving to ModelingToolkit.jl&lt;&#x2F;a&gt;. In a very early version of ModelingToolkit.jl, we did a demo with Pfizer where we &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;juliacomputing.com&#x2F;case-studies&#x2F;pfizer&#x2F;&quot;&gt;demonstrated a 175x acceleration over their original C-based simulations&lt;&#x2F;a&gt;. Part of all of this is just due to the solvers, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;benchmarks.sciml.ai&#x2F;html&#x2F;MultiLanguage&#x2F;wrapper_packages.html&quot;&gt;which benchmark really well in a cross-language way&lt;&#x2F;a&gt;. Another good chunk is due to the feature sets of the solvers, and ModelingToolkit.jl automatically enabling some of the best choices of combinations. This is explored a bit in a talk at JuliaCon 2020 titled &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=UNkXNZZ3hSw&quot;&gt;Auto-Optimization and Parallelism in DifferentialEquations.jl&lt;&#x2F;a&gt;, which was the video that announced the release of ModelingToolkit.jl as a new front end to the solvers for further improving speed.&lt;&#x2F;p&gt;
&lt;p&gt;That said, we have focused so far on the details. We want the biggest hardest models with the users who have the most demands. These other tools have put a lot more time into user interface, specifically graphical user interfaces (GUIs). Modelica and Simulink has a lot of tooling for drag-and-drop model building. Also, they have libraries of premade libraries. But, this will change very soon. Keep your eyes peeled for some announcements.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-are-the-main-challenges-to-solve-in-order-to-build-such-a-high-level-modeling-library&quot;&gt;What are the main challenges to solve in order to build such a high level modeling library?&lt;&#x2F;h4&gt;
&lt;p&gt;You want to make the modeling language be expressive enough so that every detail you can mathematically specialize on and optimize for is there, but you want to make it easy for users to actually use. Striking that balance is difficult. ModelingToolkit.jl has around 4 years in various prototype forms going through and breaking designs until we found one that could actually solve the problem to the level we hoped.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;how-is-julia-code-generated-from-symbolic-expressions&quot;&gt;How is Julia code generated from symbolic expressions?&lt;&#x2F;h4&gt;
&lt;p&gt;The symbolic expressions use the same exact pieces under different symantics. For example, square roots in the model are &lt;code&gt;sqrt&lt;&#x2F;code&gt; in Symbolics.jl and &lt;code&gt;sqrt&lt;&#x2F;code&gt; in Julia. This means all we have to do is take the symbolic expression and write it into a Julia function, and invoke the compiler. Invoking compilation on the fly as part of a symbolic language is an interesting challenge though, something that a tool like SymPy skips but which reduces speed by orders of magnitude. The specific details of this are pretty esoteric so I will spare you, but to make this all work we created a new hook into the Julia compiler called &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;SciML&#x2F;RuntimeGeneratedFunctions.jl&quot;&gt;RuntimeGeneratedFunctions&lt;&#x2F;a&gt; which allow for staged compilation that composes with garbage collection, making generated code safe.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-are-the-mechanisms-that-allow-easy-model-composition-with-modelingtoolkit-jl&quot;&gt;What are the mechanisms that allow easy model composition with ModelingToolkit.jl?&lt;&#x2F;h4&gt;
&lt;p&gt;It’s the acasual modeling. You can develop pieces in isolation and just declare relationships between the components. For example, build a model of a power generator, and a model of a computer chip. Now you want to connect these two completely different models? Physically, a wire would connect them and then Kirchoff’s laws would have to hold, i.e. the voltages would have to be equal at the connection points and the currents would sum to zero. So in ModelingToolkit.jl that’s what you’d do: you’d say “current from generator + current to chip = 0” and “voltage at generator = voltage at chip” and bingo you’re there. Now this might produce some redundant variables and equations, but it’s okay: the symbolic preprocessing system eliminates all of this and simplifies down to the most efficient problem to simulate. Then at the end, you can ask “give me the timeseries of the voltage at the chip” and it will give you it, regardless if it was actually in the simulation of not, because it has the information to reconstruct these values.&lt;&#x2F;p&gt;
&lt;p&gt;ModelingToolkit.jl goes one step further. There are &lt;code&gt;connect&lt;&#x2F;code&gt; statements which let you define a common behavior. For example, a &lt;code&gt;Pin&lt;&#x2F;code&gt; in an electrical circuit always has a voltage and a current, and those laws from above are how “connections” physically work. So at this higher level you can say “connect the pin of the generator to the pin of the circuit”, and it generates all of the physical relationships associated with that statement. There are many prebuilt systems which are coming very soon (likely to be completed before these responses are public!), so heat flow, enthalpy relationships, etc. are all simple &lt;code&gt;connect&lt;&#x2F;code&gt; statements. The connection mechanism is extendable too, so if you have a common meaning in say pharmacological models which differs, you can create a new variable type and make connections automatically enforce the laws you want. Connect the heart to the kidney means blood flow is conserved but oxygen is not. This makes it easy to specialize the systems to each of the specific scientific domains.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-are-the-advantages-of-symbolic-preprocessing-of-models&quot;&gt;What are the advantages of symbolic preprocessing of models?&lt;&#x2F;h4&gt;
&lt;p&gt;From the previous statement, note that simple modeling requires the ability to build things in isolation, and then just say “a=b”. Numerically simulating with “a=b” is rather difficult though, numerical methods really want to not solve equations exactly. But if the current at one side is 10^(-8) higher than the other, you lose conservation of current, and you can have the power of the system steadily rising until it spirals out of control and the simulation crashes. This is actually a very common behavior in causal modeling systems. But if you eliminate the variable “b” and replace it with “a” in every place where it shows up, and then if the user asks for “b” you give them “a”, now you’ve symbolically enforced equality and you will never have a numerical issue due to that effect. So not only does it make the set of equations you have to solve smaller (making the solving process faster), but it also makes the numerical solving a lot more stable and more likely to succeed.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;who-are-modelingtoolkit-jl-and-symbolics-jl-aimed-to-beyond-academia-do-you-consider-people-in-the-industry-might-find-them-useful&quot;&gt;Who are ModelingToolkit.jl and Symbolics.jl aimed to? Beyond academia, do you consider people in the industry might find them useful?&lt;&#x2F;h4&gt;
&lt;p&gt;Symbolics.jl is more academically focused. People doing symbolic computer algebra are everywhere, but I tend to see more in academia. Physicists, computational biologists, etc. Because Symbolics.jl allows for translating back and forth between Julia code and symbolic code automatically, we’re seeing computer scientists even adopt it as a nice and easy way to analyze code.&lt;&#x2F;p&gt;
&lt;p&gt;ModelingToolkit.jl on the other hand is more focused towards engineers and modelers. Mechanical engineers, robotics experts, building designers, synthetic biologists. These people are found commonly in both academia and industry. We’re getting a lot of praise from industry users of ModelingToolkit.jl already, so it’s likely to find a nice foothold there.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;how-many-people-are-involved-in-the-projects-what-are-their-backgrounds&quot;&gt;How many people are involved in the projects? What are their backgrounds?&lt;&#x2F;h4&gt;
&lt;p&gt;There are far too many involved, so I’m just going to give a shoutout to the top few. Yingbo Ma is a super star, still an undergrad but a major contributor to both SciML (the differential equation solvers and ModelingToolkit.jl) and JuliaSymbolics. Shashi Gowda is a PhD student at MIT who has been driving a lot of the internals of JuliaSymbolics. Then there have been many contributions by NASA folks, high schoolers, professors in math departments and biology departments, pandemic researchers, etc. It’s still very early on in the project but the community around it is already great.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-are-the-next-steps-for-each-project&quot;&gt;What are the next steps for each project?&lt;&#x2F;h4&gt;
&lt;p&gt;We’re going to have a major announcement very soon, so stay tuned.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>LAM: an actor-model VM for WebAssembly and native</title>
          <pubDate>Fri, 26 Feb 2021 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/lam-an-actor-model-vm-for-webassembly-and-native/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/lam-an-actor-model-vm-for-webassembly-and-native/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/lam-an-actor-model-vm-for-webassembly-and-native/">&lt;p&gt;An interview with its creator, Leandro Ostera.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-ZA5-hKa-yYGz8FX-kmZh9g.png&quot; alt=&quot;&quot; &#x2F;&gt;Source: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;abstractmachines.dev&#x2F;&quot;&gt;https:&#x2F;&#x2F;abstractmachines.dev&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Here, at NAMT, we are in love with the Actor Model.&lt;br &#x2F;&gt;
Within this paradigm, the basic units of computation are called actors. There is no shared state between them, instead, they interact via message passing. This has the advantage that actors become trivial to paralellize (in Erlang, an actor is called a &lt;em&gt;process&lt;&#x2F;em&gt;) and errors became easier to handle.&lt;&#x2F;p&gt;
&lt;p&gt;The actor model is a concurrency paradigm created by Carl Hewitt in 1973 with the goal of making the task of writing concurrent programs simpler. It is based on the idea of actors, entities that can only send, receive and process messages. By reducing the amount of shared state it reduces the need of locks for synchronization. There exists several battle-tested implementations of the Actor Model such as Erlang&#x2F;OTP, Akka (Scala&#x2F;Java) and Orleans (C#).&lt;&#x2F;p&gt;
&lt;p&gt;In this interview, we chat with Leandro Ostera, the founder of Abstract Machines. Ostera is working on LAM, The Little Actor Machine, an embeddable virtual machine for the actor model that runs native or compiles to WebAssembly.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;The questions for this interview were thought by Juan Pablo Amoroso, Javier Chatruc &amp;amp; Federico Carrone. Joaquín Centeno and Juan Bono wrote the introduction and edited the article.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;Tell us a bit about your project lab, Abstract Machines. What kind of work do you do?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I started Abstract Machines with a single goal in mind: build tools that would help me think more clearly.&lt;&#x2F;p&gt;
&lt;p&gt;Right now what I do think about the most is writing software. I think typed languages help me think clearly, so I’m building Caramel, an OCaml for the BEAM. I also think that understanding the program that runs your programs is fundamental to thinking clearly about the quality of what you build, so I’m building LAM, an actor-model VM.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;LAM’s tagline is “A Little Actor Machine that runs on Native and WebAssembly”. Could you give us a brief overview of the actor system?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The original name was Leandro’s Abstract Machine. Like Prolog’s WAM was named after Warren, Warren’s Abstract Machine, and the early Erlang VM was JAM after Joe’s Abstract Machine. But Little I think it’s a much better name overall: LAM should be small, tiny even.&lt;&#x2F;p&gt;
&lt;p&gt;The actor system it implements is in spirit very close to Erlang’s take on the actor model — processes with mailboxes, message passing across them, fair scheduling through reduction counting. There’s a few more things in the roadmap, like process linking and monitoring. Overall, if you have worked with Erlang or Elixir before, you should feel right at home with LAM.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is the motivation behind LAM? Why build a BEAM alternative?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;LAM’s mission is to make Actor concurrency available everywhere by providing a specified, lightweight runtime. Think LuaVM meets the Actor Model. I’ve always liked the LuaVM, there’s a certain elegance to it that I find very appealing.&lt;&#x2F;p&gt;
&lt;p&gt;One of the reasons to build an alternative is that the BEAM is rather large, and the implementation is the only real spec. [Erik Stenmans’ Beam Book] or [kvavks Beam Wisdoms] have tried to document it, but without an official effort to produce a JVM style spec (like the one you can get in a bookshelf), it’s unlikely we will have a reliable drop-in alternative any time soon.&lt;&#x2F;p&gt;
&lt;p&gt;So I thought I could instead make a new thing that could learn from both the LuaVM and the BEAM. At 35 instructions, LAM can run an interesting amount of Erlang programs, in fact I’d like most code that runs on the BEAM to be bytecode-translatable to run on LAM. Not all of it tho, and we’ll see what doesn’t make the cut.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;One of LAM’s targets is WebAssembly. Is there any alternative actor system for the web? How do they compare with LAM?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Yes, there are plenty! A most promising one these days is Lunatic, but on the Erlang side of things, there’s the up-and-coming Lumen.&lt;&#x2F;p&gt;
&lt;p&gt;Most of the rest are libraries for building actor applications in other languages, like how Actix lets you use Actors in Rust. Lumen in particular is more of a compiler + runtime that brings Erlang down to LLVM and gives you this single optimized executable.&lt;&#x2F;p&gt;
&lt;p&gt;LAM by contrast is a higher level VM: you feed it bytecode (spawn, send, receive, call, make list, etc), and as it runs it, side-effects happen through FFI&#x2F;Bindings depending on the platform.&lt;&#x2F;p&gt;
&lt;p&gt;Around LAM there’s a tiny compilation toolchain that takes that bytecode, lowers it to something that can be run a little faster, and packs it &lt;em&gt;with the VM&lt;&#x2F;em&gt; in a single binary that is optimized for a specific platform.&lt;&#x2F;p&gt;
&lt;p&gt;Because the VM is tiny, and the FFIs are pluggable, it’s straightforward to compile it to WebAssembly and run your bytecode there.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;The documentation mentions that one of the goals is to support Erlang&#x2F;OTP’s supervision tree structure. Would this allow more reliable&#x2F;resilient web UIs, capable of gracefully recovering from errors?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Absolutely! I expect it to let you build even more natural and flexible UIs. After all the “event” model fits perfectly: when process Button receives message Click, do this&#x2F;that.&lt;&#x2F;p&gt;
&lt;p&gt;The main problem is that preemptive scheduling makes it impossible to guarantee certain processes will have enough time to make stuff like animations run smoothly. But I’m borrowing the idea of dirty schedulers and considering introducing Greedy Processes instead, that can either request upfront how much time they need, or just run to completion. Definitely interesting to experiment with hard-real time scheduling as well.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What are some interesting use cases for LAM?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Off the top of my head, there’s 2. The first one is perhaps why I want it the most these days: fast cli tools. Write ’em in Erlang&#x2F;Elixir&#x2F;Caramel, ships as a single binary.&lt;&#x2F;p&gt;
&lt;p&gt;The second one will have the largest impact on how we build for the BEAM: actually writing full-stack applications in a single BEAM Language.&lt;&#x2F;p&gt;
&lt;p&gt;Write your backend in Elixir and run it on the BEAM, write your frontend in Elixir too but run it on LAM. And it doesn’t have to be a web-based app, it could be an actual native GUI application too.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why write it in Rust? Is the Rust-WASM toolchain mature enough to target WASM reliably with LAM?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I love Rust. It’s a good language and the learning curve has certainly taught me a lot about how to build software. I think the Rust-wasm toolchain is pretty mature these days too.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Besides performance (LAM compiles AOT), what will be the advantages of LAM over the BEAM?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Really the AOT stuff I can’t consider an advantage — I don’t expect LAM to be fundamentally faster than the BEAM, especially after the BeamJIT work. Nor do I expect it to compete in speed with Lumen.&lt;&#x2F;p&gt;
&lt;p&gt;What I see as an advantage is that LAM is being built to have a Specification and to be Embeddable.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;WebAssembly lacks a garbage collector and the BEAM is a GC environment. How does LAM tackle this?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;There is a wasm-gc spec in the works, and some other folks are waiting on it as well (like the OCaml-wasm efforts).&lt;&#x2F;p&gt;
&lt;p&gt;But since WebAssembly isn’t the only LAM target, we’ll have to embed a GC anyway. I expect it to work very closely to the BEAMs (per process collections, ref counted binary strings, etc). I haven’t looked so deeply into this, but I have a chunky book waiting for me (The Garbage Collection Handbook).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Is this a solo project or are you looking for contributors? If you are looking for contributors, how should they get started (first issues, roadmap, etc)?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;So far it is just me, but I’d love to build a friendly and welcoming community around it. At the moment I’ve been focused on getting this vertical slice of the project up and running so it becomes easier to do some horizontal scoping: how far along are we with the specification, or how much of the BEAM bytecode can we support via translation.&lt;&#x2F;p&gt;
&lt;p&gt;There’s tons of work to do starting at the design level. From figuring out how to build the right layers to FFIs across platforms (native, wasi, web), to how to optimize the main emulator loop to crunch the bytecode as fast as possible, to GC and bundling the final binaries, to writing the spec and the manual.&lt;&#x2F;p&gt;
&lt;p&gt;Formalizing the spec is a big topic where I hope I can get some interest from the TLA+ community to guide me into doing justice to both TLA+ and LAM.&lt;&#x2F;p&gt;
&lt;p&gt;LAM could use help across the board, so if you’re reading this please tweet at me (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;leostera&#x2F;&quot;&gt;@leostera&lt;&#x2F;a&gt;)!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;For our last question, in general, what are your favorite books, articles or resources for programmers?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I think that if you asked me this a year ago I would have regurgitated a bunch of books that I should list here, but that didn’t really further my understanding. There’s a lot of reference material that is just terrible for learning, because its meant to be a compendium of information rather than a pedagogically written introduction to a subject.&lt;&#x2F;p&gt;
&lt;p&gt;For example, Types and Programming Languages by Benjamin Pierce is deemed &lt;em&gt;the ultimate&lt;&#x2F;em&gt; reference for type stuff. But I learned more about the nature of typing by reading The Little Typer. After that it was a lot easier to get into the right headspace to understand what Pierce wanted me to get out of the book.&lt;&#x2F;p&gt;
&lt;p&gt;So if you’re getting into a subject, don’t rush for the ultimate reference, and find something written to teach you &lt;em&gt;the core&lt;&#x2F;em&gt; of the subject. Then the rest becomes a little easier.&lt;&#x2F;p&gt;
&lt;p&gt;Virtual Machines by Iain D. Craig, and Formal Development of a Network-Centric RTOS have been very useful in working with LAM. Hillel Wayne’s Practical TLA+, and Alloy’s Software Abstraction books have been really good to get a better grip on how to specify systems as well. Of course &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;lamport.azurewebsites.net&#x2F;tla&#x2F;book.html&quot;&gt;“Specifying Systems” by Lamport&lt;&#x2F;a&gt; has been a good reference as well.&lt;&#x2F;p&gt;
&lt;p&gt;Some books that have had a massive impact in how I think and communicate have (unsurprisingly) nothing to do with computers. Like Umberto Eco’s “6 Walks in the Fictional Woods” (focused on how to create narratives and rhetoric) or Mandelbrot’s “The (Mis)Behavior of Markets” (a historical account of how fractal geometry describes better the financial markets). Nonetheless, they’ve helped shape the way I think and I’ve come out a better programmer.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;0-nPPWbd4-7dJavk5P.gif&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Ballista, a distributed compute platform made with Rust and Apache Arrow</title>
          <pubDate>Thu, 28 Jan 2021 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/ballista-a-distributed-compute-platform-made-with-rust-and-apache-arrow/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/ballista-a-distributed-compute-platform-made-with-rust-and-apache-arrow/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/ballista-a-distributed-compute-platform-made-with-rust-and-apache-arrow/">&lt;h4 id=&quot;an-interview-with-its-creator-andy-grove&quot;&gt;An interview with its creator, Andy Grove&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-L6SAuZiiRQ4bBaCCiDaP_w.png&quot; alt=&quot;&quot; &#x2F;&gt;Ballista demo. Source: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;andygrove.io&#x2F;2020&#x2F;07&#x2F;ballista-one-year-on&#x2F;&quot;&gt;Andy Grove&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;“I have become frustrated over the years with the proliferation of Big Data tools built in JVM languages. I understand the reasons for this — Java, and especially Kotlin and Scala, are productive languages to work in, the ecosystem is very mature, and skills are widespread. However, it really isn’t the best language for these platforms. The most obvious alternative has been C++ for a long time, but I thought it would be really interesting to see what was possible with Rust.” — Andy Grove&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;As distributed computing platforms continue to become more relevant and new programming languages emerge with a modern approach and a focus on features that more traditional languages aren’t suited for, new and interesting technologies start appearing. In this interview, Andy Grove, software engineer and creator of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ballista-compute&#x2F;ballista&quot;&gt;Ballista&lt;&#x2F;a&gt;, a fresh distributed computing platform built primarily on Rust and powered by Apache Arrow technologies, provides some insight on the motivations behind the project as well as the technical details and features that make Ballista different.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-kYa4OnwY6NrvClA6wPpjZQ.png&quot; alt=&quot;&quot; &#x2F;&gt;Ballista is a work in progress. Once completed, its integrations will work like this. (Source: official documentation)&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h4 id=&quot;what-is-ballista-and-what-kind-of-problems-does-it-solve&quot;&gt;What is Ballista and what kind of problems does it solve?&lt;&#x2F;h4&gt;
&lt;p&gt;Ballista is a distributed compute platform with a current focus on executing ETL (extract, transform, and load) jobs based on queries which are defined using either a DataFrame API, SQL, or a combination of both.&lt;&#x2F;p&gt;
&lt;p&gt;Ballista is implemented in Rust and powered by Apache Arrow.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-are-the-main-advantages-of-using-apache-arrow-technologies&quot;&gt;What are the main advantages of using Apache Arrow technologies?&lt;&#x2F;h4&gt;
&lt;p&gt;In my opinion, there are quite a few advantages in using Apache Arrow for this project.&lt;&#x2F;p&gt;
&lt;p&gt;The Arrow memory format is optimized to support vectorized processing of columnar data and therefore enables significant performance improvements over row-based processing, especially when taking advantage of hardware that natively supports vectorized processing, such as SIMD and GPU.&lt;&#x2F;p&gt;
&lt;p&gt;Arrow also provides a “Flight” protocol, designed to enable Arrow data to be streamed efficiently (without &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.serde.rs&#x2F;serde&#x2F;&quot;&gt;serde&lt;&#x2F;a&gt; overhead) between processes, and Ballista’s executors implement this protocol.&lt;&#x2F;p&gt;
&lt;p&gt;In addition to these benefits, Arrow is a standard that is becoming adopted more widely over time, so designing Ballista from the ground-up to be Arrow-native helps ensure compatibility with other projects in the ecosystem.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-are-advantages-of-an-implementation-based-on-apache-arrow-over-native-data-structures&quot;&gt;What are advantages of an implementation based on Apache Arrow over native data structures?&lt;&#x2F;h4&gt;
&lt;p&gt;Arrow offers a mature type system and in-memory format for representing columnar data that has been tested and refined over many years, so I think this helps accelerate the development of the Ballista platform since there is no need to reinvent the wheel. It also ensures efficient compatibility with other projects that have also adopted Apache Arrow.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;can-you-tell-us-more-about-the-ballista-query-engine&quot;&gt;Can you tell us more about the Ballista query engine?&lt;&#x2F;h4&gt;
&lt;p&gt;Sure. Ballista is based on the Volcano design but has less overhead as a result of being designed to process batches of columnar data. Its design is very much inspired by Apache Spark but with a focus on being language-agnostic so that it can efficiently support popular programming languages such Python, Java, and C++.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;ballista-has-a-very-similar-usage-to-apache-spark-what-are-the-main-advantages-of-ballista-over-it&quot;&gt;Ballista has a very similar usage to Apache Spark, what are the main advantages of Ballista over it?&lt;&#x2F;h4&gt;
&lt;p&gt;The main advantages of Ballista (at least, once it is more mature) are:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Columnar Design&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Although Apache Spark does have some support for columnar processing, it is still largely row-based. Because Ballista is natively columnar and is implemented in a systems level language, it can take advantage of vectorized processing with SIMD and GPU.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Language Agnostic&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Apache Spark is implemented in Scala and tends to have a Scala-first approach, with other languages paying a penalty to interact with Spark due to overheads of serde. Ballista has been architected to use language-agnostic protocols and serialization formats to avoid this.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Memory Efficiency&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Because Ballista is implemented in Rust, there are no GC pauses, and performance is very consistent and predictable. The combination of Rust and Arrow also results in much lower memory usage than Apache Spark — up to 5x lower memory usage in some cases. This means that more processing can fit on a single node, reducing the overhead of distributed compute.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;how-does-it-compare-to-dask&quot;&gt;How does it compare to Dask?&lt;&#x2F;h4&gt;
&lt;p&gt;I actually do not have any experience with Dask yet, although it has been on my “to do” list for a while now. I have heard a lot of positive things about Dask and I am sure that I could learn a lot from this project.&lt;&#x2F;p&gt;
&lt;p&gt;Dask is obviously Python-centric, so I suspect that is going to be the main differentiator. Although the Ballista scheduler is being implemented in Rust, it is designed to work with executors implemented in any language due to the use of Arrow’s Flight protocol, and Google Protocol Buffers to represent query plans and scheduler tasks.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-are-the-reasons-behind-the-choice-of-rust-as-the-main-execution-language&quot;&gt;What are the reasons behind the choice of Rust as the main execution language?&lt;&#x2F;h4&gt;
&lt;p&gt;The reason that I started this project (first with DataFusion at the start of 2018, and now with Ballista) is that I have become frustrated over the years with the proliferation of Big Data tools built in JVM languages. I understand the reasons for this — Java, and especially Kotlin and Scala, are productive languages to work in, the ecosystem is very mature, and skills are widespread. However, it really isn’t the best language for these platforms. The most obvious alternative has been C++ for a long time, but I thought it would be really interesting to see what was possible with Rust.&lt;&#x2F;p&gt;
&lt;p&gt;I see Rust as being a good compromise between Java and C++. It has the memory-safety of Java (but implemented in a very different way) and the performance and predictability of C++.&lt;&#x2F;p&gt;
&lt;p&gt;The cost of compute can be very high with Big Data platforms, so it makes sense to use a language that can make efficient use of the available memory and processing power on each node. In some cases, Ballista uses a fraction of the memory of an equivalent Apache Spark job, and this means that each node in a cluster can process a multiple of the amount of data that Spark can support, resulting in smaller clusters that are utilized more effectively.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;apache-spark-has-mllib-a-library-for-handling-machine-learning-projects-what-features-does-ballista-offer-for-these-tasks&quot;&gt;Apache Spark has MLlib, a library for handling Machine Learning projects. What features does Ballista offer for these tasks?&lt;&#x2F;h4&gt;
&lt;p&gt;So far, the focus of Ballista has very much been on ETL workloads. There have been some discussions about supporting ML workloads but this is an area that I do not have experience with so I am hoping that once Ballista is a little more mature in terms of ETL processing then we can start to look at other areas like ML and listen to what the current pain points are.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-will-be-the-main-areas-of-focus-for-future-releases&quot;&gt;What will be the main areas of focus for future releases?&lt;&#x2F;h4&gt;
&lt;p&gt;The main focus now is getting the platform to a level of maturity where users can run real-world ETL workloads, using the TPC-H benchmarks to measure progress.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;beyond-performance-what-are-the-next-goals-for-the-ballista-project&quot;&gt;Beyond performance, what are the next goals for the Ballista project?&lt;&#x2F;h4&gt;
&lt;p&gt;Personally, I think that the most important goal for the Ballista project is to build a community around it. It started out as a personal side-project but I can only commit a relatively small number of hours each weekend to work on the project, and that time is better spent on writing requirements and building a community than trying to code everything myself.&lt;&#x2F;p&gt;
&lt;p&gt;To this end, I have started a weekly newsletter, named &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;ballistacompute.org&#x2F;this-week-in-ballista&#x2F;&quot;&gt;“This Week in Ballista”,&lt;&#x2F;a&gt; to share news about progress and where help is needed. I am mostly spending my time on the project on tasks such as filing issues and responding to questions in Discord. I am also prototyping new features and then asking for help from the community to complete them.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;do-you-have-any-book-recommendations-on-distributed-computing&quot;&gt;Do you have any book recommendations on distributed computing?&lt;&#x2F;h4&gt;
&lt;p&gt;Last year, I wrote &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.andygrove.io&#x2F;2020&#x2F;02&#x2F;how-query-engines-work&#x2F;&quot;&gt;“How Query Engines Work”&lt;&#x2F;a&gt;, which is an introductory guide to query engines and it does cover distributed computing at a high level. I would be hesitant in recommending this book specifically to learn about distributed computing though, since it doesn’t have very much content on this subject yet, although I do plan on extending the content once Ballista is farther along.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Rebuilding the Racket Compiler with Chez Scheme</title>
          <pubDate>Thu, 26 Nov 2020 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/rebuilding-the-racket-compiler-with-chez-scheme/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/rebuilding-the-racket-compiler-with-chez-scheme/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/rebuilding-the-racket-compiler-with-chez-scheme/">&lt;h4 id=&quot;an-interview-on-racket-cs-with-programmers-gustavo-massaccesi-matthew-flatt&quot;&gt;An interview on Racket CS with programmers Gustavo Massaccesi Matthew Flatt&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-so5Q8KpDmcaIAKUHU5V9mw.png&quot; alt=&quot;&quot; &#x2F;&gt;Still from a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=t09AJUK6IiM&quot;&gt;2018 talk by Matthew Flatt&lt;&#x2F;a&gt;, intervened by us&lt;&#x2F;p&gt;
&lt;p&gt;Racket flaunts the title of being &lt;em&gt;the programmable programming language&lt;&#x2F;em&gt;. With extensibility at its core, it takes metaprogramming to the next level by encouraging developers to implement their own DSLs to solve the problem at hand.&lt;&#x2F;p&gt;
&lt;p&gt;Following this same principle, its development team attacks the complexity of writing a compiler by stacking layers of DSLs to implement many of its components.&lt;&#x2F;p&gt;
&lt;p&gt;On the other hand, the project had many legacy components written in C that became a development bottleneck, so in 2017, Matthew Flatt made an announcement on a Racket Developers group:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-oXZFdbH7adA58JPU4Cu2tw.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;groups.google.com&#x2F;g&#x2F;racket-dev&#x2F;c&#x2F;2BV3ElyfF8Y&#x2F;m&#x2F;4RSd3XbECAAJ?pli=1&quot;&gt;Source&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Chez is a Scheme implementation which was open sourced by Cisco in 2016. Its performance has no match among other schemes and it has a long history of being used in production.&lt;&#x2F;p&gt;
&lt;p&gt;To learn more about this endeavor, we contacted Gustavo Massaccesi, and Matthew Flatt, who were part of what is now called the &lt;strong&gt;Racket CS&lt;&#x2F;strong&gt; project. In this interview, they explain the background and details of this project.&lt;&#x2F;p&gt;
&lt;p&gt;We’re big fans of Matthew Flatt’s work and of the Racket endeavor. For further reading we recommend reading Flatt’s article &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;queue.acm.org&#x2F;detail.cfm?id=2068896&quot;&gt;Creating languages in Racket&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;gumroad.com&#x2F;l&#x2F;lop-in-racket-cultural-anthro&quot;&gt;this book&lt;&#x2F;a&gt; that interviews 38 Racket programmers, and the book &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;beautifulracket.com&#x2F;&quot;&gt;Beautiful Racket&lt;&#x2F;a&gt;, which Flatt prologued.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h4 id=&quot;tell-us-about-racket-what-makes-it-stand-out-in-the-lisp-family&quot;&gt;&lt;strong&gt;Tell us about Racket. What makes it stand out in the LISP family?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Let’s distinguish “Racket the language” and “Racket the project”.&lt;&#x2F;p&gt;
&lt;p&gt;The Racket language is a general-purpose, Scheme-like language with an especially rich set of constructs for extending the language — even by Scheme standards. Racket includes support for writing quick-and-dirty macros, but it also supports nice macros with a good error checking that avoid surprising errors created in the expanded code. The close integration of macros and modules, an enforced phase separation between run-time and compile-time code, and the &lt;code&gt;#lang&lt;&#x2F;code&gt; mechanism for selecting the surface syntax all distinguish Racket from other Lisp variants.&lt;&#x2F;p&gt;
&lt;p&gt;Even the main language Racket is written in a simpler language, and that is written in an even more simple language. This tower of languages makes development easier. You can look under the hood and see all the internal languages, or just ignore all of them and get a nice high level language.&lt;&#x2F;p&gt;
&lt;p&gt;Less prominent, but also as important in practice for building language abstractions and composing them into large systems, are Racket’s run-time constructs: first-class control with continuation marks, custodians for simple and reliable task termination, reachability-based memory accounting, message-based parallelism via places, and Concurrent ML-style constructs for event-driven programs. Many of these constructs need support at lower levels of the runtime system, but then they can be used to build a wide variety of languages and libraries that mesh well.&lt;&#x2F;p&gt;
&lt;p&gt;The Racket project synthesizes research, production, and education efforts toward the overall language-building goal. The idea of “A Programmable Programming Language” serves along those directions, from building student-friendly learning environments to domain-specific languages in application to pushing the frontiers of language design and implementation.&lt;&#x2F;p&gt;
&lt;p&gt;The main page is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;racket-lang.org&#x2F;&quot;&gt;https:&#x2F;&#x2F;racket-lang.org&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-does-it-mean-that-you-can-write-your-own-language&quot;&gt;&lt;strong&gt;What does it mean that you can write your own language?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;For example, when you install Racket, it comes with 20 or 30 additional languages. (I’m not sure if someone has counted all of them.)&lt;&#x2F;p&gt;
&lt;p&gt;There are a few “Student” languages that are designed for students. They are less powerful but have more compile time checks to detect common errors in beginners. And they have different levels so once you master one, you can use the next one that includes more features.&lt;&#x2F;p&gt;
&lt;p&gt;Another language is Typed Racket, that adds types to the Racket expressions, so it refuses to compile unless the types check. And it also uses the type information to optimize the code, so the compilation is slower, but the generated code can be faster.&lt;&#x2F;p&gt;
&lt;p&gt;There are languages that implement the version of Scheme in R5RS and R6RS and many of the SRFI. And you can install a package that adds the version in the R7RS-small.&lt;&#x2F;p&gt;
&lt;p&gt;And there are also more different languages with a very different syntax like a complete implementation of Algol 60.&lt;&#x2F;p&gt;
&lt;p&gt;All these languages share the same backend and you can call the libraries written in one language from any of the other languages that are included in the distribution, the additional languages you can download as packages, or the languages you create.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What’s the difference between Racket and Scheme?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Racket started out as a Scheme implementation, and we would still call it “a Scheme.” Even though it does not fit a Scheme standard, it’s obviously derived from Scheme. There are many specific differences, such as the fact that &lt;code&gt;cons&lt;&#x2F;code&gt; always creates an immutable pair in Racket, but the main difference is philosophy: Scheme is meant to be a small language that gives you just enough to express lots of things. Racket is meant to be a big language, and while it gives you the same core pieces (and more) that can express lots of things, it also codifies the way many things are done to enable more cooperating libraries and languages.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-is-chez-scheme-how-is-it-different-from-other-scheme-implementations&quot;&gt;&lt;strong&gt;What is Chez Scheme, how is it different from other Scheme implementations?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Chez Scheme is one of the oldest Scheme implementations, and its evolution informed many parts of the Scheme standard through R6RS. (Racket’s influence on the Scheme standard, in contrast, is limited to aspects of the R6RS library design.) Chez Scheme is a relatively small language, but like all instantiations of Scheme, the implementation provides a lot more than the standard specifies.&lt;&#x2F;p&gt;
&lt;p&gt;Chez Scheme’s biggest claim to fame is its performance. It has always been among the best-performing Scheme implementations. Its object-tagging and allocation regime, its hybrid stack–heap implementations of continuations, and its compiler structure all remain state-of-the-art, even in 2020.&lt;&#x2F;p&gt;
&lt;p&gt;For most of its existence, Chez Scheme was a proprietary, closed-source implementation, but it became open source in mid-2016. As it happens, we started considering a new Racket reimplementation around the start of 2017.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;why-did-you-choose-chez-scheme-over-other-schemes-to-rebuild-racket&quot;&gt;&lt;strong&gt;Why did you choose Chez Scheme over other Schemes to rebuild Racket?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;The biggest weakness of the Racket BC (“before Chez”) implementation are its back-end compiler structure, its inefficient internal calling conventions (over-adapted to C), and its poor implementation of first-class continuations. Those are exactly the strengths of Chez Scheme. Furthermore, Racket’s evaluation model was always closely aligned with Chez Scheme, such as the emphasis on interactive evaluation and compilation.&lt;&#x2F;p&gt;
&lt;p&gt;It was clear up front that Chez Scheme lacked significant features that Racket needs, such as support for continuation marks and reachability-based memory accounting. However, the high quality of the Chez Scheme design and implementation, in contrast to old Racket’s implementation, made adapting Chez Scheme more appealing than retrofitting Racket’s old implementation further.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;why-reimplement-with-chez-scheme-to-reduce-the-c-part-instead-of-implementing-the-c-stuff-in-racket&quot;&gt;&lt;strong&gt;Why reimplement with Chez Scheme to reduce the C part instead of implementing the C stuff in Racket?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Mostly, we did reimplement the C stuff in Racket. The I&#x2F;O subsystem, the concurrency subsystem (which includes the scheduler for “green” threads, Concurrent ML-style events, and custodians), and the regexp matcher were all rewritten in Racket. Those pieces followed the rewrite of the macro expander in Racket. Other things that needed to be moved out of C, such as the compiler and the extensive support for numbers that Racket inherited from Scheme, were already written in Scheme in Chez Scheme’s implementation.&lt;&#x2F;p&gt;
&lt;p&gt;A big part of the process was to understand what to implement in Racket, what in Chez Scheme, and what new layers to introduce in translation. This work and reorganization benefits other Racket implementation efforts, such as Pycket and RacketScript.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;besides-improving-maintainability-what-are-the-advantages-of-building-racket-with-cs-over-c&quot;&gt;&lt;strong&gt;Besides improving maintainability, what are the advantages of building Racket with CS over C?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;With the exception of the garbage collector and similar low-level parts of the runtime system, much of Racket’s implementation benefits from higher-level abstractions. Writing a macro expander in C was a particularly poor choice, since higher-level abstractions obviously make tree manipulations easier, but the same reasons apply for the I&#x2F;O layer or numeric primitives. Even the garbage collector in [the Racket variant of] Chez Scheme is now half implemented by a specification and compiler that are written in Scheme.&lt;&#x2F;p&gt;
&lt;p&gt;The other big advantage is that the Racket community has a lot of Racket programmers, not C programmers. It’s easier to convince a fan of Racket to look at some code in Racket or Chez Scheme and try to find some bug or a new feature to contribute. The people that like to read and write code in C are probably making contributions to a C compiler.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-were-the-most-challenging-parts-to-implement&quot;&gt;&lt;strong&gt;What were the most challenging parts to implement?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;The most challenging part is not really one part, but the overall scale. Racket is a big language, and it all has to work the same in the new implementation. That means not just getting the right result and&#x2F;or a specific kind of error message, but getting results with the same or better performance characteristics. For example, if a macro generates a giant expansion that nevertheless compiles in reasonable time in Racket BC, then it needs to compile in reasonable time in Racket CS.&lt;&#x2F;p&gt;
&lt;p&gt;When it comes to specific pieces that we had to implement, perhaps the most challenging were adding type reconstruction to the compiler, adding support for continuation marks, allowing record values to act as procedures, reimplementing Racket’s I&#x2F;O, and upgrading Chez Scheme’s garbage collector to support memory accounting, in-place marking for large heaps, and parallelism.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-improvements-have-been-made-since-the-paper-came-out&quot;&gt;&lt;strong&gt;What improvements have been made since the paper came out?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;There have been a lot of fixes of small bugs and incompatibilities between Racket BC and Racket CS. Also the performance of Racket CS has improved, and now both variants have a more consistently similar end-to-end performance. The speed of generated code was rarely the problem with Chez Scheme as a backend, but the layers newly implemented in Racket needed lots of tuning. So, the things that used to be faster in BC are now generally about as fast in CS, while things that have been faster in CS are even faster.&lt;&#x2F;p&gt;
&lt;p&gt;One of the most important improvements at the Chez Scheme level is flunum unboxing. Until recently, the floating-point numbers were stored in a box-like object under the hood, so they can be used in a vector or other container that expects a reference to an object. Now, in many cases, the compiler detects that the box is not necessary and skips it. That reduces the number of allocations and increases the speed of programs that use a lot of floating-point numbers.&lt;&#x2F;p&gt;
&lt;p&gt;The other big area of improvement was in the garbage collector. When we started Racket CS, Chez Scheme had an admirably simple collector that performed very well on traditional Scheme programs. But Racket needed a lot more functionality from the collector. We’ve improved support for large heaps, for GUI and game-like situations that benefit from incremental collection, and for programs with parallelism.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;do-you-know-of-any-uses-of-racket-on-cs-outside-academia&quot;&gt;&lt;strong&gt;Do you know of any uses of Racket on CS outside academia?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;You can download Racket CS from the download page and it is a drop down replacement of the current version of Racket BC. Both the Racket BC and Racket CS include all the libraries and the IDE that is also written in Racket. All the code written in Racket should run without changes in the BC or CS versions, except for some corners of the foreign-function interface.&lt;&#x2F;p&gt;
&lt;p&gt;Gustavo used it in the university to edit an move quiz from a Moodle server to another. The mdz files are like .tar.gz files, so you can use the standard libraries in Racket to uncompress them, edit the xml files that are inside and then repackage the result in a new mdz file. (Does this count as “outside academia”?)&lt;&#x2F;p&gt;
&lt;p&gt;The biggest site that is using Racket is Hacker News &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com,&quot;&gt;https:&#x2F;&#x2F;news.ycombinator.com,&lt;&#x2F;a&gt; that is a forum about programming and related topics. It is programmed in their own language called Arc that is programmed in Racket. They have more than 5.5M hits a day and something between 4M and 5M unique visitors a month. They are using the BC version anyway.&lt;&#x2F;p&gt;
&lt;p&gt;There is a list of other sites and organizations that use Racket in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;racket&#x2F;racket&#x2F;wiki&#x2F;Organizations-using-Racket&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;racket&#x2F;racket&#x2F;wiki&#x2F;Organizations-using-Racket&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;to-target-cs-you-ended-up-patching-the-language-to-accommodate-its-differences-with-racket-was-that-the-intention-from-the-beginning-what-was-the-biggest-difference-between-the-two-languages&quot;&gt;&lt;strong&gt;To target CS, you ended up patching the language to accommodate its differences with Racket, was that the intention from the beginning? What was the biggest difference between the two languages?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;This possibility was considered from the beginning. There are some differences of opinion between Racket and Chez Scheme, so sooner or later some change that is useful for Racket would not be useful in Chez Scheme.&lt;&#x2F;p&gt;
&lt;p&gt;For example, Racket is more strict in checking that a function returns a single value in positions that expect a single value. This is an undefined case in the Scheme standard, so Chez Scheme sometimes ignores it. In the common case that the function actually returns a single value, Chez Scheme may be slightly faster, and in the other cases Racket may report a better error. It’s a design decision, and each team has different preferences. So the version of CS in Racket has some additional checks to track the single return expression and avoid the unnecessary checks when possible.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;is-there-a-use-case-the-vm-is-optimized-for&quot;&gt;&lt;strong&gt;Is there a use case the VM is optimized for?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;It would be fair to say that the Chez Scheme runtime system is optimized for functional programming. There’s a write barrier on object modifications, for example, and the compiler is happier when variables are not mutated. It would also be fair to say that it’s designed for settings with plenty of memory and computing power, and not more constrained, embedded settings.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-do-you-hope-to-improve-in-the-future-i-e-new-features-better-performance&quot;&gt;&lt;strong&gt;What do you hope to improve in the future (i.e. new features, better performance)?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Gustavo’s contributions in this rewrite has been in a type recovery pass for the patched version of Chez Scheme used in Racket. It reduces the number of run time checks of the types, so the final code is faster. There is still a lot of room to make the translation from Racket to Chez Scheme more optimizer friendly, and the optimization pass more translation friendly, so I expect a gain of performance in this area next year. Also, we can improve the cooperation with the high level parts of Racket that use types, like the contract system and Typed Racket.&lt;&#x2F;p&gt;
&lt;p&gt;Writing the optimizations steps in Chez Scheme opens a lot of possibilities, for example Gustavo wanted to add some escape analysis to use that information to avoid copies, or the creation of temporal struct, and other similar reductions. It was too scary to try that in C, but it looks more possible to write it in Chez Scheme. [Probably in 2022.]&lt;&#x2F;p&gt;
&lt;p&gt;Matthew has run out of immediate tasks, and he is hoping to spend less time at the level of the compiler and runtime system. Now that Racket CS has generally caught up and stabilized, he hopes to go back more to language design via the Rhombus project.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;are-there-plans-to-expand-racket-in-which-areas-where-would-you-like-to-see-racket-in-5-years&quot;&gt;&lt;strong&gt;Are there plans to expand Racket? in which areas? Where would you like to see Racket in 5 years?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;The Rhombus project is an experiment at starting fresh with the surface language and library design while preserving all of the language-building constructs, compilation pipeline, and runtime system that we now have in place in Racket. It’s still early — and still earlier than we thought it might be, since Racket CS development continued to dominate our efforts — but if this design succeeds, then we expect that to be the next direction for Racket.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;how-has-the-community-reception-been-to-racket-cs&quot;&gt;&lt;strong&gt;How has the community reception been to Racket CS?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Initially, some people were afraid of the performance drop for adding a new layer between Racket and the hardware. The initial version was slower, but the current version has a similar speed, and in many benchmarks it’s faster. Most likely, the January release of Racket will be version 8.0 with Racket CS (based on Chez Scheme) as the default implementation.&lt;&#x2F;p&gt;
&lt;p&gt;Other people were worried because the development of the low level part of Racket would be slowed down for some time, while making the new version. Now that the CS version has an almost equivalent performance, so hopefully the increase of the development speed in the CS version will compensate for the delay. Anyway, Racket is a big project so while the CS version was developed other areas had a lot of improvement, like new libraries or a more efficient contract system, and all of these new features are available in both versions.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;on-a-different-note-what-books-would-you-recommend-to-a-programmer&quot;&gt;&lt;strong&gt;On a different note, what books would you recommend to a programmer?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;We’d certainly recommend &lt;em&gt;How to Design Programs&lt;&#x2F;em&gt; (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;htdp.org&quot;&gt;https:&#x2F;&#x2F;htdp.org&lt;&#x2F;a&gt;). While it’s mainly intended for beginning programmers, it can also provide a crash course in functional programming for programmers who do not already have a lot of experience with it. &lt;em&gt;Essentials of Programming Languages&lt;&#x2F;em&gt; by Dan Friedman and Mitch Wand is a classic for learning about programming languages from the same perspective that informs HtDP.&lt;&#x2F;p&gt;
&lt;p&gt;While it’s not about programming directly, Matthew recommends &lt;em&gt;Working in Public: The Making and Maintenance of Open Source Software&lt;&#x2F;em&gt; by Nadia Eghbal. The book is a lucid reflection on the history and state of open-source software — partly the idea of open source, but especially how that idea has played out in practice.&lt;&#x2F;p&gt;
&lt;p&gt;Gustavo wants to recommend &lt;em&gt;Gödel, Escher, Bach: an Eternal Golden Braid&lt;&#x2F;em&gt;. It is not related to Racket, but it has a few nice discussions about the transforming formulas&#x2F;code to numbers&#x2F;data, that is one of the main ideas behind the macros in the LISP family.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Scientific Machine Learning with Julia: the SciML ecosystem</title>
          <pubDate>Fri, 13 Nov 2020 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/scientific-machine-learning-with-julia-the-sciml-ecosystem/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/scientific-machine-learning-with-julia-the-sciml-ecosystem/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/scientific-machine-learning-with-julia-the-sciml-ecosystem/">&lt;h4 id=&quot;interview-with-chris-rackauckas&quot;&gt;Interview with Chris Rackauckas&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-zBLCNU10DE1qv5PG4wdwbg.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We live in a complex world. For those scientists who dare to immerse themselves in that complexity and generate a deeper understanding of it, it is very common to have to deal with differential equation models that are not possible to solve without the use of a computer.&lt;&#x2F;p&gt;
&lt;p&gt;A lot of time is usually be spent in coding the particular differential equation for each problem. Julia SciML works to create and maintain tools that improve this process— from the creation of a framework that allows to automate the pipeline to create and solve problem-specific differential equations with a high level syntax, to introducing machine learning methods to infer unknown components of the model, and many other functionalities.&lt;&#x2F;p&gt;
&lt;p&gt;We interviewed the creator of SciML, Chris Rackauckas, to get to know a little more about his work.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-bCCWEZqP_ORcTiLPPV13rw.png&quot; alt=&quot;&quot; &#x2F;&gt;Source: DifferentialEquations.jl documentation&lt;&#x2F;p&gt;
&lt;h4 id=&quot;please-tell-us-a-bit-about-yourself-what-is-your-background-what-is-your-current-position&quot;&gt;Please tell us a bit about yourself. What is your background? what is your current position?&lt;&#x2F;h4&gt;
&lt;p&gt;I am an applied mathematics instructor at MIT, the Director of Scientific Research at Pumas-AI, and a senior research analyst at the University of Maryland, School of Pharmacy. My background is numerical differential equations and systems biology, where my PhD was in new methods for efficient solving of stochastic differential equations to model the control of randomness in the developing zebrafish hindbrain.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-is-sciml-why-was-it-born-and-what-s-its-purpose&quot;&gt;What is SciML? Why was it born and what’s its purpose?&lt;&#x2F;h4&gt;
&lt;p&gt;Before the “SciML” organization, there was just DifferentialEquations.jl and JuliaDiffEq, but it grew beyond just a single project. There were methods for symbolically manipulating equations, sparse automatic differentiation, automated model discovery, neural PDE solvers, and even packages in Python and R for using these tools. So the name didn’t fit and we did a reorganization around the central principle: scientific machine learning. Scientific machine learning is a burgeoning field that mixes scientific computing, like differential equation modeling, with machine learning. That is the essence of the organization: many tools for scientific simulation with differential equation solvers, chemical reaction network tools and N-body simulators, but all of them can compose with machine learning.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-YtKzMw7VOvNbOCsOkXwU0A.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;scientific-computing-and-machine-learning-are-often-perceived-as-very-different-areas-what-would-you-say-are-the-strengths-and-weaknesses-of-each-one-and-how-does-sciml-take-advantage-of-them&quot;&gt;Scientific Computing and Machine Learning are often perceived as very different areas. What would you say are the strengths and weaknesses of each one and how does SciML take advantage of them?&lt;&#x2F;h4&gt;
&lt;p&gt;Scientific computing generally requires a lot of prior knowledge about the system. You need to be able to create a “mechanistic model”, which requires knowing the physical laws, the chemicals which react, or other way to mathematically encode each interaction of the system. If you know this, great! Then you have a very predictive model. You might know all of the chemicals which interact but not know the reaction rates, and then 12 data points can turn this into quite a predictive model. So these models are interpretable (since it’s all about the mechanism), data efficient, etc. They are great at extrapolating too: the theory of gravity gives pretty good predictions for what happens on Earth as it does for the solar system as it does for galaxies.&lt;&#x2F;p&gt;
&lt;p&gt;Data-driven modeling, like machine learning, takes a completely opposite approach of being “data first”. You have a non-mechanistic model, and you “train” the model based on the data. This requires a lot of data, but you can do this even when you have no idea what the mechanism is. What’s the mechanism for what movie someone will want to watch next on Netflix given the previous movies they’ve seen? Einstein didn’t have a theory for that! But with big data, you can generate such a model.&lt;&#x2F;p&gt;
&lt;p&gt;Scientific machine learning is about pairing together these two paradigms. Incorporating mechanism into machine learning makes it more interpretable, more data efficient, and better able to predict beyond the training data, all without requiring that you know all of the mechanisms. We’re using this in cases like pharmacometrics, where in the first clinical trial we may not know everything about how the drug works, but we can start with a pretty good guess by using mechanistic models derived for similar drugs, and use the incoming data to train models which transforms the prior model towards the data.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-ihyMT0ujkdDopf3M8eiXUw.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-are-neural-odes-when-is-it-appropiate-to-work-with-one-do-you-fear-that-accuracy-or-interpretability-is-lost-by-introducing-a-neural-network-as-part-of-the-equation-aren-t-there-other-learning-methodologies-suited-for-such-a-thing&quot;&gt;What are Neural ODEs? When is it appropiate to work with one? Do you fear that accuracy or interpretability is lost by introducing a Neural Network as part of the equation? Aren’t there other learning methodologies suited for such a thing?&lt;&#x2F;h4&gt;
&lt;p&gt;Neural Ordinary Differential Equations or Neural ODEs are ordinary differential equations defined by a neural network. Indeed the result is less interpretable than having a mechanistic physical model, but it allows for the model to be learned directly from data. The neural network makes it not just estimating parameters, but estimating functions. As a middle ground, we created the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;abs&#x2F;2001.04385&quot;&gt;universal differential equation&lt;&#x2F;a&gt; which is a partially mechanistic model where the neural networks fill in areas of the model which are unknown or have a lot of uncertainty. In this sense, there is more of a continuum between the data-driven and mechanistic models.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;currently-there-exist-many-differential-equations-solvers-why-do-you-think-this-is-the-case-is-there-a-way-to-choose-the-best-one-for-each-situation&quot;&gt;Currently, there exist many differential equations solvers, why do you think this is the case? Is there a way to choose the best one for each situation?&lt;&#x2F;h4&gt;
&lt;p&gt;We created an automated algorithm chooser in order to mitigate this issue. If you do ‘solve(prob)’ (i.e. don’t specify a solver algorithm), it will choose one for you. Then you can give it hints to go down different branches. As time goes on I think we will keep refining that algorithm and pushing more people towards that.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-are-the-key-reasons-the-sciml-differential-equations-solver-is-so-fast-how-does-it-differ-from-others-how-influential-was-writing-it-in-julia&quot;&gt;What are the key reasons the SciML Differential Equations solver is so fast? How does it differ from others? How influential was writing it in Julia?&lt;&#x2F;h4&gt;
&lt;p&gt;Every differential equation solver specializes on some aspect of the differential equation, giving them different performance aspects. For example, BDF integrators, “the standard” for stiff equations, use values from past steps. This can speed things up if the equation is not too stiff, but if it’s too stiff then you cannot use a high order (known as the Dahlquist barrier) and it slows down. So it’s problem dependent as to how well it can mitigate numerical issues, which means for some problems it’s fast and in others it breaks down. Then, if you have discontinuities which are frequent, like dosing in pharmacometrics simulations, this also requires order reduction and thus makes this particular method slower. DifferentialEquations.jl has about 300 methods when you consider all of the tableaus across not just ODEs but also SDEs, DAEs, and DDEs, and it’s this collection that allows it to be efficient.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;regarding-the-importance-of-being-able-to-quantify-the-uncertainty-of-the-numerical-resolution-when-solving-differential-equations-how-does-sciml-address-this-problem&quot;&gt;Regarding the importance of being able to quantify the uncertainty of the numerical resolution when solving differential equations, how does SciML address this problem?&lt;&#x2F;h4&gt;
&lt;p&gt;DifferentialEquations.jl comes with a module DiffEqUncertainty.jl that gives sampling-based estimates of numerical uncertainty by causing jitter on the order of the error estimates calculated on each step. Normally these error estimates are only used for adapting dt, but this gives a way to get essentially a free estimate of what other possible paths look like. Andrew Stuart’s group at CalTech then has a full publication that describes that this method indeed matches the error distribution of the full solve. So if you run this a hundred times you’ll get a sense of what all of the possible trajectories could’ve been given the error tolerance that you allowed.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-are-multiscalearrays-in-what-ways-do-these-data-structures-help-us-in-simulating-complex-scientific-models&quot;&gt;What are MultiScaleArrays? In what ways do these data structures help us in simulating complex scientific models?&lt;&#x2F;h4&gt;
&lt;p&gt;The differential equation solvers, and actually all of the SciML ecosystem, work on abstract interfaces which allow for the concrete implementation of a type to be radically different from the standard implementation. MultiScaleArrays is a nice example of this where an entire multi-scale model is represented as both a graph structure and an array simultaneously. This lets the user write a model like “for every cell in the lung, do the chemical reactions of a lung cell” to define a model, but have the stiff high-performance ODE solver automatically know how to interact with this object. It’s not even an array: it’s an array of arrays of arrays etc., which acts like an array. In this form it’s very efficient to allows cells to divide and die, and the ODE solver will adapt the size of the solution vector automatically as this changes.&lt;&#x2F;p&gt;
&lt;p&gt;While this was made for the specific case of multi-scale biological modeling in mind, other users have since come up with other great examples. CuArrays are CUDA-accelerated arrays that live on the GPU that can be dropped in as a replacement to the standard array, or ComponentArrays.jl defines an array type similar to MultiScaleArrays which is backed by a real vector, so it’s faster for standard computations but slower for size changes. A lot of new features can thus be directly added and optimized in the ODE solver just by changing the input types!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-crRcFtHznAsYXDCb1uh4oQ.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;are-the-processes-of-solving-differential-equations-and-training-a-neural-networks-similar-how-do-you-put-together-both-frameworks&quot;&gt;Are the processes of solving differential equations and training a Neural Networks similar? How do you put together both frameworks?&lt;&#x2F;h4&gt;
&lt;p&gt;Training a neural network is solving an ODE defined by the gradient of the loss function until zero. Solving that ODE with Euler’s method is gradient descent. So you could use an ODE solver as the algorithm for training a neural ODE, and there is a use case that we’re looking into for that. Differential equations are more ubiquitous than I think most people realize.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;is-gpu-computing-integrated-in-the-sciml-ecosystem-how-important-is-having-this-feature-to-a-scientific-computing-framework-nowadays&quot;&gt;Is GPU computing integrated in the SciML ecosystem? How important is having this feature to a scientific computing framework nowadays?&lt;&#x2F;h4&gt;
&lt;p&gt;Yes, there’s two major ways. If you have “big kernels”, like PDE solving or neural networks integrated into models, you can do those calculations on the GPU. This is what’s known as “within-method parallelism”. One of the more recent techniques that we have is “between-method parallelism”, where we can automatically generate CUDA kernels from your model and parallelize that between trajectories of the solution. This uses some fancy code generation tricks thanks to tools like KernelAbstractions.jl, and allows “small problems” to have an effective way to use GPUs as well.&lt;&#x2F;p&gt;
&lt;p&gt;How important is it? Somewhat. There are problems which are extremely GPU-parallelizable, like neural ODEs and PDEs, and there are problems which are not, like lots of semi-mechanistic universal differential equation models. Whether a GPU is useful is very dependent on what and how you’re trying to model.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;in-which-cases-is-it-worth-to-add-a-bayesian-analysis-to-the-parameter-estimation-for-example-with-the-use-of-diffeqbayes-jl-what-are-its-advantages-over-more-classical-optimization-algorithms&quot;&gt;In which cases is it worth to add a Bayesian analysis to the parameter estimation, for example with the use of DiffEqBayes.jl? What are its advantages over more classical optimization algorithms?&lt;&#x2F;h4&gt;
&lt;p&gt;Bayesian analysis gives you a posterior distribution which has a sense of uncertainty quantification, i.e. it doesn’t just give you the “best parameter” but also a distribution which you can use to understand the error bars on your parameter estimate. In many cases this is a fundamentally interesting quantity. For example, in pharmacology we often want to know the probability that the drug concentration is in the safe zone. To evaluate this, we need a probabilistic fit of the model since only by including the uncertainty of our parameters can we get an accurate guess of the probabilities of the dynamics.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-c8-WwVO2Mlef4QqXP7SvSA.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;are-there-any-relevant-books-or-papers-you-would-like-to-recommend-for-digging-deeper-in-these-topics&quot;&gt;Are there any relevant books or papers you would like to recommend for digging deeper in these topics?&lt;&#x2F;h4&gt;
&lt;p&gt;Books schmooks. You’ll want to go directly to the sources. The only books I really recommend these days are Ernst Hairer’s “Solving Ordinary Differential Equations” I and II tomes: those are a work of art. Also Kloeden’s book on numerical methods for stochastic differential equations. Other than that, dive right into the scientific literature.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-is-next-for-sciml-are-you-currently-working-on-some-other-features-to-add-in-the-near-future&quot;&gt;What is next for SciML? Are you currently working on some other features to add in the near future?&lt;&#x2F;h4&gt;
&lt;p&gt;There’s tons we’re doing! I think a lot of what’s next is the integration of symbolic computing into all of our tools. ModelingToolkit.jl is the centerpiece of that push, and while I gave a talk at JuliaCon 2020 showcasing how it can be used as an automated code optimization tool (and gave a PyData 2020 talk on how you can GPU-accelerate ODE solves in R using it!), it’s so much more than that. It’s sometimes hard to numerically do things correctly, like ensuring positivity in an ODE solution can be difficult. But if you log transformed your model, then by definition your solution will always be positive. Right now this is up to the user, but what if we could automatically change the equations you wrote so that, not only are they more efficient, but they are also mathematically easier to solve and estimate? That’s the scope of ModelingToolkit, and if that interests you then you might want to stay tuned to that and its sister product NeuralSim which is about automated surrogate acceleration for the ModelingToolkit modeling language.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Stumpy: unleashing the power of the matrix profile for time series analysis</title>
          <pubDate>Mon, 02 Nov 2020 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/stumpy-unleashing-the-power-of-the-matrix-profile-for-time-series-analysis/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/stumpy-unleashing-the-power-of-the-matrix-profile-for-time-series-analysis/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/stumpy-unleashing-the-power-of-the-matrix-profile-for-time-series-analysis/">&lt;h4 id=&quot;an-interview-with-stumpy-creator-sean-law&quot;&gt;An interview with Stumpy creator Sean Law&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-4Y5wJGqZM2AxKb7fmT9-og.png&quot; alt=&quot;&quot; &#x2F;&gt;Source: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;stumpy.readthedocs.io&#x2F;en&#x2F;latest&#x2F;Tutorial_Time_Series_Chains.html&quot;&gt;Stumpy documentation&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In the mid-20th century, the Information Age started. Every day an astonishing amount of data is created and analyzing it in an efficient way requires computational tools that combine novel and clever approaches that benefit from cutting edge technology.&lt;&#x2F;p&gt;
&lt;p&gt;Time series are a particular kind of data: the points measured are related by time, and analyzing them can often become quite difficult because time is not just like any other variable. More traditional methods like ARIMA or machine learning methods like LSTM can quickly become computationally inefficient as the amount of points increase, and sometimes they can be too elaborate for simple results such as finding overall patterns in the data, not to mention the complications arising when finding more complex patterns in the data is the final goal.&lt;&#x2F;p&gt;
&lt;p&gt;Stumpy is a library for analyzing time series, that tries to address the problems that appear when working with this kind of data. By design, Stumpy high performance, simplicity, and to employ general purpose approaches for extracting meaningful information. We interviewed the team to learn more about this promising project.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-NWV2vLKBciK49BAVfzvN4Q.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-is-stumpy-what-are-the-goals-of-the-project&quot;&gt;What is STUMPY? What are the goals of the project?&lt;&#x2F;h4&gt;
&lt;p&gt;Numerous classical methods exist for understanding and analyzing time series data, such as data visualization, summary statistics, ARIMA modeling, Markov modeling, anomaly detection, forecasting, machine learning, deep learning, etc. The list goes on. However, when a data practitioner is presented with new or unfamiliar time series data, many of the aforementioned approaches often fail to uncover any significant pattern, anomaly, or unique observation since it isn’t known, a priori, whether or not an interesting insight even exists. Of course, if a behavior is found to be conserved within your time series (though, this may not always be true), then there must have been a reason why it was conserved and teasing out those reasons or causes can often be very useful. Note that with time series analysis we are rarely interested in single point statistics (i.e., global max, global min, etc) and, instead, it is more valuable to discover interesting “subsequences” (i.e., a continuous run of values along your time series with a preset length). So, when starting with time series analysis, one should really be asking:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Do any conserved behaviors (i.e., repeating subsequences) exist in my time series data?&lt;&#x2F;li&gt;
&lt;li&gt;If there are conserved behaviors, what are they and where are they?&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;A naive but straightforward approach that can help answer these questions (covered in more detail &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;stumpy.readthedocs.io&#x2F;en&#x2F;latest&#x2F;Tutorial_The_Matrix_Profile.html&quot;&gt;here&lt;&#x2F;a&gt;) could involve comparing the Euclidean distance for every subsequence within the time series in a pairwise fashion in order to identify subsequences that are either highly conserved or exceptionally rare. This seems intuitive at first and it provides an exact solution to our problem but, as the size of the dataset increases (&amp;gt;10,000 data points), this brute force search can quickly become computationally intractable and reveals why approximate solutions (i.e., allowing for false positives and false negatives) or less interpretable solutions (above) have prevailed. Recently, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.cs.ucr.edu&#x2F;~eamonn&#x2F;MatrixProfile.html&quot;&gt;independent research conducted at UC Riverside&lt;&#x2F;a&gt; has spawned a collection of brand new ideas and they have developed scalable algorithms that directly addresses this hard computational problem. However, the knowledge and capabilities that have been transferred to the scientific Python community has been limited.&lt;&#x2F;p&gt;
&lt;p&gt;And so, STUMPY was born. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;TDAmeritrade&#x2F;stumpy&quot;&gt;STUMPY&lt;&#x2F;a&gt; is a powerful and scalable Python package that faithfully reproduces the aforementioned academic work and, at its core, efficiently computes something called a “matrix profile”, which can be used for a variety of time series data mining tasks. Essentially, a matrix profile is a vector that stores the Euclidean distance (and index location) between each subsequence within a time series and its nearest neighbor. And, with 100% code coverage and multi-CPU&#x2F;multi-GPU support out of the box, the goal of STUMPY is to provide a highly reliable and user-friendly interface for modern time series analysis that can quickly and easily scale up to accommodate your ever-growing data needs.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-kind-of-time-series-analysis-can-be-done-with-stumpy-in-what-fields-do-you-think-it-will-help-the-most&quot;&gt;What kind of time series analysis can be done with Stumpy? In what fields do you think it will help the most?&lt;&#x2F;h4&gt;
&lt;p&gt;As mentioned above, STUMPY is focused on efficiently computing a simple-to-interpret but highly useful data structure called the “matrix profile”. Earlier, Eamonn Keogh, one of the original academic researchers, claimed that “Given the matrix profile, most time series data mining problems are easy or trivial to solve in a few lines of code.” In fact, Keogh and his colleagues have since published over 20 papers demonstrating the many things that can be done once you’ve computed the matrix profile and, below, are a just few examples:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Motif discovery — identify conserved subsequences (related to pattern recognition)&lt;&#x2F;li&gt;
&lt;li&gt;Discord discovery — uncover subsequences that are poorly conserved (related to anomaly detection)&lt;&#x2F;li&gt;
&lt;li&gt;Time series chains — find related patterns that are evolving monotonically over time (related to forecasting)&lt;&#x2F;li&gt;
&lt;li&gt;Semantic segmentation — automatically determine regime changes within your time series data (related to change point detection)&lt;&#x2F;li&gt;
&lt;li&gt;Streaming data analysis&lt;&#x2F;li&gt;
&lt;li&gt;Multi-dimensional matrix profiles&lt;&#x2F;li&gt;
&lt;li&gt;Time series clustering&lt;&#x2F;li&gt;
&lt;li&gt;And more…&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;One of the benefits of computing matrix profiles with STUMPY is that it is 100% domain agnostic. This means that it is completely generalizable and can be applied in any field where you need to analyze continuous sequential data! In addition to the previously published examples, STUMPY has been applied in analyzing the stock market, bettering server uptime and resiliency, investigating call center conversation flow, understanding IoT sensor data, improving cryptocurrency model predictions, and stabilizing ion acceleration at CERN, just to name a few. Today, time series data is ubiquitous in both academia as well as industry and so we believe that STUMPY is a new tool that is extremely well positioned to help researchers and data scientists explore their data in a systematic and focused way and, hopefully, allow them to discover new insights with much less frustration and time spent. If you already have Python installed then you should be able to get started with STUMPY in less time than it takes for you to make a cup of coffee.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-are-the-benefits-of-computing-the-matrix-profile-in-the-context-of-analyzing-a-time-series-what-are-the-advantages-over-other-methods&quot;&gt;What are the benefits of computing the matrix profile in the context of analyzing a time series? What are the advantages over other methods?&lt;&#x2F;h4&gt;
&lt;p&gt;Matrix profiles are simple, intuitive, and interpretable. Basically, if you understand what Pythagorean theorem is then you’re all set! Whereas with other methods, if you step away from the analysis for six months and then come back to it, you often have to perform a lot of mental gymnastics in order to remember and understand what was going on. With a single line of STUMPY code, you can compute your matrix profile and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;stumpy.readthedocs.io&#x2F;en&#x2F;latest&#x2F;Tutorial_STUMPY_Basics.html&quot;&gt;quickly identify motifs (conserved patterns) and discords (potential anomalies) by looking at the minima and maxima&lt;&#x2F;a&gt;, respectively. From there, a slew of rapid post-analyses can be performed using the matrix profile and the subsequent results can help you develop further hypotheses and questions about your data. Additionally, unlike other methods which may be riddled with false positives and false negatives, matrix profiles are exact and don’t require any “training” in order to find patterns. It just works right out-of-the-box!&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-is-the-general-criteria-when-choosing-a-window-size-is-there-some-indicator-to-look-up-when-analysing-a-time-series&quot;&gt;What is the general criteria when choosing a window size? Is there some indicator to look up when analysing a time series?&lt;&#x2F;h4&gt;
&lt;p&gt;That’s a good question. Usually, the window size (i.e., the length of your subsequence or sliding window) should be chosen to be large enough to encompass a potential pattern. This usually requires a little bit of domain knowledge but the academic researchers have found that matrix profiles are not so sensitive to the choice of the window size so long as it isn’t smaller than the subsequence pattern. So, being in the rough ballpark is usually enough. However, since matrix profiles are pretty fast and cheap to compute, your best bet is to simply try several different window sizes, perhaps, by repeatedly doubling your window size and observing where there may be conserved minima&#x2F;maxima across the set of matrix profiles. The academic researchers have also published a paper (which you can download &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.cs.ucr.edu&#x2F;~eamonn&#x2F;PAN_SKIMP%20%28Matrix%20Profile%20XX%29.pdf&quot;&gt;here&lt;&#x2F;a&gt;) detailing a similar approach called a “pan matrix profile” that can help narrow down the search space. So, look out for this new STUMPY feature in an upcoming release!&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-is-semantic-segmentation-in-the-context-of-time-series-what-were-the-problems-in-the-past-with-this-method-and-how-do-you-solve-them&quot;&gt;What is semantic segmentation in the context of time series? What were the problems in the past with this method and how do you solve them?&lt;&#x2F;h4&gt;
&lt;p&gt;In the context of time series, “semantic segmentation” is “the division of a time series into internally consistent areas&#x2F;regimes” or, sometimes, you can think of it as a “special type of clustering with the additional constraint that the elements in each cluster are contiguous in time”. Basically, if you have a time series where the values are repeating periodically within some range and then, in response to some external change or event, the time series shifts into another mostly periodic range so that you are left with two distinct “regimes”, then semantic segmentation may be useful for helping you identify the boundary in between the regimes. Now, methods like “change point detection” exist for detecting changes in various statistical properties of the time series (i.e., the mean or variance) but, fundamentally, we are interested in regimens which are defined by changes in the shapes of the time series subsequences, which can change without any obvious effect on the statistical properties. And this is where matrix profiles come into play. By simply using the information stored within your matrix profile, you can automatically identify and label these boundary regions in a systematic way. You can learn more in this illustrative &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;stumpy.readthedocs.io&#x2F;en&#x2F;latest&#x2F;Tutorial_Semantic_Segmentation.html&quot;&gt;STUMPY tutorial&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;how-does-the-sampling-rate-affect-the-analysis-of-a-time-series-how-often-are-important-patterns-hidden-because-of-a-bad-sampling-method&quot;&gt;How does the sampling rate affect the analysis of a time series? How often are important patterns hidden because of a bad sampling method?&lt;&#x2F;h4&gt;
&lt;p&gt;In general, sampling rate is quite important but it is often independent of the analysis method. If you have a conserved pattern that spans a full minute (i.e., it is a unique shape that is captured within 60 data points spaced one second apart) but you only collect a single aggregate data point once every hour, then it is impossible for any method to discover this pattern. Conversely, if you collect a data point once every microsecond then you might run out of storage space or lack the ability to analyze this large data set after 5 years. Unfortunately, in either case, having the best algorithms and the fastest hardware will not help you fix poor sampling. Or, as they say, “garbage in, garbage out”.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1--71VCPSQe2aIyw49RucHCQ.png&quot; alt=&quot;&quot; &#x2F;&gt;Source: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;stumpy.readthedocs.io&#x2F;en&#x2F;latest&#x2F;Tutorial_Time_Series_Chains.html&quot;&gt;Stumpy documentation&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;stumped-is-the-distributed-version-of-stump-and-it-is-implemented-using-dask-why-have-you-chosen-dask-over-other-solutions-to-implement-stumped&quot;&gt;STUMPED is the distributed version of STUMP and it is implemented using Dask. Why have you chosen Dask over other solutions to implement STUMPED?&lt;&#x2F;h4&gt;
&lt;p&gt;As a research scientist, one of my pet peeves is software that is slow or that takes way too much time and effort to install. So, it was imperative for STUMPY to have minimal dependencies, be easy to install, and also be fast and scalable. Initially, when we prototyped STUMPY, everything was written using NumPy and SciPy and this worked well for time series that contained around 10K data points. However, we noticed that not all of the threads on our machine were being used (due to the GIL) and things started to take forever as we increased the length of our time series. At the time, Cython was a popular option for releasing the GIL but it seemed really hard to maintain from a packaging perspective and the coding style never felt “Pythonic”. In contrast, we had starting hearing a lot of great things about Numba’s ability to JIT-compile Python code into performant machine code and so, within two days, we were able to parallelize STUMPY using Numba and leverage all of the compute power available on our local server. For data scientists, this is great and usually sufficient for small to medium-sized data sets but, naturally, we starting thinking about distributed computing. Dask is a wonderful Python package that offers scalable analytics, can be easily distributed to over a thousand servers, and has a large user community. Additionally, we knew that Dask interoperated well with Numba and so, within five days, we were able to go from a single server to distributing our matrix profile computation across a 32 server Dask cluster. While other solutions currently exist for distributed computing, we really liked that Dask was lightweight, heavily battle-tested, and was supported by knowledgeable maintainers who had the right vision. While STUMPY does not leverage Dask’s “big data collections” (i.e., parallel arrays and dataframes), the robust dynamic task scheduling used by STUMPY is well beyond experimental.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;was-gpu-compatibility-challenging-to-integrate-in-the-project&quot;&gt;Was GPU compatibility challenging to integrate in the project?&lt;&#x2F;h4&gt;
&lt;p&gt;This is a great question! In our journey, we carefully assessed the landscape and seriously considered the idea of using PyCUDA, CuPy, TensorFlow, PyTorch, or even writing raw CUDA kernels and interfacing it with Cython. However, these technologies can either be too hard to install, too low level and verbose, too difficult to maintain (or for others to contribute to), or their APIs are simply too unstable. Ultimately, the best solution for adding GPU support was right underneath our noses and we didn’t even need to add any additional dependencies! Because, luckily for us, Numba is also able to JIT-compile Python code to target GPUs. Of course, it is important to point out that since the programming paradigm for GPUs is quite different from CPUs, STUMPY has to maintain separate Python modules that target the different hardware and we’ve had to develop new and unique ways to ensure proper and thorough testing of our software. However, the massive performance benefits gained from leveraging GPUs and not having to switch from Python to writing CUDA is well worth the tradeoffs. If anybody tries to convince you that “Python is slow” then I’d highly recommend trying Numba and Dask as they can easily help take your Python performance scaling to the next level. If you are interested in computing matrix profiles with STUMPY using GPUs then please check out this &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;colab.research.google.com&#x2F;drive&#x2F;1FIbHQoD6mJInkhinoMehBDj2E1i7i2j7&quot;&gt;Google Colab notebook&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;considering-you-have-chosen-numba-for-optimizing-and-parallelizing-computation-have-you-thought-about-using-julia-in-the-future-which-has-built-in-features-for-this-tasks&quot;&gt;Considering you have chosen Numba for optimizing and parallelizing computation, have you thought about using Julia in the future, which has built-in features for this tasks?&lt;&#x2F;h4&gt;
&lt;p&gt;Julia has certainly grown over the years but its adoption has been slow and so we’ve yet to consider it as a viable option. However, given the amount of effort that we’ve put in to keeping our code base easy to read and digest, it shouldn’t be difficult to port STUMPY over to other languages and we’d certainly be open to sharing and collaborating in the future.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;how-do-you-justify-the-comparison-between-the-benchmark-using-256-cpus-stumped-256-against-the-one-using-16-gpus-gpu-stump-dgx2-especially-economically-speaking&quot;&gt;How do you justify the comparison between the benchmark using 256-CPUs (STUMPED.256) against the one using 16 GPUs (GPU-STUMP.DGX2), especially economically speaking?&lt;&#x2F;h4&gt;
&lt;p&gt;The STUMPY README provides rough &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;stumpy.readthedocs.io&#x2F;en&#x2F;latest&#x2F;#performance&quot;&gt;performance benchmarks&lt;&#x2F;a&gt; but the point isn’t to debate whether GPUs are “faster” or “better suited” for computing matrix profiles than CPUs. If you have access to one or more GPUs, then you should definitely use them! However, if you don’t have access to top-of-the-line GPUs or national super computing clusters, STUMPY can still be useful. Benchmarks are always biased and outdated but our goal is to be transparent and to give people a clearer sense of how long their computation might take (depending on the size of their data) and what hardware resources they may need in order to realistically complete their analysis. Otherwise, the user should be able to make an informed decision as to whether or not STUMPY is suitable for their situation. For all intents and purposes, STUMPY is more than “fast enough” and, more importantly, it faithfully reproduces the academic work and users can feel confident that STUMPY can perform equally as well on better hardware and with larger data set! Thanks to Moore’s law, you don’t have to take our word for it. Give STUMPY a try and let us know what you think!&lt;&#x2F;p&gt;
&lt;h4 id=&quot;in-the-paper-presenting-the-stomp-algorithms-an-implementation-in-a-seismologic-dataset-is-shown-working-with-a-really-huge-amount-of-data-and-analysing-it-within-days-how-near-are-we-from-real-time-anomaly-detection-systems-that-analyse-datasets-as-large-at-that-scale&quot;&gt;In the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.cs.ucr.edu&#x2F;~eamonn&#x2F;STOMP_GPU_final_submission_camera_ready.pdf&quot;&gt;paper&lt;&#x2F;a&gt; presenting the STOMP algorithms, an implementation in a seismologic dataset is shown, working with a really huge amount of data and analysing it within days. How near are we from real-time anomaly detection systems that analyse datasets as large at that scale?&lt;&#x2F;h4&gt;
&lt;p&gt;To answer this question, one first needs to clearly define what is meant by “real-time”. Typically, this involves a situation where large amounts of data is being streamed in continuously and at a reasonably high frequency rate. Additionally, when discussing real-time analysis, it is important to identify how much data needs to be collected before the analysis can begin (i.e., is it one data point or do you need to collect 10 days worth of data before you can start) and it is also worth considering whether this is a sliding window analysis (i.e., where the oldest data point is removed as a new data point arrives). I can’t speak directly to the primary research but, in the 100 million data point seismology example, the dataset was actually recorded at 20 Hz and collected over 58 days but the the matrix profile was computed in just over 12 days. In that particular case, the speed of analysis (12 days) was actually faster than the speed of data collection (58 days) and, naturally, if you could initiate your analysis with less data then the matrix profile computation would require substantially less time as well. Of course, this feels more like a batch analysis than a streaming analysis but hopefully the point that we’re trying to make is clear. In fact, the academic researchers have published additional work on how to incrementally update your matrix profile on-the-fly as additional data points are streamed in. This streaming-friendly capability is currently available in STUMPY and more detail can be found in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;stumpy.readthedocs.io&#x2F;en&#x2F;latest&#x2F;Tutorial_Matrix_Profiles_For_Streaming_Data.html&quot;&gt;this STUMPY tutorial&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;how-do-you-think-stumpy-will-evolve-do-you-have-in-mind-new-features-to-implement-in-the-near-future&quot;&gt;How do you think STUMPY will evolve? Do you have in mind new features to implement in the near future?&lt;&#x2F;h4&gt;
&lt;p&gt;One of the co-founders of Explosion, Ines Montani, gave a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;speakerdeck.com&#x2F;inesmontani&#x2F;let-them-write-code-keynote-pycon-india-2019&quot;&gt;wonderful talk at PyCon India 2019&lt;&#x2F;a&gt; titled “Let Them Write Code” where she identified that ‘Good tools help people do their work. You don’t have to do their work for them. Worst developer experiences: tools that want to be “fully integrated solution”’, which I think embodies our approach to developing STUMPY. We have purposely limited the scope of STUMPY and stayed laser-focused on making our code base rock solid, performant and well tested, and super user-friendly. While it may be tempting to over-simplify time series analysis and offer additional things like data cleaning or custom visualization tools all in one package, we want to enable all of our users to really think through their analysis approach rather than relying on a package to make false assumptions about their data, which is more than likely to be wrong anyways. To that extent, STUMPY has already achieved its goal in providing an efficient way for users to compute matrix profiles and that is scalable on a wide variety of hardware. Additionally, there has been a lot of interest in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;stumpy.readthedocs.io&#x2F;en&#x2F;latest&#x2F;api.html&quot;&gt;computing matrix profiles with non-normalized Euclidean distances&lt;&#x2F;a&gt; (as opposed to z-normalized Euclidean distances) and so we’ve added a suite of new features that addresses these needs and you can check out our &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;TDAmeritrade&#x2F;stumpy&#x2F;issues&quot;&gt;current backlog of feature enhancements on our public Github page&lt;&#x2F;a&gt;. There is still a lot of work that needs to be done to socialize the matrix profile approach, to educate others through public talks and tutorials that use real-world examples, and to continue building and fostering a transparent and supportive community. Of course, this will take time and is easier said than done but we’re making progress everyday.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;are-there-any-books-you-recommend-reading-on-the-topic&quot;&gt;Are there any books you recommend reading on the topic?&lt;&#x2F;h4&gt;
&lt;p&gt;Unfortunately, there aren’t any books on the topic yet but, for starters, readers may be interested in exploring the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;stumpy.readthedocs.io&#x2F;en&#x2F;latest&#x2F;tutorials.html&quot;&gt;STUMPY tutorials&lt;&#x2F;a&gt; or watching this &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=xLbPP5xNIJs&quot;&gt;STUMPY video&lt;&#x2F;a&gt; (hosted by the Stitch Fix Algorithms team) as they provide a balanced mixture of background information, relevant context, and technical detail to help you develop the right intuition. Additionally, I strongly recommend skimming the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.cs.ucr.edu&#x2F;~eamonn&#x2F;MatrixProfile.html&quot;&gt;plethora of articles published by Eamonn Keogh’s group&lt;&#x2F;a&gt;. They’re actually a pleasure to read and I continually learn more each time I re-read these foundational papers.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;where-can-readers-find-you-and-where-can-they-learn-more-about-stumpy&quot;&gt;Where can readers find you and where can they learn more about STUMPY?&lt;&#x2F;h4&gt;
&lt;p&gt;I blog occasionally &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;seanlaw.github.io&#x2F;&quot;&gt;on my personal website&lt;&#x2F;a&gt; but you can follow me on Twitter @seanmylaw and you can stay up-to-date on the development of STUMPY @stumpy_dev. Additionally, please post all of your STUMPY questions to our &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;TDAmeritrade&#x2F;stumpy&#x2F;issues&quot;&gt;Github issues page&lt;&#x2F;a&gt; as this will help ensure that all user questions are recorded and searchable by others. Also, we’re always looking for new contributors and, especially if you are a tech minority, we’d love to work together with you. And don’t forget to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;stumpy.readthedocs.io&#x2F;en&#x2F;latest&#x2F;&quot;&gt;share STUMPY&lt;&#x2F;a&gt; with all of your friends and colleagues and let us know how you are using STUMPY!&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Julia GPU</title>
          <pubDate>Tue, 20 Oct 2020 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/julia-gpu/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/julia-gpu/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/julia-gpu/">&lt;h3 id=&quot;how-the-julia-language-is-making-it-easy-for-programmers-to-use-gpu-capabilities-with-juliagpu&quot;&gt;How the Julia language is making it easy for programmers to use GPU capabilities with JuliaGPU&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-KJX3T1Y9T1Cj0aV3m-A22w.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We are living in a time where more and more data is being created every day as well as new techniques and complex algorithms that try to extract the most out of it. As such, CPU capabilities are approaching a bottleneck in their computing power. GPU computing opened its way into a new paradigm for high-performance and parallel computation a long time ago, but it was not until recently that it become massively used for data science.&lt;br &#x2F;&gt;
In this interview, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;maleadt&quot;&gt;Tim Besard&lt;&#x2F;a&gt;, one of the main contributors to the JuliaGPU project, digs into some of the details about GPU computing and the features that make Julia a language suited for such tasks, not only from a performance perspective but also from a user one.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h4 id=&quot;please-tell-us-a-bit-about-yourself-what-is-your-background-what-is-your-current-position&quot;&gt;Please tell us a bit about yourself. What is your background? what is your current position?&lt;&#x2F;h4&gt;
&lt;p&gt;I’ve always been interested in systems programming, and after obtaining my CS degree I got the opportunity to start a PhD at Ghent University, Belgium, right when Julia was first released around 2012. The language seemed intriguing, and since I wanted to gain some experience with LLVM, I decided to port some image processing research code from MATLAB and C++ to Julia. The goal was to match performance of the C++ version, but some of its kernels were implemented in CUDA C… So obviously Julia needed a GPU back-end!&lt;&#x2F;p&gt;
&lt;p&gt;That was easier said than done, of course, and much of my PhD was about implementing that back-end and (re)structuring the existing Julia compiler to facilitate these additional back-ends. Nowadays I’m at Julia Computing, where I still work on everything GPU-related.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-is-juliagpu-what-is-the-goal-of-the-project&quot;&gt;What is JuliaGPU? What is the goal of the project?&lt;&#x2F;h4&gt;
&lt;p&gt;JuliaGPU is the name we use to group GPU-related resources in Julia: There’s a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;JuliaGPU&quot;&gt;GitHub organization&lt;&#x2F;a&gt; where most packages are hosted, a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;juliagpu.org&#x2F;&quot;&gt;website&lt;&#x2F;a&gt; to point the way for new users, we have &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;JuliaGPU&#x2F;gitlab-ci&quot;&gt;CI infrastructure&lt;&#x2F;a&gt; for JuliaGPU projects, there’s a Slack channel and Discourse category, etc.&lt;&#x2F;p&gt;
&lt;p&gt;The goal of all this is to make it easier to use GPUs for all kinds of users. Current technologies often impose significant barriers to entry: CUDA is fairly tricky to install, C and C++ are not familiar to many users, etc. With the software we develop as part of the JuliaGPU organization, we aim to make it easy to use GPUs, without hindering the ability to optimize or use low-level features that the hardware has to offer.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-is-gpu-computing-how-important-is-it-nowadays&quot;&gt;What is GPU computing? How important is it nowadays?&lt;&#x2F;h4&gt;
&lt;p&gt;GPU computing means using the GPU, a device originally designed for graphics processing, to perform general-purpose computations. It has grown more important now that CPU performance is not improving as steadily as it used to. Instead, specialized devices like GPUs or FPGAs are increasingly used to improve the performance of certain computations. In the case of GPUs, the architecture is a great fit to perform highly-parallel applications. Machine learning networks are a good example of such parallel applications, and their popularity is one of the reasons GPUs have become so important.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;do-you-think-julia-is-an-appropriate-language-to-efficiently-use-gpu-capabilities-why&quot;&gt;Do you think Julia is an appropriate language to efficiently use GPU capabilities? Why?&lt;&#x2F;h4&gt;
&lt;p&gt;Julia’s main advantage is that the language was designed to be compiled. Even though the syntax is high-level, the generated machine code is&lt;br &#x2F;&gt;
compact and has great performance characteristics (for more details, see &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;janvitek.org&#x2F;pubs&#x2F;oopsla18b.pdf&quot;&gt;this paper&lt;&#x2F;a&gt;). This is crucial for GPU execution, where we are required to run native binaries and cannot easily (or efficiently) interpret code as is often required by other language’s semantics.&lt;&#x2F;p&gt;
&lt;p&gt;Because we’re able to directly compile Julia for GPUs, we can use almost all of the language’s features to build powerful abstractions. For example, you can define your own types, use those in GPU arrays, compose that with existing abstractions like lazy “Transpose” wrappers, access those on the GPU while benefiting from automatic bounds-checking (if needed), etc.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;from-a-python-programmer-perspective-how-does-cuda-jl-compare-to-pycuda-are-their-functionalities-equivalent&quot;&gt;From a Python programmer perspective, how does CUDA.jl compare to PyCUDA? Are their functionalities equivalent?&lt;&#x2F;h4&gt;
&lt;p&gt;PyCUDA gives the programmer access to the CUDA APIs, with high-level Python functions that are much easier to use. CUDA.jl provides the same, but in Julia. The &lt;code&gt;hello world&lt;&#x2F;code&gt; from PyCUDA’s home page looks almost identical in Julia:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;using CUDA&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;function multiply_them(dest, a, b)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; i = threadIdx().x&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; dest[i] = a[i] * b[i]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; return&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;a = CuArray(randn(Float32, 400))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;b = CuArray(randn(Float32, 400))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dest = similar(a)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@cuda threads=400 multiply_them(dest, a, b)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;println(dest-a.*b)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There’s one very big difference: “multiply_them” here is a function written in Julia, whereas PyCUDA uses a kernel written in CUDA C. The reason is straightforward: Python is not simple to compile. Of course, projects like Numba prove that it is very much possible to do so, but in the end those are separate compilers that try to match the reference Python compilers as closely as possible. With CUDA.jl, we integrate with that reference compiler, so it’s much easier to guarantee consistent semantics and follow suit when the language changes (for more details,&lt;br &#x2F;&gt;
refer to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;abs&#x2F;1712.03112&quot;&gt;this paper&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;h4 id=&quot;are-the-packages-in-the-juliagpu-organization-targeted-to-experienced-programmers-only&quot;&gt;Are the packages in the JuliaGPU organization targeted to experienced programmers only?&lt;&#x2F;h4&gt;
&lt;p&gt;Not at all. CUDA.jl targets different kinds of (GPU) programmers. If you are confident writing your own kernels, you can do so, while using all of the low-level features CUDA GPUs have to offer. But if you are new to the world of GPU programming, you can use high-level array operations that use existing kernels in CUDA.jl. For example, the above element-wise multiplication could just as well be written as:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;using CUDA&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;a = CuArray(randn(Float32, 400))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;b = CuArray(randn(Float32, 400))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dest = a .* b&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;is-it-necessary-to-know-how-to-code-in-cuda-jl-to-take-full-advantage-of-gpu-computing-in-julia&quot;&gt;Is it necessary to know how to code in CUDA.jl to take full advantage of GPU computing in Julia?&lt;&#x2F;h4&gt;
&lt;p&gt;Not for most users. Julia has a powerful language of generic array operations (“map”, “reduce”, “broadcast”, “accumulate”, etc) which can be applied to all kinds of arrays, including GPU arrays. That means you can often re-use your codebase developed for the CPU with CUDA.jl (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.sciencedirect.com&#x2F;science&#x2F;article&#x2F;abs&#x2F;pii&#x2F;S0965997818310123&quot;&gt;this paper&lt;&#x2F;a&gt; shows some powerful examples). Doing so often requires minimal changes: changing the array type, making sure you use array operations instead of for loops, etc.&lt;&#x2F;p&gt;
&lt;p&gt;It’s possible you need to go beyond this style of programming, e.g., because your application doesn’t map cleanly onto array operations, to use specific GPU features, etc. In that case, some basic knowledge about CUDA and the GPU programming model is sufficient to write kernels in CUDA.jl.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;how-is-the-experience-of-coding-a-kernel-in-cuda-jl-in-comparison-to-cuda-c-and-how-transferable-is-the-knowledge-to-one-another&quot;&gt;How is the experience of coding a kernel in CUDA.jl in comparison to CUDA C and how transferable is the knowledge to one another?&lt;&#x2F;h4&gt;
&lt;p&gt;It’s very similar, and that’s by design: We try to keep the kernel abstractions in CUDA.jl close to their CUDA C counterparts such that the programming environment is familiar to existing GPU programmers. Of course, by using a high-level source language there’s many quality-of-life improvements. You can allocated shared memory, for example, statically and dynamically as in CUDA C, but instead of a raw pointers we use an N-dimensional array object you can easily index. An example from the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;developer.nvidia.com&#x2F;blog&#x2F;using-shared-memory-cuda-cc&#x2F;&quot;&gt;NVIDIA developer blog&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;__global__ void staticReverse(int *d, int n)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; __shared__ int s[64];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; int t = threadIdx.x;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; int tr = n-t-1;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; s[t] = d[t];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; __syncthreads();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; d[t] = s[tr];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The CUDA.jl equivalent of this kernel looks very familiar, but uses array objects instead of raw pointers:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;function staticReverse(d)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; s = @cuStaticSharedMem(Int, 64)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; t = threadIdx().x&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; tr = length(d)-t+1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; s[t] = d[t]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; sync_threads()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; d[t] = s[tr]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; return&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Using array objects has many advantages, e.g. multi-dimensional is greatly simplified and we can just do “d[i,j]”. But it’s also safer, because these accesses are bounds checked:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;julia&amp;gt; a = CuArray(1:64)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;64-element CuArray{Int64,1}:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; ⋮&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 62&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 63&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;julia&amp;gt; @cuda threads=65 staticReverse(a)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ERROR: a exception was thrown during kernel execution.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Stacktrace:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; [1] throw_boundserror at abstractarray.jl:541&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Bounds checking isn’t free, of course, and once we’re certain our code is correct we can add an “@inbounds” annotation to our kernel and get the high-performance code we expect:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;julia&amp;gt; @device_code_ptx @cuda threads=64 staticReverse(a)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.visible .entry staticReverse(.param .align 8 .b8 d[16]) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; .reg .b32 %r&amp;lt;2&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; .reg .b64 %rd&amp;lt;15&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; .shared .align 32 .b8 s[512];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;mov.b64 %rd1, d;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; ld.param.u64 %rd2, [%rd1];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; ld.param.u64 %rd3, [%rd1+8];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; mov.u32 %r1, %tid.x;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; cvt.u64.u32 %rd4, %r1;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; mul.wide.u32 %rd5, %r1, 8;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; add.s64 %rd6, %rd5, -8;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; add.s64 %rd7, %rd3, %rd6;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; ld.global.u64 %rd8, [%rd7+8];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; mov.u64 %rd9, s;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; add.s64 %rd10, %rd9, %rd6;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; st.shared.u64 [%rd10+8], %rd8;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; bar.sync 0;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; sub.s64 %rd11, %rd2, %rd4;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; shl.b64 %rd12, %rd11, 3;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; add.s64 %rd13, %rd9, %rd12;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; ld.shared.u64 %rd14, [%rd13+-8];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; st.global.u64 [%rd7+8], %rd14;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; ret;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;julia&amp;gt; a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;64-element CuArray{Int64,1}:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 63&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 62&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; ⋮&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Tools like “@device_code_ptx” make it easy for an experienced developer to inspect generated code and ensure the compiler does what he wants.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;why-does-having-a-compiler-have-such-an-impact-in-libraries-like-cuda-jl-how-was-the-process-of-integrating-it-to-the-julia-compiler&quot;&gt;Why does having a compiler have such an impact in libraries like CUDA.jl? (How was the process of integrating it to the Julia compiler?)&lt;&#x2F;h4&gt;
&lt;p&gt;Because we have a compiler at our disposal, we can rely on higher-order functions and other generic abstractions that specialize based on the arguments that users provide. That greatly simplifies our library, but also gives the user very powerful tools. As an example, we have carefully implemented a &lt;code&gt;mapreduce&lt;&#x2F;code&gt; function that uses shared memory, warp intrinsics, etc to perform a high-performance reduction. The implementation is generic though, and will automatically re-specialize (even at run time) based on the arguments to the function:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;julia&amp;gt; mapreduce(identity, +, CuArray([1,2,3]))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;julia&amp;gt; mapreduce(sin, *, CuArray([1.1,2.2,3.3]))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-0.11366175839582586&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With this powerful &lt;code&gt;mapreduce&lt;&#x2F;code&gt; abstraction, implemented by a experienced GPU programmer, other developers can create derived abstractions without such experience. For example, let’s implement a &lt;code&gt;count&lt;&#x2F;code&gt; function that evaluates for how many items a predicate holds true:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;count(predicate, array) = mapreduce(predicate, +, array)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;julia&amp;gt; a = CUDA.rand(Int8, 4)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4-element CuArray{Int8,1}:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 51&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 70&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 100&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;julia&amp;gt; count(iseven, a)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Even though our &lt;code&gt;mapreduce&lt;&#x2F;code&gt; implementation has not been specifically implemented for the &lt;code&gt;Int8&lt;&#x2F;code&gt; type or the &lt;code&gt;iseven&lt;&#x2F;code&gt; predicate, the Julia compiler automatically specializes the implementation, resulting in kernel optimized for this specific invocation.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-were-the-biggest-challenges-when-developing-packages-for-juliagpu-particularly-writing-a-low-level-package-such-as-cuda-jl-in-a-high-level-programming-language-such-as-julia&quot;&gt;What were the biggest challenges when developing packages for JuliaGPU, particularly writing a low level package such as CUDA.jl in a high level programming language such as Julia?&lt;&#x2F;h4&gt;
&lt;p&gt;Much of the initial work focused on developing tools that make it possible to write low-level code in Julia. For example, we developed the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;maleadt&#x2F;LLVM.jl&quot;&gt;LLVM.jl&lt;&#x2F;a&gt; package that gives us access to the LLVM APIs. Recently, our focus has shifted towards generalizing this functionality so that other GPU back-ends, like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;JuliaGPU&#x2F;AMDGPU.jl&quot;&gt;AMDGPU.jl&lt;&#x2F;a&gt; or &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;JuliaGPU&#x2F;oneAPI.jl&quot;&gt;oneAPI.jl&lt;&#x2F;a&gt; can benefit from developments to CUDA.jl. Vendor-neutral array operations, for examples, are now implemented in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;JuliaGPU&#x2F;GPUArrays.jl&quot;&gt;GPUArrays.jl&lt;&#x2F;a&gt; whereas shared compiler functionality now lives in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;JuliaGPU&#x2F;GPUCompiler.jl&quot;&gt;GPUCompiler.jl&lt;&#x2F;a&gt;. That should make it possible to work on several GPU back-ends, even though most of them are maintained by only a single developer.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;regarding-the-latest-release-announced-in-the-juliagpu-blog-about-multi-device-programming-what-are-the-difficulties-that-this-new-functionality-solves-is-this-relevant-in-the-industry-where-big-computational-resources-are-needed&quot;&gt;Regarding the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;juliagpu.org&#x2F;2020-07-18-cuda_1.3&#x2F;&quot;&gt;latest release&lt;&#x2F;a&gt; announced in the JuliaGPU blog about multi-device programming, what are the difficulties that this new functionality solves? Is this relevant in the industry where big computational resources are needed?&lt;&#x2F;h4&gt;
&lt;p&gt;In industry or large research labs, MPI is often used to distribute work across multiple nodes or GPUs. Julia’s MPI.jl supports that use case, and integrates with CUDA.jl where necessary. The multi-device functionality added to CUDA 1.3 additionally makes it possible to use multiple GPUs within a single process. It maps nicely on Julia’s task-based concurrency, and makes it easy to distribute work within a single node:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Threads.@threads for dev in devices()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; device!(dev)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; # do some work here&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;what-are-the-plans-for-the-near-future&quot;&gt;&lt;strong&gt;What are the plans for the near future?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;There aren’t any specific roadmaps, but one upcoming major feature is proper support for reduced-precision inputs, like 16-bits floating point. We already support Float16 arrays where CUBLAS or CUDNN does, but the next version of Julia will make it possible to write kernels that operate on these values.&lt;&#x2F;p&gt;
&lt;p&gt;Other than that, features come as they do :-) Be sure to subscribe to the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;juliagpu.org&#x2F;post&#x2F;&quot;&gt;JuliaGPU blog&lt;&#x2F;a&gt; where we publish a short post for every major release of Julia’s GPU back-ends.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;You can find Tim at @&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;maleadt&quot;&gt;maleadt&lt;&#x2F;a&gt; on Twitter!&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>SymJAX: symbolic CPU&#x2F;GPU&#x2F;TPU programming</title>
          <pubDate>Fri, 18 Sep 2020 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/symjax-symbolic-cpu-gpu-tpu-programming/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/symjax-symbolic-cpu-gpu-tpu-programming/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/symjax-symbolic-cpu-gpu-tpu-programming/">&lt;h4 id=&quot;a-symbolic-programming-version-of-jax&quot;&gt;A symbolic programming version of JAX&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-U2wpT5qoWqSOwrgYtgLJ3w.png&quot; alt=&quot;&quot; &#x2F;&gt;SymJAX’s really cool logo&lt;&#x2F;p&gt;
&lt;p&gt;As we try to have a deeper undestanding of the world we live in, we tend to add more and more complex relationships in the models we use to describe it, so we need to borrow a hand from computers to run them.&lt;&#x2F;p&gt;
&lt;p&gt;Complex relationships often are represented in form of graphs and many learning algorithms require differentiation of some kind.&lt;&#x2F;p&gt;
&lt;p&gt;We also don’t want to lose mathematical interpretability, so having a symbolic programming framework that allows us to represent these complex models in a familiar way, provided with a Theano-like user experience, would be a very interesting tool to have in our pocket.&lt;&#x2F;p&gt;
&lt;p&gt;This is what SymJax has come to offer us. To know more about this, we interviewed &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;RandallBalestriero&quot;&gt;Randall Balestriero&lt;&#x2F;a&gt; the creator and sole contributor of the project so far.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-is-symjax&quot;&gt;What is SymJAX?&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;RandallBalestriero&#x2F;SymJAX&quot;&gt;SymJAX&lt;&#x2F;a&gt; is a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;networkx.github.io&#x2F;&quot;&gt;NetworkX&lt;&#x2F;a&gt; powered symbolic programming version of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;google&#x2F;jax&quot;&gt;JAX&lt;&#x2F;a&gt; providing a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Theano&#x2F;Theano&quot;&gt;Theano&lt;&#x2F;a&gt;-like user experience. In addition of simplifying graph input&#x2F;output, variable updates and providing graph utilities such as loading and saving, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;RandallBalestriero&#x2F;SymJAX&quot;&gt;SymJAX&lt;&#x2F;a&gt; features machine learning and deep learning utilities similar to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Lasagne&#x2F;Lasagne&quot;&gt;Lasagne&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.tensorflow.org&#x2F;&quot;&gt;Tensorflow1&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Illustrative example: Adam optimizer of a dummy loss&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;import symjax&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;import symjax.tensor as T&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;from symjax.nn.optimizers import Adam&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# we create a persistent variable to be optimized&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;z = T.Variable(3.0, dtype=”float32&amp;quot;, trainable=True)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# the optimization is about minimizing the following loss&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;loss = T.power(z — 1, 2, name=&amp;#39;loss&amp;#39;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# this loss is just a node in the graph, nothing is computed yet&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;print(loss) # Op(name=loss, fn=power, shape=(), dtype=float32, scope=&#x2F;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# we minimize it with Adam, we can omit to assign it to a variable since the&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# internal updates are automatically collected, 0.1 is the learning rate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Adam(loss, 0.1)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# we create the function (XLA compiled graph) and define what are the inputs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# (here none), the outputs and the persistent variable updates (from Adam)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;train = symjax.function(outputs=[loss, z], updates=symjax.get_updates())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# for illustrative purposes, we perform 200 steps and reset the graph after 100 steps&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;for i in range(200):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  if (i + 1) % 100 == 0:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  # we can use any identifier to select what to reset, (&amp;#39;*&amp;#39; is the default)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  # if we want to only reset the variables create by Adam&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  # (the moving averages etc) one would use (for example)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  # symjax.reset_variables(&#x2F;AdamOptimizer*&amp;#39;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  # in our case let reset all variables&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  symjax.reset_variables()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  # the output of this function is the current loss and value of z, and when called it also&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  # internally perform the given updates computed from Adam&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  train()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For additional examples please see: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;symjax.readthedocs.io&#x2F;en&#x2F;latest&#x2F;auto_examples&#x2F;&quot;&gt;https:&#x2F;&#x2F;symjax.readthedocs.io&#x2F;en&#x2F;latest&#x2F;auto_examples&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;the-symjax-documentation-reads-the-number-of-libraries-topping-jax-tensorflow-torch-is-large-and-growing-by-the-day-what-symjax-offers-as-opposed-to-most-is-an-all-in-one-library-with-diverse-functionalities-what-s-the-main-issue-with-having-to-use-multiple-libraries-and-how-does-creating-a-single-library-solve-it&quot;&gt;The SymJAX documentation reads: “The number of libraries topping Jax&#x2F;Tensorflow&#x2F;Torch is large and growing by the day. What SymJAX offers as opposed to most is an all-in-one library with diverse functionalities”. What’s the main issue with having to use multiple libraries and how does creating a single library solve it?&lt;&#x2F;h4&gt;
&lt;p&gt;There is absolutely nothing wrong with having complementary libraries that can be interconnected. In my opinion the current limitation of the mentioned libraries is the absence of inter-compatibility making it difficult to use features from one with another. This is different than say numpy and scipy who both complement each other seamlessly. In SymJAX, the JAX backend allows for any JAX library to be directly imported into SymJAX (as were C&#x2F;CUDA code easily imported into Theano). Second, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.tensorflow.org&#x2F;probability&#x2F;api_docs&#x2F;python&#x2F;tfp&#x2F;experimental&#x2F;substrates&#x2F;jax&quot;&gt;Tensorflow is increasingly leveraging a JAX backend&lt;&#x2F;a&gt;, this development will also allow to easily import those Tensorflow utilities into SymJAX. People interested in using a standard JAX&#x2F;Tensorflow library while benefiting from SymJAX utilities can do so easily. The other way around, any computational graph designed in SymJAX with SymJAX utilities can also be translated back into pure JAX, allowing JAX libraries to benefit from SymJAX. The target end result being that each library newly developed tool would directly benefit all cross-library users.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;the-documentation-states-that-one-of-the-goals-of-symjax-is-to-optimize-processes-how-does-the-library-enable-that-optimization-how-does-it-compare-to-other-technologies&quot;&gt;The documentation states that one of the goals of SymJAX is to optimize processes. How does the library enable that optimization? How does it compare to other technologies?&lt;&#x2F;h4&gt;
&lt;p&gt;There are really two levels of (computational) optimization in SymJAX. First, SymJAX allows to define a computational graph which can be viewed as a computational roadmap based on inputs and operations producing some desired outputs (possibly involving some persistent graph variable updates). This user-defined computational roadmap is obtained without performing any actual computation yet. It is then compiled with XLA producing a sequence of computation kernels generated specifically for the given graph. This step allows to potentially merge multiple low-level operations into a single kernel and demonstrated performances gains for example &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.tensorflow.org&#x2F;xla&#x2F;&quot;&gt;in Tensorflow&lt;&#x2F;a&gt;. This step alone provides SymJAX with similar performances to Jax and XLA-Tensorflow, ceteris paribus.&lt;&#x2F;p&gt;
&lt;p&gt;The second and most important feature of SymJAX is its graph canonicalization. This feature is the same as the one that was employed in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.deeplearning.net&#x2F;software&#x2F;theano&#x2F;&quot;&gt;now-discontinued Theano library&lt;&#x2F;a&gt;. Graph canonicalization allows generic graph optimization such as replacing the following subgraph:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;log( exp(x) * exp(4 + x) )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;by the much simpler, yet equivalent subgraph:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2 * x + 4&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This type of graph simplification can be done on much more complex parts of the graphs such as replacing the sum of two Gaussian distributions by a single Gaussian with different mean and covariance; hence greatly reducing the computational burden of random sampling. This reduced graph is then XLA compiled further optimizing low-level operations. This feature allows for much broader optimization than present in XLA and in most current libraries as it requires &lt;em&gt;a priori&lt;&#x2F;em&gt; knowledge of the computational graph.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;does-symjax-support-all-state-of-art-neural-network-architectures&quot;&gt;Does SymJAX support all state-of-art neural network architectures?&lt;&#x2F;h4&gt;
&lt;p&gt;SymJAX provides out-of-the-box some basic neural network layers implementations. The number of implemented layers increases at each release but can surely not follow the exponentially growing number of neural network flavours being designed by the deep learning community. However, the core of SymJAX provides all the standard operations featuring almost all numpy and scipy functions among many more. This allows anyone to implement their own layers and neural networks (as well as losses or any other bit of a deep learning pipelines) ensuring that any needed architecture can be implemented on-the-go.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-were-the-biggest-challenges-in-allowing-a-broad-hardware-support-gpus-tpus&quot;&gt;What were the biggest challenges in allowing a broad hardware support (GPUs, TPUs)?&lt;&#x2F;h4&gt;
&lt;p&gt;One of the crucial benefit of leveraging JAX as the backend XLA interface is the ability to benefit from their latest hardware support. There was thus nothing additional needed in SymJAX to enable such broad support.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;is-there-support-for-dynamic-computation-graphs-a-la-pytorch-if-not-are-there-any-plans-for-it&quot;&gt;Is there support for dynamic computation graphs à la Pytorch? If not, are there any plans for it?&lt;&#x2F;h4&gt;
&lt;p&gt;The computational graph in itself can be evaluated without XLA compilation allowing one to define a graph, evaluate it, and keep building it while evaluating it again (similar to session.run from Tensorflow 1). This would not give optimal performances but can be useful in some cases and would allow very general dynamic computation graphs. For best performances however the graph needs to be compiled effectively freezing its structure. However, we do allow for one dynamic aspect to persist after compilation: dynamic leading axis length (such as variable batch size). This allows, if needed, to have a compiled graph with the possibility to feed shape varying inputs. For now this is only possible on the leading axis but more general dynamic computation graphs will be considered in the future by allowing only the parts of the graph that will not vary dynamically to be compiled separately allowing for high-performance “hybrid” graphs to be evaluated.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;symjax-pays-homage-to-theano-in-many-aspects-what-s-different-from-theano-and-why-not-improve-theano-to-bring-it-up-to-date-instead-of-creating-a-new-library-from-scratch&quot;&gt;SymJAX pays homage to Theano in many aspects. What’s different from Theano and why not improve Theano to bring it up to date instead of creating a new library from scratch?&lt;&#x2F;h4&gt;
&lt;p&gt;The minimalist version of SymJAX and Theano both make the user define a graph, compile it and then evaluate it. However, SymJAX offers various user-friendly features that greatly simplify its use as opposed to Theano such as&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;much simpler graph construction and monitoring with explicit shape and dtype of each node&lt;&#x2F;li&gt;
&lt;li&gt;lazy (non compiled) partial graph evaluation (a la session.run or pytorch)&lt;&#x2F;li&gt;
&lt;li&gt;the concept of scopes (a la Tensorflow) and node&#x2F;variable&#x2F;placeholder fetching based on their names and scopes&lt;&#x2F;li&gt;
&lt;li&gt;utilities to save, load and reset variables and graphs&lt;&#x2F;li&gt;
&lt;li&gt;various graph analysis tools from networkX that can be used to study the computational graph and provide in-depth structural analysis&lt;&#x2F;li&gt;
&lt;li&gt;side utilities to allow deep learning pipelines to be built&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The option of updating Theano was considered but would have forced to not only implement the above features (requiring some important changes in the Theano design) but would also force us to consistently keep working on the XLA interface&#x2F;compilation and on the support for the latest hardwares including not only new GPU releases but also novel hardwares like TPUs. By instead building upon Jax XLA interface, we directly benefit from the latest XLA support allowing us to focus instead on additional features and graph related utilities.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;theano-is-powerful-but-in-terms-of-popularity-it-lost-the-battle-to-the-more-high-level-tensorflow-what-is-the-user-you-have-in-mind-for-symjax-how-is-it-better-than-the-other-options&quot;&gt;Theano is powerful but in terms of popularity it lost the battle to the more high-level TensorFlow. What is the user you have in mind for SymJAX? How is it better than the other options?&lt;&#x2F;h4&gt;
&lt;p&gt;As per the above points, I believe that Theano lost attraction due to its lack of user-friendly features making it too tedious to build a working pipeline as opposed to Tensorflow (or PyTorch) which allowed for a more flexible set-up thanks to features like automatically gathering trainable variables to be differentiated, automatically resetting all the graph variables without keeping track of them explicitly and so on. In addition Theano suffered from a very slow compilation step and often difficult GPU-support installation.&lt;&#x2F;p&gt;
&lt;p&gt;However, none denies the benefits of Theano in term of its graph simplification abilities and its design. By combining the best of both libraries and incorporating additional JAX abilities, you obtain SymJAX which I believe will attract users from any background. In fact, one of the main effort in SymJAX is to make the symbolic programming paradigm extremely user-friendly allowing anyone to employ it with minimum burden while enjoying all the induced benefits.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;how-many-people-are-behind-this-project-are-you-looking-for-contributors&quot;&gt;How many people are behind this project? Are you looking for contributors?&lt;&#x2F;h4&gt;
&lt;p&gt;I have been the sole contributor of this project up until recently when a geophysicist colleague stepped in. There has also been a rising interest from the PyMC developer team to see how fit would be SymJAX to replace the Theano backend they employed. This ongoing discussion also allowed for additional contributions to SymJAX. All contributions are welcome and anyone interested in getting involved more actively with this project should feel free to contact me!&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-is-symjax-s-current-status-and-plans-for-the-near-future-how-close-is-the-project-to-its-first-stable-release&quot;&gt;What is SymJAX’s current status and plans for the near future? How close is the project to its first stable release?&lt;&#x2F;h4&gt;
&lt;p&gt;SymJAX has been unstable in its early months as many graph libraries were tested and various new features required drastic changes in the entire pipeline. We now are at a much more stable point where only a few remaining features are being tested and replaced (for example the graph visualization tool, the online data saving and visualization, and the graph canonicalization). But those changes are very localized in the library and do not break any other part of the library when changed. In its current state, SymJAX can already be used actively. In addition, the main remaining task is around documentation, and providing a rich Gallery of examples detailing all the functionalities of SymJAX. Once those changes are done, the first stable release will be published; a rough estimate would put us a few weeks away from it.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;for-our-readers-who-might-want-to-know-more-what-papers-articles-and-courses-do-you-recommend-doing-to-learn-about-symbolic-programming-and-deep-learning&quot;&gt;For our readers who might want to know more, what papers, articles and courses do you recommend doing to learn about symbolic programming and deep learning?&lt;&#x2F;h4&gt;
&lt;p&gt;For a jump-start in deep learning, the Deep Learning book (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.deeplearningbook.org&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.deeplearningbook.org&#x2F;&lt;&#x2F;a&gt;) is complete and offers all the tricks of the trade for practitioners. For more in-depth understanding of deep networks there are way too many articles to cite so I will only refer to a few iconic ones in two topics that I particularly enjoy:&lt;&#x2F;p&gt;
&lt;p&gt;Orbits, Groups, Invariants and Manifolds&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;yann.lecun.com&#x2F;exdb&#x2F;publis&#x2F;pdf&#x2F;simard-98.pdf&quot;&gt;http:&#x2F;&#x2F;yann.lecun.com&#x2F;exdb&#x2F;publis&#x2F;pdf&#x2F;simard-98.pdf&lt;&#x2F;a&gt; (Transformation Invariance in Pattern Recognition, Tangent Distance and Tangent Propagation)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;pdf&#x2F;1602.07576.pdf&quot;&gt;https:&#x2F;&#x2F;arxiv.org&#x2F;pdf&#x2F;1602.07576.pdf&lt;&#x2F;a&gt; (Group Equivariant Convolutional Networks)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;pdf&#x2F;1203.1513.pdf&quot;&gt;https:&#x2F;&#x2F;arxiv.org&#x2F;pdf&#x2F;1203.1513.pdf&lt;&#x2F;a&gt; (Invariant Scattering Convolution Networks)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;ai.stanford.edu&#x2F;~ang&#x2F;papers&#x2F;nips09-MeasuringInvariancesDeepNetworks.pdf&quot;&gt;https:&#x2F;&#x2F;ai.stanford.edu&#x2F;~ang&#x2F;papers&#x2F;nips09-MeasuringInvariancesDeepNetworks.pdf&lt;&#x2F;a&gt; (Measuring Invariances in Deep Networks)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Deep Generative Networks&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;pdf&#x2F;1701.00160.pdf&quot;&gt;https:&#x2F;&#x2F;arxiv.org&#x2F;pdf&#x2F;1701.00160.pdf&lt;&#x2F;a&gt; (NIPS 2016 Tutorial:Generative Adversarial Networks)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pure.uva.nl&#x2F;ws&#x2F;files&#x2F;17891313&#x2F;Thesis.pdf&quot;&gt;https:&#x2F;&#x2F;pure.uva.nl&#x2F;ws&#x2F;files&#x2F;17891313&#x2F;Thesis.pdf&lt;&#x2F;a&gt; (Variational inference &amp;amp; deep learning)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;blog.evjang.com&#x2F;2018&#x2F;01&#x2F;nf1.html&quot;&gt;https:&#x2F;&#x2F;blog.evjang.com&#x2F;2018&#x2F;01&#x2F;nf1.html&lt;&#x2F;a&gt; (Normalizing Flows Tutorial)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>For the first time, enjoy all the talks of BuzzConf 2020 online and free of charge!</title>
          <pubDate>Sun, 26 Jul 2020 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/for-the-first-time-enjoy-all-the-talks-of-buzzconf-2020-online-and-free-of-charge/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/for-the-first-time-enjoy-all-the-talks-of-buzzconf-2020-online-and-free-of-charge/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/for-the-first-time-enjoy-all-the-talks-of-buzzconf-2020-online-and-free-of-charge/">&lt;h3 id=&quot;come-see-buzzconf-2020-a-software-and-data-science-conference-open-and-online-for-one-and-for-all&quot;&gt;Come see BuzzConf 2020, a software and data science conference, open and online for one and for all!&lt;&#x2F;h3&gt;
&lt;p&gt;The third edition of BuzzConf will be held freely online via Zoom and Youtube live. We’re very proud of our speaker lineup, which covers a wide range of topics that expand the frontiers of our technical knowledge.&lt;&#x2F;p&gt;
&lt;p&gt;We will dive into the topics of functional programming, Julia, Python, data science, machine learning, observability, operating systems and more! We believe Functional Programming and Data Science are two of the most interesting topics in the field which will open many opportunities in the near future, and we want to bring the latest developments in these areas to the global community.&lt;&#x2F;p&gt;
&lt;p&gt;This conference is the result of a combined effort of private and public sectors from Argentina, which aspires to help the development of our country’s technical capabilities while spreading and sharing knowledge with the world.&lt;&#x2F;p&gt;
&lt;p&gt;We thank the generosity of the speakers who agreed to donate their time and we hope you enjoy their talks as much as we will.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-LzNJkTEcILfT_6U8t2baDg.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;mon-july-27-2pm-pdt-6pm-gmt-3-9pm-utc&quot;&gt;Mon, July 27–2pm PDT &#x2F; 6pm GMT-3 &#x2F; 9pm UTC&lt;&#x2F;h3&gt;
&lt;h3 id=&quot;charity-majors-what-got-you-here-won-t-get-you-there-how-your-team-can-become-a-high-performing-team-by-embracing-observability&quot;&gt;Charity Majors — “What got you here won’t get you there: How your team can become a high-performing team by embracing observability”&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;em&gt;To Be Announced&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Join us on Zoom:&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;zoom.us&#x2F;j&#x2F;92898927496&quot;&gt;&lt;em&gt;https:&#x2F;&#x2F;zoom.us&#x2F;j&#x2F;92898927496&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Join us on YouTube:&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;QK6zEFdvXYw&quot;&gt;&lt;em&gt;https:&#x2F;&#x2F;youtu.be&#x2F;QK6zEFdvXYw&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;0-fTWA2R7HUM90oPA7.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;mon-july-27-3pm-pdt-7pm-gmt-3-10pm-utc&quot;&gt;Mon, July 27–3pm PDT &#x2F; 7pm GMT-3 &#x2F; 10pm UTC&lt;&#x2F;h3&gt;
&lt;h3 id=&quot;maria-vanina-martinez-symbolic-reasoning-to-model-sentiment-and-knowledge-diffusion-in-social-networks&quot;&gt;María Vanina Martinez: “Symbolic Reasoning to model Sentiment and Knowledge Diffusion in Social Networks”&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;em&gt;Social media platforms, taken in conjunction, can be seen as complex networks; in this context, understanding how agents react to sentiments expressed by their connections is of great interest. We show how Network Knowledge Bases help represent the integration of multiple social networks, and explore how information flow can be handled via belief revision operators for local (agent-specific) knowledge bases. We report on preliminary experiments on Twitter data showing that different agent types react differently to the same information — this is a first step toward developing symbolic tools to predict how agents behave asinformation flows in their social environment.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Join us on Zoom:&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;zoom.us&#x2F;j&#x2F;92898927496&quot;&gt;&lt;em&gt;https:&#x2F;&#x2F;zoom.us&#x2F;j&#x2F;92898927496&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Join us on YouTube:&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;QK6zEFdvXYw&quot;&gt;&lt;em&gt;https:&#x2F;&#x2F;youtu.be&#x2F;QK6zEFdvXYw&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;0-Urum4vQ0RP0TZub3.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;tue-july-28-2pm-pdt-6pm-gmt-3-9pm-utc&quot;&gt;Tue, July 28–2pm PDT &#x2F; 6pm GMT-3 &#x2F; 9pm UTC&lt;&#x2F;h3&gt;
&lt;h3 id=&quot;will-kurt-the-limits-of-probability&quot;&gt;Will Kurt: “The Limits of Probability”&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;em&gt;Probability is an increasingly ubiquitous part of our daily lives, especially as developers, researchers and data scientists. It is easy to mistakenly think this powerful tool is all we need to understand our world. This talk will show how our current environment of global pandemic, political unrest and economic uncertainty forces us to face the limits of probability as a tool for reasoning and understanding. This talk will cover both practical examples of the limitations of probability as well as dive into the philosophical roots of these limitations to show that it cannot be our only means to engage with our world.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Join us on Zoom:&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;zoom.us&#x2F;j&#x2F;97859783809&quot;&gt;&lt;em&gt;https:&#x2F;&#x2F;zoom.us&#x2F;j&#x2F;97859783809&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Join us on YouTube:&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;N75ebGWz2o4&quot;&gt;&lt;em&gt;https:&#x2F;&#x2F;youtu.be&#x2F;N75ebGWz2o4&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;0-a3kX6m-ky8tQK27S.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;tue-july-28-3pm-pdt-7pm-gmt-3-10pm-utc&quot;&gt;Tue, July 28–3pm PDT &#x2F; 7pm GMT-3 &#x2F; 10pm UTC&lt;&#x2F;h3&gt;
&lt;h3 id=&quot;lightning-talks&quot;&gt;Lightning Talks&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Juan Pablo Lorenzo:&lt;&#x2F;strong&gt; “Delete your code: in search of a minimalist approach to software development”&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Gajendra Deshpande:&lt;&#x2F;strong&gt; “Computation Techniques for Encrypted Data using Python”&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Join us on Zoom:&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;zoom.us&#x2F;j&#x2F;97859783809&quot;&gt;&lt;em&gt;https:&#x2F;&#x2F;zoom.us&#x2F;j&#x2F;97859783809&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Join us on YouTube:&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;N75ebGWz2o4&quot;&gt;&lt;em&gt;https:&#x2F;&#x2F;youtu.be&#x2F;N75ebGWz2o4&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;wed-july-29-2pm-pdt-6pm-gmt-3-9pm-utc&quot;&gt;Wed, July 29–2pm PDT &#x2F; 6pm GMT-3 &#x2F; 9pm UTC&lt;&#x2F;h3&gt;
&lt;h3 id=&quot;aditya-siram-what-fp-can-learn-from-static-introspection&quot;&gt;Aditya Siram: “What FP Can Learn From Static Introspection”&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;em&gt;What if compile time and type level programming in functional programming languages were easy, something you reach for without even thinking about it? What if you could debug type errors with a simple compile time print statement? Write highly flexible systems by being able to introspect into types at compile time? Pre-calculate large portions of your programs for great efficiency? Typed functional programming is a great and fun way to write resilient software, and as type systems have become more and more expressive in recent years, we are able to program sophisticated and useful properties at the type level for even better compile time safety. Just one problem: It is very difficult, requires advanced knowledge of the type system, the syntax is convoluted, the error messages are impenetrable, and it is nearly impossible to debug. This talk will dive into why we should steal static introspection from languages like Nim, and D, state-of-the-art imperative programming languages which can solve all these issues, make type systems much more approachable without losing any expressive power, and offer new design possibilities for functional programs.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Join us on Zoom:&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;zoom.us&#x2F;j&#x2F;95139644343&quot;&gt;&lt;em&gt;https:&#x2F;&#x2F;zoom.us&#x2F;j&#x2F;95139644343&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Join us on YouTube:&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;yGq0KnkqOgI&quot;&gt;&lt;em&gt;https:&#x2F;&#x2F;youtu.be&#x2F;yGq0KnkqOgI&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;0-Koxyxq-wrBx9iGfe.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;wed-july-29-3pm-pdt-7pm-gmt-3-10pm-utc&quot;&gt;Wed, July 29–3pm PDT &#x2F; 7pm GMT-3 &#x2F; 10pm UTC&lt;&#x2F;h3&gt;
&lt;h3 id=&quot;sergio-chouhy-deeploying-deep-q-learning-with-pytorch&quot;&gt;Sergio Chouhy: “Deeploying Deep Q Learning with Pytorch”&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;em&gt;Many things are being said about Deep Reinforcement Learning, but sometimes it is really hard to know where to start. In this talk, I will tell you all about the basis of this algorithms and show you how to deploy Deep Q Learning from scratch using Pytorch. I will be also talking about industrial applications for this technology.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Join us on Zoom:&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;zoom.us&#x2F;j&#x2F;95139644343&quot;&gt;&lt;em&gt;https:&#x2F;&#x2F;zoom.us&#x2F;j&#x2F;95139644343&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Join us on YouTube:&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;yGq0KnkqOgI&quot;&gt;&lt;em&gt;https:&#x2F;&#x2F;youtu.be&#x2F;yGq0KnkqOgI&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;0-82lbeMCqONPXiKq1.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;thu-july-30-2pm-pdt-6pm-gmt-3-9pm-utc&quot;&gt;Thu, July 30–2pm PDT &#x2F; 6pm GMT-3 &#x2F; 9pm UTC&lt;&#x2F;h3&gt;
&lt;h3 id=&quot;viral-b-shah-julia-a-language-for-ai-and-much-more&quot;&gt;Viral B. Shah: “Julia — A language for AI and much more”&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;em&gt;The Julia language is now used by over half a million programmers worldwide. Created to solve the two language problem, Julia is demonstrating performance gains of 50x-100x for many data science tasks such as data loading, data processing, graph processing, machine learning and scaling. Robust support for modern deep learning and the ability to do differentiable programming in an intuitive way is quickly leading to Julia becoming the language of choice for AI workloads. My talk will discuss the origin story of Julia, the formation of the Julia community, and all the amazing things happening in the world of Julia.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Join us on Zoom:&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;zoom.us&#x2F;j&#x2F;94906592252&quot;&gt;&lt;em&gt;https:&#x2F;&#x2F;zoom.us&#x2F;j&#x2F;94906592252&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Join us on YouTube:&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;fbKHLdoG7wA&quot;&gt;&lt;em&gt;https:&#x2F;&#x2F;youtu.be&#x2F;fbKHLdoG7wA&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;0--gyZtKfGpWBIxRoz.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;thu-july-30-3pm-pdt-7pm-gmt-3-10pm-utc&quot;&gt;Thu, July 30–3pm PDT &#x2F; 7pm GMT-3 &#x2F; 10pm UTC&lt;&#x2F;h3&gt;
&lt;h3 id=&quot;chris-rackauckas-sciml-how-language-is-changing-scientific-research&quot;&gt;Chris Rackauckas: “SciML: How Language is Changing Scientific Research”&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;em&gt;Scientific machine learning is a burgeoning field and its taking off in Julia. Why? The purpose of this talk is to dive into that question: how has language accelerated the development of Julia’s SciML ecosystem? The core is composibility through multiple dispatch. We will showcase how this feature is not only what makes standard Julia code as fast as C or Fortran, but also allows Julia to eschew the traditional idea of “machine learning frameworks” and instead have machine learning directly work on the standard functions and libraries of the whole Julia programming language. This language-wide differentiable programming then builds a foundation where existing climate models, helicopter simulations, and efficiency simulators for battery-powered airplanes can be instantly composed with new tools for machine learning, and we will demonstrate how this has changed the way that researchers in Julia do science.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Join us on Zoom:&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;zoom.us&#x2F;j&#x2F;94906592252&quot;&gt;&lt;em&gt;https:&#x2F;&#x2F;zoom.us&#x2F;j&#x2F;94906592252&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Join us on YouTube:&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;fbKHLdoG7wA&quot;&gt;&lt;em&gt;https:&#x2F;&#x2F;youtu.be&#x2F;fbKHLdoG7wA&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;0-2EbV5-0r03R6aPYH.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;fri-july-31-2pm-pdt-6pm-gmt-3-9pm-utc&quot;&gt;Fri, July 31–2pm PDT &#x2F; 6pm GMT-3 &#x2F; 9pm UTC&lt;&#x2F;h3&gt;
&lt;h3 id=&quot;pablo-fernandez-machine-learning-in-the-real-world&quot;&gt;Pablo Fernandez: “Machine Learning in The Real World”&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;em&gt;A tour of the last 3 years of my career where I’ve productionized 3 different machine learning projects on kind-of-a-big-company (Despegar). Some of the challenges faced, not only technical but also from a product standpoint, some of the pedagogical work needed to convince others of letting important decisions be made by a machine. Hopefully insights that help you bring your own models to production.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Join us on Zoom:&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;zoom.us&#x2F;j&#x2F;92628004626&quot;&gt;&lt;em&gt;https:&#x2F;&#x2F;zoom.us&#x2F;j&#x2F;92628004626&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Join us on YouTube:&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;t-ebpSHyBEE&quot;&gt;&lt;em&gt;https:&#x2F;&#x2F;youtu.be&#x2F;t-ebpSHyBEE&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;0-7y4gqQ8d8_6veW_j.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;fri-july-31-3pm-pdt-7pm-gmt-3-10pm-utc&quot;&gt;Fri, July 31–3pm PDT &#x2F; 7pm GMT-3 &#x2F; 10pm UTC&lt;&#x2F;h3&gt;
&lt;h3 id=&quot;peter-alvaro-what-not-where-why-a-blue-sky-os&quot;&gt;Peter Alvaro: “What not where: why a blue sky OS?”&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;em&gt;A world of distributed, persistent memory is on its way. Our programming models traditionally operate on short-lived data representations tied to ephemeral contexts such as processes or computers. In the limit, however, data lifetime is infinite compared to these transient actors. We discuss the implications for programming models raised by a world of large and potentially persistent distributed memories, including the need for explicit, context-free, invariant data references. We present a novel operating system that uses wisdom from both storage and distributed systems to center the programming model around data as the primary citizen, and reflect on the transformative potential of this change for infrastructure and applications of the future.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Join us on Zoom:&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;zoom.us&#x2F;j&#x2F;92628004626&quot;&gt;&lt;em&gt;https:&#x2F;&#x2F;zoom.us&#x2F;j&#x2F;92628004626&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Join us on YouTube:&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;t-ebpSHyBEE&quot;&gt;&lt;em&gt;https:&#x2F;&#x2F;youtu.be&#x2F;t-ebpSHyBEE&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;0-MOD81ymGRUNUrv7m.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We hope to see you there! There will be time for Q&amp;amp;A with the speakers. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.eventbrite.com.ar&#x2F;e&#x2F;buzzconf-2020-tickets-111836742708&quot;&gt;Register now&lt;&#x2F;a&gt;!&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Soss: Probabilistic Programming with Julia</title>
          <pubDate>Tue, 19 May 2020 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/soss-probabilistic-programming-with-julia/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/soss-probabilistic-programming-with-julia/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/soss-probabilistic-programming-with-julia/">&lt;h4 id=&quot;an-interview-with-its-creator-chad-scherrer&quot;&gt;An interview with its creator, Chad Scherrer&lt;&#x2F;h4&gt;
&lt;p&gt;By: Javier Rodríguez Chatruc and Federico Carrone&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-m6924vcooeuQEu7FiBOI5A.png&quot; alt=&quot;&quot; &#x2F;&gt;Credit: Chad Scherrer&lt;&#x2F;p&gt;
&lt;p&gt;Probabilistic programming is at this point an established field both for research and industry applications, but like everything else (especially in the tech industry), it is undergoing constant evolution. This is where &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;julialang.org&#x2F;&quot;&gt;Julia&lt;&#x2F;a&gt; comes in — designed for high performance in the world of data science, it seems to be the perfect fit for probabilistic programming.&lt;&#x2F;p&gt;
&lt;p&gt;To learn more about this world we contacted &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;chadscherrer&quot;&gt;Chad Scherrer&lt;&#x2F;a&gt;, the creator of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cscherrer&#x2F;Soss.jl&quot;&gt;Soss&lt;&#x2F;a&gt;, a probabilistic programming library written entirely in Julia. With a very clean syntax resembling math notation, Soss seems to bridge the gap between the more academic side of data science and the more technical&#x2F;developer one, while also providing speed and &lt;em&gt;first-class&lt;&#x2F;em&gt; models.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h4 id=&quot;please-tell-us-a-bit-about-yourself-what-is-your-background-what-is-your-current-position&quot;&gt;Please tell us a bit about yourself. What is your background? what is your current position?&lt;&#x2F;h4&gt;
&lt;p&gt;Starting out, I thought I would end up focusing on algebraic topology. So I did coursework along these lines for a few years before switching to stats. My thesis is on a special case of multivariate normal distributions with a group symmetry, so algebra still plays a big part.&lt;&#x2F;p&gt;
&lt;p&gt;After graduating, I worked at Pacific Northwest National Laboratory, mostly doing computational statistics. I learned some Python, then R. The high-level coding was nice, but I was frustrated by how awkward it was to make it fast.&lt;&#x2F;p&gt;
&lt;p&gt;One day I came across this “Great Computer Language Shootout”, where Ocaml was really dominating. So I used that for a few years. Then multicore hardware started really picking up, but at the time the Ocaml team said they wouldn’t really be doing anything with SMP (symmetric multiprocessing). So I started looking around again, and found Haskell.&lt;&#x2F;p&gt;
&lt;p&gt;Along the way, I had collaborated with the high-performance computing group doing &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;pdf&#x2F;1206.6409.pdf&quot;&gt;parallel&lt;&#x2F;a&gt; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;pdf&#x2F;1212.4174v1.pdf&quot;&gt;machine learning&lt;&#x2F;a&gt; using C&#x2F;OpenMP. And I started getting interested in probabilistic programming. I wanted to make something like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;mcmc-jags.sourceforge.net&#x2F;&quot;&gt;JAGS&lt;&#x2F;a&gt;, but using Haskell and allowing more high-level expressiveness. So I collaborated with Galois to develop &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;cscherrer.github.io&#x2F;pdf&#x2F;Scherrer%20-%202012%20-%20Passage%20A%20Parallel%20Sampler%20Generator%20for%20Hierarchical%20Bayesian%20Modeling.pdf&quot;&gt;Passage&lt;&#x2F;a&gt;, which works in terms of a now-standard probability monad, and produces C&#x2F;OpenMP code for parallel Gibbs sampling.&lt;&#x2F;p&gt;
&lt;p&gt;Based on the Passage work, Galois started getting involved with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.darpa.mil&#x2F;program&#x2F;probabilistic-programming-for-advancing-machine-Learning&quot;&gt;&lt;em&gt;Probabilistic Programming for Advancing Machine Learning (PPAML)&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;, but they needed someone to serve as technical lead. So I moved to Portland and did that for a few years. Galois is a (mostly) Haskell shop, so I was able to dig deeper into both Haskell and probabilistic programming.&lt;&#x2F;p&gt;
&lt;p&gt;Still wanting to extend some of the ideas from Passage, I moved to Seattle and spent a couple of years at &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.thisismetis.com&#x2F;&quot;&gt;Metis&lt;&#x2F;a&gt; teaching data science. In my free time, I got more up to speed on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;julialang.org&#x2F;&quot;&gt;Julia&lt;&#x2F;a&gt;, and started work on what would become &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cscherrer&#x2F;Soss.jl&quot;&gt;Soss&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;These days, I work as a Senior Research Scientist at &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.relational.ai&#x2F;&quot;&gt;RelationalAI&lt;&#x2F;a&gt;. Most machine learning pipelines treat database queries and model training as entirely independent, so to go between them requires throwing away all of the structure and just joining everything.&lt;&#x2F;p&gt;
&lt;p&gt;As it turns out, that throws away some big opportunities for optimization. So our system has an expressive language for reasoning about relational structure, and works in terms that make these optimizations natural for machine learning and probabilistic programming.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-is-probabilistic-programming-how-does-it-differ-from-other-forms-of-programming&quot;&gt;What is probabilistic programming? How does it differ from other forms of programming?&lt;&#x2F;h4&gt;
&lt;p&gt;When people talk about &lt;em&gt;Probabilistic Programming Languages&lt;&#x2F;em&gt; (PPLs), they usually mean a system for building and reasoning about Bayesian models. Maybe the simplest way to think about this is as a way of reasoning about simulations. Say you have a simulation that you can run to make a simulated “world”. Every part of the simulation has some randomness. This includes the things you can actually observe, but also the underlying choices the simulator made for things that affect those observations. But those are random too, so they might depend on &lt;em&gt;other&lt;&#x2F;em&gt; random choices.&lt;&#x2F;p&gt;
&lt;p&gt;Ok, so choices made along the way will affect the distribution of things downstream. But we can also use this to reason the other way! We observe some data, and ask “what choices along the way could have led to this?”&lt;&#x2F;p&gt;
&lt;p&gt;In the simplest case, say we have a simulation for biased coin flips where we pick a random probability of heads, say &lt;code&gt;p ~ Uniform(0,1)&lt;&#x2F;code&gt;, and simulate 20 flips. Then we observe 15 heads and 5 tails. We can’t say for certain what &lt;code&gt;p&lt;&#x2F;code&gt; was, but we can find a distribution that’s updated based on the observed data.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;how-did-you-get-into-julia-why-choose-julia-over-python-or-r&quot;&gt;How did you get into Julia? Why choose Julia over Python or R?&lt;&#x2F;h4&gt;
&lt;p&gt;I want to be able to express ideas at a high level of abstraction without sacrificing performance. I’ve used Python and R quite a bit, for the things I wanted to do I always felt constrained because getting performance always means pushing things to another language. Then there are concerns with the cost of crossing that language barrier, both in a human and computational sense.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-is-soss-how-did-it-come-about-and-what-was-the-motivation-behind-it&quot;&gt;What is Soss? How did it come about and what was the motivation behind it?&lt;&#x2F;h4&gt;
&lt;p&gt;Soss is a Julia-based PPL that represents the right-hand side of each assignment (&lt;code&gt;=&lt;&#x2F;code&gt;) and sample (&lt;code&gt;~&lt;&#x2F;code&gt;) as an AST. The nice thing about this is, it gives ultimate flexibility in what a model can do. For example, we have inference methods that take a &lt;code&gt;Model&lt;&#x2F;code&gt; and return an &lt;code&gt;AST&lt;&#x2F;code&gt; that generates code at run-time, but we also have model transformation functions that return another model. Models are first-class, and can be used inside other models, etc.&lt;&#x2F;p&gt;
&lt;p&gt;There are some other things too, for example we have an interface to SymPy so you can easily get to a symbolic representation of the log-density. Simplifications here can lead to faster code, so we also have a way to generate SSA Julia code from this. There’s still plenty more speed to be had, but I’ve seen 100x-1000x speedup with this vs a direct implementation.&lt;&#x2F;p&gt;
&lt;p&gt;I’ve wanted to build Soss for a long time, it was just a matter of finding a language with metaprogramming support that could handle the syntax I wanted, while also having the speed and a good numerically-oriented ecosystem.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;how-does-the-probabilistic-programming-ecosystem-in-julia-compare-to-the-ones-in-python-r-in-particular-how-does-soss-compare-to-pymc3&quot;&gt;How does the probabilistic programming ecosystem in Julia compare to the ones in Python&#x2F;R? In particular, how does Soss compare to PyMC3?&lt;&#x2F;h4&gt;
&lt;p&gt;To get speed, both Python and R have to call to other languages. I’ve spent a lot of time using PyMC3, and I really like it. But it still requires keeping in your head which lines of code are talking to Python, vs which are talking to Theano. There’s a language barrier to play across, and losing track of it tends to break things.&lt;&#x2F;p&gt;
&lt;p&gt;When you write a Soss model, it’s all Julia. You can use Julia functions freely. Even if you want to do Soss development (please do!), it’s still all Julia.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;on-that-note-who-is-the-end-user-for-the-library-is-it-mostly-just-used-in-academic-settings-or-are-there-industry-uses-as-well&quot;&gt;On that note, who is the end user for the library, is it mostly just used in academic settings or are there industry uses as well?&lt;&#x2F;h4&gt;
&lt;p&gt;It’s certainly intended for both. One thing I like about the AST approach is that generated code can be as fast as you can make it.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-were-the-biggest-challenges-in-developing-probabilistic-programming-for-a-new-language&quot;&gt;What were the biggest challenges in developing probabilistic programming for a new language?&lt;&#x2F;h4&gt;
&lt;p&gt;There’s always some overhead in learning a new programming language. Julia has a very Python-like syntax, so learning the basics was very fast. But metaprogramming requires different ways of thinking about things, so that took a lot of spinning up.&lt;&#x2F;p&gt;
&lt;p&gt;Macros weren’t enough, we had to use Julia’s &lt;code&gt;@generated&lt;&#x2F;code&gt; functions, which let you do staged programming. Even with this, the types weren’t quite working out, so I was using &lt;code&gt;eval&lt;&#x2F;code&gt; all over the place, which does evaluation in global scope and can cause some problems.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;thautwarm.github.io&#x2F;Site-32&#x2F;index.html&quot;&gt;Taine Zhao&lt;&#x2F;a&gt; got us out of the rut with some great Julia packages like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;thautwarm&#x2F;GeneralizedGenerated.jl&quot;&gt;GeneralizedGenerated.jl&lt;&#x2F;a&gt;. Generated functions compile new code for each new type they’re evaluated on, so she realized the model’s type could contain a representation of the entire model. It’s a clever solution, and helped a lot of other parts of the design to fall into place.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;there-seems-to-be-an-explosion-in-probabilistic-programming-on-julia-with-other-libraries-like-turing-or-gen-how-does-soss-compare-to-them&quot;&gt;There seems to be an explosion in probabilistic programming on Julia with other libraries like Turing or Gen, how does Soss compare to them?&lt;&#x2F;h4&gt;
&lt;p&gt;I’d say the syntax is closer to Turing, but the semantics are closer to Gen.&lt;&#x2F;p&gt;
&lt;p&gt;The Gen team independently came up with the same approach we’re using of representing a model as a function. In most PPLs, the model includes some indication of which data will later be observed. But leaving this out until inference time makes it much easier to compose models in different ways.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;any-books-you-recommend-reading-on-the-topic-besides-the-classics-statistical-rethinking-and-bayesian-methods-for-hackers&quot;&gt;Any books you recommend reading on the topic, besides the classics Statistical Rethinking and Bayesian Methods for Hackers?&lt;&#x2F;h4&gt;
&lt;p&gt;Both of these are great. If you’re interested in a particular system, most of the well-funded ones have a nice collection of examples and tutorials; walking through those usually helps.&lt;&#x2F;p&gt;
&lt;p&gt;If you want a broader and deeper view, I’d suggest digging into Bayesian analysis directly. One of my favorites is David MacKay’s &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.inference.org.uk&#x2F;mackay&#x2F;itila&#x2F;&quot;&gt;Information Theory, Inference, and Learning Algorithms&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-s-next-for-soss&quot;&gt;What’s next for Soss?&lt;&#x2F;h4&gt;
&lt;p&gt;There’s always more to do. Currently we’re starting work to make the documentation better. I think we need lots more examples, tutorials, and comparisons to other systems.&lt;&#x2F;p&gt;
&lt;p&gt;If you have any questions about Soss, the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;discourse.julialang.org&#x2F;&quot;&gt;Julia Discourse&lt;&#x2F;a&gt; or &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;julialang.zulipchat.com&quot;&gt;Zulip&lt;&#x2F;a&gt; are both great. And of course, there’s always GitHub issues for &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cscherrer&#x2F;Soss.jl&quot;&gt;the Soss repo&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>NuShell: the shell where traditional Unix meets  modern development, written in Rust</title>
          <pubDate>Thu, 14 May 2020 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/nushell-the-shell-where-traditional-unix-meets-modern-development-written-in-rust/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/nushell-the-shell-where-traditional-unix-meets-modern-development-written-in-rust/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/nushell-the-shell-where-traditional-unix-meets-modern-development-written-in-rust/">&lt;h4 id=&quot;we-interviewed-its-creators&quot;&gt;We interviewed its creators&lt;&#x2F;h4&gt;
&lt;p&gt;Shells have been around forever and, for better or for worse, haven’t changed much since their inception. Until &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.nushell.sh&#x2F;&quot;&gt;NuShell&lt;&#x2F;a&gt; appeared to reinvent shells and defy our muscle memory. It brought some big changes, which include rethinking how pipelines work, structured input&#x2F;output, and plugins.&lt;&#x2F;p&gt;
&lt;p&gt;We wanted to learn more about NuShell so we interviewed both of its creators: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;jntrnr&quot;&gt;Jonathan Turner&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;wycats&quot;&gt;Yehuda Katz&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h4 id=&quot;why-create-nushell-is-it-me-or-does-it-have-a-next-level-awk-vibe&quot;&gt;&lt;strong&gt;Why create NuShell? Is it me or does it have a next-level AWK vibe?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;strong&gt;Jonathan Turner&lt;&#x2F;strong&gt; : Sometimes the simplest ideas are the ones that hook you the most :). When Yehuda and I first started discussing how shells could be improved, we settled on the idea of using structured data rather than just text between applications (for example stdin&#x2F;stdout). He had just been experimenting with PowerShell and saw how adding some structure to the data opened up a lot of possibilities.&lt;&#x2F;p&gt;
&lt;p&gt;The basic idea is pretty simple: Nu opens everything into a table you can work with. Files, streams, commands like ls and ps all output this one table format. Then you have a set of commands that work with these tables, to help you get the data you want, change it, view it, etc.&lt;&#x2F;p&gt;
&lt;p&gt;Funny that you mention “awk”. In a way, Nu is a way of saying “what if we didn’t need tools like awk so often?” Since you’re working with structured data, as we add more support for file types, it’s less often you need to reach for “awk”, “jq”, “grep”, and the array of other tools to open and work with common file types.&lt;&#x2F;p&gt;
&lt;p&gt;In a way, it’s taking the original spirit of Unix — where you use pipelines to combine a set of tools — and imagining how that original spirit would work today, with what we know about programming languages and tools. And, being crossplatform, it’s nice to learn this approach and then be able to easily switch operating systems and use the same techniques.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-u77ccTVL0VJ7Cw2xT_7puA.png&quot; alt=&quot;&quot; &#x2F;&gt;NuShell screen capture&lt;&#x2F;p&gt;
&lt;h4 id=&quot;why-use-rust-how-much-experience-did-you-have-beforehand&quot;&gt;&lt;strong&gt;Why use Rust? How much experience did you have beforehand?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;strong&gt;Jonathan&lt;&#x2F;strong&gt; : Yehuda and I have been writing Rust for at least 4 years. He was one of the first people to deploy Rust into production, long before it hit 1.0.&lt;&#x2F;p&gt;
&lt;p&gt;Rust also just made sense. It naturally is crossplatform, it’s easy to optimize, it’s easy to harden against memory and threading issues, and after the initial learning curve it’s also quite a lot of fun to write. When you’re doing things in your free time, having something you’re looking forward to hacking on after work makes it a lot easier to do so day after day.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;did-using-rust-present-a-challenge-in-some-aspect&quot;&gt;&lt;strong&gt;Did using Rust present a challenge in some aspect?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;strong&gt;Yehuda Katz&lt;&#x2F;strong&gt; : Quite the opposite! Rust and its ecosystem has two properties that are a really good fit for what we’re trying to do:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Cross-platform: There is a version of almost every basic crate that works on Windows, macOS, and Linux.&lt;&#x2F;li&gt;
&lt;li&gt;Rigorous: Rust doesn’t really have exceptions. Instead, Rust’s library ecosystem surfaces edge-cases as Results. When writing something like a shell, this saved us from all kinds of problems as we evolved.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Rust also has a great package manager (Cargo), which means that gluing together fast, cross-platform, and rigorous packages from the ecosystem is really easy.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;how-do-you-go-about-making-software-cross-platform-in-rust-is-it-as-much-work-as-one-would-think&quot;&gt;&lt;strong&gt;How do you go about making software cross-platform in Rust? Is it as much work as one would think?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;strong&gt;Yehuda&lt;&#x2F;strong&gt; : Not really. What you do is look for crates on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;crates.io&#x2F;&quot;&gt;crates.io&lt;&#x2F;a&gt; that support Windows. Most of the time, crates that claim to care about Windows support Windows, as well as other platforms.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Jonathan&lt;&#x2F;strong&gt; : Rust is definitely my preferred tool for crossplatform development these days. Like Yehuda mentions, most crates work across Windows, macOS, and Linux. We’ll also likely explore making Nu work in the browser in the future, which would mean WASM support, and Rust is probably the best language for that as well.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;why-did-you-decide-to-ignore-posix-compliance&quot;&gt;&lt;strong&gt;Why did you decide to ignore POSIX-compliance?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;strong&gt;Yehuda&lt;&#x2F;strong&gt; : This question is a little bit misleading in my opinion. When people say that a shell is “POSIX compliant”, they’re talking about a tiny subset of the syntax and features that people come to rely on in a shell. If you want to run a POSIX shell script in nu, you can just run it with bash or sh. On the other hand, trying to make our syntax perfectly compliant with the POSIX standard would introduce all kinds of weird decades-old cruft and constrain the ergonomics of our syntax.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Jonathan&lt;&#x2F;strong&gt; : When people ask for POSIX-compliance, I think different people mean different things. Generally, I think they mean “don’t break my muscle memory”. That’s fair, it’s annoying to unlearn habits. That said, what it means to be compatible has changed a lot from the original ideas. I saw this tweet the other day which I thought sums it up pretty well:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-gQH1jV4nzbs_WurExrLnEw.png&quot; alt=&quot;&quot; &#x2F;&gt;Source: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;danluu&#x2F;status&#x2F;1234814736144797697&quot;&gt;Dan Luu&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;where-does-nushell-stand-compared-to-others-like-zsh-or-fish-as-of-today-can-i-set-it-as-my-default-shell&quot;&gt;&lt;strong&gt;Where does NuShell stand compared to others like zsh or fish? As of today, can I set it as my default shell?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;strong&gt;Jonathan&lt;&#x2F;strong&gt; : we’re quickly approaching when you’ll be able to use Nu as your default shell. In fact, some of Nu’s users already use it as their daily driver happily. In 0.13, we added the ability to create your own aliases, which dramatically improves how well Nu works as a shell, as it’s now easy to configure your own set of shortcuts for things you do regularly.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;how-did-you-decide-on-that-sort-of-hard-division-of-commands-streamers-filters-and-consumers-i-didn-t-see-any-official-names-for-these-concepts-but-i-think-this-conveys-the-idea&quot;&gt;&lt;strong&gt;How did you decide on that sort of “hard” division of commands: streamers, filters, and consumers?&lt;em&gt;I didn’t see any official names for these concepts, but I think this conveys the idea&lt;&#x2F;em&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;strong&gt;Yehuda&lt;&#x2F;strong&gt; : The distinctions arose organically, and make sense. When you think about streams, there are really three parts: the first part, the middle parts, and the last part. The last part is the most special one, because it takes a stream of data and turns it into something you can see, which requires looking at the inbound stream. For example, the outputted table needs to look at some rows to see what headers to use.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;why-make-a-plugin-system-what-are-the-benefits-of-using-json-rpc-for-internal-communication&quot;&gt;&lt;strong&gt;Why make a plugin system? What are the benefits of using JSON-RPC for internal communication?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;strong&gt;Yehuda&lt;&#x2F;strong&gt; : The main difference between plugins and builtins is that built-in commands have access to the shell internals. We wanted to build as many commands as possible on top of a more well-defined interface. This also meant that you could build custom commands in Python, Ruby or JavaScript pretty early in the project.&lt;&#x2F;p&gt;
&lt;p&gt;The benefit of JSON-RPC is that it’s pretty easy to work with JSON-RPC in virtually all programming languages, so it’s possible to build a plugin in any language without major assistance from the nushell team.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;why-would-i-choose-to-make-a-plugin-why-not-just-make-a-binary-that-works-on-all-shells-and-let-the-parsing-of-my-output-to-users-of-nushell&quot;&gt;&lt;strong&gt;Why would I choose to make a plugin? Why not just make a binary that works on all shells and let the parsing of my output to users of NuShell?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;strong&gt;Yehuda&lt;&#x2F;strong&gt; : The major benefit of building a plugin is the ability to work directly with structured data. This means that all of the “good stuff” that nushell gives you out of the box, like sorting and filtering, will just work without your user having to parse string output into a new structured format.&lt;&#x2F;p&gt;
&lt;p&gt;The Nushell plugin API also allows you to specify the types of your arguments, which will give you error messages, syntax highlighting and some amount of context-sensitive completion out of the box. The more information you give Nushell, the more we can give Nushell users useful information as they interact with your command.&lt;&#x2F;p&gt;
&lt;p&gt;Also, the Nushell plugin API is also built for streaming out of the box, so if you use the plugin API in the normal way, you can idiomatically interact with streams of structured data in a way that will scale up to huge amounts of input without “breaking the stream”.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-s-next-for-nushell&quot;&gt;&lt;strong&gt;What’s next for NuShell?&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;strong&gt;Jonathan&lt;&#x2F;strong&gt; : Nu, as both a shell and a language, is still very much young and growing. We’re planning on adding functions, a rich auto-completion system, better Jupyter integration for working with data, per-directory environments, and much more. In short, we want it to grow to be the best tool for working with your system, files, and data we can make.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>A brief introduction to the beauty of Information Theory</title>
          <pubDate>Wed, 06 May 2020 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/a-brief-introduction-to-the-beauty-of-information-theory/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/a-brief-introduction-to-the-beauty-of-information-theory/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/a-brief-introduction-to-the-beauty-of-information-theory/">&lt;h4 id=&quot;or-how-to-be-a-hardcore-guess-who-gamer&quot;&gt;Or how to be a hardcore Guess Who gamer&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;em&gt;Authors: Juan Pablo Amoroso, Javier Rodríguez Chatruc, Camilo Plata, and Federico Carrone.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The fundamental problem of communication is that of reproducing at one point either exactly or approximately a message selected at another point.&lt;br &#x2F;&gt;
— Claude Shannon, 1948&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Imagine you were tasked with designing a comunications system between a space station and a ground control headquarters back in Earth. The system would transmit and receive messages encoded in binary, that is, as a sequence of 1s and 0s. As the message travels, there may be interferences from other radio signals, so that what is picked up in ground control is not exactly the same as the original message. Under these circumstances, is it possible to devise a scheme that allows reliable comunication?&lt;&#x2F;p&gt;
&lt;p&gt;A simple workaround would be to add redundancy: send each bit a number of times, let’s say 5:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;11111&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;00000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;…&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If ground control receives the message &lt;em&gt;11101&lt;&#x2F;em&gt; , they could be fairly certain that what was truly sent was &lt;em&gt;11111&lt;&#x2F;em&gt;. Although this simple system would work (up to a point), we can see that it is very wasteful: we have to send 4 extra bits for every bit in the original message. The &lt;em&gt;transmission rate&lt;&#x2F;em&gt; is therefore only 20%. Can we do any better?&lt;&#x2F;p&gt;
&lt;p&gt;There seems to be a dilemma here: if we want accuracy, we must lower the rate of transmission.&lt;&#x2F;p&gt;
&lt;p&gt;This is the problem Claude Shannon tackled in his 1948 paper &lt;em&gt;A Mathematical Theory of Communication&lt;&#x2F;em&gt;. In it, he proved that there is a limit for the rate of information that can be reliably transmitted over a noisy channel (the &lt;em&gt;Shannon limit&lt;&#x2F;em&gt;). However, below this limit we can transmit information with an increasingly small error. This important result tells us that there &lt;em&gt;exists&lt;&#x2F;em&gt; a code that allows arbitrary accuracy over a given comunication channel, but it does not tell us how to build it.&lt;&#x2F;p&gt;
&lt;p&gt;More precisely, let’s say a channel has a probability &lt;em&gt;p&lt;&#x2F;em&gt; of transmitting a bit correctly, and a corresponding probability of 1 —  &lt;em&gt;p&lt;&#x2F;em&gt; of sending the wrong bit, Shannon proved that the optimum rate of transmission is:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-kCNAUFlhWJv1kUzKatqINA.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-TgCse1znfuWYULYwXeo4Aw.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The plot is symmetrical around &lt;em&gt;p = 0.5&lt;&#x2F;em&gt; , with maxima at &lt;em&gt;p = 0&lt;&#x2F;em&gt; and &lt;em&gt;p = 1&lt;&#x2F;em&gt;. The case of &lt;em&gt;p = 0&lt;&#x2F;em&gt; is interesting, the channel has perfect noise: it flips all the bits in the original message. But if we know that, then the message is trivially deciphered, we just flip them back.&lt;&#x2F;p&gt;
&lt;p&gt;The formula is commonly stated in terms of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Entropy_%28information_theory%29&quot;&gt;information entropy&lt;&#x2F;a&gt;, a measure Shannon devised that can be interpreted as the level of ‘uncertainty’ or ‘surprise’ associated with the channel.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-fCyO-nZidJEiOqwqDGWJ3g.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-s0z3MUCTtJvh_AsvxGg72g.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We can see that the entropy has a maximum at 1 when &lt;em&gt;p&lt;&#x2F;em&gt; = ½, and minima at 0 for &lt;em&gt;p =&lt;&#x2F;em&gt; 0 and &lt;em&gt;p =&lt;&#x2F;em&gt; 1.&lt;&#x2F;p&gt;
&lt;p&gt;More generally, given a random message &lt;em&gt;M&lt;&#x2F;em&gt; that can take &lt;em&gt;n&lt;&#x2F;em&gt; different values with probability &lt;em&gt;pᵢ&lt;&#x2F;em&gt; for &lt;em&gt;i =&lt;&#x2F;em&gt; 1,…,&lt;em&gt;n&lt;&#x2F;em&gt; , we define the entropy of the message as:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-ezweLprVK1INseQwDCN2yg.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;guess-who-example&quot;&gt;Guess Who example&lt;&#x2F;h4&gt;
&lt;p&gt;Let’s take a different approach. Suppose you are playing &lt;em&gt;Guess Who&lt;&#x2F;em&gt; , the game where you ask yes&#x2F;no questions about the appearance of your opponent’s character in order to single him or her out among a set of characters. You ask yourself: what order should I ask the questions in to maximise the probability of winning? Intutively, you try to ask first about features most of the characters have.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-TkW9quvg52IBgM06fM-7IA.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;Hardcore Guess Who gamers apply Information Theory for optimal results&lt;&#x2F;p&gt;
&lt;p&gt;Moreover, an optimal question is one that divides the population evenly, that is, one that regardless of the answer (&lt;em&gt;yes&lt;&#x2F;em&gt; or &lt;em&gt;no&lt;&#x2F;em&gt;) discards half the characters. In any other case, you are not gaining the optimal amount of information with each question.&lt;&#x2F;p&gt;
&lt;p&gt;But what if you can’t divide the characters evenly by their characteristics? To answer the question, first we recall the concept of entropy defined above. We can think of a question as a variable &lt;em&gt;X&lt;&#x2F;em&gt; that splits the population into groups &lt;em&gt;xᵢ&lt;&#x2F;em&gt; with probabilities &lt;em&gt;pᵢ&lt;&#x2F;em&gt;. For example, think of a question about the eye color of the character (the questions in the game are technically only &lt;em&gt;yes&lt;&#x2F;em&gt; or &lt;em&gt;no&lt;&#x2F;em&gt; but this can be generalized). With this in mind, the entropy of a question becomes:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-KZq1CO03SyEnsH0qLamzRQ.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The intuition here is that with each possible answer, we gain an amount of information  &lt;em&gt;— log&lt;&#x2F;em&gt; &lt;em&gt;p&lt;&#x2F;em&gt;(&lt;em&gt;x&lt;&#x2F;em&gt; ᵢ), meaning that if we receive an answer with a very low probability (i.e. we ask if the character has a feature that is shared by very few people, and the answer is yes), the amount of information we gained is higher than an answer with more probability.&lt;&#x2F;p&gt;
&lt;p&gt;On the other hand, entropy is related to uncertainty. For example, if we flip a coin, the uncertainty in the outcome is higher with a &lt;em&gt;p&lt;&#x2F;em&gt; = 0.5 than with any other value of &lt;em&gt;p&lt;&#x2F;em&gt;. And in our case, more uncertainty is better. Why? If we choose a question with an uneven distribution in the population, lets say 0.7 and 0.3, the odds are that our character is among the 70%, discarding with the &lt;em&gt;no&lt;&#x2F;em&gt; answer only the remaining 30%, but with a more even division (and therefore more uncertain), we always tend to discard 50% of the population, leading to an advantage in the long run. This means that the best questions to ask are those that maximize the entropy, i.e, the ones with the higher uncertainty.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;decision-trees&quot;&gt;Decision Trees&lt;&#x2F;h4&gt;
&lt;p&gt;One common use of entropy is in decision trees, where one uses a set of features (features that split the data into disjoint sets) to construct a flowchart for a classification problem. Here, a common question is: which order should we “apply” the features in to get the best splits? A possible solution is to recursively always use the feature that maximizes the &lt;em&gt;information gain&lt;&#x2F;em&gt;. If we’re working with a dataset &lt;em&gt;S&lt;&#x2F;em&gt; and our feature is called &lt;em&gt;X&lt;&#x2F;em&gt; , the information gained on &lt;em&gt;S&lt;&#x2F;em&gt; by &lt;em&gt;X&lt;&#x2F;em&gt; , &lt;em&gt;I&lt;&#x2F;em&gt;(&lt;em&gt;S&lt;&#x2F;em&gt; ,&lt;em&gt;X&lt;&#x2F;em&gt;), is calculated as:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-tIzlfBpMihRvpfZICpWZJA.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;where &lt;em&gt;H&lt;&#x2F;em&gt;(&lt;em&gt;S&lt;&#x2F;em&gt; |&lt;em&gt;X&lt;&#x2F;em&gt;) is the conditional entropy of &lt;em&gt;S&lt;&#x2F;em&gt; given &lt;em&gt;X&lt;&#x2F;em&gt;. Intuitively, this is just the reduction in the entropy of the dataset &lt;em&gt;S&lt;&#x2F;em&gt; if we know &lt;em&gt;X&lt;&#x2F;em&gt;. Thus, it makes sense to choose the features &lt;em&gt;X&lt;&#x2F;em&gt; that maximize this value, as they will be the ones that reduce uncertainty the most, effectively obtaining the best splits.&lt;&#x2F;p&gt;
&lt;p&gt;Algorithms that consider the information gain at each node to choose the next feature are called &lt;em&gt;greedy&lt;&#x2F;em&gt; algorithms. Such algorithms do not take into account the overall information gain and may lead in some cases to suboptimal queries, but they are well-behaved and have a straightforward approach.&lt;&#x2F;p&gt;
&lt;p&gt;As an example, consider the picture below, where a decision tree method was used on the famous Iris flower dataset and two features were selected, the petal width, first with 0.8 cm as a threshold and then 1.75 cm. Setting aside how these specific features are selected, why use the ≤ 0.8 first? With the information gain calculation we described, we can provide an answer. We will call the feature that separates petal width on 0.8 cm &lt;em&gt;X&lt;&#x2F;em&gt; and the other one &lt;em&gt;Y&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-dEesB-YyIVG81qhIDn_T_w.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Applying &lt;em&gt;X&lt;&#x2F;em&gt; first splits the 150 data points (usually one would split between training and test sets, here for simplicity we use the entire set) into two sets: one containing the entire &lt;em&gt;setosa&lt;&#x2F;em&gt; class (50 points, corresponding to ≤ 0.8 cm) and nothing else, and the other containing the rest. In that case the calculations yield:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-2dDOZS_8PGYonq3RZYoyAg.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;On the other hand, applying &lt;em&gt;Y&lt;&#x2F;em&gt; first gives us one set with 50 &lt;em&gt;setosa&lt;&#x2F;em&gt; , 49 &lt;em&gt;versicolor&lt;&#x2F;em&gt; and 5 &lt;em&gt;virginica&lt;&#x2F;em&gt; (≤ 1.75 cm) and another with no &lt;em&gt;setosa&lt;&#x2F;em&gt; , 1 &lt;em&gt;versicolor&lt;&#x2F;em&gt; and 45 &lt;em&gt;virginica&lt;&#x2F;em&gt;. This leaves us with:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-VCQsujq_mEufMZi1X4DGdw.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Thus the information gain from &lt;em&gt;X&lt;&#x2F;em&gt; (petal width being under or over 0.8 cm) is greater than the one from &lt;em&gt;Y&lt;&#x2F;em&gt; , and we should use it first. This makes sense intuitively, as &lt;em&gt;X&lt;&#x2F;em&gt; completely separates the &lt;em&gt;setosa&lt;&#x2F;em&gt; class from the other two, whereas using &lt;em&gt;Y&lt;&#x2F;em&gt; first gives a more entangled split.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h4&gt;
&lt;p&gt;It is hard to overstate the importance of Shannon’s work: the Theory of Information has found &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.britannica.com&#x2F;science&#x2F;information-theory&#x2F;Applications-of-information-theory&quot;&gt;many applications&lt;&#x2F;a&gt; in fields as diverse as statistical inference and machine learning, natural language processing, genetics, data compression, coding theory, and cryptography. With over 120,000 citations, few papers can boast a similar impact. In the words of information theorist Anthony Ephremides:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;It was like an earthquake and the aftershocks haven’t finished yet!&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
</description>
      </item>
      <item>
          <title>Interview with Noria’s creator: a promising dataflow research database implemented in Rust</title>
          <pubDate>Tue, 22 Oct 2019 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-norias-creator-a-promising-dataflow-database-implemented-in-rust/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-norias-creator-a-promising-dataflow-database-implemented-in-rust/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-norias-creator-a-promising-dataflow-database-implemented-in-rust/">&lt;p&gt;After reading &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;download.tensorflow.org&#x2F;paper&#x2F;whitepaper2015.pdf&quot;&gt;Tensorflow’s original paper&lt;&#x2F;a&gt; I learnt that four of its authors were authors of Microsoft &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;sigops.org&#x2F;s&#x2F;conferences&#x2F;sosp&#x2F;2013&#x2F;papers&#x2F;p439-murray.pdf&quot;&gt;Naiad’s research paper&lt;&#x2F;a&gt; too. Naiad influenced many systems like Tensorflow.&lt;&#x2F;p&gt;
&lt;p&gt;The Naiad paper is really interesting since it brings together many computation patterns: batch computation, streaming computation, and graph computation. It seemed to be a higher level abstraction than the traditional MapReduce and at the same time a more elegant &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Lambda_architecture&quot;&gt;Lambda architecture&lt;&#x2F;a&gt; that combines batch processing with streaming methods. Being an practitioner and not a researcher this paper helped me to understand to compare different projects like Hadoop, Spark, Storm, Samza, Flink, Kafka streams.&lt;&#x2F;p&gt;
&lt;p&gt;Naiad’s paper introduced a computational model called timely dataflow that has influenced other systems like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mit-pdos&#x2F;noria&quot;&gt;Noria&lt;&#x2F;a&gt;. Noria is a fast storage backend for read-heavy web applications implemented in Rust with a MySQL adapter. One of its creators is Jon Gjengset, a PhD student in the Parallel and Distributed Operating Systems group at MIT. Jon has a great &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;thesquareplanet.com&#x2F;blog&#x2F;&quot;&gt;blog&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;channel&#x2F;UC_iD0xppBwwsrM9DegC5cQQ&quot;&gt;youtube channel&lt;&#x2F;a&gt; where he discusses everything from distributed algorithms to how to implement a ZooKeeper clone. He is into many subjects I love: Rust, distributed systems, databases and the relationship between Noria, Naiad and Tensorflow were enough reasons to interview him. We did not discuss Tensorflow but I hope to find out more about the relationship between it in the future.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;What is Noria?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Noria is a dynamic dataflow database that supports partial and incremental materialized views. To break that down a bit more, it is a database that is implemented using a streaming dataflow engine that can be changed on the fly (that’s the dynamic part). It supports pre-computing the results of queries (materialized views), and updates those materialized results as the data is updated (view maintenance).&lt;&#x2F;p&gt;
&lt;p&gt;When this happens, the results are updated in-place rather than recomputed wholesale (i.e., the maintenance is incremental). When queries have parameters (e.g., &lt;em&gt;foo = ?&lt;&#x2F;em&gt;), it supports materializing the results for only some value of &lt;em&gt;foo&lt;&#x2F;em&gt; , and will compute results for “missing” values only when they are required (i.e., the materializations are partial).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;How does it compare to other software like a relational database, in memory key-value stores, map reduce systems like Spark, stream processing like Storm or timely data flow?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The answer here requires some nuance, so please bear with me.&lt;&#x2F;p&gt;
&lt;p&gt;Noria is very similar to a relation database on the outside. It has tables and SQL queries, and even supports the MySQL binary protocol. You interact with Noria through prepared statements, &lt;em&gt;SELECT&lt;&#x2F;em&gt; s, &lt;em&gt;INSERT&lt;&#x2F;em&gt; s, and &lt;em&gt;UPDATE&lt;&#x2F;em&gt; s. Internally though, it is quite different. Whereas a traditional database executes a query when it receives a &lt;em&gt;SELECT&lt;&#x2F;em&gt; , Noria generally executes &lt;strong&gt;all&lt;&#x2F;strong&gt; queries when data the query’s result depends on changes. In the steady state of the system, we expect queries to be executed on &lt;strong&gt;write&lt;&#x2F;strong&gt; , not on &lt;strong&gt;read&lt;&#x2F;strong&gt;. There are some smarts required here to not do undue work. For example, Noria only computes and maintains results for query parameters the application cares about (this is the “partial materialization” piece). Noria also executes queries “incrementally”; if you add a new vote to an article with a million votes, it knows to increase the count by one, rather than count a million and one things all over again.&lt;&#x2F;p&gt;
&lt;p&gt;While Noria implements a key-value store internally to maintain and serve its materialized results, it does not seem like a key-value store to users of the system. Application authors write full SQL queries, and get structured results (rows of columns) back, just like with a normal database. The only sense in which Noria is like a key-value store is in its performance — query results will generally be fetched about as fast as a key-value store lookup.&lt;&#x2F;p&gt;
&lt;p&gt;Streaming data-flow systems like Spark, Storm, Kafka, and timely dataflow share many similarities with Noria. They process data in the same streaming fashion, and have a similar distributed system design that relies on sharding and operator partitioning. Noria differs from these systems in a few principal ways though. First, users of Noria can change the running dataflow at any time without downtime. If a new SQL query is issued that the system has not seen before, it adapts the running dataflow on the fly to incorporate the operators from the new query. The adaptation also knows to re-use existing operators where possible to produce an overall more efficient dataflow than what you would get if you just ran each query as its own dataflow program.&lt;br &#x2F;&gt;
Second, Noria supports partial materialization. Existing dataflow systems that support materialization are usually either windowed (i.e., they only reflect “recent” updates) or fully materialized (i.e., all results are always stored and maintained). Neither of these would work for web applications. When you issue a query, you expect to get all the results for &lt;strong&gt;that&lt;&#x2F;strong&gt; query (so no windowing), but you also don’t expect the system to waste resources on results that your application does not care around. You can think of this latter requirement as “you need the ability to evict from your cache”. And finally, Noria has a familiar interface for its queries: you issue SQL queries, and the system automatically translates them into efficient dataflow and adapts the running system to them. The other systems do not generally support this.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;The Noria paper states that it can scale to 5x higher load than a hand optimised MySQL database. How does it manage to do that?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The primary reason for this is Noria’s view materialization. When you issue a query to MySQL, the system has to &lt;strong&gt;execute&lt;&#x2F;strong&gt; that query to produce the query’s results. In Noria on the other hand, an application query effectively turns into a hashmap lookup in the common case, which is &lt;strong&gt;very&lt;&#x2F;strong&gt; fast. Noria’s reads can also happen entirely in parallel, with very little synchronization overhead, whereas MySQL includes a lot of machinery to support full-fledged transactions (which Noria does not support). Part of the trick here is Noria’s use of a neat little datastructure called an evmap (for “eventual map”; named for its support for eventual consistency). It allows reads and writes to proceed entirely in parallel with very little overhead by having reads and writes go to different hashmaps, and then occasionally atomically switching between them.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is the relationship between&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;jon.tsp.io&#x2F;papers&#x2F;osdi18-noria.pdf&quot;&gt;&lt;strong&gt;Noria’s paper&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;, the&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;timelydataflow&#x2F;differential-dataflow&#x2F;blob&#x2F;master&#x2F;differentialdataflow.pdf&quot;&gt;&lt;strong&gt;Differential dataflow&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;paper and&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;sigops.org&#x2F;s&#x2F;conferences&#x2F;sosp&#x2F;2013&#x2F;papers&#x2F;p439-murray.pdf&quot;&gt;&lt;strong&gt;Naiad: a timely dataflow system&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Differential dataflow, timely dataflow, and its implementation in Naiad is one of the hallmark systems in the dataflow community. Most papers in this area relate to timely dataflow in one way or another. In the case of Noria, we also implement an incremental dataflow model, but we are trying to solve for a different use-case, and therefore arrive at different solutions.&lt;&#x2F;p&gt;
&lt;p&gt;In particular, timely established a model for incrementally executing dataflow programs that include iteration and cycles with strong guarantees about consistency through a sophisticated timestamp tracking scheme. Noria does not support iteration or cycles, and is eventually consistent.&lt;&#x2F;p&gt;
&lt;p&gt;Instead, we provide high-performance materialized views for fast reads, partial state so only the working set needs to be kept in memory, automatic multi-query optimization, support for dynamically modifying the dataflow as it runs, and of course SQL support. Timely does not support these features, though you could likely manually implement some of them on top of timely’s core given enough time and research effort.&lt;&#x2F;p&gt;
&lt;p&gt;Overall, I don’t think it’s fair to say one system is &lt;strong&gt;better&lt;&#x2F;strong&gt; than another. In many ways they complement each other. Timely largely targets arbitrary batch computations over a large, interconnected dataset where reads are less frequent than just observing the “output” of the computation. And it is &lt;strong&gt;very&lt;&#x2F;strong&gt; good at that. Noria targets read-heavy applications where repeated and similar queries are common, and where the queries change over time. And it is &lt;strong&gt;very&lt;&#x2F;strong&gt; good at that.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Do you implement the full SQL language?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It’s not clear what “full SQL” even really means, with all of the various extensions to the language that have been added to different implementations over time. Even if you restrict yourself to ANSI SQL though, the answer for Noria is no, although mostly for uninteresting reasons. Noria is a research prototype, and as such we have focused on the features that required active research to implement in Noria’s database model. Many of the remaining features we believe could be added with sufficient engineering effort, but without too much technical difficulty. To give some examples of things we don’t support: joins whose join condition is not a single column equality; &lt;em&gt;ORDER BY&lt;&#x2F;em&gt; without a limit; &lt;em&gt;CASE&lt;&#x2F;em&gt; statements; &lt;em&gt;LIKE&lt;&#x2F;em&gt; conditions; and of course the &lt;em&gt;SOUNDEX&lt;&#x2F;em&gt; operator. There are also patterns that we support, but that we believe could be optimized further, such as multi-way joins and multiple aggregations in a single query.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why did you choose to use RocksDB to persist the data?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This was a more or less arbitrary decision. We initially wrote all base table writes directly to disk as a log, but quickly realized we needed to also keep indices over that on-disk data, otherwise recovery would be far too slow. We looked for an off-the-shelf solution, and RocksDB seemed to fit the bill. The interface for this base storage layer is pretty straightforward, and it should not be too difficult to slot in another solution there. The biggest challenge in doing so is maintaining some invariants around what writes are visible when for the purposes of Noria’s upqueries, but we believe these are solveable without too much trouble.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why does Noria needs to have Zookeeper running? Why did you choose ZooKeeper over etcd or consul?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Zookeeper serves two purposes in Noria at the moment. Service discovery and leadership change. And in fact, if you run a Noria server and client in a single process, you don’t actually need Zookeeper running at all.&lt;&#x2F;p&gt;
&lt;p&gt;If you run a single Noria worker, and a separate client, Zookeeper is only used for the client to have an easy way to discover the location of the server. We’re considering adding a non-distributed mode to Noria which supports this single-worker use-case without Zookeeper. The bits are already in place (take a look at the &lt;em&gt;Authority&lt;&#x2F;em&gt; trait in the code if you are curious), it just hasn’t been a priority for us to fix. If you are running &lt;strong&gt;multiple&lt;&#x2F;strong&gt; Noria workers, then they need some way to agree on which worker is responsible for driving application-issued changes to the dataflow, and that is where Zookeeper’s consensus comes into play. We needed a system that allowed the workers to agree on who that should be, with a mechanism for failover, and Zookeeper provided that. The API we need from Zookeeper is very limited, and it should be straightforward to slot in another consensus provider in its place.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Is Noria production ready? Do you know anybody using it?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Noria is most definitely still a research prototype, though I think the thing standing between where it is now and a production-ready version is mostly just engineering effort. We are a small team of researchers working on it, and we focus our efforts on the aspects of the system that are related to our ongoing research. There is relatively little room for spending lots of time on doing “production engineering” in the academic setting :)&lt;&#x2F;p&gt;
&lt;p&gt;That said, I know of several large companies who are very interested in&lt;br &#x2F;&gt;
using Noria in a production setting, and many of them have gotten in touch with me about what might be required to achieve that. I also know that multiple companies are trying Noria out privately internally to test its viability as a replacement for certain parts of their stack. What ultimately comes of that is unclear at the moment, but I of course hope that they find Noria promising, and that they are willing to invest time into making it production ready!&lt;&#x2F;p&gt;
&lt;p&gt;There are a few features missing from Noria that I think are the primary blockers from using it in production. The first is checkpointing of materialized views. Currently, if the system is turned off and then restarted, all the materialized views are empty. This would be equivalent to a full cache purge. An external system could heat the cache, but it’d be better if Noria internally kept some form of snapshot to aid in this process. The second is fault tolerance — when Noria is run in a distributed setting, a machine failure results in related parts of the dataflow being blown away entirely and restarted. This is obviously problematic in production settings. We are actively pursuing research in this area, and have some ideas for how to fix it, but it is a complex subject. And finally, Noria currently requires ownership of its base storage. If you have an existing data store that you’d like to keep using, you’d have to feed changes to that data to Noria, and Noria would store it a second time. Changing Noria such that it can handle the base storage being managed by a different system is possible, though would require some careful engineering with respect to consistency of upqueries.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;When would you avoid using Noria?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Noria is not great for systems that do not have a well-defined working set. If your application is constantly issuing entirely new queries over your data that do not relate to previous queries, or if it rarely queries by the same set of keys more than once, then Noria’s materializations will be mostly useless and just add unnecessary overhead. Noria is also primarily built for read-heavy applications; if your application rarely does reads, but sustains a &lt;strong&gt;very&lt;&#x2F;strong&gt; high write load, then Noria in its current form is probably not what you want. I say “probably” because Noria already supports a fairly high write throughput, and if your inputs fall below that threshold, Noria will still work fine. And, crucially, its materializations will make your reads over this quickly growing collection really fast!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why did you choose to use Rust to implement it?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The answer to this is perhaps less interesting than you’d expect. When&lt;br &#x2F;&gt;
we first started this iteration of the project in mid-2016, Rust was just starting to appear as a viable systems language. We were looking for a systems language to use for this new project, and did not particularly want to write C++, and wanted to explore something beyond Go. We heard about Rust, its claims were enticing, so as researchers we figured we’d try it out and see if it could live up to its promises. The cost of failure was low, as we could always start over, so we just ran with it. And now we’re 80k lines of code in, and I still think it was the right choice.&lt;&#x2F;p&gt;
&lt;p&gt;I can also give a post-hoc analysis of the journey. I think choosing Rust has worked out great for us; specifically, it has saved us countless hours of debugging. We write a lot of concurrent code in Noria, and the Rust compiler has caught a ridiculous number of concurrency bugs that would just have slipped right by in another language. Debugging those in a distributed context in a research system where we don’t even know if the underlying &lt;strong&gt;algorithm&lt;&#x2F;strong&gt; is sound would have been a major pain (and still is when it happens). Rust has also allowed us to write low-level code when we needed to squeeze out those last bits of performance in the core pieces of Noria. What is more, I have found the Rust ecosystem to be a joy to participate in and to rely on; solid libraries like tokio have allowed us to focus on the core research-y parts of the application, and lots of knowledgeable Rustaceans have helped us when we’ve run into weird issues. Not only that, but we have been able to contribute back to that ecosystem by publishing libraries of our own and by contributing back to the compiler and other core libraries that we relied on.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;You have videos on how to implement a TCP stack, a minimal Zookeeper implementation and blog posts explaining how to implement Raft. What would gain a traditional full stack developer learning how to implement low level structures, distributed algorithms or distributed software?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I think much of this comes down to curiosity. If you’re curious about how stuff works, there’s an endless number of rabbit holes you can easily start down that teach you all of this stuff. For me, much of my distributed systems knowledge came from MIT’s 6.824 Distributed Systems class, which is &lt;strong&gt;excellent&lt;&#x2F;strong&gt;. All of their reading materials, lecture notes, and labs are also available online. For algorithms, the easiest way to get started in thinking about them is to read some of the early papers describing these algorithms, and then trying to implement them yourself! You’ll find that many of them aren’t as difficult to build as you may think, and you will learn a lot in the process. Including how tobread academic papers! I can also recommend trying to follow some low-level OS-building resources. For example, Philipp Oppermann has a great blog series on implementing an operating system from scratch in Rust that goes through all of the low-level details you’ll need to know.&lt;&#x2F;p&gt;
&lt;p&gt;Alternatively, all the components of MIT’s 6.828 Operating Systems class are also available online.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What papers, readings and exercises do you recommend doing to learn about distributed programming?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I would highly recommend following the 6.824 class schedule&lt;br &#x2F;&gt;
(&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pdos.csail.mit.edu&#x2F;6.824&#x2F;schedule.html&quot;&gt;https:&#x2F;&#x2F;pdos.csail.mit.edu&#x2F;6.824&#x2F;schedule.html&lt;&#x2F;a&gt;). It covers both classic&lt;br &#x2F;&gt;
papers, established approaches, and new research in the area. Do the&lt;br &#x2F;&gt;
labs as well; they will force you to get &lt;strong&gt;intimately&lt;&#x2F;strong&gt; familiar with many&lt;br &#x2F;&gt;
subtle distributed systems problems!&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Weld: accelerating numpy, scikit and pandas as much as 100x with Rust and LLVM</title>
          <pubDate>Sat, 21 Sep 2019 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/weld-accelerating-numpy-scikit-and-pandas-as-much-as-100x-with-rust-and-llvm/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/weld-accelerating-numpy-scikit-and-pandas-as-much-as-100x-with-rust-and-llvm/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/weld-accelerating-numpy-scikit-and-pandas-as-much-as-100x-with-rust-and-llvm/">&lt;h3 id=&quot;interview-with-weld-s-main-contributor-accelerating-numpy-scikit-and-pandas-as-much-as-100x-with-rust-and-llvm&quot;&gt;Interview with Weld’s main contributor: accelerating numpy, scikit and pandas as much as 100x with Rust and LLVM&lt;&#x2F;h3&gt;
&lt;p&gt;After working for weeks with Python’s and R’s data science stack I started to ask my self if there could be a common intermediate representation, similar to CUDA, that could be used by many languages. There should be something better than reimplementing and optimizing the same methods in each language. In addition to that, having a common runtime that could optimize the whole program instead of each function separately would be better. After a few days of researching and testing different projects I found &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.weld.rs&#x2F;&quot;&gt;Weld&lt;&#x2F;a&gt; (you can also read its &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;cs.stanford.edu&#x2F;~matei&#x2F;papers&#x2F;2017&#x2F;cidr_weld.pdf&quot;&gt;paper&lt;&#x2F;a&gt;). To my surprise, one of the creators of Weld is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;matei_zaharia&quot;&gt;Matei Zaharia&lt;&#x2F;a&gt;, who also is the creator of Spark.&lt;&#x2F;p&gt;
&lt;p&gt;That is how I contacted and interviewed &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;shoumik.xyz&#x2F;&quot;&gt;Shoumik Palkar&lt;&#x2F;a&gt;, the main contributor of Weld. Shoumik is a Ph.D. student in the Computer Science department at Stanford University, that is advised by Matei Zaharia.&lt;&#x2F;p&gt;
&lt;p&gt;Weld is far from being production ready but it is promising. If you are interested in the future of data science and in Rust, you will like this interview.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-hqC6KtF-l1RN8uDg99rmow.png&quot; alt=&quot;&quot; &#x2F;&gt;Not a Monad Tutorial new logo!&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;What was the motivation to develop weld and what problem’s does it solve?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The motivation behind Weld is to provide bare-metal performance for applications that rely on existing high-level APIs such as NumPy and Pandas. The main problem it solves is enabling cross-function and cross-library optimizations that other libraries today don’t provide. In particular, many commonly used libraries provide state-of-the-art implementations for algorithms on a per-function basis (e.g., a fast join algorithm implemented in C in Pandas, or a fast matrix multiply in NumPy), but do not provide any facility for enabling optimization across these functions (e.g., preventing unnecessary scans of memory when performing a matrix multiply followed by an aggregation). Weld provides a common runtime that enables libraries to express computations in a common IR; that IR can then be optimized using a compiler optimizer, and can then be JIT’d to parallel native machine code with optimizations such as loop fusion, vectorization, etc. Weld’s IR is natively parallel, so programs expressed in it can always be trivially parallelized.&lt;&#x2F;p&gt;
&lt;p&gt;We also have a new project called split annotations which will integrate with Weld that’s meant to lower the barrier for enabling these optimizations in existing libraries.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Optimizing numpy, pandas and scikit wouldn’t be easier? How faster it is?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Weld provides optimizations across functions in these libraries, whereas optimizing these libraries would only make individual function calls faster. In fact, many of these data libraries are already highly optimized on a per-function basis, but deliver performance below the limits of modern hardware because they do not exploit parallelism or do not make efficient use of the memory hierarchy. For example, many NumPy ndarray functions are already implemented in C, but calling each function requires scanning over each input in entirety. If these arrays do not fit in the CPU caches, most of the execution time can go into loading data from main memory rather than performing computations. Weld can look across individual function calls and perform optimizations such as loop fusion that will keep data in the CPU caches or registers. These kinds of optimizations can improve performance by over an order of magnitude on multi-core systems, because they enable better scaling.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-eheS9p1hxxEPH8Fqo3As8A.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;strong&gt;Prototype integrations of Weld with Spark (top left), NumPy (top right), and TensorFlow (bottom left) show up to 30x improvements over the native framework implementations, with no changes to users’ application code. Cross library optimizations between Pandas and NumPy (bottom right) can improve performance by up to two orders of magnitude.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is Baloo?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Baloo is a library that implements a subset of the Pandas API using Weld. It was developed by Radu Jica, who was a Master’s student in CWI in Amsterdam. The goal of Baloo is to provide the kinds of optimizations described above in Pandas to improve its single-threaded performance, reduce memory usage, and to enable parallelism.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Does Weld&#x2F;Baloo support out-of-core operations (say, like Dask) to handle data that does not fit in memory?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Weld and Baloo currently do not support out-of-core operations, though we’d love open source contributions on this kind of work!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why did you choose Rust and LLVM to implement weld? Was Rust your first choice?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We chose Rust because:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;It has a very minimal runtime (essentially just bounds checks on arrays) and is easy to embed into other languages such as Java and Python&lt;&#x2F;li&gt;
&lt;li&gt;It contains functional programming paradigms such as pattern matching that make writing code such as pattern matching compiler optimizations easier&lt;&#x2F;li&gt;
&lt;li&gt;It has a great community and high quality packages (called “crates” in Rust) that made developing our system easier.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;We chose LLVM because its an open source compiler framework that has wide use and support; we generate LLVM directly instead of C&#x2F;C++ so we don’t need to rely on the existence of a C compiler, and because it improves compilation times (we don’t need to parse C&#x2F;C++ code).&lt;&#x2F;p&gt;
&lt;p&gt;Rust was not the first language in which Weld was implemented; the first implementation was in Scala, which was chosen because of its algebraic data types and powerful pattern matching. This made writing the optimizer, which is the core part of the compiler, very easy. Our original optimizer was based on the design of Catalyst, which is Spark SQL’s extensible optimizer. We moved away from Scala because it was too difficult to embed a JVM-based language into other runtimes and languages.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;If Weld targets CPU and GPUS how does it compare to projects like RAPIDS that implements python data science libraries but for the GPU?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The main way Weld differs from systems such as RAPIDS is that it focuses on optimizing applications across individually written kernels by JIT compiling code rather than providing optimized implementations of individual functions. For example, Weld’s GPU backend would JIT-compile a single CUDA kernel optimized for the end-to-end application on the fly rather than calling existing individual kernels. In addition, Weld’s IR is meant to be hardware independent, allowing it to target GPUs as well as CPUs or custom hardware such as vector accelerators. Of course, Weld overlaps significantly and is influenced by many other projects in the same space, including RAPIDS. Runtimes such as Bohrium (a lazily evaluated NumPy) and Numba (a Python library that enables JIT compilation of numerical code) both share Weld’s high level goals, while optimizers systems such as Spark SQL have directly impacted Weld’s optimizer design.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Does weld have other applications outside data science library optimizations?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;One of the most exciting aspects of Weld’s IR is that it supports data parallelism natively. This means that loops expressed in the Weld IR are always safe to parallelize. This makes Weld an attractive IR for targeting new kinds of hardware. For example, collaborators at NEC have demonstrated that they can use Weld to run Python workloads on a custom high-memory-bandwidth vector accelerator just by adding a new backend to the existing Weld IR. The IR can also be used to implement the physical execution layer in a database, and we plan to add features that will make it possible to compile a subset of Python to Weld code as well.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Are the libraries ready to be used on real-life projects? If not, when can we expect them to be ready?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Many of the examples and benchmarks we’ve tested these libraries on are taken from real workloads, so we’d love it if users tried out the current versions for their own applications, provided feedback, and (best of all) submitted open source patches. That said, we don’t expect everything to work out of the box on real-life applications just yet. Our next few releases over the following couple months are focusing exclusively on usability and robustness of the Python libraries; our goal is to make the libraries good enough for inclusion in real-life projects, and to seamlessly fall back to the non-Weld versions of the libraries in places where support is yet to be added.&lt;&#x2F;p&gt;
&lt;p&gt;As I mentioned on the first answer, one path toward making this easier comes in the form of a related project called split annotations (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;weld-project&#x2F;split-annotations&quot;&gt;code&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;shoumik.xyz&#x2F;static&#x2F;papers&#x2F;mozart-sosp19final.pdf&quot;&gt;academic paper&lt;&#x2F;a&gt;). Split annotations are a system that allow annotating existing code to define how to split, pipeline, and parallelize it. They provide the optimization that we found was most impactful in Weld (keeping chunks of data in the CPU caches between function calls rather than scanning over the entire dataset), but they are significantly easier to integrate than Weld because they reuse existing library code rather than relying on a compiler IR. This also makes them easier to maintain and debug, which in turn improves their robustness. Libraries without full Weld support can fall back to split annotations when Weld is not supported, which will allow us to incrementally add Weld support based on feedback from users while still enabling some new optimizations.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Interview with Dask’s creator: Scale your Python from one computer to a thousand</title>
          <pubDate>Tue, 03 Sep 2019 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-dasks-creator-scale-your-python-from-one-computer-to-a-thousand/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-dasks-creator-scale-your-python-from-one-computer-to-a-thousand/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-dasks-creator-scale-your-python-from-one-computer-to-a-thousand/">&lt;p&gt;My love for building distributed systems with Erlang, databases and fetching huge volumes of data still lives on. But nowadays I want to have better theoretical and practical tools to understand the data. That is why I have been seriously studying probability, statistics and getting better at Python, numpy, pandas, scikit-learn, scipy and R. If you have read my earlier interviews you are probably aware of this.&lt;&#x2F;p&gt;
&lt;p&gt;That is why I decided to interview Dask’s creator Matthew Rocklin. Dask is a great bridge between the two areas that we specialize at my company &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;lambdaclass.com&#x2F;&quot;&gt;LambdaClass&lt;&#x2F;a&gt;: distributed systems and data science. Dask is a great tool to parallelize python libraries. When you have some spare time I highly recommend that you check its code. Meanwhile I leave you with Matthew’s answers.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;What is Dask? Why did you create it?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Dask is a Python library designed to parallelize other common Python libraries, like NumPy, Pandas, Scikit-Learn and others. It helps people use Python on either a single multi-core machine, or a large distributed cluster.&lt;&#x2F;p&gt;
&lt;p&gt;People tend to use it either as a “Big Pandas” or “Big NumPy”, or as a lower level library to build their own parallel systems.&lt;&#x2F;p&gt;
&lt;p&gt;Originally we created Dask to parallelize Numpy and Pandas. We quickly found that the internals of Dask were useful for many more things, so we quickly pivoted to exposing the internals as a generic parallel system.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Dask dataframes are a full replacement of pandas dataframes?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;No, the Pandas API is &lt;strong&gt;huge&lt;&#x2F;strong&gt; , so a full replacement is nearly impossible.&lt;&#x2F;p&gt;
&lt;p&gt;That being said, Dask Dataframe does implement the vast majority of popularly used Pandas functionality. Common staples like elementwise, reductions, groupbys, joins, rolling, timeseries, and more operations are all there. Additionally, because Dask dataframes are just a bunch of Pandas dataframes spread around a cluster it’s often pretty easy to convert custom code from Pandas to Dask easily.&lt;&#x2F;p&gt;
&lt;p&gt;It’s also worth noting that Dask != Dask Dataframes. Dataframes only account&lt;br &#x2F;&gt;
for about a third of Dask use out there. Dask goes way beyond just&lt;br &#x2F;&gt;
parallelizing Pandas.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Is there any downside of using Dask dataframes instead of pandas dataframes?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Oh definitely. If Pandas is solving your problem today, please don’t switch to Dask.&lt;&#x2F;p&gt;
&lt;p&gt;As with any distributed system, Dask adds a lot of complexity like network&lt;br &#x2F;&gt;
overheads, function serialization, and longer tracebacks in errors. We do a&lt;br &#x2F;&gt;
lot of work to keep our overhead small, both by keeping Dask lightweight and&lt;br &#x2F;&gt;
taking care of Python usability, but still, if you don’t need to switch, then&lt;br &#x2F;&gt;
don’t.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;How is it different form other distributed computation solutions (eg Hadoop MapReduce, Spark, Storm, Luigi, Airflow)?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Dask is a bit lower level and more generic than those systems, and so can be used to build up similar solutions using existing Python libraries.&lt;&#x2F;p&gt;
&lt;p&gt;For example:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;When we combine Dask with Pandas we get &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.dask.org&#x2F;en&#x2F;latest&#x2F;dataframe.html&quot;&gt;Dask Dataframes&lt;&#x2F;a&gt;, which are comparable with Spark DataFrames&lt;&#x2F;li&gt;
&lt;li&gt;When we combine Dask with Scikit-Learn we get &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;ml.dask.org&quot;&gt;Dask-ML&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;When we combine Dask with Python’s &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.dask.org&#x2F;en&#x2F;latest&#x2F;futures.html&quot;&gt;futures or async&#x2F;await&lt;&#x2F;a&gt; APIs we get a real-time framework, somewhat similar to Storm&lt;&#x2F;li&gt;
&lt;li&gt;When we combine Dask with &lt;em&gt;cron&lt;&#x2F;em&gt; like logic, we get an ETL framework like Airflow or Luigi. In fact, some of the Airflow developers split off and made &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.prefect.io&#x2F;&quot;&gt;Prefect&lt;&#x2F;a&gt; a successor to Airflow which delegates the execution and data movement to Dask&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Additionally, Dask can be combined with other libraries to get novel systems&lt;br &#x2F;&gt;
that aren’t in your list. For example:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;When we combine Dask with Numpy we get a scalable multi-dimensional &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.dask.org&#x2F;en&#x2F;latest&#x2F;array.html&quot;&gt;Dask Arrays&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;When we combine Dask with GPU-accelerated Pandas or Numpy like libraries like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;rapids.ai&quot;&gt;RAPIDS&lt;&#x2F;a&gt; we get distributed GPU-accelerated dataframes and arrays.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Internally, Dask has the scalability of a system like MapReduce or Spark, with&lt;br &#x2F;&gt;
the flexibility of a system like Luigi or Airflow. This combination is nice both when you’re building new systems, and means that Dask gets used in a ton of novel work.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;How does data locality affect the performance of Dask? Does it assume all data is local to workers?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;By data locality you might mean two things (both of which Dask handles well):&lt;&#x2F;p&gt;
&lt;p&gt;1. Where does the data live in some storage system, like S3 or HDFS?&lt;&#x2F;p&gt;
&lt;p&gt;Dask is more than happy to query a data-local storage system like HDFS,&lt;br &#x2F;&gt;
find out where all the data lives, and target computations appropriately.&lt;&#x2F;p&gt;
&lt;p&gt;However, this kind of workload is becoming increasingly rare. More often&lt;br &#x2F;&gt;
people are using storage systems that prefer global accessibility over data&lt;br &#x2F;&gt;
locality, so this matters less and less these days in practice.&lt;&#x2F;p&gt;
&lt;p&gt;2. Once data is in memory, can Dask avoid moving it around?&lt;&#x2F;p&gt;
&lt;p&gt;Dask thinks a lot about where to run computations, and avoiding needless&lt;br &#x2F;&gt;
data communication is a big part of this decision. Sometimes we do need to&lt;br &#x2F;&gt;
move data around, but yes, Dask certainly avoids this when possible.&lt;&#x2F;p&gt;
&lt;p&gt;Moreover, because Dask gets used with a &lt;strong&gt;wide&lt;&#x2F;strong&gt; variety of workloads, our&lt;br &#x2F;&gt;
scheduling heuristics have had to evolve quite a bit over the years. It’s very&lt;br &#x2F;&gt;
rare for us to find problems today on which Dask’s data locality heuristics&lt;br &#x2F;&gt;
don’t respond optimally.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is the biggest Dask cluster you have seen in production?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;One thousand Windows machines.&lt;&#x2F;p&gt;
&lt;p&gt;Dask gets used on some of the world’s largest super-computers (I was&lt;br &#x2F;&gt;
logged into &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.olcf.ornl.gov&#x2F;summit&quot;&gt;Summit&lt;&#x2F;a&gt;, the worlds largest super computer, just a few hours ago), and is deployed routinely on all major clouds.&lt;&#x2F;p&gt;
&lt;p&gt;However, Dask also scales down nicely. You can also just &lt;em&gt;import dask&lt;&#x2F;em&gt; and run it on a thread pool in a single python process or Jupyter notebook. As we like to say, &lt;em&gt;“The median cluster size is one”&lt;&#x2F;em&gt;. Dask is pure-Python, and super-lightweight if it needs to be. You can just &lt;code&gt;pip install dask&lt;&#x2F;code&gt; and it ships with the popular Anaconda distribution, which is deployed on millions of machines around the world.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;The Dask scheduler and Dask worker architecture, implementation and protocol was inspired by any other project?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The central scheduler + distributed worker architecture is pretty common today. It’s a pragmatic choice for systems that want to scale between 1–1000 nodes.&lt;&#x2F;p&gt;
&lt;p&gt;So sure, Dask was inspired by other projects. All of them :). Notably, Dask tries hard not to reinvent too much. We rely a ton on other infrastructure within the Python ecosystem. We use Tornado and asyncio for concurrency and peer-to-peer networking, Numpy, Pandas, and Scikit-learn for computation, and other Python APIs like concurrent.futures and joblib for user APIs.&lt;&#x2F;p&gt;
&lt;p&gt;Dask is really just a smashing together of Python’s networking stack with its&lt;br &#x2F;&gt;
data science stack. Most of the work was already done by the time we got here.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Which do are for you the most interesting frameworks, tools or libraries implemented on top of Dask and why?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I’ll list a few interesting frameworks, but there are a ton out there these days:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;xarray.pydata.org&quot;&gt;Xarray&lt;&#x2F;a&gt; is a library commonly used to study Earth system data, like the climate, meteorology, oceanography, satellite imagery, and more. It’s really gratifying to see people use Dask to finally be able to analyze these huge climate science simulations, and help us better understand the planet.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;prefect.io&quot;&gt;Prefect&lt;&#x2F;a&gt; provides a bunch of niceties on top of Dask for common Data Engineering or ETL workloads, similar to Airflow&#x2F;Luigi. We got these feature requests constantly when we were starting out but declared them out of scope. It was great to have another project come by, take that feature set, and implement it way better than we ever could.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;epistasislab.github.io&#x2F;tpot&quot;&gt;TPot&lt;&#x2F;a&gt; is a library for automatic machine learning. You give it a dataset, and it tries out a bunch of models and pre-processors to find a good model. TPot existed well before Dask, and it has really gnarly parallelism internally, which makes it hard for non-experts to accelerate. Fortunately the TPot and Dask developers were able to get this going in a weekend, and now you can scale out this search with Dask on whatever parallel hardware you have.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;rapids.ai&quot;&gt;RAPIDS&lt;&#x2F;a&gt; is a GPU-accelerated data science stack by NVIDIA. They were building out their own fast GPU implementation of Pandas and Numpy and wanted something to solve the multi-node problem for them. Dask was able to step in, handle all of the distributed communication, scheduling, and load balancing, and then step aside while NVIDIA’s fast GPU algorithms took over. (disclaimer, this is my current employer).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Could you please tell us about the work you are doing at NVIDIA to offload Dask computations to the GPU?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Yeah, RAPIDS is really exciting. It turns out that GPUs are good for things other than graphics and deep learning. They’re surprisingly effective at accelerating more traditional computing in data science (and actual science). Operations like dataframe joins, CSV parsing, FFTs, text processing, and more can often be accelerated 10x-200x. Historically you had to know C and CUDA to use these libraries though, which made them accessible only to somewhat experience software developers.&lt;&#x2F;p&gt;
&lt;p&gt;The RAPIDS project within NVIDIA is wrapping up all of these algorithms in Python, and exposing APIs to data science users that look like drop-in replacements for Numpy&#x2F;Pandas&#x2F;Scikit-Learn.&lt;&#x2F;p&gt;
&lt;p&gt;They use Dask to provide multi-GPU parallelism (some people have many GPUs in a single machine) and multi-node parallelism across a cluster. Dask’s&lt;br &#x2F;&gt;
flexibility, and the fact that it’s pretty unopinionated about what you run as&lt;br &#x2F;&gt;
computation make it the perfect fit. It’s also one of the only task schedulers&lt;br &#x2F;&gt;
out there that run in a non-JVM language, which helps if you use natively&lt;br &#x2F;&gt;
compiled code, like CUDA.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Do you have any book, MOOC or resource that you would recommend to those of us that want to learn more about the implementation of schedulers, concurrency models and distributed systems?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Ha! Sadly no.&lt;&#x2F;p&gt;
&lt;p&gt;Centrally managed distributed schedulers are, unfortunately, not a common topic of research these days. From an academic&#x2F;intellectual level it’s a fairly&lt;br &#x2F;&gt;
simple problem. Most of the difficult parts are in the details of engineering,&lt;br &#x2F;&gt;
which are unfortunately not that interesting to anyone who isn’t building a&lt;br &#x2F;&gt;
distributed scheduler.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Interview with Will Kurt on his latest book: Bayesian Statistics The Fun Way</title>
          <pubDate>Tue, 04 Jun 2019 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-will-kurt-on-his-latest-book-bayesian-statistics-the-fun-way/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-will-kurt-on-his-latest-book-bayesian-statistics-the-fun-way/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-will-kurt-on-his-latest-book-bayesian-statistics-the-fun-way/">&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-LDJcJQMeyOPU9lqAs98JBQ.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Like most devs, I have a diverse set of interests: functional programming, operating systems, type systems, distributed systems, and data science. That is why I was excited when I learned that &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;willkurt&quot;&gt;Will Kurt&lt;&#x2F;a&gt;, the author of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.manning.com&#x2F;books&#x2F;get-programming-with-haskell&quot;&gt;&lt;em&gt;Get Programming with Haskell,&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;__ wrote a a bayesian statistics book that is being published by No Starch Press. There aren’t many people that write books on different topics. I was sure that Will had something interesting to share in this new book. I wasn’t disappointed. The book is an excellent introduction, specially for those of us that have a rough time with advanced math but that want to advance in the data science field. I recommend reading the book after reading Think Stats, but before reading Bayesian Methods for Hackers, Bayesian Analysis with Python and Doing Bayesian Data Analysis.&lt;&#x2F;p&gt;
&lt;p&gt;If you like the interview I recommend that you also read the interviews we did with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;notamonadtutorial.com&#x2F;inteview-with-thomas-wiecki-about-probabilistic-programming-and-pymc-66a12b6f3f2e&quot;&gt;Thomas Wiecki&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;notamonadtutorial.com&#x2F;interview-with-osvaldo-martin-about-bayesian-analysis-with-python-a696b2bce3ba&quot;&gt;Osvaldo Martin&lt;&#x2F;a&gt; about Bayesian analysis and probabilistic programming.&lt;&#x2F;p&gt;
&lt;p&gt;Finally I wanted to thank two members of my team (Pablo Amoroso and Juan Bono) for helping me with the interview.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;1. Why a new statistics book?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Nearly all of the many excellent books on Bayesian statistics out now assume you are either familiar with statistics already or have a pretty solid foundation in programming. Because of this the current state of Bayesian statistics in often as an advanced alternative to classical (i.e. frequentist) statistics. So even though Bayesian statistics is gaining a lot of popularity, it’s mostly amount people who already have a quantitative background.&lt;&#x2F;p&gt;
&lt;p&gt;When someone wants to simply “learn statistics” they usually pick up an introduction based on frequentist statistics and end up half understanding a bunch of tests and rules, and feel very confused by the subject. I wanted to write a book on Bayesian statistics that really anyone could pick up and use to gain real intuitions for how to think statistically and solve real problems using statistics. For me there’s no reason why Bayesian statistics can’t be a beginners first introduction to statistics.&lt;&#x2F;p&gt;
&lt;p&gt;I would love it if, one day, when people said “statistics” it implied Bayesian statistics and frequentist statistics was just an academic niche. To get there we need more books that introduce statistics to a wide audience using Bayesian methods and assume this may be the readers first exposure to stats. I toyed with the idea of just calling this book “Statistics the Fun Way”, but I know I would probably get angry emails from people buying the book help with stats 101 and getting very confused! Hopefully this book will be a small step in getting “stat 101” to be taught from the Bayesian perspective, and statistics can make sense from the beginning.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;2. Who is your intended audience for the book? Could anyone without a math background pick it up?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;My goal with Bayesian Statistics the Fun Way was to create a book that basically anyone with a high school math background could pick up and read. Even if you only vaguely remember algebra, the book moves at a pace that should be easy to follow. Bayesian statistics does require just a little calculus and is a lot easier with a bit of code, so I’ve included two appendices that cover enough R to work as an advanced calculator and enough background in the ideas of calculus that when the book needs talk about integrals you can understand. But I promise that there is no solving of any calculus problems required.&lt;&#x2F;p&gt;
&lt;p&gt;While I worked hard to limit the mathematical prerequisites for the book, as you read through the book you should start picking up on mathematical ways of thinking. If you really understand the math your using, you can make better use of it. So I don’t try to shy away from any of the real math, but rather work up to it slowly so that all the math seems obvious as you develop your understanding. Like many people, I used to believe that math was confusing and difficult to work with. In time I really saw that when math is done right, it should be almost obvious. Confusion in mathematics is usually just the result of moving too quickly, or leaving out important steps in the reasoning.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;3. Why should software developers learn probability and statistics?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I really believe everyone should learn some probability and statistics because it really does help to reason about the uncertain world which is our everyday life. For software developers in particular there are few common places that its useful to understand statistics. It’s pretty likely that at some point in your career in software, you’ll need to write code that makes some decision based on some uncertain measurement. Maybe it’s measuring the conversion rate on a web page, generating some random reward in a game, assigning users to groups randomly or even reading information from an uncertain sensor. In all these cases really understanding probability will be very helpful. In the software part of my career I’ve also found that probability can help a lot in troubleshooting bugs that are difficult to reproduce or to trace back to a complex problem. If a bug appears to be caused by insufficient memory, does adding more memory decrease the probability of the bug in a meaningful way? If there are two explanations for a complex bug, which should be investigated first? In all these cases probability can help. And of course with the rise of Machine Learning and Data Science, engineers are more and more likely to be working on software problems that involve working directly with probabilities.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;4. Could you give a brief summary of the difference between the frequentist and bayesian approaches to probability?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Frequentists interpret probability as a statement about how frequently an event should occur in repeated trials. So if we toss a coin twice we should expect to get 1 head because the frequency of heads is 1&#x2F;2. Bayesians interpret probability as a statement of our knowledge, basically as a continuous version of logic. The probability of getting heads in a coin toss is 0.5 because I don’t believe getting heads is any more likely than getting tails. For coin tosses both schools of thought work pretty well. But when you talk about things like the probability that your favorite football team will win the world cup, talking about degrees of belief makes a lot more sense. This additionally means that Bayesian statistics does not make statements about the world but about our understanding of the world. And since we each understand the world a bit differently, Bayesian statistics allows us to incorporate that difference into our analysis. Bayesian analysis is, in many ways, the science of changing your mind.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;5. Why did you choose to focus on the bayesian approach?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;There are plenty of really great philosophical reasons to focus on Bayesian statistics but for me there is a very practical reason: everything makes sense. From a small set of relatively intuitive rules you can build out the solutions to any problem you encounter. This gives Bayesian statistics a lot of power and flexibility, and also makes it much easier to learn. I think this is something programmers will really like about Bayesian reasoning. You aren’t applying ad hoc tests to a problem, but reasoning about your problem and coming up with a solution that makes sense. Bayesian statistics is really reasoning. You agree to the statistical analysis only when it genuinely makes sense and convinces you, not because some seemingly arbitrary test result achieves some equally arbitrary value. Bayesian statistics also allows us to disagree quantitatively. It’s quite common in everyday life that two people will see the same evidence and come to different conclusions. Bayesian statistics allows us to model this disagreement in a formal way so that we can see what evidence it would take to change our beliefs. You shouldn’t believe the results of a paper because of a p-value, you should believe them because the truly convince you.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;6. How Bayesian Statistics Is Related To Machine Learning&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;One way I’ve been thinking about the relationship between Bayesian Statistics and Machine Learning (especially neural networks) in the way that each deal with the fact that calculus can get really, really hard. Machine Learning is essentially understanding and solving really tricky derivatives. You come up with a function and a loss for it, then compute (automatically) the derivative and try to follow it until you get optimal parameters. People often snarkily remark that backpropagation is “just the chain rule”, but nearly all the really hard work in deep learning is applying that successfully.&lt;&#x2F;p&gt;
&lt;p&gt;Bayesian statistics is the other part of calculus, solving really tricky integrals. The Stan developer Michael Betancourt made a great comment that basically all Bayesian analysis is really computing expectations, which is solving integrals. Bayesian analysis leaves you with a posterior distribution but you can’t use a distribution for anything unless you integrate over it to get a concrete answer. Thankfully no one makes snarky comments about integrals because everyone knows that it can be really tricky in the simplest case. This xkcd makes that point nicely:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-vska22BJzFePmtcrzokZ0A.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;So in this strange way the current state Machine Learning and Bayesian Statistics are what happens when you push basic calculus ideas to the limits of what we can compute.&lt;&#x2F;p&gt;
&lt;p&gt;This relationship also outlines the key differences. When you think about derivatives you’re looking for a specific point related to a function. If you know location and time, the derivative is speed and can tell you when you went the fastest. Moving the needle in ML is getting a single metric better than anyone else. Integration is about summarizing an entire process. Again if you know location and time, the integral is distance and tells you how far you’ve traveled. Bayesian statistics is about summarizing all of your knowledge about a problem, but this allows us to not just give single predictions but also say how confident we are in a wide range of predictions. Advancement in Bayesian statistics is about understanding more complex systems of information.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;7. If your readers wanted to dig deeper into the subject of the book, where would you point them to (books, courses, blog posts, etc)?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The biggest inspiration for this book was E.T. Jaynes’ “Probability Theory: the Logic of Science”. My secret hope is that “Bayesian Statistics the Fun Way” can be a version of that book accessible to everyone. Jaynes’ book is really quite challenging to work through and is presents a pretty radical version of Bayesian statistics. Aubrey Clayton has done an amazing service by putting together a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=rfKS69cIwHc&quot;&gt;series of lectures&lt;&#x2F;a&gt; on the key chapters of this book.&lt;&#x2F;p&gt;
&lt;p&gt;And of course if you liked reading the book you’d probably enjoy my &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.countbayesie.com&#x2F;&quot;&gt;blog&lt;&#x2F;a&gt;. I haven’t been posting much recently since I’ve been writing a “Bayesian Statistics the Fun Way” and before that “Get Programming with Haskell” but I’ve got a ton of posts in my head that I really want to get down on paper soon. Generally the blog, despite the name, is not strictly Bayesian. Typically if I have some statistics&#x2F;probability topic that I’m thinking about, it will get fleshed out into a blog post.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;8. In your experience, what is a concept from probability&#x2F;statistics that non experts find difficult to understand?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Honestly, the hardest part is interpreting probabilities. People really lost faith in a lot of Bayesian analysts like Nate Silver (and many others) when they were predicting 80% or so chance that Clinton would win the 2016 election and she didn’t. People felt like they had been tricked and everyone was wrong, but 80% chance really isn’t that high. If my doctor tells me I have an 80% chance to live I’m going to be really nervous.&lt;&#x2F;p&gt;
&lt;p&gt;A common approach to this problem is to point to probabilities themselves and say that they are a poor way to express uncertainty. The fix then is that you should be using odds or likelihood ratios or some decibel-like system similar to Jaynes’s idea of evidence. But after really thinking about probability for along time I haven’t found that there’s a universally good way to express uncertainty.&lt;&#x2F;p&gt;
&lt;p&gt;The heart of the problem is that, deep down, we really want to believe that the world is certain. Even among experienced probabilists there’s this persistent nagging feeling that maybe if you do the right analysis, learn the right prior, add another layer into your hierarchical model you can get it right and remove or at least dramatically reduce uncertainty. Part of what draws me to probability is the weird mixture of trying to make sense of the world and the mediation on the fact that even when trying your hardest, the world will surprise you.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;9. What are your thoughts on p-values as a measure of statistical significance? Could you give us a brief description of p-hacking?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;There’s two things wrong with p-values. First of all, p-values are not the way sane people answer questions. Imagine how this conversation would sound at work:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Manager: “Did you fix that bug assigned to you?”&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;You: “Well I’m pretty sure I didn’t not fix it…”&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Manager: “If you fixed it, just mark it fixed.”&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;You: “Oh no, I really can’t say that I fixed it…”&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Manager: “So you want to mark it ‘will not fix’?”&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;You: “No, no, I’m pretty sure that’s not the case”&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;p-values confuse people because they are, quite literally, confusing. Bayesian statistics gives you a posterior probability, which is exactly the positive answer to the question being posed that you want. In the previous dialog the Bayesian says “I’m pretty sure it’s fixed”, if the manager wants you to be more sure, you collect more data and then you can say “I’m basically certain it’s fixed”.&lt;&#x2F;p&gt;
&lt;p&gt;The second problem is the culture of arbitrarily picking 0.05 as some magic value that has meaning. Related to the previous question about understanding probabilities, a 5% chance of something occuring does not make it very rare. Rolling a 20 sided die and getting a 20 has a 5% chance, and anyone who knows of Dungeons and Dragons (D&amp;amp;D) knows that this is far from impossible. Outside of role playing games, focusing on a die roll is not a great system of verifying true from false.&lt;&#x2F;p&gt;
&lt;p&gt;And that brings us to p-hacking. Imagine you’re playing D&amp;amp;D with some friends and you role twenty 20-sided dice all at one. You then point one that landed on 20 and proclaim “that was the die I meant to roll, the rest are all just test dice.” It’s still cheating even if you technically did roll a 20. That’s what p-hacking essentially is. You keep doing analysis until you find something that is ‘significant’, and then claim that’s what you were looking for the entire time.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;10. Any closing recommendations on what book to read next after reading your book?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Now that I’ve finished writing this book I finally have time to start catching up on other books that I didn’t have time to read while writing it! I’m really enjoying Osvaldo Martin’s “Bayesian Analysis with Python” (I know Not Monad Tutorial interviewed him not long ago). It’s a great book that approaches Bayesian analysis through PyMC3. I really think the world of probabilistic programming is very exciting and will be more and more an essential part of practical Bayesian statistics. Another book I really want to read is Richard McElreath’s “Statistical Rethinking”. It has a second edition coming out soon so I’m slightly hesitant to get copy before that. McElreath has put up a bunch of great supporting material on his &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;xcelab.net&#x2F;rm&#x2F;statistical-rethinking&#x2F;&quot;&gt;website&lt;&#x2F;a&gt;, so I might not be able to wait until the 2nd edition to get a copy. Both of these sources would be great next steps following “Bayesian Statistics the Fun Way”. Another good recommendations would be Kruschke’s “Doing Bayesian Data Analysis”.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Sonic: a minimalist  alternative to Elasticsearch written in Rust</title>
          <pubDate>Tue, 02 Apr 2019 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/sonic-a-minimalist-alternative-to-elasticsearch-written-in-rust/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/sonic-a-minimalist-alternative-to-elasticsearch-written-in-rust/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/sonic-a-minimalist-alternative-to-elasticsearch-written-in-rust/">&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-ur9rT3EUiunAzys52MePnQ.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;« Sonic » is the mascot of the Sonic project. Valerian drew it to look like a psychedelic hipster hedgehog.&lt;&#x2F;p&gt;
&lt;p&gt;Database implementation sits in a nice spot between computer science and software engineering. There are lot of tradeoffs to consider. That is why nowadays we have a plethora of databases, each of them useful in a particular scenario. In the projects we work on at &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;lambdaclass.com&#x2F;&quot;&gt;LambdaClass&lt;&#x2F;a&gt; we always end up using the following: Redis, Elasticsearch, PostgreSQL, Kafka and Riak or Cassandra. It is difficult to keep up with the number of databases that are needed and it is even more difficult to learn about their internals.&lt;&#x2F;p&gt;
&lt;p&gt;I always end up using Elasticsearch to index documents, to generate autocompletes and for geolocation. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;valeriansaliou&#x2F;sonic&quot;&gt;Sonic&lt;&#x2F;a&gt; doesn’t solve all three problems but it is a good tool to solve the first two. I have not yet used it in production, but it seems like a good lightweight alternative to Elasticsearch.&lt;&#x2F;p&gt;
&lt;p&gt;Since we love databases and we are trying to focus on Rust projects, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;twitter.com&#x2F;nenearria&quot;&gt;Amin Arria&lt;&#x2F;a&gt; and I decided to interview Sonic’s creator, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;valeriansaliou&quot;&gt;Valerian Saliou,&lt;&#x2F;a&gt; who generously agreed. Also remember to check Sonic’s &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;valeriansaliou&#x2F;sonic&quot;&gt;repository&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;What is Sonic?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Sonic is an open-source search index server, written in Rust. It was built with simplicity, performance and lightweight-ness in mind. Sonic takes user queries in, and return identifiers. Those identifiers refer to actual documents in a relational database (eg. in our case: messages, helpdesk articles, CRM contacts, etc). Sonic does not store documents, which makes the whole system simple and efficient regarding storage, as an application getting search results from Sonic has to pull actual result data from another database (eg. MongoDB, MySQL, etc. given the search results IDs that are returned).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Don’t Solr, ElasticSearch, Tantivy and Toshi solve similar issues to Sonic? Why did you create a new alternative?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I run a business called Crisp, which provides 100,000 users with a customer support software. Users want to search in their messages, and some of our users have A LOT of messages. Using traditional open-source search index softwares (eg. Elasticsearch amongst others) proved to be too expensive for our freemium model, as those systems are heavy and thus require huge server CPU and RAM.&lt;&#x2F;p&gt;
&lt;p&gt;As a developer and sysadmin, I really love Redis for its simplicity and speed. In computer software, simplicity often provides speed, which is a good thing at scale. I built Sonic to be “the Redis of search”: simple features, simple network protocol.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why did you decide to use Rust? How was the experience of creating Sonic in Rust?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Rust makes the whole development experience smoother. The constraints of the language (eg. the borrow checker, the fact that there are no NULL values) guarantee that you won’t experience certain kinds of bugs while running your project in production (eg. NULL pointer exceptions and segmentation faults, which are unavoidable in programming languages such as C, C++ or Go; humans make mistakes).&lt;&#x2F;p&gt;
&lt;p&gt;I’ve already built other Rust projects in the past to support the Crisp infrastructure at scale, such as Bloom, Vigil and Constellation (which are also available as open-source software on my GitHub). Rust was no new thing to me; overall I love working with the language. My first Rust projects 2 years ago were a bit rough, as you have to spend a lot of time with the borrow checker getting in your way for “no reason”. Once you understand how it works, you become much more productive and Rust borrow checker errors become rare.&lt;&#x2F;p&gt;
&lt;p&gt;So overall, I can say that the experience of writing Sonic in Rust has been great. I love Rust. As a plus, it makes me become a better programmer.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is Sonic Channel? Is this feature inspired by Redis?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Sonic Channel is the name of the protocol used to communicate with Sonic over the network. As most application infrastructures today are distributed over multiple machines via the network, a TCP-based protocol to push new text data to the index and query the index was required. For performance reasons, I did not want to write an HTTP-based protocol, as Elasticsearch has.&lt;&#x2F;p&gt;
&lt;p&gt;After releasing Sonic, I got a lot of contributions from the community to build Sonic Channel libraries (integrations) for the most popular programming languages: Go, Python, Ruby, Java, PHP and JavaScript (runs on NodeJS only). This let developers push data and search for items in Sonic right from their application, in their preferred programming language. It makes the whole process of integrating Sonic easier that calling a REST API, and cleaner.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What data structures do you use to create the index and to autocomplete words?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The index is stored in a LSM (Log-Structured Merge-tree), which is used by RocksDB under the hood. To auto-complete words, Sonic uses an FST (Finite-State Transducer), which is explained in great details in an article by &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;BurntSushi&quot;&gt;BurntSushi&lt;&#x2F;a&gt; on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;blog.burntsushi.net&#x2F;transducers&#x2F;a&quot;&gt;his blog&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;An FST is stored on-disk for each Sonic (collection, bucket) pair, and is memory-mapped, which means that actual FST data is not loaded in RAM, but access is still fast. The downside of the Rust FST implementation that I’m using, is that any built FST is immutable. If a new word appears in a Sonic bucket, it needs to be pushed to the FST and thus a new FST needs to be re-built. Sonic runs a consolidation task periodically for mutated FSTs, and adds or remove words from them on-disk.&lt;&#x2F;p&gt;
&lt;p&gt;The FST structure is not only used for word auto-completion, but also for typo corrections (eg. it is capable of correcting “Englich” to “English”). It uses a Levenshtein automaton to achieve that (given a maximum Levenshtein distance that’s relative to the length of the word; ie. the longer a word is, the more typos you allow).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why did you choose RocksDB as the storage?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;facebook&#x2F;rocksdb&quot;&gt;RocksDB&lt;&#x2F;a&gt; (from Facebook) is built on LevelDB (from Google), which I had good experience using through the SSDB open-source software.&lt;&#x2F;p&gt;
&lt;p&gt;It is very good at keeping performance stable on huge key-spaces and minimizes disk usage by compressing old data (it has a leveled data storage architecture, where old data gets in lower levels, that can be compressed or compressed with a higher but slower ratio).&lt;&#x2F;p&gt;
&lt;p&gt;RocksDB improves on LevelDB, and is very configurable. This means Sonic users can tune the internals of RocksDB through Sonic configuration to get the best out of their setups given their server hardware (spinning disks or SSDs, how many CPU cores they have, etc.).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Any material you can offer for anyone wanting to learn how a search engine like Sonic works, and how to build it?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I’ve written a blog post summing up quickly &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;journal.valeriansaliou.name&#x2F;announcing-sonic-a-super-light-alternative-to-elasticsearch&#x2F;&quot;&gt;how Sonic works&lt;&#x2F;a&gt;. I plan to write an extensive documentation to explain the inner workings on Sonic, which is tracked on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;valeriansaliou&#x2F;sonic&#x2F;issues&#x2F;103&quot;&gt;this GitHub issue&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Overall, reading Sonic code should help understand how things work. I spent a lot of time commenting my code and making it as clear as possible.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is jemalloc and why do you use it?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;jemalloc is a memory allocator that has been originally written for FreeBSD. It was designed for modern CPU architectures, and is much better at managing memory on multi-core architectures. It has no benefits on single core architectures though, but has been proved to be as good as older allocators in the case of single-CPU. So at worst it’s as good as traditional allocators, at best it provides better performance on multi-core CPUs and reduced memory fragmentation.&lt;&#x2F;p&gt;
&lt;p&gt;Rust previously used jemalloc as its default allocator, and has recently moved to the system allocator for reasons other than performance. People can &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.bsdcan.org&#x2F;2006&#x2F;papers&#x2F;jemalloc.pdf&quot;&gt;read more on jemalloc&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Did you have any experience building something like this before? What do you recommend reading to other people to learn how to build a tool like Sonic?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I’ve built a great deal of server software, but I’ve never written databases. Databases can be hard, as they involve a great deal of lock strategies to prevent race conditions, so database developers have to be meticulous. Locks are hard to get right; locks in production are even harder: it’s easy to write code that dead-locks, while finding why a dead-lock occur is painful.&lt;&#x2F;p&gt;
&lt;p&gt;I’d recommend people willing to build a Sonic-like project to read existing source code. The best way to build things yourself it to understand how others did it in the past.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Do you think they are fine? Do you want to change anything?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Yes, looks like Sonic worked great so far. Crisp search is now snappy and our results are relevant. Our users are happy.&lt;&#x2F;p&gt;
&lt;p&gt;Our Sonic instance indexes half a billion objects (messages, articles, contacts). The compressed index is 20GB, and CPU usage under load is 10% of 1 Intel Xeon core. Sonic uses ~200MB of RAM for such a large index at worst, and 20MB when it’s cold-started. Search latency is under 1ms.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>An interview with the creator of Gleam: an ML like language for the Erlang VM with a compiler…</title>
          <pubDate>Mon, 01 Apr 2019 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/an-interview-with-the-creator-of-gleam-an-ml-like-language-for-the-erlang-vm-with-a-compiler/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/an-interview-with-the-creator-of-gleam-an-ml-like-language-for-the-erlang-vm-with-a-compiler/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/an-interview-with-the-creator-of-gleam-an-ml-like-language-for-the-erlang-vm-with-a-compiler/">&lt;h3 id=&quot;an-interview-with-the-creator-of-gleam-an-ml-like-language-for-the-erlang-vm-with-a-compiler-written-in-rust&quot;&gt;An interview with the creator of Gleam: an ML like language for the Erlang VM with a compiler written in Rust&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-ivv-xih7D4rulPdRNmSYkg.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I have been writting soft real time systems with Erlang for almost a decade and for that task I think it is the best tool we have around. The concurrency model, the preemptive scheduler, the GC, the profiling tools, the libraries and the community are excellent for the task. Distribution libraries like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;lasp-lang.readme.io&#x2F;docs&quot;&gt;Lasp&lt;&#x2F;a&gt; or distributed systems frameworks like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;riak_core_tutorial&quot;&gt;Riak Core&lt;&#x2F;a&gt; are not easily available in other languages. At last, cheap processes, non shared state, supervisors and the let it crash philosophy are great tools when you are writing backends. Instead of trying to catch all the errors at compile time, you accept that it is impossible to catch all the possible problems and you deal with that reality. It is a very different error handling model from what you can find in Haskell or OCaml.&lt;&#x2F;p&gt;
&lt;p&gt;However Erlang language is pretty simple. I always miss sum types when I am coding in Erlang. I miss ML’s type system expressiveness, safety and practicality. That is why I am interested in the development of Gleam, a statically typed functional programming language for the BEAM.&lt;&#x2F;p&gt;
&lt;p&gt;Another interesting thing about Gleam is that its compiler is written in Rust. I think that Rust is a sort of ML + C language. I like C since the developer is at the driver seat driving with manual transmission. I can’t explain very well but I have always seen C as a simple and powerful language but I have always disliked C++. Knowing that I like ML and C you might understand why I find Rust an interesting language.&lt;&#x2F;p&gt;
&lt;p&gt;To sum up we (me and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;JuanBono&quot;&gt;Juan Bono&lt;&#x2F;a&gt;) decided to do this interview with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;louispilfold&quot;&gt;Louis Pilfold&lt;&#x2F;a&gt; not only because of what it is, but also because it is implemented in Rust. Go ahead and check &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lpil&#x2F;gleam&quot;&gt;Gleam’s repo&lt;&#x2F;a&gt;!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-x_OU1YRmBR8037eqsSAfYA.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;Tell us a little about yourself. Have you been working on programming languages for long?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Professionally I’m a web programmer, but over the last 4 years my hobby projects have largely been compilers in one form or another. Two of the most popular ones have been Dogma (an Elixir to angry error message compiler) and exfmt (an Elixir to slightly prettier Elixir formatter). For the last year I’ve been focusing on Gleam, which is an ML inspired statically typed language for the Erlang ecosystem.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What was the first programming language you learned?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The first language I attempted to learn was C, though with no experience and nothing but a few youtube videos I didn’t make much progress. After that I discovered an online version of MIT’s introduction to computer science and worked my way through that, so Python was the first program I successfully learnt. After finishing the course I discovered Ruby, which became my day-to-day language and my introduction to the world of web dev and professional programming, and then Haskell, which really shaped how I think about solving problems with code.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why do you think that the ML languages are a good fit for the BEAM VM?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Both families share the same lambda calculus core, and once you’ve discarded the various bells and whistles of the individual languages (such as processes, type classes, module functors, etc) they all have strikingly similar semantics. Given these shared semantics I think we can take the much loved type systems of ML languages and the proven value of the BEAM VM to create a language that has the best of both, or at least lots of fun :)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;How does Gleam compare to the other ML-like initiatives targeting the Erlang VM? (Alpaca, Elchemy, etc). What are the main differences and what motivated you to create Gleam?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I think Gleam has a subtly different outlook to the other projects, it is more focused on using the learnings of ML to enhance the BEAM rather than creating an actual ML language. This thinking has resulted in some design differences such as simple interop in both directions, no auto-currying, no effects system, curly brace based syntax, and an Erlang style module system.&lt;&#x2F;p&gt;
&lt;p&gt;I’m very glad that there are multiple projects working in this area. If Gleam fails and one of the other projects manages to build a healthy community then I’ll still be happy, I just want at one to succeed so I can use it in the real world.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Do you compile Gleam directly to BEAM bytecode?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The Gleam compiler has had a few full rewrites. The previous version compiled to BEAM bytecode via Core Erlang, which is an intermediate representation with the Erlang compiler, but the current version compiles to regular Erlang source code that has been pretty-printed. This has a few nice advantages such as providing an escape hatch for people who no longer wish to use Gleam, and enabling Erlang&#x2F;Elixir&#x2F;etc projects to use libraries written in Gleam without having to install the Gleam compiler.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What kind of type system Gleam uses? (Hindley-Milner?)&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Gleam uses a Hindley-Milner type system with a fairly standard implementation of Algorithm W. One slightly unusual addition is that row types are used to represent both records (which are Erlang maps) and modules, making them polymorphic in a way that I believe fits the way we use maps and modules in Erlang&#x2F;Elixir.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Does the static typing provide any run-time guarantees beyond the compilation checks?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;At runtime all types have been erased and there are no run-time checks. This is nice for performance and makes calling Gleam from Erlang easier, but it means there’s no way of automatically handling an incorrect type annotation when calling Erlang from Gleam.&lt;&#x2F;p&gt;
&lt;p&gt;If you have an unruly or unreliable Erlang function that you wish to call from Gleam the standard library provides a module for handling dynamically typed data that can be used to handle the return values safely at runtime.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;How does the type system interact with message passing and distribution? How do you handle the message passing features of erlang? Have you given any thought on protocol specification as type checking?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Currently we don’t have a good solution for typed message passing and such, and development is currently focused on building the more run-of-the-mill parts of the language. Rather than introduce a flawed stop-gap solution that will later need to be replaced I’ve opted not to have first class support for the BEAM’s low level concurrency primitives, so these will have to be used via Erlang FFI.&lt;&#x2F;p&gt;
&lt;p&gt;On the other hand OTP behaviours such as gen_server can be implemented using Gleam’s first class module system, which is enough to start writing OTP applications using Gleam today.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why did you choose Rust for implementing the Gleam compiler? (instead of choosing erlang&#x2F;elixir, etc)&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Gleam started as a few little experiments in Elixir but fairly quickly shifted over to Erlang. In December 2018 I realised I was going to have to refactor the type inference module in a fairly major fashion in order to correct a mistake in the design. The typer was easily the most complex part of the compiler and had accrued a lot of technical debt as I learnt and iterated on the language so I wasn’t feel very confident about the refactoring, especially without a static type system to guide me.&lt;&#x2F;p&gt;
&lt;p&gt;I decided that a full rewrite of the compiler would give me a chance to produce a better application without the mistakes of the first version, and using a statically typed language would enable me to refactor more easily in future. I picked Rust, and after roughly 3 months I had a new compiler with roughly the same features, fewer bugs, and less tech debt. It’s also considerably faster.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Is Rust a good language for implementing programming languages?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Yes, I think so. The type system is sophisticated and robust enough to take refactorings that would have bested me in the Erlang version and complete them with relatively little stress and fewer bugs. The tooling, documentation, and libraries are delightful, and the community is exceptionally friendly and helpful.&lt;&#x2F;p&gt;
&lt;p&gt;As a nice little bonus the performance of Rust has improved the user experience somewhat; Compilation is faster and there’s no longer a noticeable lag caused by the Erlang virtual machine booting and loading the various modules.&lt;&#x2F;p&gt;
&lt;p&gt;However it’s certainly not a perfect language for compiler implementation. Rust’s linear type system means it doesn’t need a garbage collector, but it can be a very frustrating experience learning how to write code that type checks, and the resulting code can be quite verbose. I speculate that if I had opted to use OCaml instead the type inference code would be under half the size it currently is.&lt;&#x2F;p&gt;
&lt;p&gt;I’m quite sure that someone with more Rust experience could make a lot of my code more concise and remove unnecessary memory allocations, but what we have today performs well and isn’t too difficult to modify. Overall I’m very happy with the decision to use Rust.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What kind of features do you plan to add to Gleam in the future (if any)? Were you inspired by a specific language?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The two main features I’ve been asked about are typed message passing (as you have enquired about above!) and some form of ad-hoc polymorphism like Haskell’s type classes. I don’t think that type classes are a good fit for Gleam, though perhaps something like OCaml’s proposed implicit module system could be worth exploring. Either way it will be a long time before we can start to design and experiment here, there’s plenty to do beforehand.&lt;&#x2F;p&gt;
&lt;p&gt;I’d like to enhance how atoms are represented at type level. Currently we can say “this value is an atom”, but that’s about it. It would be more useful if we could say “this value is the atom ‘ok’ or the atom ‘error’”, or “this function can takes the atom ‘up’ or the atom ‘down’, but no other atom”. This could also be extended to create polymorphic enum variants too, though I’m unsure whether it makes sense to have those as well as Gleam’s existing pre-declared enums.&lt;&#x2F;p&gt;
&lt;p&gt;It could be fun to have some alternative backends for the compiler so that we can compile to Javascript or a native binary, allowing Gleam to be used for cloud functions, command line tools, and other applications to which BEAM is less suited.&lt;&#x2F;p&gt;
&lt;p&gt;A much more mundane feature I’m interested in is record punning, as found in Javascript or Haskell. It would be nice to be able to write this&lt;&#x2F;p&gt;
&lt;p&gt;let {name, score} = player&lt;&#x2F;p&gt;
&lt;p&gt;Instead of&lt;&#x2F;p&gt;
&lt;p&gt;let {name = name, score = score} = player&lt;&#x2F;p&gt;
&lt;p&gt;However that syntax has already been taken by tuples, so something would need to change for us to have this feature.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What recommendations would you give to someone who wants to start writing their first programming language?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Write lots of code in your language before writing the compiler! Solve lots of simple problems and compile it in your mind so that you can work out how all the different features would interplay and how it might work under the hood. Writing a compiler takes a lot of time so the more experimentation and learning you can do to build confidence in your language design the better. Changing syntax when you have one file of fake code takes seconds, while with a compiler it may take many hours. Worse still, changing the semantics of your language in your compiler could take days or weeks. It pays to get the design right first.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>How to earn your Macroeconomics and Finance white belt (as a software developer)</title>
          <pubDate>Thu, 07 Mar 2019 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/how-to-earn-your-macroeconomics-and-finance-white-belt-as-a-software-developer/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/how-to-earn-your-macroeconomics-and-finance-white-belt-as-a-software-developer/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/how-to-earn-your-macroeconomics-and-finance-white-belt-as-a-software-developer/">&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-DqV2jwq55q04VQDnm1lP-A.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I was always interested in economics. However until a few years ago I never really studied finance. Since I decided to change that, I have learnt finance from reading good and bad books, online courses, newspapers, blog posts and online forums and by executing trades. This post sums up and prioritizes the roadmap I recommend taking to learn about finance. Having a deep understanding of macroeconomics is not necessary to learn about finance, even less if you are only looking to manage your own money. However, I highly recommend that you invest some time to understand the basic foundations of how the economy works.&lt;&#x2F;p&gt;
&lt;p&gt;Andrew Lo, an MIT economist, said that while physics has three laws that explain 99% of the phenomena, finance has 99 laws that explain only 3%. Not only do we not fully understand how the economy works but also there is an endless debate on how it should function. Everyone has values and an ideology even if they don’t tell you. You should keep that in mind while studying economics. In this roadmap I try to recommend the tools easily available and that are a part of the current economic thought.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;basic-macroeconomics&quot;&gt;&lt;strong&gt;Basic macroeconomics&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;How the economic machine works&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Ray Dalio, founder of the biggest hedge fund in the world, created this 30 minute video called &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;PHe0bXAIuk0&quot;&gt;How the Economic machine works&lt;&#x2F;a&gt;. In this video he shares his template to understand how the the economy works. What is taught in this video is simple but really important. Don’t just watch it, study it.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;investopedia&quot;&gt;&lt;strong&gt;Investopedia&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Dalio’s video connects many concepts like transactions, market, central bank, monetary policy, fiscal policy, debt, collateral, credit, interest rate, inflation, deflation, productivity, economic cycles, deleveraging, recession and depression. If you don’t know what any of these words means or if you have doubts &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.investopedia.com&#x2F;search&quot;&gt;search&lt;&#x2F;a&gt; them. In most cases Investopedia will have simple and more begginner friendly definitions than Wikipedia. Also in general at the end of each article you can view useful examples and related concepts that it are useful to check.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;news&quot;&gt;&lt;strong&gt;News&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Some time ago I saw an interview with an old priest that has dedicated his life to keeping the Latin language alive. The interviewer asked him: “Why are you so good at Latin?”. The priest answered: “Do you see where I am sitting on? My butt. You sit on your butt and study Latin as long as I have. You’ll be a master too”. So the general idea is that it takes time master something, but anybody can do it. My biggest recommendation to learn more about economics and finance is to get a subscription for the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.ft.com&#x2F;&quot;&gt;Financial Times&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.economist.com&#x2F;&quot;&gt;The Economist&lt;&#x2F;a&gt;. Read the Financial Times every day, specially the Markets and Opinions sections. Read the weekly Economist magazine, especially the Finance and Economics section. It’s like working out, after some time you will see big changes but you won’t be able to see them by doing short-term comparisons. Learning and reading about the financial and economic situation of different countries of the world can be overwhelming at the beginning. Geopolitics is closely related to economics. These three Youtube channels are great for making sense of what you read: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;channel&#x2F;UCwnKziETDbHJtx78nIkfYug&quot;&gt;Caspian Report&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;channel&#x2F;UCT3v6vL2H5HK4loLMc8pmCw&quot;&gt;VisualPolitik&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;channel&#x2F;UCmmPgObSUPw1HL2lq6H4ffA&quot;&gt;Geography Now&lt;&#x2F;a&gt;. Geography Now is almost exclusively about geography but it is great to watch when you are reading news about a part of the world you don’t know much about. Caspian Report is the most profound of the three and tries to explain the deep structural reasons for what happens in the world. VisualPolitik doesn’t go as deep in the analysis as Caspian Report and has a noticeable political agenda but it is useful too.&lt;&#x2F;p&gt;
&lt;p&gt;My recommendation is that you avoid at all costs watching TV channels like CNBC or any newspaper that focus only on daily news. We live in a world without flavor, dominated by clickbait news and post-truth politics. Deep, slow to digest, opinionated analyses are hard to come by. I prefer to read anything that makes me think even if it is written by somebody that thinks or has opposite values to mine.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;macroeconomic-courses-and-books-optional&quot;&gt;&lt;strong&gt;Macroeconomic courses and books (optional)&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;To better learn the concepts that where mentioned by Ray Dalio’s video you should follow &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.khanacademy.org&#x2F;economics-finance-domain&#x2F;macroeconomics&quot;&gt;Khan’s Academy Macroeconomics course&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I am not a big fan of textbooks since I find them way too schematic, but if you want to advance in the subject you will need to read one. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.goodreads.com&#x2F;book&#x2F;show&#x2F;1753460.Principles_of_Economics&quot;&gt;Mankiw’s Principles of Economics&lt;&#x2F;a&gt; or &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.goodreads.com&#x2F;book&#x2F;show&#x2F;367710.Macroeconomics&quot;&gt;Krugman’s Macroeconomy&lt;&#x2F;a&gt; are the most basic. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.goodreads.com&#x2F;book&#x2F;show&#x2F;1308531.Macroeconomics&quot;&gt;Blanchard’s Macroeconomics&lt;&#x2F;a&gt; is a little bit more advanced. I am giving many options since you will probably find one of the three books at your library. Keep in mind that studying one of this textbooks is not needed to advance in studying finance. In addition, I don’t agree with their model of the economy but it is good to know how most economist think.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;finance&quot;&gt;Finance&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;learn-basic-finance-to-invest-your-own-money&quot;&gt;&lt;strong&gt;Learn basic finance to invest your own money&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;The first thing I recommend that you do is to follow Nobel prize Robert &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.coursera.org&#x2F;learn&#x2F;financial-markets-global&quot;&gt;Shiller’s Financial Markets course&lt;&#x2F;a&gt;. The course covers stocks, bonds, dividends, markets, brokers, exchanges, bubbles and basic financial market history. He explains things in a simple and concise way. With this course you will get a basic understanding of what finance is.&lt;&#x2F;p&gt;
&lt;p&gt;The next step on your journey should be to get some practical experience. The best way to do this is to open a brokerage account to invest some of your own money. Fees and safety should be the main considerations when choosing which broker to use. Also your nationality and where you live are big factors when choosing a broker. I had good experiences with Interactive Brokers, Saxo Bank and DEGIRO. Robinhood is a new player that you should check out too.&lt;&#x2F;p&gt;
&lt;p&gt;After opening your brokerage account you should decide what you want to invest in. The first book I recommend reading is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;gp&#x2F;product&#x2F;1119024927&#x2F;ref=as_li_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=1119024927&amp;amp;linkCode=as2&amp;amp;tag=aweaofcomsen-20&amp;amp;linkId=33NCCDPJIVOFUTL5&quot;&gt;A Wealth of Common Sense&lt;&#x2F;a&gt;. It is a very good book that explains how to create a simple framework to decide how to invest for the long term. A more dry and profound book to read that is pretty similar to the previous one is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;Random-Walk-Down-Wall-Street&#x2F;dp&#x2F;1324002182&quot;&gt;A Random Walk Down Wall Street&lt;&#x2F;a&gt;. It is an excellent critique to the so-called technical analysis and it sums up the different investigations that have shown that humans are not rational investors. It is a good book that demonstrates that for the retail investors the best thing to do is to put their money in passive, low-fee investment vehicles instead of paying a money manager that charges a lot and doesn’t even deliver market returns. My biggest issue with the book it is that it adheres way too strongly to the Efficient Market Hypothesis (EMH). Eugene Fama, another Nobel prize and one of the most important EMH adherents, said that &lt;em&gt;“In an efficient market, at any point in time, the actual price of a security will be a good estimate of its intrinsic value”&lt;&#x2F;em&gt;. That means that in general there is no free money laying around or that getting above-average returns is really difficult. That is correct especially for the retail and individual investor. However as you will see in the advanced part of this roadmap I recommend books that are critical of this theory.&lt;&#x2F;p&gt;
&lt;p&gt;Two great books that explain more complex investment strategies are &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.goodreads.com&#x2F;book&#x2F;show&#x2F;25029029&quot;&gt;Global Asset Allocation&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.goodreads.com&#x2F;book&#x2F;show&#x2F;21518331-global-value&quot;&gt;Global Value&lt;&#x2F;a&gt;. The Global Asset Allocation shows how diversifying your portfolio outside bonds and stocks can be useful. Global Value Allocation shows how investing in countries that are cheap, measured by fundamentals like the Price&#x2F;Earnings ratio, gets your great returns in the long run.&lt;&#x2F;p&gt;
&lt;p&gt;With Shiller’s course and these four books plus your broker account you should be perfectly able to invest your money in an intelligent way.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;financial-theory-and-derivatives&quot;&gt;Financial theory and derivatives&lt;&#x2F;h4&gt;
&lt;p&gt;At the beginning, learning about futures, swaps, options or derivatives can be overwhelming. Before stepping into more technical grounds I recommend that you read about the history of hedge funds with their successes and failures to understand what they did and how. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.barnesandnoble.com&#x2F;w&#x2F;more-money-than-god-sebastian-mallaby&#x2F;1100257890&quot;&gt;More Money Than God: Hedge Funds and the Making of A New Elite&lt;&#x2F;a&gt; by Mallaby does just that. A quote from the book:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Although Weymar looked to his teachers for help in refining his mathematical and computing skills, he was unimpressed by their efficient-market theories. “I thought random walk was bullshit,” he said later. “The whole idea that an individual can’t make serious money with a competitive edge over the rest of the market is wacko.”&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;As you can see, this book goes in the opposite direction than A Random Walk Down Wall Street. The success of the main protagonists depends on finding market inefficiencies, they are not believers in efficient market hypothesis. Thanks to a hedge fund called Quantopian that provides data, a development platform and education, you can write your own investment algorithms and backtest them to find this type of small market inefficiencies. Their free &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.quantopian.com&#x2F;lectures&quot;&gt;lectures&lt;&#x2F;a&gt; are a great resource that you should follow if you know how to code in Python and if you have some knowledge in probability and statistics. They will introduce you to futures, the Capital Asset Pricing Model, alpha and beta, factors, means reversion, pairs trading and long-short strategies.&lt;&#x2F;p&gt;
&lt;p&gt;After following these lectures it is time to move on into learning about options. Options are difficult because you are leveraged, they react non-linearly to volatility changes, time plays a huge factor in their pricing and their payoff function can be convex or concave (if you don’t understand what these words mean don’t worry). You can be right about your bet but still lose money and the other way around. They are a counter-intuitive beast. You can create a strategy with options that looses money 99% of the time and still make enough money on the 1% case to recover everything that was lost and more. There are two books I have used to understand options. The first book I have read is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.goodreads.com&#x2F;book&#x2F;show&#x2F;100827.Options_Futures_and_Other_Derivatives&quot;&gt;Options, Futures and Other Derivatives by John Hul&lt;&#x2F;a&gt;. It is a textbook that explains all the moving parts of a trade that involves derivatives. A good thing about the book is that is has quite a few exercises after each chapter so that you can double-check you really understood what you have read. Since it was difficult for me to grasp everything I have read from Hul’s book, I decided to read a second book called&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.goodreads.com&#x2F;book&#x2F;show&#x2F;119373.Option_Volatility_Pricing&quot;&gt; Option Volatility &amp;amp; Pricing: Advanced Trading Strategies and Techniques&lt;&#x2F;a&gt; that was written by Natenberg. The tone of the book felt like it was written by a practitioner. It was easier to digest. Hul’s book seemed a little bit more advance and I think it is better to read Natenberg book first and Hul’s book afterwards.&lt;&#x2F;p&gt;
&lt;p&gt;After learning the theory you should do some paper trading and real trading with options and futures before moving on. Now it is time to switch from the technical side of things to learning more about the history of financial theory and its critics. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.goodreads.com&#x2F;book&#x2F;show&#x2F;665134.The_Mis_Behavior_of_Markets&quot;&gt;The Misbehavior of Markets: A Fractal View of Financial Turbulence by Mandelbrot&lt;&#x2F;a&gt; is a book that summarizes the history of modern financial theory. After that, it shows that modern financial theory doesn’t take into account big market moves that happen more frequently that what the theory predicts. At the end of the book Mandelbrot proposes other ways of modelling financial markets. I found the critique more interesting than the proposal.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.goodreads.com&#x2F;book&#x2F;show&#x2F;13530973-antifragile&quot;&gt;Antifragile by Taleb&lt;&#x2F;a&gt; is a book that summarizes many ideas that Taleb wrote in Fooled by Randomness and The Black Swan. Similar to what Mandelbrot wrote, Taleb proposes that unpredictable events are far more frequent and influential than most models take into account. Therefore, we should build anything, including our financial strategies, in a manner that benefits from chaos rather than try to avoid it.&lt;&#x2F;p&gt;
&lt;p&gt;After learning about the tools at your disposal and the dangers involved in trading with options it is time to learn how to really trade volatility. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.goodreads.com&#x2F;book&#x2F;show&#x2F;24945749-trading-volatility&quot;&gt;Trading Volatility by Bennett&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.goodreads.com&#x2F;book&#x2F;show&#x2F;5404804-volatility-trading&quot;&gt;Volatility Trading by Euan Sinclair&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.goodreads.com&#x2F;book&#x2F;show&#x2F;31867439-the-volatility-smile&quot;&gt;Volatility Smile by Emanuel Derman&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.goodreads.com&#x2F;book&#x2F;show&#x2F;204689.Dynamic_Hedging&quot;&gt;Dynamic Hedging by Nassim Taleb&lt;&#x2F;a&gt; are the best books in the area. I have only studied the first two. The last two are more complex and I have only done superficially and rapid lecture.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;other-skills&quot;&gt;Other skills&lt;&#x2F;h4&gt;
&lt;p&gt;At some point you need to learn more about financial accounting. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;playlist?list=PLUkh9m2BorqnKWu0g5ZUps_CbQ-JGtbI9&quot;&gt;Aswath Damodaran has a great course&lt;&#x2F;a&gt; about companies valuation that I recommend that you follow&lt;&#x2F;p&gt;
&lt;p&gt;The modern monetary system can not be separated from the financial markets. This was deeply visible in the last financial crisis. It is important to understand how the banking and monetary system works from a practical point of view. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.coursera.org&#x2F;learn&#x2F;money-banking&quot;&gt;Mehrling’s course&lt;&#x2F;a&gt; is a great introduction to this.&lt;&#x2F;p&gt;
&lt;p&gt;At last, probability and statistics are the best tools we have to assess an work with risk. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.goodreads.com&#x2F;book&#x2F;show&#x2F;12042357-think-stats&quot;&gt;Thinks Stats&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;camdavidsonpilon.github.io&#x2F;Probabilistic-Programming-and-Bayesian-Methods-for-Hackers&#x2F;#contents&quot;&gt;Probabilistic Programming &amp;amp; Bayesian Methods for Hackers&lt;&#x2F;a&gt; are the best practical books I can recommend to quickly learn probability and statistics. If you want to start the trip that goes down the rabbit hole I recommend that you do &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.coursera.org&#x2F;specializations&#x2F;statistics&quot;&gt;Statistics with R Specialization by Duke&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Interview with Osvaldo Martin about Bayesian Analysis with Python</title>
          <pubDate>Mon, 11 Feb 2019 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-osvaldo-martin-about-bayesian-analysis-with-python/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-osvaldo-martin-about-bayesian-analysis-with-python/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-osvaldo-martin-about-bayesian-analysis-with-python/">&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-NpQf9G3ZdnMXLT-QT3sErQ.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Like our &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;notamonadtutorial.com&#x2F;inteview-with-thomas-wiecki-about-probabilistic-programming-and-pymc-66a12b6f3f2e&quot;&gt;previous interviewee&lt;&#x2F;a&gt; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;aloctavodia&quot;&gt;Osvaldo Martin&lt;&#x2F;a&gt; is one of the developers of PyMC3 and ArviZ. He is a researcher specialized in Bayesian statistics and data science. He will be speaking at our &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;buzzconf&quot;&gt;BuzzConf&lt;&#x2F;a&gt; this year. I hope you like this interview as much as we did!&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h4 id=&quot;can-you-tell-us-how-data-analysis-has-improved-over-the-years&quot;&gt;Can you tell us how data analysis has improved over the years?&lt;&#x2F;h4&gt;
&lt;p&gt;This is not a simple question to answer, specially if we take into account that we have been doing data analysis from ancient times. The analysis of astronomical data has a long tradition it even predates (modern) science. For most of our history it was motivated by the many different religious liturgies we have invented over the centuries and the more &lt;em&gt;grounded&lt;&#x2F;em&gt; need of improving and controlling the food production. Fast-forwarding thousand of years one can argue that the data-driven studies of astronomers like Tycho Brahe had a decisive impact on setting up the scientific revolution. Astronomy and astrology were not fully separated by that time, but Brahe, based on his observations and experience already thought that astrologists were just charlatans and he maintains that the planets and stars have null influence over the human affairs. If that’s not a Data Scientist, who is?&lt;&#x2F;p&gt;
&lt;p&gt;So the “big thing” we are living now is not that we suddenly realize data is important, we have already known that for centuries, the difference is that now we have tons of available data from scientific disciplines like Biology and Astronomy, just to name two, and from daily interactions with streaming platforms, social networks, cell phones, and sensors all around us. Computers have made this possible by increasing our capacity to storage, process and transmits information by several order of magnitude, and perhaps equally important computers has also changed the way we ask questions and provide answers. There is a whole array of new methods to analyze and generate data, that are impractical without computers. Indeed, the modern practice and development of Bayesian methods have been profoundly influenced by the computers and computational methods up to the point that modern Bayesian statistics IS computational statistics. The only reason we are talking now about probabilistic programming, Machine Learning and Data Science is because we have cheap and fast computers.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;can-you-tell-us-in-brief-how-pymc3-and-arviz-help-with-bayesian-analysis&quot;&gt;Can you tell us in brief how PyMC3 and ArviZ help with Bayesian Analysis?&lt;&#x2F;h4&gt;
&lt;p&gt;PyMC3 is a probabilistic programming language offering two main components: a very clear syntax to define probabilistic models and a powerful set of methods to solve those models, mainly Markov Chain Monte Carlo and Variational Inference. Ideally the methods to solve probabilistic models should be Universal in the sense that they should be able to solve any valid probabilistic model. Unfortunately, even when current methods are very powerful they do not always work as we like, some models are still very difficult or slow to solve. Thus an important step in Bayesian Analysis is to check that inference was done properly. And this is one the motivations for creating ArviZ, a Python package for exploratory analysis of Bayesian models. ArviZ Includes functions for posterior analysis, sample diagnostics, model checking, and comparison. ArviZ works hand-in-hand with PyMC3, and other probabilistic programming language, like PyStan, emcee, Pyro, etc. Where the aim of the probabilistic programming languages is to make it easy to build and solve Bayesian models, the aim of the ArviZ library is to make it easy to process and analyze the results from the Bayesian models.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;can-you-explain-some-of-the-main-concepts-of-bayesian-analysis&quot;&gt;Can you explain some of the main concepts of Bayesian Analysis?&lt;&#x2F;h4&gt;
&lt;p&gt;Bayesian analysis can be summarized in just two concepts. Use probability distributions to represents the uncertainty in your model parameters. Then use Bayes theorem to update those probabilities given the data you have. All the rest derives from these two main concepts. Other concepts that are important to the practice of Bayesian Analysis are shared with other modeling approaches, like evaluating if models make sense by comparing their output against the data and the available domain-knowledge.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;why-do-you-like-working-with-data&quot;&gt;Why do you like working with data?&lt;&#x2F;h4&gt;
&lt;p&gt;I am not sure I “like” working with data, working with data is hard, data collection, data wrangling, cleaning and processing is generally time consuming. Data &lt;em&gt;per se&lt;&#x2F;em&gt; is not important what really matters is understanding phenomena, solving problems and designing better tools to solve problems. What happens is that data is essential to all these tasks. To answer any question in a scientific way you will need data at some point, for some problems you can progress a lot with just theory, but eventually you will need some data. The only scientific discipline that can avoid using data is pure mathematics. And for that reason many people do not think that mathematics is a scientific discipline, or if so they classify it as a logical science and not a factual one.&lt;&#x2F;p&gt;
&lt;p&gt;Everyone is talking about the data deluge and thus is easy to miss that data is produced by someone and that producing data is not always easy or cheap. Even when we have access to pre-existing data it may need further processing or it may not be suitable to answer our questions and thus we may need to generate data from scratch. In general, answering specific questions requires generating specific data under specific conditions. Just a few years ago many computational biologists and bioinformaticians believed that by extracting biological information from scientific journals and databases we will be able to build very reliable models of the cell. It turns out that while this is a good idea, is not that easy as its sounds and not applicable to every question. Papers are behind paywalls, written in formats not that easy to analyze programatically, experiments are performed under so many different conditions that integrating the information coherently is closer to a bad breakup than a romantic dinner, some experimental results are too noisy or the experimental design is flawed, observations can be contradictory, information in databases need to be further curated, etc.&lt;&#x2F;p&gt;
&lt;p&gt;To many people Data Science have put “data” in the spotlight, but science has always been data-driven. Charles Darwin was responsible from one of the most elegant scientific theories, and one of the most misrepresented ones. He spent years and years collecting data, not for the sake of having data but to try to make sense of the diversity and complexity of living organisms. Nowadays evolutionary biologists still spend a lot of time producing and gathering data from carefully designed observations, experiments and simulations in order to refine evolutionary ideas.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-are-the-advantages-and-disadvantages-of-using-python-over-other-languages-for-data-analysis&quot;&gt;What are the advantages and disadvantages of using Python over other languages for data analysis?&lt;&#x2F;h4&gt;
&lt;p&gt;One of the reasons I use Python is that it is a general purpose language, and while I spend a lot of time on data-analysis related stuff I also use Python to solve other types of problems. I learned to program during my PhD without formal training but with the help of great books like Think Python by Allen Downey and A Primer on Scientific Programming with Python by Hans Petter Langtangen, and also helped in many different ways by a large, welcoming and enthusiastic Python community.&lt;&#x2F;p&gt;
&lt;p&gt;At the time of my PhD most of my “coding” was about automating boring stuff and gluing specific scientific packages in order to perform molecular simulations and very very simple data-analysis problems. I used to do that using a collections of poorly documented (and probably poorly written) bash scripts. With the time this approach turns to be too restrictive, so I tried to learn Fortran and C, but I found them overcomplicated for most of the tasks I wanted to solve at the moment, and only very useful for a subsets of them… until I find Python! As someone said Python is not the best programming language for almost any task but is good enough for most of them as I would discover with the pass of time and with every new project that involved Python. One super tedious task for me at that moment was updating plots. I used a software with a GUI (and open source clone of a reeeeeally expensive proprietary scientific plotting software). Updating plots after re-running a simulation or noticing a mistake or getting feedback from my advisors or peers was a lot of work. Somehow, I did not remember the exact moment I found matplotlib, that was a deal-breaker for me and one of the reasons to learn even more Python.&lt;&#x2F;p&gt;
&lt;p&gt;Another epiphany was when I re-wrote a small piece of software a colleague kindly passed to me. Like me, my colleague was a non-computer-scientist. This code was a collection of bash scripts and a Fortran main program. I started with the bash scripts, instead of running several bash scripts I unified all of them into a collection of coherent Python functions. This already make my workflow easier and I was already super-happy, then I decide to change the Fortran code, at first this was mainly an exercise to challenge myself to learn more NumPy and Scipy. After many attempts to get this right (I never truly learned Fortran) I got a working Python version of the code, this code was not only much more shorter, easier to read and more modular, but to my surprise it was also 10x faster! Most of the speed-up come by replacing a lot of Fortran code with a SciPy call and a couple of NumPy array operations. And this was an important lesson to me. Do not re-invent the wheel, there are many specialized, well-tested, efficient routines out there, use them! Because while Python is &lt;em&gt;slow&lt;&#x2F;em&gt; not being proficient programmer in a &lt;em&gt;fast&lt;&#x2F;em&gt; language like Fortran or C can be even slower!&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-aspects-of-doing-bayesian-analysis-with-python-do-you-feel-are-tricky-to-get-past&quot;&gt;What aspects of doing Bayesian Analysis with Python do you feel are tricky to get past?&lt;&#x2F;h4&gt;
&lt;p&gt;For newcomers getting a fully functional Python environment can sometimes be tricky. Anaconda (a scientific Python distribution) and conda (a package manager) have helped a lot to get things installed properly, specially for Windows users.&lt;&#x2F;p&gt;
&lt;p&gt;When I show PyMC3 code to people most of them seem surprised by how much you can do with a few lines of codes. I even get responses like “that’s not programming” which I totally agree is just using a programming language to give instructions to a computer and get things done ;-) The challenge when using PyMC3 is then not so much on the programming-side but on the mental-modeling side, at first most people has problems figuring out how to express they problems in terms of a probabilistic model. This is a matter of practice and the creative part of the job. In the book I tried to show many examples of different models to help ease this transition to thinking probabilistically. This is something that needs practice, knowing that most pop-songs are built from the same chord progression of 3 to 4 chords that’s not automatically makes you a pop-star.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;your-take-on-the-data-analysis-environment-with-regards-to-innovations-in-it-the-knowledge-and-skills-gap-and-software-development-how-do-you-think-the-tech-landscape-is-changing&quot;&gt;Your take on the data analysis environment with regards to innovations in it, the knowledge and skills gap, and software development. How do you think the tech landscape is changing?&lt;&#x2F;h4&gt;
&lt;p&gt;My impression is that we now have something that was completely unimagined just a couple of decades ago: the popularization of very powerful computer methods. One of the side effects of the computer revolution is that any person with a modest understanding of a programming language like Python now has access to a plethora of powerful computational methods for data analysis, simulations, and other complex tasks. I am totally in favor of this, is one of my motivation to work on Open Source Software projects and to give free courses at the University. But I also recognize that this should be an invitation to us, as a community, to be extra careful about these methods not only to be able to apply them correctly from a technical point of view and to avoid making false claims but also from an ethical and democratic perspective. Otherwise we face the risk of giving too much control over important decisions to an increasingly reduced group of rich and powerful people and corporations, something that I am afraid is already happening and with disastrous consequences for those of us that not are part of the super-rich club. To turn this popularization of methods into a true democratization we need not only to make the methods accessible we also need to make other resources widely available. If the majority of the data generating processes, the data itself and the most powerful hardware is controlled by a small group then, we are not aiming for a true democracy we are just spending a lot of resources into training a high skilled work-force to serve the interest of a few and that is just a technocratic version of an oligarchy.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Inteview with Thomas Wiecki about Probabilistic programming and PyMC</title>
          <pubDate>Fri, 16 Nov 2018 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/inteview-with-thomas-wiecki-about-probabilistic-programming-and-pymc/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/inteview-with-thomas-wiecki-about-probabilistic-programming-and-pymc/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/inteview-with-thomas-wiecki-about-probabilistic-programming-and-pymc/">&lt;h3 id=&quot;inteview-with-thomas-wiecki-about-pymc-and-probabilistic-programming&quot;&gt;Inteview with Thomas Wiecki about PyMC and probabilistic programming&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-Ke59y1Iyox6MUJ1HpEkLyg.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;“A colleague of von Neumann and Ulam, Nicholas Metropolis, suggested using the name &lt;strong&gt;Monte Carlo&lt;&#x2F;strong&gt; , which refers to the Monte Carlo Casino in Monaco where Ulam’s uncle would borrow money from relatives to gamble”&lt;&#x2F;p&gt;
&lt;p&gt;After studying and working with distributed systems my interests drifted into data science, artificial intelligence, machine learning and now statistics. After a while I found I really liked applying what I have learnt into finance. That is how I learnt about probabilistic programming and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.pymc.io&#x2F;&quot;&gt;PyMC&lt;&#x2F;a&gt; while reading Thomas Wiecki posts at &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;blog.quantopian.com&#x2F;&quot;&gt;Quantopian blog&lt;&#x2F;a&gt;. That’s why we decided to interview Thomas. I hope you like this interview as much as we did.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;What is probabilistic programming?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Probabilistic Programming is a paradigm that allows the expression of Bayesian statistical models in computer code. Imagine you run an A&#x2F;B test and want to know which version is better. With a few lines of code you could build a model with 2 convergence rate parameters that are linked to the data you observed this far. So far that’s only model specification. The real power in probabilistic programming comes from the inference algorithms that have become so powerful that they usually work very well no matter what model you throw at them. So all you have to do is build the model, hit the inference button and analyze your outputs. In this example, the outputs will be the estimates of the convergence rates for both conditions as well as the uncertainty in those estimates. From there it is trivial to extract statements such as “with x% probability, version A has a higher convergence rate than version B”.&lt;&#x2F;p&gt;
&lt;p&gt;This is a really simple example but these models can get staggeringly complex, depending on the problem you are trying to solve.&lt;&#x2F;p&gt;
&lt;p&gt;In general, whenever you have a problem where uncertainty plays a big role, where there is structure to be exploited (e.g. hierarchical), or you have prior knowledge you want to include in the model, probabilistic programming is the tool of choice.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is PyMC?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;PyMC3 is such a probabilistic programming framework. It is different from most previous frameworks in that it does not require you to write models in a domain specific language but in plain Python. It features state-of-the-art inference algorithms and diagnostics, flexible support for Gaussian Processes, model comparison metrics, and has a very active community.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why was PyMC created? What is the difference with other projects like Edward and Stan?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;PyMC3 is a result of the desire to implement next-generation Hamiltonian Monte Carlo (HMC) samplers which are vastly superior to previous MCMC algorithms. Contrary to these previous algorithms, HMC requires gradients to be computed. Theano was the first library that allowed to build a compute graph in Python from which it is easy to automatically compute gradients. John Salvatier went through various designs until he came up with the core design that would constitute PyMC3. While HMC is the core motivation, Theano provides many other benefits to PyMC3, like high performance due to graph optimizations and compilation to CPU and GPU, while keeping the model definition and code-base pure Python.&lt;&#x2F;p&gt;
&lt;p&gt;The biggest difference to Stan is that this one is written in C++ with a custom DSL to define models. This is great as it allows interfaces from various languages but it comes at the cost of a more complex code-base, and having to learn a DSL rather than being able to use Python. Having said that, PyMC3 is hugely inspired by Stan in many ways.&lt;&#x2F;p&gt;
&lt;p&gt;Edward is a more recent PPL built on TensorFlow so in that way it is quite similar to PyMC3 in that you can construct models in pure Python. Its focus is more on variational inference (which can also be expressed in the same PPL), scalability and deep generative models. I don’t think it is actively developed anymore so I think some interested should take a look at TensorFlow Probability instead.&lt;&#x2F;p&gt;
&lt;p&gt;In general, I would say that if you are a ML researcher developing new deep networks or variational inference algorithms, use TensorFlow Probability; if you are an R user with a statistical background, use Stan; if you are a Data Scientist most comfortable in Python, use PyMC3.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Could you please tell us about real world examples where PyMC is being used?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;PyMC3 is widely used in academia, there are currently close to 200 papers using PyMC3 in various fields, including astronomy, chemistry, ecology, psychology, neuroscience, computer security, and many more. It is also used to solve various business problems by large and small companies. One common use case I have heard is for A&#x2F;B testing, which makes sense as uncertainty plays a big role. Another problem well solved by PyMC3 is supply chain optimization.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;How does PyMC differ from other probabilistic programming languages (eg Figaro, Church, Anglican)?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;These more academic PPLs really push the envelope of what is possible to do in this framework. They are Turing complete and thus there is little that can not be done. Often these high standards on theoretical guarantees and pureness of the PPL come at the cost of usability and performance. PyMC3 on the other hand is focusing on solving 80% of the problems encountered in reality as succinctly and performant as possible.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;How far is support for Deep Learning methods integrated into PyMC?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I wrote a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;twiecki.github.io&#x2F;blog&#x2F;2016&#x2F;06&#x2F;01&#x2F;bayesian-deep-learning&#x2F;&quot;&gt;couple&lt;&#x2F;a&gt; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;twiecki.github.io&#x2F;blog&#x2F;2016&#x2F;07&#x2F;05&#x2F;bayesian-deep-learning&#x2F;&quot;&gt;of&lt;&#x2F;a&gt; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;twiecki.github.io&#x2F;blog&#x2F;2017&#x2F;03&#x2F;14&#x2F;random-walk-deep-net&#x2F;&quot;&gt;blog&lt;&#x2F;a&gt; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twiecki.github.io&#x2F;blog&#x2F;2018&#x2F;08&#x2F;13&#x2F;hierarchical_bayesian_neural_network&#x2F;&quot;&gt;posts&lt;&#x2F;a&gt; exploring these topics. As deep learning was Theano’s original purpose we can tap into a lot of that functionality and extend deep nets in interesting ways. I have not seen it been much explored elsewhere, however. PyMC4 will be based on TensorFlow Probability (TFP) which definitely has a strong focus on deep generative models so this type of model will be much easier to build and TFP’s powerful inference algorithms will also allow it to scale.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What are the tradeoffs of using Variational Inference vs standard Markov chain Monte Carlo with regards to finance?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Variational inference is generally much faster at the cost of a less accurate approximation of the posterior. In finance you are often operating under razor-thin margins so everything counts. My recommendation is to thus use MCMC.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Is there support for modelling Generalized Extreme Value distributions in PyMC3?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I haven’t come across that one yet but it looks like it should be fairly easy to add. We certainly have the Gumbell and Weibull distribution which are special cases of it.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;How is model criticism implemented?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;There is pymc3.sample_posterior_predictive() which allows you to generate new data from your model which you can then compare to your original data to test if the model can capture the important properties in your model. See &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.pymc.io&#x2F;notebooks&#x2F;posterior_predictive.html&quot;&gt;https:&#x2F;&#x2F;docs.pymc.io&#x2F;notebooks&#x2F;posterior_predictive.html&lt;&#x2F;a&gt; for more information.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;How do you use PyMC3 at Quantopian?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We use it in various places, but most critical for portfolio weighting. At Quantopian our challenge is to evaluate return streams of trading algorithms over limited time periods to decide if they have an edge in the market or just got lucky over a certain time-period. Thus, correctly quantifying uncertainty is critical. The return streams themselves have many challenging characteristics on top of that which are important to consider when trying to select them. Some key characteristics are that over time, they often change volatility; the “edge” they have can also vary over time; and they can be correlated with other strategies you are considering.&lt;&#x2F;p&gt;
&lt;p&gt;Adrian Seyboldt built a fairly sophisticated model which takes all these properties (and more) into account and ends up having tens of thousands of parameters. The incredible thing about PyMC3 and HMC is that this hugely complex model can be fit in well under an hour. But the really business critical advantage is that once this model is fitted, correctly attributing all the uncertainty in these various characteristics, we can put everything into an optimizer to give us the optimal portfolio. This way, we solve the algorithm selection &lt;em&gt;and&lt;&#x2F;em&gt; portfolio weighting problem in one go. Before, there was a lot of discretionary leeway in what constitutes enough evidence that an algorithm should be turned on or off leading to suboptimal decisions.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Has PyMC been ever used to price financial derivatives?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Not to my knowledge but I would not be surprised if they had been used for that. People come up to me constantly at conferences and tell me about the cool domain problems they solved with PyMC3 at their company. I love hearing about this because it is hard to assess how many and for what purpose people use your software.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;How big a problem is autocorrelation in sampling financial (tail risk, pricing) distributions?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It is definitely an important source of risk that is often ignored when applying frequentist statistics to finance, as the normality assumption is baked into most tests. Using probabilistic programming we can model changes in volatility like the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.pymc.io&#x2F;notebooks&#x2F;stochastic_volatility.html&quot;&gt;stochastic volatility model&lt;&#x2F;a&gt; does. Alternatively one can also use a Student-T distribution for the likelihood which allows for heavier tails.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What could be improved in PyMC?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I think the documentation and website needs more work to make it easier to find things and more beginner friendly. We also recently spun out the plotting code into a separate project called &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;arviz-devs.github.io&#x2F;arviz&#x2F;&quot;&gt;ArviZ&lt;&#x2F;a&gt;. In the upcoming release, we will slowly transition to using that library.&lt;&#x2F;p&gt;
&lt;p&gt;Our next major project will be PyMC4 which will be based on TensorFlow Probability which provides a great core architecture and allows us to put more focus on usability and we have some interesting ideas for improved model creation API. In the meantime, maintenance of Theano is going to be taken over by the PyMC development team as the original authors are moving on.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Is the project looking for contributors?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Yes, we constantly have new contributors show up on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;pymc-devs&#x2F;pymc3&quot;&gt;GitHub&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;discourse.pymc.io&quot;&gt;discourse&lt;&#x2F;a&gt; and keep growing our list of core developers. We also have a summit coming up where all developers will be meeting in London to hack on PyMC4.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What books or MOOCs would you recommend for a software dev that wants to learn more about probability and statistics?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;camdavidsonpilon.github.io&#x2F;Probabilistic-Programming-and-Bayesian-Methods-for-Hackers&#x2F;&quot;&gt;Probabilistic Programming for Hackers&lt;&#x2F;a&gt; is a great read. For a more formal introduction I like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.indiana.edu&#x2F;~kruschke&#x2F;DoingBayesianDataAnalysis&#x2F;&quot;&gt;Kruschke’s puppy book&lt;&#x2F;a&gt; (which was &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;JWarmenhoven&#x2F;DBDA-python&quot;&gt;ported to PyMC3&lt;&#x2F;a&gt;) as well as Osvaldo Martin’s (who is a PyMC core developer) book on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.packtpub.com&#x2F;big-data-and-business-intelligence&#x2F;bayesian-analysis-python-second-edition&quot;&gt;Bayesian Analysis with Python&lt;&#x2F;a&gt;. Also if you find that screencasts are a good way to learn — Peadar Coyle (who is a PyMC core developer) put together a course called &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.probabilisticprogrammingprimer.com&#x2F;&quot;&gt;Probabilistic Programming Primer&lt;&#x2F;a&gt;, he also looks at other PPLs including Pyro (from Uber based on Pytorch) and Rainier (a Scala based PPL). Finally, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;xcelab.net&#x2F;rm&#x2F;statistical-rethinking&#x2F;&quot;&gt;Statistical Rethinking&lt;&#x2F;a&gt; (ported to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;pymc-devs&#x2F;resources&#x2F;tree&#x2F;master&#x2F;Rethinking&quot;&gt;PyMC3&lt;&#x2F;a&gt;) is a fantastic resource as well.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>There’s more to life than HTTP: VerneMQ a high-performance and distributed MQTT broker</title>
          <pubDate>Wed, 05 Sep 2018 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/theres-more-to-life-than-http-vernemq-an-mqtt-broker/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/theres-more-to-life-than-http-vernemq-an-mqtt-broker/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/theres-more-to-life-than-http-vernemq-an-mqtt-broker/">&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-vHHvudyYcHEpI5d52doOcQ.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;At &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;lambdaclass.com&#x2F;&quot;&gt;LambdaClass&lt;&#x2F;a&gt; and our blog &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;this-is-not-a-monad-tutorial&#x2F;&quot;&gt;This is not a Monad tutorial&lt;&#x2F;a&gt; we are a big fans of exploring new topics, different operating systems, platforms, languages and libraries&#x2F;frameworks. We have been talking in our company about exploring new subjects like protocols.&lt;&#x2F;p&gt;
&lt;p&gt;There is a whole generation of developers that has only worked with HTTP, ReST and JSON. While a partial improvement over previous technologies, it has created a protocol monoculture. There are situations where other protocols are better suited but many of the young bloods don’t even know they exist.&lt;&#x2F;p&gt;
&lt;p&gt;MQTT is the first protocol we want to dive into. For us VerneMQ (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;vernemq.com&#x2F;&quot;&gt;https:&#x2F;&#x2F;vernemq.com&#x2F;&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;erlio&#x2F;vernemq&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;erlio&#x2F;vernemq&lt;&#x2F;a&gt;) is one of the best MQTT brokers implementations we know and it is familiar to us since it is implemented in Erlang. The questions were answered by &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;frescosecco&quot;&gt;André Fatton&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;der_graf&quot;&gt;André Graf&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;larshesel&quot;&gt;Lars Hesel Christensen&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;What is MQTT?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
MQTT was developed by Andy Stanford-Clarke (IBM) and Arlen Nipper (Cirrus Link) in 1999 as a light-weight protocol efficient in terms of bandwidth and resource usage. In fact one of the original use cases was to send telemetry back from oil-pipelines in remote areas where transmitting data is expensive and service windows are far between. The defining feature of MQTT is that it is a dynamic pub&#x2F;sub type paradigm where clients need to actively subscribe to a topic to receive messages published to it, thus decoupling producers and consumers completely. MQTT also supports various quality of service levels as well as persisted sessions and a few other handy things.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is VerneMQ?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
VerneMQ is an open source (Apache License version 2) MQTT broker supporting the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.oasis-open.org&#x2F;mqtt&#x2F;mqtt&#x2F;v3.1.1&#x2F;mqtt-v3.1.1.html&quot;&gt;MQTT 3.1.1&lt;&#x2F;a&gt; standard as well as &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.oasis-open.org&#x2F;mqtt&#x2F;mqtt&#x2F;v5.0&#x2F;mqtt-v5.0.html&quot;&gt;MQTT 5.0&lt;&#x2F;a&gt; (though, to be fair MQTT 5.0 support has not yet been merged to master at the time of writing, but should be within a few days). Besides being just another MQTT broker, VerneMQ was built from the start to be a distributed MQTT broker with high scalability in mind.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why would somebody use MQTT instead of HTTP 2 or WebSocket?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
MQTT, HTTP&#x2F;2 and WebSockets all have their strengths and weaknesses. HTTP is a request&#x2F;reply type protocol, while MQTT is a publish&#x2F;subscribe type protocol. So if all you really need is request&#x2F;reply then MQTT might not be the right choice for the use case. But if the messaging patterns are more complex such as fan-in and fan-out and none or a small part is request&#x2F;reply, then MQTT might be an appropriate choice. What MQTT brings to the table is decoupling of the producers and consumers and all the flexibility that comes with that as well as a well defined routing mechanism based on subscriptions with wildcards. In an HTTP or WebSocket context one would have to build a custom routing scheme, which may of course be better suited for the job than something general as MQTT. On the other hand if the desired features are supported by MQTT, then MQTT has a huge advantage in that it is an open (and royalty free) standard and high quality client libraries are available in pretty much any programming language one could imagine.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Does it have an overlap with other protocols like AMQP (implemented by RabbitMQ for example)?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Yes, essentially both AMQP (speaking for the 0.9.1 version) and MQTT implement a publish&#x2F;subscribe messaging pattern. Both protocols rely on intermediate queuing&#x2F;store-and-forward techniques to reduce or eliminate message loss in case a client loses the connection to the broker. The main conceptual difference is that in MQTT one client (identified by a ‘unique’ client id), has one TCP connection to the broker and only a single “queue”. As a consequence, even if a client has multiple subscriptions all messages end up in the same queue. In contrast, with AMQP a queue is a resource on the broker and is decoupled from the client, multiple clients can consume the same queue e.g. for load balancing purposes. So a client can create many queues and decide if and when to consume messages. Moreover, a AMQP connection, which is just a TCP connection, is multiplexed via logical channels, enabling the development of highly performant consumers and publishers.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why did you decide to implement another MQTT broker?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
We stumbled upon the MQTT protocol while working for a customer on a IoT project that heavily used RabbitMQ and AMQP. Although AMQP has been a requirement by the customer we soon figured out that AMQP (and RabbitMQ) might not be the silver bullet for every messaging use case and started to look out for a better IoT protocol. We discovered MQTT and found it a very interesting addition to the other protocols that were widely in use back then and still are today. Especially the small protocol overhead and the focus on small devices (embedded and mobile) instead of big application servers teased us to take the protocol a bit further. Even more so because at that time no scalable and clusterable MQTT broker was around, MQTT was always added as an addition to a ‘main’ protocol like it was done in RabbitMQ or Apache Apollo. We generally disliked the idea of such a ‘multi-protocol’ capability. For example an AMQP broker was traditionally serving a few hundreds to a few thousands of publishers and subscribers with a high message throughput so you build a broker around such scalability and performance requirements. However a traditional MQTT case is the exact opposite, you have ‘a lot’ (a few thousands to a few hundred thousands, to millions) of clients each one only publishing very rarely very small messages. Combining the two protocols in a single software, reusing shared functionality, and still being able to match all the requirements from both worlds seemed like a tough job, too tough for us, and back then no broker known to us did that successfully and we think still no one does today.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Is there anything you dislike about MQTT or that needs an improvement?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Sure, while MQTT v3.1.1 is a great protocol, there are a number of limitations. An example is the lack of negative acknowledgements. Take for example a client attempting to publish to a topic where it’s not authorized to do so: the only action allowed according to the spec is to simply disconnect the client with no way telling it why, which is a bit heavy handed. Another example is that there is no way to add meta information to MQTT payloads such as a content type or decoding schemes etc. The only way to deal with this is to decide on an a priori scheme and encode this information into the payloads themselves. A common workaround is to embed the payload into a thin wrapper which contain such information — but it’s always ad-hoc in every system out there.&lt;&#x2F;p&gt;
&lt;p&gt;Fortunately the OASIS consortium has been working with feedback from the community and carefully used these to develop the next version of the MQTT protocol, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.oasis-open.org&#x2F;mqtt&#x2F;mqtt&#x2F;v5.0&#x2F;mqtt-v5.0.html&quot;&gt;MQTT protocol version 5.0&lt;&#x2F;a&gt;. This version basically addresses the issues mentioned above by incorporating them into the protocol, providing a standard way of doing things. We’re really excited about the new protocol version, so we even wrote a bit about it in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;vernemq.com&#x2F;blog&#x2F;2018&#x2F;06&#x2F;18&#x2F;is-mqttv5-worth-the-trouble.html&quot;&gt;Is MQTT 5 worth the trouble?&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why did you choose Erlang to implement it?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
We chose Erlang because it was the right tool for the job. Erlang was designed to support highly concurrent and highly available (through fault tolerance) systems which fits exactly for a project like VerneMQ. It was also important that the concurrency model was a first class concept and the units of concurrency can’t block each other if one happens to run for a long time as that would be detrimental when building a low latency system. There are a lot of other features which make Erlang a great tool to work with, the way supervision trees makes writing defensive code unnecessary is an important one as one only writes code to handle only the cases the problem domain requires. This makes the code generally brief and concise. The core of VerneMQ including tests is about 30K lines of Erlang code which we think is quite remarkable.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;After implementing it, do you think you made the right call using Erlang to implement VerneMQ?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Yes, absolutely. To build the best possible product Erlang was definitely the right choice. We still think it is one of the best options out there, today there are other interesting options though.To us an obvious one is Elixir, but another, albeit more exotic (we know this might sound ironic coming from a Erlang devs) option would be something like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.ponylang.org&#x2F;&quot;&gt;Pony&lt;&#x2F;a&gt; which is an extremely interesting language since it eliminates a lot of nasty error classes (deadlocks, data-races, exceptions etc) via the type system and the guys over at &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.wallaroolabs.com&quot;&gt;Wallaroo Labs&lt;&#x2F;a&gt; are building some pretty amazing stuff with it.&lt;&#x2F;p&gt;
&lt;p&gt;We really love Erlang, but we’re also being realistic that if there’s a better technology or the use case doesn’t require or benefit from the featureset we’re completely open to use other tools for the job.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;How do you retain messages and replicate subscription data?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Great question! A retained message in MQTT is a message which is stored on the broker using a topic as the key and whenever a client subscribes to that particular topic the broker delivers a copy of the message. Since VerneMQ is a distributed broker we need to replicate retained messages and for this we currently use an implementation of the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.gsd.inesc-id.pt&#x2F;~ler&#x2F;reports&#x2F;srds07.pdf&quot;&gt;Plumtree&lt;&#x2F;a&gt; protocol which was initially implemented for the now defunct Basho Technologies’ distributed database &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;basho&#x2F;riak&quot;&gt;Riak&lt;&#x2F;a&gt;. Later this implementation was factored out into its own repository and we maintain our own &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;erlio&#x2F;plumtree&quot;&gt;fork&lt;&#x2F;a&gt; with a bunch of tweaks. Note, that the replication mechanism in VerneMQ is eventually consistent as this is much easier to scale as no distributed locking is required.&lt;&#x2F;p&gt;
&lt;p&gt;Besides the retained messages VerneMQ also needs to distribute client session state such as subscription information so each VerneMQ node is able to route the published messages across the cluster.&lt;&#x2F;p&gt;
&lt;p&gt;This is all currently handled using Plumtree and Plumtree is doing a great job of it. That said, Plumtree uses relatively many resources when syncing nodes (it uses &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Merkle_tree&quot;&gt;Merkle trees&lt;&#x2F;a&gt; under the hood) and using plain dotted vector clocks means that deleting things require cluster wide synchronization as it is not possible to distinguish between something which was deleted and something which is just missing. To address this we’re working on implementing a new replication mechanism called &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;haslab.uminho.pt&#x2F;tome&#x2F;files&#x2F;global_logical_clocks.pdf&quot;&gt;Server Wide Clocks&lt;&#x2F;a&gt; which combines vector clocks per key-value pair with a node-clock for each participating node, making it possible to establish a global history and thus discard events observed by all members. This makes deletions a special case of the general history trimming process. Furthermore replications with SWC is cheaper than in Plumtree as no Merkle trees are needed and there’s a much smaller overhead per key-value pair on the wire while replicating the state.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What load can VerneMQ manage? Do you have a concrete example (number of nodes, number of connections per node, throughput, latency, etc)?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
This is a difficult question we can’t give a straight answer for. The main reason for this is that the scenarios, use cases, and deployment environments are very different. E.g. we know people deploying a VerneMQ cluster on a couple of Raspberry PIs, and others deploying a large cluster on Kubernetes. Unfortunately many vendors started to publish benchmarks that are hard if not impossible to reproduce, mainly for marketing purposes. While we don’t exclude doing this in the future, we’d prefer a more scientific approach. For now, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;vernemq.com&#x2F;blog&#x2F;2016&#x2F;08&#x2F;26&#x2F;loadtesting-mqtt-brokers.html%29&quot;&gt;we develop and publish benchmarking tools&lt;&#x2F;a&gt;, so everyone can run a benchmark scenario matching their own use case and see how VerneMQ and also other brokers perform. Moreover those benchmarking tools will simplify the reproducibility once we publish any sort of benchmarks.&lt;&#x2F;p&gt;
&lt;p&gt;That said, we saw several interesting setups on the road of course. Some were more successful than others. E.g. someone deployed a VerneMQ cluster of 80 nodes over multiple sites and managed to connect around 5 millions clients. Obviously they run into multiple problems with such a setup, and required our assistance to design a better architecture. Right now we’re helping a customer to scale a MQTT application to 10+ millions concurrent clients, we’ll see how this ends, but we’re quite confident that we come up with a good VerneMQ setup for this case.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;How do you test VerneMQ?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
About 25% of the code is test code — of course this doesn’t mean much, but we believe our test suites are pretty thorough. Of course they can always be better, and we routinely add new tests whenever a bug is discovered or a new feature is added. Almost all of our tests are written as Common Test suites as it’s a really fantastic framework which makes it easy to do both unit and integration tests. We do have a few tests written as EUnit tests but almost all new tests are written using Common Test. We’re great fans of property based testing, but so far we haven’t invested enough into making a proper property based test suite. It’s something we’d love to do at some point, though.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What was the most challenging part of VerneMQ to design and build?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
In Joe Armstrong’s saying “Make it work, make it beautiful, make it fast” the initial “Make it work” wasn’t too challenging, most of the engineering problems were already solved and it was about combining multiple approaches. We borrowed a lot from the way Basho was building and packaging the Riak database as well as the previously mentioned Plumtree. Moreover the initial topic trie routing algorithm was fully taken from the RabbitMQ MQTT plugin. Also the early decision to use LevelDB for disk persistence simplified a lot in the beginning. So it wouldn’t be fair to say that that part was very challenging, especially at the beginning, where we just wanted it to work. Moreover the ‘supposed-to-be-challenging’-part was already solved by Erlang and its distributed nature. However, back then it was challenging to stay focussed on what VerneMQ should become and not adding every possible feature in a half-baked way. So we focussed on a solid plugin system instead of providing everything out of the box right from day one. In retrospective the engineering of the plugin system was actually quite challenging.&lt;&#x2F;p&gt;
&lt;p&gt;These days the implementation of the SWC challenges us as the distributed algorithm is quite complex and we couldn’t just use an existing library for that. Moreover the implementation and integration of the MQTT 5 further challenges also our plugin system.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What’s ahead for VerneMQ?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
First of all we’re going to get the MQTT 5 support merged into the master branch, and then work with the community and our uses to squash the inevitable bugs and make it better. Parallel to that we’re working on getting the improved replication mechanism (SWC) in place which will be available in VerneMQ 2.0, but may also be made available in the 1.x series as an opt-in feature. Besides this we’re working on improving the entire experience around containerization (Kubernetes, etc), clustering, discoverability and the tooling around that. So lots of interesting stuff going on.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What do you recommend to do or read (books, courses, RFCs, codebases, exercises) for young devs that want to start working with distributed systems?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
This is a really good question but also a really hard one to give a good answer to. When we studied computer science most of the results on distributed systems made so many crazy assumptions that they were more or less unusable to build actual systems from. So for a practitioner it was a disappointing experience, but it did give us a good understanding of what the challenges of distributed computing are. When starting out from scratch with distributed computing this is probably a good place to start: Learning about the basics such as the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Fallacies_of_distributed_computing&quot;&gt;Fallacies of distributed computing&lt;&#x2F;a&gt; and some of the impossibility results such as the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;CAP_theorem&quot;&gt;CAP theorem&lt;&#x2F;a&gt;. To really learn about and understand distributed systems it’s important to work and play with them and for this we of course recommend either Erlang or Elixir as they come with distribution built in so there’s a very low barrier to getting started. Also the actor model of Erlang forces one to start thinking about message passing and building protocols which is really what distributed systems are all about.&lt;&#x2F;p&gt;
&lt;p&gt;To learn anything the best advice usually is to make sure to play and have fun. So go have fun!&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>How to pretend you have social skills</title>
          <pubDate>Tue, 14 Aug 2018 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/how-to-pretend-you-have-social-skills/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/how-to-pretend-you-have-social-skills/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/how-to-pretend-you-have-social-skills/">&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-Zn-cHY_cpFVxmhkIAwhYzw.png&quot; alt=&quot;&quot; &#x2F;&gt;A software company from another dimension&lt;&#x2F;p&gt;
&lt;p&gt;This time I decided to do something uncommon. I have asked Martina Cantaro, a psychologist that works for our company &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;lambdaclass.com&#x2F;&quot;&gt;Lambdaclass,&lt;&#x2F;a&gt; to write about the work she is doing training young developers. I hope you find it useful.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;My role at Lambda is to help young developers train their social skills to perform their best. Soft skills are not secondary to technical knowledge — they are what makes knowledge shine by making it useful to the human beings with and for which we work. A lot of good technical developers tend to underestimate the need of social&#x2F;soft skills.&lt;&#x2F;p&gt;
&lt;p&gt;First of all let’s define what social skills are. According to wikipedia social skills involve:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Coordination — Adjusting actions in relation to others’ actions&lt;&#x2F;li&gt;
&lt;li&gt;Mentoring — Teaching and helping others how to do something (e.g. a study partner).&lt;&#x2F;li&gt;
&lt;li&gt;Negotiation — Discussion aimed at reaching an agreement.&lt;&#x2F;li&gt;
&lt;li&gt;Persuasion — The action or fact of persuading someone or of being persuaded to do or believe something.&lt;&#x2F;li&gt;
&lt;li&gt;Service Orientation — Actively looking for ways to evolve compassionately and grow psycho-socially with people.&lt;&#x2F;li&gt;
&lt;li&gt;Social Perceptiveness — Being aware of others’ reactions and able to respond in an understanding manner.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Since many people have asked me how to develop soft skills and which are the most common problems, I thought I’d share a few vignettes of what I do at Lambda. I hope you find them as interesting as I do.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Don’t kill the dog&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Two programmers had received a message from the client via Slack. The message seemed pretty straightforward. It said: “Feature X isn’t working”. Next, the tech lead of the client listed a series of detailed steps to solve this problem. This client was pretty new so we needed some help to understand how to solve it since the issue was related to business rules we didn’t know. The diligent programmers followed the steps carefully and once they were done reported back to the client: “There! It’s done”; and went on to fulfill the tasks that were awaiting them in Github.&lt;&#x2F;p&gt;
&lt;p&gt;A few hours later, the programmers were shocked to hear that the client was not happy at all. “Feature X still isn’t working!” the client demanded. “But we followed the instructions you sent to the letter!”, the programmers cried out. They repeated this defense to me when we talked about the issue a few days later in our weekly workshop.&lt;&#x2F;p&gt;
&lt;p&gt;Well, I said, and paused, trying to come up with a metaphor that would put things into perspective for them. Then I saw Simon, our office dog. “If I take Simon to the vet because he has a stomach ache, and I tell the vet to please anestesize him, cut him open, swap his liver with his bladder and stitch him up, the vet will promptly stop me and tell me we need to find an alternative solution. Alternatively, if she does exactly as I said, and Simon dies, I will know I need to find a better vet”.&lt;&#x2F;p&gt;
&lt;p&gt;The client described a problem to you. The fact that they helpfully provided you with a path to a solution doesn’t mean that they just wanted you to blindly follow the steps and call it a day. The primary goal is always fixing the problem.&lt;&#x2F;p&gt;
&lt;p&gt;The takeaway here is: &lt;strong&gt;your job is to find solutions to problems&lt;&#x2F;strong&gt;. Test your solutions. Make sure you provided a solution for the client’s problem. Their suggestions may help but it’s not their job to spell out the solution for you. Otherwise it would be program-by-numbers! Always remember your goal. Test what you just did to see if you met that goal. If the provided solution didn’t work, try another one. If you don’t have permission to modify something, report back: the client needs to know it couldn’t be fixed by you and why.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;The truth in your heart&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I was coaching programmers before an interview with a client. One of the topics we expected would come up was their opinion on different programming languages and tools. We didn’t know the interviewer’s style, so the interview could be more structured or more like a casual conversation on programming. I began with some basic, open-ended questions, like “what programming language do you prefer and why?”.&lt;&#x2F;p&gt;
&lt;p&gt;There are two types of wrong answers to this question. I call one the “dogmatic” answer and the other the “judgement day” answer.&lt;&#x2F;p&gt;
&lt;p&gt;The Dogmatic knows exactly how to answer that question because there’s only one possible answer. There is only one language to conquer all languages, and it is usually the one they happen to use. This language has every feature that matters, and none of its disadvantages are really that important. It can do almost anything. Most problems can and should be solved using this language. And all naysayers are stupid.&lt;&#x2F;p&gt;
&lt;p&gt;On the other hand, we have the Judgement Day answer. One programmer just couldn’t make up his mind. He’s a very centered person, who likes to be precise and think through issues before taking a stance. Great qualities for a critical thinker, but in an interview setting his hesitation could be taken the wrong way. He hummed and hawed and only after pressuring him a bit he came up with “Haskell”. Very well, I said, why do you prefer it? He quickly made two or three very valid points and also mentioned its downsides — he had clearly thought about the pros and cons of the language before — and then paused and said candidly: “but I’m not sure Haskell is really my favorite programming language”. Well, I told him, when Judgement Day comes, you better think it through 100%. There are many pros and cons to each language and entire books could be written about why each one is better than the others. But for now, we’ll settle for a 90% accurate answer. Because the question is not really about that.&lt;&#x2F;p&gt;
&lt;p&gt;I mean, sure, the interviewer does want to know which programming language you prefer. But what they truly want to find out, if they are decent interviewers, is the analysis behind your choice. Why did you choose that language? Are you aware of its downsides? Do you know which situations it’s best for? So there’s not one correct answer. Haskell would have been as good an answer as Erlang, as long as you are able to justify it.&lt;&#x2F;p&gt;
&lt;p&gt;I find this happens often with less experienced devs. Their hearts are too pure. They are eager to search their souls and hand you their deepest truth. Also, they are not sure what exactly is being evaluated by these interview questions.&lt;&#x2F;p&gt;
&lt;p&gt;Of course, if the company works with Erlang and you fervently praise Cobol, the interviewer might think you won’t be a good match. So, to sum up, as long as your answer is 1) relevant to them and 2) well justified, you’ll be forgiven for not plunging your hand into your chest, pulling out your heart and finding out what programming language is written in there.&lt;&#x2F;p&gt;
&lt;p&gt;So, young developers. of the world, don’t fret. If you feel paralyzed when an interviewer asks you how you see yourself in five years, remember she doesn’t want you to read the future, she wants to learn about your motivation and goals. The same thing goes for your favorite programming language. However also have in mind that the person that is interviewing you might lack social skills too! You can’t entirely control the output of the interview.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;0-tb0bOX6gqdjieBZE.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Communication&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Most of the programmers at Lambda speak English as a second language — their first one being Spanish. Since communication between the programmers and the (often English-speaking) client is key to perform well, we devised a series of exercises to improve their communication skills.&lt;&#x2F;p&gt;
&lt;p&gt;In order for a client-programmer conversation about code to be effective, both have to have a similar representation of the code on their minds. Code is an abstract structure, and both have to build that structure in their heads in order to discuss it. It is also important to be able to clearly articulate and understand the transformations we want to make to that structure — often in a non-native language.&lt;&#x2F;p&gt;
&lt;p&gt;So we began with this exercise:&lt;&#x2F;p&gt;
&lt;p&gt;I built a series of increasingly complex structures using common office objects and photographed them. Then I scattered the elements on the table and instructed one person to look at the photograph of the structure and give out verbal instructions to another person to replicate the structure in the photograph.&lt;&#x2F;p&gt;
&lt;p&gt;This proved to be more challenging than it seemed. Trial and error were very frequent. I encouraged them to give out more and more precise instructions: “Rotate the spoon? How many degrees, in which direction?”. Ideally, sentences would be self-explanatory and steps should be followed without trial and error.&lt;&#x2F;p&gt;
&lt;p&gt;I then instructed the executor of the instructions to proceed as if they were deactivating a bomb — to make a move if they were absolutely certain the movement was going to be accurate. If not, they should ask for clarification&lt;&#x2F;p&gt;
&lt;p&gt;By the third or fourth iteration, their sentences had become longer and better structured, and their language more precise. The executor was also more alert and made sure they understood instructions perfectly.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Technical problems and people problems: know the difference&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Sometimes personal issues are disguised as technical ones. For example, a worker repeatedly pointing out minor mistakes to a colleague in front of third-parties might not be motivated by a desire to improve the quality of work but to make the other feel uncomfortable.&lt;&#x2F;p&gt;
&lt;p&gt;When we first learned to identify these sorts of situations, one case popped up. Some programmers were working for a client in cooperation with another service company. The tech lead of this company had been on the project since the beginning and was not keen on having newcomers on it. He frequently withheld information the programmers needed to complete their tasks and was bent on chastising them for their mistakes on the general chat.&lt;&#x2F;p&gt;
&lt;p&gt;The situation was so bad that there was legitimate concern that this was an attempt to push our programmers out of the project, so the situation had to be handled with great care so as to not make matters worse.&lt;&#x2F;p&gt;
&lt;p&gt;So on one occasion where the chastising was particularly bad and unwarranted, our project manager intervened. He answered on the same chat channel that work was being carried out according to the plan and there was no basis for the criticisms being made, effectively standing between the angry tech lead and the programmers with a sword and shiny armor, ready to defend them against attacks.&lt;&#x2F;p&gt;
&lt;p&gt;One of our less experienced programmers, however, felt bad about the situation and wanted to placate Angry Tech Lead. He didn’t know what he had done wrong, but he wanted to make the situation OK.&lt;&#x2F;p&gt;
&lt;p&gt;So, following the epic defense of the project manager, he wrote an apology on the same channel. This opened a flank for the angry tech lead to continue his attack, rendering the project manager’s defense useless.&lt;&#x2F;p&gt;
&lt;p&gt;We analyzed this dynamic later. Here, the hierarchical structure of the company dictated that if your higher up was deflecting the attack, there was no need to take the hit. In fact, taking the hit could justify subsequent attacks by Angry Tech Lead.&lt;&#x2F;p&gt;
&lt;p&gt;Two lessons were drawn from this: first, to trust the higher-ups’ handling of the situation (or at least talk to them first) because they are probably protecting you. Secondly, we dissected the situation and distinguished constructive criticism from destructive criticism. Constructive criticism is given in a spirit of cooperation, with respect and it provides information on how to correct the mistake or avoid it in the future. It is also often dosed so that it doesn’t overwhelm the recipient, unless the matter is urgent. When it is about a task, it focuses on the problem and not the person. But in this case there was little cooperation since information was being withheld, criticism flowed like a cascade and there was no focus on how to accomplish the task more efficiently.&lt;&#x2F;p&gt;
&lt;p&gt;What at first had seemed to them a technical problem now revealed itself as a people’s problem. This took us a little further into understanding the complex relationship between both realms.&lt;&#x2F;p&gt;
&lt;p&gt;Like captain Spock, we combine the worlds of logical thinking with the human dimension, which may seem irrational when analyzed through the cold prisma of mathematical rationality but has its own logic and meaning. And we need to develop skills in both areas, because, ultimately, we are humans working for other humans — code is just our tool.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Interview with Brad Chamberlain about a productive parallel programming language called Chapel</title>
          <pubDate>Mon, 12 Feb 2018 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-brad-chamberlain-about-chapel-a-productive-parallel-programming-language/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-brad-chamberlain-about-chapel-a-productive-parallel-programming-language/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-brad-chamberlain-about-chapel-a-productive-parallel-programming-language/">&lt;p&gt;As you might know, I am a big fan of concurrency, parallelism and distribution but I know almost nothing about high performance computing (HPC) so I decided to get out from my comfort area. This time I’ve interviewed Brad Chamberlain about &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;chapel-lang&#x2F;chapel&quot;&gt;Chapel&lt;&#x2F;a&gt;, a productive parallel programming language.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-Vbk8JH0pBz1gSHSbxV799A.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What problems does Chapel solve? Who is the ideal user of Chapel?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Chapel supports scalable parallel programming in a portable way: programs developed on a user’s multicore laptop can be run on commodity clusters, the cloud, and supercomputers from &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.cray.com&#x2F;&quot;&gt;Cray&lt;&#x2F;a&gt; or other vendors. Chapel is also designed to vastly improve the productivity of performance-oriented programming, whether serial or parallel. As such, it supports programs with Python-like clarity while retaining the performance of lower-level approaches to programming like C, C++, Fortran, MPI, and OpenMP (the &lt;em&gt;de facto&lt;&#x2F;em&gt; standards for high-performance parallel programming).&lt;&#x2F;p&gt;
&lt;p&gt;Ideal Chapel users include Python programmers who are interested in parallel or performance-oriented programming as well as parallel programmers who are fed up with conventional approaches.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Were there any other previous languages that tried to solve the same issue?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Definitely. There’s a long list of failed attempts at developing scalable parallel programming languages, and skeptics like to remind you of them all the time: “If all of these languages have failed, how will you ever succeed?” In designing Chapel, we spent a lot of time reviewing other parallel languages to learn from their mistakes. Historically, I’d say that most parallel languages have failed for one of two reasons: Many were too high-level, limiting what an expert programmer could explicitly control while requiring a lot from their compilers. Others were lower-level, but as a result didn’t provide sufficient appeal over existing approaches like MPI.&lt;&#x2F;p&gt;
&lt;p&gt;Our response to this tension was to design a language using what we refer to as a &lt;em&gt;multiresolution&lt;&#x2F;em&gt; &lt;em&gt;philosophy&lt;&#x2F;em&gt; : Chapel supports higher-level features like parallel loops and distributed arrays for productivity and ease-of-use. Yet, it also supports lower-level features that give programmers more explicit control over the system. Notably, the high-level features are implemented in terms of the lower-level features within Chapel itself. This provides programmers with the ability to extend the language by creating their own abstractions. For example, an advanced Chapel user can implement new work-scheduling policies for their parallel loops, or new distributions or memory layouts for their arrays.&lt;&#x2F;p&gt;
&lt;p&gt;In my opinion, many scalable parallel language attempts have also failed to gain traction because they’ve been insufficiently general-purpose. Once programmers have a capability, they tend to be reluctant to give it up. This lack of generality often stems from the fact that most efforts have been undertaken by academic groups who need to pick their battles in order to publish papers and graduate students. With Chapel, we’ve created a language whose capabilities exceed C or Fortran with MPI and OpenMP, yet in a language that strives to be as attractive to read and write as Python.&lt;&#x2F;p&gt;
&lt;p&gt;It’s obviously very difficult for any new programming language to succeed, yet that’s no reason to avoid pursuing them — particularly when existing languages have major capability gaps. In our case, we believe that parallelism and locality are first-class programming concerns — not just in High-Performance Computing (HPC) where they make or break a program’s ability to scale well, but also in mainstream programming now that multicore processors and accelerators are pervasive. That said, parallelism and locality have traditionally been afterthoughts in language design. So rather than being paralyzed by the challenges of language adoption, we’re striving to fill that gap. And happily, users seem to be excited by our efforts.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;In some ways, don’t OpenMP, MPI, and CUDA solve the same problem?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;OpenMP, MPI, and CUDA are the &lt;em&gt;de facto&lt;&#x2F;em&gt; standards for HPC programmers today when targeting multicore processors, distributed memory systems, and (NVIDIA) GPUs, respectively. In that sense, Chapel is targeting a similar problem space as they are. However, they’re not considered very productive approaches and are great illustrations of my claim that parallelism and locality are traditionally afterthoughts in language design: they’re implemented using pragmas, libraries, and language extensions rather than first-class syntax and semantics. As a result, they feel like they’re “tacked on” rather than a core part of the language. This hurts not just their ease-of-use but also their ability to be optimized by compilers.&lt;&#x2F;p&gt;
&lt;p&gt;These approaches also tend to be very specific to a given type of parallelism in the system architecture: If you’ve written an OpenMP program and now want to run it at scale on a cluster or a Cray, you’ll have to rewrite it in something like MPI, which requires learning a completely different set of features and abstractions. In contrast, Chapel is designed to support parallel programming across these diverse types of parallel hardware with a single, unified set of features for expressing parallelism and locality.&lt;&#x2F;p&gt;
&lt;p&gt;To their immense credit, OpenMP, CUDA, and (especially) MPI have been responsible for the vast majority of scientific advances in high-performance computing over the past several decades. And if you program in these notations and are happy with them, Chapel may not be for you. Yet, just as early computational results were obtained using assembly language before giving way to more modern and portable approaches like Fortran, C, C++, Java, and eventually Python, we think parallel computing is overdue for a similar leap in evolution: from lower-level, detail-oriented approaches to higher-level ones that improve productivity and portability. As such, Chapel strives to empower the millions of desktop-only programmers to use distributed parallel computers for the first time, while also making existing parallel programmers even more effective.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What does Chapel do differently &#x2F; better?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;A characteristic shared by most general-purpose approaches to scalable parallel programming — including MPI, SHMEM, UPC, and Fortran 2008’s co-arrays — is that they express parallelism using the &lt;em&gt;Single Program, Multiple Data&lt;&#x2F;em&gt; (SPMD) programming model. The basic idea is that the user writes their program with the understanding that when it is run, multiple copies of ‘main()’ will execute simultaneously and cooperatively across a number of processors. This forces parallel programmers to write programs using a &lt;em&gt;local view&lt;&#x2F;em&gt; , in which the code expresses the perspective of a single process out of many: “What subset of the data do I need to allocate? What subset of the iteration space do I need to execute?” While the SPMD approach is sufficient for many computations, it’s also very different from traditional programming where one copy of ‘main()’ executes and all computation proceeds from that point. This requires programmers to think differently, to manage lots of bookkeeping details, and even to launch their programs differently. It also means that in order to get finer-grain parallelism, they need to mix in some other parallel programming model like POSIX threads, OpenMP, or CUDA.&lt;&#x2F;p&gt;
&lt;p&gt;In stark contrast, Chapel supports what we call a &lt;em&gt;global view&lt;&#x2F;em&gt; of programming, in which a single task runs ‘main()’ and then any additional parallelism is created as features that introduce tasks are encountered. Similarly, computation and data are distributed across compute nodes when features that control locality are encountered. This permits scalable parallel programming to be far more intuitive and similar to conventional desktop programming, making it accessible to the millions of developers who might never get around to learning MPI. At the same time, Chapel’s global view also supports SPMD programming for computations or users that require it, so nothing is lost.&lt;&#x2F;p&gt;
&lt;p&gt;As an illustration of Chapel’s advantages, consider the STREAM Triad benchmark which multiplies a vector by a scalar, adds it to a second vector, and assigns it to a third. In Chapel, this can be written in a way that will use all the cores of all the system’s compute nodes as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;use BlockDist, HPCCProblemSize;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;config type elemType = real;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;config const m = computeProblemSize(numArrays=3, elemType),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;         alpha = 3.0;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;proc main() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  const ProblemSpace = {1..m} dmapped Block(boundingBox={1..m});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  var A, B, C: [ProblemSpace] elemType;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  B = 2.0;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  C = 1.0;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  A = B + alpha * C;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In contrast, doing the same thing in C + MPI + OpenMP results in computation like the following, due to the SPMD programming model as well as the lower-level notations (MPI-oriented code is in red, OpenMP in blue):&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;0-7A817ub0TK9QWgLW.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Performance-wise, how does Chapel compare to languages like C, C++, Go, Rust?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Today, Chapel programs tend to perform competitively with hand-coded C and C++. I’m not aware of any detailed performance comparisons with Go and Rust, though in the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;benchmarksgame.alioth.debian.org&#x2F;&quot;&gt;Computer Language Benchmarks Game&lt;&#x2F;a&gt; (CLBG) we’re currently ranked as being a bit faster than Go and a bit slower than Rust. That said, there are specific CLBG benchmarks where any of these five languages win or lose, and many of the fastest entries take a far more heroic and painstaking approach than the Chapel versions.&lt;&#x2F;p&gt;
&lt;p&gt;Since we care about code clarity, we tend to graph the Computer Language Benchmark Game results on scatter plots showing normalized execution times versus code compactness (as a proxy metric for clarity). In such views, Chapel tends to fall in a very unique position, being competitive in speed with the fastest languages while also nearly as compact as scripting languages. The following two plots illustrate this (the right graph zooms in on the fastest entries for readability):&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;0-5HKm6tfdrqfXiXWP.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;0-YHDLOnTtFepJmsUV.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why did you implement Chapel using LLVM?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In all honesty, one of my biggest regrets in the project today is that we didn’t implement Chapel using LLVM from day one. When our project started, LLVM was still in its infancy, and there was no reason to believe that it would become the foundational technology that it is today. As a result, our initial compiler approach (which remains the default today) was to compile Chapel down to C which is then compiled by the back-end C compiler of your choice. This approach treats C as a portable assembly language and has worked reasonably well for us over time. However, it is also unfortunate because the Chapel compiler may have semantic information which is challenging or impossible to convey through C to the back-end compiler.&lt;&#x2F;p&gt;
&lt;p&gt;In contrast, Chapel’s LLVM back-end permits us to translate Chapel directly to LLVM’s Internal Representation (IR), giving us greater semantic control plus the possibility of adding Chapel-specific extensions. Since LLVM is a popular compiler framework, using it lets us leverage developer familiarity, not to mention open-source packages. One such example is Simon Moll’s Region Vectorizer for LLVM, developed at Saarland University. We’ve found that it tends to generate better vector performance for Chapel programs than conventional C back-end compilers. But even more importantly, LLVM gives us a single, portable back-end that saves us the trouble of wrestling with the quirks and bugs that are present across the wide diversity of back-end C compiler versions that we attempt to support today. In 2018, we hope to make LLVM our default back-end for these reasons.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is GASNet? Why do you use it in Chapel?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;GASNet is an open-source library for portable inter-process communication developed by Berkeley Labs &#x2F; UC Berkeley. Its communication primitives include active messages and one-sided puts to (or gets from) the memory of a remote process. The GASNet team maps these calls down to the native Remote Direct Memory Access (RDMA) capabilities of various networks while also supporting fallback implementations over UDP or MPI for portability.&lt;&#x2F;p&gt;
&lt;p&gt;These primitives are precisely what a language like Chapel needs to compile to distributed memory systems: Active messages are the natural way to implement Chapel’s &lt;em&gt;on-clauses&lt;&#x2F;em&gt; which are used to migrate tasks from one compute node to another. Similarly, writing&#x2F;reading a variable back on the originating locale maps naturally to one-sided puts&#x2F;gets since only one process will know when such communications are required. As a result, GASNet gives us a portable way to run Chapel on virtually any distributed system. It’s also one of the best engineered and maintained open-source packages we’ve worked with, and the development team is incredibly responsive to questions and issues.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;How do you manage errors? If a long-running computation in multiple nodes crashes in one node, how do you recover the work done or re-execute it without having to re-run everything?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;For user-level errors within the program itself, Chapel supports the ability to throw and catch errors using a low-overhead approach that was inspired by Swift’s error-handling model. This is a relatively new feature set within Chapel, and it rounds out our core capabilities nicely.&lt;&#x2F;p&gt;
&lt;p&gt;That said, your question seems more oriented toward catastrophic errors that may be outside of the programmer’s control, such as having one of their compute nodes fail. Today, Chapel doesn’t handle such cases gracefully, which arguably reflects our HPC heritage. Runtime libraries and system software for HPC have a long tradition of tearing down jobs when fatal errors occur, and Chapel inherits this behavior to some extent. Resiliency is a growing concern within the HPC community as our system scales grow, and we have some ideas for improving Chapel’s ability to cope with such events. Similar features could also be attractive to users from cloud computing environments who are accustomed to elasticity in their environment. That said, we have not yet had the opportunity to pursue these ideas, so they remain an area of potential future research or collaboration.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Is there any way to trace what a live system is currently doing?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We haven’t developed any Chapel-specific tools for tracing or visualizing Chapel executions in real-time. That said, third-party tools can be used with Chapel as with any other C program. We do have a tool named &lt;em&gt;chplvis,&lt;&#x2F;em&gt; developed by Professor Phil Nelson of Western Washington University, which supports visualizing the communication and tasking events logged by a Chapel program. This permits a user to visually inspect a Chapel program’s execution to find possible sources of overhead, but it is strictly a post-mortem tool at present.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Are you aware of anybody using Chapel in the AI&#x2F;Machine Learning world?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We’ve definitely seen an uptick in interest from AI programmers in recent years as the field has become more prevalent, both in HPC and in general. Our most prominent user in this space at present is Brian Dolan, who is the Chief Scientist and Co-Founder of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;deep6.ai&#x2F;&quot;&gt;Deep 6 AI&lt;&#x2F;a&gt;, a start-up that is accelerating the matching of medical patients to clinical trials. After being disappointed by programming solutions that didn’t live up to their hype, Brian was drawn to Chapel last summer due to its ability to support programs with Python-like clarity, combined with the promise of supporting performance and scalability like C or Fortran with MPI. Half a year later, he’s become one of our most active and vocal users.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>One does not simply build a user interface: our ClojureScript&#x2F;re-frame app</title>
          <pubDate>Mon, 04 Dec 2017 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/one-does-not-simply-build-a-user-interface-our-clojurescript-re-frame-app/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/one-does-not-simply-build-a-user-interface-our-clojurescript-re-frame-app/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/one-does-not-simply-build-a-user-interface-our-clojurescript-re-frame-app/">&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;notamonadtutorial.com&#x2F;holiday-ping-how-we-implemented-our-first-open-source-app-with-erlang-and-clojurescript-fad5b66fc325&quot;&gt;Part I of this article&lt;&#x2F;a&gt; discussed the motivation to build &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;holidayping.lambdaclass.com&quot;&gt;HolidayPing&lt;&#x2F;a&gt; and the design and development process of the back end Erlang application. In this follow-up Facundo (the main dev) focuses on the user interface and what we learnt building it.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Discuss and vote at&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;lobste.rs&#x2F;s&#x2F;qlblgh&#x2F;one_does_not_simply_build_user_interface&quot;&gt; &lt;em&gt;lobsters&lt;&#x2F;em&gt;&lt;&#x2F;a&gt; &lt;em&gt;,&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;programming&#x2F;comments&#x2F;7hhrb1&#x2F;one_does_not_simply_build_a_user_interface_our&#x2F;&quot;&gt;&lt;em&gt;reddit&lt;&#x2F;em&gt;&lt;&#x2F;a&gt; &lt;em&gt;and&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=15844203&quot;&gt; &lt;em&gt;hn&lt;&#x2F;em&gt;&lt;&#x2F;a&gt; &lt;em&gt;.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-BdFV-bGWhQ5HiIL6VfY5xg.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Before getting into the details, a couple of disclaimers are in order:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Me and most of my coworkers have done front end over the years, but we’re all primarily back end developers. Particularly, the last time I worked on a Single-Page Application, Angular 1 was king; I vaguely knew about React ideas, but never came close to using it.&lt;&#x2F;li&gt;
&lt;li&gt;Although we threw in a wizard and a fancy yearly calendar view, the application was your typical CRUD. Exactly the kind of thing for which &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.freecodecamp.org&#x2F;why-i-hate-your-single-page-app-f08bb4ff9134&quot;&gt;you usually don’t want to build a Single-Page application&lt;&#x2F;a&gt;. We knew this and we choose to do a SPA anyway because this wasn’t a paid project so we weren’t optimizing for resource efficiency but for learning.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;language-javascript-vs-clojurescript-vs-elm&quot;&gt;Language: JavaScript vs ClojureScript vs Elm&lt;&#x2F;h3&gt;
&lt;p&gt;The first big decision was the programming language. JavaScript is the default option, but even with a solid knowledge of the language and coming out of a couple of years with Node.js as my daily work platform, becoming a productive front end JavaScript developer in 2017 is a notable feat. The tooling and even the language keeps moving under your feet. For engineers that only get out of the server from time to time, it all feels like throw-away knowledge (just like my previous Angular experience is of little use today). And if you want to do fashionable JavaScript, you end up using transpilers anyway, so why not just use a different language altogether? I mean, we’re using Erlang already, it’s not like we mind throwing some weirdness into the mix.&lt;&#x2F;p&gt;
&lt;p&gt;Elm has always been a very tempting choice for us, but learning an entire language (and one so different from the others I already know) was too much to take on for a side project whose goal was to get familiar with Erlang.&lt;&#x2F;p&gt;
&lt;p&gt;And then there was ClojureScript. I was already fluent in Clojure, had some experience with ClojureScript, my Emacs was already prepared to move parentheses around… &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=gsffg5xxFQI&quot;&gt;And it delivered its promises&lt;&#x2F;a&gt;. &lt;em&gt;lein new re-frame holiday-ping&lt;&#x2F;em&gt; is all it took to setup a workflow with a live REPL, hot code reloading (thanks primarily to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bhauman&#x2F;lein-figwheel&#x2F;&quot;&gt;lein-figwheel&lt;&#x2F;a&gt;) and advanced JavaScript compilation. This is not only simpler than all the disparate tools you need to do the same job in JavaScript, but also requires a smaller effort than &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;thinkrelevance.com&#x2F;blog&#x2F;2013&#x2F;06&#x2F;04&#x2F;clojure-workflow-reloaded&quot;&gt;setting up a good workflow in JVM Clojure&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;om-vs-reagent-vs-om-next-vs-re-frame&quot;&gt;Om vs Reagent vs Om.next vs re-frame&lt;&#x2F;h3&gt;
&lt;p&gt;Next up was the library or framework to build the UI. We could have gone with a simple DOM manipulation library like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;plumatic&#x2F;dommy&quot;&gt;dommy&lt;&#x2F;a&gt;, but we decided — at our own risk — to build a Single-Page App, therefore we looked at React wrappers: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;reagent-project.github.io&#x2F;&quot;&gt;Reagent&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;omcljs&#x2F;om&quot;&gt;Om&lt;&#x2F;a&gt;. We couldn’t afford to build prototypes with both tools so we have to settle for reviewing the documentation and examples, and getting opinions from friends and the web. As Gandalf once said: &lt;em&gt;all engineers have to do is to pick a library with the time that is given to them&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Reagent right away seemed more idiomatic Clojure, relying mostly on plain data and functions (and, in the case of re-frame, &lt;em&gt;pure&lt;&#x2F;em&gt; functions) while Om used a lot of objects and protocols, &lt;em&gt;reify&lt;&#x2F;em&gt; and JavaScript interop. Reagent also used the lovely hiccup syntax to describe HTML as data, while Om leaned on functions by default (although there are &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;r0man&#x2F;sablono&quot;&gt;libraries to switch to hiccup&lt;&#x2F;a&gt;). Lastly, Om seemed to require a better knowledge of the React lifecycle, which added another layer to get familiar with. A quick comparison of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;todomvc.com&#x2F;&quot;&gt;TodoMVC&lt;&#x2F;a&gt; code illustrates why my gut feeling was to go with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;reagent-project&#x2F;reagent&#x2F;blob&#x2F;master&#x2F;examples&#x2F;todomvc&#x2F;src&#x2F;todomvc&#x2F;core.cljs#L62-L75&quot;&gt;Reagent&lt;&#x2F;a&gt; rather than &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;swannodette&#x2F;todomvc&#x2F;blob&#x2F;gh-pages&#x2F;labs&#x2F;architecture-examples&#x2F;om&#x2F;src&#x2F;todomvc&#x2F;item.cljs#L47-L83&quot;&gt;Om&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;So I leaned more towards Reagent than Om. But those only provide React wrappers; the real choice had to be between &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;omcljs&#x2F;om&#x2F;wiki&#x2F;Quick-Start-%28om.next%29&quot;&gt;Om.next&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Day8&#x2F;re-frame&quot;&gt;re-frame&lt;&#x2F;a&gt;, otherwise I’d had have to come up with an architecture myself, and I didn’t have the background to do it effectively. I caught a great explanation of this by Mike Thompson (author of re-frame) in the Clojurians Slack:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can absolutely use Reagent by itself if your application is simple enough. BUT if you just use Reagent by itself then you only have the V bit of an application. As your application starts to get more complicated, you &lt;strong&gt;will&lt;&#x2F;strong&gt; start to create an architecture which adds &lt;em&gt;control logic&lt;&#x2F;em&gt; and &lt;em&gt;state management&lt;&#x2F;em&gt; — the M and C parts (even if you don’t think you are, you are). So then the question becomes: is your architecture better than re-frame’s or not? And some people prefer their own architectures and would answer “yes” :-) Fair enough.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;I think the only danger arises if this process is not conscious — if someone creates a dog’s breakfast of an architecture and doesn’t even know they’ve done it. I’ve had MANY people privately admit that’s what happened to them… and then they swapped to re-frame to get some structure back. So, my advice is… if your application is a little more complicated, be sure to make a conscious choice around architecture, because one way or another you’ll be using one.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;css-framework&quot;&gt;CSS framework&lt;&#x2F;h3&gt;
&lt;p&gt;For styles we went with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;bulma.io&#x2F;&quot;&gt;Bulma&lt;&#x2F;a&gt;: we wanted something lighter than Bootstrap, specifically no JavaScript. Bulma is simple, easy to use, feels lightweight and looks good. In combination with hiccup it meant I was pulling off a beautiful UI without HTML, CSS or JavaScript; all my components were conveniently built by moving Clojure data around Emacs.&lt;&#x2F;p&gt;
&lt;p&gt;Perhaps the one downside was that there aren’t many pre-baked fancy components like Bootstrap has. We kind of made that choice anyway by using ClojureScript in the first place; when we wanted a complex component we either coded it ourselves (we did with tag list inputs) or we avoided them (e.g. no type-ahead selects).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;developing-a-single-page-app-with-clojurescript-and-re-frame&quot;&gt;Developing a Single-Page App with ClojureScript and re-frame&lt;&#x2F;h3&gt;
&lt;p&gt;I just needed to read the first few &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Day8&#x2F;re-frame&#x2F;tree&#x2F;master&#x2F;docs&quot;&gt;re-frame tutorials&lt;&#x2F;a&gt; to get started. It felt like re-frame built on the concepts I was already familiar from Clojure and I became reasonably productive in a matter of days, which was amazing considering I hardly knew the first thing about React. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;purelyfunctional.tv&#x2F;guide&#x2F;re-frame-building-blocks&#x2F;&quot;&gt;This guide&lt;&#x2F;a&gt; provides a good overview of the framework.&lt;&#x2F;p&gt;
&lt;p&gt;As mentioned, the workflow is amazing: you write pure functions, describing HTML components as Clojure data literals, and figwheel auto reloads them; if you want to play around with a dependency or interop with JavaScript and the browser APIs, just switch to the tab where the REPL is running. Instant gratification all the way.&lt;&#x2F;p&gt;
&lt;p&gt;At first, the re-frame structure can be a little overwhelming: you have events, subscriptions, effects, co-effects… Specially it took me a while to find the justification for subscription handlers, since most of the times they were trivial reads of the database. I think it helped when I read enough times that a design goal of re-frame was to keep views as dumb and decoupled from state as possible; under that light all the pieces started to fall into place: re-frame handles the dirty work and side-effects, you just declare what needs to be done through functions that return data (with the bonus that your code becomes easier to test).&lt;&#x2F;p&gt;
&lt;p&gt;The one thing I don’t quite like about re-frame is how all definitions (reg-event, reg-sub, reg-fx, reg-cofx) set up some hidden application state. I’d prefer to just have standalone functions and pass a map or some other data structure into a single re-frame initialization step. As it is, it forces you to require namespaces just for the side effects they produce, which doesn’t feel very idiomatic.&lt;&#x2F;p&gt;
&lt;p&gt;While re-frame is a very opinionated framework and provides a lot structure, there still are some design aspects left to the programmer. Following are some notes of decisions I had to make; a lot of it I figured out along the way and there may be better ways to do it. Critiques and suggestions are certainly welcome.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;routing-and-navigation&quot;&gt;Routing and navigation&lt;&#x2F;h3&gt;
&lt;p&gt;Perhaps the most complex part of the front end application was properly handling navigation. It’s also the place where you pay the penalty of using a SPA framework to build an application that requires browser-like logic (i.e. multiple multiple entry points based on the url, working back&#x2F;forward buttons, etc.).&lt;&#x2F;p&gt;
&lt;p&gt;Initially it was simple, I just followed the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Day8&#x2F;re-frame&#x2F;blob&#x2F;master&#x2F;docs&#x2F;Navigation.md&quot;&gt;re-frame documentation&lt;&#x2F;a&gt;: you add an &lt;em&gt;:active-panel&lt;&#x2F;em&gt; value to your application state, update it when the user produces a navigation event (e.g. select a tab) and make your main view show the proper component based on the &lt;em&gt;:active-panel&lt;&#x2F;em&gt; current value.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(def panels {:panel1 [panel1]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             :panel2 [panel2]})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(defn high-level-view &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  (let [active (re-frame&#x2F;subscribe [:active-panel])]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    (fn []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      [:div&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       [:div.title   &amp;quot;Heading&amp;quot;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;       (get panels @active)])))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This was enough to get me going, but my first concern was how to fetch different data from the server based on the selected panel (i.e. when I’m on the channel list, GET &#x2F;api&#x2F;channels; when I’m on the calendar for channel &lt;em&gt;my-channel&lt;&#x2F;em&gt; , GET &#x2F;api&#x2F;channels&#x2F;my-channel&#x2F;holidays; etc.). The first idea that came to mind was to just trigger a request event inside the component view function, but this was directly against the philosophy of keeping logic out of the views.&lt;&#x2F;p&gt;
&lt;p&gt;Asking in the re-frame Slack channel, I got the suggestion of just fetching all the required data when the user enters the application, load it in the in-memory app-db and use that as the source of truth instead of synchronizing with the server on every step. I wasn’t entirely convinced by this, especially as the application grew bigger, but it was better than polluting view functions with logic and, again, enough to move forward.&lt;&#x2F;p&gt;
&lt;p&gt;Eventually, though, the API reached a point where this approach was impractical and inefficient: we had multiple endpoints which more or less mapped to different views in the UI, we couldn’t just load all the data to cover every possible navigation path. Moreover, with very distinct views it was time to bring URLs and the expected browser behavior: proper routing, interacting with the history API. I turned to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;juxt&#x2F;bidi&quot;&gt;bidi&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;kibu-australia&#x2F;pushy&quot;&gt;pushy&lt;&#x2F;a&gt;, based on a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pupeno.com&#x2F;2015&#x2F;08&#x2F;26&#x2F;no-hashes-bidirectional-routing-in-re-frame-with-bidi-and-pushy&#x2F;&quot;&gt;tutorial by J. Pablo Fernández&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Now we needed some way to specify what data was to be fetch for each route, without cluttering the views; I came up with a generic event handler, using multimethods:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(re-frame&#x2F;reg-event-fx&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; :navigate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; (fn [{:keys [db]} [_ new-view]]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   {;; trigger the load-view event in case data from the server is required&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    :dispatch    [:load-view new-view] &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ;; update the browser history API and switch to the given view&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    :set-history new-view&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    ;; set the current view in the app-db so the dom is updated&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    :db          (assoc db&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                        :loading-view? true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                        :current-view new-view)}))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(defmulti load-view&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;quot;Create a multimethod that will implement different event handlers based on the&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   view keyword.&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  (fn [cofx [view]] view))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(re-frame&#x2F;reg-event-fx&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; :load-view&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; (fn [cofx [_ new-view]]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   ;; delegate event handling to the proper multimethod&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (load-view cofx [vector new-view])))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(defmethod load-view &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  :default&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  [{:keys [db]} _]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ;; by default don&amp;#39;t load anything&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  {:db (assoc db :loading-view? false)})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(defmethod load-view&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  :channel-list&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  [_ _]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ;; when navigating to the channel list, fetch the channels&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  {:http-xhrio {:method     :get&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                :uri        &amp;quot;&#x2F;api&#x2F;channels&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                :on-success [:channel-list-success]}})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Even though this felt a bit hacky, seeing the view functions become cleaner somewhat validated the approach. For such an opinionated framework, though, I wished there was a recommended way to handle this use case, which is probably a frequent one (maybe there is and I just didn’t find it).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;forms-and-validations&quot;&gt;Forms and validations&lt;&#x2F;h3&gt;
&lt;p&gt;There must be few tasks as repetitive as writing forms in a web application, specially if there are many CRUD components. After writing a couple of them, I obviously started looking for ways to build a reusable component that would create them based on a specification. I managed to do so, again by resorting to multimethods, such that each method would render differently based on the input type (text, password, select, etc.); the API ended up looking like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[forms&#x2F;form-view {:submit-text &amp;quot;Register&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                  :on-submit   [:register-submit]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                  :fields      [{:key      :email&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                 :type     &amp;quot;email&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                 :validate :valid-email?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                 :required true}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                {:key      :password&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                 :type     &amp;quot;password&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                 :required true}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                {:key      :password-repeat&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                 :type     &amp;quot;password&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                 :label    &amp;quot;Repeat password&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                 :validate :matching-passwords?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                 :required true}]}]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The form-view maintains a local state atom, and when the submit button is clicked, the :on-submit event is triggered passing the current input values.&lt;&#x2F;p&gt;
&lt;p&gt;It took me a couple of iterations to properly integrate these from components with the rest of the app, specially when I needed to pre-populate them with data coming from other views or from back end responses. This was the one area where I had to get a bit more familiar with React internals, for example learning about &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;goshakkk.name&#x2F;controlled-vs-uncontrolled-inputs-react&#x2F;&quot;&gt;controlled and uncontrolled components&lt;&#x2F;a&gt;. After introducing the load-view handler described in the previous section this kind of issues went away.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, I needed a way to introduce reusable validations to the form component, without breaking the “no logic in views” rule. I found that encapsulating validation in subscription handlers worked really well. I could specify validations as part of the form specification, subscribe to them to change the style of erroneous inputs and disable submit buttons, and also use the same validations outside of the forms:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(re-frame&#x2F;reg-sub&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; :valid-required?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; (fn [db [_ value]]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (if (string&#x2F;blank? value)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     [false &amp;quot;This field is required.&amp;quot;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;     [true])))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(re-frame&#x2F;reg-sub&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; :valid-form?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; (fn [[_ form fields]]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (-&amp;gt;&amp;gt; fields&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        (get-validation-subs form)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        (map re-frame&#x2F;subscribe)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        (doall)))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(fn [validations _]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;   (every? true? (map first validations))))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;closing-thoughts&quot;&gt;Closing thoughts&lt;&#x2F;h3&gt;
&lt;p&gt;This was a modest project and as such didn’t reveal any higher truth. Instead, it reinforced some ideas and reminded us about things we tend to forget. I liked that it gave us a better perspective than what we’re used to, working mainly as back end engineers: this time we had to write a front end to our APIs and be a user to our interfaces.&lt;&#x2F;p&gt;
&lt;p&gt;A good design should model the domain of the problem it is trying to solve, rather than accommodate to immediate client needs. But as engineers we have to expect the user experience to reveal aspects of the domain that we missed, were unforeseeable or plainly didn’t exist at design stage. You need a UI to be able to poke around with the application to see what feels right and what doesn’t, and change the model accordingly. In our case, as soon as we started to use the front end, we realized that the relationships between our entities had to be turned around. What was more interesting: once we made those changes the code became simpler in ways we hadn’t considered.&lt;&#x2F;p&gt;
&lt;p&gt;This is no news, but front end takes a lot of work. We were aiming for a very simple UI, one that covered a fraction of the application surface, and it still required more work and way more trial and error than the back end. The dumbest front end application takes a non trivial amount of work to get right and provide an adequate user experience; traditional server-side applications, on the other hand, are becoming easier and easier to put together, to the point that they are arguably becoming extinct.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Holiday Ping: how we implemented our first open source app with Erlang and Clojurescript</title>
          <pubDate>Tue, 14 Nov 2017 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/holiday-ping-how-we-implemented-our-first-open-source-app-with-erlang-and-clojurescript/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/holiday-ping-how-we-implemented-our-first-open-source-app-with-erlang-and-clojurescript/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/holiday-ping-how-we-implemented-our-first-open-source-app-with-erlang-and-clojurescript/">&lt;p&gt;After almost ten years of working as a developer for different companies, two years ago I started my own company &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;&quot;&gt;LambdaClass&lt;&#x2F;a&gt;. I did so because I wanted to have more freedom in choosing the type of projects and team I work with.&lt;&#x2F;p&gt;
&lt;p&gt;That is why today it is a very special day for me. We take a break from regular interviews and celebrate the release of our first open source application: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;holidayping.lambdaclass.com&#x2F;&quot;&gt;Holiday Ping&lt;&#x2F;a&gt;. Facundo Olano is the main developer of the application. The application was written in two of the best programming languages we know (Clojure and Erlang) and our favorite database (PostgreSQL). This post was written by him and tells his journey and lessons learned with the backend side. A similar post on the frontend will be forthcoming. If you find any issue or want to help check &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;holiday_ping&quot;&gt;github&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Discuss and vote at&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;lobste.rs&#x2F;s&#x2F;mgefw9&#x2F;holiday_ping_how_we_implemented_our_first&quot;&gt; &lt;em&gt;lobsters&lt;&#x2F;em&gt;&lt;&#x2F;a&gt; &lt;em&gt;,&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;programming&#x2F;comments&#x2F;7cweat&#x2F;holiday_ping_how_we_implemented_our_first_open&#x2F;&quot;&gt;&lt;em&gt;reddit&lt;&#x2F;em&gt;&lt;&#x2F;a&gt; &lt;em&gt;and&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=15695955&quot;&gt; &lt;em&gt;hn&lt;&#x2F;em&gt;&lt;&#x2F;a&gt; &lt;em&gt;.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-9ngymzWNwkPMhZ9u7uZ_XA.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;background&quot;&gt;&lt;strong&gt;Background&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Earlier this year I joined LambdaClass, a Buenos Aires-based software consultant founded a while ago by some colleagues and schoolmates. LambdaClass has a special interest in distributed systems, and while it’s not exclusively an Erlang shop, most of its projects are implemented in &lt;em&gt;BEAM&lt;&#x2F;em&gt; languages.&lt;&#x2F;p&gt;
&lt;p&gt;Although I have a recent background in microservices and functional languages (mainly Clojure), I needed some time to ramp up and gain experience with the OTP platform and its underlying philosophy. I started working on some of the LambdaClass projects right away, but there are aspects of the learning process, specially those related with architecture and design, that are best experienced in greenfield projects. The company also has the goal of a strong open source presence, thus the decision to spend part of my time on public side projects.&lt;&#x2F;p&gt;
&lt;p&gt;We considered a couple of mid sized projects and implemented one of them (which arguably looked smaller in scope than ended up being). The purpose of this document is to share our experience, put some of our discussions into words so we wrap our understanding of them, and make conclusions that can help us in future projects.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-project&quot;&gt;The Project&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;holidayping.lambdaclass.com&quot;&gt;HolidayPing&lt;&#x2F;a&gt; is a small web application that sends holiday reminders through different services like email and slack. It’s mainly aimed at consultants and freelancers used to work with clients abroad. It’s free of charge and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;holiday_ping&quot;&gt;open source&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;spin-off-projects&quot;&gt;Spin-off projects&lt;&#x2F;h3&gt;
&lt;p&gt;As part of the HolidayPing effort, we have started to design and implement some open source tools that solve a couple of problems that we identify as recurring: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;throttle&quot;&gt;throttle&lt;&#x2F;a&gt;, to perform access control over resources such as API endpoints, and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;reconnections&quot;&gt;reconnections&lt;&#x2F;a&gt;, to initiate and maintain connections to external services in an OTP idiomatic way.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-backend&quot;&gt;The Backend&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;language-erlang-vs-elixir&quot;&gt;Language: Erlang vs. Elixir&lt;&#x2F;h4&gt;
&lt;p&gt;The first decision was the programming language: Erlang or Elixir. We use both at LambdaClass, so I’d eventually have to learn them both, the question was which was more effective to learn first, considering both goals of being productive and properly understanding the Erlang platform in the long run.&lt;&#x2F;p&gt;
&lt;p&gt;Elixir would have probably been easier, considering my previous background and that it has a syntax closer to other modern languages. But learning it first carried the risk of just scratching the surface of OTP: using the language like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=ChUB5Oj2Jj4&quot;&gt;it’s the new Ruby&lt;&#x2F;a&gt;, and hiding what’s going on underneath. It does seem like it’s simpler to get a good understanding of the “OTP way” by starting with Erlang, especially since &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;learnyousomeerlang.com&#x2F;&quot;&gt;there’s literature that guides you through the process&lt;&#x2F;a&gt;. Then, switching to Elixir would mostly consist of getting familiar with a new syntax and a few language features.&lt;&#x2F;p&gt;
&lt;p&gt;We understand that as Elixir is gaining popularity and more Elixir code is being written, a deeper understanding of Erlang and OTP will become a valuable asset for the company. In addition, many robust and useful libraries are written in Erlang and being able to dive in the code is important.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;learning-erlang&quot;&gt;Learning Erlang&lt;&#x2F;h4&gt;
&lt;p&gt;A quick note on my impressions of the language: I found it to be very expressive, mostly because of pattern matching; coming from Clojure, I didn’t have issues to grasp Erlang’s functional aspects; contrary to a lot of people, I don’t mind the syntax, I actually like it a lot with the exception of some notable quirks (one comes to mind: binary literals, while very powerful, are very inconvenient as a string replacement). As my coworkers kept telling me and I later confirmed: OTP is the big deal, and not the language itself.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;application-and-supervisor-structure&quot;&gt;Application and supervisor structure&lt;&#x2F;h4&gt;
&lt;p&gt;At a high level, the application can be divided into the following components&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A RESTful API, mostly for CRUD operations.&lt;&#x2F;li&gt;
&lt;li&gt;A Process that periodically checks whether reminders should be sent (e.g.: today is a holiday in Bob’s country, and Bob asked to send reminders through slack and email channels).&lt;&#x2F;li&gt;
&lt;li&gt;Worker processes that send the reminders.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;rest-api&quot;&gt;Rest API&lt;&#x2F;h3&gt;
&lt;p&gt;The CRUD API didn’t require much thinking, at least from the OTP point of view. It’s implemented with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;ninenines.eu&#x2F;docs&#x2F;en&#x2F;cowboy&#x2F;2.0&#x2F;guide&#x2F;rest_handlers&#x2F;&quot;&gt;Cowboy rest handlers&lt;&#x2F;a&gt;, and I’ll just note that the library does a great job at forcing you to define a well behaved REST server without too much code.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;reminder-checker&quot;&gt;Reminder checker&lt;&#x2F;h4&gt;
&lt;p&gt;The processes involved in the reminders were more interesting, and obviously more important since the value of the application depends on them working properly (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;jlouisramblings.blogspot.com.ar&#x2F;2010&#x2F;11&#x2F;on-erlang-state-and-crashes.html&quot;&gt;this is the “error kernel” of the app&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;The process that checks whether holidays should be sent (remind_checker) is a gen_server that uses timer:send_interval to periodically query the database, asking what reminders should be sent. It then triggers worker creation with the necessary data to send the reminders.&lt;&#x2F;p&gt;
&lt;p&gt;How often the checker runs and what information is passed to workers are things that changed as the model and its implementation got more sophisticated, but the general idea was to always isolate the decision to send a reminder from the act of sending it, so a failure in a specific channel wouldn’t affect other channels, other users, or the checker process.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;reminder-router&quot;&gt;Reminder router&lt;&#x2F;h4&gt;
&lt;p&gt;The reminders are sent by gen_server processes called reminder routers, which are children of a supervisor under a simple_one_for_one strategy. Different channel modules implement the specifics to send the message on each service (email, slack, webhook).&lt;&#x2F;p&gt;
&lt;h4 id=&quot;why-not-gen-event&quot;&gt;Why not gen_event?&lt;&#x2F;h4&gt;
&lt;p&gt;While first studying OTP behaviors, my coworkers suggested I defer reading about gen_event, since it wasn’t used much in practice. When I started to work on HolidayPing, though, which is almost entirely about setting up and triggering events, it sounded like gen_event would be something to consider. And indeed a superficial overview confirmed that; quoting the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.erlang-in-anger.com&#x2F;&quot;&gt;Erlang in Anger book&lt;&#x2F;a&gt;: &lt;em&gt;a gen_event will act as an event hub for callbacks, or as a way to deal with notifications of some sort&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;So I went back to my coworkers: how come we aren’t using gen_event for this? It turns out that this behavior &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.afronski.pl&#x2F;2015&#x2F;11&#x2F;02&#x2F;what-is-wrong-with-gen-event.html&quot;&gt;doesn’t provide much of the benefits&lt;&#x2F;a&gt; one would expect for such an event hub. In terms of what was discussed at the beginning of this section, gen_event does not provide isolation between events, so a slow or crashing event would affect the rest.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;why-not-worker-pools&quot;&gt;Why not worker pools?&lt;&#x2F;h4&gt;
&lt;p&gt;At a certain point in the development, each router was sending the reminders for all the channels of a user on a given holiday. We wanted to further separate processing to have isolated channel requests (e.g. we don’t to bypass email sending if there was a crash requesting Slack).&lt;&#x2F;p&gt;
&lt;p&gt;The obvious option was to add a second simple_one_for_one supervisor with a new gen_server, but we briefly considered a worker pool instead. In other language ecosystems, where threads are expensive, a pool is an usual option. In Erlang, though, the story is different: processes are cheap and there’s no reason upfront to force a limit on the amount of processes being created (with some exceptions, such as maintaining a pool of connections to a database). And if you hit a point where there’s so much work to do that the amount of concurrent processes becomes too expensive, you most likely will need something fancier than a pool to overcome it (i.e. the pool manager will become a bottleneck or the queue will grow faster than workers can process it).&lt;&#x2F;p&gt;
&lt;p&gt;Admittedly, our situation is atypical in the sense that a potential overload wouldn’t come from requests constantly arriving, but a burst of reminders that need to be sent when the checker runs (currently every 15 minutes). We could easily alleviate this load by spreading the reminders through the time we have between one checker run and the next. Then again, it would be a useless optimization to do this upfront.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;avoiding-throttling-issues&quot;&gt;Avoiding throttling issues&lt;&#x2F;h4&gt;
&lt;p&gt;Which brings me to an issue that we didn’t notice until I was writing these lines, and that’s &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;holiday_ping&#x2F;issues&#x2F;34&quot;&gt;still open&lt;&#x2F;a&gt;. While we don’t have reasons to expect that our system won’t be able to handle sending all reminders at once, it’s likely that the third party services we hit will enforce throttling limits on us.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s say that hopefully a thousand developers from Argentina find our project useful, and all of them set up a Slack channel, with the default reminder settings. If that’s the case, on Christmas morning at about 9:00am the reminder checker will attempt to send a thousand requests to Slack, more or less at the same time. Slack will likely reject those requests (and their retries next time the checker runs).&lt;&#x2F;p&gt;
&lt;p&gt;One way to reduce the chance of this happening, would be the same as mentioned in previous section: spread the reminder sending across the available time between one run and the next. Of course, with enough users the limit could be hit anyway and we’d have to resort to finer grained queuing or throttling mechanisms.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;database&quot;&gt;Database&lt;&#x2F;h3&gt;
&lt;p&gt;The database pick was simple: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;@jlouis666&#x2F;how-to-build-stable-systems-6fe9dcf32fc4&quot;&gt;&lt;em&gt;PostgreSQL is the default database&lt;&#x2F;em&gt;&lt;&#x2F;a&gt; &lt;em&gt;.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;For me it had been years either &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;facundoolano.wordpress.com&#x2F;2012&#x2F;03&#x2F;11&#x2F;django-db-optimization-for-pedestrians&#x2F;&quot;&gt;hiding the database behind an ORM&lt;&#x2F;a&gt;, or using schema-less stores like MongoDB. Although the lazy developer inside of me grumbled a bit at having to define the schemas upfront, I eventually came to remember how amazingly flexible and powerful PostgreSQL can be, to the point where I found myself pushing stuff (e.g. time arithmetics) to the database level because it was just easier to work with than the available Erlang libraries. We even &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;holiday_ping&#x2F;issues&#x2F;179&quot;&gt;want to explore&lt;&#x2F;a&gt; domain integrity constraints to implement the long-postponed input validations on the backend.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;handle-the-configuration-differences-between-channels&quot;&gt;Handle the configuration differences between channels&lt;&#x2F;h4&gt;
&lt;p&gt;Our model had a spot that was hard to fit in the database schema: the user creates channels that can be of different types (Slack, email, webhook), each with different configuration parameters. The email channel takes a list of email addresses, webhook takes a single url, Slack takes an hook url, a list of channels and users, an emoji, etc.&lt;&#x2F;p&gt;
&lt;p&gt;We care about those differences only in each end of the application: when we validate the user input, and when we execute the type-specific logic to send a reminder; everywhere else, we want to treat the channels equally, regardless of the configuration. We tried several PostgreSQL features to save the channel configuration.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;inheritance&quot;&gt;Inheritance&lt;&#x2F;h4&gt;
&lt;p&gt;This use case seemed like a good fit for &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.postgresql.org&#x2F;docs&#x2F;9.6&#x2F;static&#x2F;ddl-inherit.html&quot;&gt;table inheritance&lt;&#x2F;a&gt;: we wrote a base channel table with all the common fields (user, name, type) and separate tables inheriting from it adding the type-specific configuration. But we soon found out that inheritance features are &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.postgresql.org&#x2F;docs&#x2F;9.6&#x2F;static&#x2F;ddl-inherit.html#DDL-INHERIT-CAVEATS&quot;&gt;very limited&lt;&#x2F;a&gt; and don’t provide the features that would justify the choice: unique constraints aren’t enforced across children, you can’t get children’s data when querying the parent, etc.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;plain-tables&quot;&gt;Plain tables&lt;&#x2F;h4&gt;
&lt;p&gt;Given that inheritance didn’t provide much operational value, using separate tables for configuration and managing them manually made more sense. This is the way to go in the long run, since we want to benefit from type validations and constraints, but compared with a schemaless storage, it would induce a lot of overhead in the early stages of development, considering the channel types and the model in general were far from being stable.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;hstore&quot;&gt;hstore&lt;&#x2F;h4&gt;
&lt;p&gt;We started looking at unstructured PostgreSQL data types. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.postgresql.org&#x2F;docs&#x2F;current&#x2F;static&#x2F;hstore.html&quot;&gt;hstore&lt;&#x2F;a&gt; is a key&#x2F;value type, but it doesn’t have arrays (e.g. more than one value per key). We needed this for channel options, so hstore didn’t do the trick.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;jsonb&quot;&gt;jsonb&lt;&#x2F;h4&gt;
&lt;p&gt;So we turned again to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.postgresql.org&#x2F;docs&#x2F;9.5&#x2F;static&#x2F;datatype-json.html&quot;&gt;JSON&lt;&#x2F;a&gt;. jsonb fields let us store arbitrary configuration inside the channel table, and treat it like an opaque value except on the spot where we actually use that configuration to send a reminder. Arguably this is the most convenient option only because we never got to the point of thoroughly validating channel input in the backend. When we get there, it will make sense to define properly structured tables first.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;rest-api-1&quot;&gt;Rest API&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;identifiers&quot;&gt;Identifiers&lt;&#x2F;h4&gt;
&lt;p&gt;We’ve spent some time discussing ways of identifying our resources across the project. This is a relevant discussion since it applies to most of our projects; we may as well settle with one design and be consistent from now on.&lt;&#x2F;p&gt;
&lt;p&gt;As we see it, the most flexible method is to use:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A serial ID, just for PostgreSQL. Every table has it, you use it for foreign keys and joins. You don’t want to expose it in the API, since it’s implementation dependent, and something that may not be reusable should you want to switch databases (or add an extra one).&lt;&#x2F;li&gt;
&lt;li&gt;A separate ID to uniquely identify the resource: a UUID that will never change and can be reused across databases.&lt;&#x2F;li&gt;
&lt;li&gt;When it makes sense, a “model” ID for the resource (a user email, an unique name, etc.). You may use it as an identifier in the user facing API (i.e. in the REST uris or the UI routes), to make it user friendly. But you shouldn’t rely on it for internal storage and correlation: even if you start out with an “email won’t change” assumption, business rules like that do change and there’s no benefit in relying too heavily on them for your implementation.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The last one is something we didn’t get entirely right, and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;holiday_ping&#x2F;issues&#x2F;113&quot;&gt;there’s still work to do&lt;&#x2F;a&gt;. Our current implementation has model IDs (user email, channel name, holiday date), but no external UUIDs, so some use cases like changing a channel name are not supported.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;authentication-and-authorization&quot;&gt;Authentication and authorization&lt;&#x2F;h4&gt;
&lt;p&gt;To manage authorization of the API, we went with Bearer tokens based on previous experience. What’s convenient about token authorization, as opposed to, say, requiring Basic Auth on every request, is that it allows us to decouple the authentication from the authorization: if we want to support a new authentication method (which we did when we added GitHub login), we just add a new auth endpoint that returns an access token; authorization on the rest of the API remains untouched.&lt;&#x2F;p&gt;
&lt;p&gt;Regarding the token format, I initially went with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;jwt.io&#x2F;&quot;&gt;JWT&lt;&#x2F;a&gt; without giving it much thought, because that’s what I’ve seen most commonly used to authorize web apps accessing a REST backend. My coworkers, who haven’t heard about it before, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lambdaclass&#x2F;holiday_ping&#x2F;issues&#x2F;20&quot;&gt;were suspicious&lt;&#x2F;a&gt;, which I understand, because it totally sounds like:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;0-LmkSEubDQc5xYFKb.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;And we’re &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;@jlouis666&#x2F;two-technologies-which-are-bad-for-you-160311ad6b24#13fd&quot;&gt;not very fond of JSON&lt;&#x2F;a&gt;. So I digged up a little bit more to make sure the decision made sense. There are &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;cryto.net&#x2F;~joepie91&#x2F;blog&#x2F;2016&#x2F;06&#x2F;13&#x2F;stop-using-jwt-for-sessions&#x2F;&quot;&gt;several&lt;&#x2F;a&gt; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;kev.inburke.com&#x2F;kevin&#x2F;things-to-use-instead-of-jwt&#x2F;&quot;&gt;articles&lt;&#x2F;a&gt; expressing concerns about using JWT, although most of them don’t apply to our use case. Assuming we want to stick to Bearer tokens, the alternative to JWT would be to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;auth0.com&#x2F;blog&#x2F;ten-things-you-should-know-about-tokens-and-cookies&#x2F;#token-oauth&quot;&gt;just store a random string in the database&lt;&#x2F;a&gt;, associated with the user, and check that value on every request. A quick comparison between the two options:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;JWT lets you identify the user without the need to hit the database on every request: the server decodes the token with the same secret it used to generate it, and checks the claims. To be fair, at least in our use case, there’s no evidence that going to the database on each request would be a problem.&lt;&#x2F;li&gt;
&lt;li&gt;JWT is stateless, which seems to be more inline with REST principles: there’s no session, the client sends the token on each request which is enough to identify it.&lt;&#x2F;li&gt;
&lt;li&gt;Database stored tokens require a bit of extra effort: we need to manage expiration ourselves, delete old tokens and make sure we pick a secure enough method to generate them. On the other hand, blacklisting compromised tokens is easier than with JWT, since we can just flag them in the database (although this is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;7030694&#x2F;why-do-access-tokens-expire&#x2F;7035926#7035926&quot;&gt;less of an issue&lt;&#x2F;a&gt; using a short expiration).&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;In conclusion, JWT is easier (although &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.infoq.com&#x2F;presentations&#x2F;Simple-Made-Easy&quot;&gt;it may not be simpler&lt;&#x2F;a&gt;) than database stored tokens. Either option can work, and I don’t see a strong enough reason to drop JWT having that already working.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;nested-resources&quot;&gt;Nested resources&lt;&#x2F;h4&gt;
&lt;p&gt;This is one of the things that we debated but didn’t get to a definite answer. We have these restful resources:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&#x2F;api&#x2F;channels&#x2F;:name&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&#x2F;api&#x2F;channels&#x2F;:name&#x2F;holidays&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&#x2F;api&#x2F;channels&#x2F;:name&#x2F;reminders&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;And at some point the UI needs to display a summary view that lists channels including their holiday and reminder information.&lt;&#x2F;p&gt;
&lt;p&gt;What do we do? We obviously don’t want to force the UI to collect the data by making two extra requests per channel in the list. We don’t want to have an API tailor-made for this specific client, either. And don’t say GraphQL, because this is nowhere near big enough to call for that. View saw two acceptable solutions:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Use a generic query parameter like &lt;code&gt;?children=true&lt;&#x2F;code&gt; to indicate that all the children resources should be included in the response. The problem is that this is an all-or-nothing approach: with big enough resources, you may want some of the children and not all. I’ve seen APIs suffer from that, coming up with weird DSLs to recursively pick nested children in the responses (now, &lt;em&gt;that&lt;&#x2F;em&gt; is the case where you’d look at GraphQL nowadays).&lt;&#x2F;li&gt;
&lt;li&gt;Consider the detailed version of the channel (the one that includes its children information) as a separate resource altogether. At first this too felt a bit like forcing the backend to fit a client need (and, to be honest, looking at the URIs &#x2F;api&#x2F;channels and &#x2F;api&#x2F;channels_detail didn’t help); but after some thinking: better to let resources reproduce and keep the interface as dumb as possible (i.e. no magic query parameters).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;We could have gone either way. We chose the separate resource because it was easier to implement.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;tests&quot;&gt;Tests&lt;&#x2F;h3&gt;
&lt;p&gt;I think you can’t write serious software without some sort of testing. At some point it’s inefficient to try to make progress without having tests to have your back. But I also think there are situations where being obligated to add tests is counter productive. Apart from the one commandment: &lt;em&gt;thou shalt test thy shit&lt;&#x2F;em&gt; , I don’t like any kind of religiousness about testing. Some types of software benefit a lot from unit tests (testing specific functions, isolated from the rest of the system), some not so much; coverage can be a good indicator, but forcing a specific coverage level sucks; some people work better with TDD, some people work better by adding tests after having some working code; some stuff calls for testing every possible scenario, some for generative testing. Etcetera.&lt;&#x2F;p&gt;
&lt;p&gt;In my experience over the last few years, working on small APIs that mostly deal with connecting to and integrating with external services, there’s little benefit in making pure unit tests. You have to spend a lot of time building mocks to test glue code, and still the most common scenarios can totally fail. If your software deals mostly with integrations, then you need integration tests to have some sort of confidence that your project works and that you don’t break it when you modify it. Because I change it a lot, all the time; that’s something I &lt;em&gt;am&lt;&#x2F;em&gt; religious about: if you aren’t breaking any APIs, you have the time and you know how to put your code in a better shape, then you do it every time you can.&lt;&#x2F;p&gt;
&lt;p&gt;Fortunately my coworkers share the same vision, so for HolidayPing we focused on integration tests that make sure the project works as a whole, with a real database and sending actual reminders. At first with lots of shortcuts to make sure the internal parts were working, but eventually, as development moved forward and the API stabilized, we were able to rewrite the tests so they mostly talk to the external API.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;To be continued…&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Lasp: a little further down the Erlang rabbithole</title>
          <pubDate>Tue, 09 May 2017 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/lasp-a-little-further-down-the-erlang-rabbithole/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/lasp-a-little-further-down-the-erlang-rabbithole/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/lasp-a-little-further-down-the-erlang-rabbithole/">&lt;p&gt;A few years ago I found &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;lasp-lang.readme.io&#x2F;docs&quot;&gt;Lasp&lt;&#x2F;a&gt;: &lt;em&gt;“a suite of libraries aimed at providing a comprehensive programming system for planetary scale Elixir and Erlang applications”&lt;&#x2F;em&gt;. At this point it should come as no surprise for you to learn that here at Not a Monad Tutorial we are are interested in distributed systems and Erlang. After playing a little bit with Lasp I watched a few talks by its creator: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;cmeik&quot;&gt;Christopher Meiklejohn&lt;&#x2F;a&gt;. After watching his talk &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=lsKaNDj4TrE&quot;&gt;“Distributed, Eventually Consistent Computations”&lt;&#x2F;a&gt; I decided it was time to interview Christopher.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Discuss and vote at&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;lobste.rs&#x2F;s&#x2F;3gvmyl&#x2F;lasp_little_further_down_erlang&quot;&gt; &lt;em&gt;lobsters&lt;&#x2F;em&gt;&lt;&#x2F;a&gt; &lt;em&gt;,&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;programming&#x2F;comments&#x2F;6a620o&#x2F;lasp_a_little_further_down_the_erlang_rabbithole&#x2F;&quot;&gt;&lt;em&gt;reddit&lt;&#x2F;em&gt;&lt;&#x2F;a&gt; &lt;em&gt;and&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=14300763&quot;&gt; &lt;em&gt;hn&lt;&#x2F;em&gt;&lt;&#x2F;a&gt; &lt;em&gt;.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-SKlcy2D4QxhBrMdNYNCIHA.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is Lasp?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Originally, Lasp was a programming model designed for deterministic distributed computing with weak synchronization. Lasp’s programming model appears function, in that you write applications that look like functional programs, but under arbitrary distribution, these applications are guaranteed to return the correct result, with minimal coordination, under network anomalies such as network partitions or node failures. Lasp achieves this by building upon the design philosophy of Conflict-free Replicated Data Types, or CRDTs: data structures that are designed to achieve convergence without requiring locking or other synchronization primitives.&lt;&#x2F;p&gt;
&lt;p&gt;During the evaluation phase of Lasp, we were tasked with trying to scale a prototype implementation written in Erlang to 10,000 nodes; we got as far as we could in the allotted time we had, which was 1,024 nodes running on Amazon EC2. In the process of trying to achieve that scale, we had to develop a number of libraries in Erlang to provide supporting infrastructure: new distribution algorithms, optimized implementations of the data types, deployment and operations tooling, etc. So, I’d say at this point Lasp, in the academic sense refers to the original programming model, but Lasp in the industrial sense, refers to the entire suite of libraries that deliver the programming system and programming model at large scale.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What are CRDTs? What problems do CRDT solve?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;CRDTs, or Conflict-free Replicated Data Types, are data types that are designed for use in distributed systems: think regular sequential abstract data types, but with a predefined, deterministic merge function for any two possible values.&lt;&#x2F;p&gt;
&lt;p&gt;One of the big challenges in distributed computing is related to consistency. When a network partition occurs, any system that is managing replicated data must make a choice: do they allow operations to proceed, remaining available-under-partition, or do they prohibit operations to proceed, remaining consistent-under-partition.&lt;br &#x2F;&gt;
Consistent-under-partition systems, or CP systems, provide strong consistency which makes application development easier, whereas available-under-partition systems, or AP systems, allow the developer to both exploit available concurrency in the system for performance, and keep servicing requests when network partitions inevitably occur. Available-under-partition systems are ideal for applications that are geo-distributed, because they allow users to read and write locally to their geographically close replica and don’t incur a synchronization penalty for write operations (which, in some cases can be &amp;gt; 100ms an operation).&lt;&#x2F;p&gt;
&lt;p&gt;However, one of the challenges in using available-under-partition systems is the potential for write conflicts: two writes happen to the same object concurrently at two replicas. When the network ultimately convergences, the different replicas have to come to an agreement over which value wins. When using a database with opaque value registers that you &lt;code&gt;set&lt;&#x2F;code&gt; or &lt;code&gt;get&lt;&#x2F;code&gt; values on, this choice can be arbitrary: either choice may be valid, and systems like Cassandra resort to solving this by using the user provided timestamp to pick a value. Approaches like this, while deterministic, are problematic, however, because arbitrarily picking a value based on time and dropping the other write operation may fail to capture developer intent.&lt;&#x2F;p&gt;
&lt;p&gt;CRDTs say, rather than have opaque registers, why not store actual data types in the database, and then have a conflict resolution policy that is compatible with the semantics of the data type. One example of a trivial CRDT is the grow-only set: if you can never remove elements from the set, it’s always safe to merge copies of a set, that is independently modified, using the set union operation. Similar designs exist for sets where you can add and remove elements arbitrarily, graphs, dictionaries, counters, and booleans.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What other alternatives exists apart from CRDTs to solve the same type of issue?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Operational transformation is an alternative approach, which predates CRDTs, and was used to build both Google Docs and Apache Wave. Operational transformation relies on “transforming” edit operations based on concurrent operations so they achieve the desired effect through the transformation once the document has been modified. There exist a significant number of different algorithms, each which makes a different set of tradeoffs, and there’s no algorithm that’s better than the others in the general case. Its are extremely difficult to implement correctly and to verify, given the number of possible operations and operation interleaving and transformations that must be considered.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Are there any downsides of using CRDTs?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;CRDTs can be very expensive in terms of implementation and state synchronization. Lots of effort has gone into reducing the overhead in state transmission through both operations-based CRDTs (a variant that sends just operations instead of state, with the tradeoff that it requires a stronger property for message delivery from the network) and delta-CRDTs (a variant that minimizes the required state that needs to be transferred by minimizing the change representation.)&lt;&#x2F;p&gt;
&lt;p&gt;One open challenge for both CRDTs, and any system that has to manage a large-amount of replicas of objects that will be concurrently operated on, is actor management. Typically, these systems and data structures must carry metadata sizes O(n) on the number of actors to ever modify an object in the system: in a system with a large amount of mobile devices and high churn, this can be prohibitive in terms of space. Recent approaches to try to address this problem rely on either imposing a structure on the way nodes share information with one another to allow some nodes to subsume the changes of other nodes, or allowing transient nodes to temporarily “borrow” identities of a smaller number of permanent nodes so the identifiers of temporary nodes aren’t carried around in the objects metadata indefinitly.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;lasp-lang.readme.io&#x2F;docs&#x2F;what-is-lasp-pg&quot;&gt;&lt;strong&gt;Lasp process registry&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;? Why create a new process registry if we already got global, pg2, gproc or syn in Erlang?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;About three or so years ago I created Riak PG, a process registry that used the same distribution strategy as Riak (with, a corresponding paper presented at the Erlang Workshop that year.) I created this process registry because I had done an extensive study and writeup about why pg2, proc, and global are not designed properly for&lt;br &#x2F;&gt;
distributed scenarios where partitions can occur and availability is paramount.&lt;&#x2F;p&gt;
&lt;p&gt;Lasp PG is a natural extension of this, where it uses an unstructured overlay with full replication and CRDTs instead of partial replication across a structured overlay network and CRDTs.&lt;&#x2F;p&gt;
&lt;p&gt;While Ericsson is working on scaling the global facility and growing distributed Erlang to support a larger number of nodes, they are focusing on:&lt;&#x2F;p&gt;
&lt;p&gt;a) supporting existing applications developed at Ericsson with distributed Erlang&lt;&#x2F;p&gt;
&lt;p&gt;b) smaller scale of nodes, operating in a LAN configuration (think ~200–500)&lt;&#x2F;p&gt;
&lt;p&gt;Their solution for scaling global shards the information across nodes, and requires availability of the DHT (they are using Kademlia, a structured overlay network) for requests to be serviced.&lt;&#x2F;p&gt;
&lt;p&gt;Lasp (and, therefore, Lasp PG) is focusing on large-scale, wide-area programming: think ~10–100k nodes operating at geo-scale. In this scenario, partitions are common — in fact, mobile clients or IoT devices might disable their antennas to preserve battery. In this scenario, we have to assume that nodes are not aware of every other node in the network, have to route messages through other nodes, and have to be resilient to partitions and have the ability to keep operating. Lasp PG is the first step towards this, and our work that was presented at Erlang Factory, Loquat, is the second step towards this goal.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Do you think that parts of what you created and found while developing Lasp will be ported to more traditional programming languages?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Hopefully, but it’s unclear what components will end up being useful or not. We are mainly focused on quickly prototyping things and performing evaluations, all in Erlang and Elixir, to determine which approaches scale, are easy to program with, etc.&lt;&#x2F;p&gt;
&lt;p&gt;I think that once we get a bit further along in the research, maybe 4 to 5 years, that some of the ideas we’re just coming up with now might be useful and developed enough to make it into the mainstream.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;lasp-lang.readme.io&#x2F;docs&#x2F;overview&quot;&gt;&lt;strong&gt;Partisan&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;? Why did you not use the default distributed Erlang?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Partisan is a membership layer for clustering groups of Erlang nodes. It bypasses distributed Erlang completely, can run in a variety of topologies, will soon support connection multiplexing, and has full support for TLS&#x2F;SSL. Partisan can support clusters of nodes running in star-topologies, random unstructured overlays, and clusters that are fully connected.&lt;&#x2F;p&gt;
&lt;p&gt;Distributed Erlang is a bit too rigid for us: it assumes a fully connected network, which is extremely difficult to scale to large clusters of nodes, and uses a single TCP connection between all processes communicating from one node to another. In order to build a more reliable system that would scale to large clusters of nodessecurely, we needed our own membership layer for state dissemination. Right now, partisan doesn’t support all of the semantics that Erlang provides, but we’re actively working with some developers in the open source community to extend partisan to support normal Erlang message passing across our highly-available framework.&lt;&#x2F;p&gt;
&lt;p&gt;We’ve also started to see some companies using Erlang and Elixir pick up partisan as a tool for helping them build reliable, large-scale, applications that need to do efficient state dissemination which is very nice for an implementation that came out of a research group.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What other programming languages or pieces of software do you keep an eye on?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Right now, what I’m most excited about is Space-Time Insight’s implementation of Microsoft Orleans in Erlang, called &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;SpaceTime-IoT&#x2F;erleans&quot;&gt;Erleans&lt;&#x2F;a&gt;. I think that Orleans take a lot of the complexity out of actor management in Erlang and Elixir and helps developers get straight to building distributed applications without having to focus on the low level details around message routing, actor placement, and actor creation and termination.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What do you recommend reading or doing for those of us that we are trying to learn more about distributed systems?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I think that everyone is building distributed applications nowadays — from your web developer building a rich-web client in JavaScript to mobile developers building the next hit application — we all have to deal with the problems of state, synchronization, offline operation, and maintaining consistency.&lt;&#x2F;p&gt;
&lt;p&gt;That said, from the academic side, I’ll recommend&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.springer.com&#x2F;gp&#x2F;book&#x2F;9783642152597&quot;&gt; “Introduction to Reliable and Secure Distributed Programming”&lt;&#x2F;a&gt; from Cahin, Guerraoui, and Rodrigues. It’s the book that my university teaches with, and the course that I’ve TA’d and contributed content to.&lt;&#x2F;p&gt;
&lt;p&gt;The course is also taught via a MOOC on edX as well, and I’ll be doing&lt;br &#x2F;&gt;
a guest lecture this semester in Part 2 on Lasp and CRDTs.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.edx.org&#x2F;course&#x2F;reliable-distributed-algorithms-part-1-kthx-id2203-1x&quot;&gt;Reliable Distributed Algorithms, Part 1This course gives a comprehensive introduction to the theory and practice of distributed algorithms for designing…www.edx.org&lt;img src=&quot;https:&#x2F;&#x2F;cdn-images-1.medium.com&#x2F;fit&#x2F;c&#x2F;160&#x2F;160&#x2F;0*I3V5Fl71IfPeGbC2.&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.edx.org&#x2F;course&#x2F;reliable-distributed-algorithms-part-2-kthx-id2203-2x&quot;&gt;Reliable Distributed Algorithms, Part 2The course will help students gain an in-depth understanding of distributed algorithms to build reliable and scalable…www.edx.org&lt;img src=&quot;https:&#x2F;&#x2F;cdn-images-1.medium.com&#x2F;fit&#x2F;c&#x2F;160&#x2F;160&#x2F;0*wlK5JSGA0E8nK6Kp.&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>The big old reliable elephant: talking about Postgres with Craig Kerstiens</title>
          <pubDate>Wed, 26 Apr 2017 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/the-big-old-reliable-elephant-talking-about-postgres-with-craig-kerstiens/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/the-big-old-reliable-elephant-talking-about-postgres-with-craig-kerstiens/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/the-big-old-reliable-elephant-talking-about-postgres-with-craig-kerstiens/">&lt;p&gt;In this opportunity I interviewed Craig Kerstiens. Craig works for &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.citusdata.com&#x2F;&quot;&gt;citusdata&lt;&#x2F;a&gt;, a company that helps customers scale databases beyond a single node. Over the last few years, after building systems that used Redis, Cassandra, Riak, Elasticsearch and even Mongo, I rediscovered my love for PostgreSQL. The documentation is excellent, its development pace is astonishing and it is a good old reliable beast. However its feature set can be quite overwhelming. To mention just a few of its special features: you got a big option of index types (B-tree, Hash, GiST, SP-GiST, GIN and BRIN), many &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.craigkerstiens.com&#x2F;2014&#x2F;05&#x2F;07&#x2F;Postgres-datatypes-the-ones-youre-not-using&#x2F;&quot;&gt;data types&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;railsware.com&#x2F;blog&#x2F;&#x2F;2012&#x2F;04&#x2F;23&#x2F;postgresql-most-useful-extensions&#x2F;&quot;&gt;extensions&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;postgresguide.com&#x2F;sql&#x2F;window.html&quot;&gt;window functions&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;postgresguide.com&#x2F;cool&#x2F;ctes.html&quot;&gt;common table expressions&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.craigkerstiens.com&#x2F;2013&#x2F;08&#x2F;05&#x2F;a-look-at-FDWs&#x2F;&quot;&gt;foreign data wrappers&lt;&#x2F;a&gt;. As Craig said in one of this talks “Postgres is the Emacs of databases”. If you have ever used Emacs you know that learning it can take some time due to the number of choices available.&lt;&#x2F;p&gt;
&lt;p&gt;Craig helped me decide what postgres features to use and how, thanks to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.craigkerstiens.com&#x2F;content&#x2F;&quot;&gt;his blog&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.postgresguide.com&#x2F;&quot;&gt;postgresguide.com&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;postgresweekly.com&#x2F;&quot;&gt;postgresweekly.com&lt;&#x2F;a&gt;. He has been really helpful in sharpening my postgres knife.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Discuss and vote at&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;lobste.rs&#x2F;s&#x2F;y0k2h5&#x2F;big_old_reliable_elephant_talking_about&quot;&gt; &lt;em&gt;lobsters&lt;&#x2F;em&gt;&lt;&#x2F;a&gt; &lt;em&gt;,&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;programming&#x2F;comments&#x2F;67owq6&#x2F;the_big_old_reliable_elephant_talking_about&#x2F;&quot;&gt;&lt;em&gt;reddit&lt;&#x2F;em&gt;&lt;&#x2F;a&gt; &lt;em&gt;and&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=14203940&quot;&gt; &lt;em&gt;hn&lt;&#x2F;em&gt;&lt;&#x2F;a&gt; &lt;em&gt;.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-xBJtkf59c2V5ncf-Q-1_Eg.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why do you prefer PostgreSQL over other SQL databases?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It was actually a little ways into my career before I came around to Postgres. I started on Oracle in college. When I found Postgres it was a bit stodgey and just correct. There was nothing wrong with it, but it wasn’t anything to write home about. What was interesting about it was the license which made it very favorable to fork and extend and add any more value. Since that time though it’s really come a long way from a user experience perspective, and really expanding beyond the “SQL” world.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why do you think a lot of developers moved away from SQL databases a few years ago?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;To be right to the point… user experience. SQL is a great language for querying lots of data. The idea that you have to setup your schema ahead of time and define your data model is painful though. Over the longterm is pays off, but there is nothing inherint in SQL that says you can’t model things in documents and have that transformed to relational. The ease and promise of document databases is huge for getting started, but it’s not a perfect long term solution…&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why did many of them return to use SQL databases?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The ability to get up and running quickly is always at odds with long term maintainability. Thats not to say that you should pre-maturely optimize, but SQL has stood a test of time of querying and accessing data and we’re seeing that in a return to systems that re-implement SQL on top of other datastores.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;In which cases wouldn’t you use PostgreSQL?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The only one that really comes to mind is graph databases. Over time PostgreSQL has gained support XML, key value, full text search, document storage, the only thing it hasn’t covered yet really is the graph arena.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is the most misused feature of PostgreSQL or SQL?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Wow, thats a tough one. I’m going to completely side step the question and say that it’s not leveraging Postgres specific features. I see a lot of developers say “I want to be able to migrate away so I’m going to do the most generic bare bones thing possible” Whether that’s not using the array datatype, JSONB, GIN or GiST indexes, at that point why even pick Postgres? The biggest mistake I see is not mis-using a feature, it’s not using it for the idea you might one day migrate.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What are your favorite PostgreSQL extensions?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Obviously I’m biased towards &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;citusdata&#x2F;citus&quot;&gt;Citus&lt;&#x2F;a&gt;. I’ve actually known the Citus team for over 4 years now, before they were an extension to Postgres. At Heroku what Iwould hear and see over and over is people running into this ceiling with Postgres. SQL databases typically work really well on a single node, and there’s this notion that SQL can’t be distributed. Citus actually solves a problem for hundreds of customers I saw outgrowing single node Postgres whether at 100 GB or 1 TB, that makes it trivial to shard out while still maintaining transactional semantics.&lt;&#x2F;p&gt;
&lt;p&gt;Though I have to mention my second favorite: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.citusdata.com&#x2F;blog&#x2F;2017&#x2F;04&#x2F;04&#x2F;distributed_count_distinct_with_postgresql&#x2F;&quot;&gt;HyperLogLog&lt;&#x2F;a&gt;. This is one I personally have not got to put into production, but is super awesome. It’s essentially a sketch algorithm for probabilistic distincts across really large datasets.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Is there any feature that another database has that you would like PostgreSQL to have?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I think the biggest would be easier onboarding or not having to define your schema ahead of time. ToroDB aims to do some of this for Postgres when coming from Mongo, but a native Postgres experience would be huge here.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What do you recommend reading to understand the implementation of PostgreSQL?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Subscribe to the hackers mailing list.&lt;br &#x2F;&gt;
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.postgresql.org&#x2F;list&#x2F;pgsql-hackers&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.postgresql.org&#x2F;list&#x2F;pgsql-hackers&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The best engineers (even one that don’t actively develop for Postgres subscribe here as it’s just great discussion and development).&lt;&#x2F;p&gt;
&lt;p&gt;And for a lighter read, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;postgresweekly.com&quot;&gt;postgresweekly.com&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What do you recommend reading to get better at SQL and PostgreSQL?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I actually got my foundation in relational algebra. At the time it seemed overly academic like a lot of other CS, when it comes to databases though and in particular SQL it gives you a huge leg up. I’d very much encourage people to spend some time on the academic side of relational algebra, then move to SQL syntax, over the long term it’ll really pay off.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Gaming with Elixir: discovering new lands in the BEAM realm</title>
          <pubDate>Thu, 20 Apr 2017 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/gaming-with-elixir-discovering-new-lands-in-the-beam-realm/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/gaming-with-elixir-discovering-new-lands-in-the-beam-realm/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/gaming-with-elixir-discovering-new-lands-in-the-beam-realm/">&lt;p&gt;In this opportunity I interviewed somebody I don’t normally interview: a client, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;in&#x2F;chrisjimison&#x2F;&quot;&gt;Chris Jimison&lt;&#x2F;a&gt;, CTO of Merigo. One of my clients. After working for almost a year with Merigo, I appreciate and understand the differences between using a BEAM language to develop a typical REST JSON system and using it to develop a videogame backend. I am not aware of many companies using Elixir to develop backends. I have only watch a talk by Jamie Winsor called “&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;_i6n-eWiVn4&quot;&gt;Building And Releasing A Massively Multiplayer Online Game”&lt;&#x2F;a&gt;. I hope to be able to interview Jamie in the following weeks.&lt;&#x2F;p&gt;
&lt;p&gt;To sum up I did this interview because I wanted to share my experience of using Elixir for developing a different kind of beast. I am also writting a post about what I like and dislike about Elixir after developing in Erlang for quite a few years.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Discuss and vote at&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;lobste.rs&#x2F;s&#x2F;f1wxuc&#x2F;gaming_with_elixir_discovering_new_lands&quot;&gt; &lt;em&gt;lobsters&lt;&#x2F;em&gt;&lt;&#x2F;a&gt; &lt;em&gt;,&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;programming&#x2F;comments&#x2F;66hnpk&#x2F;gaming_with_elixir_discovering_new_lands_in_the&#x2F;&quot;&gt;&lt;em&gt;reddit&lt;&#x2F;em&gt;&lt;&#x2F;a&gt; &lt;em&gt;and&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=14156379&quot;&gt; &lt;em&gt;hn&lt;&#x2F;em&gt;&lt;&#x2F;a&gt; &lt;em&gt;.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-3HjK0CX5813XXtDwfKIhWw.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Could you describe your experience in the software industry?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I started in the software industry about 15 years ago. My career has been focused in the game development industry, specializing in networking problems. This includes games that have a peer-to-peer deterministic game play model, all the way to big MMORPG titles. In the last 7 years I have been working on mobile titles where the game networking requirements are more of a hybrid of REST and MMORPG-style technologies. Some companies I have worked for in the past include EA, Sony R&amp;amp;D, NGMOCO and DeNA.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;merigo.co&#x2F;&quot;&gt;&lt;strong&gt;Merigo&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;About 3 and a half years ago my cofounders and I decided we wanted to start our own company to help game developers be more successful in the market. One of the big issues that has come around in the last 4–5 years is single player games just don’t make that much money in the market place (outside of the occasional indie hit). As mobile game developers move into the “Online Gaming” space, the costs of creating these applications are increasing exponentially. When the iPhone 3G first launched (this was the first model that had the App Store) many game teams consisted of one or two engineers — a “large” game having 3–5 engineers. We are now seeing team sizes of anywhere between 10–20 and have even heard of some titles consisting of over 30 engineers. This means costs of titles are skyrocketing and the need to “fail fast” is more critical. “Fail fast” gets to the heart of game development. A game designer comes up with an idea they “think” will be fun. However you don’t truly know until you have it in your hands to play. Some ideas work, some don’t. With such a high development cost, many game teams must choose to implement a feature and hope that it works because they don’t have the budget to try a second or third time. Merigo wants teams spending more time “focusing on the fun” and less time worrying about how to make it all work.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is SDE?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The Merigo SDE (Server Development Environment) is a system that allows developers to build out their server logic quickly without having to worry about all the pain of how to scale out and manage their stack. We provide many common game services such as authentication, purchase verification, leaderboards, player persistence, etc. However the SDE is not a bunch of black box REST APIs. The SDE enables developers to write custom “scripts” in Elixir that can be loaded&#x2F;updated at runtime, allowing them to create custom APIs and behaviors needed for their application. Since we have provided the basic framework of how the scripts are managed and when they are called we can now “scale” this logic out across a distributed server cluster. Our main philosophy with the SDE is “servers are cheap, people are expensive”. With the SDE we wanted to provide a system that allows for fast development and rapid iteration with the knowledge that you can always spin up new servers to balance the load, even if your business logic is not optimized for high performance. Each team can then decide where they want to invest their time once the game goes “live.” They can decide where to best invest their time: building new features or optimizing their code to reduce their server costs. Basically turning development into a simple Return on Investment (ROI) equation.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What languages&#x2F;platforms did you consider or try before settling on BEAM&#x2F;Elixir?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Java, Scala, Go and for one crazy day I even debated just writing the whole stack in C++.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What made you choose the Erlang VM (BEAM) instead of the JVM?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I hate writing Java… The real reason we didn’t go with a JVM environment is tuning it is kind of a black art and something I have not done in years (since Java 1.4).&lt;&#x2F;p&gt;
&lt;p&gt;Also, we had the following goals:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;High level of fault tolerance&lt;br &#x2F;&gt;
a. Because game teams write “scripts” we did not want them to be able to bring the node down because they wrote bad code&lt;br &#x2F;&gt;
b. If the game server goes down this is VERY bad for game developers. Users will get mad quickly and just download a different game with a very slim chance they may come back&lt;br &#x2F;&gt;
c. User Acquisition (UA) is expensive. To “buy” a user (this is done via Ads or Promotions, etc) you can spend up to $30 per person, and if your game server is crashed that money is gone.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;2. Easy to scale horizontally&lt;&#x2F;p&gt;
&lt;p&gt;3. Easy to upgrade servers with hot patches without taking the system down&lt;&#x2F;p&gt;
&lt;p&gt;With those three goals BEAM is one of the best tools for the job.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Lua is a language that is pretty common in the game development community. The Erlang VM has a Lua based language called Luerl. Why did you choose to implement Playground in Elixir instead of Luerl?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We actually started with Luerl in early 2014 as our scripting language. The problem with Luerl at the time (I have not reviewed it in some years) was its basic architecture didn’t fit our needs. Luerl is designed for you to pass it a bunch of data, process that data in Lua, then get the results back. However if you don’t know what the Lua code will be doing you need to pass in ALL possible data in one big map (and this was pre-Erlang maps so it was a custom struct the Luerl lib created). This meant we had to spend a lot of time modifying the actual Luerl package to extend its basic APIs so the game logic could “ask” our Erlang code for needed data, etc. Around mid&#x2F;late 2014 Elixir had matured and we felt that the language was easy enough that most folks could pick up the basic syntax without a lot of work. In the end we are really happy that we moved off Luerl. Now our System &amp;lt;-&amp;gt; scripting environment has a near zero overhead (we don’t have to serialize&#x2F;deserialize struct, etc). In fact we liked Elixir so much we ended up porting all of our Erlang system to it and now we are pretty much an Elixir shop.&lt;&#x2F;p&gt;
&lt;p&gt;Also Elixir made it easy to “Walk” the code AST where we can check it for operations we don’t allow. For example, when a team writes Elixir business logic we don’t allow them to use OTP, or even spawn processes, etc.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is the biggest difference between implementing a backend for a video game and a HTTP REST JSON api?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It all boils down to two things: latency and state.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;State&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Games are very state-full, and if you had to send all the data needed to finish a REST-based transaction your JSON would be HUGE both upstream and downstream. Games also tend to react to events that the user did not generate so bi-directional communication is a very strong requirement. For example: If player 1 attacks player 2, player 2 will need to be notified of this event and different actions may be triggered if player 2 is online or not. Also, this state may need to be presented to other players, so in the last example player 3 may see that players 1 and 2 are in combat so he&#x2F;she may jump in and help player 2.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Latency&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
For a typically ecommerce site a 500ms latency may be completely unnoticeable. However, in a game, 500 ms could be the difference between winning and losing. So we are constantly concerned with latency. This includes things like time spent serializing&#x2F;deserializing your communications, how much data you are sending up and down the wire, how long you spent accessing the DB, etc, etc.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What are the main difference between implementing actual games and game development tools?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It is the same as developing any tools&#x2F;lib vs a product that goes directly to consumers. With tools you need to think about not just what the tool does but also you have to think about how others will use it. Does it have the flexibility to work in N different use cases, etc. With a game you know exactly how your product should behave and can quickly tell when things work or they don’t. With a tool it may work great with the designed use case, but some other creative engineer decided to repurpose it in a completely different way. As a tools&#x2F;lib developer your challenge is to have the flexibility to support both.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What was your experience using&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;basho&#x2F;riak_core&quot;&gt;&lt;strong&gt;Riak Core&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;? What did you like and what did you not?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Riak Core is a very cool library but really you have to look at it from two angles.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Do I buy into the whole Consistency Hashing thing?&lt;&#x2F;li&gt;
&lt;li&gt;Do I want to implement my own solution for this?&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;About two years ago we said yes to the first question, however getting Riak Core to work in an elixir environment was just too painful so we rolled our own solution. It worked well and was actually a bit faster than Riak Core, however it was not nearly as robust and did not handle node failures and handoffs well. Recently the Phoenix and Basho got a Hex package that actually works in Elixir and we jumped at the chance to try it out. After some evaluation we decided that the little bit of performance gains we got from our system was outweighed by the expanded functionality that Riak Core provided.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Liked&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Very robust software that handles a lot of error cases for us.&lt;&#x2F;li&gt;
&lt;li&gt;Built in gossip protocol&lt;&#x2F;li&gt;
&lt;li&gt;Handles data handoffs when new nodes are brought online&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Dislike&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Dependencies that don’t work because Basho bases all their libs&#x2F;tools on Erlang R15&lt;&#x2F;li&gt;
&lt;li&gt;Very heavy weight&lt;&#x2F;li&gt;
&lt;li&gt;Difficult to track down errors deep in the system code&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Is there anything you miss from implementing actual videogames?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Working on videogames is a truly unique experience. Not only are you working with very smart engineers, you also get to work closely with Artists, Game Designers, Musicians, and sometimes even Actors. That is a very fun and exciting environment to be in.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>A Pythonist finds a new home at Clojure land</title>
          <pubDate>Fri, 14 Apr 2017 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/a-pythonist-finds-a-new-home-at-clojure-land/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/a-pythonist-finds-a-new-home-at-clojure-land/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/a-pythonist-finds-a-new-home-at-clojure-land/">&lt;p&gt;Welcome back to another interview of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;notamonadtutorial.com&#x2F;&quot;&gt;Not a Monad Tutorial&lt;&#x2F;a&gt;. In this opportunity I decided to interview Facundo Olano, a friend, a teammate, and a developer with a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;facundoolano&quot;&gt;diverse experience&lt;&#x2F;a&gt;. We talked about Python, Node.js, Clojure, Common Lisp and software development in general. Something worth mentioning is that this is not the first time Python and Clojure get mentioned together at Not a Monad Tutorial. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;notamonadtutorial.com&#x2F;indie-languages-interview-pixie-and-timothy-baldridge-cadbc36418dc&quot;&gt;Timothy Baldridge implemented Pixie&lt;&#x2F;a&gt;, a Lisp language inspired by Clojure, in Python.&lt;&#x2F;p&gt;
&lt;p&gt;Vote and discuss at &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;lobste.rs&#x2F;s&#x2F;nz28ef&#x2F;pythonist_finds_new_home_at_clojure_land&quot;&gt;lobsters&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;programming&#x2F;comments&#x2F;65ct5j&#x2F;a_pythonist_finds_a_new_home_at_clojure_land&#x2F;&quot;&gt;reddit&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=14114624&quot;&gt;hn&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-4XmtTGqxc82DyQwcpmr9pw.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;A wallpaper I created for my OpenBSD laptop. Lisp, BSD, Erlang, Rust. We live in the best of all possible worlds.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;You are quite in love with Python. Why is that?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Heh, love is a big word, isn’t it? But, yes, I guess for a while I had pretty strong feelings for Python. I still have, to a degree. If you’re going with the love metaphor let’s say I had a series of shitty girlfriends that didn’t treat me all that well and I didn’t even noticed it, then I meet this great woman, this caring and interesting woman that listens to what I have to say and doesn’t, um, force me to wrap everything in class.&lt;&#x2F;p&gt;
&lt;p&gt;Seriously speaking, I learnt to program in college, arguably at an old age, and there they taught me Pascal (because some folks are convinced that’s still the best way to teach good programming manners), then a fair amount of C++, and lots of Java. Everybody was in love with Java over there and they kind of gave you the impression that that was it: this is as good as programming gets, this is what will get you a job and it’s so much better than C++, which I already knew wasn’t pleasant to work with. So I got a job programming Java and I loved it, I read all the books, &lt;em&gt;Refactoring&lt;&#x2F;em&gt; and the Design Patterns stuff. But then I had to quit because I was getting behind in College, I got some free time back and I was curious about Python because some former coworkers and other students talked heavens about it.&lt;&#x2F;p&gt;
&lt;p&gt;I got this book &lt;em&gt;Learning Python&lt;&#x2F;em&gt; and went through it top to bottom one summer. I guess I felt scammed, in a way: how come nobody told me about this? I felt I had been wasting my time writing XMLs and type hierarchies, while there was a simpler way to do about everything: dynamic typing gave me polymorphism for free, the data structures were built-in and had literals, string manipulation was just amazingly easy, you could have standalone functions and pass them like values, a lot of the Java design patterns were reduced to one-liners… I guess one of the take-aways of the experience was that sometimes your peers know better than your teachers (or your bosses).&lt;&#x2F;p&gt;
&lt;p&gt;But besides it feeling better than Java, what’s still unique for me about Python is the set of principles that are best expressed in the &lt;em&gt;Zen of Python&lt;&#x2F;em&gt;. It felt like every bit of the language followed those principles and it encouraged you to do the same with your own code; when in doubt about how to tackle something, the Zen of Python would tell you the right way to go. I still follow most of those ideas when I program, regardless of the language.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Before learning Clojure, your&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;facundoolano.wordpress.com&#x2F;2012&#x2F;01&#x2F;31&#x2F;first-impressions-on-common-lisp&#x2F;&quot;&gt;&lt;strong&gt;first experience with a Lisp&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;was with Common Lisp. From what I have talked with you about learning Common Lisp I could sum up that it was a bittersweet experience. Why didn’t you like Common Lisp?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I got interested in Lisp after reading Paul Graham essays. Then there was that bit of Eric Raymond about the religious experience of &lt;em&gt;getting&lt;&#x2F;em&gt; Lisp. After what I went through with Java and Python I made a point about always looking for chances to learn new languages.&lt;&#x2F;p&gt;
&lt;p&gt;But it just didn’t feel right, in a lot of ways it was the opposite of what I loved about Python: the code was very difficult to read (not because parens or prefix notation, just because it was filled with symbols), the operator set was huge, with really weird names and not dynamic at all, I remember it having like six equality operators for different types. Add to that it’s an old language with a small community and zero chances of getting a job using it, it made no sense to invest much time in it, since it wasn’t fun either. But fortunately there are many Lisps and I already knew right then I’d give a chance to Clojure eventually.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why was the experience with&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;facundoolano.wordpress.com&#x2F;2016&#x2F;03&#x2F;20&#x2F;first-impressions-on-clojure&#x2F;&quot;&gt;&lt;strong&gt;Clojure different&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;? As&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;programming&#x2F;comments&#x2F;65ct5j&#x2F;a_pythonist_finds_a_new_home_at_clojure_land&#x2F;dg97mao&#x2F;&quot;&gt;&lt;strong&gt;stesch said in reddit&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;, Clojure land is in the Java sea. Those are strange waters for a pythonist. What did you like about it?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;For starters, it addresses everything that put me off about Common Lisp. It’s more readable. The operator set is big, but very consistent and polymorphic: all core functions work as expected with every data type. It has a strong focus on immutability and functional programming, which CL hadn’t. But it’s also a very pragmatic language: it doesn’t ask you to learn category theory or to know what a functor is in order to get why you would benefit from it. That’s the approach to functional programming that I like. I’m not saying theory isn’t important, just that I’m the kind of programmer whose interest you won’t catch with theory detached from practice. Also, the community is very active and welcoming, and the fact that it’s a JVM language makes it get a lot of attention, considering it’s a Lisp dialect.&lt;&#x2F;p&gt;
&lt;p&gt;Another thing that made me feel at home about Clojure is that it has a strong philosophy and you can tell its design has been driven by it. The philosophy is not the same as the one in Python, and now I understand that that doesn’t really matter. I want consistently opinionated languages rather than bags of features you can bend to program in ten different ways; &lt;em&gt;what&lt;&#x2F;em&gt; the philosophy is is secondary to the fact that &lt;em&gt;there is&lt;&#x2F;em&gt; a philosophy.&lt;&#x2F;p&gt;
&lt;p&gt;The talks by Rich Hickey are enlightening, and every time I watch one I feel like I improved my understanding of the language, even if the talk isn’t about Clojure itself. Kind of like a Zen of Clojure.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What do you think about the JVM and its community?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I’ve been working to suppress the strong feelings I used to have against Java. I still dislike it as a language and the way of programming it encourages, though. I revisited it a couple of years ago to write some Android apps and nope, still not my cup of tea. Everything just feels convoluted and over engineered, I’d constantly think how much simpler this is in Python or Perl or Ruby or JavaScript. It’s a very programmer-centric view, I’m aware, mostly based in what I enjoy in the day to day, which doesn’t necessarily make sense from a business perspective. There’s a reason why big companies go to Java; I recognize there’s a lot of top of the class software written in it, and it’s fast. I don’t have the background to make a serious assessment of the JVM but I’m pretty sure it’s an amazing piece of software.&lt;&#x2F;p&gt;
&lt;p&gt;The good thing is the JVM can now host other languages, and something as weird as a functional Lisp dialect is fairly close to being popular and you can even get a job with it. That’s a lot to say.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What do you miss from Python?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Sometimes I say, half-joking, that programming is a branch of literature. In that sense I value elegance and succinctness, I think there can be beauty in code, but I also know that beauty is completely subjective and I can’t argue about one style being better than another. I’m not talking about readability, that’s important and it’s more or less measureable; I’m talking about aesthetics. I think Python had that kind of beauty for me, which is harder to get in Clojure. Clojure can be more expressive and it’s more powerful but can easily get ugly if you don’t have a lot of discipline. Again: all subjective stuff.&lt;&#x2F;p&gt;
&lt;p&gt;Truth be told, I don’t think I miss Python all that much, at least not while I’m doing Clojure. JavaScript is a different story, JavaScript is a mess. But still, if you bend it in the right directions, it can be a fairly decent functional language. I noticed that Python can’t, there’s stuff that just doesn’t work that way (lambdas come to mind), and that probably would annoy me nowadays. So I guess I’m not married to any language anymore. That’s a good thing, right?&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Your most known projects in Github are written in JavaScript. Do you like coding in JavaScript?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;JavaScript is Frankenstein. As Douglas Crockford showed in &lt;em&gt;The Good Parts&lt;&#x2F;em&gt; years ago, there’s a lot of awful bits and you &lt;em&gt;have&lt;&#x2F;em&gt; to subset the language. That’s gotten worse, because they keep adding stuff to it (some of it really cool, some of it to make it look like Java), and they can’t remove the old stuff, so it has become one of those things you have to agree upfront on which parts you’re going to use and which parts are banned, kind of like C++.&lt;&#x2F;p&gt;
&lt;p&gt;But, as said, if you pick the right subset it can be good. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;eslint.org&#x2F;&quot;&gt;eslint&lt;&#x2F;a&gt; helps. If you ban &lt;em&gt;this&lt;&#x2F;em&gt; and &lt;em&gt;new&lt;&#x2F;em&gt; and treat objects like maps, most problems go away. If you’re bold you can even pick a set of eslint rules to force immutability. And then there’s &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;ramdajs.com&quot;&gt;Ramda&lt;&#x2F;a&gt;. That’s the secret sauce; it makes data manipulation a joy, in some spots I even like its functions better than their Clojure counterparts. The async stuff is weird. I still can’t make my mind if Promises are better than callbacks, but I got used to them. It’s a lousy way of hiding concurrency, though.&lt;&#x2F;p&gt;
&lt;p&gt;I have a fair amount of Node.js projects in GitHub, yes. That’s the killer thing about Node.js: NPM, its ecosystem, this philosophy of small unix-y modules. You have an idea, you write up a file and you’re two commands away from publishing it and getting feedback. No other language I’ve tried reduces the boilerplate to share your work that much. That’s a real boost for Open Source and Collaboration. I recognize it has some bad side effects (mixed module quality, left-pad, etc.), but those are much less than the advantages. I remember Python dependency and publishing story being way more cumbersome.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;In the last few months you started using Emacs. What do you think about it?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I’ve been putting off a blog post about that. I know I’m glad that I decided not to learn Emacs at the same time that I was learning Clojure. That could have caused me to drop both things. I think there’s this idea that you can’t learn a Lisp without Emacs, and that may have been true before, but now that there’s &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;shaunlebron.github.io&#x2F;parinfer&#x2F;&quot;&gt;parinfer&lt;&#x2F;a&gt; you can safely hack Lisp on most modern editors. Hardcore lispers may not notice how amazing of a contribution to the community this is, it makes it dramatically easier to get started with Lisp and reachable to people that wouldn’t even consider using something like Emacs.&lt;&#x2F;p&gt;
&lt;p&gt;I pleasantly used Clojure with Sublime and parinfer for almost a year. Then I started reading &lt;em&gt;Coders at work&lt;&#x2F;em&gt; and saw all these amazing hackers mentioning Emacs again and again. It felt like I was missing out on something, so I decided I should give it a try, as a weekend project.&lt;&#x2F;p&gt;
&lt;p&gt;And it was a hell of weekend. The first lesson I learned was that I was a shitty typist, but that got better as the days went by. Fortunately it was a quiet week at work because I could barely get anything done for a while. One interesting note is that I went through this process with JavaScript, so I could make Emacs my daily editor at work. It wasn’t until I felt comfortable with the editor that I tried it with Clojure. And then I realised my Clojure experience wasn’t complete before. It probably goes the other way around: you get the best out of Emacs when you’re doing Lisp.&lt;&#x2F;p&gt;
&lt;p&gt;I’m not sure I’d recommend it to every programmer, though, specially if they work on a single language that already has a killer editor. Learning Emacs is a really fun and enriching experience, but you have to be prepared to spend a lot of time tuning the editor at first and acknowledge the fact that &lt;em&gt;your Emacs config will be the project of your life&lt;&#x2F;em&gt; , as I read somewhere.&lt;&#x2F;p&gt;
&lt;p&gt;I know I love those times when you realise you are doing something repeatedly, that could be done by a command, and you write it (or, better, you find that someone else wrote it already). That’s when it pays off.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Is there any particular Clojure library that you would specially recommend?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jonase&#x2F;kibit&quot;&gt;kibit&lt;&#x2F;a&gt; I find amazing because it’s not only a useful linter (like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jonase&#x2F;eastwood&#x2F;&quot;&gt;eastwood&lt;&#x2F;a&gt; also is), but it teaches you the standard library as you go, which can be a little bit overwhelming when you are starting out. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bhauman&#x2F;lein-figwheel&quot;&gt;Figwheel&lt;&#x2F;a&gt; is another obvious one that made a big difference for me when I started to play with ClojureScript.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;macchiato-framework.github.io&#x2F;&quot;&gt;Macchiato framework&lt;&#x2F;a&gt; is doing a great job of bringing Node.js to ClojureScript.**** I noticed some people don’t take Node.js very seriously, but being Clojure a language that makes such a strong point of leveraging the host platform, the world of possibilities available in NPM can’t be disregarded. There’s another often overlooked fact: you’re much more likely to find a functional programming enthusiast nowadays doing Node.js than in the Java world, so shortening that gap can only bring good to the community.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;candid82&#x2F;joker&quot;&gt;Joker&lt;&#x2F;a&gt; is another great one. It’s a Clojure interpreter written in Go, but what I’ve found incredibly useful is how it works as a linter, which you can easily hook to an editor. It really improved my workflow, early catching typos and bugs while I program.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, in the testing related work I’ve been doing recently I’ve found &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jakemcc&#x2F;lein-test-refresh&quot;&gt;lein-test-refresh&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;weavejester&#x2F;eftest&quot;&gt;eftest&lt;&#x2F;a&gt; to be useful and insightful about how clojure.test and leiningen internals work.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;On your github profile you have many pretty well known open source projects. What motivates you to invest time in them?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I just love programming. I have lots of hobbies, but definitely programming is one of the things that I enjoy the most, what gives me the most pleasure. It’s like an itch: I get this idea or I encounter a need that isn’t addressed by an existing library or maybe I’m just playing to learn a new technology. I can’t help it but sitting down and building something, until is see something working on the screen and the itch goes away. I learned not to be lazy, polishing it a bit and uploading it to GitHub.&lt;&#x2F;p&gt;
&lt;p&gt;Open source is ideal, because you get to work on your own time, you do the stuff you’re interested in and drop the project whenever it bores you. I wish someone would pay me to do that. With a real job it’s harder: sometimes it gets boring, sometimes there’s nothing to do or you depend on someone else to move forward. Most often than not you can’t share your work.&lt;&#x2F;p&gt;
&lt;p&gt;And I always liked this process of conceiving a project, executing it and sharing it with others. Not just in software; the same goes for my fiction writing or when I recorded music as a teenager. When I was in high school I didn’t know how to program but I was obsessed with making games, I spent most of my afternoons fiddling with these game maker programs, RPG Maker and such, sharing my creations with friends. Unfortunately internet access was limited at home and they didn’t teach programming in my school, so it wasn’t until much later that I was able to do serious stuff on my own.&lt;&#x2F;p&gt;
&lt;p&gt;During college I did little projects and games but the languages I knew and skills I had weren’t enough to get me very far at the beginning. There was no GitHub, so it was harder to share and find interesting projects to work on. Later I had to juggle between a full-time job and finishing college. It wasn’t until these last couple of years that I got the freedom to work on whatever I want. And I know in a couple of years I’ll have kids and other stuff going on in my life, so I’m trying to enjoy this programming spring as much as I can.&lt;&#x2F;p&gt;
&lt;p&gt;And then there’s marketing factor. I’m not great at some types of job interviews and my resume may not tell you that much on its own, but I have a portfolio of open source projects that shows I’m a serious coder, a published Android game that proves I can take a personal project to production and a blog that tells you that I reason about my craft and I’m constantly trying to improve it. If you care enough to read it.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What are you working on lately?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I work on a Node.js shop, but the team is full of functional enthusiasts. We can’t convince our boss to let us write a production microservice in Clojure or Elixir, or a user interface in Elm. But the boss doesn’t care that much about our integration tests (as long as there &lt;em&gt;are&lt;&#x2F;em&gt; tests). So when someone complained for the zillionth time about how painful it is to write our API integration tests in JavaScript, I proposed migrating them to Clojure. To my surprise they agreed. So I hacked together this little library to easily do all that we were already doing in our Node.js API tests. And I liked how it turned out, so I’ve &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;facundoolano&#x2F;restpect&quot;&gt;published it in GitHub&lt;&#x2F;a&gt;. Nothing too fancy but it was a good excuse to escape from JavaScript, and it got three of my coworkers learning Clojure, which is great news.&lt;&#x2F;p&gt;
&lt;p&gt;Other than that, I keep slowly growing my &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;facundoolano&#x2F;advenjure&quot;&gt;advenjure engine&lt;&#x2F;a&gt;; just &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;facundoolano.github.io&#x2F;house-taken&quot;&gt;published a full game&lt;&#x2F;a&gt; with it, based on a story by Julio Cortázar. Also been doing some &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;cljsbin-bkhgroqzwe.now.sh&#x2F;&quot;&gt;experiments with Macchiato&lt;&#x2F;a&gt;, to write Clojure web apps that run on Node.js. I have this Machine Learning book I’m about to start, see where that takes me. Node.js microservices still pay my bills. For now, I guess. At some point I hope to be able to get paid for writing Clojure.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>MLFE: ML landing in the Erlang world</title>
          <pubDate>Tue, 15 Nov 2016 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/d-day-invasion-with-mlfe-ml-landing-in-the-erlang-world/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/d-day-invasion-with-mlfe-ml-landing-in-the-erlang-world/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/d-day-invasion-with-mlfe-ml-landing-in-the-erlang-world/">&lt;p&gt;Time has passed since our last interview for &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;notamonadtutorial.com&#x2F;&quot;&gt;This is not a Monad Tutorial&lt;&#x2F;a&gt;. OpenBSD released its 6.0 version after 20 years of continues releases without agile, OpenSSL vulnerabilities keep on breeding, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;blog.bugreplay.com&#x2F;post&#x2F;152579164219&#x2F;pornhubdodgesadblockersusingwebsockets&quot;&gt;Pornhub war against ad blockers continued&lt;&#x2F;a&gt;, the Macbook Pro is not that Pro anymore, a new javascript package manager was released by Facebook and last but not least Brexit and Trump are a reality that will shape the new world order.&lt;&#x2F;p&gt;
&lt;p&gt;Going back to our endogamic tech world, I interviewed &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;noisycode.com&#x2F;&quot;&gt;Jeremy Pierre&lt;&#x2F;a&gt; about &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;j14159&#x2F;mlfe&quot;&gt;MLFE&lt;&#x2F;a&gt; or ML Flavoured Erlang. After learning Haskell and after playing with Elm I became quite a fan of ADTs and Hindley-Milner type systems so that is why I am really exited by MLFE. So I think this is a way to counterbalance my love for Lisp languages. Let’s add a little bit of ML into our coffee. One of the projects I had in my To Do list was to implement an ML like language on top of the Erlang VM&#x2F;BEAM. Instead of recreating the wheel, I hope to see further by standing upon the shoulders of MLFE. The invasion has began!&lt;&#x2F;p&gt;
&lt;p&gt;If you have any more questions please let me know via &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;lobste.rs&#x2F;s&#x2F;vw8zb2&#x2F;d_day_invasion_with_mlfe_ml_landing_erlang&quot;&gt;lobsters&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;programming&#x2F;comments&#x2F;5d2ooi&#x2F;dday_invasion_with_mlfe_ml_landing_in_the_erlang&#x2F;&quot;&gt;reddit programming&lt;&#x2F;a&gt; or &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=12958099&quot;&gt;hn&lt;&#x2F;a&gt;. Au revoir.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-VHoeeRQqosE3Woi37aHFeA.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;2016 MLFE&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is MLFE?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;ML Flavoured Erlang is a statically typed and strict (eagerly evaluated) language for the Erlang VM patterned a little bit after parts of both OCaml and Elm. It’s incredibly early in the language’s development but we already have things like sum types and product types (e.g. tuples, records with row polymorphism) and a pretty basic foreign function interface to Erlang proper. Honestly the language is probably in need of renaming almost entirely because it’s impossible to call Erlang code directly outside of the FFI.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why did you create an ML language on top of the Erlang VM&#x2F;BEAM?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I appreciate a lot of the practicalities in the Erlang ecosystem, not least of which are the operational aspects of the VM but wanted something with faster feedback on type issues than Dialyzer currently provides, along with the brevity and expressiveness that come with features like OCaml or Elm’s ADTs. One of the earliest drivers for this was constantly wishing for Scala’s case classes every time I wrote Erlang (my day job involves both).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What are the main problems you find while coding in Erlang and while coding in ML like languages?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I don’t often work directly in ML dialects to be perfectly honest although I keep trying to find reasons to use them. Maybe that’s a subconscious reason behind starting MLFE .&lt;&#x2F;p&gt;
&lt;p&gt;As mentioned above however I do often work in Scala and its less pervasive approach to pattern matching and second class nature of things like actors on the JVM are often sore points for me. Having said that, it would be really great to have something like Scala’s Future or ScalaZ’s Task in an Erlang VM language as well. Maybe we can build something with MLFE to scratch that itch but it’s a little early to say I think.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;How did you implement the type inference algorithm?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I have to give credit (or apologize for implementing it badly?) to Oleg Kiselyov for his incredibly helpful article &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;okmij.org&#x2F;ftp&#x2F;ML&#x2F;generalization.html&quot;&gt;How OCaml type checker works&lt;&#x2F;a&gt;. I relied heavily on this, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.cis.upenn.edu&#x2F;~bcpierce&#x2F;tapl&#x2F;&quot;&gt;Types and Programming Languages&lt;&#x2F;a&gt;, and a bit on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tomprimozic&#x2F;type-systems&#x2F;tree&#x2F;master&#x2F;algorithm_w&quot;&gt;algorithm_w&lt;&#x2F;a&gt; for the earliest work on the typer.&lt;&#x2F;p&gt;
&lt;p&gt;It started with a very basic translation to Erlang of Oleg Kiselyov’s eager&#x2F;strict inferencer examples and then grew from there. Since the algorithm relies on unification (and hence mutation), MLFE’s inferencer needs reference cells which are currently implemented as Erlang processes. I’d like to move these to something like ETS but will probably wait until trying to rewrite and clean up the typer in MLFE itself.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Do you generate core Erlang code or Erlang code?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The MLFE AST is translated to a Core Erlang AST using the “cerl” module and then compiled to BEAM modules from there.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;How do you type check messages?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In MLFE a receive block types as a &lt;em&gt;receiver&lt;&#x2F;em&gt;. Receivers are polymorphic with two parameters: the kind of messages received and the result type of the contained expression. These two parameters are determined by unifying the types in the patterns and the types in the result portion of the receive’s clauses, e.g.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;receive with &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 0 -&amp;gt; :zero&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; | x, is_integer x -&amp;gt; :not_zero&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;All of the above patterns are clearly integers and all of the result portions are atoms so the type (internally) in MLFE would be &lt;code&gt;{t_receiver, t_int, t_atom}&lt;&#x2F;code&gt;. As an aside we can of course use union types if we want more complex messages.&lt;&#x2F;p&gt;
&lt;p&gt;Unifying receivers with enclosing expressions makes &lt;em&gt;those&lt;&#x2F;em&gt; expressions receivers too so if we’re assigning a variable in a let expression, the whole thing becomes a receiver e.g.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;let my_msg = receive with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 0 -&amp;gt; :zero&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; | x, is_integer x -&amp;gt; :not_zero &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;in [my_msg, :in_a_list, :why_not]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The above let expression is a &lt;em&gt;{t_receiver, t_int, {t_list, t_atom}}.&lt;&#x2F;em&gt; If we wrapped that in a function, the whole function is a receiver:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;foo () = let my_msg = receive with &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 0 -&amp;gt; :zero&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; | x, is_integer x -&amp;gt; :not_zero &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;in [my_msg, :in_a_list, :why_not]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The type of the above is:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{t_receiver, t_int, {t_arrow, [t_unit], {t_list, t_atom}}}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That is a function from unit to a list of atoms that internally receives integer messages.&lt;&#x2F;p&gt;
&lt;p&gt;Now when we spawn a process, &lt;em&gt;spawn&lt;&#x2F;em&gt; uses the receiver’s first parameter to constrain the resulting PID to a specific type. If we spawn a function that’s a receiver of integers (resulting in a &lt;em&gt;{t_pid, t_int}&lt;&#x2F;em&gt;), all messages sent must be able to unify with &lt;em&gt;t_int&lt;&#x2F;em&gt; so if we try to send it a float or a string we get a type error at compile time.&lt;&#x2F;p&gt;
&lt;p&gt;If we spawn a function that is &lt;em&gt;not&lt;&#x2F;em&gt; a receiver, we get a &lt;em&gt;{t_pid, undefined}&lt;&#x2F;em&gt;. Since &lt;em&gt;undefined&lt;&#x2F;em&gt; will not unify with any other type, it’s a type error to send that particular process any messages at all.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;One of the biggest issues I have with Erlang is that in some cases it is necessary to write code that has a lot of nested cases. Elixir added the&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;learningelixir.joekain.com&#x2F;learning-elixir-with&#x2F;&quot;&gt;&lt;strong&gt;with&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;special form to deal with this issue. Rust 1.3 added a new&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;blog.rust-lang.org&#x2F;2016&#x2F;11&#x2F;10&#x2F;Rust-1.13.html#the--operator&quot;&gt;&lt;strong&gt;? operator&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;that provides syntax sugar that helps to deal with this issue. The RabbitMQ team created&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.rabbitmq.com&#x2F;blog&#x2F;2011&#x2F;05&#x2F;17&#x2F;can-you-hear-the-drums-erlando&#x2F;&quot;&gt;&lt;strong&gt;Erlando&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;using Erlang’s parse transform (Erlang like macros) that adds syntax extensions to Erlang, with the&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rabbitmq&#x2F;erlando#user-content-lots-of-different-types-of-monads&quot;&gt;&lt;strong&gt;do syntax&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;for monads being the most important one to solve somehow this issue. From what I have seen the mlfe_type.erl of MLFE also&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;j14159&#x2F;mlfe&#x2F;blob&#x2F;master&#x2F;src&#x2F;mlfe_typer.erl#L403-L427&quot;&gt;&lt;strong&gt;has this issue&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Do you plan on adding some construct or syntactic sugar to deal with this type of issue?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This is certainly a common issue within MLFE’s typer itself. I don’t currently have plans to add any specific error handling sugar since I worry that doing so might push people away from OTP and supervision hierarchies. Having said that, I don’t think it’s at all unreasonable to have a simple error type and handling alternatives in a library. While try&#x2F;catch don’t exist yet in MLFE it could look like something as simple as the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;module simple_try&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;export try_f&#x2F;1, try_map&#x2F;2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;type t &amp;#39;result &amp;#39;error = Ok &amp;#39;result | Error &amp;#39;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-- try to run f, wrapping successes in Ok and failures in Error:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;try_f f = try&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Ok (f ())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;catch &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; err -&amp;gt; Error err&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-- If t is a success apply the function f to it or maintain a failed result:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;try_map t f = match t with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Ok result -&amp;gt; let runner () = f result in try_f runner&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; | Error e -&amp;gt; t&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I wouldn’t call the above ideal (and we need anonymous functions to make it usable to begin with) but I think it does demonstrate that it’s relatively easy to solve the problem in a few ways without needing first-class constructs.&lt;&#x2F;p&gt;
&lt;p&gt;To be clear, I think Rust’s approach makes a great deal of sense since as far as I’m aware, its Result type is core to the language. My reluctance with doing the same in MLFE is almost entirely due to the conventions and capabilities in place with OTP that I see as beneficial in their own right.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What was the most difficult thing about implementing MLFE?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Wrapping my head around type inference and unification was definitely the most challenging thing so far. I’m still working to understand a lot of the details and I’m barely ready to dig into something like the implementation of an ML module system, especially when it comes to functors. We need parametric modules in order to type bindings to a lot of OTP so there will probably be something pretty simple and restrictive to start but I have a lot of studying and learning to do before I can be even reasonably confident we’ll still have a type system that’s decidable.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Do you have any recommendation for those of us that did not implemented any language yet?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Pick a problem or feature you find interesting and dive in! Start with a simple definitional interpreter to play with things first if you don’t want to learn an existing platform’s AST (Reynolds’ paper is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;surface.syr.edu&#x2F;cgi&#x2F;viewcontent.cgi?article=1012&amp;amp;context=lcsmith_other&quot;&gt;great&lt;&#x2F;a&gt;) or just write an interpreter! If you wanted to target a particular runtime Core Erlang’s AST is generally pretty easy to get started with and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lfe&#x2F;&quot;&gt;LFE&lt;&#x2F;a&gt; is great to learn from. If you like the JVM then &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;graalvm&quot;&gt;Graal and Truffle&lt;&#x2F;a&gt; look really interesting too.&lt;&#x2F;p&gt;
&lt;p&gt;I haven’t yet taken the time to dig into SICP or &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;cs.brown.edu&#x2F;~sk&#x2F;Publications&#x2F;Books&#x2F;ProgLangs&#x2F;&quot;&gt;PLAI&lt;&#x2F;a&gt; (and I’ve heard Dr Krishnamurthi has been working on a new one) but want to at some point. I understand they’re both really good deep dives.&lt;&#x2F;p&gt;
&lt;p&gt;There are so many great ideas to check out and explore, recent work like Dr Jean Yang’s on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;projects.csail.mit.edu&#x2F;jeeves&#x2F;&quot;&gt;Jeeves&lt;&#x2F;a&gt; for security policy enforcement; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.cs.ubc.ca&#x2F;~rxg&#x2F;gtes.pdf&quot;&gt;gradual typing&lt;&#x2F;a&gt; — especially for effects — e.g. from Drs Banados Schwerter, Garcia, and Tanter; 1ML for a new approach to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;people.mpi-sws.org&#x2F;~rossberg&#x2F;1ml&#x2F;&quot;&gt;first class modules&lt;&#x2F;a&gt; from Dr Andreas Rossberg and so much more we’ve barely dug into (Dr Barbara Liskov’s decades of work!).&lt;&#x2F;p&gt;
&lt;p&gt;We have mountains of great ideas from so many people and are barely scratching the surface, it’s really exciting. I’d enthusiastically recommend anyone with any interest in programming languages to just pick a paper to read or an idea to research and just start following where it leads. Start reading groups!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What other languages do you recommend keeping an eye on?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Rust and Pony both look like they’re doing really interesting stuff and I’m curious as to where &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;purerl&quot;&gt;purerl&lt;&#x2F;a&gt; — an Erlang backend for PureScript — will go too. There seems to be a lot of cool stuff happening on the Scheme side of things that I keep worrying I’m missing out on.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Interview with Robert Virding, creator of Lisp Flavored Erlang, an alien technology masterpiece</title>
          <pubDate>Mon, 29 Feb 2016 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-robert-virding-creator-lisp-flavored-erlang-an-alien-technology-masterpiece/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-robert-virding-creator-lisp-flavored-erlang-an-alien-technology-masterpiece/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-robert-virding-creator-lisp-flavored-erlang-an-alien-technology-masterpiece/">&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-0_N8_5MqdROjW5duRb6Dpw.png&quot; alt=&quot;&quot; &#x2F;&gt;As you might know zombies, skeletons and momies are good friends of aliens&lt;&#x2F;p&gt;
&lt;p&gt;This time I interviewed &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;rvirding&quot;&gt;Robert Virding&lt;&#x2F;a&gt;, co-creator of Erlang and creator of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;lfe.io&#x2F;&quot;&gt;Lisp Flavored Erlang&lt;&#x2F;a&gt; (LFE). I am an Erlang developer and Lisp fan — if you are learning Clojure check out my post &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;this-is-not-a-monad-tutorial&#x2F;how-to-earn-your-clojure-white-belt-7e7db68a71e5#.dtmcog9gk&quot;&gt;How to earn your Clojure white belt&lt;&#x2F;a&gt; — so logically I am very excited about LFE.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;Why did you create LFE?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I discovered and learnt Lisp long before we started working with Erlang, and have always loved it. But I also like the Erlang language (I don’t have problems with the syntax :-)) and how it can build systems. My goal was to make a lisp which was a “real” lisp which builds systems in the Erlang way. Hence LFE.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is the LFE philosophy?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;LFE is a proper lisp based on the features and limitations of the Erlang VM, which coexists seamlessly with vanilla Erlang and OTP and runs on the standard Erlang VM.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;In your talk called&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=afLRmoSOnHA&quot;&gt;&lt;strong&gt;“About Language Design”&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;you said:&lt;br &#x2F;&gt;
&lt;em&gt;“&lt;&#x2F;em&gt; &lt;em&gt;People complain about the Erlang libraries and once thing they complain very rightly about the Elang libraries is they’re inconsistent, the naming conventions is inconsistent, the argument ordering is inconsistent, everything is inconsistent about them and that is correct. They are right and people complain about that.”&lt;&#x2F;em&gt;&lt;br &#x2F;&gt;
At some point, will you create a new standard library in LFE?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I would like to but there are some deep problems trying to do that. Basically you can’t really change any library module that is used by OTP without the effect propagating and going viral in OTP. Adding new libraries yes, modifying old modules not really. Elixir got around this by having their special module aliases which map onto module name ‘Elixir.XXX’ but then you end up with 2 module naming conventions. I preferred to keep the same names.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rvirding&#x2F;lfe&#x2F;blob&#x2F;dev-macro&#x2F;src&#x2F;cl.lfe&quot;&gt;&lt;strong&gt;Common Lisp macros and functions&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;have been added to&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rvirding&#x2F;lfe&#x2F;blob&#x2F;dev-macro&#x2F;src&#x2F;cl.lfe&quot;&gt;&lt;strong&gt;LFE&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;.&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lfex&#x2F;clj&#x2F;issues&#x2F;18&quot;&gt;&lt;strong&gt;Clojure macros and functions&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;are also available as a separate library. LFE follows more traditional LISPs like Common Lisp, Scheme or more modern Lisps like Clojure?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;LFE more has the feel of CL and Scheme, especially CL as it is a lisp-2 not a lisp-1 like Scheme. Clojure is definitely interesting but I felt that the way it does concurrency doesn’t really map well onto Erlang and the style of building systems feels different. Clojure feels more like language with concurrency while Erlang feels more like a operating system with a language.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rvirding&#x2F;flavors&quot;&gt;&lt;strong&gt;LFE Flavors&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;and the&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;oubiwann&#x2F;los&quot;&gt;&lt;strong&gt;LFE Object System&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;? Aren’t they pretty similar?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Flavors is an object system on the Lisp Machine. I did LFE Flavors out of pure fun and curiosity. A long time ago (about 30 yrs) I did an implementation of Flavors for another lisp system, Portable Standard Lisp, and I was curious to see what it would be like to do one for LFE. It worked quite well for the central parts but there is a lot of Lisp machine specifics which can’t be transferred. CLOS is based on Flavors and you can see the heritage.&lt;&#x2F;p&gt;
&lt;p&gt;My plan with LFE Flavors is not to bake it in as part of LFE but have it as a supported compatible plugin. I like to keep the core simple. I also have plans to implements more general structs which will allow more control over data structures and access to them. It would subsume records and elixir structs amongst other things.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;A few months ago you&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;groups.google.com&#x2F;d&#x2F;topic&#x2F;lisp-flavoured-erlang&#x2F;l_Te7ZHkm9M&#x2F;discussion&quot;&gt;&lt;strong&gt;sent an email&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;titled “New macro handling and compiled macros”. How does the macro system work in LFE, what are you changing and why?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Currently macros work by defining them locally in each file where they are used. If you need to share macros then you define them in include files. The new macro handling will allow macros to be exported from modules in much the same way as functions and you would call them in the same way. So for a module foo you call functions with (foo:function …) and macros with (foo:macro …) making the interface much more consistent generic. Most uses of include files will disappear.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What do you think about Elixir?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Ambivalent! I don’t speak Ruby at all, so much of the syntax feels very strange and foreign. It also manages to push some of my programming buttons, for example having multiple ways of representing the same thing and adding syntax for special cases; both which I feel are just wrong. I am jealous of their ability to clean up some of the OTP modules by writing their own interfaces and having a way to avoid overlapping module names. I wonder about some of the complexity but that is just because I have a thing about simplicity.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Have you incorporated any idea from it into LFE?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I have not taken any ideas directly from Elixir though we do share some features, for example having multiple modules in one file (which I am not sure I like but it can be practical).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;I have seen&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;blog.lfe.io&#x2F;design&#x2F;2015&#x2F;07&#x2F;11&#x2F;1720-towards-multi-methods-in-lfe&#x2F;&quot;&gt;&lt;strong&gt;multimethods&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;and&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lfex&#x2F;los&#x2F;issues&#x2F;8&quot;&gt;&lt;strong&gt;protocols&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;mentioned a few times by the LFE community. What do you think about Clojure multimethods and protocols?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;One difficulty doing something like this in Erlang is that Erlang modules must be compiled as one unit, it is impossible to add, or remove, functions afterwards without recompiling the whole module. This makes it very difficult to have methods which are to be in one module in different places. Which lessens the usefulness of multimethods. IMAO.&lt;&#x2F;p&gt;
&lt;p&gt;Flavors gets around this by compiling each component flavor separately and building a object flavor from all its mixin when the first instance is created. This allows us to create the components separately as long as all are done before their first time they are used. After that they cannot be modified.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Do you think adding something like&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;26317325&#x2F;can-someone-explain-clojure-transducers-to-me-in-simple-terms&quot;&gt;&lt;strong&gt;transducers&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;to LFE would be a good idea?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;They probably would be, but they are not really the way I think. I find I tend to be very explicit in which data types I use; for me this is as fundamental as choosing which algorithm to use. This means that having polymorphic transformation functions becomes less interesting for me.&lt;&#x2F;p&gt;
&lt;p&gt;I know that many people prefer working in this way and I see no problems in adding them to the set of standard LFE libraries. They just won’t be integrated into LFE at the lowest level. You will be able to choose.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;I have seen some discussions about Dialyzer in LFE’s mailing list and there is a dialyzer branch in the&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rvirding&#x2F;lfe&#x2F;tree&#x2F;dev-dialyzer&quot;&gt;&lt;strong&gt;LFE repository&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;. How well does LFE support&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;erlang.org&#x2F;doc&#x2F;man&#x2F;dialyzer.html&quot;&gt;&lt;strong&gt;Dialyzer&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Supporting dialyzer is a little tricky as the official interface to dialyzer is very restricted: you either pass in erlang files, or you pass in beam files containing the Erlang AST of the code (compiling with the debug_info option). This does not work with LFE as the LFE compiler generates Core erlang, a language used internally in the compiler.&lt;&#x2F;p&gt;
&lt;p&gt;However, by being a bit cunning I have generated some alternate dialyzer interface modules which can load in the Core erlang forms directly. It works but it is really only an experiment; a better solution would be to do a proper fix of the dialyzer interface but this is not that simple as the current interface is not very cleanly coded. It is actually quite ironic as dialyzer uses Core erlang internally.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What do you think about&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.sbcl.org&#x2F;manual&#x2F;#Handling-of-Types&quot;&gt;&lt;strong&gt;Steel Bank Common Lisp Type system&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;,&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.racket-lang.org&#x2F;ts-guide&#x2F;index.html&quot;&gt;&lt;strong&gt;Typed Racket&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;or&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;clojure&#x2F;core.typed&quot;&gt;&lt;strong&gt;Clojure’s core.typed&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;and&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.shenlanguage.org&#x2F;learn-shen&#x2F;types&#x2F;types.html&quot;&gt;&lt;strong&gt;Shen Types&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I have never tried these so I can’t say. Generally I am very dynamically typed. :-)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is the roadmap for LFE v1.0?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;So far the roadmap has been a little “I just want to add this one last feature and then I’ll release 1.0”. Anyway, my plan now is that when the new macro handling works and is properly integrated then the system will feel well rounded and I will release 1.0.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h4 id=&quot;did-you-like-it-follow-me-on-twitter-unbalancedparen&quot;&gt;Did you like it? F&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;unbalancedparen&quot;&gt;ollow me on Twitter — @unbalancedparen&lt;&#x2F;a&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Oh and I recommend that you read this email from Robert about LFE titled &lt;em&gt;“A bit of philosophy and some design principles”&lt;&#x2F;em&gt; :&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;There was a bit of discussion on the IRC about the CL module and where LFE gets its impulses from, that it doesn’t try to stand on its feet. There are things in it from scheme and CL but most of it is based on Erlang and the features it provides and the type of systems you build using it.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The base of LFE rests directly on what the underlying Erlang VM provides and this determines what LFE can do and how it works. It is based on language features like modules, pattern matching, immutable data and how functions work. This is what defines LFE. I don’t think that LFE tries as hard as Elixir to hide this background.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;This, for example, is why LFE is a lisp-2 not a lisp-1 as it is a better fit for how Erlang handles functions. On top of this there is a set of convenience macros which were originally more scheme inspired but became more CL inspired when LFE became a lisp-2. They are just a better fit. Of course this doesn’t make LFE a scheme or a CL as there are many things in both scheme and CL which LFE can’t do because of the underlying Erlang VM like mutable data and the handling of nil&#x2F;() and symbols with values, plists and function bindings [*].&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;An alternative would have been more inspired by clojure which shares some properties with Erlang. However they are fundamentally different in many ways so it would mainly have been using clojure’s naming conventions. Also clojure’s concurrency model is very different from Erlang&#x2F;LFE so its way of building systems is also very different. You get the feeling, at least I do, that it is based on a central thread of execution where we you can run things in parallel, but there is this central thread. This is very un-Erlangy as Erlang&#x2F;LFE systems typically don’t have a central thread.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;This gets us, finally, to the CL module. It is just a library containing many of the standard CL library functions which gives you the possibility of writing in a CL style. Not everything can be included, for example the nXXXX functions which mutate data, and some features don’t mesh well with Erlang&#x2F;LFE. For example equating nil&#x2F;() and predicates which in Erlang&#x2F;LFE return true&#x2F;false while in CL are truthy and return nil&#x2F;() and anything else [**]. It is in no way a fundamental part of LFE and is just an add-on. If anyone feels inclined to do a similar module for clojure then I will definitely consider including it. Again it would just be an add-on. These could easily be included in the base release.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Packages like flavors, which I did because they are interesting and I think fun, should probably not be part of the base. This wou|d also apply to things like LFE CLOS (if anyone decided to do it) and LFE clojure-like protocols. They are interesting and useful in themselves but not things I would consider part of the LFE base. A set of these should probably kept in a standard place to make them easily accessible for everyone. I would like to keep the base relatively simple, clean and “basic”, a “lean, mean, fighting machine” if you will. It is all too easy to add things, even sensible and useful things, and end up with a bloated mess. I really want to avoid this, hence keeping the base simple and clean.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
</description>
      </item>
      <item>
          <title>Interview with Jay Kreps about Apache Kafka</title>
          <pubDate>Mon, 22 Feb 2016 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-jay-kreps-about-apache-kafka/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-jay-kreps-about-apache-kafka/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-jay-kreps-about-apache-kafka/">&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-lRRJqrarJFi5TPtnBm_8hA.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This time we interviewed &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;jaykreps&quot;&gt;Jay Kreps&lt;&#x2F;a&gt;, one of the creators of Apache Kafka. Kafka is an open source messaging system with a few design choices that make it particulary useful for high throughput and low latency scenarios.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;“This experience lead me to focus on building Kafka to combine what we had seen in messaging systems with the log concept popular in databases and distributed system internals. We wanted something to act as a central pipeline first for all activity data, and eventually for many other uses, including data deployment out of Hadoop, monitoring data, etc.” — Jay Kreps&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Kafka is built around the concept of a distributed database commit log. If you have no idea what that is, then I highly recommend that after you finish reading the interview you check the links I have pasted at the end. I learnt a lot by reading them.&lt;&#x2F;p&gt;
&lt;p&gt;In the following weeks I am going to publish an interview with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;martinkl&quot;&gt;Martin Kleppmann&lt;&#x2F;a&gt;, one of the authors of Samza, about his book Data Intensive Applications and realtime stream processing systems vs batch processing systems.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;What problem does Kafka solve?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Kafka is a distributed storage system for data streams. It allows you to publish streams of data and subscribe to them. It is built around the concept of a persistent log that is appended to — publishers of data append to this log and consumers subscribe to changes. Perhaps most importantly, it scales really well so it can function as a central hub for these data streams even in a company with a lot of data like LinkedIn or Netflix or Uber.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why RabbitMQ, ActiveMQ and other similar open source projects where not useful to solve this problem?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;There are a few things that are different about Kafka:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;It is built from the ground up as a modern distributed system. It handles replication, fault-tolerance, and partitioning. You think about Kafka as a cluster, not a collection of individual brokers. This impacts everything from how you manage it to how programs behave.&lt;&#x2F;li&gt;
&lt;li&gt;Kafka does a good job of persistence. Data in Kafka is always persisted and can be re-read.&lt;&#x2F;li&gt;
&lt;li&gt;Kafka is faster than traditional messaging system and hence more suitable to really large volume data streams such as would come from logging use cases, or massive streams of sensor data.&lt;&#x2F;li&gt;
&lt;li&gt;Kafka was designed to support distributed stream processing as a layer on top of its core primitives. This is why Kafka is so commonly used with things like Spark Streaming or Storm.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;strong&gt;In what type of structure do you persist messages and in which format?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;A message or record in Kafka is just a key-value pair, where the key and value are some string of bytes.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;0-4N-FW2mHbx6AsraV.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Kafka provides the abstraction of a “topic” which is split into one or more partitions (usually many) and spread over a cluster of nodes. A topic is a kind of feed of records. Applications publish records into a topic, and the record’s key determines the partition within that topic that the record goes to. Each partition is replicated on multiple machines for fault-tolerance.&lt;&#x2F;p&gt;
&lt;p&gt;The core abstraction Kafka provides (as well as the data structure it uses in its implementation) is a write ahead log. This log is just an ordered sequence of the records written to the cluster that is persisted to disk. Each record is assigned a sequential number called an offset. This offset acts as a position in the log.&lt;&#x2F;p&gt;
&lt;p&gt;An application consuming that partition can be thought of as having a position in the log designated by that offset, which means it has consumed all the records earlier and none of the records after. The application controls that position and can continue to read forward or go back in time to re-read.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;How does Kafka manage to handle easily many dozens of thousand of messages per seconds if it persists them to disk instead of keeping them in memory?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Careful design! Our observation was that there was no fundamental reason that the log abstraction we wanted couldn’t be as fast as the underlying filesystem at linear writes, which means anything from hundreds of MB&#x2F;sec on spinning disks to GBs&#x2F;sec on SSDs. To make this happen Kafka does a good job of batching together lots of small writes into big linear appends to files. This batching happens both in the consumer, in the replication protocol, in the consumer, and in the operating system itself.&lt;&#x2F;p&gt;
&lt;p&gt;I do think the domain of infrastructure engineering is different in this way. Application developers are warned against the dangers of premature optimization, but for infrastructure I think you need to start thinking about performance in the design phase. The reason it is so different is that the fundamental constraints are well known ahead of time and usually system designs are not very flexible, so if you ignore performance initially it is generally very hard to get it back later by optimizing within your existing design.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What guarantees does Kafka provides? In which cases can messages be lost?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Kafka guarantees that writes are replicated across N instances in the same order (where N is a replication factor you choose) and that your write won’t be lost as long as at least one of these instance remains alive.&lt;&#x2F;p&gt;
&lt;p&gt;In combination with the way consumers control their own offset this translates to an “at-least-once” delivery.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;In&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;9RMOc0SwRro&quot;&gt;&lt;strong&gt;this talk&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;you mentioned Kafka streams. Could you briefly explain what is it and why it will be useful?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Kafka Streams is a stream processing layer for Kafka we’ve been working on. It’s a little different from the existing stream processing frameworks that are out there — more focused on building streaming applications and less a kind of real-time version of MapReduce.&lt;&#x2F;p&gt;
&lt;p&gt;We’ll be doing a preview release in early March (we’re really excited).&lt;&#x2F;p&gt;
&lt;p&gt;Combined with the work we did on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.confluent.io&#x2F;blog&#x2F;announcing-kafka-connect-building-large-scale-low-latency-data-pipelines&quot;&gt;Kafka Connect&lt;&#x2F;a&gt;, we think this makes Kafka a really compelling &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.confluent.io&#x2F;blog&#x2F;stream-data-platform-1&#x2F;&quot;&gt;platform for streaming data&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What needs to be done before releasing Kafka 1.0?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We’ll get there. We thought we needed to at least get a stable version of Connect and Streams done as they are a pretty essential part of the platform.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why did you choose Java to implement Kafka? Did you ever consider using another programming language?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We had a lot of experience with the JVM and knew it was possible to build reliable and fast infrastructure on top of it — and it was more convenient to work with than C or C++.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;I work as an Erlang developer and I was thrilled by your comments about concurrency and languages in&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;blog.empathybox.com&#x2F;post&#x2F;90318905473&#x2F;concurrency-is-not-a-language-thing-anymore&quot;&gt;&lt;strong&gt;“Concurrency is not a language thing anymore”&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;:&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
&lt;em&gt;“In the near-real-time processing domain stream processing frameworks do a good job of providing asynchronous processing without directly thinking about concurrency at all. Again you interact with concurrency and parallelism only at the framework level, the code you write appears completely single-threaded.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;The offline world seems to be moving in the direction of a handful of YARN frameworks for different specialized purposes. What almost all of these share is that they don’t require users to directly manage concurrency.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;This leads me to think that putting more time into language support for single-server concurrency (software transactional memory and all that) is of limited utility. It will only help the implementors of these frameworks, not the end user.”&lt;&#x2F;em&gt;&lt;br &#x2F;&gt;
&lt;strong&gt;Apart from Erlang, some languages like Go and Clojure added a good concurrency model and semantics from the start. Don’t you think there is any area where having good concurrency baked into the language is useful for the normal developer and not only for the implementor of frameworks?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The critique I was trying to make is sort of analogous to the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;End-to-end_principle&quot;&gt;end-to-end principle&lt;&#x2F;a&gt; for network protocols, basically you end up needing to solve the concurrency problem at a higher level anyway which makes the lower-level primitive the languages provide redundant. What I see is each language is trying to provide built-in primitives for multi-core programming. Other than Erlang I think most of these ignore the problem of distributed computing. But what has changed is that modern programming is always done in some framework that introduces a concurrency model at a higher level. Examples of these frameworks would be the whole Apple and Android stacks, numerous microservice frameworks, and things like Spark or Kafka Streams. These higher level frameworks are able to do a better job because they can make assumptions about the environment that just aren’t possible at the language level. So, for example, many of them are able to introduce a model that simultaneously solves for spreading computation over CPU cores on one machine as well as over multiple machines.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why does Kafka depends on Zookeeper? What job does Zookeeper do for Kafka?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.confluent.io&#x2F;blog&#x2F;distributed-consensus-reloaded-apache-zookeeper-and-replication-in-kafka&quot;&gt;This article&lt;&#x2F;a&gt; gives an overview of its role in Kafka’s replication design.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Do you have any recommendation for those of us who want to start learning about distributed systems? Was there any books, papers or codebase that really helped you implement and design Kafka?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I think a great place to start is Martin Kleppman’s book &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;shop.oreilly.com&#x2F;product&#x2F;0636920032175.do?cmp=af-strata-books-videos-product_cj_9781491903094_%25zp&quot;&gt;Designing Data Intensive Applications&lt;&#x2F;a&gt;. I have only read parts of it, but from what I’ve seen it is the best accessible introduction to distributed systems out there. Unfortunately only 9 of 12 chapters are available so we should all bug him to finish it!&lt;&#x2F;p&gt;
&lt;p&gt;A good textbook you &lt;em&gt;can&lt;&#x2F;em&gt; buy today is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.amazon.com&#x2F;Introduction-Reliable-Secure-Distributed-Programming&#x2F;dp&#x2F;3642152597&quot;&gt;Introduction to Reliable and Secure Distributed Programming&lt;&#x2F;a&gt;. This book isn’t great for learning but it is an order of magnitude better than other text books which are utterly terrible. Unfortunately distributed systems research had several decades in which it wasn’t really very practical and hence it developed a culture that seems to pride itself on it’s lack of connection to mainstream practice. For example, that book, manages to spend on the order of a hundred pages introducing different possible communication primitives and talking about their properties without bothering to connect any of these to the actual mainstream network protocols like UDP and TCP which seems pretty silly to me.&lt;&#x2F;p&gt;
&lt;p&gt;The best thing is that these days there are hundreds of open source distributed systems available and you can learn quite a lot about the design and implementation of these.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;As I mentioned in the introduction to the interview, I highly recomend that you read the following three links about Kafka, its design and uses:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;engineering.linkedin.com&#x2F;distributed-systems&#x2F;log-what-every-software-engineer-should-know-about-real-time-datas-unifying&quot;&gt;The Log: What every software engineer should know about real-time data’s unifying abstractionI joined LinkedIn about six years ago at a particularly interesting time. We were just beginning to run up against the…engineering.linkedin.com&lt;img src=&quot;&#x2F;images&#x2F;fit&#x2F;c&#x2F;160&#x2F;160&#x2F;0-EKXwv5gzf95qmyw9.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.confluent.io&#x2F;blog&#x2F;stream-data-platform-1&#x2F;&quot;&gt;Putting Apache Kafka To Use: A Practical Guide to Building a Stream Data Platform (Part 1)These days you hear a lot about “stream processing”, “event data”, and “real-time”, often related to technologies like…www.confluent.io&lt;img src=&quot;&#x2F;images&#x2F;fit&#x2F;c&#x2F;160&#x2F;160&#x2F;0-wDG3xKC21IQ4qaC7.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.confluent.io&#x2F;blog&#x2F;stream-data-platform-2&#x2F;&quot;&gt;Putting Apache Kafka To Use: A Practical Guide to Building a Stream Data Platform (Part 2)This is the second part of our guide on streaming data and Apache Kafka. In part one I talked about the uses for real…www.confluent.io&lt;img src=&quot;&#x2F;images&#x2F;fit&#x2F;c&#x2F;160&#x2F;160&#x2F;0-D5SxPsgpumFDy5py.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;kafka.apache.org&#x2F;documentation.html#design&quot;&gt;Apache KafkaKafka is a distributed, partitioned, replicated commit log service. It provides the functionality of a messaging system…kafka.apache.org&lt;img src=&quot;&#x2F;images&#x2F;fit&#x2F;c&#x2F;160&#x2F;160&#x2F;0-5a9GIkEZZHsR80Z0.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Jay also gave a few excellent talks about Kafka that explain why it was created and what are its uses:&lt;&#x2F;p&gt;
&lt;h4 id=&quot;&quot;&gt;&lt;&#x2F;h4&gt;
</description>
      </item>
      <item>
          <title>Interview with Jesper Louis Andersen about Erlang, Haskell, OCaml, Go, Idris, the JVM, software and…</title>
          <pubDate>Tue, 29 Dec 2015 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-jesper-louis-andersen-about-erlang-haskell-ocaml-go-idris-the-jvm-software-and-60901251608c356716f2f92e/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-jesper-louis-andersen-about-erlang-haskell-ocaml-go-idris-the-jvm-software-and-60901251608c356716f2f92e/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-jesper-louis-andersen-about-erlang-haskell-ocaml-go-idris-the-jvm-software-and-60901251608c356716f2f92e/">&lt;h3 id=&quot;interview-with-jesper-louis-andersen-about-erlang-haskell-ocaml-go-idris-the-jvm-software-and-protocol-design-part-ii&quot;&gt;Interview with Jesper Louis Andersen about Erlang, Haskell, OCaml, Go, Idris, the JVM, software and protocol design — PART II&lt;&#x2F;h3&gt;
&lt;p&gt;This is part II of the interview with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;jlouis666&quot;&gt;Jesper Louis Andersen&lt;&#x2F;a&gt;. You can read &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;this-is-not-a-monad-tutorial&#x2F;interview-with-jesper-louis-andersen-about-erlang-haskell-ocaml-go-idris-the-jvm-software-and-b0de06440fbd#.4gidstolk&quot;&gt;part I here.&lt;&#x2F;a&gt; This part of the interview is mostly about Erlang, one of my favorite languages. If you want to learn Erlang, take a look at &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;spawnedshelter.com&#x2F;&quot;&gt;Spawned Shelter&lt;&#x2F;a&gt;, a website I made for Erlang newcomers.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-DCzEYU60hk2pO7WCJj3GoQ.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What are the advantages of the Erlang VM over the JVM and vice versa?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;From a perspective of history, the choice of building the BEAM VM for Erlang was the correct one. Massive concurrency was less on the radar for many people, and Ericsson needed a platform which they controlled. Furthermore, the BEAM can exploit it is executing functional languages only: the GC needs no generation forward set for instance.&lt;&#x2F;p&gt;
&lt;p&gt;The roll-your-own-design decision has proven to be very valuable, even though compared to the JVM, the OTP team is far smaller. My guess is that for every hour sunk into BEAM, there is at least 15–20 hours of work in the JVM. In turn, there are things which you cannot do efficiently on the BEAM. It is still (2015) bytecode interpreted and has no JIT, which means raw execution of computationally intensive tasks is about 10–20 times slower than typical well-written Java. Projects such as Quasar&#x2F;Pulsar and Akka promises Erlang-style concurrency on the JVM, but they are recently developed whereas the BEAM has been in production for many years.&lt;&#x2F;p&gt;
&lt;p&gt;The key differing design criteria comes from the design space originating in Bjarne Däcker’s thesis. Most notably the soft real-time constraints and the need for seamless hardware interaction, but also the need for running very large software systems in which feature interaction is complex. It turns out in such a world that the major problems are rarely raw execution speed, but rather how parts of the system operate as a coherent whole. Many of the problems in the design space requires a different approach than sheer execution brute force, especially in a multicore world. Had fast execution been important, it would have been addressed a long time ago. But it turns out every major release of BEAM provides a far more important set of new features. There is a lot of power in having a large industrial company backing the system, as the new features tend to be operational&#x2F;industrial in nature.&lt;&#x2F;p&gt;
&lt;p&gt;The key difference in implementation is that the BEAM is built from the ground up as a resource sharing system, much like in an operating system. In an OS, two processes A and B are isolated and gets a fair share of the resources. If B is badly written, this has considerably less impact on A. Suppose for instance B has bad GC productivity and allocates a lot. Then the GC of B has to run far more often and B has to pay: either in lower throughput, or worse latency. At the same time, A will keep on running, without B having any bad impact on its operation. The BEAM isolates resources in such a way that a B application cannot directly impact an A application from a resource standpoint.&lt;&#x2F;p&gt;
&lt;p&gt;The contrast are systems where one large shared heap is used. They hedge both A and B on the same GC heap, hoping it is fast enough to power through. But clearly, a badly written B can affect a well written A far more. It matters in very-large-scale development since you cannot hope every part of the system is perfectly written.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;If the Erlang VM uses asynchronous I&#x2F;O&lt;&#x2F;strong&gt; &lt;strong&gt;how does it do to present a normal api to the developer? Why aren’t callbacks needed like in Node.js?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Node.js uses a cooperative scheduling algorithm as seen in old operating systems such as MacOS 9, Windows 95 running legacy 16-bit code, MS-DOS and so on. The method, in which the program explicitly yields the CPU for the next task, has a number of advantages: it is easy to adapt existing languages and systems to the method. It is highly efficient in throughput. And it allows you to “pack” lots of work into a single process.&lt;&#x2F;p&gt;
&lt;p&gt;The weakness of the cooperative model is its fragility in server settings. If one of the tasks in the task queue monopolizes the CPU, hangs or blocks, then the impact is worse throughput, higher latency, or a deadlocked server. The fragility has to be avoided in large-scale systems, so the Erlang runtime is built preemptively. The normal code is “instrumented” such that any call which may block automatically puts that process to sleep, and switches in the next one on the CPU. Furthermore, Erlang being functional, any process must loop by calling functions. An internal funcall counter measures “reductions” and once 2000 of these has been used, the process is forced off the CPU and the next one is switched in. The process is entirely automatic and follows the modern idea of time-sharing in operating systems: AmigaOS, UNIX, Windows NT+, and so on.&lt;&#x2F;p&gt;
&lt;p&gt;Note that in Erlang there is &lt;em&gt;no way&lt;&#x2F;em&gt; to call blocking operations at all, since they are all handled by the runtime. This means the model is coherent and I can use any library I like without fear of it doing something bad. As an example, BEAM uses its own PCRE Regex library which cooperatively yields expensive NFA traversals. It also breaks up expensive crypto-computations, long-running GCs, and costly term serializations. It even includes a blocking monitor built-in so you can get notified if a monopolization has happened. Calls to foreign code written in C is harder though, since you have to take its blocking behavior into account.&lt;&#x2F;p&gt;
&lt;p&gt;You can get much of the same in any other language by using an appropriate framework. However, this breeds fragmentation: library code in one framework is not usable in another framework without adaptation. And code written for no framework has to be inspected for eventual blocking behavior. In turn, code is colored in different colors, and you can’t mix them.&lt;&#x2F;p&gt;
&lt;p&gt;A far better approach is seen in Quasar&#x2F;Pulsar: take existing bytecode and rewrite it by instrumentation, much like in Erlang. You can insert forced preemptions into loops, and protect any potentially blocking call by a lightweight fiber switch. If you add your own I&#x2F;O manager underneath, you almost have a full implementation of the Erlang model. But it takes a serious amount of work to get the lower parts to run fast in this model, since you have to reimplement all of the Erlang VM inside Java.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;In practical term what do you gain from using a VM like the Erlang VM that has a preemptive scheduler?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Preemption is an exchange in which you sacrifice explicit control for gains in productivity. First, you don’t have to adapt existing code to your model, which saves time. In languages without proper abstraction barriers, calling the wrong function at the wrong time can block a scheduler. Second, in a post-DevOps world where you run your own systems, productivity is directly tied to the maintenance overhead of existing systems. The lower fragility of the model means you have more time to actually write new code rather than fix old problems. You can afford to let bad behavior live for longer in the system since its impact simply gracefully degrades the system a bit.&lt;&#x2F;p&gt;
&lt;p&gt;Most importantly however, you don’t have to worry about every nook and cranny of the code. Rarely run code can be written slightly less performance-oriented since its cost is automatically amortized over the whole of the program by the scheduler. And even in the critical paths, the smearing operation of the scheduler helps a lot to alleviate spikes. Long running background jobs can simply be started without much worry.&lt;&#x2F;p&gt;
&lt;p&gt;Another gain is had from the observation “N starts out small and then grows” which is to say that over time, a piece of software gets to handle gradually more and more data. Without a preemptive scheduler, this growth very often ends up having a considerable latency or throughput impact. Erlang systems errs on the side of maintaining good low-latency for slightly worse throughput in these situations. As load increases on a system, this is often the desirable behavior as it is less likely to affect other systems directly. The system simply degrades gracefully rather than abruptly.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;You wrote:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;In Haskell, Type Classes are often the abstraction way to go. In ML, the key is to use modules.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Don’t you miss type classes or ML modules in Erlang?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I do miss them a lot, but they both rely on efficient type worlds in order to function. Adding them to an untyped language like Erlang is going to be rather hard. A far more reasonable way to go at Erlang programs is to look inside the Elixir and Clojure communities. Clojure’s “procotols” would be a good addition I think, and it fits the Erlang design space far more. Another good place for inspiration is Scheme48’s implementation of modules, which took inspiration from Standard ML’s functors among other things. Scheme48 being a R5RS (&lt;em&gt;Revised^5 Report on the Algorithmic Language Scheme&lt;&#x2F;em&gt;) implementation also shares lots of its design space with Erlang.&lt;&#x2F;p&gt;
&lt;p&gt;It is often said a Haskell type class construction can be implemented with an ML module. The correspondence to Erlang would be to use a process. Processes forces code to modularize and isolate, since the communication can only be done through exchange of messages. Granted, it happens at runtime, but used correctly it yields emergent behaviors in the source code: the same module is executed by many isolated processes at runtime, and their interaction defines the behavior of the program. The literature on swarm intelligence provide more information in this area.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Is it possible to implement a rich static type system and also have message passing at the same time?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Yes it is! Most such systems introduces some kind of “box” which can be typed as in a “box containing type X”. The box is often a single-message mailbox, or a channel. The type system doesn’t even need to be rich for this to work out, as Go shows. It works because the box threads a type with it, so when you put things into the box or extract things from the box, you can statically reason about the type of the extracted&#x2F;inserted value.&lt;&#x2F;p&gt;
&lt;p&gt;Haskell has several highly interesting communication models which enjoy rich typing. There is also John Reppy’s ConcurrentML, which takes communication a step further: not only are channels first class values which can be manipulated, &lt;em&gt;events&lt;&#x2F;em&gt; are first class. CML has an algebra for manipulating events, and combining them. Once you call &lt;em&gt;sync&lt;&#x2F;em&gt; on the event, then the scenario plays out. It is akin being able to have &lt;em&gt;receive&lt;&#x2F;em&gt; -clauses as values which you can join: &lt;em&gt;sync join(Recv1, Recv2)&lt;&#x2F;em&gt;. The most mind-altering operation in Reppy’s calculus is the &lt;em&gt;withNack&lt;&#x2F;em&gt; which is an event firing if &lt;em&gt;another&lt;&#x2F;em&gt; event is picked. It is often used for cancellation situations.&lt;&#x2F;p&gt;
&lt;p&gt;Most of these models assume a non-distributed setting though. They assume that communication cannot fail, and that code cannot be upgraded as it is running. CMLs event resolution in a distributed setting is likely to run into the CAP theorem for instance. Most type systems assume total static knowledge&#x2F;control, something you rarely have in a distributed system. Hence you have to verify interactions between distributed agents, which somewhat defeats the holistic aspect of static typing.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What do you think about monads in erlang? Are they useful? Have you tried out&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rabbitmq&#x2F;erlando&quot;&gt;&lt;strong&gt;erlando&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I do use a monad construction in Erlang from time to time, when the code is going to flow better with a monad, but I rarely use tools such as erlando when doing so. The packages assumes a monad is a module whereas I often use a record for my monad work. To me, monads have always been a tool best used in special cases, and to understand formal logics. Personally, I much prefer the hybrid approaches of OCaml and Erlang, where the languages are imperative rather than the approach of Haskell and purity above all. The latter “forces” monads upon you in ways I don’t always appreciate.&lt;&#x2F;p&gt;
&lt;p&gt;The monad story in Erlang is somewhat weaker than I would like it to be. In Haskell, it is nice because the compiler can use the types to implicitly infer what monad is to be used and then use that monad. A lot of the power comes from the ability to interweave the monadic bind into your code. A Haskell weakness is when you have monad transformer stacks where your code has to change whenever you reorder to stack, but perhaps the work on Free’er monads by Kiselyov can amend this weakness. I feel the productivity is slightly less so in e.g., OCaml (4.02), which needs explicit reference to the monad in order to use it. In Erlang, simple monads are easy to comprehend. But once you raise a complex system out of abstraction, you really need a proper type system to guide you, which you don’t get in Erlang. In turn, Erlang code tends to be less abstraction heavy.&lt;&#x2F;p&gt;
&lt;p&gt;I don’t necessarily think it is a bad idea to have code which uses relatively few abstractions. My own code style, even in OCaml and Haskell, tend to rely on simple principles rather than high levels of abstraction. If you introduce many abstractions, you are also introducing the need for readers to have that knowledge. It is possible to go overboard here, and end up with code which only a few people in the world can read and understand. It might be very efficient and very elegant, but you won’t get many programmers looking at the code. Hence, I tend to use a couple of abstractions when they really help the code, but I refrain from using them in most other situations, preferring to rewrite code through simpler means.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What do you think about Idris Erlang?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Sam Elliot wrote a thesis on this subject[0], and I take that it is this work you are asking about. Among the contributions is a proof-of-concept Erlang-backend for Idris. It allows you to take Idris modules and compile them as Erlang modules. A proper backend would definitely need more work, and it should target Erlang’s Core rather than concatenating strings together to form an Erlang program. Yet, one has to remember what the goals of a thesis are, which is to say it is not about producing production quality backends for languages. But the thesis also explores another path which was perhaps a bit overlooked: how do we type message communication?&lt;&#x2F;p&gt;
&lt;p&gt;Looking at the Erlang message model, and squinting your eyes a lot, you get what is essentially IP&#x2F;UDP communication of messages, of arbitrary size. If you know a Process ID, you know it’s “IP” and you have a capability to send that PID a message. You also have the property that message loss might occur but it is very unlikely unless something is going seriously wrong. Since the risk of failure is low, you can usually handle it by restarting from a known good state, rather than implementing complex recovery schemes.&lt;&#x2F;p&gt;
&lt;p&gt;This model is extremely flexible and you can build almost any kind of messaging on top of it. But on the other hand, generality weakens the meta-theoretic properties of any protocol: we can’t say anything about the well-formedness of messages.&lt;&#x2F;p&gt;
&lt;p&gt;What Elliot points out in his thesis is the notion of constraining our communication to certain limited patterns. By giving up the general messaging, we can suddenly define a typed world in which we understand what is going on. In turn, we can prove well-typed patterns enjoy desirable properties. With enough work, we may be able to capture essentially all the healthy patterns of communication, while rejecting the bad ones. If this could lead to removal of subtle concurrency&#x2F;distribution mistakes, we have come a long way.&lt;&#x2F;p&gt;
&lt;p&gt;Another thesis I have to mention in passing is Simon Fowlers on monitoring communication patterns in Erlang&#x2F;OTP[1]. Fowler explores the idea of monitoring messaging at runtime through an altered &lt;em&gt;gen_server&lt;&#x2F;em&gt; construct. One of his major observations is that many Erlang message patterns are not captured by a typical two-party session type, let alone a multi-party session type. In particular multi-party session types doesn’t allow for the dynamic introduction of new members nor for the termination of members while the session is ongoing. Fowler proposes several interesting solutions and paths in his thesis on how to adapt the system to handle these problems.&lt;&#x2F;p&gt;
&lt;p&gt;All in all, these observations seem to suggest we need some more research work in the area to understand the full interplay between a language such a Idris, and a highly concurrent ecosystem such as the Erlang BEAM VM. It would seem Erlang is a more generic fabric on top of which we could &lt;em&gt;patch in&lt;&#x2F;em&gt; restrictions which improves the quality of our systems through automatic fault removal. In any case, typing concurrent&#x2F;distributed programming in a very general communication model such as Erlang seems to be very hard.&lt;&#x2F;p&gt;
&lt;p&gt;We also need to explore messaging patterns in Erlang which are typeable in some type system. Usually such patterns have additional desirable structure embedded in them because the type system enforces rigidity. By researching in this area, one may hope to improve the understanding of why certain patterns are used, or not.&lt;&#x2F;p&gt;
&lt;p&gt;[0] &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;lenary.co.uk&#x2F;publications&#x2F;dissertation&#x2F;&quot;&gt;http:&#x2F;&#x2F;lenary.co.uk&#x2F;publications&#x2F;dissertation&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;[1] &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;simonjf.com&#x2F;writing&#x2F;msc-thesis.pdf&quot;&gt;http:&#x2F;&#x2F;simonjf.com&#x2F;writing&#x2F;msc-thesis.pdf&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Since it is very common to use a pool of gen servers in Erlang: Wouldn’t it be a good idea for Erlang&#x2F;OTP to have a default gen_pool implementation?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Erlangs tenet is “provide tools, not solutions”. That is, provide the tooling for building a pool, but don’t provide a pool. The reason has to do with the fact pools are not alike. Over the last 10 years I’ve come across perhaps 5 different pool implementations and the key observation is they are all &lt;em&gt;valid&lt;&#x2F;em&gt; such implementations. How to hand out resources from the pool differ: some do round-robin proxying. Some queue requests and hand them out in FIFO order. Some uses LIFO order. Some are distributed Job-Idle Queue implementations, whereas some can only run on a single machine. Some provide automatic health checks and reconnections. Some block the caller when there is no work, others errors, and some queues the caller for a while, before erroring.&lt;&#x2F;p&gt;
&lt;p&gt;The other observation is how such pools handle failure, reclaim stale resources, handle errors in the pool implementation itself etc. Again, it is not clear what &lt;em&gt;the&lt;&#x2F;em&gt; implementation should be, and what would be the correct operation. It is mostly a function of context in which the pool is used.&lt;&#x2F;p&gt;
&lt;p&gt;My experience is that this problem space requires either chaos monkeys, concuerror or QuickCheck+PULSE to remove faults, and it is hard to get entirely right. But such tools require a specification of “correct operation”, and there are several such specifications.&lt;&#x2F;p&gt;
&lt;p&gt;Had Erlang&#x2F;OTP provided a default gen_pool implementation, then people would use it even if it doesn’t fit their problem space. This tend to create subtle hard-to-find faults.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Interview with Jesper Louis Andersen about Erlang, Haskell, OCaml, Go, Idris, the JVM, software and…</title>
          <pubDate>Mon, 28 Dec 2015 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-jesper-louis-andersen-about-erlang-haskell-ocaml-go-idris-the-jvm-software-and/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-jesper-louis-andersen-about-erlang-haskell-ocaml-go-idris-the-jvm-software-and/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-jesper-louis-andersen-about-erlang-haskell-ocaml-go-idris-the-jvm-software-and/">&lt;h3 id=&quot;interview-with-jesper-louis-andersen-about-erlang-haskell-ocaml-go-idris-the-jvm-software-and-protocol-design-part-i&quot;&gt;Interview with Jesper Louis Andersen about Erlang, Haskell, OCaml, Go, Idris, the JVM, software and protocol design — PART I&lt;&#x2F;h3&gt;
&lt;p&gt;In this occasion we interviewed Jesper Louis Andersen, a type theorist with lot of practical knowledge and experience. His &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;@jlouis666&quot;&gt;blog&lt;&#x2F;a&gt; (you should also check his old &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;jlouisramblings.blogspot.com&#x2F;&quot;&gt;blog&lt;&#x2F;a&gt;, you will find a lot of good things over there) and code (specially things like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jlouis&#x2F;safetyvalve&quot;&gt;safetyvalve&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jlouis&#x2F;fuse&quot;&gt;fuse&lt;&#x2F;a&gt;) have been a big inspiration to me. That is why I published the interview in two parts: I had too many questions for him. I hope you enjoy reading his answers as much as I did.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-mIrYVuSZtaYe3WJkRwUqwQ.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I published part II of the interview. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;this-is-not-a-monad-tutorial&#x2F;interview-with-jesper-louis-andersen-about-erlang-haskell-ocaml-go-idris-the-jvm-software-and-5628fe591295&quot;&gt;Check it out!&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;Your reply to the picture that is below was:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The typical applications I write in Erlang have 3–4 functions above it in the call stack&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Modern comfortable programming language #java:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;0-Ee-kDajNT561ZgOd.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why is it so? Why this is not the case in most OOP languages?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It is not really an artifact of OOP-style languages as much as it is an artifact of how we develop software. In biology, it has been observed solutions are usually not rewriting code, but rather patching code. Imagine a world where we are more inclined to build on top of what we already have rather than go down and rewrite older parts. I think each new generation of programmers tend to add a layer on top of what we already have, mostly to put their mark on programming and to simplify and abstract the parts of the lower levels which are in common use while also hiding the rare parts. What you get is the deep call stack. Another similar view would be in geology where you can see older layers and go back in time to older periods. Much of the Java stack has this in it.&lt;&#x2F;p&gt;
&lt;p&gt;Erlang is no different, but from the outset, small-community languages are less susceptible to patching. Especially if it is easy to rewrite code, which means an itch can be scratched by writing something new, rather than building on top of what others did. What brings the call stack down to 3–4 frames, however, are processes. In an Erlang-system a typical web request is served by cooperation of 3–4 processes, each of those having a call stack. Add them all together, and you approach the above size, but in isolation, they are small. An eventual error will result in a crash report with 3 things in it: the backtrace, the state &lt;em&gt;before&lt;&#x2F;em&gt; the process crashed and the incoming message which made it crash. The reason we have the original state is because of functional programming: every data structure is persistent, so we can version it. Usually this is enough to quickly isolate and figure out where the error is and what went wrong.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;You tweeted:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Lets talk agile: The ultimate agile language is one in which you can deliver working code quickly, which is also maintainable. Hence there are only a few agile languages in existence: Haskell, Ocaml and Erlang are 3. Go, Javascript, Python and the rest lacks the necessary abstractions to be regarded as agile. You end up having to recode. However, the &lt;strong&gt;real&lt;&#x2F;strong&gt; solution is to stop doing agile. The idea is bullshit in the first place.”&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why Haskell, OCaml and Erlang are the only agile languages?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If the waterfall model risks not building the right product, then agile risks not building the product right. I’m very fond of Erlang creator Mike Williams point: “If you don’t make experiments before starting a project, then your whole project will be an experiment”. My hunch is what a lot of Agile process misses is that you need to experiment before you build.&lt;&#x2F;p&gt;
&lt;p&gt;If we instead ask about prototyping, then we need a programming language with certain traits. The team is usually small, so we need an expressive language, and we need to address the core kernel of the system in isolation, first. We don’t need a lot of interfacing to foreign systems and in general we won’t care too much if the system we build is fast. Also, we usually won’t need to operate the prototype in production, since it is simply a proof of concept.&lt;&#x2F;p&gt;
&lt;p&gt;From a perspective of rapid prototyping and proof-of-concept development, functional languages tend to have an edge over imperative ones. Their higher level and expressivity allows more to be said succinctly, in fewer lines of code. They also tend to describe data structures and algorithms in ways that are clearer, which helps understanding of the problem space.&lt;&#x2F;p&gt;
&lt;p&gt;In turn, since agile values the minimum viable product, moving fast and making experiments, then you need languages in which it is easy to experiment with the unknown ideas many agile projects face. In languages such as Haskell, Erlang and OCaml you can often iterate over far more designs in a limited time window. Thus you can carry out more experiments and this often leads to a better product, even if the final product is not even written in a functional language. In general I feel we value experimentation too little. Build it, throw it away, and rewrite with the new knowledge.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What do you think about Clojure?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Sadly, my experience with Clojure is limited to carrying out a set of Koans in the language, and I have not ever used it for anything serious work. I must admit I don’t find the language especially compelling, and in general I don’t find Lisp-dialects interesting. My language roots are closer to Standard ML, which may be the reason it did not catch my interest when I finally tried toying with Scheme and Common Lisp.&lt;&#x2F;p&gt;
&lt;p&gt;That said, people are doing lots of outright &lt;em&gt;amazing&lt;&#x2F;em&gt; stuff in Clojure. I think the Datomic project is genuinely interesting as a database system. And the work Kyle Kingsbury has done with his “Jepsen” framework and his “Knossos” linearizability checker in Clojure is solid work. I’m also following David Nolen’s work with interest. But I’m pretty sure the language isn’t “for me”.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;You tweeted:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Functional programming semantics are far more important than static typing for removing errors from programs.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why? Could you elaborate?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I’ve somewhat alluded to this before, but never in more than 140 characters. In an imperative program a function depends on two things: the parameters it is passed and also the current state of the machine store. In a functional language, only the former matters. The consequence of this choice if far reaching:&lt;&#x2F;p&gt;
&lt;p&gt;One, the state space we have to reason about as human beings is far smaller for FP, which makes it harder to make a programming mistake. Two, we can test functions in isolation and be rather confident we have covered the functions execution well. Three, data processing is inductive in nature, recursing over the &lt;em&gt;structure&lt;&#x2F;em&gt; of data rather than manipulating the store from afar. The programming is closer to a proof by induction, which force the programmer to handle corner cases rigorously.&lt;&#x2F;p&gt;
&lt;p&gt;The ease of reasoning also comes into play once you have found a bug. It is often easier to figure out what the program is doing wrong just by taking a close look. It is rare you need to attach a debugger, which you can’t in a concurrent and&#x2F;or distributed system where some parts are outside of your direct control.&lt;&#x2F;p&gt;
&lt;p&gt;When you add typing to the above, you obtain another dimension where your system is (automatically) checked for additional rigor. But I often find people forget how much power there is to be had just by functional programming on its own, with no regard to types. From my own experience, functional programs tend to have an order of magnitude fewer errors than imperative counterpart programs, especially when these are subtle corner-case errors, types or not. Naturally, types + functional programming help even more. But had I the choice between imperative programming with types or functional without, I know what I’d pick without hesitation.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is your opinion regarding dependent types like the one Idris has?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I have not studied Idris very much yet, but I did some work in Agda and Coq, which both employs dependent types, albeit the type theory is subtly different between all of them. I’ve deliberately been pushing it ahead of me for a while, like I also have done with Rust. Mostly because I’d like them to settle down and mature a bit more before I start looking into them. I’d probably start looking around 2017 on both. From a research perspective, Idris is extremely important. We need to explore this area more for real world programs as well, and having a language designed for programs rather than proof-assistance is fairly important. Of course, one would like to see a more mature language, but one has to understand how much is being sunk into Idris to make this happen currently.&lt;&#x2F;p&gt;
&lt;p&gt;I’m not yet entirely convinced we necessarily want to add dependent types to mainstream languages in its full form. Perhaps it turns out we’d rather want a simpler type system in some areas in order to extend it along other dimensions. I’m somewhat interested in the Curry-Howard correspondence between distributed programming and epistemic logic for instance. And it is not a priori clear we even understand what it means to marry dependent types to such a beast. We may have to cut the cake differently in order to understand the type-level interactions.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Don’t you think that OCaml and Go compete for the same space? What has been your experience with the two languages and how do you think they compare?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If you squint your eyes hard enough, OCaml is an imperative language on top of which you added a lambda calculus. Or it is a lambda calculus with primitive operations for imperative execution. Either way, Go and OCaml are very much alike in the core: both are garbage collected, and natively compiled languages. They tend to provide execution speed in the same ballpark: usually they are in the same order of magnitude when it comes to executing programs.&lt;&#x2F;p&gt;
&lt;p&gt;What sets the two languages apart is the underlying ideology of how to design a programming language. Go is a modest cleanup of the C semantics on top of which you add channels, goroutines and interfaces. OCaml is a programming language in the tradition of Milners Meta-Language (ML), drawing inspiration from several sources including Haskell and Standard ML, among others.&lt;&#x2F;p&gt;
&lt;p&gt;Go usually opts for simplicity and separation of features into a small basis. The language is specifically addressing concerns when programming in the large. This yields programs which are highly coherent because the programmer have relatively few abstraction tools at their disposal. In addition, the interface concept in Go is implicit, which means you have less need to alter other parts of the system. In a large setting with 100s of programmers, altering code someone else “owns” is usually measured in days, whereas local alterations takes hours. So the time lost on lower abstraction can be deceiving.&lt;&#x2F;p&gt;
&lt;p&gt;The simple coherent design of Go also fosters fast compilation with little to no abstraction overhead. It doesn’t matter what abstractions you use, your program will usually compile fast and it will be pretty obvious what the performance behavior of the program is. Fast compilation speed matters in large settings because waiting on the compiler is often wasted time[*]&lt;&#x2F;p&gt;
&lt;p&gt;Russ Cox noted that some abstractions, generics for instance, makes a trade-off between putting the onus on the programmer, the compiler or the execution speed. Leave out generics and the programmer has to work around it. Add generics, and the compiler has to do more work in the compilation phase. Or abstract away generics by a boxing construction, which affects execution speed. Go opts for the first of these.&lt;&#x2F;p&gt;
&lt;p&gt;OCaml contrasts heavily. From an abstraction perspective, it leaves Go in the dust, and supports so much more efficient use of the programmers time. The compiler is also relatively fast and it handles the added abstraction well, though at the current time there is an overhead to the abstraction use. In the notion of Cox, the current version of OCaml (4.02) sacrifices execution speed in some cases. The new FLambda IR in OCaml 4.03, shifts this onus around and puts more into the compiler[0].&lt;&#x2F;p&gt;
&lt;p&gt;Another important dividing factor is the current lack of a proper Multicore support in OCaml, which also means the lack of a proper concurrency runtime built-in by default. In OCaml, you have to rely on a system such as LWT or Async to achieve the same as goroutines do in Go. And the fact there is two, means everyone has to support both for their libraries. The situation is far from perfect.&lt;&#x2F;p&gt;
&lt;p&gt;I usually grab OCaml for problems which have certain traits. Symbolic manipulation is one thing at which OCaml excels because it has proper algebraic datatypes. Thus, I would never write a compiler or proof assistant in something else. Programs generating programs is another area in which OCaml excels. Finally, problems which have embarrassingly parallel structure can easily be handled by just spawning more OS processes in OCaml, and the cogen of OCaml is quite efficient.&lt;&#x2F;p&gt;
&lt;p&gt;I usually write Go for simple brute-force programs where the interactions are not very complex and there is a simple channel network inside the program. I avoid it for anything with complex interactions, because the simplicity of the language often gets in the way. But some problems have the virtue of being simple by construction, which makes Go a really good language.&lt;&#x2F;p&gt;
&lt;p&gt;Personally, I prefer the OCaml ideology. Add abstractions to the language, build a powerful module system, with functors, in which you can program in the large by β-reducing modules into one another. And use the compiler and computer as a sacrifice to pay for this additional abstraction. Those programs are easier to maintain, and easier to recombine.&lt;&#x2F;p&gt;
&lt;p&gt;Go and OCaml are best used for the programs where there is a part of the program which is heavily CPU-bound and you are not memory bound. The vast majority of the programs I write have little to no need to run on a tight CPU-schedule and there I usually just write them in Erlang. If you are bound by memory, you often end up in situations where the gain of dropping to OCaml or Go is small. And if you are bound by outside interaction, disk or network, there is almost no gain.&lt;&#x2F;p&gt;
&lt;p&gt;[*] Fast compilation and linking speed are two major reasons I like Erlang too.&lt;&#x2F;p&gt;
&lt;p&gt;[0] A worthwhile aside: The MLton Standard ML compiler takes this to an extreme by compiling &lt;em&gt;all&lt;&#x2F;em&gt; of the program in one fell swoop. Thus, it is able to perform whole-program analysis and optimization with perfect knowledge of the program. This makes a lot of the abstractions free, but the price is long compilation times.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;In a great post where you explained the drawbacks of JSON and REST HTTP APIS you also wrote:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;“We need to go back to our roots and start building protocols again. This change will never come from a large company. It has to rely on an open tinkerer culture. We need well-defined protocols and multiple implementations of these. Protocol design is quickly becoming a lost art. Rather, people are satiated with “APIs” to the point where they can’t recover.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;We need de-centralization. The internet is built on the idea of end-to-end interaction between machines. The current state is more of a client&#x2F;server infrastructure in which few central entities drive the status quo.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;We need distribution. If we rely on big players, we tie ourselves to their solutions. This will be a bane going forward as we build infrastructure around vendors only interesting in lock-in.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;And finally, we need education. A lot of the current “protocol design” is so bad compared to what can be found in old RFCs. If you want to implement something new, you need to study the past a lot before you build it. If you reject an old idea, you need to explain why. If you reinvent an old idea, you need to know you reinvented it and what happened historically for that idea not to catch on.”&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Could you give us some recommendations of RFC, books, articles to read and exercises to do learn how to design protocols?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Good protocol design is an art form. The goal is produce protocols which are simple to implement, are hard to implement wrong and have future extensibility. Take the TCP protocol for instance. You can implement it in hardware as a simple stop-and-go protocol, ignoring everything about sliding windows. This is a correct and valid implementation of the protocol, though it will be slow. Once that works, you can add layers on top which makes the protocol faster. In addition to the RFCs for TCP, James E. White’s RFCs, 707 and 708, are dear to my heart. They were written in 1976, and they handle a lot of problems we still have to this day: how will distributed machines communicate.&lt;&#x2F;p&gt;
&lt;p&gt;The BitTorrent protocol deserves mention as well. It defines how clients communicate, but it gives relatively few rules about how a client is supposed to implement their behavior. Once you set forth and start implementing the protocol however, you find there is only one true way of doing each part. So that could be left out of the specification. Instead, a minimal viable protocol is given, and the details can be altered as you go along. But also note how the original BT protocol used a Bit-array of 64 bits in the handshake rendezvous in order to negotiate what additional features were supported. This was later replaced with a fully extensible system because it proved to be inadequate. Whenever you see such patches of the protocol design, think about how it could have been avoided in the first place.&lt;&#x2F;p&gt;
&lt;p&gt;Another incredibly well-designed protocol is the 9p protocol from Plan9. And it is generic enough it can be adapted to a lot of other situations as well. It implements many good ideas, like out-of-order messaging, proper multiplexing of messages on one channel, requests initiated from both ends of the connection, and so on.&lt;&#x2F;p&gt;
&lt;p&gt;The general advice is to cut out any part which nominates how the peer should behave itself internally. You need to maximize the freedom of the implementer and only establish the basis for communication. Cut cut cut. Leave out everything which will not destroy the coherency and internal consistency of the protocol. Layer the protocol and push things into separate layers. A layered protocol is much easier to reason about formally, and you better be doing so though either Model Checking or quickchecking the protocol internals.&lt;&#x2F;p&gt;
&lt;p&gt;One should read the critiques of HTTP&#x2F;2.0 and how we got there from HTTP&#x2F;1.1. The protocol suffers from some rushed work, sadly. Read some of the simpler alternative approaches. As an example the PUSH message from Server to Client in HTTP&#x2F;2.0 grows out of White’s observation in RFC707: both peers in a protocol needs to be able to initiate communication. But HTTP is skewed, like most RPC, since all communication is initiated from the client toward the server.&lt;&#x2F;p&gt;
&lt;p&gt;A good approach is that of Roy T. Fielding — define what constraints you need, and then squeeze hard until the minimal protocol comes out. That is, start by defining a large framing of what you need your protocol to do and then create a protocol with those properties. TCP is defined by its constraints of being a stream protocol, connection oriented and without data loss. ZeroMQ is a message channel, connection oriented, without data loss. UDP are message oriented, datagram oriented, with loss. SCTP is …, and so on.&lt;&#x2F;p&gt;
&lt;p&gt;Protocols are far better than APIs because they invite multiple competing implementations of the same thing. They debug themselves over time by virtue of non-interaction between peers. And they open up the design space, rather than closing it down. In a distributed world, we should not be slaves to API designs by large mega-corporations, but be masters of the protocols.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Efene: an Erlang VM language that embraces the Zen of Python</title>
          <pubDate>Fri, 27 Nov 2015 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/efene-an-erlang-vm-language-that-embraces-the-python-zen/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/efene-an-erlang-vm-language-that-embraces-the-python-zen/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/efene-an-erlang-vm-language-that-embraces-the-python-zen/">&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-Y6aaUiw3qoh372nY7WNzJg.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In this ocasion we interviewed &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;marianoguerra&quot;&gt;Mariano Guerra&lt;&#x2F;a&gt;, creator of Efene. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;efene.org&#x2F;&quot;&gt;Efene&lt;&#x2F;a&gt; is &lt;em&gt;“an alternative syntax for the Erlang Programming Language focusing on simplicity, consistency, ease of use and programmer UX”.&lt;&#x2F;em&gt; After reading the interview with Mariano Guerra, check &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;efene.org&#x2F;quick-efene-introduction-busy-programmer.html&quot;&gt;Efene Quick Introduction for the Busy&#x2F;Lazy Programmer&lt;&#x2F;a&gt; for learning more about Efene.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why did you create efene?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I learn by doing, and a while ago I wanted to learn Erlang, it was the first functional programming language I wanted to learn coming from C, C++, ASM, Java and Python so I was looking for some toy project to learn it.&lt;&#x2F;p&gt;
&lt;p&gt;For a while I couldn’t find a project that was interesting to me and also matched the strengths of Erlang at some point I decided that I would do a small calculator in Erlang, you can see the first commit &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;marianoguerra&#x2F;match&#x2F;commit&#x2F;cc048638b4cc99719ad5c28cea2f9e8163b9661c&quot;&gt;here&lt;&#x2F;a&gt; and the full project &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;marianoguerra&#x2F;match&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;At first I was doing all the eval stuff myself but pretty quickly I added support to compile the expression to an Erlang &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;marianoguerra&#x2F;match&#x2F;commit&#x2F;6c726f641e5d651f6bb46b2ae04202e557ea022b&quot;&gt;module with a function&lt;&#x2F;a&gt;. The next commit added function support and then I realized there was a programming language there, you can read the rest of the commits to see how it morphed into one.&lt;&#x2F;p&gt;
&lt;p&gt;At that point the only other beam language other than Erlang was &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;reia-lang.org&#x2F;&quot;&gt;Reia&lt;&#x2F;a&gt;. I wasn’t planning anything in particular with my powerful calculator&#x2F;language hybrid, but at some point people from Erlang Factory asked me if I wanted to give a talk about my language and of course I said yes, then I got a dose of impostor syndrome, so I started the project from scratch to do a proper programming language and I decided to support every feature that Erlang supports and not much more. At that point the project changed from a toy to an actual programming language.&lt;&#x2F;p&gt;
&lt;p&gt;After &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.erlang-factory.com&#x2F;conference&#x2F;London2010&#x2F;speakers&#x2F;MarianoGuerra&quot;&gt;my talk&lt;&#x2F;a&gt; and some initial excitement things got quiet. I just had got my Engineers degree and had a new job so development stopped for a while, then Elixir appeared and got much more attention, so I thought “OK, someone got it right, I will just stop pushing efene” and some years passed. But then looking into Elixir I saw that the Elixir ideas weren’t exactly the ideas of efene and I decided to rewrite it to try to fill the niche of “just a different syntax for Erlang, reuse as much as possible from the Erlang ecosystem, unified tooling and documentation as the core of the project”. The language has been complete for a while now. I’m just working on documentation, rebar3 plugins andwaiting for some of the surrounding tools to mature to avoid having to redo the documentation (mainly &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rebar&#x2F;rebar3&quot;&gt;rebar3&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=YGuAXS0Cy_8&quot;&gt;cowboy 2&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why do you embrace the&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.python.org&#x2F;dev&#x2F;peps&#x2F;pep-0020&#x2F;&quot;&gt;&lt;strong&gt;Zen of Python&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-6_ijRzr0oB6Zckr8GTrq4A.png&quot; alt=&quot;&quot; &#x2F;&gt; Zen of Python&lt;&#x2F;p&gt;
&lt;p&gt;Python was the first language I enjoyed coding in before I coded in C, C++, ASM and Java, but just because it was what I knew or they provided something I needed. With Python it was the first time I said “I’m a Python programmer” and not “I’m a programmer”, also the Python Argentina community helped a lot witht hat.&lt;&#x2F;p&gt;
&lt;p&gt;Python has this attitude of simplicity and community that I like and instead of coming up with an “ad hoc, informally-specified, bug-ridden, slow implementation of half of the python zen” I decided just to copy it.&lt;&#x2F;p&gt;
&lt;p&gt;David Nolen summarized it well the other day:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;swannodette&#x2F;status&#x2F;667694050426945536&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;That’s why efene is a mixture of what I like about the languages, communities and philosophies of Python, Javascript and Erlang, don’t expect a lot of novelty in efene, just a remix of what’s there :).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Could you show to us a short and good example of an efene program?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I can’t think of a particularly short snippet of code that will show you all the interesting bits of efene, mainly because there are no clever parts to efene, the idea is to be regular, simple, explicit and readable.&lt;&#x2F;p&gt;
&lt;p&gt;This means it doesn’t try to win a codegolf competition, or some clever language trick.&lt;&#x2F;p&gt;
&lt;p&gt;But I think you can take a look at this project which is a client for an API that supports REST, Web Sockets, Server Sent Events and COMET and then starts some clients that send some pseudo-random stuff to test the server:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;marianoguerra&#x2F;ioriofn&#x2F;&quot;&gt;marianoguerra&#x2F;ioriofnioriofn - ioriodb client and tests in efenegithub.com&lt;img src=&quot;https:&#x2F;&#x2F;cdn-images-1.medium.com&#x2F;fit&#x2F;c&#x2F;160&#x2F;160&#x2F;0*zv67McG0GOVsOXyh.&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If your reaction is “I understand this and this is boring”, then I would be happy :), of course knowing some Erlang will help the understanding since efene semantics and patterns are the same as Erlang’s.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Which are the biggest advantages of coding in a language that runs on top of the Erlang VM (BEAM)?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The semantics of the VM are really thought out and really simple to learn.&lt;&#x2F;p&gt;
&lt;p&gt;The stability and scalability of the platform is great and there’s a lot of people that have worked on really hard problems for a long time on top of the Erlang VM, this means you can get really good advice and help from them.&lt;&#x2F;p&gt;
&lt;p&gt;One thing I really like and I don’t think is mentioned that much is the level of runtime introspection and visibility the VM has, and the tooling that is build and can be built around it is great.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What difficulties did you find in implementing efene?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Learning the limits of the parser and what syntax is valid an unambiguous, learning to avoid introducing crazy ideas into the language because syntax and semantics are always tricky and you don’t want to have a “WAT” language.&lt;&#x2F;p&gt;
&lt;p&gt;Also learning about Erlang and its VM while doing it.&lt;&#x2F;p&gt;
&lt;p&gt;But to sum it up, it ended up not being as difficult as I thought it will be, it just requires persistence and some hammock-driven development ;)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Do you have any recommendation for those of us that did not implemented any language yet?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Learn about lexing and parsing, then build a calculator using S-Expressions (Lisp-like) or reverse-polish syntax (Forth-like).&lt;&#x2F;p&gt;
&lt;p&gt;Start it as an interpreter, copy the semantics from a simple language you already know, coming up with good semantics is hard, don’t try to invent them the first time.&lt;&#x2F;p&gt;
&lt;p&gt;Then ride on top of a language you know, either transpile to that language or compile to bytecode or some intermediate representation.&lt;&#x2F;p&gt;
&lt;p&gt;Try to reuse as much of the tooling from the other language as possible (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.erlang.org&#x2F;doc&#x2F;apps&#x2F;erts&#x2F;absform.html&quot;&gt;AST from Erlang&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;docs.python.org&#x2F;3&#x2F;library&#x2F;ast.html&quot;&gt;AST from Python&lt;&#x2F;a&gt; or similar), this will allow you to reuse all the tooling and code built around those representations.&lt;&#x2F;p&gt;
&lt;p&gt;Read about Lisps and Forth. Implement a simple Lisp (Scheme) or Forth.&lt;&#x2F;p&gt;
&lt;p&gt;Once you learn to lex and parse you can think syntax for languages and try to parse them.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is the match expression and why did you introduce it?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;At the core of efene rewrite was the concept of “Everything revolves around 4 main things, pattern matching, functions, guards and data”, pattern matching is done when using the equal sign (=), on the argument list of a function definition and on other Erlang expressions. I wanted to unify the pattern matching under a single syntax and reuse it everywhere, that’s where the “case clauses” came to be.&lt;&#x2F;p&gt;
&lt;p&gt;If you haven’t look at efene yet, the shape of efene expressions is something like:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;keyword&amp;gt; [&amp;lt;expr-args&amp;gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;case-clauses&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [else: &amp;lt;body&amp;gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;A case-clause has this shape:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;case &amp;lt;case-args&amp;gt; [when &amp;lt;guards&amp;gt;]: &amp;lt;body&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For example try&#x2F;catch:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;try&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;body&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;catch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;case-clauses&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [else: &amp;lt;body&amp;gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[after &amp;lt;body&amp;gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Receive:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;receive&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;case-clauses&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [else: &amp;lt;body&amp;gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[after &amp;lt;after-expr&amp;gt;: &amp;lt;body&amp;gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Functions:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fn [&amp;lt;name&amp;gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;lt;case-clauses&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    [else: &amp;lt;body&amp;gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You should see a pattern there, since the case keyword was already taken and it’s what Erlang use for what “match” does in efene I had to look for a new keyword.&lt;&#x2F;p&gt;
&lt;p&gt;One thing I like about python is this concept of “executable pseudocode”, I like the fact that if you read Python code aloud it sounds like what it does, so I thought “what am I doing here”, “I’m matching and expression against cases”, in imperative it would be “match A [against] case B, case C, else … end” and that’s how I ended up with match.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why did you introduce a &lt;em&gt;for&lt;&#x2F;em&gt; expression?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The initial idea for efene was to be familiar for people coming from “algol-like” or “mainstream” languages, so they can focus on learning what’s interesting about Erlang which are the semantics and the abstractions and avoid learning a new syntax on the way to epiphany.&lt;&#x2F;p&gt;
&lt;p&gt;Since list comprehensions aren’t available in many of those languages but “for” is, I decided to implement list comprehensions as a more familiar construct but in fact it does the same.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is the arrow operator and why did you add it?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;First a quick introduction for people unfamiliar with efene or the arrow operator.&lt;&#x2F;p&gt;
&lt;p&gt;There’s this thing in Erlang where if you want to apply a sequence of operations to a list you have to create a new binding for each intermediate result:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MyList = create_list(),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MyList1 = op1(MyList),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MyList2 = op2(MyList1),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MyList3 = op3(MyList2),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MyList4 = op4(MyList3).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then if you want to reorder or remove some of the operations you have to rearrange the names to fit.&lt;&#x2F;p&gt;
&lt;p&gt;The idea of the arrow operator is to help with that, it’s a compile operation, this means that if you write:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MyList = create_list() -&amp;gt; op1() -&amp;gt; op2() -&amp;gt; op3() -&amp;gt; op4()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It will compile to:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MyList = op4(op3(op2(op1(create_list))))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The thing is that the Erlang libraries don’t have a standard position for the thing you are operating on like in other languages where it tends to be the first argument, inspired by Clojure (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;clojuredocs.org&#x2F;clojure.core&#x2F;-%3E&quot;&gt;http:&#x2F;&#x2F;clojuredocs.org&#x2F;clojure.core&#x2F;-%3E&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;clojuredocs.org&#x2F;clojure.core&#x2F;-%3E%3E&quot;&gt;http:&#x2F;&#x2F;clojuredocs.org&#x2F;clojure.core&#x2F;-%3E%3E&lt;&#x2F;a&gt;)&lt;br &#x2F;&gt;
I created two variants:&lt;&#x2F;p&gt;
&lt;p&gt;_“- &amp;gt;” _adds the result of evaluating the expression on the left as first argument on the function call on the right&lt;&#x2F;p&gt;
&lt;p&gt;_“- &amp;gt;&amp;gt;” _adds the result of evaluating the expression on the left as last argument on the function call on the right&lt;&#x2F;p&gt;
&lt;p&gt;But thinking about symmetry and other common idiom in Erlang and other functional languages which is higher order functions (passing functions as arguments to other functions) I decided to create the reverse of those but with a more restricted use.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;“ &amp;lt;-”&lt;&#x2F;em&gt; adds the case clauses on the right as an anonymous function as last argument on the function call on the left.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;“ &amp;lt;&amp;lt;-”&lt;&#x2F;em&gt; adds the case clauses on the right as an anonymous function as first argument on the function call on the left.&lt;&#x2F;p&gt;
&lt;p&gt;You can see it says “case clauses” and not “anonymous function”, this is because you don’t have to write the &lt;em&gt;fn&lt;&#x2F;em&gt; keyword, it gives this expression a DSL taste that I like, for example:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;lists.map(Things) &amp;lt;&amp;lt;-&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; case 0: zero&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; case A when A % 2 is 0: even&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; else odd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Going back to the restricted uses of the right-to-left arrows it’s because since code reads from left to right, putting something on the right that is just a value doesn’t help readability hence I decided not to support it.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;I just saw that you are creating a new language for the BEAM called interfix. What is it?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;As I said above, efene is a language that doesn’t try to come up with anythingnew. This led me to avoid doing experiments on efene itself, but I still wanted to do those experiments somewhere else.&lt;&#x2F;p&gt;
&lt;p&gt;With time the number of ideas for crazy languages I had grew and condensed to a point I thought I had a nice little language. Then coming back from a conference I had a lot of dead time on airports and no internet so I decided to give it a try.&lt;&#x2F;p&gt;
&lt;p&gt;After I landed, the language was growing and all the ideas I had didn’t seem to have any problems so I kept growing it quite fast and for the last days it’s almost a complete language (in the sense that it can do everything Erlang can do).&lt;&#x2F;p&gt;
&lt;p&gt;At this point I’m finishing adding the remaining features and when everything is there and I know everything fits I will move to cleaning the code and adding some tooling and docs around it for people that want to play with a more “experimental” language.&lt;&#x2F;p&gt;
&lt;p&gt;I say experimental in the sense that it has some crazy ideas in it but not experimental in that it will crash, break backward compatibility or compile the code to wrong bytecode.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;You wrote the&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;marianoguerra.github.io&#x2F;little-riak-core-book&#x2F;&quot;&gt;&lt;strong&gt;Little Riak Core Book&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;and you gave a talk called F&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=eiVqDnA0k0U&quot;&gt;&lt;strong&gt;rom 0 to a working distributed system with riak_core&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;. Could you explain what riak core is and why it can be useful for those of us who implement distributed systems?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Riak Core is the foundation of Riak KV and other Basho projects, it’s the generic and reusable part of a “dynamo style” distributed system, it provides some abstractions and utilities to build multi-node, master-less distributed systems.&lt;&#x2F;p&gt;
&lt;p&gt;In a Riak Core based application you build your system by implemented interfaces to handle the work your application does inside virtual nodes (vnodes) that live inside a ring of vnodes, the work is done by routing commands consistently to those vnodes by hashing a key that you specify.&lt;&#x2F;p&gt;
&lt;p&gt;It also provides ways to run a command in more than one vnode and compare the results, grow or shrink the cluster without downtime, migrate vnodes between physical nodes, authentication&#x2F;authorization and a metadata system to hold information about the cluster and your application in a distributed manner.&lt;&#x2F;p&gt;
&lt;p&gt;This frees you from having to implement all this building blocks so you can focus on what actually makes your application different and building upon a tested and production ready foundation.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;While reading your blog I could see that you have used Scala and Clojure apart from Erlang. What has been your experience with Scala and Clojure? What advantages and disadvantages did you find when comparing Scala, Clojure and Erlang?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The experience with the 3 programming languages has been really good, I’ve built similar systems with those programming languages (a kind of pub&#x2F;sub system with persistence), the reason I moved this backend initially from Scala (lift+akka) to Clojure (immutant) was because the system handled lot of semi-structured data both from the frontend and the backend and I was using a lot of time putting that data into “rigid” types to serialize it to json again&lt;&#x2F;p&gt;
&lt;p&gt;after some operations, and each time the shape of the data evolved on the frontend or the storage I had to go and change those types in a backward compatible manner and it was getting really tiring since the backend was really simple in what it actually did.&lt;&#x2F;p&gt;
&lt;p&gt;So I decided to move to Clojure and it resulted in a huge reduction on code but after the code evolved I saw myself implementing this pub&#x2F;sub like system by hand with low level tools like agents, atoms and promises copying the Erlang “patterns”, at this point some customers were asking about scalability and clustering, so I decided to do a prototype using riak_core and after some coding we tried at a new project and since we could improve it fast and it was working quite nice we decided to adopt it as our default backend.&lt;&#x2F;p&gt;
&lt;p&gt;I’m still using scala for Spark jobs, I use clojure for internal tools and internal frontends with clojurescript but the backend now is Erlang.&lt;&#x2F;p&gt;
&lt;p&gt;I just want to clarify that our backend is quite simple in what it does so moving between languages in the backend is not a big deal, the bulk of what we do is in our frontend code.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>How to earn your Clojure white belt</title>
          <pubDate>Mon, 07 Sep 2015 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/how-to-earn-your-clojure-white-belt/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/how-to-earn-your-clojure-white-belt/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/how-to-earn-your-clojure-white-belt/">&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-uFlthCHz1YbmOvzhdVBrFw.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I tend to think that if I do not know how to implement something then I do not undestand completely how it works. That is why I want to learn so many things: new frameworks, programming languages, garbage collectors, type systems, compilers, editors, operating systems, protocols, kernel development. The road to enlightenment is long and difficult. To make things worse, you need to invest time on keeping up to date with technologies you thought you already knew. I usually feel like Mario in one of those levels where he needs to jump between moving clouds to reach the finish line.&lt;&#x2F;p&gt;
&lt;p&gt;That is why one of the best skills to get is being able to separate the wheat from the chaff. We have finite time and distractions are infinite. If you are going to invest time in learning a new language then you should consider Lisp which is definitely wheat of the best quality. If you don’t know why, then go read &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.paulgraham.com&#x2F;avg.html&quot;&gt;Beating the Averages&lt;&#x2F;a&gt; article. Clojure is a member of the Lisp family. If you have used a Lisp dialect such as &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.schemers.org&#x2F;&quot;&gt;Scheme&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;common-lisp.net&#x2F;&quot;&gt;Common Lisp&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Emacs_Lisp&quot;&gt;Emacs Lisp&lt;&#x2F;a&gt;, or even really alien and amazing creatures such &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.shenlanguage.org&#x2F;&quot;&gt;Shen&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;lfe.io&#x2F;&quot;&gt;LFE&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;racket-lang.org&#x2F;&quot;&gt;Racket&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;pixie-lang&#x2F;pixie&quot;&gt;Pixie&lt;&#x2F;a&gt; you might ask yourself why you should be learning Clojure. This is my opinionated point of view:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The language’s creator: Rich Hickey has a holistic understanding of this era development issues. You should read&#x2F;watch his talks called &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matthiasn&#x2F;talk-transcripts&#x2F;blob&#x2F;master&#x2F;Hickey_Rich&#x2F;AreWeThereYet.md&quot;&gt;Are We There Yet?&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;matthiasn&#x2F;talk-transcripts&#x2F;blob&#x2F;master&#x2F;Hickey_Rich&#x2F;SimpleMadeEasy.md&quot;&gt;Simple Made Easy&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;ROor6_NGIWU&quot;&gt;The Language of the System&lt;&#x2F;a&gt;. I see Clojure as a step in the right direction for tackling this era’s development issues&lt;&#x2F;li&gt;
&lt;li&gt;Great functional programming support: First class functions, persistent, immutable data structures and lazy &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.braveclojure.com&#x2F;core-functions-in-depth&#x2F;#2__The_Sequence_Abstraction&quot;&gt;sequences&lt;&#x2F;a&gt;. It has great support of polimorphism thanks to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;clojure-doc.org&#x2F;articles&#x2F;language&#x2F;polymorphism.html&quot;&gt;multimethods and protocols&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Concurrency support from its inception thanks to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;clojure-doc.org&#x2F;articles&#x2F;language&#x2F;concurrency_and_parallelism.html&quot;&gt;atoms, agents, refs, a software transactional memory &lt;&#x2F;a&gt;system and asynchronous programming using channels a la &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Communicating_sequential_processes&quot;&gt;CSP&lt;&#x2F;a&gt; with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;clojure.com&#x2F;blog&#x2F;2013&#x2F;06&#x2F;28&#x2F;clojure-core-async-channels.html&quot;&gt;core.async&lt;&#x2F;a&gt; library&lt;&#x2F;li&gt;
&lt;li&gt;Batteries included: good core libraries and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=6mTbuzafcII&quot;&gt;transducers&lt;&#x2F;a&gt; support&lt;&#x2F;li&gt;
&lt;li&gt;Clojurescript: Clojure that targets JavaScript with great libraries such as &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;reagent-project&#x2F;reagent&quot;&gt;reagent&lt;&#x2F;a&gt;, an interface to React.js that is really simple and useful. Check David Nolen’s talks called ClojureScript: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;MTawgp3SKy8&quot;&gt;Lisp’s Revenge&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;-I5ldi2aJTI&quot;&gt;Introduction to ClojureScript&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;JVM’s power (available almost everyhwere, optimized garbage collector, JIT compilation, Java interoperability), but also some issues such as not being able to properly support tail call optimization and awful stacktraces. If you are a Java developer you should check part &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=P76Vbsk_3J0&quot;&gt;I&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=hb3rurFxrZ8&quot;&gt;II&lt;&#x2F;a&gt; from Rich Hickey’s Clojure for Java Programmers talk&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;ready-steady-go&quot;&gt;Ready, steady, go!&lt;&#x2F;h3&gt;
&lt;p&gt;Install &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;leiningen.org&#x2F;#install&quot;&gt;Leiningen&lt;&#x2F;a&gt; and configure your editor of choice.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Emacs with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;clojure-emacs&#x2F;cider&quot;&gt;Cider&lt;&#x2F;a&gt; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;clojure-emacs&#x2F;clojure-mode&quot;&gt;Clojure mode&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;company-mode.github.io&quot;&gt;Company mode&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Vim with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tpope&#x2F;vim-fireplace&quot;&gt;vim-fireplace&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tpope&#x2F;vim-sexp-mappings-for-regular-people&quot;&gt;im-sexp-mappings-for-regular-people&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tpope&#x2F;vim-salve&quot;&gt;vim-salve&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;luochen1990&#x2F;rainbow&quot;&gt;rainbow&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;lighttable.com&#x2F;&quot;&gt;Light Table&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;sekao.net&#x2F;nightcode&#x2F;&quot;&gt;Nightcode&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Sublime with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;odyssomay&#x2F;paredit&quot;&gt;paredit&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;odyssomay&#x2F;sublime-lispindent&quot;&gt;Lispindent&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.google.com.ar&#x2F;search?q=SublimeREPL&quot;&gt;SublimeREPL&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;cursiveclojure.com&#x2F;&quot;&gt;Cursive&lt;&#x2F;a&gt; (IntelliJ)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;doc.ccw-ide.org&#x2F;documentation.html#install-as-standalone-product&quot;&gt;Counterclockwise&lt;&#x2F;a&gt; (Eclipse)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;good-tools-that-deserve-a-mention&quot;&gt;Good tools that deserve a mention&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;Linter &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jonase&#x2F;eastwood&quot;&gt;Eastwood&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Idiomatic Clojure checker &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jonase&#x2F;kibit&quot;&gt;kibit&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Clojure formatter &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;weavejester&#x2F;cljfmt&quot;&gt;cljfmt&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Check simple issues in your code &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dakrone&#x2F;lein-bikeshed&quot;&gt;bikeshed&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;love-at-first-sight&quot;&gt;Love at first sight&lt;&#x2F;h3&gt;
&lt;p&gt;First of all get an idea of Clojure syntax and semantics:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;learnxinyminutes.com&#x2F;docs&#x2F;clojure&#x2F;&quot;&gt;Learn X in Y minutes where X=clojure&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;kimh.github.io&#x2F;clojure-by-example&#x2F;&quot;&gt;Clojure by example&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;howistart.org&#x2F;posts&#x2F;clojure&#x2F;1&#x2F;&quot;&gt;How I start Clojure&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.se-radio.net&#x2F;2010&#x2F;03&#x2F;episode-158-rich-hickey-on-clojure&#x2F;&quot;&gt;Listen to Software Engineering Radio’s interview with Rich Hickey&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;If you do not understand something move on. At this stage the only objective is to grasp some basic ideas about Clojure.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;practice-plus-reading-equals-perfection&quot;&gt;Practice plus reading equals perfection&lt;&#x2F;h4&gt;
&lt;ol&gt;
&lt;li&gt;First practice with the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;clojurekoans.com&#x2F;&quot;&gt;Koans&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Then read &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.braveclojure.com&#x2F;&quot;&gt;Clojure for the Brave and True&lt;&#x2F;a&gt;, a simple and short book. If you prefer to watch videos, you can buy the course &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.purelyfunctional.tv&#x2F;intro-to-clojure&quot;&gt;Introduction to Clojure&lt;&#x2F;a&gt; from PurelyFunctionalTV.&lt;&#x2F;li&gt;
&lt;li&gt;Practice again with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.4clojure.com&#x2F;&quot;&gt;4clojure problems&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Follow the road to perfection with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;exercism.io&#x2F;languages&#x2F;clojure&quot;&gt;Clojure exercism&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Finish the practice with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gigasquid&#x2F;wonderland-clojure-katas&quot;&gt;Wanderland Clojure Katas&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;It is always a good idea to have the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;clojure.org&#x2F;api&#x2F;cheatsheet&quot;&gt;cheatsheet&lt;&#x2F;a&gt; at hand.&lt;&#x2F;p&gt;
&lt;p&gt;Other two good tutorials worth mentioning are &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;aphyr.com&#x2F;tags&#x2F;Clojure-from-the-ground-up&quot;&gt;Clojure from the ground up&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;hitchhikersclojure.com&#x2F;&quot;&gt;Hitchhiker’s Guide to Clojure&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;idiomatic-clojure&quot;&gt;Idiomatic Clojure&lt;&#x2F;h4&gt;
&lt;p&gt;Clojure is not Java, neither Common Lisp or Scheme. You should learn to write idiomatic Clojure. The Joy of Clojure is your best friend to become a native Clojure speaker:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.joyofclojure.com&#x2F;the-book&#x2F;&quot;&gt;About The Joy of ClojureWhen this book was conceived, our first instinct was to create a comprehensive com- parison between Clojure and its…www.joyofclojure.com&lt;img src=&quot;https:&#x2F;&#x2F;cdn-images-1.medium.com&#x2F;fit&#x2F;c&#x2F;160&#x2F;160&#x2F;0*B4upiW5LhjZYt_TK.&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It is also important to follow table manners or the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bbatsov&#x2F;clojure-style-guide&quot;&gt;Clojure style guide&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;If you have trouble like me grasping macros, then you should also check out &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;pragprog.com&#x2F;book&#x2F;cjclojure&#x2F;mastering-clojure-macros&quot;&gt;Mastering Clojure Macros&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Oh, if you miss your type checking then now it is a good time that you read about &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;typedclojure.org&#x2F;&quot;&gt;optional type system&lt;&#x2F;a&gt; for Clojure.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;keep-up-to-date&quot;&gt;Keep up to date&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;planet.clojure.in&#x2F;&quot;&gt;Planet Clojure&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.clojuregazette.com&#x2F;&quot;&gt;Clojure Gazette&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;reborg.tumblr.com&#x2F;&quot;&gt;Clojure Weekly&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;Clojure&#x2F;&quot;&gt;Reddit&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;user&#x2F;ClojureTV&quot;&gt;ClojureTV&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;know-the-full-arsenal-at-your-disposal&quot;&gt;Know the full arsenal at your disposal&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.clojure-toolbox.com&#x2F;&quot;&gt;Clojure Toolbox&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;razum2um&#x2F;awesome-clojure&quot;&gt;Awesome Clojure&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;get-help&quot;&gt;Get help&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;groups.google.com&#x2F;forum&#x2F;#!forum&#x2F;clojure&quot;&gt;Google Group&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;IRC: #clojure channel in Freenode server&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;clojurians.slack.com&#x2F;&quot;&gt;Clojurians Slack&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;introduction-to-clojurescript&quot;&gt;Introduction to Clojurescript&lt;&#x2F;h4&gt;
&lt;p&gt;Clojure on the frontend trench:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;clojure&#x2F;clojurescript&#x2F;wiki&#x2F;Quick-Start&quot;&gt;Quickstart&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;clojure&#x2F;clojurescript&#x2F;wiki&#x2F;Differences-from-Clojure&quot;&gt;Differences from Clojure&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;magomimmo&#x2F;modern-cljs&quot;&gt;A series of tutorials on Clojurescript&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h4 id=&quot;building-your-own-lisp&quot;&gt;Building your own Lisp&lt;&#x2F;h4&gt;
&lt;p&gt;Building a Lisp is similar to a road trip with friends and good music but with no particular destination. Make yourself comfortable and enjoy the ride!&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.buildyourownlisp.com&#x2F;&quot;&gt;Build your own Lisp&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikibooks.org&#x2F;wiki&#x2F;Write_Yourself_a_Scheme_in_48_Hours&quot;&gt;Write Yourself a Scheme in 48 hours&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;norvig.com&#x2F;lispy.html&quot;&gt;(How to Write a (Lisp) Interpreter (in Python))&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Interview with Nenad Rakocevic about Red, a Rebol inspired programming language</title>
          <pubDate>Fri, 28 Aug 2015 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-nenad-rakocevic-about-red-a-rebol-inspired-programming-language/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-nenad-rakocevic-about-red-a-rebol-inspired-programming-language/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-nenad-rakocevic-about-red-a-rebol-inspired-programming-language/">&lt;p&gt;After our &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;this-is-not-a-monad-tutorial&#x2F;interview-with-brian-mckenna-about-roy-purescript-haskell-idris-and-dependent-types-63bb1289ea3d&quot;&gt;last interview with Brian McKenna&lt;&#x2F;a&gt; for &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;this-is-not-a-monad-tutorial&quot;&gt;This is not a Monad tutorial&lt;&#x2F;a&gt; we interviewed &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dockimbel&quot;&gt;Nenad Rakocevic&lt;&#x2F;a&gt;, creator of the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.red-lang.org&#x2F;&quot;&gt;Red&lt;&#x2F;a&gt; programming language.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-C0sMUPxpbBs40YIBX848jQ.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;From my completely subjective point of view Red and Rebol are quite strange creatures! But don’t get me wrong, that doesn’t mean something bad. For example, I am not aware of many high-level languages which features an embedded DSL for general-purpose low-level programming or that have 50 native types. You should check it out, you might find some interesting ideas inside Red development.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Please tell us a little bit about Red’s inception. Why was it created?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-869fRKUVs2sTdVDYrqblMQ.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I started programming micro-computers, an Amiga in my case, in my teens. I have now been programming for more than 30 years. After my early experiences, I was unhappy with existing programming languages and tools. This was mostly because I found them not productive or friendly enough for my taste. So, when I stumbled across the Rebol language, in 1999, it was an eye-opener on what was wrong with so called “modern” computing practice. (Nowadays it’s even worse). Fighting complexity on all software fronts became the logical course of action.&lt;&#x2F;p&gt;
&lt;p&gt;In 2010, Rebol was closed source. I deeply felt that the approach had a lot more to offer but Rebol was barely evolving. This was the trigger for me to start work on an open source relative to Rebol with much higher ambitions and a broader field of usage.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What are the main selling points of Red?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;First fullstack programming solution: combines in one tool, the ability to write high-level code (GUI apps, scripting and DSL) and fast low-level code (writing device drivers, operating systems, native interfacing, etc). Moreover, Red is also a &lt;em&gt;both-sided&lt;&#x2F;em&gt; technology (client &amp;amp; server).&lt;&#x2F;li&gt;
&lt;li&gt;Cross-platform native code compiler: from any platform the toolchain runs on, you can compile to about 15 other platforms, with a simple command-line option (-t Windows, -t Linux, -t Darwin, -t RPi, …).&lt;&#x2F;li&gt;
&lt;li&gt;Extremely lightweight: Red is a 1MB, single-file, no install, no setup, toolchain. It takes typically a few seconds to download and you can immediatly start writing and running code, there’s &lt;em&gt;nothing&lt;&#x2F;em&gt; to setup (it’s just terrible that this is the exception instead of being the norm…).&lt;&#x2F;li&gt;
&lt;li&gt;Batteries-included solution: it comes with a very rich runtime library, despite its tiny size, covering pretty much anything you need for common tasks.&lt;&#x2F;li&gt;
&lt;li&gt;DSL-oriented environment: Red comes with many embedded DSL addressing important needs (like GUI or system-programming). DSL are a very powerful way to reduce complexity arising from frameworks or API, while drastically increasing productivity. Red includes a DSL (called Parse) for constructing DSLs.&lt;&#x2F;li&gt;
&lt;li&gt;Red (like Rebol) is a Lisp derivative, but with a human-friendly syntax (no parenthesis hell). Red is its own data format. All code is treated as data until you evaluate it, code&#x2F;data serialization comes for free. The minimal punctuation makes it easy on the eye.&lt;&#x2F;li&gt;
&lt;li&gt;The underlying philosophy of Red (as was that of Rebol) is to make the simple easy and the difficult possible.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;What made Rebol the main inspiration for Red?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Rebol is one of the most innovative programming language created in the last 20 years. Sadly, it remained under the radar being closed source at a time when open-source languages like Perl, Python and Ruby hit the streets. Rebol’s approach shakes the foundation of what programmers consider “simple” or “efficient” in programming. Typically, API which other languages would call “simple”, look uselessly complicated when you are used to wear Rebol glasses. ;-) Here are a few one-liners as examples (using the Rebol2 REPL):&lt;&#x2F;p&gt;
&lt;p&gt;Create a GUI window with a button printing, on click, Hello in the console:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;view layout [button “Click Me” [print “Hello”]]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Dump the content of a web page in console:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;print read http:&#x2F;&#x2F;rebol.com&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Extract the title of a web page:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;parse read http:&#x2F;&#x2F;rebol.com [thru &amp;lt;title&amp;gt; copy text to &amp;lt;&#x2F;title&amp;gt; (print text)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Send the list of files in current folder by email:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;send user@domain.com mold read %.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Retrieve records from a MySQL database and print them in console:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;foreach row read&#x2F;custom mysql:&#x2F;&#x2F;root@localhost&#x2F;books [“SELECT * FROM authors”] [print row]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Notice that even if you never looked at Rebol code before, you can nonetheless read it and guess what most of the code is doing.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What are the main differences between Rebol and Red?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Red can be (cross-)compiled to native code, Rebol is only interpreted. Compiled code can run much faster than interpreted code.&lt;&#x2F;li&gt;
&lt;li&gt;Red allows system-programming and fast low-level code, Rebol is stuck at scripting-level.&lt;&#x2F;li&gt;
&lt;li&gt;Red relies on native widgets and native backends for GUI support, Rebol has a custom GUI engine. So Red will make your GUI apps feel more natural and better integrated to the OS user.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Besides that, the languages itself are very similar, somewhere around 95% the same. If you know Rebol, you know Red.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Red covers the whole range of abstraction between low-level and high-level programming by offering Red&#x2F;System as a dialect with C-type semantics and Rebol-type syntax. Was the distinction between Red and Red&#x2F;System present in the original design? What advantages do you gain by using Red&#x2F;System?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Absolutely, Red&#x2F;System was one of the main incentive to build a new programming stack instead of simply duplicating the Rebol implementation. Red&#x2F;System is a statically compiled language targetting native code (like C). Red&#x2F;System serves two main purposes:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;provide an embedded DSL to Red users for fast code support and system programming needs&lt;&#x2F;li&gt;
&lt;li&gt;fill the role of an IR (Intermediate Representation) language for compiled Red code&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;AFAIK, Red is the first high-level language which features such embedded DSL for general-purpose low-level programming.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Who uses Red&#x2F;Rebol?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The Rebol community used to be relatively big in the early 2000, but it shrank a lot as its evolution tailed off. The profile of users was astonishly broad on the skills scale. Many were attracted by its simplicity for simple tasks and its cross-platform GUI engine, but other were more interested by its depth (dynamic binding, easy DSL crafting, strong meta-programming abilities, …).&lt;&#x2F;p&gt;
&lt;p&gt;Since then, only the hardcore fans or companies which have built their software on top of it, continue to use and promote it. Many of those same people now form the early adopters for Red, along with many other people which were interested in Rebol when it launched, but rejected it due to its closed-source nature. Some of them wrote libraries for Red, other small games or even a Windows device driver! :-) As soon as Red is ready for production, we’ll make sure many more people will join them and have fun using Red.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;For which scenarios do you think Red is an appropriate language?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Red is a general-purpose programming solution which should be good enough for &lt;em&gt;any&lt;&#x2F;em&gt; programming task. In practice, it’s (only) limited by the available frameworks and libraries. So these tasks are a very good match for Red:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;scripting &#x2F; glue code&lt;&#x2F;li&gt;
&lt;li&gt;GUI apps (in upcoming v0.6.0)&lt;&#x2F;li&gt;
&lt;li&gt;Android apps (in v0.6.1)&lt;&#x2F;li&gt;
&lt;li&gt;data processing&lt;&#x2F;li&gt;
&lt;li&gt;grammar parsers &#x2F; DSL creation&lt;&#x2F;li&gt;
&lt;li&gt;system programming&lt;&#x2F;li&gt;
&lt;li&gt;device drivers&lt;&#x2F;li&gt;
&lt;li&gt;IoT devices programming (runinng on Intel or ARM cpu)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Once we reach 1.0 (next year), Red will also be very good for:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;webapps programming&lt;&#x2F;li&gt;
&lt;li&gt;servers creation&lt;&#x2F;li&gt;
&lt;li&gt;2D games&lt;&#x2F;li&gt;
&lt;li&gt;robotics&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Rebol and Red offer a great variety of built in types with practical applications. Some would argue that it is better to offer a small core of language features. What is your take on that?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Rebol and Red offer about 50 datatypes in a runtime of about 500KB. Among them, two-thirds have a specific literal form (like money, email, url, time, date, colors,…) which gives you, out of the box, a rich set of literals you can use for building embedded DSL.&lt;&#x2F;p&gt;
&lt;p&gt;Another big gain is that most of the features you need for daily work are already there, as first-class citizens, perfectly integrated with the rest, working exactly the same on every supported platform. This is a productivity boost and makes learning&#x2F;using the language much more pleasant (no need to make “imports” for any simple task). Such languages are pragmatic and aiming at reducing the costs of software building.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is a sky-high view of how Red is implemented? Are all the components (parsers, code generators, garbage collectors, etc) hand-written? What dependencies does Red have?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Excepting for a good part of the unit tests, which are generated by script, everything else is hand-written. We are bootstrapping Red using Rebol, so the toolchain (compilers, linker, builders) is written in Rebol2. Rebol offers a parsing DSL which is very effective, adding to that its deep metaprogramming abilities, there is simply no need to use any other tool for building such toolchain. Red scripts can be interpreted from the REPL or compiled to native code, using Red&#x2F;System as intermediary target. The runtime library is built in a mix of Red and Red&#x2F;System code.&lt;&#x2F;p&gt;
&lt;p&gt;Red executables are typically around 0.5MB and have no dependencies.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;How complete is Red as of Mid-2015?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;There’s already a lot implemented, so I’ll describe rather what’s missing. Right now, we are completing the cross-platform GUI support with a first backend for Windows. Android, Linux and OS X backends will follow. The I&#x2F;O is currently limited to simple file operations and HTTP client support only. Modular compilation, full garbage collector and concurrency support are the main features missing before reaching 1.0. We aim at launching the 1.0 release in 2016.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Where do you see Red in the future?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Red has the potential to seduce many developers (especially indie-developers who have the freedom of choice) who are frustrated by existing tools (even the so-called “simple” ones). I expect Red to be wide-spread in a couple of years, helping programmers achieving many different tasks while having fun doing it and making their life easier. Red will expand with many strong DSL for various domains, offering nice replacements for existing libraries direct usage. For example, we’ll push it in robotic and AI fields.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What are the most important lessons learned from the development of Red?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Open-source is a superior way to build quality software (just confirmed that fact with Red project).&lt;&#x2F;li&gt;
&lt;li&gt;Working “in the open” is not always a good thing, sometimes you need to isolate yourself from the outside “noise” to execute complex tasks (mostly design tasks). Being able to do so is increasingly difficult as the project growths up.&lt;&#x2F;li&gt;
&lt;li&gt;Having to deal with a growing community of users consumes a &lt;em&gt;lot&lt;&#x2F;em&gt; of time. Finding people to deal with the community for you is critical.&lt;&#x2F;li&gt;
&lt;li&gt;Designing good syntactic rules is &lt;em&gt;way&lt;&#x2F;em&gt; more difficult than designing good semantics. That’s a part overlooked by many language designers, which end up with great semantics but terrible syntaxes.&lt;&#x2F;li&gt;
&lt;li&gt;Writing a native code compiler for a statically typed language is really not difficult, most programmers with a minimal CS background could do it, they’re just not aware they can.&lt;&#x2F;li&gt;
&lt;li&gt;Premature optimization can (often) bite you in the back. Knowing when you’re optimizing prematurely is a bit of a black art.&lt;&#x2F;li&gt;
&lt;li&gt;Every big software project should be started by a team of at least 2 highly tuned, equally skilled developers. Working alone on big projects is insane, and not a guarantee of best results.&lt;&#x2F;li&gt;
&lt;li&gt;If you work on an open-source project that is attractive enough and gather enough followers, you can live from user’s donations (I did so for 2 years, covering all my basic life expenses). I never thought that would be possible when I started, nor did I counted on it. I guess I’m just lucky that Red has an amazing community.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;strong&gt;What reading material do you recommend for implementing your first programming language?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;You can have a good overview of all the required parts in a book like this &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.goodreads.com&#x2F;book&#x2F;show&#x2F;112256.Modern_Programming_Languages&quot;&gt;Modern Programming Languages: A Practical Introduction&lt;&#x2F;a&gt;. If you want to go in-depth and dive into more abstract concerns, the “Dragon book” is still the reference.&lt;&#x2F;p&gt;
&lt;p&gt;But the most useful way is to study several small languages implementation, that will give you the best insights about how to achieve it yourself. For example, Red 0.1.0 release is just a 24KB zip archive, but features already a working compiler&#x2F;linker for Red&#x2F;System with many features already (including FFI). Get it from here: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;red&#x2F;red&#x2F;releases&#x2F;tag&#x2F;v0.1.0&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;red&#x2F;red&#x2F;releases&#x2F;tag&#x2F;v0.1.0&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What other languages or technologies are you keeping an eye?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Go: it’s the language with the fastest growth in the last years, understanding why, could be a key to help Red growing faster too. Go’s concurrency model also seems attractive to users, so worth studying.&lt;&#x2F;li&gt;
&lt;li&gt;Lua: trying to understand where it’s heading and how it grows.&lt;&#x2F;li&gt;
&lt;li&gt;Python3.x: trying to understand where it’s heading, not sure I understand its strategy though.&lt;&#x2F;li&gt;
&lt;li&gt;Webassembly: the foundation for the future of web programming.&lt;&#x2F;li&gt;
&lt;li&gt;MagicLeap: the future of HCI!&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Interview with Brian McKenna about Roy, Purescript, Haskell, Idris and dependent types</title>
          <pubDate>Wed, 26 Aug 2015 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-brian-mckenna-about-roy-purescript-haskell-idris-and-dependent-types/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-brian-mckenna-about-roy-purescript-haskell-idris-and-dependent-types/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/interview-with-brian-mckenna-about-roy-purescript-haskell-idris-and-dependent-types/">&lt;p&gt;As promised in our &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;this-is-not-a-monad-tutorial&#x2F;eric-merritt-erlang-and-distributed-systems-expert-gives-his-views-on-beam-languages-hindley-a09b15f53a2f&quot;&gt;last interview&lt;&#x2F;a&gt; for &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;this-is-not-a-monad-tutorial&quot;&gt;This is not a Monad tutorial&lt;&#x2F;a&gt; we interviewed &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;puffnfresh&quot;&gt;Brian McKenna&lt;&#x2F;a&gt;, creator of the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;roy.brianmckenna.org&#x2F;&quot;&gt;Roy&lt;&#x2F;a&gt; programming language. In this interview Brian talks about Roy, its implementation, how it compares with Purescript, and also about dependent types and other interesting technologies like Morte and Unison. I highly recommend that you check &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;brianmckenna.org&#x2F;blog&#x2F;&quot;&gt;Brian’s blog&lt;&#x2F;a&gt; after you finish reading this interview.&lt;&#x2F;p&gt;
&lt;p&gt;In the following weeks we will be talking with the creators of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.red-lang.org&#x2F;&quot;&gt;Red programming language&lt;&#x2F;a&gt;, Robert Virding — Erlang co-inventor and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;lfe.io&#x2F;&quot;&gt;Lisp Flavored Erlang&lt;&#x2F;a&gt; creator — and with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mirage.io&#x2F;&quot;&gt;MirageOS unikernel&lt;&#x2F;a&gt; dev team.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-vYf7TCGE19Gni5ssKXQaHA.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What are Roy’s main features?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Roy featured things common to languages which are well suited to typed&lt;br &#x2F;&gt;
functional programming:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Types and type inference (with row polymorphism)&lt;&#x2F;li&gt;
&lt;li&gt;Algebraic data types and pattern matching&lt;&#x2F;li&gt;
&lt;li&gt;Monadic syntax&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Why did you create it?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I created Roy after doing years of JavaScript work. I learned Haskell&lt;br &#x2F;&gt;
and it made a huge amount of sense to me. Functional programming with&lt;br &#x2F;&gt;
types seemed like the ideal way for me to work on software and so I&lt;br &#x2F;&gt;
wanted to bring it to web programming.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;I am tempted to say that Roy has some big similarities with&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.purescript.org&#x2F;&quot;&gt;&lt;strong&gt;Purescript&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;. What are the main differences between the two languages?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Roy was first!&lt;&#x2F;p&gt;
&lt;p&gt;PureScript had almost the exact same goals as Roy but had a much&lt;br &#x2F;&gt;
better implementation. Quoting the PureScript wiki:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Roy is probably the most similar language on the list, and was a&lt;br &#x2F;&gt;
large influence on the development of PureScript.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I stopped working on Roy once PureScript got around equal in&lt;br &#x2F;&gt;
functionality. PureScript’s implementation means it’s a lot easier to&lt;br &#x2F;&gt;
work on and has much fewer bugs.&lt;&#x2F;p&gt;
&lt;p&gt;Originally the PureScript FFI started off being very different (i.e.&lt;br &#x2F;&gt;
it used inline JS instead of an externs file) but recently changed to&lt;br &#x2F;&gt;
being similar to the original design Roy had. That was probably the&lt;br &#x2F;&gt;
biggest difference the projects had.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;You implemented the lexer and the parser. Did you do so to learn&#x2F;play or because you thought that the available tools were not good enough?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I implemented a whitespace sensitive lexer which was passed into the&lt;br &#x2F;&gt;
Jison parser generator. It was the same approach which CoffeeScript&lt;br &#x2F;&gt;
took.&lt;&#x2F;p&gt;
&lt;p&gt;A custom lexer was necessary because the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;this-is-not-a-monad-tutorial&#x2F;interview-with-brian-mckenna-about-roy-purescript-haskell-idris-and-dependent-types-63bb1289ea3d&quot;&gt;Jison&lt;&#x2F;a&gt; lexer generator was not&lt;br &#x2F;&gt;
capable of stateful scanning of whitespace.&lt;&#x2F;p&gt;
&lt;p&gt;I prefer working with parser combinators such as Parsec and Trifecta.&lt;br &#x2F;&gt;
They’re easier to work with and allow you to write reusable&lt;br &#x2F;&gt;
abstractions.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why did you use a whitespace sensitive grammar a la Python&#x2F;Haskell in Roy?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Just to look like Haskell. I hate thinking about syntax — I copy&lt;br &#x2F;&gt;
things as much as I can. I’m also annoyed that we’re still writing&lt;br &#x2F;&gt;
programs using text. They’re trees, not lists of characters!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why is it useful to have monadic sugar in a language that has unrestricted side effects?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Roy was not designed to allow side-effects, but you could do anything&lt;br &#x2F;&gt;
with the FFI and so it was possible.&lt;&#x2F;p&gt;
&lt;p&gt;Scala has (pretty limited) monadic sugar and also unrestricted&lt;br &#x2F;&gt;
side-effects. People use monadic sugar for things as straight-forward&lt;br &#x2F;&gt;
as Option:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;for {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  name &amp;lt;- maybeFirstName&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  user &amp;lt;- lookup(name)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  avatar &amp;lt;- getAvatar(user)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;} yield avatar&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Which can be easier to type than:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;maybeFirstName.flatMap { name =&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  lookup(name).flatMap { user =&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    getAvatar(user)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It doesn’t have anything to do with side-effects.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;From what we could read in the Damas-Hindley-Milner type inference algorithm source comments it is based on Robert Smallshire’s Python code. Do you have any recommendation for those who want to implement it?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I recommend reading “Generalizing Hindley-Milner Type Inference&lt;br &#x2F;&gt;
Algorithms” which turns the algorithm into explicit separate&lt;br &#x2F;&gt;
constraint collection and constraint solving problems, which is a bit&lt;br &#x2F;&gt;
easier to work with than plain Algorithm W. It’s then possible to do&lt;br &#x2F;&gt;
tree annotation via the cofree comonad, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;brianmckenna.org&#x2F;blog&#x2F;type_annotation_cofree&quot;&gt;which gives a pretty nice&lt;&#x2F;a&gt;&lt;br &#x2F;&gt;
&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;brianmckenna.org&#x2F;blog&#x2F;type_annotation_cofree&quot;&gt;implementation&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What reading material do you recommend for implementing your first programming language?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Source code of other languages are great resources. I think the&lt;br &#x2F;&gt;
PureScript and Idris compilers are somewhat easy to play around with.&lt;&#x2F;p&gt;
&lt;p&gt;Hackage has a lot of code to look at, such as reference&lt;br &#x2F;&gt;
implementations of Algorithm W:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;hackage.haskell.org&#x2F;packages&#x2F;&quot;&gt;https:&#x2F;&#x2F;hackage.haskell.org&#x2F;packages&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What would you recommend us to read to learn about different type systems?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.cis.upenn.edu&#x2F;~bcpierce&#x2F;tapl&#x2F;&quot;&gt;Types and Programming Languages&lt;&#x2F;a&gt; by Benjamin Pierce is a brilliant&lt;br &#x2F;&gt;
resource for understanding both. It’s surprised me by being a very&lt;br &#x2F;&gt;
good introduction to types and having pretty good reference&lt;br &#x2F;&gt;
implementations in OCaml for each of the discussed type-systems. Very&lt;br &#x2F;&gt;
highly recommended.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Have you tried&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;elm-lang.org&#x2F;&quot;&gt;&lt;strong&gt;Elm&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;? What do you think of&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Functional_reactive_programming&quot;&gt;&lt;strong&gt;FRP&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I think Functional Reactive Programming could be generalised a bit to&lt;br &#x2F;&gt;
just general stream combinator libraries and we could make it as&lt;br &#x2F;&gt;
simple as libraries such as pipes, machines and scalaz-stream. I’d&lt;br &#x2F;&gt;
like to implement one of those libraries in PureScript and try to&lt;br &#x2F;&gt;
write combinators to fill in the gaps for developing user interfaces&lt;br &#x2F;&gt;
to see how close we get to current FRP libraries.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;You recently gave a talk about&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.idris-lang.org&#x2F;&quot;&gt;&lt;strong&gt;Idris&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;, a language with&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Dependent_type&quot;&gt;&lt;strong&gt;dependent types&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;. Could you explain what are dependent types?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In non-dependently typed languages we have a way of making values&lt;br &#x2F;&gt;
depend upon other values: functions! In dependent typed languages we&lt;br &#x2F;&gt;
have those functions, but also functions which can return types.&lt;&#x2F;p&gt;
&lt;p&gt;Haskell has two completely separate languages: the language of values&lt;br &#x2F;&gt;
and the language of types. Recent versions of GHC give a way of&lt;br &#x2F;&gt;
promoting certain values up to types, but if you want to write a&lt;br &#x2F;&gt;
function over those values, you’ll have to write a version at the&lt;br &#x2F;&gt;
value level and separately at the type level.&lt;&#x2F;p&gt;
&lt;p&gt;Dependent-types remove the separation. If you write a function, you&lt;br &#x2F;&gt;
can reuse it for terms at any level.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What are the practical benefits of using a language with dependent types?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Since you can use values in your types, you can specify a lot more.&lt;br &#x2F;&gt;
For example, I can specify that list reversal is an involution, i.e.&lt;br &#x2F;&gt;
reversing twice is the same as not reversing at all:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;reverseInvolution : (xs : List a) -&amp;gt; reverse (reverse xs) = r&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;No need for tests — if I implement a value for that type, I have a&lt;br &#x2F;&gt;
proof for all possible values.&lt;&#x2F;p&gt;
&lt;p&gt;Or we can specify that a sort function will generate a list where each&lt;br &#x2F;&gt;
element is smaller than the next. The implementation of sort will only&lt;br &#x2F;&gt;
compile if we prove that to be true.&lt;&#x2F;p&gt;
&lt;p&gt;We can also do things like metaprogramming, since we know more about&lt;br &#x2F;&gt;
the values which are passed in, we can compute fancy types for things&lt;br &#x2F;&gt;
such as literals.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;From what we have read from your blog you have learnt Coq and Agda. What can code monkeys like us learn from programming languages like Coq and Agda?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I know a tiny amount of Coq and Agda. They teach people what types are&lt;br &#x2F;&gt;
capable of and how they can be used to interactively prove programs&lt;br &#x2F;&gt;
correct. It’ll also show the potential of typed metaprogramming, for&lt;br &#x2F;&gt;
example allowing the type of printf to depend upon the input string or&lt;br &#x2F;&gt;
how it’s possible to write your own statically checked literal&lt;br &#x2F;&gt;
strings.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Have you checked&lt;&#x2F;strong&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;goto.ucsd.edu&#x2F;~rjhala&#x2F;liquid&#x2F;haskell&#x2F;blog&#x2F;about&#x2F;&quot;&gt;&lt;strong&gt;LiquidHaskell&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt;&lt;strong&gt;? What do you think about and refinement types?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I think refinement types are interesting. It’s very exciting to just&lt;br &#x2F;&gt;
be able to add on annotations to existing programs and let proof&lt;br &#x2F;&gt;
searching do the rest but I’d prefer dependent types to be a research&lt;br &#x2F;&gt;
area for a couple of reasons:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;LiquidHaskell can do some dependent looking things but doesn’t have&lt;br &#x2F;&gt;
full pi-types so can’t do as much as real dependent types&lt;&#x2F;li&gt;
&lt;li&gt;We’re relying on an SMT solver to come up with a reasoning for why&lt;br &#x2F;&gt;
something is true, dependent types allow you to create and manipulate&lt;br &#x2F;&gt;
your own justifications — this might be solvable just via tooling,&lt;br &#x2F;&gt;
though&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;strong&gt;What other languages or technologies are you keeping an eye on that we should check?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Morte&lt;&#x2F;strong&gt; by Gabriel Gonzalez is a brilliant way of talking about&lt;br &#x2F;&gt;
distributable programs. I want to work on Morte to create a database&lt;br &#x2F;&gt;
of super-optimised code, where package management is about functions,&lt;br &#x2F;&gt;
not libraries. Morte has a pretty good introduction &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;hackage.haskell.org&#x2F;package&#x2F;morte-1.2.1&#x2F;docs&#x2F;Morte-Tutorial.html&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Paul Chiusano’s &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;unisonweb.org&#x2F;&quot;&gt;&lt;strong&gt;Unison&lt;&#x2F;strong&gt;&lt;&#x2F;a&gt; is an attempt at removing the “list of&lt;br &#x2F;&gt;
characters” problem from programming. It’s also trying to create a&lt;br &#x2F;&gt;
better UX for functional programming.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Erlang and distributed systems expert gives his views on BEAM languages, Hindley–Milner…</title>
          <pubDate>Sat, 08 Aug 2015 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/eric-merritt-erlang-and-distributed-systems-expert-gives-his-views-on-beam-languages-hindley/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/eric-merritt-erlang-and-distributed-systems-expert-gives-his-views-on-beam-languages-hindley/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/eric-merritt-erlang-and-distributed-systems-expert-gives-his-views-on-beam-languages-hindley/">&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-Bvd7l2Q-OmEhkVC2qcclJA.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;eric-merritt-erlang-and-distributed-systems-expert-gives-his-views-on-beam-languages-hindley-milner-type-systems-and-new-technologies&quot;&gt;Eric Merritt, Erlang and distributed systems expert, gives his views on BEAM languages, Hindley–Milner type systems and new technologies&lt;&#x2F;h3&gt;
&lt;p&gt;In this case, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;this-is-not-a-monad-tutorial&quot;&gt;This is not a Monad tutorial&lt;&#x2F;a&gt; interviewed &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;ericbmerritt&quot;&gt;Eric Merritt&lt;&#x2F;a&gt;, author of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.manning.com&#x2F;logan&#x2F;&quot;&gt;Erlang and OTP in Action&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;joxa.org&#x2F;&quot;&gt;Joxa&lt;&#x2F;a&gt; (a small semantically clean, functional lisp running on the Erlang VM), &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;erlware&#x2F;relx&quot;&gt;relx&lt;&#x2F;a&gt; (best release creation tool in Erlang).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-XCrgX6wctMhx0GLjNQS9nw.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In the following weeks we will be talking with Robert Virding — Erlang co-inventor and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;lfe.io&#x2F;&quot;&gt;Lisp Flavored Erlang&lt;&#x2F;a&gt; creator — , &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;puffnfresh&quot;&gt;Brian McKenna&lt;&#x2F;a&gt; —&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;puffnfresh&#x2F;roy&quot;&gt;Roy&lt;&#x2F;a&gt; language creator— and with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mirage.io&#x2F;&quot;&gt;MirageOS unikernel&lt;&#x2F;a&gt; dev team. Stay tuned!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;In the Functional Geekery podcast you stated that the Erlang VM (BEAM) is brilliant. What did it get right that other VMs did not?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.functionalgeekery.com&#x2F;episode-20-eric-b-merritt&#x2F;&quot;&gt; Functional Geekery Episode 20 - Eric B. MerrittIn this episode I talk with Eric Merritt. We talk about his background in Erlang, static typing and using OCaml, as…www.functionalgeekery.com&lt;img src=&quot;https:&#x2F;&#x2F;cdn-images-1.medium.com&#x2F;fit&#x2F;c&#x2F;160&#x2F;160&#x2F;0*ssE1kmVx69o3l2qd.&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;BEAM is the only reasonably popular VM that took the language model, in this case Actors, and leveraged that model to make the platform itself more efficient. I find that brilliant. The two major examples of that approach in BEAM are how the Garbage Collector works with the runtime and how IO works.&lt;&#x2F;p&gt;
&lt;p&gt;In many systems, Java included, the Garbage Collector (GC) must examine the entire heap in order to collect all the garbage. There are optimizations to this, like using Generations in a Generational GC, but those optimizations are still just optimizations for walking the entire heap. BEAM takes a different approach, leveraging the actor model on which it is based. That approach basically has the following tenets:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;If a process hasn’t been run, it doesn’t need to be collected&lt;&#x2F;li&gt;
&lt;li&gt;If a process has run, but ended before the next GC run, it doesn’t need&lt;br &#x2F;&gt;
to be collected&lt;&#x2F;li&gt;
&lt;li&gt;If, in the end, the process does need to be collected, only that&lt;br &#x2F;&gt;
single process needs to be stopped while collection occurs&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Those three tenets are one of the primary reasons that Erlang can be a soft-real time system &lt;em&gt;[&lt;&#x2F;em&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;jlouisramblings.blogspot.com.ar&#x2F;2013&#x2F;01&#x2F;how-erlang-does-scheduling.html&quot;&gt;Elang has a preemptive scheduler that also plays big a part for this&lt;&#x2F;a&gt; &lt;em&gt;]&lt;&#x2F;em&gt;. The fact that the model subsets the work that the GC has to do allows that work to remain small and manageable. Its an impressive achievement.&lt;&#x2F;p&gt;
&lt;p&gt;Another big win for the BEAM and its approach to leveraging Erlang’s Actor model is that it leverages low level, efficient, non-blocking asyncronous IO primitives from the operating system to do IO, but presents a comfortable blocking interface to the language layer. Developers using the platform can use a very human understandable synchronous IO primitives while gaining all the advantages of asyncronous IO. This too, is an impressive achievement. I just gave a talk on this topic for the Seattle Scalability Meetup:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Apart from the Erlang VM (BEAM), what do you think about Erlang as a language?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I think it’s not a bad language. It has the benefit of being both very declarative and very simple. That is a big win in distributed systems where complexity composes and quickly becomes unmanagable. I tend to prefer languages with an algebraic type system and a type inferencing and reasonable meta programming capabilities. Erlang has neither and that’s unfortunate. That said, I have implemented a large number of very reliable systems in Erlang and wouldn’t hesitate to do so again.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;You implemented Joxa, a Lisp for the Erlang VM. Why did you do it?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;For a while there I was working on a problem that was best solved via a suite of DSLs. The platform we built for that was based on Erlang and BEAM, but Erlang doesn’t really lend itself to DSLs. So I decided to write Joxa to facilitate DSL development on the BEAM. It just so happens that creating DSLs for problems is a generally good idea and that makes Joxa a decent general purpose language.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What is your opinion about LFE (Lisp Flavored Erlang)?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Joxa took a very different direction than LFE, even though LFE predated it by quite some time. When I ran into the problem that caused Joxa to be created, I investigated it rather deeply to see if it would solve the problem. I ran into a few issues while I was investigating it. In general, I found the implementation very hard to follow. It’s not a bad implementation, it’s just so different from the way I think about languages that it confounded me. That made it difficult for me to expand it.&lt;&#x2F;p&gt;
&lt;p&gt;I was also looking for something with simple semantics that I could build other languages on. LFE is, quite literally, Lisp Flavored Erlang. It is Erlang with S-expression based syntax. That’s not a problem unless you are looking for something with much lower level syntax to build upon. Finally, and this really is a nitpick, Macros are interpreted by LFE and that interpreter is very limited. The rest of the language is interpreted by BEAM. Having to remember if something was going to be run inside the macro interpreter or inside of the normal runtime bothered me a lot.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;And what do you think about Elixir?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I think Elixir has brought a lot of people to the Erlang world that wouldn’t have otherwise come over. That is a very good thing and a powerful contribution to the Erlang eco-system. However, I am not a big fan of Elixir itself. I find the macro system to be a bit inconsistent and I really dislike that Elixir tries to hide immutability. That does make it slightly easier for beginners, but it’s a leaky abstraction. The immutability eventually bleeds through and then you have to think about it. It also introduces additional complexity within bindings in Elixir Macros among other things. It doesn’t help that I have never been a fan of Ruby syntax and Elixir borrows heavily from that sphere.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What do you think about laziness in programming languages? In which cases do you think it is useful, if any?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I love lazyness in concept. I think the idea that computation only occurs when it’s needed is right in line with the trend that has been occurring in functional programming for many decades. The problem that I have with lazyness is more pragmatic. It is very easy to create space leaks and, as of this writing, good tools to detect and debug those space leaks don’t yet exist. That makes me very hesitant to use a language that is lazy by default in production. The Haskell guys are working hard to resolve this, and I think they will, but they haven’t yet.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why do you like Hindley–Milner type system? [the type system used in the ML family (Standard ML, Caml, OCaml, F#) and Haskell]&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-TKFIhHLhfGTz5uMBn6NfkQ.png&quot; alt=&quot;&quot; &#x2F;&gt; Image stolen from &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;learnyousomeerlang.com&#x2F;&quot;&gt;http:&#x2F;&#x2F;learnyousomeerlang.com&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Essentially, it’s because I am lazy. Much like resource management, contract management is a slow, manual painful process. By contract management, I mean verifying that the form of data a function recieves is the form of data that it expects. A Hindley-Milner style type system allows me to offload that tedious work to the compiler. Computers are essentially better at that kind of tedious work than humans.&lt;&#x2F;p&gt;
&lt;p&gt;A type system like this is just an evolution of our ongoing effort to offload work to the computer. Originally, we wrote in machine code, then we moved up to Assembly, which was one step higher. Not long after we started using higher level languages like Fortran, Cobol and Lisp. A bit later on we started offloading resource management to the computer as well in the form of GC. An algebraic type system is just a continuation of that. With this type system we are offloading contract checking to the computer. Just like with resource management the contract checking must happen, its just that many languages force the human to do it when the compiler can do it much more effectively.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Do you think that it would be possible to create a language with a Hindley Milner type system for the Erlang VM without affecting the power of Erlang semantics?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Not only do I think its possible, I have been planning to do it for a while now, time being the limiting factor. The main problem you will run into is the mismatch between the untyped bits of the Erlang native system and the typed bits of the new language. Dialyzer attempts to solve this through Success Typing, but there may be a better way. Something like what &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;roy.brianmckenna.org&#x2F;&quot;&gt;Roy&lt;&#x2F;a&gt; [programming languages that tries to meld JavaScript semantics with some features common in static functional languages] is doing in its type system or &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;clojure&#x2F;core.typed&quot;&gt;Clojure’s core.typed&lt;&#x2F;a&gt;. I am not sure, but it’s a fun and solvable problem.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Do you think it would be worthwhile adding algebraic data types to the Erlang VM? Or is using records (Erlang, Joxa) and tagged maps (Elixir) enough for all practical purposes?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Type systems have very little to do with the VM and very much to do with the language. That is, it’s usually a compile time thing rather than a runtime thing. It might actually be useful to add, simply so that BEAM can take advantage of the type annotations to run more optimized versions of the code, but it’s not especially helpful to the efforts to run a well typed language on top of the VM.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;In the past we had to create a few clients and console applications. Python and Ruby were great for building them quickly. However not being able to easily generate standalone binaries for each OS and architecture is a shortcoming of those languages. We are testing Nim and Go since they have good cross compilation and library support. Have you tried them? Could OCaml be a good alternative?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I have not tried either Nim or Go unfortunately. I have used Python extensively and Ruby as well, though to a lesser extent. I have also used OCaml extensively for these types of work and I find that I like OCaml the best. I like it for all the reasons I talked about above. That said, it is very different from other shell programming approaches and takes a bit of getting used to. I should also note that the vast majority of my work with OCaml has been in conjunction with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;janestreet.github.io&#x2F;&quot;&gt;Jane Street Capital’s Core and Async libraries&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What other languages or technologies are you keeping an eye on that we should check?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I haven’t seen any new languages pop up recently that have grabbed my interest. On technologies, I think that microkernels are very, very interesting. Things like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;osv.io&#x2F;&quot;&gt;OSv&lt;&#x2F;a&gt; for the JVM based languages, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;mirage.io&#x2F;&quot;&gt;Mirage&lt;&#x2F;a&gt; for OCaml and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;rumpkernel.org&#x2F;&quot;&gt;BSD Rump Kernels&lt;&#x2F;a&gt; for the rest. I think those are going to become the fundamental building block of &lt;strong&gt;system orchestration&lt;&#x2F;strong&gt; in the very near future. The other thing to keep an eye on is the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;nixos.org&#x2F;nix&#x2F;&quot;&gt;Nix Package manager&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;nixos.org&#x2F;&quot;&gt;NixOS&lt;&#x2F;a&gt;, and technologies like Atlas from Hashicorp. It’s not going to be too much longer before we declaratively describe out systems as well as our code. I am looking forward to that.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>The eleventh year: what to do after having taught yourself programming in ten years</title>
          <pubDate>Sun, 11 Jan 2015 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/the-eleventh-year-what-to-do-after-having-taught-yourself-programming-in-ten-years/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/the-eleventh-year-what-to-do-after-having-taught-yourself-programming-in-ten-years/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/the-eleventh-year-what-to-do-after-having-taught-yourself-programming-in-ten-years/">&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2025&#x2F;12&#x2F;1-ITiI4UpZDr3uVhpAqtmzIw.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;You have followed the “&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;norvig.com&#x2F;21-days.html&quot;&gt;Teach Yourself Programming in Ten Years&lt;&#x2F;a&gt;” advice. Now what?&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-oNMoLW1PYnEIcHQaHkDD_w.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;strong&gt;“when you don’t create things, you become defined by your tastes rather than ability. your tastes only narrow &amp;amp; exclude people. so create.”―&lt;&#x2F;strong&gt;&lt;strong&gt;&lt;strong&gt;Why The Lucky  Stiff&lt;&#x2F;strong&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Christmas and the new year’s eve have passed. Now you are a few kilograms fatter. You have spent the last few days reading Hacker News and Reddit and playing League of Legends or GTA V for the PS4. Finally, even if you will never accomplish all of them, you know that it is time to write your goals for this new year.&lt;&#x2F;p&gt;
&lt;p&gt;After working for more than a decade in IT as a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;blog.codinghorror.com&#x2F;vampires-programmers-versus-werewolves-sysadmins&#x2F;&quot;&gt;programmer and sysadmin&lt;&#x2F;a&gt; I know that I am nothing more than an &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.paulgraham.com&#x2F;avg.html&quot;&gt;average&lt;&#x2F;a&gt; developer or &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;zedshaw.com&#x2F;archive&#x2F;the-master-the-expert-the-programmer&#x2F;&quot;&gt;novice&lt;&#x2F;a&gt; that knows a little bit of many things. After developing for quite some time in C, C++, Ruby, Python and Javascript I wanted to move on to something else. I was bored. Thankfully, working with Erlang for a year and a half introduced me to the amazing world of functional programming, distributed systems, parallalelism and concurrency, and there is no way of going back. &lt;a href=&quot;&#x2F;languages-i-want-to-learn-and-use-this-2014&#x2F;&quot;&gt;Erlang also led me to the Haskell and Lisp&#x2F;Clojure&lt;&#x2F;a&gt; world. I found Haskell, with its awesome &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;book.realworldhaskell.org&#x2F;read&#x2F;using-parsec.html&quot;&gt;Parsec&lt;&#x2F;a&gt; parser combinator library, at the bottom of the rabbit hole of compilers and programming language design. Finally, Lisp was the selling point that made me migrate from vim to emacs.&lt;&#x2F;p&gt;
&lt;p&gt;In this post I try to to share my goals of this year for myself, so that I can check them next year to measure the outcame of 2015. I really hope that you can find an interesting link or at least that it encourages you to write your 2015 goals so that next year you can check how much improvement you have made!&lt;&#x2F;p&gt;
&lt;h3 id=&quot;cleaning-up-my-closet&quot;&gt;&lt;strong&gt;Cleaning up my closet&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;gut&quot;&gt;gut&lt;&#x2F;h4&gt;
&lt;p&gt;First of all I need to finish my project &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;unbalancedparentheses&#x2F;gut&quot;&gt;gut&lt;&#x2F;a&gt; (pronounced ‘goot’, short for ‘gutenberg’). gut is a template printing, aka scaffolding, tool for Erlang. It is like rails generate or yeoman. I have created it because in my last job I did something that most Erlang developers that I know don’t do very often: creating projects from scratch. Erlang applications have many setup files: rebar.config, Makefile, erlang.mk, project.app.src, rel&#x2F;sys.config, config&#x2F;vm.args and tipically a project_app.erl and project_sup.erl. Creating this every time you need to create a new project for a new customer is pretty boring and overwhelming if you are a newcomer. So I created gut, a tool that uses project generators to instantiate a new project. Generators can be created by any user, and I do not need to add them to gut: anybody can use them since gut fetches them from github.&lt;&#x2F;p&gt;
&lt;p&gt;rebar3, the latest Erlang build tool, has a similar concept called &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.rebar3.org&#x2F;v1.0&#x2F;docs&#x2F;using-templates&quot;&gt;template&lt;&#x2F;a&gt;. I was not aware of this when I created gut. I will try to change gut so that gut generators are fully compatible with rebar3 templates. In some way, rebar3 templates solve the same problem that gut does. However, gut can automatically download on demand any generator&#x2F;template available in github to instantiate a new project.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;tinyerl&quot;&gt;tinyerl&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;unbalancedparentheses&#x2F;tinyerl&quot;&gt;tinyerl&lt;&#x2F;a&gt; is a really small project to show how easy it is to create a URL shortener service in Erlang using different HTTP servers such as cowboy, axiom, elli and leptus. It is meant to teach Erlang. I only need to polish it a little bit and update &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;erlang-lisp-and-haskell&#x2F;become-an-erlang-cowboy-and-tame-the-wild-wild-web-part-i-37f8dd1df160&quot;&gt;Become an Erlang Cowboy and tame the Wild Wild Web — Part I&lt;&#x2F;a&gt; before writing Part II which will be based on tinyerl.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;lunfardo&quot;&gt;lunfardo&lt;&#x2F;h4&gt;
&lt;p&gt;Like most devs, I have tested and used many IDEs: Eclipse, Netbeans, Xcode, Visual Studio, IntelliJ IDEA, RubyMine, PyCharm, Code::Blocks, Aptana. Nevertheless, for the last few years I could never move away from the combination of a good shell like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;fishshell.com&#x2F;&quot;&gt;fish&lt;&#x2F;a&gt; with a good configuration like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bpinto&#x2F;oh-my-fish&quot;&gt;oh my fish&lt;&#x2F;a&gt;, a customized vim based on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;vim.spf13.com&#x2F;&quot;&gt;spf13&lt;&#x2F;a&gt; distribution, and the simple but great &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;dwm.suckless.org&#x2F;&quot;&gt;dwm&lt;&#x2F;a&gt; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Tiling_window_manager&quot;&gt;tiling window manager&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;After reading &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.defmacro.org&#x2F;ramblings&#x2F;lisp.html&quot;&gt;The Nature of Lisp&lt;&#x2F;a&gt; I have been interested in using Lisp but I never invested enough time to really play with it. After watching a coworker use Emacs and a few good ruby minor modes, I started using Emacs and its Elisp. Emacs is like a mini operating system. It has a package manager, the best &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;magit&#x2F;magit&quot;&gt;git client&lt;&#x2F;a&gt; I have used, great modes like paredit…&lt;&#x2F;p&gt;
&lt;p&gt;swank-js for editing Javascript…&lt;&#x2F;p&gt;
&lt;p&gt;and undo-tree for treating history as tree.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-xcDvxVvdrTYMR_WMunTlqw.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This video shows really well how easy it is to hack with Emacs and lisp:&lt;&#x2F;p&gt;
&lt;p&gt;The only issue I had with Emacs is that I like modal editing á la Vi. Hopefully, Emacs has a great mode called &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;bling.github.io&#x2F;blog&#x2F;2013&#x2F;10&#x2F;27&#x2F;emacs-as-my-leader-vim-survival-guide&#x2F;&quot;&gt;evil&lt;&#x2F;a&gt; that transforms Emacs into the best Vim editor after Vim.&lt;&#x2F;p&gt;
&lt;p&gt;Inspired by bbatsov’s &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bbatsov&#x2F;prelude&quot;&gt;Prelude&lt;&#x2F;a&gt; distribution, I coded my own distribution called &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;unbalancedparentheses&#x2F;lunfardo&quot;&gt;lunfardo&lt;&#x2F;a&gt;. It’s still in alpha stage. I am not yet a great Elisp coder and I keep on adding and removing modes and shortcuts. I have not yet commited the code for managing most of the programming languages I use (Python, Ruby, Javascript, Erlang, C, Haskell).&lt;&#x2F;p&gt;
&lt;p&gt;I am already used to all the Emacs shortcuts but I don’t really like them. So I am changing most of them into more modern ones. The final objective is to use Emacs as the platform, with defaults shortcuts based on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.sublimetext.com&#x2F;&quot;&gt;Sublime&lt;&#x2F;a&gt; and with a shortcut to quickly toggle on and off vim modal editing. We will see how it works out, I am quite excited about it but I am not completely sure that it is possible to easily change everthing I want in Emacs (specially some shorcuts). So I wouldn’t recommend to test lunfardo yet since it will break very often, but I am pretty sure you can find a few cool ideas and modes.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;spawned-shelter&quot;&gt;Spawned Shelter&lt;&#x2F;h4&gt;
&lt;p&gt;Finally, this year I started acollection of the best articles, videos and presentations related to Erlang called &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;unbalancedparentheses&#x2F;spawnedshelter&quot;&gt;Spawned Shelter&lt;&#x2F;a&gt;. I wanted to create a static web page like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;superherojs.com&#x2F;&quot;&gt;Superhero.js&lt;&#x2F;a&gt; for Erlang but I have been way to busy. I am pretty sad since I could not do it yet. Before the end of this year I am completely sure that it will be finished.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;distributed-systems&quot;&gt;Distributed systems&lt;&#x2F;h3&gt;
&lt;p&gt;Using Erlang, Apache &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;planetcassandra.org&#x2F;what-is-apache-cassandra&#x2F;&quot;&gt;Cassandra&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;highscalability.com&#x2F;zookeeper-reliable-scalable-distributed-coordination-system&quot;&gt;Zookeeper&lt;&#x2F;a&gt; in my last project was the final step I needed to take to be fully interested by distributed systems. I can not be more thankfull to my previous employer (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;inaka.net&#x2F;&quot;&gt;Inaka&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.erlang-solutions.com&#x2F;&quot;&gt;Erlang Solutions&lt;&#x2F;a&gt;) for giving me the oportunity to work with those tools and to learn from great teammates and our CTO &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elbrujohalcon&quot;&gt;Brujo&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;book.mixu.net&#x2F;distsys&#x2F;&quot;&gt;Distributed systems for fun and profit&lt;&#x2F;a&gt; mini book was the best place for me to start reading about this topic. Christopher Meiklejohn’s &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;christophermeiklejohn.com&#x2F;distributed&#x2F;systems&#x2F;2013&#x2F;07&#x2F;12&#x2F;readings-in-distributed-systems.html&quot;&gt;reading list&lt;&#x2F;a&gt; also seems very good but isn’t a good place to start without knowing a few things before.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, Aphyr’s &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;aphyr.com&#x2F;tags&#x2F;Jepsen&quot;&gt;posts&lt;&#x2F;a&gt; and talks are also an excellent place where to learn from:&lt;&#x2F;p&gt;
&lt;p&gt;After reading about and playing with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;basho.com&#x2F;riak&#x2F;&quot;&gt;Riak&lt;&#x2F;a&gt;, I have already decided that in the next work project where I need to use a distributed database or a key-value store I will give it a try. In the process of reading about Riak, I found &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;basho&#x2F;riak_core&quot;&gt;Riak Core&lt;&#x2F;a&gt;, a toolkit for building distributed, scalable, fault-tolerant applications. Before giving it a try I want to implement something like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rzezeski&#x2F;try-try-try&quot;&gt;try-try-try&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Next I want to implement Plan9 &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;@jlouis666&#x2F;eventi-ffd423d82b35&quot;&gt;venti&lt;&#x2F;a&gt;, a network storage system were a hash of the data acts as its address, using riak and Erlang. It won’t be very different from &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;@jlouis666&#x2F;&quot;&gt;Jesper L. Andersen&lt;&#x2F;a&gt;’s &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jlouis&#x2F;eventi&quot;&gt;code&lt;&#x2F;a&gt;, but my objective is to learn, not to create something new.&lt;&#x2F;p&gt;
&lt;p&gt;I hope I will have some spare time to play with the following list of interesting Erlang libraries: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jlouis&#x2F;fuse&quot;&gt;fuse&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jlouis&#x2F;safetyvalve&quot;&gt;safetyvalve&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ferd&#x2F;dispcount&quot;&gt;dispcount&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;inaka&#x2F;worker_pool&quot;&gt;worker_pool&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;duomark&#x2F;epocxy&quot;&gt;epocxy&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ferd&#x2F;pobox&quot;&gt;pobox&lt;&#x2F;a&gt;, and to read the latest book from &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;ferd.ca&#x2F;&quot;&gt;Fred Hébert&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.erlang-in-anger.com&#x2F;&quot;&gt;Stuff Goes Bad: Erlang in AngerThis book intends to be a little guide about how to be the Erlang medic in a time of war. It is first and foremost a…www.erlang-in-anger.com&lt;img src=&quot;https:&#x2F;&#x2F;cdn-images-1.medium.com&#x2F;fit&#x2F;c&#x2F;160&#x2F;160&#x2F;0*nevqmTdZyE2QPpJN.&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;programming-languages&quot;&gt;Programming Languages&lt;&#x2F;h3&gt;
&lt;p&gt;After going through the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.coursera.org&#x2F;course&#x2F;proglang&quot;&gt;Programming Languages&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.coursera.org&#x2F;course&#x2F;compilers&quot;&gt;Compilers&lt;&#x2F;a&gt; Coursera courses I become more interested by programming language design and implementation. Then I started experimenting with and reading about &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Lexical_analysis&quot;&gt;lexical analysis&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Compiler-compiler&quot;&gt;parser generators&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.garshol.priv.no&#x2F;download&#x2F;text&#x2F;bnf.html&quot;&gt;BNF grammar&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;trevorjim.com&#x2F;how-to-prove-that-a-programming-language-is-context-free&#x2F;&quot;&gt;context free grammar&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;blog.reverberate.org&#x2F;2013&#x2F;07&#x2F;ll-and-lr-parsing-demystified.html&quot;&gt;LL and LALR&lt;&#x2F;a&gt; parsing, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;gnuu.org&#x2F;2009&#x2F;09&#x2F;18&#x2F;writing-your-own-toy-compiler&#x2F;&quot;&gt;flex and bison&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.hwaci.com&#x2F;sw&#x2F;lemon&#x2F;lemon.html&quot;&gt;lemon&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.antlr.org&#x2F;&quot;&gt;antlr&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.colm.net&#x2F;open-source&#x2F;ragel&#x2F;&quot;&gt;ragel&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;bnfc.digitalgrammars.com&#x2F;&quot;&gt;bnfc&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;morepypy.blogspot.it&#x2F;2011&#x2F;04&#x2F;tutorial-writing-interpreter-with-pypy.html&quot;&gt;rpython&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;tmcnab.github.io&#x2F;Hyperglot&#x2F;&quot;&gt;hyperglot&lt;&#x2F;a&gt; and how &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;trevorjim.com&#x2F;parsing-is-the-weakest-link&#x2F;&quot;&gt;parsing is the weakest link in software security&lt;&#x2F;a&gt;!&lt;&#x2F;p&gt;
&lt;p&gt;After reading all that, I needed to get my hands dirty so I followed &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.buildyourownlisp.com&#x2F;contents&quot;&gt;Build Your Own Lisp&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;createyourproglang.com&#x2F;&quot;&gt;Create Your Own Programming Language&lt;&#x2F;a&gt;. In the process I got really interested by the simplicity of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;plataforma10.com&#x2F;login&quot;&gt;Parsec&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;fdik.org&#x2F;pyPEG&#x2F;&quot;&gt;PEG parsers&lt;&#x2F;a&gt; (saddly they have some important &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;1857022&#x2F;limitations-of-peg-grammar-parser-generators&quot;&gt;limitations&lt;&#x2F;a&gt;). Its worth mentioning that I found Parsec while reading the mind-blowing book &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;book.realworldhaskell.org&#x2F;read&#x2F;&quot;&gt;Real World Haskell&lt;&#x2F;a&gt;. You should check &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bitemyapp&#x2F;learnhaskell&quot;&gt;learnhaskell&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;JakeWheat&#x2F;intro_to_parsing&quot;&gt;intro_to_parsing&lt;&#x2F;a&gt; if you are interested by Haskell and Parsec.&lt;&#x2F;p&gt;
&lt;p&gt;One of my goals for this year is to start writing my own programming language using &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.stephendiehl.com&#x2F;llvm&#x2F;&quot;&gt;Haskell and LLVM&lt;&#x2F;a&gt;. Before that I am doing something easier: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikibooks.org&#x2F;wiki&#x2F;Write_Yourself_a_Scheme_in_48_Hours&quot;&gt;Write Yourself a Scheme in 48 Hours&lt;&#x2F;a&gt;, which also uses Haskell. Obviously, I am not trying to create the next programming language. That might even be impossible until programming language design is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;@jlouis666&#x2F;proglang-design-with-evidence-1444213f3902&quot;&gt;done based on more real evidence&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Someday I hope that I can implement an Erlang clone that runs on the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;jlouisramblings.blogspot.com.ar&#x2F;2013&#x2F;10&#x2F;embrace-copying.html&quot;&gt;really&lt;&#x2F;a&gt; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;jlouisramblings.blogspot.com.ar&#x2F;2013&#x2F;01&#x2F;how-erlang-does-scheduling.html&quot;&gt;awesome&lt;&#x2F;a&gt; BEAM VM, but that uses indentation á la Python as a way to delimit blocks of code instead of “&lt;strong&gt;,&lt;&#x2F;strong&gt; ”&lt;strong&gt;,&lt;&#x2F;strong&gt; “&lt;strong&gt;;&lt;&#x2F;strong&gt; ” and “.”. It would be a sort of exact copy of Erlang but without its Prolog terminators. Apparently this has &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;farmdev.com&#x2F;thoughts&#x2F;47&#x2F;making-erlang-indentation-sensitive&#x2F;&quot;&gt;already&lt;&#x2F;a&gt; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;ulf.wiger.net&#x2F;weblog&#x2F;2008&#x2F;03&#x2F;19&#x2F;indentation-sensitive-erlang&#x2F;&quot;&gt;been&lt;&#x2F;a&gt; &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;ulf.wiger.net&#x2F;weblog&#x2F;2008&#x2F;03&#x2F;20&#x2F;indentation-sensitive-erlang-2&#x2F;&quot;&gt;done&lt;&#x2F;a&gt; by Ulf Wiger but I would like to do it with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;relops.com&#x2F;blog&#x2F;2014&#x2F;01&#x2F;13&#x2F;leex_and_yecc&#x2F;&quot;&gt;leex and yecc&lt;&#x2F;a&gt;, the lex and yacc of the Erlang toolset, which are used for example by &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rvirding&#x2F;luerl&quot;&gt;luerl&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rvirding&#x2F;lfe&quot;&gt;lfe&lt;&#x2F;a&gt;. Mariano Guerra has implemented a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;marianoguerra&#x2F;match&quot;&gt;toy language&lt;&#x2F;a&gt;, which is incredible useful for learning purposes, using leex and yecc before implementing efene, a programming language with C-like syntax that runs on the Erlang platform.&lt;&#x2F;p&gt;
&lt;p&gt;Since I am noob in this area and I like to share what I learn I will continue interviewing language developers and good devs for my &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;indie-programming-languages&quot;&gt;Indie Programming Languages&lt;&#x2F;a&gt; collection. I will publish two interviews in the following weeks. In the meanwhile you can read:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;p&#x2F;cadbc36418dc&quot;&gt;Indie languages — Interview with Timothy Baldridge, Pixie’s language creatorPlease tell us a little bit about Pixie’s inception and the road to the current status I’ve been a language hacker for…medium.com&lt;img src=&quot;&#x2F;images&#x2F;fit&#x2F;c&#x2F;160&#x2F;160&#x2F;1-jYqNf1VQpmxhv7WwkPm1Ag.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;do-you-need-a-cool-project&quot;&gt;Do you need a cool project?&lt;&#x2F;h3&gt;
&lt;p&gt;I won’t be able to do it this year, but I hope that next year I will be able to go through Linux From Scratch’s &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.linuxfromscratch.org&#x2F;lfs&#x2F;&quot;&gt;guide&lt;&#x2F;a&gt; and the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;littleosbook.github.io&#x2F;&quot;&gt;little book about OS development&lt;&#x2F;a&gt; to scratch the surface of how operating systems work.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;this-is-the-end-my-only-friend-the-end&quot;&gt;This is the end, my only friend, the end&lt;&#x2F;h3&gt;
&lt;p&gt;As you have read, in my free time I am not trying to code anything groundbreaking. For the moment I am only interested in exploring how things work.&lt;&#x2F;p&gt;
&lt;p&gt;Even if this is not your eleventh year in the world of development and you are pretty new, I cannot stress enough how much functional programming will open your mind. At least in my case it has been a mind-blowing experience since it has opened me the hell’s gate of distributed systems and programming languages implementation and design. Someday it might be time to return to the old and powerful C, but not yet…&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-zIUcPGRK3us1N3oFwJ8y5w.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Interview with Timothy Baldridge, Pixie’s language creator</title>
          <pubDate>Mon, 08 Dec 2014 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/indie-languages-interview-pixie-and-timothy-baldridge/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/indie-languages-interview-pixie-and-timothy-baldridge/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/indie-languages-interview-pixie-and-timothy-baldridge/">&lt;p&gt;We interviewed &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;timbaldridge&quot;&gt;Timothy Baldridge&lt;&#x2F;a&gt;, creator of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;pixie-lang&#x2F;pixie&quot;&gt;Pixie&lt;&#x2F;a&gt;, a small fast, native lisp with &lt;em&gt;magical&lt;&#x2F;em&gt; powers. We hope you try it out!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-jYqNf1VQpmxhv7WwkPm1Ag.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;“In modern use, Pixie can be synonymous with fairies or sprites”&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Please tell us a little bit about Pixie’s inception and the road to the current status.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-s4cstPwICRsq-gb1zJ261Q.jpeg&quot; alt=&quot;&quot; &#x2F;&gt; Timothy Baldridge&lt;&#x2F;p&gt;
&lt;p&gt;I’ve been a language hacker for years, and have played around with RPython (PyPy’s tool-chain) for some time. I’ve always had it in the back of my head that a lisp on RPython would be a good project. But it seems like this time it’s really taken off.&lt;&#x2F;p&gt;
&lt;p&gt;I started the project about 3 months ago, and by now it’s grown quite a bit. The standard library is about to hit 2000 loc (lines of code), and we have about half a dozen contributors. Not bad for only a few months work.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why a new language? Is Pixie an exercise in language design, an attempt to build a language to target production code or is that still to be determined?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
There are a few experiments I’ve tried at different times in Pixie’s lifecycle, but at this point I’m really aiming for Pixie to be a “Python-esque lisp”. That is to say, if you’re doing lightweight scripting, or want something that boots fast and runs well on low-end systems, Pixie might be a good fit. Basically I want it for all those times I’d reach for Python instead of Clojure.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What are Pixie’s main features?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;It’s a lisp.&lt;&#x2F;li&gt;
&lt;li&gt;It stresses the use of immutable data structures.&lt;&#x2F;li&gt;
&lt;li&gt;It’s not hosted on the CLR, JVM or any other pre-existing VM.&lt;&#x2F;li&gt;
&lt;li&gt;It’s quite fast as it includes a tracing JIT.&lt;&#x2F;li&gt;
&lt;li&gt;FFI (&lt;em&gt;Foreign Function Interface&lt;&#x2F;em&gt;&lt;strong&gt;)&lt;&#x2F;strong&gt; support is currently quite primitive, but FFI on par with Python’s ctypes or Lua’s FFI are planned and in the works.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;What is the reason behind including transducers from the start?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Much of what is needed for a robust run-time can be built with transducers. Operations such as hashing a collection, converting a collection to a string, or even comparing two collections, can be built with transducers. And since the JIT produced by RPython is a tracing (instead of a method) JIT, transducers are extremely efficient, often faster than transducers implemented in other languages.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why would developers choose Pixie? Who are Pixie’s target users?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
If you like Clojure, but are unhappy with the start-up time, or if you want something outside of the JVM ecosystem, then Pixie may be for you. For much of my work Clojure is a perfect choice, but once in a while I find myself reaching for a lighter language, like Python. Hopefully Pixie will allow me to stay in a Lisp in those situations as well.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why did you implement it in Python?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Technically I implemented Pixie in RPython, which is a subset of Python that can be compiled to C with the PyPy translation tool-chain. The reason I chose RPython instead of C really comes down to the PyPy tool-chain’s feature set. Namely it supports a GC out-of-the-box, and if you write an interpreter in RPython you can put a few hints in the code, and it’ll spit out a JIT for that interpreter. This has saved me countless hours of work.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;How does Pixie compare to Clojure?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Since Pixie implements its own VM, it’s different in many ways. We don’t claim that Pixie is a “Clojure port”, as that locks us into following Clojure in all ways. Instead we take inspiration from Clojure, keep what we like, discard what we don’t, and improve what we can.&lt;&#x2F;p&gt;
&lt;p&gt;Performance-wise, Pixie can be faster than Clojure in some areas, mostly around boxing, as Pixie can remove boxing in tight loops, even when using transducers, or other higher-order-functions. However our GC is way less mature than the JVM GC, so I wouldn’t expect it to out-perform Clojure in all (or even most) cases.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What can experienced Lisp users expect from Pixie?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
First, pixie is fast. Really fast. We can obtain the performance normally only found in a compiled language, while remaining completely dynamic. We also have a complete set of immutable data structures, including vectors and hash maps. So perhaps the best way to describe it is: Clojure with the lightweight feel of Python.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;When do you plan to release a stable version?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Thats TBD, probably not till early&#x2F;mid 2015 when the language stabilizes a bit. Also I’d like to release the first version with full support for Windows, something we haven’t even started yet.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Were there other experimental languages you worked on previous to Pixie?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Probably one of the best known projects was &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;halgari&#x2F;clojure-py&quot;&gt;clojure-py&lt;&#x2F;a&gt; which was a port of Clojure to the Python VM. But I’ve been working on languages most of my life. In fact, the first language I ever wrote was when I was in high-school. It was a small interpreted language named &lt;em&gt;PhaLinks&lt;&#x2F;em&gt; and was terrible, but I learned a lot from the effort. I also acquired a distaste for parsers in the process. Which, incidentally, is why I stick with Lisp these days: Lisp parsers are super easy to write.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Do you think that developing Pixie made you a better programmer?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Of course, if you’re not learning something every day of your life, you’re doing something wrong.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What difficulties are associated with designing a programming language from scratch?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
One of the biggest is figuring out the right balance between performance and desired features. Many times in the development of Pixie I’ve wanted to add a certain feature, but then found out that if I tweaked it a bit, it’d be much faster. So now there’s a choice to be made, do you have the perfect language, written exactly the way you want, or do you want something that performs much better, but is lacking some cool feature.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;What reading material do you recommend for implementing your first programming language?&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
I recommend googling for tutorials like “writing a Lisp in X” or “writing a simple Forth”, and going from there. Also, read the source code from other languages. I learned most of what I know of language development simply by reading papers online, and studying source code of existing projects.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Become an Erlang Cowboy and tame the Wild Wild Web — Part I</title>
          <pubDate>Wed, 18 Jun 2014 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/become-an-erlang-cowboy-and-tame-the-wild-wild-web-part-i/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/become-an-erlang-cowboy-and-tame-the-wild-wild-web-part-i/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/become-an-erlang-cowboy-and-tame-the-wild-wild-web-part-i/">&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2025&#x2F;12&#x2F;1-kQjlW-vovZA1YmfxPHC5YQ.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;erlang-from-zero-to-coding-a-commenting-system&quot;&gt;Erlang: From zero to coding a commenting system&lt;&#x2F;h4&gt;
&lt;hr &#x2F;&gt;
&lt;h4 id=&quot;objective&quot;&gt;Objective&lt;&#x2F;h4&gt;
&lt;p&gt;In the following series of posts we will be creating a commenting system like &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;disqus.com&#x2F;&quot;&gt;http:&#x2F;&#x2F;disqus.com&#x2F;&lt;&#x2F;a&gt;. The system will have normal HTTP&#x2F;REST handlers but also some SSE and websockets handlers, and background jobs for uploading images to Amazon S3 and sending push notifications to iOS and Android clients via Amazon SNS. At the end of the series, we will connect Erlang and the system with other programming languages for those tasks that can be more difficult to do with Erlang.&lt;&#x2F;p&gt;
&lt;p&gt;By no means will this be an attempt to create a new reference for learning the syntax, types and functions of the language. There are already three great books that cover that purpose:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Erlang Programming by Francesco Cesarini and Simon Thompson&lt;&#x2F;li&gt;
&lt;li&gt;Programming Erlang: Software for a Concurrent World — Joe Armstrong&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;learnyousomeerlang.com&#x2F;&quot;&gt;Learn you some Erlang for Great Good — Fred Hébert&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;At some point you will need to read them if you want to work with Erlang. My objective is to create a “Hands on Erlang” guide, and hopefully a small book, where we use the most important and useful Erlang concepts to create a working and real system so that you can see by yourself how highly scalable, concurrent, parallelizable, battleproof and especially how well designed the Erlang platform is. I separate the Erlang language from its plataform even if they are intertwined because you could change Erlang’s syntax or be using another language that runs on top of the BEAM like Elixir or LFE (Lisp Flavored Erlang) and still get almost all, if not all, of the Erlang benefits and even some mores. Don’t get me wrong. I really like the language per se. But its real power comes from its ecosystem and from the system in general. From my point of view, C++, Java, C#, Objective-C, Python, Ruby and even Javascript are very similar. Sure, they have different syntaxes and small different ways of doing the same thing. But you do not have to learn a new way of thinking when changing from one to another. You can learn the syntax of Erlang language in only a few hours but you will not be able to learn the concurrent&#x2F;fault tolerant paradigm in one day. Nobody learnt Object Oriented paradigm in that lapse of time. If you are looking to learn a new syntax or a new rails-like framework you have come to the wrong place.&lt;&#x2F;p&gt;
&lt;p&gt;If you are interested on moving out of your comfort zone, you have come to the right place. I will do my best to help you learn a new and different way of thinking and designing applications. The length of the journey however will depend entirely on your will. You will have to play, reimplement the same idea in different ways and obviously fight with a new compiler to conquer victory.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;audience&quot;&gt;Audience&lt;&#x2F;h4&gt;
&lt;p&gt;This series of posts is oriented towards developers that need to create backend servers that normally use languages and frameworks such as Python and Flask, Twisted, Celery; Ruby and Rails&#x2F;Sinatra&#x2F;Grape, Sidekiq&#x2F;Rescue, Concurrent Ruby with JRuby or Rubinius; Javascript with Nodejs, Express&#x2F;Koa or Go. I have worked with these technologies for some years, creating HTTP servers that produced JSON consumed by single page applications, iOS and Android clients. I was very comfortable with them. But for the last year I have been using Erlang, and even if I still like Ruby, Python and Javascript, I have no regrets when I say that Erlang is superior, in most areas, for building these types of systems.&lt;&#x2F;p&gt;
&lt;p&gt;My idea is to show how easily and cleanly you can create a distributed, resilient system thanks to Erlang semantics, its awesome BEAM virtual machine and some great libraries like Cowboy. If I cannot convince you to use Erlang on your next project, then I hope that at least you respect its awesome power.&lt;&#x2F;p&gt;
&lt;p&gt;On this first post I will show you some basic Erlang code so that in next one I can start working on the first handlers of our system.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;requirements&quot;&gt;Requirements&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;Erlang 17 installed. Check &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.erlang-solutions.com&#x2F;downloads&#x2F;download-erlang-otp&quot;&gt;Erlang Solutions downloads page&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;robots.thoughtbot.com&#x2F;back-to-basics-http-requests&quot;&gt;Basic http&lt;&#x2F;a&gt; knowledge&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Before starting I must say that I am very thankful to my employer —&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;inaka.net&#x2F;&quot;&gt;Inaka&lt;&#x2F;a&gt; — for letting me write part of these posts during my working hours.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-ugly-duckling&quot;&gt;The ugly duckling?&lt;&#x2F;h3&gt;
&lt;p&gt;Programming languages have a defined set of goals. Most of them put &lt;strong&gt;performance&lt;&#x2F;strong&gt; , &lt;strong&gt;developer expressiveness&lt;&#x2F;strong&gt; or &lt;strong&gt;developer productivity at the top of the list.&lt;&#x2F;strong&gt; Let’s see what they have to say about themselves so that we can compare with Erlang’s description:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Rust&lt;&#x2F;strong&gt; is a systems programming language that&lt;strong&gt;runs blazingly fast&lt;&#x2F;strong&gt; , &lt;strong&gt;prevents almost all crashes&lt;&#x2F;strong&gt; , and eliminates data races. — &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.rust-lang.org&#x2F;&quot;&gt;http:&#x2F;&#x2F;www.rust-lang.org&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Java&lt;&#x2F;strong&gt; is designed to enable development of portable, &lt;strong&gt;high-performance applications&lt;&#x2F;strong&gt; for the widest range of computing platforms possible. — &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.java.com&#x2F;en&#x2F;about&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.java.com&#x2F;en&#x2F;about&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-EPh-KvfabwINW5psttwbig.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Haskell&lt;&#x2F;strong&gt; is an advanced purely-functional programming language. An open-source product of more than twenty years of cutting-edge research, &lt;strong&gt;it allows rapid development of robust, concise, correct software&lt;&#x2F;strong&gt;. With strong support for integration with other languages, built-in concurrency and parallelism, debuggers, profilers, rich libraries and an active community, Haskell makes it easier to produce flexible, maintainable, high-quality software. — &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.haskell.org&#x2F;haskellwiki&#x2F;Haskell&quot;&gt;http:&#x2F;&#x2F;www.haskell.org&#x2F;haskellwiki&#x2F;Haskell&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Python&lt;&#x2F;strong&gt; is a programming language that lets you &lt;strong&gt;work quickly&lt;br &#x2F;&gt;
and integrate systems more effectively&lt;&#x2F;strong&gt;. — &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.python.org&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.python.org&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Ruby&lt;&#x2F;strong&gt; is a &lt;strong&gt;dynamic&lt;&#x2F;strong&gt; , open source programming language with a &lt;strong&gt;focus on simplicity and productivity&lt;&#x2F;strong&gt;. It has an &lt;strong&gt;elegant syntax that is natural to read and easy to write&lt;&#x2F;strong&gt;. — &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.ruby-lang.org&#x2F;en&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.&lt;strong&gt;ruby&lt;&#x2F;strong&gt; -lang.org&#x2F;en&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The only reliable plan is to design for performance. Performance doesn’t mean speed; that’s taking the metaphor too literally. Speed counts, but a programming language is first of all a tool for thinking in. We want thinking in &lt;strong&gt;Arc&lt;&#x2F;strong&gt; to&lt;strong&gt;feel like driving a 911.&lt;&#x2F;strong&gt; — &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.paulgraham.com&#x2F;design.html&quot;&gt;http:&#x2F;&#x2F;www.paulgraham.com&#x2F;design.html&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-ezjVLCDsv-Qur7C2BvhnsQ.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;strong&gt;&lt;strong&gt;1973 Porsche  911E&lt;&#x2F;strong&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;strong&gt;Go&lt;&#x2F;strong&gt; programming language is an open source project to &lt;strong&gt;make programmers more productive&lt;&#x2F;strong&gt;. Go is &lt;strong&gt;expressive, concise, clean, and efficient&lt;&#x2F;strong&gt;. Its concurrency mechanisms make it&lt;strong&gt;easy to write programs that get the most out of multicore and networked machines&lt;&#x2F;strong&gt; , while its novel type system enables**** flexible and modular program construction. Go compiles quickly to machine code yet has the convenience of garbage collection and the power of run-time reflection. It’s a &lt;strong&gt;fast, statically typed, compiled language that feels like a dynamically typed, interpreted language&lt;&#x2F;strong&gt;. — &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;golang.org&#x2F;doc&#x2F;&quot;&gt;http:&#x2F;&#x2F;golang.org&#x2F;doc&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Let’s see what Erlang has to say about itself:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Erlang&lt;&#x2F;strong&gt; is a programming language&lt;strong&gt;used to build massively scalable soft real-time systems with requirements on high availability.&lt;&#x2F;strong&gt; Some of its uses are in telecoms, banking, e-commerce, computer telephony and instant messaging. Erlang’s runtime system has built-in support for concurrency, distribution and fault tolerance. — &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.erlang.org&#x2F;&quot;&gt;http:&#x2F;&#x2F;www.erlang.org&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Erlang seems to be the ugly duckling compared to other programming languages since it doesn’t describe itself as being fast, clean or expressive.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-qV-Mz3gUxyM1Ug0XANoZgg.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Erlang was created for building fault-tolerant systems. This is natural since Erlang’s roots are in the telecommunication world. Most important design choices of the language were taken to fulfill this requirement. However this does not mean it is not clean or expressive. Let’s take a closer look.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;syntax&quot;&gt;Syntax&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;erlang&#x2F;otp&#x2F;blob&#x2F;maint&#x2F;lib&#x2F;stdlib&#x2F;src&#x2F;erl_parse.yrl#L-0-L-535&quot;&gt;Erlang grammar&lt;&#x2F;a&gt; is simple, it has less than 550 lines of code. That makes erlang syntax easy to understand even if it is different from mainstream languages. But what is more important it is really consistent. Enough talk:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;%% this is a comment&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-module(foo).     %% we define a module called foo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-export([bar&#x2F;0]). %% and export the function bar that has 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                  %% arguments&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;bar() -&amp;gt;          %% we define the function bar&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; io:format(&amp;quot;Hello World!~n&amp;quot;).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Lets compile it and run inside the erlang shell the bar function from module foo.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ erlc foo.erl &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ erl          &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1&amp;gt; foo:bar().  %% we call the bar function&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Hello World!&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ok&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let me show you an example that is a little more complex:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-module(test).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-compile(export_all).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;%% factorial implemented as you would normally do in most&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;%% imperative languages.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fac_if(N) -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  if &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    N =:= 0 -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      1;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    true -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      N * fac_if(N - 1)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  end.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;%% factorial implemented with a case. if N matches 0 it&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;%% returns 0. If N matches any other value it will call&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;%% fac_case with N-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fac_case(N) -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  case N of&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    0 -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      1;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    N -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      N * fac_case(N - 1)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  end.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;%% factorial implemented with function clauses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; fac(0) -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  1;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fac(N) -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  N * fac(N - 1).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now let’s save it as test.erl, compile it and call the erlang shell:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ erlc test.erl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ erl &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The last case uses something called pattern matching in the function head. In just a few lines you will learn more about pattern matching. Now we can call the fac function:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2&amp;gt; test:fac(20).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2432902008176640000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3&amp;gt; test:fac(40). &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;815915283247897734345611269596115894272000000000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The syntax is not difficult. It is just different from Algol or C based syntax. As you will see there are not many reserverd words or language constructs. I think only Lisps are way simpler languages from the syntax and grammar point of view.&lt;&#x2F;p&gt;
&lt;p&gt;I wanted to add that as you have noticed erlang uses “&lt;strong&gt;,&lt;&#x2F;strong&gt; ”&lt;strong&gt;,&lt;&#x2F;strong&gt; “&lt;strong&gt;;&lt;&#x2F;strong&gt; ”**** and**** “&lt;strong&gt;.&lt;&#x2F;strong&gt; ” as terminators. I am not a big fan of them, since I have to change them when moving lines of code up or down. In general I like indentation a la Python as a way to delimit blocks of code. However Erlang terminators are not a big pain in the a** once you get used to them. Also I agree with Robert Virding, co creator of Erlang, that Erlang syntax is small, simple, regular and concise. It is difficult not to agree with that even if you do not like Erlang syntax. All the mainstream languages I have used (e.g. C++, Java, C# or Objective-C) have a much more complex and less consistent syntax. Returning to the terminator issue, Fred Hebert has a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;ferd.ca&#x2F;on-erlang-s-syntax.html&quot;&gt;great article&lt;&#x2F;a&gt; with some tips on how to understand how to use and read them.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s move onto more important things:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;expressiveness&quot;&gt;Expressiveness&lt;&#x2F;h3&gt;
&lt;p&gt;When thinking about Erlang expressiveness the first thing that comes to mind is message passing, process creation and management. Nevertheless pattern matching is a big player too in this field and serves a big purpose in making things easier for receiving messages. Let’s start by showing a simple example of pattern matching before moving on to message passing and process management.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4&amp;gt; Body.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* 1: variable &amp;#39;Body&amp;#39; is unbound&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5&amp;gt; Headers.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* 1: variable &amp;#39;Headers&amp;#39; is unbound&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;First we tried to access the content of Body and Headers variables (all variables in Erlang must start with a capital letter). The shell answers with the obvious: the variables are unbound. Now it is time to do something more interesting.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Exit the shell we have being using up to now doing twice Control-C. Since we are going to use an http library (ibrowse) on the following example, instead of setting up everything:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ git clone git@github.com:unbalancedparentheses&#x2F;erlskeletor_cowboy.git&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ cd erlskeletor_cowboy&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ make&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Make will fetch all the dependencies and compile the project. Up to now we executed erl to launch the erlang shell. Now we are going to use:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ make shell&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Make shell will start erlang and all the dependencies we need. You will see a lot of output. Now we can return to our work:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1&amp;gt; ibrowse:send_req(&amp;quot;http:&#x2F;&#x2F;www.google.com&#x2F;&amp;quot;, [], get).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{ok,&amp;quot;302&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[{&amp;quot;Cache-Control&amp;quot;,&amp;quot;private&amp;quot;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&amp;quot;Content-Type&amp;quot;,&amp;quot;text&#x2F;html; charset=UTF-8&amp;quot;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&amp;quot;Location&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;quot;https:&#x2F;&#x2F;www.google.com.ar&#x2F;?gfe_rd=cr&amp;amp;ei=Nk11U4zsFIeF8Qf6hoC4BA&amp;quot;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&amp;quot;Content-Length&amp;quot;,&amp;quot;263&amp;quot;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&amp;quot;Date&amp;quot;,&amp;quot;Thu, 15 May 2014 23:26:46 GMT&amp;quot;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&amp;quot;Server&amp;quot;,&amp;quot;GFE&#x2F;2.0&amp;quot;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&amp;quot;Alternate-Protocol&amp;quot;,&amp;quot;443:quic&amp;quot;}],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;meta http-equiv=\&amp;quot;content-type\&amp;quot; content=\&amp;quot;text&#x2F;html;charset=utf-8\&amp;quot;&amp;gt;\n&amp;lt;TITLE&amp;gt;302 Moved&amp;lt;&#x2F;TITLE&amp;gt;&amp;lt;&#x2F;HEAD&amp;gt;&amp;lt;BODY&amp;gt;\n&amp;lt;H1&amp;gt;302 Moved&amp;lt;&#x2F;H1&amp;gt;\nThe document has moved\n&amp;lt;A HREF=\&amp;quot;https:&#x2F;&#x2F;www.google.com.ar&#x2F;?gfe_rd=cr&amp;amp;amp;ei=Nk11U4zsFIeF8Qf6hoC4BA\&amp;quot;&amp;gt;here&amp;lt;&#x2F;A&amp;gt;.\r\n&amp;lt;&#x2F;BODY&amp;gt;&amp;lt;&#x2F;HTML&amp;gt;\r\n&amp;quot;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We call the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cmullaparthi&#x2F;ibrowse&#x2F;blob&#x2F;master&#x2F;src&#x2F;ibrowse.erl#L-165&quot;&gt;send_req&lt;&#x2F;a&gt; function from the module &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cmullaparthi&#x2F;ibrowse&quot;&gt;ibrowse&lt;&#x2F;a&gt;, an HTTP erlang client. The first argument is a string with the URL. Strings are a &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.erlang.org&#x2F;faq&#x2F;academic.html#id58248&quot;&gt;linked list of integers&lt;&#x2F;a&gt; since Erlang doesn’t have a real string type. It is not very common to use strings in Erlang. You have &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Symbol_%28programming%29&quot;&gt;atoms&lt;&#x2F;a&gt; (&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.reactive.io&#x2F;tips&#x2F;2009&#x2F;01&#x2F;11&#x2F;the-difference-between-ruby-symbols-and-strings&#x2F;&quot;&gt;Ruby&lt;&#x2F;a&gt; or &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;8846628&#x2F;what-exactly-is-a-symbol-in-lisp-scheme&quot;&gt;Lisp&lt;&#x2F;a&gt; symbols), binaries and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;prog21.dadgum.com&#x2F;70.html&quot;&gt;IOLists&lt;&#x2F;a&gt; . Atoms and binaries are really common and handy. For the moment this is not important but I wanted to mention this so that you do not start rambling afterwards.&lt;&#x2F;p&gt;
&lt;p&gt;The second argument of the call to send_req is a list of headers we want to send with the request. We are not sending any header in this case. At last, with the third argument, we specify the verb of the request. We used the atom &lt;em&gt;get&lt;&#x2F;em&gt; for that. Variables can not begin with a lowercase letter because atoms do. Atoms start with lower-case letters or enclosed in single quotes. As you can see we sent a get request to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.google.com&#x2F;&quot;&gt;http:&#x2F;&#x2F;www.google.com&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s inspect the result of the call:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{ok,&amp;quot;302&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[{&amp;quot;Cache-Control&amp;quot;,&amp;quot;private&amp;quot;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&amp;quot;Content-Type&amp;quot;,&amp;quot;text&#x2F;html; charset=UTF-8&amp;quot;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&amp;quot;Location&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;quot;https:&#x2F;&#x2F;www.google.com.ar&#x2F;?gfe_rd=cr&amp;amp;ei=Nk11U4zsFIeF8Qf6hoC4BA&amp;quot;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&amp;quot;Content-Length&amp;quot;,&amp;quot;263&amp;quot;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&amp;quot;Date&amp;quot;,&amp;quot;Thu, 15 May 2014 23:26:46 GMT&amp;quot;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&amp;quot;Server&amp;quot;,&amp;quot;GFE&#x2F;2.0&amp;quot;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&amp;quot;Alternate-Protocol&amp;quot;,&amp;quot;443:quic&amp;quot;}],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; &amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;meta http-equiv=\&amp;quot;content-type\&amp;quot; content=\&amp;quot;text&#x2F;html;charset=utf-8\&amp;quot;&amp;gt;\n&amp;lt;TITLE&amp;gt;302 Moved&amp;lt;&#x2F;TITLE&amp;gt;&amp;lt;&#x2F;HEAD&amp;gt;&amp;lt;BODY&amp;gt;\n&amp;lt;H1&amp;gt;302 Moved&amp;lt;&#x2F;H1&amp;gt;\nThe document has moved\n&amp;lt;A HREF=\&amp;quot;https:&#x2F;&#x2F;www.google.com.ar&#x2F;?gfe_rd=cr&amp;amp;amp;ei=Nk11U4zsFIeF8Qf6hoC4BA\&amp;quot;&amp;gt;here&amp;lt;&#x2F;A&amp;gt;.\r\n&amp;lt;&#x2F;BODY&amp;gt;&amp;lt;&#x2F;HTML&amp;gt;\r\n&amp;quot;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The result is a tuple with four elements. &lt;strong&gt;{Term1,…,TermN}&lt;&#x2F;strong&gt; in erlang denotes a tuple. Tuples have a fixed number of terms or elements. Erlang tuples are very similar to Python tuples. The first element is the atom &lt;strong&gt;ok&lt;&#x2F;strong&gt; , that lets us know that everything went fine. The second element is the string with content 302. 302 Found HTTP status code is usually used to redirect the user to somewhere else. The third element of the result is the list of headers in the answer that google sent us.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[{&amp;quot;Cache-Control&amp;quot;,&amp;quot;private&amp;quot;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&amp;quot;Content-Type&amp;quot;,&amp;quot;text&#x2F;html; charset=UTF-8&amp;quot;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&amp;quot;Location&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;quot;https:&#x2F;&#x2F;www.google.com.ar&#x2F;?gfe_rd=cr&amp;amp;ei=Nk11U4zsFIeF8Qf6hoC4BA&amp;quot;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&amp;quot;Content-Length&amp;quot;,&amp;quot;263&amp;quot;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&amp;quot;Date&amp;quot;,&amp;quot;Thu, 15 May 2014 23:26:46 GMT&amp;quot;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&amp;quot;Server&amp;quot;,&amp;quot;GFE&#x2F;2.0&amp;quot;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&amp;quot;Alternate-Protocol&amp;quot;,&amp;quot;443:quic&amp;quot;}]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As you can see the headers are represented as a list of tuples. Each tuple has two elements: a key and a value. This is a type of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.erlang.org&#x2F;doc&#x2F;man&#x2F;proplists.html&quot;&gt;proplist&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The first header has a key of type string “Cache-Control” with a string value “private”. Also check that the “Location” key has the URL value of the redirect where google wants us to go. I know it can be different from what you are used to, but it is not that difficult to understand. After a few hours of reading proplists, tuples or lists in Erlang it will feel very natural.&lt;&#x2F;p&gt;
&lt;p&gt;The last element of the answer to the call to ibrowse:send_req is a big string with the HTML that google sent us:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;quot;&amp;lt;HTML&amp;gt;&amp;lt;HEAD&amp;gt;&amp;lt;meta http-equiv=\&amp;quot;content-type\&amp;quot; content=\&amp;quot;text&#x2F;html;charset=utf-8\&amp;quot;&amp;gt;\n&amp;lt;TITLE&amp;gt;302 Moved&amp;lt;&#x2F;TITLE&amp;gt;&amp;lt;&#x2F;HEAD&amp;gt;&amp;lt;BODY&amp;gt;\n&amp;lt;H1&amp;gt;302 Moved&amp;lt;&#x2F;H1&amp;gt;\nThe document has moved\n&amp;lt;A HREF=\&amp;quot;https:&#x2F;&#x2F;www.google.com.ar&#x2F;?gfe_rd=cr&amp;amp;amp;ei=Nk11U4zsFIeF8Qf6hoC4BA\&amp;quot;&amp;gt;here&amp;lt;&#x2F;A&amp;gt;.\r\n&amp;lt;&#x2F;BODY&amp;gt;&amp;lt;&#x2F;HTML&amp;gt;\r\n&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now let’s store the result:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2&amp;gt; {ok, &amp;quot;302&amp;quot;, Headers, Body} = ibrowse:send_req(&amp;quot;http:&#x2F;&#x2F;www.google.com&#x2F;&amp;quot;, [], get).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-9mLW7UAh0eDj2ljx5GfCJw.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;Pattern, pattern, pattern matching everything!!!&lt;&#x2F;p&gt;
&lt;p&gt;We sent a get request to google, got an answer. ‘ok &lt;em&gt;’&lt;&#x2F;em&gt; is an atom, and &lt;em&gt;“302“&lt;&#x2F;em&gt; a string. They are not assigned, since they are not variables. So why did we use the equal sign to assign them? Well because in Erlang the equal sign is not exactly the same as assignment. Since Erlang supports the pattern matching mechanism, the equal sign is used as a match operator. It tries to find equivalence between the two sides, and then binds values to unbound variables, thus assigning them a value.&lt;&#x2F;p&gt;
&lt;p&gt;So after getting the result from our call to ibrowse:send_req, Erlang asserts that we got a tuple with four elements that started with the elements ok and “302“. Then since it knows that Headers and Body are unbound it assigned the headers proplist to the variable Headers and the HTML returned by Google to the variable Body.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3&amp;gt; Headers.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[{&amp;quot;Cache-Control&amp;quot;,&amp;quot;private&amp;quot;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&amp;quot;Content-Type&amp;quot;,&amp;quot;text&#x2F;html; charset=UTF-8&amp;quot;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&amp;quot;Location&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;quot;https:&#x2F;&#x2F;www.google.com.ar&#x2F;?gfe_rd=cr&amp;amp;ei=Nk11U4zsFIeF8Qf6hoC4BA&amp;quot;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&amp;quot;Content-Length&amp;quot;,&amp;quot;263&amp;quot;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&amp;quot;Date&amp;quot;,&amp;quot;Thu, 15 May 2014 23:26:46 GMT&amp;quot;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&amp;quot;Server&amp;quot;,&amp;quot;GFE&#x2F;2.0&amp;quot;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&amp;quot;Alternate-Protocol&amp;quot;,&amp;quot;443:quic&amp;quot;}]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To sum up, pattern matching is way more than another syntax for writing your C switch or if&#x2F;else&#x2F;elif from Python and most languages. With pattern matching you get normal branching, conditionals on complex structure, not only by comparing simple values, and you can also extract specific values when you do the comparison or&#x2F;and assignment. You &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;deliberate-software.com&#x2F;function-pattern-matching&#x2F;&quot;&gt;make the compiler work for you&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;At last I wanted to show a beautiful example of pattern matching where we dissect a TCP segment by its bits:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&amp;lt;SourcePort:16, DestinationPort:16,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; SequenceNumber:32,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; AckNumber:32,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; DataOffset:4, _Reserved:4, Flags:8, WindowSize:16,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Checksum:16, UrgentPointer:16,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Payload&#x2F;binary&amp;gt;&amp;gt; = TcpSegment.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Ain’t this a good example of Erlang expressiveness?&lt;&#x2F;p&gt;
&lt;h4 id=&quot;god-cannot-alter-the-past-though-historians-can-and-some-developers-too-samuel-butler&quot;&gt;God cannot alter the past, though historians can (and some developers too)— Samuel Butler&lt;&#x2F;h4&gt;
&lt;p&gt;Variables are either bound or unbound. As you might know values are inmutable in Erlang and once the variable is bound, you can not assign a new value to it. Only one assignment is allowed. You can not modify a variable or a value once it was created.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4&amp;gt; Message = &amp;quot;Hello ladies!&amp;quot;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;quot;Hello ladies!&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5&amp;gt; Message = &amp;quot;Die die my darling&amp;quot;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;** exception error: no match of right hand side value &amp;quot;Die die my darling&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Inmutability and single assignment at first might seem awkward, uncomfortable, but they are very useful properties since they minimize side effects. Even if it is not impossible to write Erlang code with race conditions, it is way more difficult than with general imperative and stateful languages. You will see this in the next section.&lt;&#x2F;p&gt;
&lt;p&gt;A really interesting property, helped by single assignment and inmutability, is &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Referential_transparency_%28computer_science%29&quot;&gt;referential transparency&lt;&#x2F;a&gt;. In plain english this means that the result of a function is always the same when you provide the same arguments&#x2F;input. You might think this is a property of most programming languages, but it is not.&lt;&#x2F;p&gt;
&lt;p&gt;The output of calling a method in most object oriented languages like for example C++, Java, Ruby depends on the state of the object. Previous calls to other method change the state of the object that is used by the methods you are calling. So the result will not depend only on the arguments, but also on what other methods have been called before. With referential transparency, you are on the greener side of the grass since you have some degree of determinism. Also writing test cases is way easier since, in general, you do not need to mock entire objects or use dependency injection since you only call functions with the arguments you want.&lt;&#x2F;p&gt;
&lt;p&gt;You might think we are using complicated words for showing off. But as you will see in the following posts thanks to referential transparency and pattern matching we will be able to refactor nested branching implemented with cases into calling small and simple functions. In many languages, inspired by how Java and C++ implemented OOP, the code is so damn interdependent that it is more difficult to refactor it.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;processes-and-messages&quot;&gt;Processes and Messages&lt;&#x2F;h4&gt;
&lt;p&gt;Functions in functional programming languages are first class citizens. This means that they are not discriminated. They can be assigned to variables, passed as arguments to other functions and returned as values from other functions. Say no to racism. Treat functions as any other type!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-FLmbrG6z0Pt25nbfeG775g.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;6&amp;gt; F = fun(X, Y, Operation) -&amp;gt; Operation(X,Y) end.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#Fun&amp;lt;erl_eval.18.106461118&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;7&amp;gt; Plus = fun(X, Y) -&amp;gt; X + Y end.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#Fun&amp;lt;erl_eval.12.106461118&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8&amp;gt; F(2, 2, Plus).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;9&amp;gt; DividePlusTwo = fun(A,B) -&amp;gt; A &#x2F; B + 2 end.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#Fun&amp;lt;erl_eval.12.106461118&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;10&amp;gt; F(2, 2, DividePlusTwo). &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3.0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Creating a new process in Erlang is really simple. You use the spawn primitive with the function you want to launch in another process.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;11&amp;gt; G = fun() -&amp;gt; 2 + 2 end.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#Fun&amp;lt;erl_eval.20.106461118&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;12&amp;gt; G().&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;13&amp;gt; spawn(G).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;0.60.0&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;14&amp;gt; spawn(G).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;0.65.0&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Spawn creates the new process and returns the PID (unique Process Identifier) of that process. You might ask where does the return value go? Well apparently it disappeared. Black magic? No. Processes do not return anything. You have to send the result as a message to another. Before that let me show you that the shell itself is a process and that we can get its PID:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;15&amp;gt; self().&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;0.32.0&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;16&amp;gt; exit(self()).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;** exception exit: &amp;lt;0.32.0&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;17&amp;gt; self().&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;0.35.0&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With self() we got the PID of the actual process, in this case obviously the shell’s PID. We then exited that process and a new shell process automatically was launched, that is why the PID changed from &amp;lt;0.32.0&amp;gt; to &amp;lt;0.35.0&amp;gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;18&amp;gt; Pid = self().&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;0.32.0&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;19&amp;gt; H = fun() -&amp;gt; Pid ! 2+2 end.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#Fun&amp;lt;erl_eval.20.106461118&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;20&amp;gt; spawn(H).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;0.36.0&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;21&amp;gt; flush().&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Shell got 4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ok&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The ! or bang symbol, is a primitive that sends the message at its right to the process identified by the PID at its left. Each process has a mailbox, a queue that stores the messages the process receives. With flush you can see all the messages the process has.&lt;&#x2F;p&gt;
&lt;p&gt;However in general you want to do something based on the message you received, not only see them on the shell. That is where the receive statement appears to save the game!&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;22&amp;gt; Echofun = fun Echo() -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           receive&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             X -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;               io:format(&amp;quot;Message ~p~n&amp;quot;, [X])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;         end.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#Fun&amp;lt;erl_eval.20.106461118&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;23&amp;gt; EchoPid = spawn(Echofun).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;0.35.0&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;24&amp;gt; EchoPid ! test.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Message test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We created an Echofun function that receives a message and prints it. Receive blocks until it receives a message. Receive is very similar to the case statement. If a message correctly pattern matches, the associated expression gets executed.&lt;&#x2F;p&gt;
&lt;p&gt;Returning to our example, we saved the Echofun function in the Echo variable. Then we spawned the function and stored the Pid. Finally we sent an atom as a message using the bang symbol. The message is received by the process and as any message will pattern match to the variable X the io:fomat line gets executed. The first parameter of io:format is a string that contains a ~p. ~p gets replaced by each element of the list, that is the second argument of the call to io:format.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;25&amp;gt; EchoPid ! test.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If we send the message again, the process will not print “Message test” as before because the function already finished it’s execution. That’s why we need to recursively call the function so that it keeps running after receiving a message.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;26&amp;gt; Echofun2 = fun Echo() -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             receive&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;               X -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                 io:format(&amp;quot;Message ~p~n&amp;quot;, [X]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                 Echo()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;             end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;           end.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#Fun&amp;lt;erl_eval.44.106461118&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;27&amp;gt; EchoPid2 = spawn(Echofun2).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;0.35.0&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;28&amp;gt; EchoPid2 ! test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Message test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;29&amp;gt; EchoPid2 ! test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Message test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;30&amp;gt; EchoPid2 ! test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Message test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now after receiving and printing the first message, the function call itself and waits for the next message to be received.&lt;&#x2F;p&gt;
&lt;p&gt;Erlang and most functional programming languages have a great property called &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Tail_call&quot;&gt;tail recursion&lt;&#x2F;a&gt;. Thanks to it your process can have a long and great life without making your stack grow and explode in your face.&lt;&#x2F;p&gt;
&lt;p&gt;Let’s add a new clause inside the receive so that we can kill the process:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;31&amp;gt; Echofun3 = fun Echo() -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  receive &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    die -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      io:format(&amp;quot;Process with PID ~p has died~n&amp;quot;, [self()]);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    X -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      io:format(&amp;quot;Message ~p~n&amp;quot;, [X]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      Echo()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; end.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#Fun&amp;lt;erl_eval.44.106461118&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now instead of spawning the function in a process and storing the PID, we will register the process:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Besides addressing a process by using its pid, there are also built in functions (BIFs) for registering a process under a name. The name must be an atom and is automatically unregistered if the process terminates&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;32&amp;gt; register(echo_process, spawn(Echofun3)).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We register the process created by spawn(Echofun3) under the name echo_process.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;33&amp;gt; echo_process ! test.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Message test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;34&amp;gt; echo_process ! die.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Process with PID &amp;lt;0.37.0&amp;gt; has died&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;die&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-wysu8drrpca_-GPtNsoYNQ.gif&quot; alt=&quot;&quot; &#x2F;&gt;killing a process thanks to message passing&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;35&amp;gt; echo_process ! test.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;** exception error: bad argument&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;in operator !&#x2F;2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;called as echo_process ! test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The receive in the process function that is running under a new process pattern matchs the messages it receives. Since the first message does not match the die atom, it then checks if it matchs the X variable. Since the X variable is unbound, the message will always match it. The message gets printed out.&lt;&#x2F;p&gt;
&lt;p&gt;We send a die atom as a message to the same process. Since die matchs the first clause of the receive, a sentence stating that the process has died. As we do not call the function again effectively the process dies.&lt;&#x2F;p&gt;
&lt;p&gt;When we try to send again a test atom as message to the process that was registered via the echo_process we get a bad argument exception. This happens since the process died the echo_process atom does not reference a process anymore, and obviously that’s why we can not send a message.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;the-final-fight&quot;&gt;The final fight&lt;&#x2F;h4&gt;
&lt;p&gt;Now we are going to play with three processes: a client (the shell), a project manager and a developer. The shell will send a message to the project manager. The project manager will forward the task to developer. Simple but cool:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;36&amp;gt; Dev = fun Devfun() -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  receive&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Task -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      io:format(&amp;quot;DEV(~p):~n I got a new task: ~p ~n---~n&amp;quot;, [self(), Task]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      Devfun()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;end.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As you can see the Dev variable contains a function that receives a message and prints it out. After that it calls itself.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;37&amp;gt; Pm = fun Pmfun() -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  receive&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    Task -&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      io:format(&amp;quot;PM(~p):~n I received the following task: ~p.~n My job is to forward it to the developer ~n---~n&amp;quot;, [self(), Task]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      dev ! Task,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      Pmfun()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;end.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Well the Project Manager is not very different from the Developer. He receives a task, prints it out and finally it sends the Task he received to the dev process. We need to spawn and register the dev and pm processes. If we do not register the process that spawns the Dev function, then we would not be able to send it a message as we are doing. So let’s do it:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;38&amp;gt; register(dev, spawn(Dev)),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;register(pm, spawn(Pm)).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally we are going to create a really simple function that sends the task to the pm:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;39&amp;gt; NewTask = fun (Task) -&amp;gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  io:format(&amp;quot;Client(~p):~n ~p~n---~n&amp;quot;, [self(), Task]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  pm ! Task&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;end.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Time to send our task!&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;40&amp;gt; NewTask(&amp;quot;Add cover to TPS report&amp;quot;).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And we get this ouput printed out:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Client(&amp;lt;0.32.0&amp;gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; &amp;quot;Add cover to TPS report&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PM(&amp;lt;0.37.0&amp;gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; I received the following task: &amp;quot;Add cover to TPS report&amp;quot;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; My job is to forward it to the developer&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DEV(&amp;lt;0.36.0&amp;gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; I got a new task: &amp;quot;Add cover to TPS report&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-1MQrMONE3YjecZdrkdOhTg.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The Dev process could be running in one server in the US, the PM process in an Europe based server and the Client, my shell, could be running on my computer here in Buenos Aires, Argentina. In another language this would require a really big code change. When using Erlang this only requires adding a few lines of code. Technically, we would have to register the processes globally and set up some kind of vpn so that the virtual machines see themselves as if on a local network. The point is that erlang has distribution built in, and getting to the point where systems run on clusters is not difficult.&lt;&#x2F;p&gt;
&lt;p&gt;For the following posts we leave error detection and supervision of processes, an area where Erlang really really shines.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;moving-foward&quot;&gt;Moving foward&lt;&#x2F;h3&gt;
&lt;p&gt;You might be asking yourself why would you want to create processes and send messages between them? Sooner rather than later in relative big project you will need to parallelize some code for example a call to a third party api that is taking too much time for example. That is why you will need to use a concurrency construct. In most programming languages threads, processes or any construct related to concurrency or parallelism is something you rarely use. In most universities it is something you will learn only after your first programming courses. You might have used a ThreadPool in Java or even a pthread in C. But it is not something you generally use or do as often as defining a class, instantiating an object, calling a function or writing a conditional statement. Even if this is changing and we now have really interesting libraries, frameworks and toolkits like Akka for the Java world, Concurrent-Ruby or Celluloid for Ruby or even languages as Clojure that already set a pretty high bar, truth be told concurrency is not the cornerstone of most languages. In Erlang you will use them as frequently as you use an if construct in C, because they are cheap and great for designing your systems.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-o61yZIq3SpkTDPn-pzAJTA.gif&quot; alt=&quot;&quot; &#x2F;&gt;Message passing&lt;&#x2F;p&gt;
&lt;p&gt;Up to now we have only played with processes so that you can see how easy it is to use concurrency based primitives in Erlang since you do not require external library support like in most languages. You will see some of its real uses in the nexts posts. I must add that pattern matching plays an essential role too, and it is very well integrated with the the rest because it makes it very easy to select what to do based on the message received.&lt;&#x2F;p&gt;
&lt;p&gt;To sum up thanks to message passing, pattern matching, light processes you can avoid threads, mutex, semaphores and a lot of deadly weapons that sooner rather than later will backfire.&lt;&#x2F;p&gt;
&lt;p&gt;Stay tuned, we will work on some real stuff next week: comments and threads, http endpoints of our commenting system!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-1LLFcr72yLfiLfFloQHaeg.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;This is me after my first hour playing with Erlang!&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Languages I want to learn and use this 2014</title>
          <pubDate>Tue, 01 Apr 2014 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/languages-i-want-to-learn-and-use-this-2014/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/languages-i-want-to-learn-and-use-this-2014/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/languages-i-want-to-learn-and-use-this-2014/">&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2025&#x2F;12&#x2F;1-w6YUSUjzOr5yeXXUggaEIg.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;take-aim-much-higher-than-the-mark&quot;&gt;Take aim much higher than the mark&lt;&#x2F;h4&gt;
&lt;hr &#x2F;&gt;
&lt;blockquote&gt;
&lt;p&gt;A wise man ought always to follow the paths beaten by great men, and to imitate those who have been supreme, so that if his ability does not equal theirs, at least it will savor of it. &lt;strong&gt;Let him act like the clever archers who&lt;&#x2F;strong&gt; , designing to hit the mark which yet appears too far distant, and knowing the limits to which the strength of their bow attains, &lt;strong&gt;take aim much higher than the mark&lt;&#x2F;strong&gt; , not to reach by their strength or arrow to so great a height, but &lt;strong&gt;to be able with the aid of so high an aim to hit the mark they wish to reach.&lt;&#x2F;strong&gt; —&lt;strong&gt;&lt;em&gt;Niccolo&lt;&#x2F;em&gt; &lt;em&gt;Machiavelli&lt;&#x2F;em&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;And that’s the excuse I have to explain why I want to learn so many languages on this 2014.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;lisp-common-lisp-and-clojure&quot;&gt;Lisp, Common Lisp and Clojure&lt;&#x2F;h3&gt;
&lt;p&gt;Immediately after reading &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;paulgraham.com&#x2F;avg.html&quot;&gt;Beating the Averages&lt;&#x2F;a&gt; from Paul Graham I wanted to learn Lisp:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;By induction, the only programmers in a position to see all the differences in power between the various languages are those who understand the most powerful one. (This is probably what Eric Raymond meant about Lisp making you a better programmer.) You can’t trust the opinions of the others, because of the Blub paradox: they’re satisfied with whatever language they happen to use, because it dictates the way they think about programs.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;However, I didn’t have enough time to do it. At that moment I was coding a lot in Ruby, Python, C++ and Java in order to earn enough to live by my own.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-uDtazbx2QjY_M5c2iu-gNQ.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Now that I am a better paid code monkey and that I have enough free time, I am reading &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;landoflisp.com&#x2F;&quot;&gt;The Land Of Lisp&lt;&#x2F;a&gt;. As I dive down into the rabbit hole of the Lisp world, I am trying to create my own emacs distribution called &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;pyotrgalois&#x2F;lunfardo&quot;&gt;Lunfardo&lt;&#x2F;a&gt;. I think it’s a good way to learn Emacs and Lisp. I hope to finish reading the book and the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;google&#x2F;lisp-koans&quot;&gt;Lisp Koans&lt;&#x2F;a&gt; in the following weeks.&lt;&#x2F;p&gt;
&lt;p&gt;A few weeks ago I read some chapters from &lt;strong&gt;Seven Concurrency Models in Seven Weeks&lt;&#x2F;strong&gt; by Paul Butcher. The chapter &lt;strong&gt;The Clojure Way — Separating Identity from State&lt;&#x2F;strong&gt; got my attention. After reading it, I investigated &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;clojure&#x2F;core.async&quot;&gt;core.async&lt;&#x2F;a&gt; and its &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;clojure.com&#x2F;blog&#x2F;2013&#x2F;06&#x2F;28&#x2F;clojure-core-async-channels.html&quot;&gt;channels&lt;&#x2F;a&gt;. It appears that, as in many great languages, there are &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;adambard.com&#x2F;blog&#x2F;clojure-concurrency-smorgasbord&#x2F;&quot;&gt;many flavors of concurrency in Clojure&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Then I watched &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.infoq.com&#x2F;presentations&#x2F;Value-Identity-State-Rich-Hickey&quot;&gt;Persistent Data Structures and Managed References&lt;&#x2F;a&gt; by Rich Hickey, author of Clojure. Since I am interested in concurrency-related things and in Lisp, Clojure seems like a good next stop in my roadmap. So I added &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;http&#x2F;&#x2F;www.braveclojure.com&#x2F;&quot;&gt;Clojure for the Brave and True&lt;&#x2F;a&gt; to the list of books I have to read in the next few weeks. As I read it I hope to play with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;functional-koans&#x2F;clojure-koans&quot;&gt;Clojure Koans&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;However, as most developers, I think that the best way to learn a language is to use it in a real project. Therefore, I will try to implement a few ideas I got in Clojure.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-PyX6M9lSBXLHvVgAlDXrTA.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;haskell&quot;&gt;Haskell&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-mIrYVuSZtaYe3WJkRwUqwQ.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The most important reason why I want to learn Haskell is that two of the most inteligent persons I know really love it -and that’s a good enough reason for me. After checking &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;learnxinyminutes.com&#x2F;docs&#x2F;haskell&#x2F;&quot;&gt;Learn X in Y minutes Where X=haskell&lt;&#x2F;a&gt;, the syntax seems quite simple. I have read complaints about it. At this moment I really can’t see why. I will have to learn it before having a strong opinion.&lt;&#x2F;p&gt;
&lt;p&gt;This video from Brian Beckman caught my attention: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=ZhuHCtR3xq8&quot;&gt;Don’t fear the Monad&lt;&#x2F;a&gt;. Even if monads are not unique to Haskell, they are really important for this language since it’s a pure language:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Haskell functions are in general pure functions: when given the same arguments, they return the same results. The reason for this paradigm is that pure functions are much easier to debug and to prove correct. Test cases can also be set up much more easily, since we can be sure that nothing other than the arguments will influence a function’s result. We also require pure functions not to have side effects other than returning a value: a pure function must be self-contained, and cannot open a network connection, write a file or do anything other than producing its result. This allows the Haskell compiler to optimise the code very aggressively.&lt;br &#x2F;&gt;
However, there are very useful functions that cannot be pure: an input function, say getLine, will return different results every time it is called; indeed, that’s the point of an input function, since an input function returning always the same result would be pointless. Output operations have side effects, such as creating files or printing strings on the terminal: this is also a violation of purity, because the function is no longer self-contained.&lt;br &#x2F;&gt;
Unwilling to drop the purity of standard functions, but unable to do without impure ones, Haskell places the latter ones in the IO monad. In other words, what we up to now have called “IO actions” are just values in the IO monad.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I have never used a really pure programming language. It’s time to check it out and weigh its benefits.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-3IMSBVSph3XTwJEidHh0tw.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;mrb_bk&quot;&gt;@mrb_bk&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Think of typechecking the same way you think of testing or even linting — an analysis phase that can help you gain confidence&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Once you grasp the deep connections that “propositions as types” has to offer, you’ll get hooked and long for correctness&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Proper modern languages will have modern type checkers that can seamlessly analyze programs and aid in annotation.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I am also interested in using a language with a strong typesystem that adds something. In Java, C++ and similar languages I feel like that I have to add a lot of information to my code without having a real benefit. That’s why I prefer to use Javascript, Python or Ruby. From what I have read Haskell’s typesystem is really usefull.&lt;&#x2F;p&gt;
&lt;p&gt;At last, some years ago I played with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;xmonad.org&#x2F;&quot;&gt;xmonad&lt;&#x2F;a&gt;, a tiling window manager. You configure it using Haskell. For the last 4 or 5 years I have used its main competitor called awesome (configured with Lua). I want to learn Haskell to understand and use xmonad.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;erlang-elixir-and-lfe&quot;&gt;Erlang, Elixir and LFE&lt;&#x2F;h3&gt;
&lt;p&gt;For the last 6 months I have been working as an Erlang developer. At this moment I am coding a messaging server for &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;whisper.sh&#x2F;&quot;&gt;Whisper&lt;&#x2F;a&gt; using ElasticSearch for storing the messages and Cowboy to create the webserver endpoints.&lt;&#x2F;p&gt;
&lt;p&gt;I really like Erlang, even if I think its ecosystem leaves a lot of room for improvement. I am not a big fan of its Prolog based syntax. I don’t think it’s complex or difficult but the use of comma ‘&lt;strong&gt;,’&lt;&#x2F;strong&gt; , semicolon ‘&lt;strong&gt;;’&lt;&#x2F;strong&gt; and period &lt;strong&gt;‘.’&lt;&#x2F;strong&gt; as terminators is cumbersome (you need to change the terminator almost every time you move a line) and doesn’t have any real benefit:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;devintorr.es&#x2F;blog&#x2F;2013&#x2F;01&#x2F;22&#x2F;the-excitement-of-elixir&#x2F;&quot;&gt;The excitement of Elixir&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Erlang’s syntax does away with nested statement terminators and instead uses expression separators everywhere. Lisp suffers the same problem, but Erlang doesn’t have the interesting properties of a completely uniform syntax and powerful macro system to redeem itself.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;It is not a real problem anyway. If you follow one of the three ways to read Erlang code explained on the post called &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;ferd.ca&#x2F;on-erlang-s-syntax.html&quot;&gt;On Erlang’s Syntax&lt;&#x2F;a&gt;, you will get it really fast. In general, I agree with &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;rvirding.blogspot.com&#x2F;2014&#x2F;01&#x2F;erlang-syntax-again-and-again-and-again.html&quot;&gt;Erlang syntax again … and again … and again …&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;While I can understand people may dislike the syntax of a certain language, even I dislike some syntaxes, I don’t understand people who say “I was going to learn Erlang but the syntax was so strange I quit”.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;If you know that there are really awesome areas where &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;ferd.ca&#x2F;rtb-where-erlang-blooms.html&quot;&gt;Erlang BLOOMS&lt;&#x2F;a&gt;, you will learn the language even if it’s different from your main language.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;My point is that the syntax is the easy part of learning a new language, just look it up in the manual. It is learning the semantics of the new language and how to use it efficiently to solve your problems which are the major difficulties. How do I structure my solution to best make use of the language and its environment? This is where major rethinks will occur. This is what takes time to learn and understand. Not in what it looks like.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I want to use Elixir on a daily basis not only because I think it has a better syntax:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;devintorr.es&#x2F;blog&#x2F;2013&#x2F;06&#x2F;11&#x2F;elixir-its-not-about-syntax&#x2F;&quot;&gt;Elixir: It’s Not About Syntax&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The great thing about the Elixir standard library is that with each release it can provide features that Erlang developers clamor for everyday. We have Erlangers, Clojurists, Haskellers, Rubyists, and Pythonistas trying to incorporate useful features into Elixir every day. Elixir isn’t afraid of introducing functionality that improves the lives of Elixir developers, and everything is on the table: new data structures, real Unicode support, anything.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;[…]&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Elixir isn’t the CoffeeScript of Erlang just as Clojure isn’t the CoffeeScript of Java. Just like Clojure, Elixir is more than a pretty face. Elixir is the power of it’s tooling, the expressiveness of it’s metaprogrammability, and the expansive feature set of it’s standard library while maintaining complete compatibility with—and heavily leveraging—OTP. Once again I have yet to adequately scratch the surface of what makes Elixir special, but I have more Elixir to write!&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I have only played with Elixir for a few hours before learning and really using Erlang. I plan to use &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dynamo&#x2F;dynamo&quot;&gt;Dynamo&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elixir-lang&#x2F;ecto&quot;&gt;Ecto&lt;&#x2F;a&gt; instead of using Nodejs with Express or Erlang with Cowboy to create my next REST system. I will let you know if I find a real benefit of using it instead of Erlang.&lt;&#x2F;p&gt;
&lt;p&gt;At last I wanted to mention my latest discover: Lisp Flavored Erlang (LFE)&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Nothing Quite Compares to the taste of Erlang, aged in the oaken barrels of Lisp, served at a temperature of perfect hotness.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-Zv2If-7X5lPmvj_BAtOVIw.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I think this doesn’t need any more clarification. After learning Lisp I will give LFE a try. Check out its &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;lfe.github.io&#x2F;user-guide&#x2F;intro&#x2F;1.html&quot;&gt;awesome guide&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;r-programming-language&quot;&gt;R programming language&lt;&#x2F;h3&gt;
&lt;p&gt;A few months ago I bought a book called &lt;strong&gt;Exploring Everyday Things with R and Ruby&lt;&#x2F;strong&gt;. I saw its table of contents and I knew I wanted to read it.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you’re curious about how things work, this fun and intriguing guide will help you find real answers to everyday problems. By using fundamental math and doing simple programming with the Ruby and R languages, you’ll learn how to model a problem and work toward a solution.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Here are some of the questions you’ll explore:&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;- Determine how many restroom stalls can accommodate an office with 70 employees&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;- Mine your email to understand your particular emailing habits&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;- Use simple audio and video recording devices to calculate your heart rate&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;- Create an artificial society—and analyze its behavioral patterns to learn how specific factors affect our real society&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I bet now you want to read it too. But that’s not all. A guy that I really respect, called Zed Shaw, wrote &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;zedshaw.com&#x2F;essays&#x2F;programmer_stats.html&quot;&gt;Programmers Need To Learn Statistics Or I Will Kill Them All&lt;&#x2F;a&gt;. At the end of the post he encourages you to learn R. I only know basics of statistics, so I will try to kill two birds with one stone:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Learning to use R will help you also learn statistics better.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-SgUML3Hsk6MNGH3uvn7VRw.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;A few weeks ago I started a course on coursera about &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.coursera.org&#x2F;course&#x2F;ml&quot;&gt;Machine Learning&lt;&#x2F;a&gt;. Apparently, R is also very useful if you are into Machine Learning. There also an interesting book from O’Reilly called &lt;strong&gt;Machine Learning for hackers&lt;&#x2F;strong&gt; that uses R. Check them if you are interested.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-ULb9lkajm38eGIfrtRX7ZQ.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;As you can see I have a lot to learn this year. I hope I could inspire you to learn some of these language!&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Is Ruby.nil? or Ruby.hype.dead? A current overview of Ruby</title>
          <pubDate>Thu, 27 Mar 2014 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://lambdaclass.github.io/lambdaclass_blog/posts/is-ruby-nil-or-ruby-hype-dead-a-current-overview-of-ruby/</link>
          <guid>https://lambdaclass.github.io/lambdaclass_blog/posts/is-ruby-nil-or-ruby-hype-dead-a-current-overview-of-ruby/</guid>
          <description xml:base="https://lambdaclass.github.io/lambdaclass_blog/posts/is-ruby-nil-or-ruby-hype-dead-a-current-overview-of-ruby/">&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;2025&#x2F;12&#x2F;1-9vg-qHXQqxgYWVwtmo_V1A.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;the-main-languages-i-ve-used-this-year&quot;&gt;The main languages I’ve used this year&lt;&#x2F;h4&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;My last post was a really short mention of the resources I have used to learn and develop my skills in JavaScript and Erlang. On this post I’m going to share with you some thoughts I have regarding Ruby’s present.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ruby&quot;&gt;&lt;strong&gt;Ruby&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Oh my dear Ruby, son of Lisp, Perl, Eiffel and Smalltalk, time has passed but I think you still are such an amazing creature. Sure, you need to resolve some issues. Everbody does. Some really intelligent doctors have stated that you are sick, that you might be dying, others are not quite sure about that:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;jmoses.co&#x2F;2013&#x2F;12&#x2F;21&#x2F;is-ruby-dying.html&quot;&gt;Is Ruby Dying?&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;rubini.us&#x2F;2013&#x2F;10&#x2F;15&#x2F;introducing-rubinius-x&#x2F;&quot;&gt;Introducing Rubinius X&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Good clarification about the previous post: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.infoworld.com&#x2F;t&#x2F;ruby-rails&#x2F;rubinius-seeks-modernize-not-bury-the-ruby-language-229445&quot;&gt;Rubinius seeks to modernize, not bury, the Ruby language&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=6553767&quot;&gt;Discussion on Hacker News about Introducing Rubinius X&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.reddit.com&#x2F;comments&#x2F;1oi8wd&quot;&gt;Discussion on Reddit about the Hacker News discussion&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h4 id=&quot;quantitative-analysis&quot;&gt;&lt;strong&gt;Quantitative analysis&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Let’s start with some graphs. Everybody loves graphs!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-QCE2zU-R9MKX6Sqj5lZNyQ.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Programming language popularity indexes&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;adambard.com&#x2F;blog&#x2F;top-github-languages-for-2013-so-far&#x2F;&quot;&gt;Ruby seems to be the second language&lt;&#x2F;a&gt; with more repositories (218812) created (without counting forks) between January 1st and Aug 30th of 2013 on Github. JavaScript is the first with 264131 repositories created.&lt;&#x2F;p&gt;
&lt;p&gt;As reported by the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;TIOBE_index&quot;&gt;TIOBE Index&lt;&#x2F;a&gt;, Ruby has descended one position on its ranking during this year. On January 2013, Ruby was the eleventh most used language and is now the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.tiobe.com&#x2F;index.php&#x2F;content&#x2F;paperinfo&#x2F;tpci&#x2F;index.html&quot;&gt;twelfth&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.tiobe.com&#x2F;index.php&#x2F;content&#x2F;paperinfo&#x2F;tpci&#x2F;Ruby.html&quot;&gt;TIOBE ratings for Ruby&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-gt6Mt5Fq20JpvL3DNwYBNA.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;According to the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;sites.google.com&#x2F;site&#x2F;pydatalog&#x2F;pypl&#x2F;PyPL-PopularitY-of-Programming-Language&quot;&gt;Popularity of Programming Language index&lt;&#x2F;a&gt; (PYPL), Ruby is the ninth most popular programming language. PYPL is created by analyzing how often language tutorials are searched on Google.&lt;&#x2F;p&gt;
&lt;p&gt;According to &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;redmonk.com&#x2F;sogrady&#x2F;2014&#x2F;01&#x2F;22&#x2F;language-rankings-1-14&#x2F;&quot;&gt;RedMonk Programming Language Rankings&lt;&#x2F;a&gt;, at this moment, Ruby is the seventh most popular language based on correlations between GitHub’s and Stack Overflow’s rankings.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;Other popularity indicators&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Let’s move onto other indicators.&lt;&#x2F;p&gt;
&lt;p&gt;Ruby conferences registered by &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;lanyrd.com&#x2F;&quot;&gt;lanyrd&lt;&#x2F;a&gt; per year:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;2009: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;lanyrd.com&#x2F;topics&#x2F;ruby&#x2F;2009&#x2F;&quot;&gt;16&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;2010: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;lanyrd.com&#x2F;topics&#x2F;ruby&#x2F;2010&#x2F;&quot;&gt;50&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;2011: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;lanyrd.com&#x2F;topics&#x2F;ruby&#x2F;2011&#x2F;&quot;&gt;139&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;2012: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;lanyrd.com&#x2F;topics&#x2F;ruby&#x2F;2012&#x2F;&quot;&gt;188&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;2013: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;lanyrd.com&#x2F;topics&#x2F;ruby&#x2F;2013&#x2F;&quot;&gt;207&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The absolute number of conferences kept on growing, however the growth speed diminished.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;modulecounts.com&#x2F;&quot;&gt;Module counts&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-syyHrXaZtCo9O1V6iTtTEQ.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The number of modules seems to have kept growing at about the same speed for the last years.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.ohloh.net&#x2F;p&#x2F;ruby&quot;&gt;Ruby’s lines of code&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-Dibiyr75hsGDLCatZTiRxQ.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Ohloh reports that the Ruby language number of lines has grown at a steady speed.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.google.com&#x2F;trends&#x2F;explore#cat=0-5&amp;amp;q=%2Fm%2F06ff5&amp;amp;cmpt=q&quot;&gt;Interest over time reported by Google Trends&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-bHHmLXNdXqaT9IbDoEcfpg.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;However the interest over time registered by Google seems to have plunked.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.indeed.com&#x2F;jobtrends?q=ruby&quot;&gt;Ruby and Javascript Indeed job trends (absolute&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-kFX3kYHAfcR7_NuXO0PtbA.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.indeed.com&#x2F;jobtrends?q=ruby%2C+javascript&amp;amp;l=&amp;amp;relative=1&quot;&gt;Ruby and Javascript Indeed job trends (relative&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-IwJKDz6AwEQxl93gKlvM7g.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Nevertheless, even if Ruby job postings are way down compared to JavaScript, they are still on the rise and its percentage growth continues to be quite important. In the startup world, there are at least &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;angel.co&#x2F;javascript&#x2F;jobs&quot;&gt;five startups&lt;&#x2F;a&gt;registered on AngelList that need a JavaScript developer for &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;angel.co&#x2F;ruby&#x2F;jobs&quot;&gt;each startup&lt;&#x2F;a&gt;that needs at least someone with Ruby knowledge.&lt;&#x2F;p&gt;
&lt;p&gt;These statistics show that even though Ruby is not as popular as it was a few years ago, it’s still a big player.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h4 id=&quot;qualitative-data&quot;&gt;&lt;strong&gt;Qualitative data&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;So far, we have seen some numbers. Now it’s a good time to check other indicators that account for liveliness of Ruby.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-P_BdP89ac9dcWAMDTBoaPw.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Let me mention a few interesting tools created in Ruby apart from Rails and other web frameworks such as Sinatra or Padrino. I think this might give an idea about Ruby’s usage. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;brew.sh&#x2F;&quot;&gt;Homebrew&lt;&#x2F;a&gt;, coded in Ruby, is the simplest and more useful package manager for Mac OS X. Even if I prefer other alternatives, created in Nodejs, such as &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bevry&#x2F;docpad&quot;&gt;Docpad&lt;&#x2F;a&gt;, Jekyll, which is coded in Ruby, was one of the main reasons for the popularity of static page generators. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.discourse.org&#x2F;&quot;&gt;Discourse&lt;&#x2F;a&gt;, the best discussion platform. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;artoo.io&#x2F;&quot;&gt;Artoo&lt;&#x2F;a&gt; is a micro-framework for robotics. I don’t know a heck about it. Ruby also has got the two most used IT automation tools that exist: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.getchef.com&#x2F;chef&#x2F;&quot;&gt;Chef&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;puppetlabs.com&#x2F;&quot;&gt;Puppet&lt;&#x2F;a&gt;. These are two really big players that won’t disappear anytime soon and it doesn’t look as though they want to move away from Ruby.&lt;&#x2F;p&gt;
&lt;p&gt;Regarding books, Ruby always had great and fascinating books such as:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;mislav.uniqpath.com&#x2F;poignant-guide&#x2F;&quot;&gt;Why’s (Poignant) Guide to Ruby&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.confidentruby.com&#x2F;&quot;&gt;Confident Ruby&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.poodr.com&#x2F;&quot;&gt;Practical Object-Oriented Design in Ruby (POODR&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;eloquentruby.com&#x2F;&quot;&gt;Eloquent Ruby&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;pragprog.com&#x2F;book&#x2F;ager&#x2F;exceptional-ruby&quot;&gt;Exceptional Ruby: Master the Art of Handling Failure in Ruby&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.manning.com&#x2F;black2&#x2F;&quot;&gt;The Well-Grounded Rubyist&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;And now we got &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;patshaughnessy.net&#x2F;ruby-under-a-microscope&quot;&gt;Ruby under a microscope&lt;&#x2F;a&gt;. One of the latest and greatest books about Ruby that keeps up with this tradition of precious books.&lt;&#x2F;p&gt;
&lt;p&gt;Last but not least, let’s see some Ruby talks:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=fyq8Z6E5E14&quot;&gt;Ruby-Core dilemmas by Marc-André Lafortune&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=wPu2kVI09Yc&quot;&gt;Towards Tooling; A Look at What is Missing From our Toolbox&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=mhXyNGX38mw&quot;&gt;Ruby On Robots Using Artoo by Ron Evans&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=cxqjgq4VhgY&quot;&gt;Thinking about Machine Learning with Ruby by Bryan Liles&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;youtu.be&#x2F;cO26TjhQWvA&quot;&gt;Machine Learning with Ruby&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;michaelrbernste.in&#x2F;2013&#x2F;06&#x2F;10&#x2F;to-know-a-garbage-collector-goruco-2013.html&quot;&gt;To Know A Garbage Collector&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;As we can see, very different pieces of software are crafted with Ruby and Ruby developers seem to be attracted by very different things. From my point of view these are only examples that show how much life there is on the Ruby world. In my humble opinion Ruby is not going to die anytime soon. I think that, while Ruby’s hype is dead, the language and its great community have a great future.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h4 id=&quot;ruby-s-hardest-problem&quot;&gt;&lt;strong&gt;Ruby’s hardest problem&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;This doesn’t mean there are no problems on Ruby. Ruby seems to be in the same order of magnitude in terms of speed than &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.unlimitednovelty.com&#x2F;2012&#x2F;06&#x2F;ruby-is-faster-than-python-php-and-perl.html&quot;&gt;Python, PHP, and Perl&lt;&#x2F;a&gt; but in general Ruby it is not the fastest kid on the block. Even Matsumoto, its creator, admits it!&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.infoworld.com&#x2F;d&#x2F;application-development&#x2F;infoworld-interview-ruby-creator-sets-sights-mobile-171503?page=0,1&quot;&gt;Yukihiro Matsumoto details the past, present, and future of the popular programming language, calling mobile ‘the way to go&lt;&#x2F;a&gt;’&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;InfoWorld:&lt;&#x2F;strong&gt; Are there any limitations with developing Ruby applications?&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Matsumoto:&lt;&#x2F;strong&gt; Well, in some cases, performance could be the limitation. For example, Twitter was originally written in Ruby, but it has now has billions of users so, it’s larger, its core [is now] on top of the JVM. It was originally running on C Ruby, my Ruby. [With Twitter’s JVM-based program], the program is written in Scala and Clojure.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I think Matsumoto represents very well the self-critical spirit of the Ruby community. But it would be great if we could sidestep the performance problem. One way to do it is with concurrency and parallelism.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Ruby implementations&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Some say that:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Both Python and Ruby have full support for multi-threading. There are some implementations (e.g. CPython, MRI, YARV) which cannot actually run threads in parallel, but that’s a limitation of those specific implementations, not the language. This is similar to Java, where there are also some implementations which cannot run threads in parallel, but that doesn’t mean that Java is single-threaded. Note that in both cases there are lots of implementations which can run threads in parallel: PyPy, IronPython, Jython, IronRuby and JRuby are only few of the examples. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;3086467&#x2F;confused-are-languages-like-python-ruby-single-threaded-unlike-say-java-for&quot;&gt;Are languages like python and ruby single threaded unlike say java?&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;But come on, that’s pure theory. Almost everybody uses MRI, the main Ruby implementation. I think that the main reason is that it’s &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;andrewjgrimm.wordpress.com&#x2F;2013&#x2F;07&#x2F;08&#x2F;mri-boring-but-reliable&#x2F;&quot;&gt;reliable&lt;&#x2F;a&gt;. However the issue with MRI is that it:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;has something called a global interpreter lock (GIL). It’s a lock around the execution of Ruby code. This means that in a multi-threaded context, only one thread can execute Ruby code at any one time. So if you have 8 threads busily working on a 8-core machine, only one thread and one core will be busy at any given time. The GIL exists to protect Ruby internals from race conditions that could corrupt data. There are caveats and optimizations, but this is the gist. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.jstorimer.com&#x2F;blogs&#x2F;workingwithcode&#x2F;8085491-nobody-understands-the-gil&quot;&gt;Nobody understands the GIL:&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;With GIL or without it (read &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;tonyarcieri.com&#x2F;2012-the-year-rubyists-learned-to-stop-worrying-and-love-the-threads&quot;&gt;2012: The Year Rubyists Learned to Stop Worrying and Love Threads&lt;&#x2F;a&gt;) it’s pretty clear that:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;the single-core nature of the canonical Ruby interpreter, MRI (the “Matz Ruby Interpreter”), is limiting Ruby’s potential applications.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.igvita.com&#x2F;2008&#x2F;11&#x2F;13&#x2F;concurrency-is-a-myth-in-ruby&#x2F;&quot;&gt;Parallelism is a Myth in Ruby&lt;&#x2F;a&gt;. While we wait for this to get solved for MRI we can check out &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.unlimitednovelty.com&#x2F;2012&#x2F;03&#x2F;why-critics-of-rails-have-it-all-wrong.html&quot;&gt;why critics of Rails have it all wrong (and Ruby’s bright multicore future&lt;&#x2F;a&gt;) and learn how to overcome this problem:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Rubinius is an implementation of Ruby designed for concurrency using native threads to run Ruby code on all the CPU cores. It also has a low-pause generational garbage collector, LLVM-based just-in-time (JIT) native machine code compiler. Pretty badass piece of technology. It’s mainly implemented on Ruby. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Chicken_or_the_egg&quot;&gt;Chicken or the egg?&lt;&#x2F;a&gt;. But it has a big downside: Rubinius currently implements MRI Ruby version 1.8.7. MRI Ruby 1.8.7 was released on April 2008, that’s more than 5 years ago. From what I have read Rubinius is working on implementing the upcoming MRI 2.1 release.&lt;&#x2F;li&gt;
&lt;li&gt;JRuby runs your Ruby code on the JVM, and that’s why we get real threading. Latest version of JRuby is compatible with MRI Ruby 1.8.7 and 1.9.3. If you haven’t got enough links yet start reading&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;blog.engineyard.com&#x2F;2011&#x2F;concurrency-in-jruby&quot;&gt;Concurrency in JRuby&lt;&#x2F;a&gt;. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;youtu.be&#x2F;t_JJD-AEtNM&quot;&gt;JRuby: Insights from Six Years in Production&lt;&#x2F;a&gt;and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;youtu.be&#x2F;4TAwkq0aQdE&quot;&gt;The Future of JRuby by Charles Nutter and Thomas Enebo&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Also you got &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;youtu.be&#x2F;yl_zYzPiDto&quot;&gt;Visualizing Garbage Collection in Rubinius, JRuby and Ruby 2.0&lt;&#x2F;a&gt; that will be useful for any of the three implementation we mentioned.&lt;&#x2F;p&gt;
&lt;p&gt;Even if it’s a synthetic benchmark, this comparison between &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;miguelcamba.com&#x2F;blog&#x2F;2013&#x2F;10&#x2F;05&#x2F;benchmarking-the-ruby-2-dot-1-and-rubinius-2-dot-0&#x2F;&quot;&gt;MRI 1.9.3, MRI 2.0.0, MRI 2.1.0dev JRuby 1.7.4 and Rubinius 2.0.0&lt;&#x2F;a&gt; has some interesting information.&lt;&#x2F;p&gt;
&lt;p&gt;Again I think it’s a good idea to hear what Matsumoto thinks:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;InfoWorld:&lt;&#x2F;strong&gt; What’s your perspective on alternative Ruby implementations just as JRuby and Rubinius?&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Matsumoto:&lt;&#x2F;strong&gt; I don’t see any problem about other implementations just because the diversity is very sound, the healthy things they have. And actually Ruby, the language, is very good for productivity but the programming environment differs from application to application. For example, some clients require very stable and multicore applications on top of the JVM. In that kind of field, JRuby works better than my Ruby, actually, which is called C Ruby. For most of the cases, C Ruby is good for Web applications. But in certain situations, JRuby and maybe Rubinius are a better fit for a particular requirement.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;hr &#x2F;&gt;
&lt;h4 id=&quot;we-need-a-concurrency-model&quot;&gt;&lt;strong&gt;We need a concurrency model!&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;Despite having real concurrency or being able to run code in many cores, doesn’t mean it’s easy to do so:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;blog.smartbear.com&#x2F;programming&#x2F;why-johnny-cant-write-multithreaded-programs&#x2F;&quot;&gt;Why Johnny Can’t Write Multithreaded Programs&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Introductory multithreading materials explain what threads are. Then they launch into discussions of how to make those threads work together in various ways, such as controlling access to shared data with locks and semaphores, and perhaps controlling when things happen with events. There’s detailed discussion of condition variables, memory barriers, critical sections, mutexes, volatile fields, and atomic operations. You’re given examples of how to use those low level constructs to do all manner of systems level things. By the time a programmer is halfway through that material, she thinks she knows how to use those primitives in her applications. After all, if you understand how to use something at the systems level, using it at the application level should be trivial, right?&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;This is like teaching a teenager how to build an internal combustion engine from discrete parts and then, without the benefit of any driving instruction, setting him behind the wheel of a car and turning him loose on the roads. The teenager understands how the car works internally, but he has no idea how to drive it from point A to point B.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Knowing how threads work at the systems level is mostly irrelevant to understanding how to use them in an application program. I’m not saying that programmers shouldn’t know how things work under the hood, just that they shouldn’t expect that knowledge to be directly applicable to the design or implementation of a business application. After all, knowing the details of the intake, compression, combustion, and exhaust cycle doesn’t help you in getting from home to the grocery store and back.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Introductory multithreading textbooks (and computer science courses) shouldn’t be teaching those low level constructs. Rather, they should concentrate on common classes of problems and show developers how to use higher level constructs to solve those problems. For example, a large number of business applications are in concept extremely simple programs: They read data from one or more input devices, apply some arbitrarily complex processing to that data (perhaps querying some other stored data in the process), and then output the results.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;You need a concurrency model or you will keep recreating one on each project. In my humble opinion, these words about Javascript written by Joe Armstrong, creator of Erlang, apply almost perfectly for Ruby too even if it has &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;merbist.com&#x2F;2011&#x2F;02&#x2F;22&#x2F;concurrency-in-ruby-explained&#x2F;&quot;&gt;threads, process and fibers&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;joearms.github.io&#x2F;2013&#x2F;04&#x2F;02&#x2F;Red-and-Green-Callbacks.html&quot;&gt;Red and Green Callbacks&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;It’s actually worse, every Javascript programmer who has a concurrent problem to solve must invent their own concurrency model. The problem is that they don’t know that this is what they are doing. Every time a Javascript programmer writes a line of code that says “on this do that” they are actually inventing a new concurrency model, and they haven’t a clue how the code will interleave when it executes.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;(I actually have a love-hate relationship with Javascript, most parts I love but I hate the concurrency model- that might sound funny since Javascript has no concurrency model — so there’s nothing to hate :-)&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;What’s even more difficult to understand is errors. Errors in multi-threaded callback code with shared memory is something that would give me an extremely large headache.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The best concurrency model I know in the Ruby land is the one provided by the family of &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;celluloid&#x2F;celluloid&quot;&gt;Celluloid&lt;&#x2F;a&gt;. Celluloid, with the help of its sons &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;celluloid&#x2F;dcell&quot;&gt;DCell&lt;&#x2F;a&gt; — this is the best one — and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;celluloid&#x2F;celluloid-io&quot;&gt;Celluloi-io&lt;&#x2F;a&gt;, tries to help you achieve the nirvana described by these two famous quotes:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;“I thought of objects being like biological cells and&#x2F;or individual computers on a network, only able to communicate with messages” — &lt;strong&gt;Alan Kay, creator of Smalltalk, on the meaning of “object oriented programming”&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;hr &#x2F;&gt;
&lt;blockquote&gt;
&lt;p&gt;“Objects can message objects transparently that live on other machines over the network, and you don’t have to worry about the networking gunk, and you don’t have to worry about finding them, and you don’t have to worry about anything. It’s just as if you messaged an object that’s right next door.” -&lt;strong&gt;Steve Jobs describing the NeXT Portable Distributed Object system&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;hr &#x2F;&gt;
&lt;h4 id=&quot;why-i-like-ruby&quot;&gt;&lt;strong&gt;Why I like Ruby&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;max&#x2F;2000&#x2F;1-U24Mc9wNeiSNp2_eOYIGWg.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Time to land on Earth. We have spent too much time floating on the sky. I have never explained why I use and like Ruby.&lt;&#x2F;p&gt;
&lt;p&gt;In comparison with other dynamic type languages it has an awesome set of tools as &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;bbatsov&#x2F;rubocop&quot;&gt;rubocop&lt;&#x2F;a&gt;, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;YorickPeterse&#x2F;ruby-lint&quot;&gt;ruby-lint&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;troessner&#x2F;reek&quot;&gt;reek&lt;&#x2F;a&gt; that help you analyze your code. Furthermore it has the best &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Read%E2%80%93eval%E2%80%93print_loop&quot;&gt;REPL&lt;&#x2F;a&gt; that I am aware of: &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;pryrepl.org&#x2F;&quot;&gt;pry&lt;&#x2F;a&gt;. Watch &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;youtu.be&#x2F;D9j_Mf91M0I&quot;&gt;REPL driven development with Pry&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;youtu.be&#x2F;jDXsEzOHb2M&quot;&gt;Pry, The Good Parts!&lt;&#x2F;a&gt; to learn how it can help you speed up your development.&lt;&#x2F;p&gt;
&lt;p&gt;On the other hand, as I mentioned before, it’s not as fast as C or Java but Ruby core developers are doing an excellent work on that area. For example, check the history of improvements to the &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;tmm1.net&#x2F;ruby21-rgengc&#x2F;&quot;&gt;Ruby garbage collector&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Even though I sometimes think that it’s Perl-inherited attitude of having more than &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.senktec.com&#x2F;2013&#x2F;09&#x2F;one-way-to-do-it&#x2F;&quot;&gt;one way to do the same thing&lt;&#x2F;a&gt; is overwhelming (for some reason I need to reread &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.robertsosinski.com&#x2F;2008&#x2F;12&#x2F;21&#x2F;understanding-ruby-blocks-procs-and-lambdas&#x2F;&quot;&gt;Understanding Ruby Blocks, Procs and Lambdas&lt;&#x2F;a&gt;every month or so), in general I really like its syntax and semantics. I think it’s a very expressive and intuitive language. In my opinion how good a language is is not defined only by semantics, syntax and performance. I am not an academic. I have not even finished university.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;zedshaw.com&#x2F;essays&#x2F;master_and_expert.html&quot;&gt;The Master, The Expert, The Programmer&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Programming is a very new discipline, so there’s not too many master programmers out there. What’s worse is that the few people I would consider masters aren’t very exemplary of the software profession and art. They are typically professors who never write anything under a deadline and are given complete artistic freedom to develop whatever they want.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;I am not saying this in any mean way. I have huge respect for professors and researchers. But I am not one. I code stuff on a deadline. That’s why for me the community and the tools that it has created are really important. They are the salt and pepper of what I am cooking. This is why I love Ruby. It has a lot of salt and pepper. I particularly like Rails, the most known Ruby framework, and its cut down version &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rails-api&#x2F;rails-api&quot;&gt;Rails API&lt;&#x2F;a&gt;, because of the following features:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.unlimitednovelty.com&#x2F;2012&#x2F;08&#x2F;debunking-nodejs-gish-gallop.html&quot;&gt;Debunking the Node.js Gish Gallop&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Handled at the middleware layer:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Reloading: Rails applications support transparent reloading. This works even if your application gets big and restarting the server for every request becomes non-viable.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Development Mode: Rails application come with smart defaults for development, making development pleasant without compromising production-time performance.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Test Mode: Ditto test mode.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Logging: Rails applications log every request, with a level of verbosity appropriate for the current mode. Rails logs in development include information about the request environment, database queries, and basic performance information.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Security: Rails detects and thwarts IP spoofing attacks and handles cryptographic signatures in a timing attack aware way. Don’t know what an IP spoofing attack or a timing attack is? Exactly.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Parameter Parsing: Want to specify your parameters as JSON instead of as a URL-encoded String? No problem. Rails will decode the JSON for you and make it available in params. Want to use nested URL-encoded params? That works too.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Conditional GETs: Rails handles conditional GET, (ETag and Last-Modified), processing request headers and returning the correct response headers and status code. All you need to do is use the stale? check in your controller, and Rails will handle all of the HTTP details for you.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Caching: If you use dirty? with public cache control, Rails will automatically cache your responses. You can easily configure the cache store. HEAD requests: Rails will transparently convert HEAD requests into GET requests, and return just the headers on the way out. This makes HEAD work reliably in all Rails APIs.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Handled at the ActionPack layer:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Resourceful Routing: If you’re building a RESTful JSON API, you want to be using the Rails router. Clean and conventional mapping from HTTP to controllers means not having to spend time thinking about how to model your API in terms of HTTP.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;URL Generation: The flip side of routing is URL generation. A good API based on HTTP includes URLs (see the GitHub gist APIfor an example).&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Header and Redirection Responses: head :no &lt;em&gt;content and redirect&lt;&#x2F;em&gt; to user &lt;em&gt;url(current&lt;&#x2F;em&gt; user) come in handy. Sure, you could manually add the response headers, but why?&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Caching: Rails provides page, action and fragment caching. Fragment caching is especially helpful when building up a nested JSON object. Basic, Digest and Token Authentication: Rails comes with out-of-the-box support for three kinds of HTTP authentication.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Instrumentation: Rails 3.0 added an instrumentation API that will trigger registered handlers for a variety of events, such as action processing, sending a file or data, redirection, and database queries. The payload of each event comes with relevant information (for the action processing event, the payload includes the controller, action, params, request format, request method and the request’s full path).&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Generators: This may be passé for advanced Rails users, but it can be nice to generate a resource and get your model, controller, test stubs, and routes created for you in a single command.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Plugins: Many third-party libraries come with support for Rails that reduces or eliminates the cost of setting up and gluing together the library and the web framework. This includes things like overriding default generators, adding rake tasks, and honoring Rails choices (like the logger and cache backend).&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;These features are priceless when a deadline is near cutting your head like a guillotine. I think these features are partly the reason &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;blog.targeterapp.com&#x2F;post&#x2F;22984987832&#x2F;why-we-moved-from-nodejs-to-ror&quot;&gt;Why Targeter moved from NodeJS to RoR&lt;&#x2F;a&gt;. This doesn’t mean I don’t like Nodejs, but that discussion is beyond the scope of this post.&lt;&#x2F;p&gt;
&lt;p&gt;For example, this week, a client asked me to create a button on the admin site so that they could get the emails from the users of the application. It took me less than ten minutes to do it:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;invitations_emails = InvitationRequest.pluck(:email)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;user_emails = User.pluck(:email)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;content = (invitations_emails + user_email).to_csv&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;send_data content, filename: “emails.csv”&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;However all this magic ain’t always great, in particular when you have performance issues or library-related bugs. But in most cases it will save you from reinventing the wheel.&lt;&#x2F;p&gt;
&lt;p&gt;In this same line devise (authentication), paperclip (file attachment library that helps you treat files as any other attribute), kaminari (paginator), geocoder (really simple and complete geocoding solution), koala (Facebook library supporting the Graph and REST API), aws-sdk (self-explanatory), tire (API and DSL for the Elasticsearch search engine) or other alternatives that you can find in &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.ruby-toolbox.com&#x2F;&quot;&gt;The Ruby Toolbox&lt;&#x2F;a&gt; will make you cry of joy if your non techincal boss ask you to add a new functionality in a couple of hours.&lt;&#x2F;p&gt;
&lt;p&gt;Also, cucumber and rspec will be of great utility to check that the commit you did on Monday morning while you are really sleepy won’t destroy everything. I also wanted to mention RVM — the greatest version manager of any language I know — and Ruby Gems. After Nodejs great npm package manager, this is the best one I know.&lt;&#x2F;p&gt;
&lt;p&gt;At last, I wanted to show you &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;watirwebdriver.com&#x2F;&quot;&gt;watir-webdriver&lt;&#x2F;a&gt;. I bet you can’t find a better api to drive a browser. This is a perfect example of how rich and simple Ruby libraries are:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #E1E4E8; background-color: #24292E;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;require &amp;#39;watir-webdriver&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;b = Watir::Browser.new&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;b.goto &amp;#39;bit.ly&#x2F;watir-webdriver-demo&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;b.text_field(:id =&amp;gt; &amp;#39;entry_0&amp;#39;).set &amp;#39;your name&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;b.select_list(:id =&amp;gt; &amp;#39;entry_1&amp;#39;).select &amp;#39;Ruby&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;b.select_list(:id =&amp;gt; &amp;#39;entry_1&amp;#39;).selected? &amp;#39;Ruby&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;b.button(:name =&amp;gt; &amp;#39;submit&amp;#39;).click&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;b.text.include? &amp;#39;Thank you&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I have not mentioned before that Ruby is also an excellent language for creating prototypes or for doing IT related work like dealing with files and parsing strings.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, if you need to create a webpage or a REST API, specially when you don’t need real-time stuff, with limited time and money I can’t currently imagine a better replacement for Ruby and Rails.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h4 id=&quot;closing-words&quot;&gt;&lt;strong&gt;Closing words&lt;&#x2F;strong&gt;&lt;&#x2F;h4&gt;
&lt;p&gt;I won’t deny that Ruby has lost some momentum. But that doesn’t mean the language is dead. &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.codinghorror.com&#x2F;blog&#x2F;2013&#x2F;03&#x2F;why-ruby.html&quot;&gt;I think it has matured&lt;&#x2F;a&gt; and that it is a great tool to add to your arsenal as a developer.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;programming&#x2F;comments&#x2F;1oi8wd&#x2F;ruby_is_a_dying_language&#x2F;?utm_source=rubyweekly&amp;amp;utm_medium=email&quot;&gt;frycicle&lt;&#x2F;a&gt; explained it really well in a few words.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Shoot, in terms of libraries, language design, and community, Ruby has it all. It’s won’t scale to 10 website levels. And that is ok for it’s use. They usually have to make super specialized software anyways.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Even accepting that that Ruby is not dying, we could ask ourselves &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;youtu.be&#x2F;dE4toi7y1MM&quot;&gt;why hasn’t Ruby won?&lt;&#x2F;a&gt;. The answer is that:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Sarah Mei:&lt;&#x2F;strong&gt; this is a game where there is no winning turns out, but there is losing, there is definently losing. […] The best thing that you can do for Ruby is go learn something else and then come back.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;bascule&quot;&gt;@bascule&lt;&#x2F;a&gt; daily amazed at the number of ruby people I come across in the scala and Go worlds too. Ruby opens your mind.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;— Paul Lamb (@PaulLamb) &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;PaulLamb&#x2F;statuses&#x2F;426338111094661120&quot;&gt;January 23, 2014&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;That’s why you should learn some Python, &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;blog.grok.se&#x2F;2013&#x2F;10&#x2F;on-comparing-languages-c-and-go&#x2F;&quot;&gt;Go&lt;&#x2F;a&gt;, Rust, Erlang, Scala, Haskell, Clojure or any Lisp dialect. Oh, and keep an eye on &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;julialang.org&#x2F;&quot;&gt;Julia&lt;&#x2F;a&gt; and &lt;a rel=&quot;noopener external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;elixir-lang.org&#x2F;&quot;&gt;Elixir&lt;&#x2F;a&gt;!&lt;&#x2F;p&gt;
</description>
      </item>
    </channel>
</rss>
